Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(822)

Side by Side Diff: third_party/grpc/src/core/json/json_string.c

Issue 1932353002: Initial checkin of gRPC to third_party/ Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 #include <stdlib.h>
36
37 #include <grpc/support/alloc.h>
38 #include <grpc/support/log.h>
39
40 #include "src/core/json/json.h"
41 #include "src/core/json/json_reader.h"
42 #include "src/core/json/json_writer.h"
43
44 /* The json reader will construct a bunch of grpc_json objects and
45 * link them all up together in a tree-like structure that will represent
46 * the json data in memory.
47 *
48 * It also uses its own input as a scratchpad to store all of the decoded,
49 * unescaped strings. So we need to keep track of all these pointers in
50 * that opaque structure the reader will carry for us.
51 *
52 * Note that this works because the act of parsing json always reduces its
53 * input size, and never expands it.
54 */
55 typedef struct {
56 grpc_json *top;
57 grpc_json *current_container;
58 grpc_json *current_value;
59 uint8_t *input;
60 uint8_t *key;
61 uint8_t *string;
62 uint8_t *string_ptr;
63 size_t remaining_input;
64 } json_reader_userdata;
65
66 /* This json writer will put everything in a big string.
67 * The point is that we allocate that string in chunks of 256 bytes.
68 */
69 typedef struct {
70 char *output;
71 size_t free_space;
72 size_t string_len;
73 size_t allocated;
74 } json_writer_userdata;
75
76 /* This function checks if there's enough space left in the output buffer,
77 * and will enlarge it if necessary. We're only allocating chunks of 256
78 * bytes at a time (or multiples thereof).
79 */
80 static void json_writer_output_check(void *userdata, size_t needed) {
81 json_writer_userdata *state = userdata;
82 if (state->free_space >= needed) return;
83 needed -= state->free_space;
84 /* Round up by 256 bytes. */
85 needed = (needed + 0xff) & ~0xffU;
86 state->output = gpr_realloc(state->output, state->allocated + needed);
87 state->free_space += needed;
88 state->allocated += needed;
89 }
90
91 /* These are needed by the writer's implementation. */
92 static void json_writer_output_char(void *userdata, char c) {
93 json_writer_userdata *state = userdata;
94 json_writer_output_check(userdata, 1);
95 state->output[state->string_len++] = c;
96 state->free_space--;
97 }
98
99 static void json_writer_output_string_with_len(void *userdata, const char *str,
100 size_t len) {
101 json_writer_userdata *state = userdata;
102 json_writer_output_check(userdata, len);
103 memcpy(state->output + state->string_len, str, len);
104 state->string_len += len;
105 state->free_space -= len;
106 }
107
108 static void json_writer_output_string(void *userdata, const char *str) {
109 size_t len = strlen(str);
110 json_writer_output_string_with_len(userdata, str, len);
111 }
112
113 /* The reader asks us to clear our scratchpad. In our case, we'll simply mark
114 * the end of the current string, and advance our output pointer.
115 */
116 static void json_reader_string_clear(void *userdata) {
117 json_reader_userdata *state = userdata;
118 if (state->string) {
119 GPR_ASSERT(state->string_ptr < state->input);
120 *state->string_ptr++ = 0;
121 }
122 state->string = state->string_ptr;
123 }
124
125 static void json_reader_string_add_char(void *userdata, uint32_t c) {
126 json_reader_userdata *state = userdata;
127 GPR_ASSERT(state->string_ptr < state->input);
128 GPR_ASSERT(c <= 0xff);
129 *state->string_ptr++ = (uint8_t)c;
130 }
131
132 /* We are converting a UTF-32 character into UTF-8 here,
133 * as described by RFC3629.
134 */
135 static void json_reader_string_add_utf32(void *userdata, uint32_t c) {
136 if (c <= 0x7f) {
137 json_reader_string_add_char(userdata, c);
138 } else if (c <= 0x7ff) {
139 uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f);
140 uint32_t b2 = 0x80 | (c & 0x3f);
141 json_reader_string_add_char(userdata, b1);
142 json_reader_string_add_char(userdata, b2);
143 } else if (c <= 0xffff) {
144 uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f);
145 uint32_t b2 = 0x80 | ((c >> 6) & 0x3f);
146 uint32_t b3 = 0x80 | (c & 0x3f);
147 json_reader_string_add_char(userdata, b1);
148 json_reader_string_add_char(userdata, b2);
149 json_reader_string_add_char(userdata, b3);
150 } else if (c <= 0x1fffff) {
151 uint32_t b1 = 0xf0 | ((c >> 18) & 0x07);
152 uint32_t b2 = 0x80 | ((c >> 12) & 0x3f);
153 uint32_t b3 = 0x80 | ((c >> 6) & 0x3f);
154 uint32_t b4 = 0x80 | (c & 0x3f);
155 json_reader_string_add_char(userdata, b1);
156 json_reader_string_add_char(userdata, b2);
157 json_reader_string_add_char(userdata, b3);
158 json_reader_string_add_char(userdata, b4);
159 }
160 }
161
162 /* We consider that the input may be a zero-terminated string. So we
163 * can end up hitting eof before the end of the alleged string length.
164 */
165 static uint32_t json_reader_read_char(void *userdata) {
166 uint32_t r;
167 json_reader_userdata *state = userdata;
168
169 if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF;
170
171 r = *state->input++;
172 state->remaining_input--;
173
174 if (r == 0) {
175 state->remaining_input = 0;
176 return GRPC_JSON_READ_CHAR_EOF;
177 }
178
179 return r;
180 }
181
182 /* Helper function to create a new grpc_json object and link it into
183 * our tree-in-progress inside our opaque structure.
184 */
185 static grpc_json *json_create_and_link(void *userdata, grpc_json_type type) {
186 json_reader_userdata *state = userdata;
187 grpc_json *json = grpc_json_create(type);
188
189 json->parent = state->current_container;
190 json->prev = state->current_value;
191 state->current_value = json;
192
193 if (json->prev) {
194 json->prev->next = json;
195 }
196 if (json->parent) {
197 if (!json->parent->child) {
198 json->parent->child = json;
199 }
200 if (json->parent->type == GRPC_JSON_OBJECT) {
201 json->key = (char *)state->key;
202 }
203 }
204 if (!state->top) {
205 state->top = json;
206 }
207
208 return json;
209 }
210
211 static void json_reader_container_begins(void *userdata, grpc_json_type type) {
212 json_reader_userdata *state = userdata;
213 grpc_json *container;
214
215 GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
216
217 container = json_create_and_link(userdata, type);
218 state->current_container = container;
219 state->current_value = NULL;
220 }
221
222 /* It's important to remember that the reader is mostly stateless, so it
223 * isn't trying to remember what the container was prior the one that just
224 * ends. Since we're keeping track of these for our own purpose, we are
225 * able to return that information back, which is useful for it to validate
226 * the input json stream.
227 *
228 * Also note that if we're at the top of the tree, and the last container
229 * ends, we have to return GRPC_JSON_TOP_LEVEL.
230 */
231 static grpc_json_type json_reader_container_ends(void *userdata) {
232 grpc_json_type container_type = GRPC_JSON_TOP_LEVEL;
233 json_reader_userdata *state = userdata;
234
235 GPR_ASSERT(state->current_container);
236
237 state->current_value = state->current_container;
238 state->current_container = state->current_container->parent;
239
240 if (state->current_container) {
241 container_type = state->current_container->type;
242 }
243
244 return container_type;
245 }
246
247 /* The next 3 functions basically are the reader asking us to use our string
248 * scratchpad for one of these 3 purposes.
249 *
250 * Note that in the set_number case, we're not going to try interpreting it.
251 * We'll keep it as a string, and leave it to the caller to evaluate it.
252 */
253 static void json_reader_set_key(void *userdata) {
254 json_reader_userdata *state = userdata;
255 state->key = state->string;
256 }
257
258 static void json_reader_set_string(void *userdata) {
259 json_reader_userdata *state = userdata;
260 grpc_json *json = json_create_and_link(userdata, GRPC_JSON_STRING);
261 json->value = (char *)state->string;
262 }
263
264 static int json_reader_set_number(void *userdata) {
265 json_reader_userdata *state = userdata;
266 grpc_json *json = json_create_and_link(userdata, GRPC_JSON_NUMBER);
267 json->value = (char *)state->string;
268 return 1;
269 }
270
271 /* The object types true, false and null are self-sufficient, and don't need
272 * any more information beside their type.
273 */
274 static void json_reader_set_true(void *userdata) {
275 json_create_and_link(userdata, GRPC_JSON_TRUE);
276 }
277
278 static void json_reader_set_false(void *userdata) {
279 json_create_and_link(userdata, GRPC_JSON_FALSE);
280 }
281
282 static void json_reader_set_null(void *userdata) {
283 json_create_and_link(userdata, GRPC_JSON_NULL);
284 }
285
286 static grpc_json_reader_vtable reader_vtable = {
287 json_reader_string_clear, json_reader_string_add_char,
288 json_reader_string_add_utf32, json_reader_read_char,
289 json_reader_container_begins, json_reader_container_ends,
290 json_reader_set_key, json_reader_set_string,
291 json_reader_set_number, json_reader_set_true,
292 json_reader_set_false, json_reader_set_null};
293
294 /* And finally, let's define our public API. */
295 grpc_json *grpc_json_parse_string_with_len(char *input, size_t size) {
296 grpc_json_reader reader;
297 json_reader_userdata state;
298 grpc_json *json = NULL;
299 grpc_json_reader_status status;
300
301 if (!input) return NULL;
302
303 state.top = state.current_container = state.current_value = NULL;
304 state.string = state.key = NULL;
305 state.string_ptr = state.input = (uint8_t *)input;
306 state.remaining_input = size;
307 grpc_json_reader_init(&reader, &reader_vtable, &state);
308
309 status = grpc_json_reader_run(&reader);
310 json = state.top;
311
312 if ((status != GRPC_JSON_DONE) && json) {
313 grpc_json_destroy(json);
314 json = NULL;
315 }
316
317 return json;
318 }
319
320 #define UNBOUND_JSON_STRING_LENGTH 0x7fffffff
321
322 grpc_json *grpc_json_parse_string(char *input) {
323 return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
324 }
325
326 static void json_dump_recursive(grpc_json_writer *writer, grpc_json *json,
327 int in_object) {
328 while (json) {
329 if (in_object) grpc_json_writer_object_key(writer, json->key);
330
331 switch (json->type) {
332 case GRPC_JSON_OBJECT:
333 case GRPC_JSON_ARRAY:
334 grpc_json_writer_container_begins(writer, json->type);
335 if (json->child)
336 json_dump_recursive(writer, json->child,
337 json->type == GRPC_JSON_OBJECT);
338 grpc_json_writer_container_ends(writer, json->type);
339 break;
340 case GRPC_JSON_STRING:
341 grpc_json_writer_value_string(writer, json->value);
342 break;
343 case GRPC_JSON_NUMBER:
344 grpc_json_writer_value_raw(writer, json->value);
345 break;
346 case GRPC_JSON_TRUE:
347 grpc_json_writer_value_raw_with_len(writer, "true", 4);
348 break;
349 case GRPC_JSON_FALSE:
350 grpc_json_writer_value_raw_with_len(writer, "false", 5);
351 break;
352 case GRPC_JSON_NULL:
353 grpc_json_writer_value_raw_with_len(writer, "null", 4);
354 break;
355 default:
356 GPR_UNREACHABLE_CODE(abort());
357 }
358 json = json->next;
359 }
360 }
361
362 static grpc_json_writer_vtable writer_vtable = {
363 json_writer_output_char, json_writer_output_string,
364 json_writer_output_string_with_len};
365
366 char *grpc_json_dump_to_string(grpc_json *json, int indent) {
367 grpc_json_writer writer;
368 json_writer_userdata state;
369
370 state.output = NULL;
371 state.free_space = state.string_len = state.allocated = 0;
372 grpc_json_writer_init(&writer, indent, &writer_vtable, &state);
373
374 json_dump_recursive(&writer, json, 0);
375
376 json_writer_output_char(&state, 0);
377
378 return state.output;
379 }
OLDNEW
« no previous file with comments | « third_party/grpc/src/core/json/json_reader.c ('k') | third_party/grpc/src/core/json/json_writer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698