json_writer.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
20 
21 #include <stdint.h>
22 #include <stdlib.h>
23 
24 #include <map>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 #include "absl/strings/string_view.h"
30 
31 #include "src/core/lib/json/json.h"
32 
33 namespace grpc_core {
34 
35 namespace {
36 
37 /* The idea of the writer is basically symmetrical of the reader. While the
38  * reader emits various calls to your code, the writer takes basically the
39  * same calls and emit json out of it. It doesn't try to make any check on
40  * the order of the calls you do on it. Meaning you can theorically force
41  * it to generate invalid json.
42  *
43  * Also, unlike the reader, the writer expects UTF-8 encoded input strings.
44  * These strings will be UTF-8 validated, and any invalid character will
45  * cut the conversion short, before any invalid UTF-8 sequence, thus forming
46  * a valid UTF-8 string overall.
47  */
48 class JsonWriter {
49  public:
50  static std::string Dump(const Json& value, int indent);
51 
52  private:
53  explicit JsonWriter(int indent) : indent_(indent) {}
54 
55  void OutputCheck(size_t needed);
56  void OutputChar(char c);
57  void OutputString(const absl::string_view str);
58  void OutputIndent();
59  void ValueEnd();
60  void EscapeUtf16(uint16_t utf16);
61  void EscapeString(const std::string& string);
62  void ContainerBegins(Json::Type type);
63  void ContainerEnds(Json::Type type);
64  void ObjectKey(const std::string& string);
65  void ValueRaw(const std::string& string);
66  void ValueString(const std::string& string);
67 
68  void DumpObject(const Json::Object& object);
69  void DumpArray(const Json::Array& array);
70  void DumpValue(const Json& value);
71 
72  int indent_;
73  int depth_ = 0;
74  bool container_empty_ = true;
75  bool got_key_ = false;
77 };
78 
79 /* This function checks if there's enough space left in the output buffer,
80  * and will enlarge it if necessary. We're only allocating chunks of 256
81  * bytes at a time (or multiples thereof).
82  */
83 void JsonWriter::OutputCheck(size_t needed) {
84  size_t free_space = output_.capacity() - output_.size();
85  if (free_space >= needed) return;
86  needed -= free_space;
87  /* Round up by 256 bytes. */
88  needed = (needed + 0xff) & ~0xffU;
89  output_.reserve(output_.capacity() + needed);
90 }
91 
92 void JsonWriter::OutputChar(char c) {
93  OutputCheck(1);
94  output_.push_back(c);
95 }
96 
97 void JsonWriter::OutputString(const absl::string_view str) {
98  OutputCheck(str.size());
99  output_.append(str.data(), str.size());
100 }
101 
102 void JsonWriter::OutputIndent() {
103  static const char spacesstr[] =
104  " "
105  " "
106  " "
107  " ";
108  unsigned spaces = static_cast<unsigned>(depth_ * indent_);
109  if (indent_ == 0) return;
110  if (got_key_) {
111  OutputChar(' ');
112  return;
113  }
114  while (spaces >= (sizeof(spacesstr) - 1)) {
115  OutputString(absl::string_view(spacesstr, sizeof(spacesstr) - 1));
116  spaces -= static_cast<unsigned>(sizeof(spacesstr) - 1);
117  }
118  if (spaces == 0) return;
119  OutputString(
120  absl::string_view(spacesstr + sizeof(spacesstr) - 1 - spaces, spaces));
121 }
122 
123 void JsonWriter::ValueEnd() {
124  if (container_empty_) {
125  container_empty_ = false;
126  if (indent_ == 0 || depth_ == 0) return;
127  OutputChar('\n');
128  } else {
129  OutputChar(',');
130  if (indent_ == 0) return;
131  OutputChar('\n');
132  }
133 }
134 
135 void JsonWriter::EscapeUtf16(uint16_t utf16) {
136  static const char hex[] = "0123456789abcdef";
137  OutputString(absl::string_view("\\u", 2));
138  OutputChar(hex[(utf16 >> 12) & 0x0f]);
139  OutputChar(hex[(utf16 >> 8) & 0x0f]);
140  OutputChar(hex[(utf16 >> 4) & 0x0f]);
141  OutputChar(hex[(utf16)&0x0f]);
142 }
143 
144 void JsonWriter::EscapeString(const std::string& string) {
145  OutputChar('"');
146  for (size_t idx = 0; idx < string.size(); ++idx) {
147  uint8_t c = static_cast<uint8_t>(string[idx]);
148  if (c == 0) {
149  break;
150  } else if (c >= 32 && c <= 126) {
151  if (c == '\\' || c == '"') OutputChar('\\');
152  OutputChar(static_cast<char>(c));
153  } else if (c < 32 || c == 127) {
154  switch (c) {
155  case '\b':
156  OutputString(absl::string_view("\\b", 2));
157  break;
158  case '\f':
159  OutputString(absl::string_view("\\f", 2));
160  break;
161  case '\n':
162  OutputString(absl::string_view("\\n", 2));
163  break;
164  case '\r':
165  OutputString(absl::string_view("\\r", 2));
166  break;
167  case '\t':
168  OutputString(absl::string_view("\\t", 2));
169  break;
170  default:
171  EscapeUtf16(c);
172  break;
173  }
174  } else {
175  uint32_t utf32 = 0;
176  int extra = 0;
177  int i;
178  int valid = 1;
179  if ((c & 0xe0) == 0xc0) {
180  utf32 = c & 0x1f;
181  extra = 1;
182  } else if ((c & 0xf0) == 0xe0) {
183  utf32 = c & 0x0f;
184  extra = 2;
185  } else if ((c & 0xf8) == 0xf0) {
186  utf32 = c & 0x07;
187  extra = 3;
188  } else {
189  break;
190  }
191  for (i = 0; i < extra; i++) {
192  utf32 <<= 6;
193  ++idx;
194  /* Breaks out and bail if we hit the end of the string. */
195  if (idx == string.size()) {
196  valid = 0;
197  break;
198  }
199  c = static_cast<uint8_t>(string[idx]);
200  /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
201  if ((c & 0xc0) != 0x80) {
202  valid = 0;
203  break;
204  }
205  utf32 |= c & 0x3f;
206  }
207  if (!valid) break;
208  /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam.
209  * Any other range is technically reserved for future usage, so if we
210  * don't want the software to break in the future, we have to allow
211  * anything else. The first non-unicode character is 0x110000. */
212  if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000)) {
213  break;
214  }
215  if (utf32 >= 0x10000) {
216  /* If utf32 contains a character that is above 0xffff, it needs to be
217  * broken down into a utf-16 surrogate pair. A surrogate pair is first
218  * a high surrogate, followed by a low surrogate. Each surrogate holds
219  * 10 bits of usable data, thus allowing a total of 20 bits of data.
220  * The high surrogate marker is 0xd800, while the low surrogate marker
221  * is 0xdc00. The low 10 bits of each will be the usable data.
222  *
223  * After re-combining the 20 bits of data, one has to add 0x10000 to
224  * the resulting value, in order to obtain the original character.
225  * This is obviously because the range 0x0000 - 0xffff can be written
226  * without any special trick.
227  *
228  * Since 0x10ffff is the highest allowed character, we're working in
229  * the range 0x00000 - 0xfffff after we decrement it by 0x10000.
230  * That range is exactly 20 bits.
231  */
232  utf32 -= 0x10000;
233  EscapeUtf16(static_cast<uint16_t>(0xd800 | (utf32 >> 10)));
234  EscapeUtf16(static_cast<uint16_t>(0xdc00 | (utf32 & 0x3ff)));
235  } else {
236  EscapeUtf16(static_cast<uint16_t>(utf32));
237  }
238  }
239  }
240  OutputChar('"');
241 }
242 
243 void JsonWriter::ContainerBegins(Json::Type type) {
244  if (!got_key_) ValueEnd();
245  OutputIndent();
246  OutputChar(type == Json::Type::OBJECT ? '{' : '[');
247  container_empty_ = true;
248  got_key_ = false;
249  depth_++;
250 }
251 
252 void JsonWriter::ContainerEnds(Json::Type type) {
253  if (indent_ && !container_empty_) OutputChar('\n');
254  depth_--;
255  if (!container_empty_) OutputIndent();
256  OutputChar(type == Json::Type::OBJECT ? '}' : ']');
257  container_empty_ = false;
258  got_key_ = false;
259 }
260 
261 void JsonWriter::ObjectKey(const std::string& string) {
262  ValueEnd();
263  OutputIndent();
264  EscapeString(string);
265  OutputChar(':');
266  got_key_ = true;
267 }
268 
269 void JsonWriter::ValueRaw(const std::string& string) {
270  if (!got_key_) ValueEnd();
271  OutputIndent();
272  OutputString(string);
273  got_key_ = false;
274 }
275 
276 void JsonWriter::ValueString(const std::string& string) {
277  if (!got_key_) ValueEnd();
278  OutputIndent();
279  EscapeString(string);
280  got_key_ = false;
281 }
282 
283 void JsonWriter::DumpObject(const Json::Object& object) {
284  ContainerBegins(Json::Type::OBJECT);
285  for (const auto& p : object) {
286  ObjectKey(p.first.data());
287  DumpValue(p.second);
288  }
289  ContainerEnds(Json::Type::OBJECT);
290 }
291 
292 void JsonWriter::DumpArray(const Json::Array& array) {
293  ContainerBegins(Json::Type::ARRAY);
294  for (const auto& v : array) {
295  DumpValue(v);
296  }
297  ContainerEnds(Json::Type::ARRAY);
298 }
299 
300 void JsonWriter::DumpValue(const Json& value) {
301  switch (value.type()) {
302  case Json::Type::OBJECT:
303  DumpObject(value.object_value());
304  break;
305  case Json::Type::ARRAY:
306  DumpArray(value.array_value());
307  break;
308  case Json::Type::STRING:
309  ValueString(value.string_value());
310  break;
311  case Json::Type::NUMBER:
312  ValueRaw(value.string_value());
313  break;
315  ValueRaw(std::string("true", 4));
316  break;
318  ValueRaw(std::string("false", 5));
319  break;
321  ValueRaw(std::string("null", 4));
322  break;
323  default:
324  GPR_UNREACHABLE_CODE(abort());
325  }
326 }
327 
329  JsonWriter writer(indent);
330  writer.DumpValue(value);
331  return std::move(writer.output_);
332 }
333 
334 } // namespace
335 
337  return JsonWriter::Dump(*this, indent);
338 }
339 
340 } // namespace grpc_core
grpc_core::Json::Array
std::vector< Json > Array
Definition: src/core/lib/json/json.h:55
xds_interop_client.str
str
Definition: xds_interop_client.py:487
grpc_core::Json::Type::JSON_TRUE
@ JSON_TRUE
fix_build_deps.c
list c
Definition: fix_build_deps.py:490
grpc_core::Json::Type::OBJECT
@ OBJECT
uint16_t
unsigned short uint16_t
Definition: stdint-msvc2008.h:79
grpc_core
Definition: call_metric_recorder.h:31
container_empty_
bool container_empty_
Definition: json_writer.cc:74
re2::Dump
static void Dump(StringPiece pattern, Regexp::ParseFlags flags, std::string *forward, std::string *reverse)
Definition: bloaty/third_party/re2/re2/testing/compile_test.cc:242
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
xds_manager.p
p
Definition: xds_manager.py:60
python_utils.upload_rbe_results.indent
indent
Definition: upload_rbe_results.py:183
grpc_core::Json::Type::JSON_FALSE
@ JSON_FALSE
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
grpc_core::Json::Type
Type
Definition: src/core/lib/json/json.h:44
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
array
Definition: undname.c:101
Json
JSON (JavaScript Object Notation).
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:227
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
valid
@ valid
Definition: base64_test.cc:37
depth_
int depth_
Definition: json_writer.cc:73
grpc_core::Json::Type::NUMBER
@ NUMBER
grpc_core::Json::Type::ARRAY
@ ARRAY
indent_
int indent_
Definition: json_writer.cc:72
json.h
GPR_UNREACHABLE_CODE
#define GPR_UNREACHABLE_CODE(STATEMENT)
Definition: impl/codegen/port_platform.h:652
stdint.h
setup.idx
idx
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:197
writer
void writer(void *n)
Definition: libuv/docs/code/locks/main.c:22
value
const char * value
Definition: hpack_parser_table.cc:165
output_
std::string output_
Definition: json_writer.cc:76
grpc_core::Json::Object
std::map< std::string, Json > Object
Definition: src/core/lib/json/json.h:54
absl::chars_format::hex
@ hex
grpc_core::Json::Type::JSON_NULL
@ JSON_NULL
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
got_key_
bool got_key_
Definition: json_writer.cc:75
grpc_core::Json::Dump
std::string Dump(int indent=0) const
Definition: json_writer.cc:336
grpc_core::Json::Type::STRING
@ STRING
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
port_platform.h


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:00:26