| /* |
| * |
| * 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, uint32_t c) { |
| reader->vtable->string_add_char(reader->userdata, c); |
| } |
| |
| static void json_reader_string_add_utf32(grpc_json_reader *reader, |
| uint32_t utf32) { |
| reader->vtable->string_add_utf32(reader->userdata, utf32); |
| } |
| |
| static uint32_t 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) { |
| uint32_t 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 = (uint32_t)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 = (uint32_t)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 = (uint16_t)(reader->unicode_char << 4); |
| reader->unicode_char = (uint16_t)(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 */ |
| uint32_t utf32; |
| if (reader->unicode_high_surrogate == 0) |
| return GRPC_JSON_PARSE_ERROR; |
| utf32 = 0x10000; |
| utf32 += (uint32_t)( |
| (reader->unicode_high_surrogate - 0xd800) * 0x400); |
| utf32 += (uint32_t)(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); |
| } |