The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
660 lines
22 KiB
660 lines
22 KiB
/* |
|
* |
|
* Copyright 2015, Google Inc. |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are |
|
* met: |
|
* |
|
* * Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* * Redistributions in binary form must reproduce the above |
|
* copyright notice, this list of conditions and the following disclaimer |
|
* in the documentation and/or other materials provided with the |
|
* distribution. |
|
* * Neither the name of Google Inc. nor the names of its |
|
* contributors may be used to endorse or promote products derived from |
|
* this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
* |
|
*/ |
|
|
|
#include <string.h> |
|
|
|
#include <grpc/support/port_platform.h> |
|
|
|
#include <grpc/support/log.h> |
|
|
|
#include "src/core/json/json_reader.h" |
|
|
|
static void json_reader_string_clear(grpc_json_reader *reader) { |
|
reader->vtable->string_clear(reader->userdata); |
|
} |
|
|
|
static void json_reader_string_add_char(grpc_json_reader *reader, |
|
gpr_uint32 c) { |
|
reader->vtable->string_add_char(reader->userdata, c); |
|
} |
|
|
|
static void json_reader_string_add_utf32(grpc_json_reader *reader, |
|
gpr_uint32 utf32) { |
|
reader->vtable->string_add_utf32(reader->userdata, utf32); |
|
} |
|
|
|
static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader *reader) { |
|
return reader->vtable->read_char(reader->userdata); |
|
} |
|
|
|
static void json_reader_container_begins(grpc_json_reader *reader, |
|
grpc_json_type type) { |
|
reader->vtable->container_begins(reader->userdata, type); |
|
} |
|
|
|
static grpc_json_type grpc_json_reader_container_ends( |
|
grpc_json_reader *reader) { |
|
return reader->vtable->container_ends(reader->userdata); |
|
} |
|
|
|
static void json_reader_set_key(grpc_json_reader *reader) { |
|
reader->vtable->set_key(reader->userdata); |
|
} |
|
|
|
static void json_reader_set_string(grpc_json_reader *reader) { |
|
reader->vtable->set_string(reader->userdata); |
|
} |
|
|
|
static int json_reader_set_number(grpc_json_reader *reader) { |
|
return reader->vtable->set_number(reader->userdata); |
|
} |
|
|
|
static void json_reader_set_true(grpc_json_reader *reader) { |
|
reader->vtable->set_true(reader->userdata); |
|
} |
|
|
|
static void json_reader_set_false(grpc_json_reader *reader) { |
|
reader->vtable->set_false(reader->userdata); |
|
} |
|
|
|
static void json_reader_set_null(grpc_json_reader *reader) { |
|
reader->vtable->set_null(reader->userdata); |
|
} |
|
|
|
/* Call this function to initialize the reader structure. */ |
|
void grpc_json_reader_init(grpc_json_reader *reader, |
|
grpc_json_reader_vtable *vtable, void *userdata) { |
|
memset(reader, 0, sizeof(*reader)); |
|
reader->vtable = vtable; |
|
reader->userdata = userdata; |
|
json_reader_string_clear(reader); |
|
reader->state = GRPC_JSON_STATE_VALUE_BEGIN; |
|
} |
|
|
|
int grpc_json_reader_is_complete(grpc_json_reader *reader) { |
|
return ((reader->depth == 0) && |
|
((reader->state == GRPC_JSON_STATE_END) || |
|
(reader->state == GRPC_JSON_STATE_VALUE_END))); |
|
} |
|
|
|
grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) { |
|
gpr_uint32 c, success; |
|
|
|
/* This state-machine is a strict implementation of ECMA-404 */ |
|
for (;;) { |
|
c = grpc_json_reader_read_char(reader); |
|
switch (c) { |
|
/* Let's process the error cases first. */ |
|
case GRPC_JSON_READ_CHAR_ERROR: |
|
return GRPC_JSON_READ_ERROR; |
|
|
|
case GRPC_JSON_READ_CHAR_EAGAIN: |
|
return GRPC_JSON_EAGAIN; |
|
|
|
case GRPC_JSON_READ_CHAR_EOF: |
|
if (grpc_json_reader_is_complete(reader)) { |
|
return GRPC_JSON_DONE; |
|
} else { |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
/* Processing whitespaces. */ |
|
case ' ': |
|
case '\t': |
|
case '\n': |
|
case '\r': |
|
switch (reader->state) { |
|
case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: |
|
case GRPC_JSON_STATE_OBJECT_KEY_END: |
|
case GRPC_JSON_STATE_VALUE_BEGIN: |
|
case GRPC_JSON_STATE_VALUE_END: |
|
case GRPC_JSON_STATE_END: |
|
break; |
|
|
|
case GRPC_JSON_STATE_OBJECT_KEY_STRING: |
|
case GRPC_JSON_STATE_VALUE_STRING: |
|
if (c != ' ') return GRPC_JSON_PARSE_ERROR; |
|
if (reader->unicode_high_surrogate != 0) |
|
return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_add_char(reader, c); |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NUMBER: |
|
case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: |
|
case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: |
|
case GRPC_JSON_STATE_VALUE_NUMBER_EPM: |
|
success = (gpr_uint32)json_reader_set_number(reader); |
|
if (!success) return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_clear(reader); |
|
reader->state = GRPC_JSON_STATE_VALUE_END; |
|
break; |
|
|
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
/* Value, object or array terminations. */ |
|
case ',': |
|
case '}': |
|
case ']': |
|
switch (reader->state) { |
|
case GRPC_JSON_STATE_OBJECT_KEY_STRING: |
|
case GRPC_JSON_STATE_VALUE_STRING: |
|
if (reader->unicode_high_surrogate != 0) |
|
return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_add_char(reader, c); |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NUMBER: |
|
case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: |
|
case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: |
|
case GRPC_JSON_STATE_VALUE_NUMBER_EPM: |
|
success = (gpr_uint32)json_reader_set_number(reader); |
|
if (!success) return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_clear(reader); |
|
reader->state = GRPC_JSON_STATE_VALUE_END; |
|
/* The missing break here is intentional. */ |
|
|
|
case GRPC_JSON_STATE_VALUE_END: |
|
case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: |
|
case GRPC_JSON_STATE_VALUE_BEGIN: |
|
if (c == ',') { |
|
if (reader->state != GRPC_JSON_STATE_VALUE_END) { |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
if (reader->in_object) { |
|
reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; |
|
} else { |
|
reader->state = GRPC_JSON_STATE_VALUE_BEGIN; |
|
} |
|
} else { |
|
if (reader->depth-- == 0) return GRPC_JSON_PARSE_ERROR; |
|
if ((c == '}') && !reader->in_object) { |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
if ((c == '}') && |
|
(reader->state == GRPC_JSON_STATE_OBJECT_KEY_BEGIN) && |
|
!reader->container_just_begun) { |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
if ((c == ']') && !reader->in_array) return GRPC_JSON_PARSE_ERROR; |
|
if ((c == ']') && |
|
(reader->state == GRPC_JSON_STATE_VALUE_BEGIN) && |
|
!reader->container_just_begun) { |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
reader->state = GRPC_JSON_STATE_VALUE_END; |
|
switch (grpc_json_reader_container_ends(reader)) { |
|
case GRPC_JSON_OBJECT: |
|
reader->in_object = 1; |
|
reader->in_array = 0; |
|
break; |
|
case GRPC_JSON_ARRAY: |
|
reader->in_object = 0; |
|
reader->in_array = 1; |
|
break; |
|
case GRPC_JSON_TOP_LEVEL: |
|
GPR_ASSERT(reader->depth == 0); |
|
reader->in_object = 0; |
|
reader->in_array = 0; |
|
reader->state = GRPC_JSON_STATE_END; |
|
break; |
|
default: |
|
GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); |
|
} |
|
} |
|
break; |
|
|
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
/* In-string escaping. */ |
|
case '\\': |
|
switch (reader->state) { |
|
case GRPC_JSON_STATE_OBJECT_KEY_STRING: |
|
reader->escaped_string_was_key = 1; |
|
reader->state = GRPC_JSON_STATE_STRING_ESCAPE; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_STRING: |
|
reader->escaped_string_was_key = 0; |
|
reader->state = GRPC_JSON_STATE_STRING_ESCAPE; |
|
break; |
|
|
|
/* This is the \\ case. */ |
|
case GRPC_JSON_STATE_STRING_ESCAPE: |
|
if (reader->unicode_high_surrogate != 0) |
|
return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_add_char(reader, '\\'); |
|
if (reader->escaped_string_was_key) { |
|
reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; |
|
} else { |
|
reader->state = GRPC_JSON_STATE_VALUE_STRING; |
|
} |
|
break; |
|
|
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
default: |
|
reader->container_just_begun = 0; |
|
switch (reader->state) { |
|
case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: |
|
if (c != '"') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; |
|
break; |
|
|
|
case GRPC_JSON_STATE_OBJECT_KEY_STRING: |
|
GPR_ASSERT(reader->unicode_high_surrogate == 0); |
|
if (c == '"') { |
|
reader->state = GRPC_JSON_STATE_OBJECT_KEY_END; |
|
json_reader_set_key(reader); |
|
json_reader_string_clear(reader); |
|
} else { |
|
if (c <= 0x001f) return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_add_char(reader, c); |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_STRING: |
|
if (reader->unicode_high_surrogate != 0) |
|
return GRPC_JSON_PARSE_ERROR; |
|
if (c == '"') { |
|
reader->state = GRPC_JSON_STATE_VALUE_END; |
|
json_reader_set_string(reader); |
|
json_reader_string_clear(reader); |
|
} else { |
|
if (c < 32) return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_add_char(reader, c); |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_OBJECT_KEY_END: |
|
if (c != ':') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_VALUE_BEGIN; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_BEGIN: |
|
switch (c) { |
|
case 't': |
|
reader->state = GRPC_JSON_STATE_VALUE_TRUE_R; |
|
break; |
|
|
|
case 'f': |
|
reader->state = GRPC_JSON_STATE_VALUE_FALSE_A; |
|
break; |
|
|
|
case 'n': |
|
reader->state = GRPC_JSON_STATE_VALUE_NULL_U; |
|
break; |
|
|
|
case '"': |
|
reader->state = GRPC_JSON_STATE_VALUE_STRING; |
|
break; |
|
|
|
case '0': |
|
json_reader_string_add_char(reader, c); |
|
reader->state = GRPC_JSON_STATE_VALUE_NUMBER_ZERO; |
|
break; |
|
|
|
case '1': |
|
case '2': |
|
case '3': |
|
case '4': |
|
case '5': |
|
case '6': |
|
case '7': |
|
case '8': |
|
case '9': |
|
case '-': |
|
json_reader_string_add_char(reader, c); |
|
reader->state = GRPC_JSON_STATE_VALUE_NUMBER; |
|
break; |
|
|
|
case '{': |
|
reader->container_just_begun = 1; |
|
json_reader_container_begins(reader, GRPC_JSON_OBJECT); |
|
reader->depth++; |
|
reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; |
|
reader->in_object = 1; |
|
reader->in_array = 0; |
|
break; |
|
|
|
case '[': |
|
reader->container_just_begun = 1; |
|
json_reader_container_begins(reader, GRPC_JSON_ARRAY); |
|
reader->depth++; |
|
reader->in_object = 0; |
|
reader->in_array = 1; |
|
break; |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_STRING_ESCAPE: |
|
if (reader->escaped_string_was_key) { |
|
reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; |
|
} else { |
|
reader->state = GRPC_JSON_STATE_VALUE_STRING; |
|
} |
|
if (reader->unicode_high_surrogate && c != 'u') |
|
return GRPC_JSON_PARSE_ERROR; |
|
switch (c) { |
|
case '"': |
|
case '/': |
|
json_reader_string_add_char(reader, c); |
|
break; |
|
case 'b': |
|
json_reader_string_add_char(reader, '\b'); |
|
break; |
|
case 'f': |
|
json_reader_string_add_char(reader, '\f'); |
|
break; |
|
case 'n': |
|
json_reader_string_add_char(reader, '\n'); |
|
break; |
|
case 'r': |
|
json_reader_string_add_char(reader, '\r'); |
|
break; |
|
case 't': |
|
json_reader_string_add_char(reader, '\t'); |
|
break; |
|
case 'u': |
|
reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1; |
|
reader->unicode_char = 0; |
|
break; |
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_STRING_ESCAPE_U1: |
|
case GRPC_JSON_STATE_STRING_ESCAPE_U2: |
|
case GRPC_JSON_STATE_STRING_ESCAPE_U3: |
|
case GRPC_JSON_STATE_STRING_ESCAPE_U4: |
|
if ((c >= '0') && (c <= '9')) { |
|
c -= '0'; |
|
} else if ((c >= 'A') && (c <= 'F')) { |
|
c -= 'A' - 10; |
|
} else if ((c >= 'a') && (c <= 'f')) { |
|
c -= 'a' - 10; |
|
} else { |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
reader->unicode_char = (gpr_uint16)(reader->unicode_char << 4); |
|
reader->unicode_char = (gpr_uint16)(reader->unicode_char | c); |
|
|
|
switch (reader->state) { |
|
case GRPC_JSON_STATE_STRING_ESCAPE_U1: |
|
reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U2; |
|
break; |
|
case GRPC_JSON_STATE_STRING_ESCAPE_U2: |
|
reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U3; |
|
break; |
|
case GRPC_JSON_STATE_STRING_ESCAPE_U3: |
|
reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4; |
|
break; |
|
case GRPC_JSON_STATE_STRING_ESCAPE_U4: |
|
/* See grpc_json_writer_escape_string to have a description |
|
* of what's going on here. |
|
*/ |
|
if ((reader->unicode_char & 0xfc00) == 0xd800) { |
|
/* high surrogate utf-16 */ |
|
if (reader->unicode_high_surrogate != 0) |
|
return GRPC_JSON_PARSE_ERROR; |
|
reader->unicode_high_surrogate = reader->unicode_char; |
|
} else if ((reader->unicode_char & 0xfc00) == 0xdc00) { |
|
/* low surrogate utf-16 */ |
|
gpr_uint32 utf32; |
|
if (reader->unicode_high_surrogate == 0) |
|
return GRPC_JSON_PARSE_ERROR; |
|
utf32 = 0x10000; |
|
utf32 += (gpr_uint32)( |
|
(reader->unicode_high_surrogate - 0xd800) * 0x400); |
|
utf32 += (gpr_uint32)(reader->unicode_char - 0xdc00); |
|
json_reader_string_add_utf32(reader, utf32); |
|
reader->unicode_high_surrogate = 0; |
|
} else { |
|
/* anything else */ |
|
if (reader->unicode_high_surrogate != 0) |
|
return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_add_utf32(reader, reader->unicode_char); |
|
} |
|
if (reader->escaped_string_was_key) { |
|
reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; |
|
} else { |
|
reader->state = GRPC_JSON_STATE_VALUE_STRING; |
|
} |
|
break; |
|
default: |
|
GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NUMBER: |
|
json_reader_string_add_char(reader, c); |
|
switch (c) { |
|
case '0': |
|
case '1': |
|
case '2': |
|
case '3': |
|
case '4': |
|
case '5': |
|
case '6': |
|
case '7': |
|
case '8': |
|
case '9': |
|
break; |
|
case 'e': |
|
case 'E': |
|
reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; |
|
break; |
|
case '.': |
|
reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; |
|
break; |
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: |
|
json_reader_string_add_char(reader, c); |
|
switch (c) { |
|
case '0': |
|
case '1': |
|
case '2': |
|
case '3': |
|
case '4': |
|
case '5': |
|
case '6': |
|
case '7': |
|
case '8': |
|
case '9': |
|
break; |
|
case 'e': |
|
case 'E': |
|
reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; |
|
break; |
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: |
|
if (c != '.') return GRPC_JSON_PARSE_ERROR; |
|
json_reader_string_add_char(reader, c); |
|
reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NUMBER_DOT: |
|
json_reader_string_add_char(reader, c); |
|
switch (c) { |
|
case '0': |
|
case '1': |
|
case '2': |
|
case '3': |
|
case '4': |
|
case '5': |
|
case '6': |
|
case '7': |
|
case '8': |
|
case '9': |
|
reader->state = GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL; |
|
break; |
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NUMBER_E: |
|
json_reader_string_add_char(reader, c); |
|
switch (c) { |
|
case '0': |
|
case '1': |
|
case '2': |
|
case '3': |
|
case '4': |
|
case '5': |
|
case '6': |
|
case '7': |
|
case '8': |
|
case '9': |
|
case '+': |
|
case '-': |
|
reader->state = GRPC_JSON_STATE_VALUE_NUMBER_EPM; |
|
break; |
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NUMBER_EPM: |
|
json_reader_string_add_char(reader, c); |
|
switch (c) { |
|
case '0': |
|
case '1': |
|
case '2': |
|
case '3': |
|
case '4': |
|
case '5': |
|
case '6': |
|
case '7': |
|
case '8': |
|
case '9': |
|
break; |
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_TRUE_R: |
|
if (c != 'r') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_VALUE_TRUE_U; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_TRUE_U: |
|
if (c != 'u') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_VALUE_TRUE_E; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_TRUE_E: |
|
if (c != 'e') return GRPC_JSON_PARSE_ERROR; |
|
json_reader_set_true(reader); |
|
reader->state = GRPC_JSON_STATE_VALUE_END; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_FALSE_A: |
|
if (c != 'a') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_VALUE_FALSE_L; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_FALSE_L: |
|
if (c != 'l') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_VALUE_FALSE_S; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_FALSE_S: |
|
if (c != 's') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_VALUE_FALSE_E; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_FALSE_E: |
|
if (c != 'e') return GRPC_JSON_PARSE_ERROR; |
|
json_reader_set_false(reader); |
|
reader->state = GRPC_JSON_STATE_VALUE_END; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NULL_U: |
|
if (c != 'u') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_VALUE_NULL_L1; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NULL_L1: |
|
if (c != 'l') return GRPC_JSON_PARSE_ERROR; |
|
reader->state = GRPC_JSON_STATE_VALUE_NULL_L2; |
|
break; |
|
|
|
case GRPC_JSON_STATE_VALUE_NULL_L2: |
|
if (c != 'l') return GRPC_JSON_PARSE_ERROR; |
|
json_reader_set_null(reader); |
|
reader->state = GRPC_JSON_STATE_VALUE_END; |
|
break; |
|
|
|
/* All of the VALUE_END cases are handled in the specialized case |
|
* above. */ |
|
case GRPC_JSON_STATE_VALUE_END: |
|
switch (c) { |
|
case ',': |
|
case '}': |
|
case ']': |
|
GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); |
|
break; |
|
|
|
default: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
break; |
|
|
|
case GRPC_JSON_STATE_END: |
|
return GRPC_JSON_PARSE_ERROR; |
|
} |
|
} |
|
} |
|
|
|
GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); |
|
}
|
|
|