1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#include <google/protobuf/util/internal/json_objectwriter.h>
32
33#include <cmath>
34#include <cstdint>
35#include <limits>
36
37#include <google/protobuf/stubs/casts.h>
38#include <google/protobuf/stubs/logging.h>
39#include <google/protobuf/stubs/common.h>
40#include <google/protobuf/util/internal/utility.h>
41#include <google/protobuf/stubs/strutil.h>
42#include <google/protobuf/util/internal/json_escaping.h>
43
44namespace google {
45namespace protobuf {
46namespace util {
47namespace converter {
48
49
50JsonObjectWriter::~JsonObjectWriter() {
51 if (element_ && !element_->is_root()) {
52 GOOGLE_LOG(WARNING) << "JsonObjectWriter was not fully closed.";
53 }
54}
55
56JsonObjectWriter* JsonObjectWriter::StartObject(StringPiece name) {
57 WritePrefix(name);
58 WriteChar(c: '{');
59 PushObject();
60 return this;
61}
62
63JsonObjectWriter* JsonObjectWriter::EndObject() {
64 Pop();
65 WriteChar(c: '}');
66 if (element() && element()->is_root()) NewLine();
67 return this;
68}
69
70JsonObjectWriter* JsonObjectWriter::StartList(StringPiece name) {
71 WritePrefix(name);
72 WriteChar(c: '[');
73 PushArray();
74 return this;
75}
76
77JsonObjectWriter* JsonObjectWriter::EndList() {
78 Pop();
79 WriteChar(c: ']');
80 if (element()->is_root()) NewLine();
81 return this;
82}
83
84JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name,
85 bool value) {
86 return RenderSimple(name, value: value ? "true" : "false");
87}
88
89JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name,
90 int32_t value) {
91 return RenderSimple(name, value: StrCat(a: value));
92}
93
94JsonObjectWriter* JsonObjectWriter::RenderUint32(StringPiece name,
95 uint32_t value) {
96 return RenderSimple(name, value: StrCat(a: value));
97}
98
99JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name,
100 int64_t value) {
101 WritePrefix(name);
102 WriteChar(c: '"');
103 WriteRawString(s: StrCat(a: value));
104 WriteChar(c: '"');
105 return this;
106}
107
108JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
109 uint64_t value) {
110 WritePrefix(name);
111 WriteChar(c: '"');
112 WriteRawString(s: StrCat(a: value));
113 WriteChar(c: '"');
114 return this;
115}
116
117JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
118 double value) {
119 if (std::isfinite(x: value)) {
120 return RenderSimple(name, value: SimpleDtoa(value));
121 }
122
123 // Render quoted with NaN/Infinity-aware DoubleAsString.
124 return RenderString(name, value: DoubleAsString(value));
125}
126
127JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name,
128 float value) {
129 if (std::isfinite(x: value)) {
130 return RenderSimple(name, value: SimpleFtoa(value));
131 }
132
133 // Render quoted with NaN/Infinity-aware FloatAsString.
134 return RenderString(name, value: FloatAsString(value));
135}
136
137JsonObjectWriter* JsonObjectWriter::RenderString(StringPiece name,
138 StringPiece value) {
139 WritePrefix(name);
140 WriteChar(c: '"');
141 JsonEscaping::Escape(input: value, output: &sink_);
142 WriteChar(c: '"');
143 return this;
144}
145
146JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name,
147 StringPiece value) {
148 WritePrefix(name);
149 std::string base64;
150
151 if (use_websafe_base64_for_bytes_)
152 WebSafeBase64EscapeWithPadding(src: std::string(value), dest: &base64);
153 else
154 Base64Escape(src: value, dest: &base64);
155
156 WriteChar(c: '"');
157 // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes
158 // directly to the stream, rather than first putting them
159 // into a string and then writing them to the stream.
160 stream_->WriteRaw(buffer: base64.data(), size: base64.size());
161 WriteChar(c: '"');
162 return this;
163}
164
165JsonObjectWriter* JsonObjectWriter::RenderNull(StringPiece name) {
166 return RenderSimple(name, value: "null");
167}
168
169JsonObjectWriter* JsonObjectWriter::RenderNullAsEmpty(StringPiece name) {
170 return RenderSimple(name, value: "");
171}
172
173void JsonObjectWriter::WritePrefix(StringPiece name) {
174 bool not_first = !element()->is_first();
175 if (not_first) WriteChar(c: ',');
176 if (not_first || !element()->is_root()) NewLine();
177 if (!name.empty() || element()->is_json_object()) {
178 WriteChar(c: '"');
179 if (!name.empty()) {
180 JsonEscaping::Escape(input: name, output: &sink_);
181 }
182 WriteRawString(s: "\":");
183 if (!indent_string_.empty()) WriteChar(c: ' ');
184 }
185}
186
187} // namespace converter
188} // namespace util
189} // namespace protobuf
190} // namespace google
191