Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include <string.h>
35 :
36 : #include <grpc/support/port_platform.h>
37 :
38 : #include "src/core/json/json_writer.h"
39 :
40 20829 : static void json_writer_output_char(grpc_json_writer *writer, char c) {
41 20829 : writer->vtable->output_char(writer->userdata, c);
42 20829 : }
43 :
44 27 : static void json_writer_output_string(grpc_json_writer *writer,
45 : const char *str) {
46 27 : writer->vtable->output_string(writer->userdata, str);
47 27 : }
48 :
49 729 : static void json_writer_output_string_with_len(grpc_json_writer *writer,
50 : const char *str, size_t len) {
51 729 : writer->vtable->output_string_with_len(writer->userdata, str, len);
52 729 : }
53 :
54 36 : void grpc_json_writer_init(grpc_json_writer *writer, int indent,
55 : grpc_json_writer_vtable *vtable, void *userdata) {
56 36 : memset(writer, 0, sizeof(*writer));
57 36 : writer->container_empty = 1;
58 36 : writer->indent = indent;
59 36 : writer->vtable = vtable;
60 36 : writer->userdata = userdata;
61 36 : }
62 :
63 1998 : static void json_writer_output_indent(grpc_json_writer *writer) {
64 : static const char spacesstr[] =
65 : " "
66 : " "
67 : " "
68 : " ";
69 :
70 1998 : unsigned spaces = (unsigned)(writer->depth * writer->indent);
71 :
72 1998 : if (writer->indent == 0) return;
73 :
74 900 : if (writer->got_key) {
75 356 : json_writer_output_char(writer, ' ');
76 356 : return;
77 : }
78 :
79 1088 : while (spaces >= (sizeof(spacesstr) - 1)) {
80 0 : json_writer_output_string_with_len(writer, spacesstr,
81 : sizeof(spacesstr) - 1);
82 0 : spaces -= (unsigned)(sizeof(spacesstr) - 1);
83 : }
84 :
85 544 : if (spaces == 0) return;
86 :
87 1080 : json_writer_output_string_with_len(
88 540 : writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
89 : }
90 :
91 967 : static void json_writer_value_end(grpc_json_writer *writer) {
92 967 : if (writer->container_empty) {
93 289 : writer->container_empty = 0;
94 289 : if ((writer->indent == 0) || (writer->depth == 0)) return;
95 116 : json_writer_output_char(writer, '\n');
96 : } else {
97 678 : json_writer_output_char(writer, ',');
98 678 : if (writer->indent == 0) return;
99 310 : json_writer_output_char(writer, '\n');
100 : }
101 : }
102 :
103 50 : static void json_writer_escape_utf16(grpc_json_writer *writer,
104 : gpr_uint16 utf16) {
105 : static const char hex[] = "0123456789abcdef";
106 :
107 50 : json_writer_output_string_with_len(writer, "\\u", 2);
108 50 : json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
109 50 : json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
110 50 : json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
111 50 : json_writer_output_char(writer, hex[(utf16)&0x0f]);
112 50 : }
113 :
114 1318 : static void json_writer_escape_string(grpc_json_writer *writer,
115 : const char *string) {
116 1318 : json_writer_output_char(writer, '"');
117 :
118 : for (;;) {
119 16470 : gpr_uint8 c = (gpr_uint8)*string++;
120 16470 : if (c == 0) {
121 1316 : break;
122 15154 : } else if ((c >= 32) && (c <= 126)) {
123 15101 : if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
124 15101 : json_writer_output_char(writer, (char)c);
125 53 : } else if ((c < 32) || (c == 127)) {
126 9 : switch (c) {
127 : case '\b':
128 0 : json_writer_output_string_with_len(writer, "\\b", 2);
129 0 : break;
130 : case '\f':
131 0 : json_writer_output_string_with_len(writer, "\\f", 2);
132 0 : break;
133 : case '\n':
134 2 : json_writer_output_string_with_len(writer, "\\n", 2);
135 2 : break;
136 : case '\r':
137 1 : json_writer_output_string_with_len(writer, "\\r", 2);
138 1 : break;
139 : case '\t':
140 4 : json_writer_output_string_with_len(writer, "\\t", 2);
141 4 : break;
142 : default:
143 2 : json_writer_escape_utf16(writer, c);
144 2 : break;
145 : }
146 9 : } else {
147 44 : gpr_uint32 utf32 = 0;
148 44 : int extra = 0;
149 : int i;
150 44 : int valid = 1;
151 44 : if ((c & 0xe0) == 0xc0) {
152 28 : utf32 = c & 0x1f;
153 28 : extra = 1;
154 16 : } else if ((c & 0xf0) == 0xe0) {
155 8 : utf32 = c & 0x0f;
156 8 : extra = 2;
157 8 : } else if ((c & 0xf8) == 0xf0) {
158 7 : utf32 = c & 0x07;
159 7 : extra = 3;
160 : } else {
161 1 : break;
162 : }
163 106 : for (i = 0; i < extra; i++) {
164 64 : utf32 <<= 6;
165 64 : c = (gpr_uint8)(*string++);
166 : /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
167 64 : if ((c & 0xc0) != 0x80) {
168 1 : valid = 0;
169 1 : break;
170 : }
171 63 : utf32 |= c & 0x3f;
172 : }
173 43 : if (!valid) break;
174 : /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam.
175 : * Any other range is technically reserved for future usage, so if we
176 : * don't want the software to break in the future, we have to allow
177 : * anything else. The first non-unicode character is 0x110000. */
178 42 : if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000))
179 : break;
180 42 : if (utf32 >= 0x10000) {
181 : /* If utf32 contains a character that is above 0xffff, it needs to be
182 : * broken down into a utf-16 surrogate pair. A surrogate pair is first
183 : * a high surrogate, followed by a low surrogate. Each surrogate holds
184 : * 10 bits of usable data, thus allowing a total of 20 bits of data.
185 : * The high surrogate marker is 0xd800, while the low surrogate marker
186 : * is 0xdc00. The low 10 bits of each will be the usable data.
187 : *
188 : * After re-combining the 20 bits of data, one has to add 0x10000 to
189 : * the resulting value, in order to obtain the original character.
190 : * This is obviously because the range 0x0000 - 0xffff can be written
191 : * without any special trick.
192 : *
193 : * Since 0x10ffff is the highest allowed character, we're working in
194 : * the range 0x00000 - 0xfffff after we decrement it by 0x10000.
195 : * That range is exactly 20 bits.
196 : */
197 6 : utf32 -= 0x10000;
198 6 : json_writer_escape_utf16(writer, (gpr_uint16)(0xd800 | (utf32 >> 10)));
199 6 : json_writer_escape_utf16(writer,
200 6 : (gpr_uint16)(0xdc00 | (utf32 & 0x3ff)));
201 : } else {
202 36 : json_writer_escape_utf16(writer, (gpr_uint16)utf32);
203 : }
204 : }
205 15152 : }
206 :
207 1318 : json_writer_output_char(writer, '"');
208 1318 : }
209 :
210 268 : void grpc_json_writer_container_begins(grpc_json_writer *writer,
211 : grpc_json_type type) {
212 268 : if (!writer->got_key) json_writer_value_end(writer);
213 268 : json_writer_output_indent(writer);
214 268 : json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
215 268 : writer->container_empty = 1;
216 268 : writer->got_key = 0;
217 268 : writer->depth++;
218 268 : }
219 :
220 268 : void grpc_json_writer_container_ends(grpc_json_writer *writer,
221 : grpc_json_type type) {
222 268 : if (writer->indent && !writer->container_empty)
223 116 : json_writer_output_char(writer, '\n');
224 268 : writer->depth--;
225 268 : if (!writer->container_empty) json_writer_output_indent(writer);
226 268 : json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
227 268 : writer->container_empty = 0;
228 268 : writer->got_key = 0;
229 268 : }
230 :
231 778 : void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string) {
232 778 : json_writer_value_end(writer);
233 778 : json_writer_output_indent(writer);
234 778 : json_writer_escape_string(writer, string);
235 778 : json_writer_output_char(writer, ':');
236 778 : writer->got_key = 1;
237 778 : }
238 :
239 27 : void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string) {
240 27 : if (!writer->got_key) json_writer_value_end(writer);
241 27 : json_writer_output_indent(writer);
242 27 : json_writer_output_string(writer, string);
243 27 : writer->got_key = 0;
244 27 : }
245 :
246 132 : void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer,
247 : const char *string, size_t len) {
248 132 : if (!writer->got_key) json_writer_value_end(writer);
249 132 : json_writer_output_indent(writer);
250 132 : json_writer_output_string_with_len(writer, string, len);
251 132 : writer->got_key = 0;
252 132 : }
253 :
254 540 : void grpc_json_writer_value_string(grpc_json_writer *writer,
255 : const char *string) {
256 540 : if (!writer->got_key) json_writer_value_end(writer);
257 540 : json_writer_output_indent(writer);
258 540 : json_writer_escape_string(writer, string);
259 540 : writer->got_key = 0;
260 540 : }
|