• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 #include <grpc/support/port_platform.h>
20 
21 #include <string.h>
22 
23 #include "src/core/lib/json/json_writer.h"
24 
json_writer_output_char(grpc_json_writer * writer,char c)25 static void json_writer_output_char(grpc_json_writer* writer, char c) {
26   writer->vtable->output_char(writer->userdata, c);
27 }
28 
json_writer_output_string(grpc_json_writer * writer,const char * str)29 static void json_writer_output_string(grpc_json_writer* writer,
30                                       const char* str) {
31   writer->vtable->output_string(writer->userdata, str);
32 }
33 
json_writer_output_string_with_len(grpc_json_writer * writer,const char * str,size_t len)34 static void json_writer_output_string_with_len(grpc_json_writer* writer,
35                                                const char* str, size_t len) {
36   writer->vtable->output_string_with_len(writer->userdata, str, len);
37 }
38 
grpc_json_writer_init(grpc_json_writer * writer,int indent,grpc_json_writer_vtable * vtable,void * userdata)39 void grpc_json_writer_init(grpc_json_writer* writer, int indent,
40                            grpc_json_writer_vtable* vtable, void* userdata) {
41   memset(writer, 0, sizeof(*writer));
42   writer->container_empty = 1;
43   writer->indent = indent;
44   writer->vtable = vtable;
45   writer->userdata = userdata;
46 }
47 
json_writer_output_indent(grpc_json_writer * writer)48 static void json_writer_output_indent(grpc_json_writer* writer) {
49   static const char spacesstr[] =
50       "                "
51       "                "
52       "                "
53       "                ";
54 
55   unsigned spaces = static_cast<unsigned>(writer->depth * writer->indent);
56 
57   if (writer->indent == 0) return;
58 
59   if (writer->got_key) {
60     json_writer_output_char(writer, ' ');
61     return;
62   }
63 
64   while (spaces >= (sizeof(spacesstr) - 1)) {
65     json_writer_output_string_with_len(writer, spacesstr,
66                                        sizeof(spacesstr) - 1);
67     spaces -= static_cast<unsigned>(sizeof(spacesstr) - 1);
68   }
69 
70   if (spaces == 0) return;
71 
72   json_writer_output_string_with_len(
73       writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
74 }
75 
json_writer_value_end(grpc_json_writer * writer)76 static void json_writer_value_end(grpc_json_writer* writer) {
77   if (writer->container_empty) {
78     writer->container_empty = 0;
79     if ((writer->indent == 0) || (writer->depth == 0)) return;
80     json_writer_output_char(writer, '\n');
81   } else {
82     json_writer_output_char(writer, ',');
83     if (writer->indent == 0) return;
84     json_writer_output_char(writer, '\n');
85   }
86 }
87 
json_writer_escape_utf16(grpc_json_writer * writer,uint16_t utf16)88 static void json_writer_escape_utf16(grpc_json_writer* writer, uint16_t utf16) {
89   static const char hex[] = "0123456789abcdef";
90 
91   json_writer_output_string_with_len(writer, "\\u", 2);
92   json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
93   json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
94   json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
95   json_writer_output_char(writer, hex[(utf16)&0x0f]);
96 }
97 
json_writer_escape_string(grpc_json_writer * writer,const char * string)98 static void json_writer_escape_string(grpc_json_writer* writer,
99                                       const char* string) {
100   json_writer_output_char(writer, '"');
101 
102   for (;;) {
103     uint8_t c = static_cast<uint8_t>(*string++);
104     if (c == 0) {
105       break;
106     } else if ((c >= 32) && (c <= 126)) {
107       if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
108       json_writer_output_char(writer, static_cast<char>(c));
109     } else if ((c < 32) || (c == 127)) {
110       switch (c) {
111         case '\b':
112           json_writer_output_string_with_len(writer, "\\b", 2);
113           break;
114         case '\f':
115           json_writer_output_string_with_len(writer, "\\f", 2);
116           break;
117         case '\n':
118           json_writer_output_string_with_len(writer, "\\n", 2);
119           break;
120         case '\r':
121           json_writer_output_string_with_len(writer, "\\r", 2);
122           break;
123         case '\t':
124           json_writer_output_string_with_len(writer, "\\t", 2);
125           break;
126         default:
127           json_writer_escape_utf16(writer, c);
128           break;
129       }
130     } else {
131       uint32_t utf32 = 0;
132       int extra = 0;
133       int i;
134       int valid = 1;
135       if ((c & 0xe0) == 0xc0) {
136         utf32 = c & 0x1f;
137         extra = 1;
138       } else if ((c & 0xf0) == 0xe0) {
139         utf32 = c & 0x0f;
140         extra = 2;
141       } else if ((c & 0xf8) == 0xf0) {
142         utf32 = c & 0x07;
143         extra = 3;
144       } else {
145         break;
146       }
147       for (i = 0; i < extra; i++) {
148         utf32 <<= 6;
149         c = static_cast<uint8_t>(*string++);
150         /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
151         if ((c & 0xc0) != 0x80) {
152           valid = 0;
153           break;
154         }
155         utf32 |= c & 0x3f;
156       }
157       if (!valid) break;
158       /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam.
159        * Any other range is technically reserved for future usage, so if we
160        * don't want the software to break in the future, we have to allow
161        * anything else. The first non-unicode character is 0x110000. */
162       if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000))
163         break;
164       if (utf32 >= 0x10000) {
165         /* If utf32 contains a character that is above 0xffff, it needs to be
166          * broken down into a utf-16 surrogate pair. A surrogate pair is first
167          * a high surrogate, followed by a low surrogate. Each surrogate holds
168          * 10 bits of usable data, thus allowing a total of 20 bits of data.
169          * The high surrogate marker is 0xd800, while the low surrogate marker
170          * is 0xdc00. The low 10 bits of each will be the usable data.
171          *
172          * After re-combining the 20 bits of data, one has to add 0x10000 to
173          * the resulting value, in order to obtain the original character.
174          * This is obviously because the range 0x0000 - 0xffff can be written
175          * without any special trick.
176          *
177          * Since 0x10ffff is the highest allowed character, we're working in
178          * the range 0x00000 - 0xfffff after we decrement it by 0x10000.
179          * That range is exactly 20 bits.
180          */
181         utf32 -= 0x10000;
182         json_writer_escape_utf16(writer,
183                                  static_cast<uint16_t>(0xd800 | (utf32 >> 10)));
184         json_writer_escape_utf16(
185             writer, static_cast<uint16_t>(0xdc00 | (utf32 & 0x3ff)));
186       } else {
187         json_writer_escape_utf16(writer, static_cast<uint16_t>(utf32));
188       }
189     }
190   }
191 
192   json_writer_output_char(writer, '"');
193 }
194 
grpc_json_writer_container_begins(grpc_json_writer * writer,grpc_json_type type)195 void grpc_json_writer_container_begins(grpc_json_writer* writer,
196                                        grpc_json_type type) {
197   if (!writer->got_key) json_writer_value_end(writer);
198   json_writer_output_indent(writer);
199   json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
200   writer->container_empty = 1;
201   writer->got_key = 0;
202   writer->depth++;
203 }
204 
grpc_json_writer_container_ends(grpc_json_writer * writer,grpc_json_type type)205 void grpc_json_writer_container_ends(grpc_json_writer* writer,
206                                      grpc_json_type type) {
207   if (writer->indent && !writer->container_empty)
208     json_writer_output_char(writer, '\n');
209   writer->depth--;
210   if (!writer->container_empty) json_writer_output_indent(writer);
211   json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
212   writer->container_empty = 0;
213   writer->got_key = 0;
214 }
215 
grpc_json_writer_object_key(grpc_json_writer * writer,const char * string)216 void grpc_json_writer_object_key(grpc_json_writer* writer, const char* string) {
217   json_writer_value_end(writer);
218   json_writer_output_indent(writer);
219   json_writer_escape_string(writer, string);
220   json_writer_output_char(writer, ':');
221   writer->got_key = 1;
222 }
223 
grpc_json_writer_value_raw(grpc_json_writer * writer,const char * string)224 void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string) {
225   if (!writer->got_key) json_writer_value_end(writer);
226   json_writer_output_indent(writer);
227   json_writer_output_string(writer, string);
228   writer->got_key = 0;
229 }
230 
grpc_json_writer_value_raw_with_len(grpc_json_writer * writer,const char * string,size_t len)231 void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer,
232                                          const char* string, size_t len) {
233   if (!writer->got_key) json_writer_value_end(writer);
234   json_writer_output_indent(writer);
235   json_writer_output_string_with_len(writer, string, len);
236   writer->got_key = 0;
237 }
238 
grpc_json_writer_value_string(grpc_json_writer * writer,const char * string)239 void grpc_json_writer_value_string(grpc_json_writer* writer,
240                                    const char* string) {
241   if (!writer->got_key) json_writer_value_end(writer);
242   json_writer_output_indent(writer);
243   json_writer_escape_string(writer, string);
244   writer->got_key = 0;
245 }
246