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 <math.h>
34
35#include <google/protobuf/stubs/casts.h>
36#include <google/protobuf/stubs/logging.h>
37#include <google/protobuf/stubs/common.h>
38#include <google/protobuf/util/internal/utility.h>
39#include <google/protobuf/util/internal/json_escaping.h>
40#include <google/protobuf/stubs/strutil.h>
41#include <google/protobuf/stubs/mathlimits.h>
42
43namespace google {
44namespace protobuf {
45namespace util {
46namespace converter {
47
48using strings::ArrayByteSource;
49;
50
51JsonObjectWriter::~JsonObjectWriter() {
52  if (!element_->is_root()) {
53    GOOGLE_LOG(WARNING) << "JsonObjectWriter was not fully closed.";
54  }
55}
56
57JsonObjectWriter* JsonObjectWriter::StartObject(StringPiece name) {
58  WritePrefix(name);
59  WriteChar('{');
60  Push();
61  return this;
62}
63
64JsonObjectWriter* JsonObjectWriter::EndObject() {
65  Pop();
66  WriteChar('}');
67  if (element()->is_root()) NewLine();
68  return this;
69}
70
71JsonObjectWriter* JsonObjectWriter::StartList(StringPiece name) {
72  WritePrefix(name);
73  WriteChar('[');
74  Push();
75  return this;
76}
77
78JsonObjectWriter* JsonObjectWriter::EndList() {
79  Pop();
80  WriteChar(']');
81  if (element()->is_root()) NewLine();
82  return this;
83}
84
85JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name, bool value) {
86  return RenderSimple(name, value ? "true" : "false");
87}
88
89JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name, int32 value) {
90  return RenderSimple(name, SimpleItoa(value));
91}
92
93JsonObjectWriter* JsonObjectWriter::RenderUint32(StringPiece name,
94                                                 uint32 value) {
95  return RenderSimple(name, SimpleItoa(value));
96}
97
98JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name, int64 value) {
99  WritePrefix(name);
100  WriteChar('"');
101  stream_->WriteString(SimpleItoa(value));
102  WriteChar('"');
103  return this;
104}
105
106JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
107                                                 uint64 value) {
108  WritePrefix(name);
109  WriteChar('"');
110  stream_->WriteString(SimpleItoa(value));
111  WriteChar('"');
112  return this;
113}
114
115JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
116                                                 double value) {
117  if (MathLimits<double>::IsFinite(value)) {
118    return RenderSimple(name, SimpleDtoa(value));
119  }
120
121  // Render quoted with NaN/Infinity-aware DoubleAsString.
122  return RenderString(name, DoubleAsString(value));
123}
124
125JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, float value) {
126  if (MathLimits<float>::IsFinite(value)) {
127    return RenderSimple(name, SimpleFtoa(value));
128  }
129
130  // Render quoted with NaN/Infinity-aware FloatAsString.
131  return RenderString(name, FloatAsString(value));
132}
133
134JsonObjectWriter* JsonObjectWriter::RenderString(StringPiece name,
135                                                 StringPiece value) {
136  WritePrefix(name);
137  WriteChar('"');
138  ArrayByteSource source(value);
139  JsonEscaping::Escape(&source, &sink_);
140  WriteChar('"');
141  return this;
142}
143
144JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name,
145                                                StringPiece value) {
146  WritePrefix(name);
147  string base64;
148
149  if (use_websafe_base64_for_bytes_)
150    WebSafeBase64Escape(value.ToString(), &base64);
151  else
152    Base64Escape(value, &base64);
153
154  WriteChar('"');
155  // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes
156  //              directly to the stream, rather than first putting them
157  //              into a string and then writing them to the stream.
158  stream_->WriteRaw(base64.data(), base64.size());
159  WriteChar('"');
160  return this;
161}
162
163JsonObjectWriter* JsonObjectWriter::RenderNull(StringPiece name) {
164  return RenderSimple(name, "null");
165}
166
167void JsonObjectWriter::WritePrefix(StringPiece name) {
168  bool not_first = !element()->is_first();
169  if (not_first) WriteChar(',');
170  if (not_first || !element()->is_root()) NewLine();
171  if (!name.empty()) {
172    WriteChar('"');
173    ArrayByteSource source(name);
174    JsonEscaping::Escape(&source, &sink_);
175    stream_->WriteString("\":");
176    if (!indent_string_.empty()) WriteChar(' ');
177  }
178}
179
180}  // namespace converter
181}  // namespace util
182}  // namespace protobuf
183}  // namespace google
184