Convert json_reader and json_writer to C++

pull/21224/head
Mark D. Roth 5 years ago
parent 380b70d3a6
commit 4520072f92
  1. 776
      src/core/lib/json/json_reader.cc
  2. 296
      src/core/lib/json/json_writer.cc

File diff suppressed because it is too large Load Diff

@ -26,6 +26,10 @@
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
namespace grpc_core {
namespace {
/* The idea of the writer is basically symmetrical of the reader. While the /* 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 * 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 * 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 * cut the conversion short, before any invalid UTF-8 sequence, thus forming
* a valid UTF-8 string overall. * 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 { void OutputCheck(size_t needed);
int indent; void OutputChar(char c);
int depth; void OutputStringWithLen(const char* str, size_t len);
int container_empty; void OutputString(const char* str);
int got_key; void OutputIndent();
char* output; void ValueEnd();
size_t free_space; void EscapeUtf16(uint16_t utf16);
size_t string_len; void EscapeString(const char* string);
size_t allocated; void ContainerBegins(grpc_json_type type);
} grpc_json_writer; 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, /* 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 * and will enlarge it if necessary. We're only allocating chunks of 256
* bytes at a time (or multiples thereof). * bytes at a time (or multiples thereof).
*/ */
static void json_writer_output_check(grpc_json_writer* writer, size_t needed) { void JsonWriter::OutputCheck(size_t needed) {
if (writer->free_space >= needed) return; if (free_space_ >= needed) return;
needed -= writer->free_space; needed -= free_space_;
/* Round up by 256 bytes. */ /* Round up by 256 bytes. */
needed = (needed + 0xff) & ~0xffU; needed = (needed + 0xff) & ~0xffU;
writer->output = static_cast<char*>( output_ = static_cast<char*>(gpr_realloc(output_, allocated_ + needed));
gpr_realloc(writer->output, writer->allocated + needed)); free_space_ += needed;
writer->free_space += needed; allocated_ += needed;
writer->allocated += needed;
} }
static void json_writer_output_char(grpc_json_writer* writer, char c) { void JsonWriter::OutputChar(char c) {
json_writer_output_check(writer, 1); OutputCheck(1);
writer->output[writer->string_len++] = c; output_[string_len_++] = c;
writer->free_space--; free_space_--;
} }
static void json_writer_output_string_with_len(grpc_json_writer* writer, void JsonWriter::OutputStringWithLen(const char* str, size_t len) {
const char* str, size_t len) { OutputCheck(len);
json_writer_output_check(writer, len); memcpy(output_ + string_len_, str, len);
memcpy(writer->output + writer->string_len, str, len); string_len_ += len;
writer->string_len += len; free_space_ -= len;
writer->free_space -= len;
} }
static void json_writer_output_string(grpc_json_writer* writer, void JsonWriter::OutputString(const char* str) {
const char* str) {
size_t len = strlen(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[] = static const char spacesstr[] =
" " " "
" " " "
" " " "
" "; " ";
unsigned spaces = static_cast<unsigned>(depth_ * indent_);
unsigned spaces = static_cast<unsigned>(writer->depth * writer->indent); if (indent_ == 0) return;
if (got_key_) {
if (writer->indent == 0) return; OutputChar(' ');
if (writer->got_key) {
json_writer_output_char(writer, ' ');
return; return;
} }
while (spaces >= (sizeof(spacesstr) - 1)) { while (spaces >= (sizeof(spacesstr) - 1)) {
json_writer_output_string_with_len(writer, spacesstr, OutputStringWithLen(spacesstr, sizeof(spacesstr) - 1);
sizeof(spacesstr) - 1);
spaces -= static_cast<unsigned>(sizeof(spacesstr) - 1); spaces -= static_cast<unsigned>(sizeof(spacesstr) - 1);
} }
if (spaces == 0) return; if (spaces == 0) return;
OutputStringWithLen(spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
json_writer_output_string_with_len(
writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
} }
static void json_writer_value_end(grpc_json_writer* writer) { void JsonWriter::ValueEnd() {
if (writer->container_empty) { if (container_empty_) {
writer->container_empty = 0; container_empty_ = 0;
if ((writer->indent == 0) || (writer->depth == 0)) return; if (indent_ == 0 || depth_ == 0) return;
json_writer_output_char(writer, '\n'); OutputChar('\n');
} else { } else {
json_writer_output_char(writer, ','); OutputChar(',');
if (writer->indent == 0) return; if (indent_ == 0) return;
json_writer_output_char(writer, '\n'); 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"; static const char hex[] = "0123456789abcdef";
OutputStringWithLen("\\u", 2);
json_writer_output_string_with_len(writer, "\\u", 2); OutputChar(hex[(utf16 >> 12) & 0x0f]);
json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]); OutputChar(hex[(utf16 >> 8) & 0x0f]);
json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]); OutputChar(hex[(utf16 >> 4) & 0x0f]);
json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]); OutputChar(hex[(utf16)&0x0f]);
json_writer_output_char(writer, hex[(utf16)&0x0f]);
} }
static void json_writer_escape_string(grpc_json_writer* writer, void JsonWriter::EscapeString(const char* string) {
const char* string) { OutputChar('"');
json_writer_output_char(writer, '"'); while (true) {
for (;;) {
uint8_t c = static_cast<uint8_t>(*string++); uint8_t c = static_cast<uint8_t>(*string++);
if (c == 0) { if (c == 0) {
break; break;
} else if ((c >= 32) && (c <= 126)) { } else if (c >= 32 && c <= 126) {
if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\'); if (c == '\\' || c == '"') OutputChar('\\');
json_writer_output_char(writer, static_cast<char>(c)); OutputChar(static_cast<char>(c));
} else if ((c < 32) || (c == 127)) { } else if (c < 32 || c == 127) {
switch (c) { switch (c) {
case '\b': case '\b':
json_writer_output_string_with_len(writer, "\\b", 2); OutputStringWithLen("\\b", 2);
break; break;
case '\f': case '\f':
json_writer_output_string_with_len(writer, "\\f", 2); OutputStringWithLen("\\f", 2);
break; break;
case '\n': case '\n':
json_writer_output_string_with_len(writer, "\\n", 2); OutputStringWithLen("\\n", 2);
break; break;
case '\r': case '\r':
json_writer_output_string_with_len(writer, "\\r", 2); OutputStringWithLen("\\r", 2);
break; break;
case '\t': case '\t':
json_writer_output_string_with_len(writer, "\\t", 2); OutputStringWithLen("\\t", 2);
break; break;
default: default:
json_writer_escape_utf16(writer, c); EscapeUtf16(c);
break; break;
} }
} else { } else {
@ -218,101 +229,89 @@ static void json_writer_escape_string(grpc_json_writer* writer,
* That range is exactly 20 bits. * That range is exactly 20 bits.
*/ */
utf32 -= 0x10000; utf32 -= 0x10000;
json_writer_escape_utf16(writer, EscapeUtf16(static_cast<uint16_t>(0xd800 | (utf32 >> 10)));
static_cast<uint16_t>(0xd800 | (utf32 >> 10))); EscapeUtf16(static_cast<uint16_t>(0xdc00 | (utf32 & 0x3ff)));
json_writer_escape_utf16(
writer, static_cast<uint16_t>(0xdc00 | (utf32 & 0x3ff)));
} else { } else {
json_writer_escape_utf16(writer, static_cast<uint16_t>(utf32)); EscapeUtf16(static_cast<uint16_t>(utf32));
} }
} }
} }
OutputChar('"');
json_writer_output_char(writer, '"');
} }
static void grpc_json_writer_container_begins(grpc_json_writer* writer, void JsonWriter::ContainerBegins(grpc_json_type type) {
grpc_json_type type) { if (!got_key_) ValueEnd();
if (!writer->got_key) json_writer_value_end(writer); OutputIndent();
json_writer_output_indent(writer); OutputChar(type == GRPC_JSON_OBJECT ? '{' : '[');
json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '['); container_empty_ = 1;
writer->container_empty = 1; got_key_ = 0;
writer->got_key = 0; depth_++;
writer->depth++;
} }
static void grpc_json_writer_container_ends(grpc_json_writer* writer, void JsonWriter::ContainerEnds(grpc_json_type type) {
grpc_json_type type) { if (indent_ && !container_empty_) OutputChar('\n');
if (writer->indent && !writer->container_empty) depth_--;
json_writer_output_char(writer, '\n'); if (!container_empty_) OutputIndent();
writer->depth--; OutputChar(type == GRPC_JSON_OBJECT ? '}' : ']');
if (!writer->container_empty) json_writer_output_indent(writer); container_empty_ = 0;
json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']'); got_key_ = 0;
writer->container_empty = 0;
writer->got_key = 0;
} }
static void grpc_json_writer_object_key(grpc_json_writer* writer, void JsonWriter::ObjectKey(const char* string) {
const char* string) { ValueEnd();
json_writer_value_end(writer); OutputIndent();
json_writer_output_indent(writer); EscapeString(string);
json_writer_escape_string(writer, string); OutputChar(':');
json_writer_output_char(writer, ':'); got_key_ = 1;
writer->got_key = 1;
} }
static void grpc_json_writer_value_raw(grpc_json_writer* writer, void JsonWriter::ValueRaw(const char* string) {
const char* string) { if (!got_key_) ValueEnd();
if (!writer->got_key) json_writer_value_end(writer); OutputIndent();
json_writer_output_indent(writer); OutputString(string);
json_writer_output_string(writer, string); got_key_ = 0;
writer->got_key = 0;
} }
static void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, void JsonWriter::ValueRawWithLen(const char* string, size_t len) {
const char* string, if (!got_key_) ValueEnd();
size_t len) { OutputIndent();
if (!writer->got_key) json_writer_value_end(writer); OutputStringWithLen(string, len);
json_writer_output_indent(writer); got_key_ = 0;
json_writer_output_string_with_len(writer, string, len);
writer->got_key = 0;
} }
static void grpc_json_writer_value_string(grpc_json_writer* writer, void JsonWriter::ValueString(const char* string) {
const char* string) { if (!got_key_) ValueEnd();
if (!writer->got_key) json_writer_value_end(writer); OutputIndent();
json_writer_output_indent(writer); EscapeString(string);
json_writer_escape_string(writer, string); got_key_ = 0;
writer->got_key = 0;
} }
static void json_dump_recursive(grpc_json_writer* writer, const grpc_json* json, void JsonWriter::DumpRecursive(const grpc_json* json, int in_object) {
int in_object) { while (json != nullptr) {
while (json) { if (in_object) ObjectKey(json->key);
if (in_object) grpc_json_writer_object_key(writer, json->key);
switch (json->type) { switch (json->type) {
case GRPC_JSON_OBJECT: case GRPC_JSON_OBJECT:
case GRPC_JSON_ARRAY: case GRPC_JSON_ARRAY:
grpc_json_writer_container_begins(writer, json->type); ContainerBegins(json->type);
if (json->child) if (json->child != nullptr) {
json_dump_recursive(writer, json->child, DumpRecursive(json->child, json->type == GRPC_JSON_OBJECT);
json->type == GRPC_JSON_OBJECT); }
grpc_json_writer_container_ends(writer, json->type); ContainerEnds(json->type);
break; break;
case GRPC_JSON_STRING: case GRPC_JSON_STRING:
grpc_json_writer_value_string(writer, json->value); ValueString(json->value);
break; break;
case GRPC_JSON_NUMBER: case GRPC_JSON_NUMBER:
grpc_json_writer_value_raw(writer, json->value); ValueRaw(json->value);
break; break;
case GRPC_JSON_TRUE: case GRPC_JSON_TRUE:
grpc_json_writer_value_raw_with_len(writer, "true", 4); ValueRawWithLen("true", 4);
break; break;
case GRPC_JSON_FALSE: case GRPC_JSON_FALSE:
grpc_json_writer_value_raw_with_len(writer, "false", 5); ValueRawWithLen("false", 5);
break; break;
case GRPC_JSON_NULL: case GRPC_JSON_NULL:
grpc_json_writer_value_raw_with_len(writer, "null", 4); ValueRawWithLen("null", 4);
break; break;
default: default:
GPR_UNREACHABLE_CODE(abort()); 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) { char* grpc_json_dump_to_string(const grpc_json* json, int indent) {
grpc_json_writer writer; return grpc_core::JsonWriter::Dump(json, indent);
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;
} }

Loading…
Cancel
Save