From 4520072f92eed7fed50e0a576e25c56f7c016115 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 23 Jan 2020 12:44:11 -0800 Subject: [PATCH] Convert json_reader and json_writer to C++ --- src/core/lib/json/json_reader.cc | 832 +++++++++++++++---------------- src/core/lib/json/json_writer.cc | 296 +++++------ 2 files changed, 564 insertions(+), 564 deletions(-) diff --git a/src/core/lib/json/json_reader.cc b/src/core/lib/json/json_reader.cc index 0e7caec1714..3dd63756278 100644 --- a/src/core/lib/json/json_reader.cc +++ b/src/core/lib/json/json_reader.cc @@ -24,126 +24,148 @@ #include "src/core/lib/json/json.h" -typedef enum { - GRPC_JSON_STATE_OBJECT_KEY_BEGIN, - GRPC_JSON_STATE_OBJECT_KEY_STRING, - GRPC_JSON_STATE_OBJECT_KEY_END, - GRPC_JSON_STATE_VALUE_BEGIN, - GRPC_JSON_STATE_VALUE_STRING, - GRPC_JSON_STATE_STRING_ESCAPE, - GRPC_JSON_STATE_STRING_ESCAPE_U1, - GRPC_JSON_STATE_STRING_ESCAPE_U2, - GRPC_JSON_STATE_STRING_ESCAPE_U3, - GRPC_JSON_STATE_STRING_ESCAPE_U4, - GRPC_JSON_STATE_VALUE_NUMBER, - GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL, - GRPC_JSON_STATE_VALUE_NUMBER_ZERO, - GRPC_JSON_STATE_VALUE_NUMBER_DOT, - GRPC_JSON_STATE_VALUE_NUMBER_E, - GRPC_JSON_STATE_VALUE_NUMBER_EPM, - GRPC_JSON_STATE_VALUE_TRUE_R, - GRPC_JSON_STATE_VALUE_TRUE_U, - GRPC_JSON_STATE_VALUE_TRUE_E, - GRPC_JSON_STATE_VALUE_FALSE_A, - GRPC_JSON_STATE_VALUE_FALSE_L, - GRPC_JSON_STATE_VALUE_FALSE_S, - GRPC_JSON_STATE_VALUE_FALSE_E, - GRPC_JSON_STATE_VALUE_NULL_U, - GRPC_JSON_STATE_VALUE_NULL_L1, - GRPC_JSON_STATE_VALUE_NULL_L2, - GRPC_JSON_STATE_VALUE_END, - GRPC_JSON_STATE_END -} grpc_json_reader_state; - -enum { +namespace grpc_core { + +namespace { + +class JsonReader { + public: + static grpc_json* Parse(char* input, size_t size); + + private: + enum class Status { + GRPC_JSON_DONE, /* The parser finished successfully. */ + GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */ + GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */ + }; + + enum class State { + GRPC_JSON_STATE_OBJECT_KEY_BEGIN, + GRPC_JSON_STATE_OBJECT_KEY_STRING, + GRPC_JSON_STATE_OBJECT_KEY_END, + GRPC_JSON_STATE_VALUE_BEGIN, + GRPC_JSON_STATE_VALUE_STRING, + GRPC_JSON_STATE_STRING_ESCAPE, + GRPC_JSON_STATE_STRING_ESCAPE_U1, + GRPC_JSON_STATE_STRING_ESCAPE_U2, + GRPC_JSON_STATE_STRING_ESCAPE_U3, + GRPC_JSON_STATE_STRING_ESCAPE_U4, + GRPC_JSON_STATE_VALUE_NUMBER, + GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL, + GRPC_JSON_STATE_VALUE_NUMBER_ZERO, + GRPC_JSON_STATE_VALUE_NUMBER_DOT, + GRPC_JSON_STATE_VALUE_NUMBER_E, + GRPC_JSON_STATE_VALUE_NUMBER_EPM, + GRPC_JSON_STATE_VALUE_TRUE_R, + GRPC_JSON_STATE_VALUE_TRUE_U, + GRPC_JSON_STATE_VALUE_TRUE_E, + GRPC_JSON_STATE_VALUE_FALSE_A, + GRPC_JSON_STATE_VALUE_FALSE_L, + GRPC_JSON_STATE_VALUE_FALSE_S, + GRPC_JSON_STATE_VALUE_FALSE_E, + GRPC_JSON_STATE_VALUE_NULL_U, + GRPC_JSON_STATE_VALUE_NULL_L1, + GRPC_JSON_STATE_VALUE_NULL_L2, + GRPC_JSON_STATE_VALUE_END, + GRPC_JSON_STATE_END + }; + /* The first non-unicode value is 0x110000. But let's pick * a value high enough to start our error codes from. These * values are safe to return from the read_char function. */ - GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0, - GRPC_JSON_READ_CHAR_EAGAIN, - GRPC_JSON_READ_CHAR_ERROR -}; + static constexpr uint32_t GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0; -typedef struct grpc_json_reader { - /* That structure is fully private, and initialized by grpc_json_reader_init. - * The definition is public so you can put it on your stack. - */ + JsonReader(char* input, size_t size) + : input_(reinterpret_cast(input)), + remaining_input_(size), + string_ptr_(input_) { + StringClear(); + } + + void StringClear(); + void StringAddChar(uint32_t c); + void StringAddUtf32(uint32_t c); + uint32_t ReadChar(); + grpc_json* CreateAndLink(grpc_json_type type); + void ContainerBegins(grpc_json_type type); + grpc_json_type ContainerEnds(); + void SetKey(); + void SetString(); + bool SetNumber(); + void SetTrue(); + void SetFalse(); + void SetNull(); + bool IsComplete(); + Status Run(); + + State state_ = State::GRPC_JSON_STATE_VALUE_BEGIN; + + int depth_ = 0; + int in_object_ = 0; + int in_array_ = 0; + int escaped_string_was_key_ = 0; + int container_just_begun_ = 0; + uint16_t unicode_char_ = 0; + uint16_t unicode_high_surrogate_ = 0; + + grpc_json* top_ = nullptr; + grpc_json* current_container_ = nullptr; + grpc_json* current_value_ = nullptr; + uint8_t* input_; + size_t remaining_input_; + uint8_t* string_ptr_; + uint8_t* key_ = nullptr; + uint8_t* string_ = nullptr; +}; - int depth; - int in_object; - int in_array; - int escaped_string_was_key; - int container_just_begun; - uint16_t unicode_char, unicode_high_surrogate; - grpc_json_reader_state state; - - grpc_json* top; - grpc_json* current_container; - grpc_json* current_value; - uint8_t* input; - uint8_t* key; - uint8_t* string; - uint8_t* string_ptr; - size_t remaining_input; -} grpc_json_reader; - -/* The return type of the parser. */ -typedef enum { - GRPC_JSON_DONE, /* The parser finished successfully. */ - GRPC_JSON_EAGAIN, /* The parser yields to get more data. */ - GRPC_JSON_READ_ERROR, /* The parser passes through a read error. */ - GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */ - GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */ -} grpc_json_reader_status; - -static void json_reader_string_clear(grpc_json_reader* reader) { - if (reader->string) { - GPR_ASSERT(reader->string_ptr < reader->input); - *reader->string_ptr++ = 0; +void JsonReader::StringClear() { + if (string_ != nullptr) { + GPR_ASSERT(string_ptr_ < input_); + *string_ptr_++ = 0; } - reader->string = reader->string_ptr; + string_ = string_ptr_; } -static void json_reader_string_add_char(grpc_json_reader* reader, uint32_t c) { - GPR_ASSERT(reader->string_ptr < reader->input); +void JsonReader::StringAddChar(uint32_t c) { + GPR_ASSERT(string_ptr_ < input_); GPR_ASSERT(c <= 0xff); - *reader->string_ptr++ = static_cast(c); + *string_ptr_++ = static_cast(c); } -static void json_reader_string_add_utf32(grpc_json_reader* reader, uint32_t c) { +void JsonReader::StringAddUtf32(uint32_t c) { if (c <= 0x7f) { - json_reader_string_add_char(reader, c); + StringAddChar(c); } else if (c <= 0x7ff) { uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f); uint32_t b2 = 0x80 | (c & 0x3f); - json_reader_string_add_char(reader, b1); - json_reader_string_add_char(reader, b2); + StringAddChar(b1); + StringAddChar(b2); } else if (c <= 0xffff) { uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f); uint32_t b2 = 0x80 | ((c >> 6) & 0x3f); uint32_t b3 = 0x80 | (c & 0x3f); - json_reader_string_add_char(reader, b1); - json_reader_string_add_char(reader, b2); - json_reader_string_add_char(reader, b3); + StringAddChar(b1); + StringAddChar(b2); + StringAddChar(b3); } else if (c <= 0x1fffff) { uint32_t b1 = 0xf0 | ((c >> 18) & 0x07); uint32_t b2 = 0x80 | ((c >> 12) & 0x3f); uint32_t b3 = 0x80 | ((c >> 6) & 0x3f); uint32_t b4 = 0x80 | (c & 0x3f); - json_reader_string_add_char(reader, b1); - json_reader_string_add_char(reader, b2); - json_reader_string_add_char(reader, b3); - json_reader_string_add_char(reader, b4); + StringAddChar(b1); + StringAddChar(b2); + StringAddChar(b3); + StringAddChar(b4); } } -static uint32_t grpc_json_reader_read_char(grpc_json_reader* reader) { - if (reader->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF; - uint32_t r = *reader->input++; - reader->remaining_input--; +uint32_t JsonReader::ReadChar() { + if (remaining_input_ == 0) return GRPC_JSON_READ_CHAR_EOF; + uint32_t r = *input_++; + remaining_input_--; if (r == 0) { - reader->remaining_input = 0; + remaining_input_ = 0; return GRPC_JSON_READ_CHAR_EOF; } return r; @@ -152,12 +174,11 @@ static uint32_t 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* json_create_and_link(grpc_json_reader* reader, - grpc_json_type type) { +grpc_json* JsonReader::CreateAndLink(grpc_json_type type) { grpc_json* json = grpc_json_create(type); - json->parent = reader->current_container; - json->prev = reader->current_value; - reader->current_value = json; + json->parent = current_container_; + json->prev = current_value_; + current_value_ = json; if (json->prev) { json->prev->next = json; } @@ -166,101 +187,77 @@ static grpc_json* json_create_and_link(grpc_json_reader* reader, json->parent->child = json; } if (json->parent->type == GRPC_JSON_OBJECT) { - json->key = reinterpret_cast(reader->key); + json->key = reinterpret_cast(key_); } } - if (!reader->top) { - reader->top = json; + if (top_ == nullptr) { + top_ = json; } return json; } -static void json_reader_container_begins(grpc_json_reader* reader, - grpc_json_type type) { +void JsonReader::ContainerBegins(grpc_json_type type) { GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT); - grpc_json* container = json_create_and_link(reader, type); - reader->current_container = container; - reader->current_value = nullptr; + grpc_json* container = CreateAndLink(type); + current_container_ = container; + current_value_ = nullptr; } -static grpc_json_type grpc_json_reader_container_ends( - grpc_json_reader* reader) { +grpc_json_type JsonReader::ContainerEnds() { grpc_json_type container_type = GRPC_JSON_TOP_LEVEL; - GPR_ASSERT(reader->current_container); - reader->current_value = reader->current_container; - reader->current_container = reader->current_container->parent; - if (reader->current_container) { - container_type = reader->current_container->type; + GPR_ASSERT(current_container_); + current_value_ = current_container_; + current_container_ = current_container_->parent; + if (current_container_ != nullptr) { + container_type = current_container_->type; } return container_type; } -static void json_reader_set_key(grpc_json_reader* reader) { - reader->key = reader->string; -} +void JsonReader::SetKey() { key_ = string_; } -static void json_reader_set_string(grpc_json_reader* reader) { - grpc_json* json = json_create_and_link(reader, GRPC_JSON_STRING); - json->value = reinterpret_cast(reader->string); +void JsonReader::SetString() { + grpc_json* json = CreateAndLink(GRPC_JSON_STRING); + json->value = reinterpret_cast(string_); } -static int json_reader_set_number(grpc_json_reader* reader) { - grpc_json* json = json_create_and_link(reader, GRPC_JSON_NUMBER); - json->value = reinterpret_cast(reader->string); - return 1; +bool JsonReader::SetNumber() { + grpc_json* json = CreateAndLink(GRPC_JSON_NUMBER); + json->value = reinterpret_cast(string_); + return true; } -static void json_reader_set_true(grpc_json_reader* reader) { - json_create_and_link(reader, GRPC_JSON_TRUE); -} +void JsonReader::SetTrue() { CreateAndLink(GRPC_JSON_TRUE); } -static void json_reader_set_false(grpc_json_reader* reader) { - json_create_and_link(reader, GRPC_JSON_FALSE); -} +void JsonReader::SetFalse() { CreateAndLink(GRPC_JSON_FALSE); } -static void json_reader_set_null(grpc_json_reader* reader) { - json_create_and_link(reader, GRPC_JSON_NULL); -} +void JsonReader::SetNull() { CreateAndLink(GRPC_JSON_NULL); } -static int 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))); +bool JsonReader::IsComplete() { + return (depth_ == 0 && (state_ == State::GRPC_JSON_STATE_END || + state_ == State::GRPC_JSON_STATE_VALUE_END)); } /* Call this function to start parsing the input. It will return the following: * . GRPC_JSON_DONE if the input got eof, and the parsing finished * successfully. - * . GRPC_JSON_EAGAIN if the read_char function returned again. Call the - * parser again as needed. It is okay to call the parser in polling mode, - * although a bit dull. - * . GRPC_JSON_READ_ERROR if the read_char function returned an error. The - * state isn't broken however, and the function can be called again if the - * error has been corrected. But please use the EAGAIN feature instead for - * consistency. * . GRPC_JSON_PARSE_ERROR if the input was somehow invalid. * . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid * internal state. */ -static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { +JsonReader::Status JsonReader::Run() { uint32_t c, success; /* This state-machine is a strict implementation of ECMA-404 */ - for (;;) { - c = grpc_json_reader_read_char(reader); + while (true) { + c = ReadChar(); 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; - + /* Let's process the error case first. */ case GRPC_JSON_READ_CHAR_EOF: - if (json_reader_is_complete(reader)) { - return GRPC_JSON_DONE; + if (IsComplete()) { + return Status::GRPC_JSON_DONE; } else { - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } break; @@ -269,34 +266,34 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { 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: + switch (state_) { + case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN: + case State::GRPC_JSON_STATE_OBJECT_KEY_END: + case State::GRPC_JSON_STATE_VALUE_BEGIN: + case State::GRPC_JSON_STATE_VALUE_END: + case State::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); + case State::GRPC_JSON_STATE_OBJECT_KEY_STRING: + case State::GRPC_JSON_STATE_VALUE_STRING: + if (c != ' ') return Status::GRPC_JSON_PARSE_ERROR; + if (unicode_high_surrogate_ != 0) + return Status::GRPC_JSON_PARSE_ERROR; + StringAddChar(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 = static_cast(json_reader_set_number(reader)); - if (!success) return GRPC_JSON_PARSE_ERROR; - json_reader_string_clear(reader); - reader->state = GRPC_JSON_STATE_VALUE_END; + case State::GRPC_JSON_STATE_VALUE_NUMBER: + case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: + case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO: + case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM: + success = static_cast(SetNumber()); + if (!success) return Status::GRPC_JSON_PARSE_ERROR; + StringClear(); + state_ = State::GRPC_JSON_STATE_VALUE_END; break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } break; @@ -304,182 +301,183 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { 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; + switch (state_) { + case State::GRPC_JSON_STATE_OBJECT_KEY_STRING: + case State::GRPC_JSON_STATE_VALUE_STRING: + if (unicode_high_surrogate_ != 0) { + return Status::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: - if (reader->depth == 0) { - return GRPC_JSON_PARSE_ERROR; - } else if ((c == '}') && !reader->in_object) { - return GRPC_JSON_PARSE_ERROR; - } else if ((c == ']') && !reader->in_array) { - return GRPC_JSON_PARSE_ERROR; + StringAddChar(c); + break; + + case State::GRPC_JSON_STATE_VALUE_NUMBER: + case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: + case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO: + case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM: + if (depth_ == 0) { + return Status::GRPC_JSON_PARSE_ERROR; + } else if ((c == '}') && !in_object_) { + return Status::GRPC_JSON_PARSE_ERROR; + } else if ((c == ']') && !in_array_) { + return Status::GRPC_JSON_PARSE_ERROR; } - success = static_cast(json_reader_set_number(reader)); - if (!success) return GRPC_JSON_PARSE_ERROR; - json_reader_string_clear(reader); - reader->state = GRPC_JSON_STATE_VALUE_END; + success = static_cast(SetNumber()); + if (!success) return Status::GRPC_JSON_PARSE_ERROR; + StringClear(); + state_ = State::GRPC_JSON_STATE_VALUE_END; /* The missing break here is intentional. */ /* fallthrough */ - case GRPC_JSON_STATE_VALUE_END: - case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: - case GRPC_JSON_STATE_VALUE_BEGIN: + case State::GRPC_JSON_STATE_VALUE_END: + case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN: + case State::GRPC_JSON_STATE_VALUE_BEGIN: if (c == ',') { - if (reader->state != GRPC_JSON_STATE_VALUE_END) { - return GRPC_JSON_PARSE_ERROR; + if (state_ != State::GRPC_JSON_STATE_VALUE_END) { + return Status::GRPC_JSON_PARSE_ERROR; } - if (reader->in_object) { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; - } else if (reader->in_array) { - reader->state = GRPC_JSON_STATE_VALUE_BEGIN; + if (in_object_) { + state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN; + } else if (in_array_) { + state_ = State::GRPC_JSON_STATE_VALUE_BEGIN; } else { - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } } else { - if (reader->depth-- == 0) return GRPC_JSON_PARSE_ERROR; - if ((c == '}') && !reader->in_object) { - return GRPC_JSON_PARSE_ERROR; + if (depth_-- == 0) return Status::GRPC_JSON_PARSE_ERROR; + if ((c == '}') && !in_object_) { + return Status::GRPC_JSON_PARSE_ERROR; } if ((c == '}') && - (reader->state == GRPC_JSON_STATE_OBJECT_KEY_BEGIN) && - !reader->container_just_begun) { - return GRPC_JSON_PARSE_ERROR; + (state_ == State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN) && + !container_just_begun_) { + return Status::GRPC_JSON_PARSE_ERROR; } - if ((c == ']') && !reader->in_array) return GRPC_JSON_PARSE_ERROR; + if ((c == ']') && !in_array_) + return Status::GRPC_JSON_PARSE_ERROR; if ((c == ']') && - (reader->state == GRPC_JSON_STATE_VALUE_BEGIN) && - !reader->container_just_begun) { - return GRPC_JSON_PARSE_ERROR; + (state_ == State::GRPC_JSON_STATE_VALUE_BEGIN) && + !container_just_begun_) { + return Status::GRPC_JSON_PARSE_ERROR; } - reader->state = GRPC_JSON_STATE_VALUE_END; - switch (grpc_json_reader_container_ends(reader)) { + state_ = State::GRPC_JSON_STATE_VALUE_END; + switch (ContainerEnds()) { case GRPC_JSON_OBJECT: - reader->in_object = 1; - reader->in_array = 0; + in_object_ = 1; + in_array_ = 0; break; case GRPC_JSON_ARRAY: - reader->in_object = 0; - reader->in_array = 1; + in_object_ = 0; + 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; + GPR_ASSERT(depth_ == 0); + in_object_ = 0; + in_array_ = 0; + state_ = State::GRPC_JSON_STATE_END; break; default: - GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); + GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR); } } break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::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; + switch (state_) { + case State::GRPC_JSON_STATE_OBJECT_KEY_STRING: + escaped_string_was_key_ = 1; + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_STRING: + escaped_string_was_key_ = 0; + state_ = 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; + case State::GRPC_JSON_STATE_STRING_ESCAPE: + if (unicode_high_surrogate_ != 0) + return Status::GRPC_JSON_PARSE_ERROR; + StringAddChar('\\'); + if (escaped_string_was_key_) { + state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { - reader->state = GRPC_JSON_STATE_VALUE_STRING; + state_ = State::GRPC_JSON_STATE_VALUE_STRING; } break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::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; + container_just_begun_ = 0; + switch (state_) { + case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN: + if (c != '"') return Status::GRPC_JSON_PARSE_ERROR; + state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING; break; - case GRPC_JSON_STATE_OBJECT_KEY_STRING: - if (reader->unicode_high_surrogate != 0) { - return GRPC_JSON_PARSE_ERROR; + case State::GRPC_JSON_STATE_OBJECT_KEY_STRING: + if (unicode_high_surrogate_ != 0) { + return Status::GRPC_JSON_PARSE_ERROR; } if (c == '"') { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_END; - json_reader_set_key(reader); - json_reader_string_clear(reader); + state_ = State::GRPC_JSON_STATE_OBJECT_KEY_END; + SetKey(); + StringClear(); } else { - if (c < 32) return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_char(reader, c); + if (c < 32) return Status::GRPC_JSON_PARSE_ERROR; + StringAddChar(c); } break; - case GRPC_JSON_STATE_VALUE_STRING: - if (reader->unicode_high_surrogate != 0) { - return GRPC_JSON_PARSE_ERROR; + case State::GRPC_JSON_STATE_VALUE_STRING: + if (unicode_high_surrogate_ != 0) { + return Status::GRPC_JSON_PARSE_ERROR; } if (c == '"') { - reader->state = GRPC_JSON_STATE_VALUE_END; - json_reader_set_string(reader); - json_reader_string_clear(reader); + state_ = State::GRPC_JSON_STATE_VALUE_END; + SetString(); + StringClear(); } else { - if (c < 32) return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_char(reader, c); + if (c < 32) return Status::GRPC_JSON_PARSE_ERROR; + StringAddChar(c); } break; - case GRPC_JSON_STATE_OBJECT_KEY_END: - if (c != ':') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_BEGIN; + case State::GRPC_JSON_STATE_OBJECT_KEY_END: + if (c != ':') return Status::GRPC_JSON_PARSE_ERROR; + state_ = State::GRPC_JSON_STATE_VALUE_BEGIN; break; - case GRPC_JSON_STATE_VALUE_BEGIN: + case State::GRPC_JSON_STATE_VALUE_BEGIN: switch (c) { case 't': - reader->state = GRPC_JSON_STATE_VALUE_TRUE_R; + state_ = State::GRPC_JSON_STATE_VALUE_TRUE_R; break; case 'f': - reader->state = GRPC_JSON_STATE_VALUE_FALSE_A; + state_ = State::GRPC_JSON_STATE_VALUE_FALSE_A; break; case 'n': - reader->state = GRPC_JSON_STATE_VALUE_NULL_U; + state_ = State::GRPC_JSON_STATE_VALUE_NULL_U; break; case '"': - reader->state = GRPC_JSON_STATE_VALUE_STRING; + state_ = State::GRPC_JSON_STATE_VALUE_STRING; break; case '0': - json_reader_string_add_char(reader, c); - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_ZERO; + StringAddChar(c); + state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO; break; case '1': @@ -492,73 +490,73 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { case '8': case '9': case '-': - json_reader_string_add_char(reader, c); - reader->state = GRPC_JSON_STATE_VALUE_NUMBER; + StringAddChar(c); + state_ = 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; + container_just_begun_ = 1; + ContainerBegins(GRPC_JSON_OBJECT); + depth_++; + state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN; + in_object_ = 1; + 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; + container_just_begun_ = 1; + ContainerBegins(GRPC_JSON_ARRAY); + depth_++; + in_object_ = 0; + in_array_ = 1; break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } break; - case GRPC_JSON_STATE_STRING_ESCAPE: - if (reader->escaped_string_was_key) { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; + case State::GRPC_JSON_STATE_STRING_ESCAPE: + if (escaped_string_was_key_) { + state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { - reader->state = GRPC_JSON_STATE_VALUE_STRING; + state_ = State::GRPC_JSON_STATE_VALUE_STRING; } - if (reader->unicode_high_surrogate && c != 'u') { - return GRPC_JSON_PARSE_ERROR; + if (unicode_high_surrogate_ && c != 'u') { + return Status::GRPC_JSON_PARSE_ERROR; } switch (c) { case '"': case '/': - json_reader_string_add_char(reader, c); + StringAddChar(c); break; case 'b': - json_reader_string_add_char(reader, '\b'); + StringAddChar('\b'); break; case 'f': - json_reader_string_add_char(reader, '\f'); + StringAddChar('\f'); break; case 'n': - json_reader_string_add_char(reader, '\n'); + StringAddChar('\n'); break; case 'r': - json_reader_string_add_char(reader, '\r'); + StringAddChar('\r'); break; case 't': - json_reader_string_add_char(reader, '\t'); + StringAddChar('\t'); break; case 'u': - reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1; - reader->unicode_char = 0; + state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U1; + unicode_char_ = 0; break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::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: + case State::GRPC_JSON_STATE_STRING_ESCAPE_U1: + case State::GRPC_JSON_STATE_STRING_ESCAPE_U2: + case State::GRPC_JSON_STATE_STRING_ESCAPE_U3: + case State::GRPC_JSON_STATE_STRING_ESCAPE_U4: if ((c >= '0') && (c <= '9')) { c -= '0'; } else if ((c >= 'A') && (c <= 'F')) { @@ -566,62 +564,60 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { } else if ((c >= 'a') && (c <= 'f')) { c -= 'a' - 10; } else { - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } - reader->unicode_char = - static_cast(reader->unicode_char << 4); - reader->unicode_char = - static_cast(reader->unicode_char | c); - - switch (reader->state) { - case GRPC_JSON_STATE_STRING_ESCAPE_U1: - reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U2; + unicode_char_ = static_cast(unicode_char_ << 4); + unicode_char_ = static_cast(unicode_char_ | c); + + switch (state_) { + case State::GRPC_JSON_STATE_STRING_ESCAPE_U1: + state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U2; break; - case GRPC_JSON_STATE_STRING_ESCAPE_U2: - reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U3; + case State::GRPC_JSON_STATE_STRING_ESCAPE_U2: + state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U3; break; - case GRPC_JSON_STATE_STRING_ESCAPE_U3: - reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4; + case State::GRPC_JSON_STATE_STRING_ESCAPE_U3: + state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U4; break; - case GRPC_JSON_STATE_STRING_ESCAPE_U4: + case State::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) { + if ((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) { + if (unicode_high_surrogate_ != 0) + return Status::GRPC_JSON_PARSE_ERROR; + unicode_high_surrogate_ = unicode_char_; + } else if ((unicode_char_ & 0xfc00) == 0xdc00) { /* low surrogate utf-16 */ uint32_t utf32; - if (reader->unicode_high_surrogate == 0) - return GRPC_JSON_PARSE_ERROR; + if (unicode_high_surrogate_ == 0) + return Status::GRPC_JSON_PARSE_ERROR; utf32 = 0x10000; utf32 += static_cast( - (reader->unicode_high_surrogate - 0xd800) * 0x400); - utf32 += static_cast(reader->unicode_char - 0xdc00); - json_reader_string_add_utf32(reader, utf32); - reader->unicode_high_surrogate = 0; + (unicode_high_surrogate_ - 0xd800) * 0x400); + utf32 += static_cast(unicode_char_ - 0xdc00); + StringAddUtf32(utf32); + 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 (unicode_high_surrogate_ != 0) + return Status::GRPC_JSON_PARSE_ERROR; + StringAddUtf32(unicode_char_); } - if (reader->escaped_string_was_key) { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; + if (escaped_string_was_key_) { + state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { - reader->state = GRPC_JSON_STATE_VALUE_STRING; + state_ = State::GRPC_JSON_STATE_VALUE_STRING; } break; default: - GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); + GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR); } break; - case GRPC_JSON_STATE_VALUE_NUMBER: - json_reader_string_add_char(reader, c); + case State::GRPC_JSON_STATE_VALUE_NUMBER: + StringAddChar(c); switch (c) { case '0': case '1': @@ -636,18 +632,18 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { break; case 'e': case 'E': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; + state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_E; break; case '.': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; + state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT; break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } break; - case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: - json_reader_string_add_char(reader, c); + case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: + StringAddChar(c); switch (c) { case '0': case '1': @@ -662,21 +658,21 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { break; case 'e': case 'E': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; + state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_E; break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::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; + case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO: + if (c != '.') return Status::GRPC_JSON_PARSE_ERROR; + StringAddChar(c); + state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT; break; - case GRPC_JSON_STATE_VALUE_NUMBER_DOT: - json_reader_string_add_char(reader, c); + case State::GRPC_JSON_STATE_VALUE_NUMBER_DOT: + StringAddChar(c); switch (c) { case '0': case '1': @@ -688,15 +684,15 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { case '7': case '8': case '9': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL; + state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL; break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } break; - case GRPC_JSON_STATE_VALUE_NUMBER_E: - json_reader_string_add_char(reader, c); + case State::GRPC_JSON_STATE_VALUE_NUMBER_E: + StringAddChar(c); switch (c) { case '0': case '1': @@ -710,15 +706,15 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { case '9': case '+': case '-': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_EPM; + state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_EPM; break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } break; - case GRPC_JSON_STATE_VALUE_NUMBER_EPM: - json_reader_string_add_char(reader, c); + case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM: + StringAddChar(c); switch (c) { case '0': case '1': @@ -732,108 +728,108 @@ static grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { case '9': break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::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; + case State::GRPC_JSON_STATE_VALUE_TRUE_R: + if (c != 'r') return Status::GRPC_JSON_PARSE_ERROR; + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_TRUE_U: + if (c != 'u') return Status::GRPC_JSON_PARSE_ERROR; + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_TRUE_E: + if (c != 'e') return Status::GRPC_JSON_PARSE_ERROR; + SetTrue(); + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_FALSE_A: + if (c != 'a') return Status::GRPC_JSON_PARSE_ERROR; + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_FALSE_L: + if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR; + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_FALSE_S: + if (c != 's') return Status::GRPC_JSON_PARSE_ERROR; + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_FALSE_E: + if (c != 'e') return Status::GRPC_JSON_PARSE_ERROR; + SetFalse(); + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_NULL_U: + if (c != 'u') return Status::GRPC_JSON_PARSE_ERROR; + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_NULL_L1: + if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR; + state_ = 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; + case State::GRPC_JSON_STATE_VALUE_NULL_L2: + if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR; + SetNull(); + state_ = 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: + case State::GRPC_JSON_STATE_VALUE_END: switch (c) { case ',': case '}': case ']': - GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); + GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR); break; default: - return GRPC_JSON_PARSE_ERROR; + return Status::GRPC_JSON_PARSE_ERROR; } break; - case GRPC_JSON_STATE_END: - return GRPC_JSON_PARSE_ERROR; + case State::GRPC_JSON_STATE_END: + return Status::GRPC_JSON_PARSE_ERROR; } } } - GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); + GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR); } -/* And finally, let's define our public API. */ -grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) { - if (input == nullptr) return nullptr; - // Initialize reader. - grpc_json_reader reader; - memset(&reader, 0, sizeof(reader)); - reader.string_ptr = reader.input = reinterpret_cast(input); - reader.remaining_input = size; - json_reader_string_clear(&reader); - reader.state = GRPC_JSON_STATE_VALUE_BEGIN; - // Perform read. - grpc_json_reader_status status = grpc_json_reader_run(&reader); - // Process results. - grpc_json* json = reader.top; - if ((status != GRPC_JSON_DONE) && json != nullptr) { +grpc_json* JsonReader::Parse(char* input, size_t size) { + JsonReader reader(input, size); + Status status = reader.Run(); + grpc_json* json = reader.top_; + if ((status != Status::GRPC_JSON_DONE) && json != nullptr) { grpc_json_destroy(json); json = nullptr; } return json; } +} // namespace + +} // namespace grpc_core + +/* And finally, let's define our public API. */ +grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) { + if (input == nullptr) return nullptr; + return grpc_core::JsonReader::Parse(input, size); +} + #define UNBOUND_JSON_STRING_LENGTH 0x7fffffff grpc_json* grpc_json_parse_string(char* input) { diff --git a/src/core/lib/json/json_writer.cc b/src/core/lib/json/json_writer.cc index 6dbb08ccd1e..199d568e7ea 100644 --- a/src/core/lib/json/json_writer.cc +++ b/src/core/lib/json/json_writer.cc @@ -26,6 +26,10 @@ #include "src/core/lib/json/json.h" +namespace grpc_core { + +namespace { + /* The idea of the writer is basically symmetrical of the reader. While the * reader emits various calls to your code, the writer takes basically the * same calls and emit json out of it. It doesn't try to make any check on @@ -37,133 +41,140 @@ * cut the conversion short, before any invalid UTF-8 sequence, thus forming * a valid UTF-8 string overall. */ +class JsonWriter { + public: + static char* Dump(const grpc_json* json, int indent); + + private: + explicit JsonWriter(int indent) : indent_(indent) {} -typedef struct grpc_json_writer { - int indent; - int depth; - int container_empty; - int got_key; - char* output; - size_t free_space; - size_t string_len; - size_t allocated; -} grpc_json_writer; + void OutputCheck(size_t needed); + void OutputChar(char c); + void OutputStringWithLen(const char* str, size_t len); + void OutputString(const char* str); + void OutputIndent(); + void ValueEnd(); + void EscapeUtf16(uint16_t utf16); + void EscapeString(const char* string); + void ContainerBegins(grpc_json_type type); + void ContainerEnds(grpc_json_type type); + void ObjectKey(const char* string); + void ValueRaw(const char* string); + void ValueRawWithLen(const char* string, size_t len); + void ValueString(const char* string); + void DumpRecursive(const grpc_json* json, int in_object); + + int indent_; + int depth_ = 0; + int container_empty_ = 1; + int got_key_ = 0; + char* output_ = nullptr; + size_t free_space_ = 0; + size_t string_len_ = 0; + size_t allocated_ = 0; +}; /* 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 json_writer_output_check(grpc_json_writer* writer, size_t needed) { - if (writer->free_space >= needed) return; - needed -= writer->free_space; +void JsonWriter::OutputCheck(size_t needed) { + if (free_space_ >= needed) return; + needed -= free_space_; /* Round up by 256 bytes. */ needed = (needed + 0xff) & ~0xffU; - writer->output = static_cast( - gpr_realloc(writer->output, writer->allocated + needed)); - writer->free_space += needed; - writer->allocated += needed; + output_ = static_cast(gpr_realloc(output_, allocated_ + needed)); + free_space_ += needed; + allocated_ += needed; } -static void json_writer_output_char(grpc_json_writer* writer, char c) { - json_writer_output_check(writer, 1); - writer->output[writer->string_len++] = c; - writer->free_space--; +void JsonWriter::OutputChar(char c) { + OutputCheck(1); + output_[string_len_++] = c; + free_space_--; } -static void json_writer_output_string_with_len(grpc_json_writer* writer, - const char* str, size_t len) { - json_writer_output_check(writer, len); - memcpy(writer->output + writer->string_len, str, len); - writer->string_len += len; - writer->free_space -= len; +void JsonWriter::OutputStringWithLen(const char* str, size_t len) { + OutputCheck(len); + memcpy(output_ + string_len_, str, len); + string_len_ += len; + free_space_ -= len; } -static void json_writer_output_string(grpc_json_writer* writer, - const char* str) { +void JsonWriter::OutputString(const char* str) { size_t len = strlen(str); - json_writer_output_string_with_len(writer, str, len); + OutputStringWithLen(str, len); } -static void json_writer_output_indent(grpc_json_writer* writer) { +void JsonWriter::OutputIndent() { static const char spacesstr[] = " " " " " " " "; - - unsigned spaces = static_cast(writer->depth * writer->indent); - - if (writer->indent == 0) return; - - if (writer->got_key) { - json_writer_output_char(writer, ' '); + unsigned spaces = static_cast(depth_ * indent_); + if (indent_ == 0) return; + if (got_key_) { + OutputChar(' '); return; } - while (spaces >= (sizeof(spacesstr) - 1)) { - json_writer_output_string_with_len(writer, spacesstr, - sizeof(spacesstr) - 1); + OutputStringWithLen(spacesstr, sizeof(spacesstr) - 1); spaces -= static_cast(sizeof(spacesstr) - 1); } - if (spaces == 0) return; - - json_writer_output_string_with_len( - writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces); + OutputStringWithLen(spacesstr + sizeof(spacesstr) - 1 - spaces, spaces); } -static void json_writer_value_end(grpc_json_writer* writer) { - if (writer->container_empty) { - writer->container_empty = 0; - if ((writer->indent == 0) || (writer->depth == 0)) return; - json_writer_output_char(writer, '\n'); +void JsonWriter::ValueEnd() { + if (container_empty_) { + container_empty_ = 0; + if (indent_ == 0 || depth_ == 0) return; + OutputChar('\n'); } else { - json_writer_output_char(writer, ','); - if (writer->indent == 0) return; - json_writer_output_char(writer, '\n'); + OutputChar(','); + if (indent_ == 0) return; + OutputChar('\n'); } } -static void json_writer_escape_utf16(grpc_json_writer* writer, uint16_t utf16) { +void JsonWriter::EscapeUtf16(uint16_t utf16) { static const char hex[] = "0123456789abcdef"; - - json_writer_output_string_with_len(writer, "\\u", 2); - json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]); - json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]); - json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]); - json_writer_output_char(writer, hex[(utf16)&0x0f]); + OutputStringWithLen("\\u", 2); + OutputChar(hex[(utf16 >> 12) & 0x0f]); + OutputChar(hex[(utf16 >> 8) & 0x0f]); + OutputChar(hex[(utf16 >> 4) & 0x0f]); + OutputChar(hex[(utf16)&0x0f]); } -static void json_writer_escape_string(grpc_json_writer* writer, - const char* string) { - json_writer_output_char(writer, '"'); - - for (;;) { +void JsonWriter::EscapeString(const char* string) { + OutputChar('"'); + while (true) { uint8_t c = static_cast(*string++); if (c == 0) { break; - } else if ((c >= 32) && (c <= 126)) { - if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\'); - json_writer_output_char(writer, static_cast(c)); - } else if ((c < 32) || (c == 127)) { + } else if (c >= 32 && c <= 126) { + if (c == '\\' || c == '"') OutputChar('\\'); + OutputChar(static_cast(c)); + } else if (c < 32 || c == 127) { switch (c) { case '\b': - json_writer_output_string_with_len(writer, "\\b", 2); + OutputStringWithLen("\\b", 2); break; case '\f': - json_writer_output_string_with_len(writer, "\\f", 2); + OutputStringWithLen("\\f", 2); break; case '\n': - json_writer_output_string_with_len(writer, "\\n", 2); + OutputStringWithLen("\\n", 2); break; case '\r': - json_writer_output_string_with_len(writer, "\\r", 2); + OutputStringWithLen("\\r", 2); break; case '\t': - json_writer_output_string_with_len(writer, "\\t", 2); + OutputStringWithLen("\\t", 2); break; default: - json_writer_escape_utf16(writer, c); + EscapeUtf16(c); break; } } else { @@ -218,101 +229,89 @@ static void json_writer_escape_string(grpc_json_writer* writer, * That range is exactly 20 bits. */ utf32 -= 0x10000; - json_writer_escape_utf16(writer, - static_cast(0xd800 | (utf32 >> 10))); - json_writer_escape_utf16( - writer, static_cast(0xdc00 | (utf32 & 0x3ff))); + EscapeUtf16(static_cast(0xd800 | (utf32 >> 10))); + EscapeUtf16(static_cast(0xdc00 | (utf32 & 0x3ff))); } else { - json_writer_escape_utf16(writer, static_cast(utf32)); + EscapeUtf16(static_cast(utf32)); } } } - - json_writer_output_char(writer, '"'); + OutputChar('"'); } -static void grpc_json_writer_container_begins(grpc_json_writer* writer, - grpc_json_type type) { - if (!writer->got_key) json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '['); - writer->container_empty = 1; - writer->got_key = 0; - writer->depth++; +void JsonWriter::ContainerBegins(grpc_json_type type) { + if (!got_key_) ValueEnd(); + OutputIndent(); + OutputChar(type == GRPC_JSON_OBJECT ? '{' : '['); + container_empty_ = 1; + got_key_ = 0; + depth_++; } -static void grpc_json_writer_container_ends(grpc_json_writer* writer, - grpc_json_type type) { - if (writer->indent && !writer->container_empty) - json_writer_output_char(writer, '\n'); - writer->depth--; - if (!writer->container_empty) json_writer_output_indent(writer); - json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']'); - writer->container_empty = 0; - writer->got_key = 0; +void JsonWriter::ContainerEnds(grpc_json_type type) { + if (indent_ && !container_empty_) OutputChar('\n'); + depth_--; + if (!container_empty_) OutputIndent(); + OutputChar(type == GRPC_JSON_OBJECT ? '}' : ']'); + container_empty_ = 0; + got_key_ = 0; } -static void grpc_json_writer_object_key(grpc_json_writer* writer, - const char* string) { - json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_escape_string(writer, string); - json_writer_output_char(writer, ':'); - writer->got_key = 1; +void JsonWriter::ObjectKey(const char* string) { + ValueEnd(); + OutputIndent(); + EscapeString(string); + OutputChar(':'); + got_key_ = 1; } -static void grpc_json_writer_value_raw(grpc_json_writer* writer, - const char* string) { - if (!writer->got_key) json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_output_string(writer, string); - writer->got_key = 0; +void JsonWriter::ValueRaw(const char* string) { + if (!got_key_) ValueEnd(); + OutputIndent(); + OutputString(string); + got_key_ = 0; } -static void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, - const char* string, - size_t len) { - if (!writer->got_key) json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_output_string_with_len(writer, string, len); - writer->got_key = 0; +void JsonWriter::ValueRawWithLen(const char* string, size_t len) { + if (!got_key_) ValueEnd(); + OutputIndent(); + OutputStringWithLen(string, len); + got_key_ = 0; } -static void grpc_json_writer_value_string(grpc_json_writer* writer, - const char* string) { - if (!writer->got_key) json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_escape_string(writer, string); - writer->got_key = 0; +void JsonWriter::ValueString(const char* string) { + if (!got_key_) ValueEnd(); + OutputIndent(); + EscapeString(string); + got_key_ = 0; } -static void json_dump_recursive(grpc_json_writer* writer, const grpc_json* json, - int in_object) { - while (json) { - if (in_object) grpc_json_writer_object_key(writer, json->key); +void JsonWriter::DumpRecursive(const grpc_json* json, int in_object) { + while (json != nullptr) { + if (in_object) ObjectKey(json->key); switch (json->type) { case GRPC_JSON_OBJECT: case GRPC_JSON_ARRAY: - grpc_json_writer_container_begins(writer, json->type); - if (json->child) - json_dump_recursive(writer, json->child, - json->type == GRPC_JSON_OBJECT); - grpc_json_writer_container_ends(writer, json->type); + ContainerBegins(json->type); + if (json->child != nullptr) { + DumpRecursive(json->child, json->type == GRPC_JSON_OBJECT); + } + ContainerEnds(json->type); break; case GRPC_JSON_STRING: - grpc_json_writer_value_string(writer, json->value); + ValueString(json->value); break; case GRPC_JSON_NUMBER: - grpc_json_writer_value_raw(writer, json->value); + ValueRaw(json->value); break; case GRPC_JSON_TRUE: - grpc_json_writer_value_raw_with_len(writer, "true", 4); + ValueRawWithLen("true", 4); break; case GRPC_JSON_FALSE: - grpc_json_writer_value_raw_with_len(writer, "false", 5); + ValueRawWithLen("false", 5); break; case GRPC_JSON_NULL: - grpc_json_writer_value_raw_with_len(writer, "null", 4); + ValueRawWithLen("null", 4); break; default: GPR_UNREACHABLE_CODE(abort()); @@ -321,12 +320,17 @@ static void json_dump_recursive(grpc_json_writer* writer, const grpc_json* json, } } +char* JsonWriter::Dump(const grpc_json* json, int indent) { + JsonWriter writer(indent); + writer.DumpRecursive(json, 0); + writer.OutputChar(0); + return writer.output_; +} + +} // namespace + +} // namespace grpc_core + char* grpc_json_dump_to_string(const grpc_json* json, int indent) { - grpc_json_writer writer; - memset(&writer, 0, sizeof(writer)); - writer.container_empty = 1; - writer.indent = indent; - json_dump_recursive(&writer, json, 0); - json_writer_output_char(&writer, 0); - return writer.output; + return grpc_core::JsonWriter::Dump(json, indent); }