|
|
|
@ -61,24 +61,25 @@ typedef struct { |
|
|
|
|
char* string; |
|
|
|
|
char* string_ptr; |
|
|
|
|
size_t remaining_input; |
|
|
|
|
} grpc_json_reader_opaque; |
|
|
|
|
} json_reader_userdata; |
|
|
|
|
|
|
|
|
|
/* This json writer will put everything in a big string.
|
|
|
|
|
* The point is that we allocate that string in chunks of 256 bytes. |
|
|
|
|
*/ |
|
|
|
|
typedef struct { |
|
|
|
|
char* output; |
|
|
|
|
size_t free_space, string_len, allocated; |
|
|
|
|
} grpc_json_writer_opaque; |
|
|
|
|
size_t free_space; |
|
|
|
|
size_t string_len; |
|
|
|
|
size_t allocated; |
|
|
|
|
} json_writer_userdata; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function checks if there's enough space left in the output buffer,
|
|
|
|
|
* and will enlarge it if necessary. We're only allocating chunks of 256 |
|
|
|
|
* bytes at a time (or multiples thereof). |
|
|
|
|
*/ |
|
|
|
|
static void grpc_json_writer_output_check(grpc_json_writer* writer, |
|
|
|
|
size_t needed) { |
|
|
|
|
grpc_json_writer_opaque* state = writer->userdata; |
|
|
|
|
static void json_writer_output_check(void* userdata, size_t needed) { |
|
|
|
|
json_writer_userdata* state = userdata; |
|
|
|
|
if (state->free_space >= needed) return; |
|
|
|
|
needed -= state->free_space; |
|
|
|
|
/* Round up by 256 bytes. */ |
|
|
|
@ -89,34 +90,33 @@ static void grpc_json_writer_output_check(grpc_json_writer* writer, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* These are needed by the writer's implementation. */ |
|
|
|
|
static void grpc_json_writer_output_char(grpc_json_writer* writer, |
|
|
|
|
char c) { |
|
|
|
|
grpc_json_writer_opaque* state = writer->userdata; |
|
|
|
|
grpc_json_writer_output_check(writer, 1); |
|
|
|
|
static void json_writer_output_char(void* userdata, char c) { |
|
|
|
|
json_writer_userdata* state = userdata; |
|
|
|
|
json_writer_output_check(userdata, 1); |
|
|
|
|
state->output[state->string_len++] = c; |
|
|
|
|
state->free_space--; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void grpc_json_writer_output_string_with_len( |
|
|
|
|
grpc_json_writer* writer, const char* str, size_t len) { |
|
|
|
|
grpc_json_writer_opaque* state = writer->userdata; |
|
|
|
|
grpc_json_writer_output_check(writer, len); |
|
|
|
|
static void json_writer_output_string_with_len(void* userdata, |
|
|
|
|
const char* str, size_t len) { |
|
|
|
|
json_writer_userdata* state = userdata; |
|
|
|
|
json_writer_output_check(userdata, len); |
|
|
|
|
memcpy(state->output + state->string_len, str, len); |
|
|
|
|
state->string_len += len; |
|
|
|
|
state->free_space -= len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void grpc_json_writer_output_string(grpc_json_writer* writer, |
|
|
|
|
static void json_writer_output_string(void* userdata, |
|
|
|
|
const char* str) { |
|
|
|
|
size_t len = strlen(str); |
|
|
|
|
grpc_json_writer_output_string_with_len(writer, str, len); |
|
|
|
|
json_writer_output_string_with_len(userdata, str, len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* The reader asks us to clear our scratchpad. In our case, we'll simply mark
|
|
|
|
|
* the end of the current string, and advance our output pointer. |
|
|
|
|
*/ |
|
|
|
|
static void grpc_json_reader_string_clear(grpc_json_reader* reader) { |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
static void json_reader_string_clear(void* userdata) { |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
if (state->string) { |
|
|
|
|
GPR_ASSERT(state->string_ptr < state->input); |
|
|
|
|
*state->string_ptr++ = 0; |
|
|
|
@ -124,47 +124,49 @@ static void grpc_json_reader_string_clear(grpc_json_reader* reader) { |
|
|
|
|
state->string = state->string_ptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void grpc_json_reader_string_add_char(grpc_json_reader* reader, gpr_uint32 c) { |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
static void json_reader_string_add_char(void* userdata, gpr_uint32 c) { |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
GPR_ASSERT(state->string_ptr < state->input); |
|
|
|
|
GPR_ASSERT(c <= 0xff); |
|
|
|
|
*state->string_ptr++ = (char)c; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* We are converting a UTF-32 character into UTF-8 here. */ |
|
|
|
|
static void grpc_json_reader_string_add_utf32(grpc_json_reader* reader, gpr_uint32 c) { |
|
|
|
|
/* We are converting a UTF-32 character into UTF-8 here,
|
|
|
|
|
* as described by RFC3629. |
|
|
|
|
*/ |
|
|
|
|
static void json_reader_string_add_utf32(void* userdata, gpr_uint32 c) { |
|
|
|
|
if (c <= 0x7f) { |
|
|
|
|
grpc_json_reader_string_add_char(reader, c); |
|
|
|
|
json_reader_string_add_char(userdata, c); |
|
|
|
|
} else if (c <= 0x7ff) { |
|
|
|
|
int b1 = 0xc0 | ((c >> 6) & 0x1f); |
|
|
|
|
int b2 = 0x80 | (c & 0x3f); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b1); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b2); |
|
|
|
|
json_reader_string_add_char(userdata, b1); |
|
|
|
|
json_reader_string_add_char(userdata, b2); |
|
|
|
|
} else if (c <= 0xffff) { |
|
|
|
|
int b1 = 0xe0 | ((c >> 12) & 0x0f); |
|
|
|
|
int b2 = 0x80 | ((c >> 6) & 0x3f); |
|
|
|
|
int b3 = 0x80 | (c & 0x3f); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b1); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b2); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b3); |
|
|
|
|
json_reader_string_add_char(userdata, b1); |
|
|
|
|
json_reader_string_add_char(userdata, b2); |
|
|
|
|
json_reader_string_add_char(userdata, b3); |
|
|
|
|
} else if (c <= 0x1fffff) { |
|
|
|
|
int b1 = 0xf0 | ((c >> 18) & 0x07); |
|
|
|
|
int b2 = 0x80 | ((c >> 12) & 0x3f); |
|
|
|
|
int b3 = 0x80 | ((c >> 6) & 0x3f); |
|
|
|
|
int b4 = 0x80 | (c & 0x3f); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b1); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b2); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b3); |
|
|
|
|
grpc_json_reader_string_add_char(reader, b4); |
|
|
|
|
json_reader_string_add_char(userdata, b1); |
|
|
|
|
json_reader_string_add_char(userdata, b2); |
|
|
|
|
json_reader_string_add_char(userdata, b3); |
|
|
|
|
json_reader_string_add_char(userdata, b4); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* We consider that the input may be a zero-terminated string. So we
|
|
|
|
|
* can end up hitting eof before the end of the alleged string length. |
|
|
|
|
*/ |
|
|
|
|
static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader* reader) { |
|
|
|
|
static gpr_uint32 json_reader_read_char(void* userdata) { |
|
|
|
|
gpr_uint32 r; |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
|
|
|
|
|
if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF; |
|
|
|
|
|
|
|
|
@ -182,10 +184,10 @@ static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader* reader) { |
|
|
|
|
/* Helper function to create a new grpc_json object and link it into
|
|
|
|
|
* our tree-in-progress inside our opaque structure. |
|
|
|
|
*/ |
|
|
|
|
static grpc_json* grpc_json_new_and_link(grpc_json_reader* reader, |
|
|
|
|
grpc_json_type type) { |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
grpc_json* json = grpc_json_new(type); |
|
|
|
|
static grpc_json* json_create_and_link(void* userdata, |
|
|
|
|
grpc_json_type type) { |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
grpc_json* json = grpc_json_create(type); |
|
|
|
|
|
|
|
|
|
json->parent = state->current_container; |
|
|
|
|
json->prev = state->current_value; |
|
|
|
@ -209,14 +211,13 @@ static grpc_json* grpc_json_new_and_link(grpc_json_reader* reader, |
|
|
|
|
return json; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void grpc_json_reader_container_begins(grpc_json_reader* reader, |
|
|
|
|
grpc_json_type type) { |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
static void json_reader_container_begins(void* userdata, grpc_json_type type) { |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
grpc_json* container; |
|
|
|
|
|
|
|
|
|
GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT); |
|
|
|
|
|
|
|
|
|
container = grpc_json_new_and_link(reader, type); |
|
|
|
|
container = json_create_and_link(userdata, type); |
|
|
|
|
state->current_container = container; |
|
|
|
|
state->current_value = NULL; |
|
|
|
|
} |
|
|
|
@ -230,10 +231,9 @@ static void grpc_json_reader_container_begins(grpc_json_reader* reader, |
|
|
|
|
* Also note that if we're at the top of the tree, and the last container |
|
|
|
|
* ends, we have to return GRPC_JSON_TOP_LEVEL. |
|
|
|
|
*/ |
|
|
|
|
static grpc_json_type grpc_json_reader_container_ends( |
|
|
|
|
grpc_json_reader* reader) { |
|
|
|
|
static grpc_json_type json_reader_container_ends(void* userdata) { |
|
|
|
|
grpc_json_type container_type = GRPC_JSON_TOP_LEVEL; |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
|
|
|
|
|
GPR_ASSERT(state->current_container); |
|
|
|
|
|
|
|
|
@ -253,22 +253,20 @@ static grpc_json_type grpc_json_reader_container_ends( |
|
|
|
|
* Note that in the set_number case, we're not going to try interpreting it. |
|
|
|
|
* We'll keep it as a string, and leave it to the caller to evaluate it. |
|
|
|
|
*/ |
|
|
|
|
static void grpc_json_reader_set_key(grpc_json_reader* reader) { |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
static void json_reader_set_key(void* userdata) { |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
state->key = state->string; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void grpc_json_reader_set_string( |
|
|
|
|
grpc_json_reader* reader) { |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
grpc_json* json = grpc_json_new_and_link(reader, GRPC_JSON_STRING); |
|
|
|
|
static void json_reader_set_string(void* userdata) { |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
grpc_json* json = json_create_and_link(userdata, GRPC_JSON_STRING); |
|
|
|
|
json->value = state->string; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int grpc_json_reader_set_number( |
|
|
|
|
grpc_json_reader* reader) { |
|
|
|
|
grpc_json_reader_opaque* state = reader->userdata; |
|
|
|
|
grpc_json* json = grpc_json_new_and_link(reader, GRPC_JSON_NUMBER); |
|
|
|
|
static int json_reader_set_number(void* userdata) { |
|
|
|
|
json_reader_userdata* state = userdata; |
|
|
|
|
grpc_json* json = json_create_and_link(userdata, GRPC_JSON_NUMBER); |
|
|
|
|
json->value = state->string; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
@ -276,27 +274,39 @@ static int grpc_json_reader_set_number( |
|
|
|
|
/* The object types true, false and null are self-sufficient, and don't need
|
|
|
|
|
* any more information beside their type. |
|
|
|
|
*/ |
|
|
|
|
static void grpc_json_reader_set_true( |
|
|
|
|
grpc_json_reader *reader) { |
|
|
|
|
grpc_json_new_and_link(reader, GRPC_JSON_TRUE); |
|
|
|
|
static void json_reader_set_true(void* userdata) { |
|
|
|
|
json_create_and_link(userdata, GRPC_JSON_TRUE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void grpc_json_reader_set_false( |
|
|
|
|
grpc_json_reader *reader) { |
|
|
|
|
grpc_json_new_and_link(reader, GRPC_JSON_FALSE); |
|
|
|
|
static void json_reader_set_false(void* userdata) { |
|
|
|
|
json_create_and_link(userdata, GRPC_JSON_FALSE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void grpc_json_reader_set_null( |
|
|
|
|
grpc_json_reader *reader) { |
|
|
|
|
grpc_json_new_and_link(reader, GRPC_JSON_NULL); |
|
|
|
|
static void json_reader_set_null(void* userdata) { |
|
|
|
|
json_create_and_link(userdata, GRPC_JSON_NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_json_reader_vtable reader_vtable = { |
|
|
|
|
json_reader_string_clear, |
|
|
|
|
json_reader_string_add_char, |
|
|
|
|
json_reader_string_add_utf32, |
|
|
|
|
json_reader_read_char, |
|
|
|
|
json_reader_container_begins, |
|
|
|
|
json_reader_container_ends, |
|
|
|
|
json_reader_set_key, |
|
|
|
|
json_reader_set_string, |
|
|
|
|
json_reader_set_number, |
|
|
|
|
json_reader_set_true, |
|
|
|
|
json_reader_set_false, |
|
|
|
|
json_reader_set_null |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/* And finally, let's define our public API. */ |
|
|
|
|
grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) { |
|
|
|
|
grpc_json_reader reader; |
|
|
|
|
grpc_json_reader_opaque state; |
|
|
|
|
json_reader_userdata state; |
|
|
|
|
grpc_json *json = NULL; |
|
|
|
|
grpc_json_reader_ret status; |
|
|
|
|
grpc_json_reader_status status; |
|
|
|
|
|
|
|
|
|
if (!input) return NULL; |
|
|
|
|
|
|
|
|
@ -304,26 +314,13 @@ grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) { |
|
|
|
|
state.string = state.key = NULL; |
|
|
|
|
state.string_ptr = state.input = input; |
|
|
|
|
state.remaining_input = size; |
|
|
|
|
reader.userdata = &state; |
|
|
|
|
reader.string_clear = grpc_json_reader_string_clear; |
|
|
|
|
reader.string_add_char = grpc_json_reader_string_add_char; |
|
|
|
|
reader.string_add_utf32 = grpc_json_reader_string_add_utf32; |
|
|
|
|
reader.read_char = grpc_json_reader_read_char; |
|
|
|
|
reader.container_begins = grpc_json_reader_container_begins; |
|
|
|
|
reader.container_ends = grpc_json_reader_container_ends; |
|
|
|
|
reader.set_key = grpc_json_reader_set_key; |
|
|
|
|
reader.set_string = grpc_json_reader_set_string; |
|
|
|
|
reader.set_number = grpc_json_reader_set_number; |
|
|
|
|
reader.set_true = grpc_json_reader_set_true; |
|
|
|
|
reader.set_false = grpc_json_reader_set_false; |
|
|
|
|
reader.set_null = grpc_json_reader_set_null; |
|
|
|
|
grpc_json_reader_init(&reader); |
|
|
|
|
grpc_json_reader_init(&reader, &reader_vtable, &state); |
|
|
|
|
|
|
|
|
|
status = grpc_json_reader_run(&reader); |
|
|
|
|
json = state.top; |
|
|
|
|
|
|
|
|
|
if ((status != GRPC_JSON_DONE) && json) { |
|
|
|
|
grpc_json_delete(json); |
|
|
|
|
grpc_json_destroy(json); |
|
|
|
|
json = NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -336,8 +333,8 @@ grpc_json* grpc_json_parse_string(char* input) { |
|
|
|
|
return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void grpc_json_dump_recursive(grpc_json_writer* writer, |
|
|
|
|
grpc_json* json, int in_object) { |
|
|
|
|
static void json_dump_recursive(grpc_json_writer* writer, |
|
|
|
|
grpc_json* json, int in_object) { |
|
|
|
|
while (json) { |
|
|
|
|
if (in_object) grpc_json_writer_object_key(writer, json->key); |
|
|
|
|
|
|
|
|
@ -346,8 +343,8 @@ static void grpc_json_dump_recursive(grpc_json_writer* writer, |
|
|
|
|
case GRPC_JSON_ARRAY: |
|
|
|
|
grpc_json_writer_container_begins(writer, json->type); |
|
|
|
|
if (json->child) |
|
|
|
|
grpc_json_dump_recursive(writer, json->child, |
|
|
|
|
json->type == GRPC_JSON_OBJECT); |
|
|
|
|
json_dump_recursive(writer, json->child, |
|
|
|
|
json->type == GRPC_JSON_OBJECT); |
|
|
|
|
grpc_json_writer_container_ends(writer, json->type); |
|
|
|
|
break; |
|
|
|
|
case GRPC_JSON_STRING: |
|
|
|
@ -372,20 +369,23 @@ static void grpc_json_dump_recursive(grpc_json_writer* writer, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_json_writer_vtable writer_vtable = { |
|
|
|
|
json_writer_output_char, |
|
|
|
|
json_writer_output_string, |
|
|
|
|
json_writer_output_string_with_len |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
char* grpc_json_dump_to_string(grpc_json* json, int indent) { |
|
|
|
|
grpc_json_writer writer; |
|
|
|
|
grpc_json_writer_opaque state; |
|
|
|
|
json_writer_userdata state; |
|
|
|
|
|
|
|
|
|
state.output = NULL; |
|
|
|
|
state.free_space = state.string_len = state.allocated = 0; |
|
|
|
|
writer.userdata = &state; |
|
|
|
|
writer.output_char = grpc_json_writer_output_char; |
|
|
|
|
writer.output_string = grpc_json_writer_output_string; |
|
|
|
|
writer.output_string_with_len = grpc_json_writer_output_string_with_len; |
|
|
|
|
grpc_json_writer_init(&writer, indent); |
|
|
|
|
grpc_json_writer_init(&writer, indent, &writer_vtable, &state); |
|
|
|
|
|
|
|
|
|
grpc_json_dump_recursive(&writer, json, 0); |
|
|
|
|
json_dump_recursive(&writer, json, 0); |
|
|
|
|
|
|
|
|
|
grpc_json_writer_output_char(&writer, 0); |
|
|
|
|
json_writer_output_char(&state, 0); |
|
|
|
|
|
|
|
|
|
return state.output; |
|
|
|
|
} |
|
|
|
|