| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_WRITER_H__ |
| #define GOOGLE_PROTOBUF_JSON_INTERNAL_WRITER_H__ |
| |
| #include <cfloat> |
| #include <cmath> |
| #include <cstdint> |
| #include <iostream> |
| #include <limits> |
| #include <ostream> |
| #include <string> |
| #include <tuple> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "google/protobuf/stubs/strutil.h" |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/string_view.h" |
| #include "google/protobuf/io/zero_copy_sink.h" |
| #include "google/protobuf/io/zero_copy_stream.h" |
| #include "google/protobuf/stubs/status_macros.h" |
| |
| // Must be included last. |
| #include "google/protobuf/port_def.inc" |
| |
| namespace google { |
| namespace protobuf { |
| namespace json_internal { |
| struct WriterOptions { |
| // Whether to add spaces, line breaks and indentation to make the JSON output |
| // easy to read. |
| bool add_whitespace = false; |
| // Whether to always print primitive fields. By default proto3 primitive |
| // fields with default values will be omitted in JSON output. For example, an |
| // int32 field set to 0 will be omitted. Set this flag to true will override |
| // the default behavior and print primitive fields regardless of their values. |
| bool always_print_primitive_fields = false; |
| // Whether to always print enums as ints. By default they are rendered as |
| // strings. |
| bool always_print_enums_as_ints = false; |
| // Whether to preserve proto field names |
| bool preserve_proto_field_names = false; |
| // The original parser used by json_util2 accepted a number of non-standard |
| // options. Setting this flag enables them. |
| // |
| // What those extensions were is explicitly not documented, beyond what exists |
| // in the unit tests; we intend to remove this setting eventually. See |
| // b/234868512. |
| bool allow_legacy_syntax = false; |
| }; |
| |
| template <typename Tuple, typename F, size_t... i> |
| void EachInner(const Tuple& value, F f, std::index_sequence<i...>) { |
| int ignored[] = |
| {(f(std::get<i>(value)), 0)...}; // NOLINT(readability/braces) |
| (void)ignored; |
| } |
| |
| // Executes f on each element of value. |
| template <typename Tuple, typename F> |
| void Each(const Tuple& value, F f) { |
| EachInner(value, f, |
| std::make_index_sequence<std::tuple_size<Tuple>::value>()); |
| } |
| |
| // See JsonWriter::Write(). |
| template <typename... T> |
| struct Quoted { |
| std::tuple<T...> value; |
| }; |
| |
| // Because this is not C++17 yet, we cannot add a deduction guide. |
| template <typename... T> |
| static Quoted<T...> MakeQuoted(T... t) { |
| return Quoted<T...>{std::make_tuple(t...)}; |
| } |
| |
| class JsonWriter { |
| public: |
| JsonWriter(io::ZeroCopyOutputStream* out, WriterOptions options) |
| : sink_(out), options_(options) {} |
| |
| const WriterOptions& options() const { return options_; } |
| |
| void Push() { ++indent_; } |
| void Pop() { --indent_; } |
| |
| // The many overloads of Write() will write a value to the underlying stream. |
| // Some values may want to be quoted; the Quoted<> type will automatically add |
| // quotes and escape sequences. |
| // |
| // Note that Write() is not implemented for 64-bit integers, since they |
| // cannot be crisply represented without quotes; use MakeQuoted for that. |
| |
| void Write(absl::string_view str) { sink_.Append(str.data(), str.size()); } |
| |
| void Write(char c) { sink_.Append(&c, 1); } |
| |
| // The precision on this and the following function are completely made-up, |
| // in an attempt to match the behavior of the ESF parser. |
| void Write(double val) { |
| if (!MaybeWriteSpecialFp(val)) { |
| Write(SimpleDtoa(val)); |
| } |
| } |
| |
| void Write(float val) { |
| if (!MaybeWriteSpecialFp(val)) { |
| Write(SimpleFtoa(val)); |
| } |
| } |
| |
| void Write(int32_t val) { |
| char buf[22]; |
| int len = absl::SNPrintF(buf, sizeof(buf), "%d", val); |
| absl::string_view view(buf, static_cast<size_t>(len)); |
| Write(view); |
| } |
| |
| void Write(uint32_t val) { |
| char buf[22]; |
| int len = absl::SNPrintF(buf, sizeof(buf), "%d", val); |
| absl::string_view view(buf, static_cast<size_t>(len)); |
| Write(view); |
| } |
| |
| void Write(int64_t) = delete; |
| void Write(uint64_t) = delete; |
| |
| template <typename... Ts> |
| void Write(Quoted<Ts...> val) { |
| Write('"'); |
| Each(val.value, [this](auto x) { this->WriteQuoted(x); }); |
| Write('"'); |
| } |
| |
| template <typename... Ts> |
| auto Write(Ts... args) -> |
| // This bit of SFINAE avoids this function being called with one argument, |
| // so the other overloads of Write() can be picked up instead. |
| typename std::enable_if<sizeof...(Ts) != 1, void>::type { |
| Each(std::make_tuple(args...), [this](auto x) { this->Write(x); }); |
| } |
| |
| void Whitespace(absl::string_view ws) { |
| if (options_.add_whitespace) { |
| Write(ws); |
| } |
| } |
| |
| void NewLine() { |
| Whitespace("\n"); |
| for (int i = 0; i < indent_; ++i) { |
| Whitespace(" "); |
| } |
| } |
| |
| void WriteComma(bool& is_first) { |
| if (is_first) { |
| is_first = false; |
| return; |
| } |
| Write(","); |
| } |
| |
| void WriteBase64(absl::string_view str); |
| |
| // Returns a buffer that can be re-used throughout a writing session as |
| // variable-length scratch space. |
| std::string& ScratchBuf() { return scratch_buf_; } |
| |
| private: |
| template <typename T> |
| void WriteQuoted(T val) { |
| Write(val); |
| } |
| |
| void WriteQuoted(absl::string_view val) { WriteEscapedUtf8(val); } |
| |
| void WriteQuoted(int64_t val) { |
| char buf[22]; |
| int len = absl::SNPrintF(buf, sizeof(buf), "%d", val); |
| absl::string_view view(buf, static_cast<size_t>(len)); |
| Write(view); |
| } |
| |
| void WriteQuoted(uint64_t val) { |
| char buf[22]; |
| int len = absl::SNPrintF(buf, sizeof(buf), "%d", val); |
| absl::string_view view(buf, static_cast<size_t>(len)); |
| Write(view); |
| } |
| |
| // Tries to write a non-finite double if necessary; returns false if |
| // nothing was written. |
| bool MaybeWriteSpecialFp(double val); |
| |
| void WriteEscapedUtf8(absl::string_view str); |
| void WriteUEscape(uint16_t val); |
| |
| io::zc_sink_internal::ZeroCopyStreamByteSink sink_; |
| WriterOptions options_; |
| int indent_ = 0; |
| |
| std::string scratch_buf_; |
| }; |
| } // namespace json_internal |
| } // namespace protobuf |
| } // namespace google |
| |
| #include "google/protobuf/port_undef.inc" |
| #endif // GOOGLE_PROTOBUF_JSON_INTERNAL_WRITER_H__ |