From 03cc4eab0170befe52f220f0efe4f1c9b097c2d5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 14 Apr 2018 14:19:24 -0700 Subject: [PATCH] json: Allow formatting read json back to writer. --- ext/native/json/json_writer.cpp | 134 ++++++++++++++++++++++++++++++++ ext/native/json/json_writer.h | 20 ++++- 2 files changed, 152 insertions(+), 2 deletions(-) diff --git a/ext/native/json/json_writer.cpp b/ext/native/json/json_writer.cpp index ea826a312c..95c2a3983f 100644 --- a/ext/native/json/json_writer.cpp +++ b/ext/native/json/json_writer.cpp @@ -1,5 +1,6 @@ #include #include +#include "ext/vjson/json.h" #include "json/json_writer.h" JsonWriter::JsonWriter(int flags) { @@ -15,6 +16,16 @@ void JsonWriter::begin() { stack_.push_back(StackEntry(DICT)); } +void JsonWriter::beginArray() { + str_ << "["; + stack_.push_back(StackEntry(ARRAY)); +} + +void JsonWriter::beginRaw() { + // For the uncommon case of writing a value directly, to avoid duplicated code. + stack_.push_back(StackEntry(RAW)); +} + void JsonWriter::end() { pop(); if (pretty_) @@ -41,6 +52,8 @@ const char *JsonWriter::indent() const { } const char *JsonWriter::arrayIndent() const { + if (!pretty_) + return ""; int amount = (int)stack_.size() + 1; amount *= 2; // 2-space indent. return stack_.back().first ? indent(amount) : ""; @@ -128,6 +141,19 @@ void JsonWriter::writeString(const char *name, const char *value) { stack_.back().first = false; } +void JsonWriter::writeRaw(const char *value) { + str_ << arrayComma() << arrayIndent() << value; + stack_.back().first = false; +} + +void JsonWriter::writeRaw(const char *name, const char *value) { + str_ << comma() << indent() << "\""; + writeEscapedString(name); + str_ << (pretty_ ? "\": " : "\":"); + str_ << value; + stack_.back().first = false; +} + void JsonWriter::pop() { BlockType type = stack_.back().type; stack_.pop_back(); @@ -140,6 +166,8 @@ void JsonWriter::pop() { case DICT: str_ << "}"; break; + case RAW: + break; } if (stack_.size() > 0) stack_.back().first = false; @@ -181,3 +209,109 @@ void JsonWriter::writeEscapedString(const char *str) { str_ << str; } } + +static void json_stringify_object(JsonWriter &writer, const json_value *value); +static void json_stringify_array(JsonWriter &writer, const json_value *value); + +std::string json_stringify(const json_value *value) { + JsonWriter writer; + + // Handle direct values too, not just objects. + switch (value->type) { + case JSON_NULL: + case JSON_STRING: + case JSON_INT: + case JSON_FLOAT: + case JSON_BOOL: + writer.beginRaw(); + // It's the same as a one entry array without brackets, so reuse. + json_stringify_array(writer, value); + break; + + case JSON_OBJECT: + writer.begin(); + for (const json_value *it = value->first_child; it; it = it->next_sibling) { + json_stringify_object(writer, it); + } + break; + case JSON_ARRAY: + writer.beginArray(); + for (const json_value *it = value->first_child; it; it = it->next_sibling) { + json_stringify_array(writer, it); + } + break; + } + + writer.end(); + return writer.str(); +} + +static void json_stringify_object(JsonWriter &writer, const json_value *value) { + switch (value->type) { + case JSON_NULL: + writer.writeRaw(value->name, "null"); + break; + case JSON_STRING: + writer.writeString(value->name, value->string_value); + break; + case JSON_INT: + writer.writeInt(value->name, value->int_value); + break; + case JSON_FLOAT: + writer.writeFloat(value->name, value->float_value); + break; + case JSON_BOOL: + writer.writeBool(value->name, value->int_value != 0); + break; + + case JSON_OBJECT: + writer.pushDict(value->name); + for (const json_value *it = value->first_child; it; it = it->next_sibling) { + json_stringify_object(writer, it); + } + writer.pop(); + break; + case JSON_ARRAY: + writer.pushArray(value->name); + for (const json_value *it = value->first_child; it; it = it->next_sibling) { + json_stringify_array(writer, it); + } + writer.pop(); + break; + } +} + +static void json_stringify_array(JsonWriter &writer, const json_value *value) { + switch (value->type) { + case JSON_NULL: + writer.writeRaw("null"); + break; + case JSON_STRING: + writer.writeString(value->string_value); + break; + case JSON_INT: + writer.writeInt(value->int_value); + break; + case JSON_FLOAT: + writer.writeFloat(value->float_value); + break; + case JSON_BOOL: + writer.writeBool(value->int_value != 0); + break; + + case JSON_OBJECT: + writer.begin(); + for (const json_value *it = value->first_child; it; it = it->next_sibling) { + json_stringify_object(writer, it); + } + writer.pop(); + break; + case JSON_ARRAY: + writer.beginArray(); + for (const json_value *it = value->first_child; it; it = it->next_sibling) { + json_stringify_array(writer, it); + } + writer.pop(); + break; + } +} diff --git a/ext/native/json/json_writer.h b/ext/native/json/json_writer.h index 378a09f5b9..cf4ba87259 100644 --- a/ext/native/json/json_writer.h +++ b/ext/native/json/json_writer.h @@ -7,8 +7,7 @@ // // Does not deal with encodings in any way. // -// Zero dependencies apart from stdlib. -// See json_writer_test.cpp for usage. +// Zero dependencies apart from stdlib (if you remove the vhjson usage.) #include #include @@ -19,6 +18,8 @@ public: JsonWriter(int flags = NORMAL); ~JsonWriter(); void begin(); + void beginArray(); + void beginRaw(); void end(); void pushDict(const char *name); void pushArray(const char *name); @@ -40,6 +41,17 @@ public: void writeString(const std::string &name, const std::string &value) { writeString(name.c_str(), value.c_str()); } + void writeRaw(const char *value); + void writeRaw(const char *name, const char *value); + void writeRaw(const std::string &value) { + writeRaw(value.c_str()); + } + void writeRaw(const char *name, const std::string &value) { + writeRaw(name, value.c_str()); + } + void writeRaw(const std::string &name, const std::string &value) { + writeRaw(name.c_str(), value.c_str()); + } std::string str() const { return str_.str(); @@ -61,6 +73,7 @@ private: enum BlockType { ARRAY, DICT, + RAW, }; struct StackEntry { StackEntry(BlockType t) : type(t), first(true) {} @@ -71,3 +84,6 @@ private: std::ostringstream str_; bool pretty_; }; + +struct json_value; +std::string json_stringify(const json_value *json);