diff --git a/src/coders/json.cpp b/src/coders/json.cpp index ea2d33c9..a15a40a2 100644 --- a/src/coders/json.cpp +++ b/src/coders/json.cpp @@ -63,6 +63,10 @@ void stringifyValue( stringifyObj(map->get(), ss, indent, indentstr, nice); } else if (auto listptr = std::get_if(&value)) { stringifyArr(listptr->get(), ss, indent, indentstr, nice); + } else if (auto bytesptr = std::get_if(&value)) { + auto bytes = bytesptr->get(); + ss << "\"" << util::base64_encode(bytes->data(), bytes->size()); + ss << "\""; } else if (auto flag = std::get_if(&value)) { ss << (*flag ? "true" : "false"); } else if (auto num = std::get_if(&value)) { diff --git a/src/data/dynamic.cpp b/src/data/dynamic.cpp index f49a0aee..42100735 100644 --- a/src/data/dynamic.cpp +++ b/src/data/dynamic.cpp @@ -249,6 +249,12 @@ List_sptr Map::list(const std::string& key) const { return nullptr; } +ByteBuffer_sptr Map::bytes(const std::string& key) const { + auto found = values.find(key); + if (found != values.end()) return std::get(found->second); + return nullptr; +} + void Map::flag(const std::string& key, bool& dst) const { dst = get(key, dst); } diff --git a/src/data/dynamic.hpp b/src/data/dynamic.hpp index 838e5fa8..ed7a0786 100644 --- a/src/data/dynamic.hpp +++ b/src/data/dynamic.hpp @@ -15,11 +15,11 @@ namespace dynamic { none = 0, map, list, + bytes, string, number, boolean, - integer, - bytes + integer }; const std::string& type_name(const Value& value); @@ -127,6 +127,7 @@ namespace dynamic { void num(const std::string& key, double& dst) const; Map_sptr map(const std::string& key) const; List_sptr list(const std::string& key) const; + ByteBuffer_sptr bytes(const std::string& key) const; void flag(const std::string& key, bool& dst) const; Map& put(std::string key, std::unique_ptr value) { @@ -156,6 +157,13 @@ namespace dynamic { Map& put(std::string key, bool value) { return put(key, Value(static_cast(value))); } + Map& put(const std::string& key, const ByteBuffer* bytes) { + return put(key, std::make_unique( + bytes->data(), bytes->size())); + } + Map& put(std::string key, const ubyte* bytes, size_t size) { + return put(key, std::make_unique(bytes, size)); + } Map& put(std::string key, const char* value) { return put(key, Value(value)); } diff --git a/src/util/Buffer.hpp b/src/util/Buffer.hpp index 4787d2ed..68e185c6 100644 --- a/src/util/Buffer.hpp +++ b/src/util/Buffer.hpp @@ -48,5 +48,9 @@ namespace util { Buffer clone() const { return Buffer(ptr.get(), length); } + + void resizeFast(size_t size) { + length = size; + } }; } diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index 97ca4786..4452301b 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -319,8 +319,8 @@ std::string util::mangleid(uint64_t value) { return ss.str(); } -std::vector util::base64_decode(const char* str, size_t size) { - std::vector bytes((size / 4) * 3); +util::Buffer util::base64_decode(const char* str, size_t size) { + util::Buffer bytes((size / 4) * 3); ubyte* dst = bytes.data(); for (size_t i = 0; i < size;) { ubyte a = base64_decode_char(ubyte(str[i++])); @@ -335,12 +335,12 @@ std::vector util::base64_decode(const char* str, size_t size) { size_t outsize = bytes.size(); if (str[size - 1] == '=') outsize--; if (str[size - 2] == '=') outsize--; - bytes.resize(outsize); + bytes.resizeFast(outsize); } return bytes; } -std::vector util::base64_decode(const std::string& str) { +util::Buffer util::base64_decode(const std::string& str) { return base64_decode(str.c_str(), str.size()); } diff --git a/src/util/stringutil.hpp b/src/util/stringutil.hpp index 38e7cf89..21d58e5e 100644 --- a/src/util/stringutil.hpp +++ b/src/util/stringutil.hpp @@ -4,6 +4,7 @@ #include #include "typedefs.hpp" +#include "util/Buffer.hpp" namespace util { /// @brief Function used for string serialization in text formats @@ -56,8 +57,8 @@ namespace util { std::wstring to_wstring(double x, int precision); std::string base64_encode(const ubyte* data, size_t size); - std::vector base64_decode(const char* str, size_t size); - std::vector base64_decode(const std::string& str); + util::Buffer base64_decode(const char* str, size_t size); + util::Buffer base64_decode(const std::string& str); std::string mangleid(uint64_t value); diff --git a/test/coders/json.cpp b/test/coders/json.cpp new file mode 100644 index 00000000..7212a087 --- /dev/null +++ b/test/coders/json.cpp @@ -0,0 +1,41 @@ +#include + +#include "coders/json.hpp" +#include "util/stringutil.hpp" + +#include + +TEST(JSON, EncodeDecode) { + const std::string name = "JSON-encoder"; + const int bytesSize = 20; + const int year = 2019; + const float score = 3.141592; + dynamic::ByteBuffer srcBytes(bytesSize); + for (int i = 0; i < bytesSize; i ++) { + srcBytes[i] = rand(); + } + + std::string text; + { + dynamic::Map map; + map.put("name", name); + map.put("year", year); + map.put("score", score); + map.put("data", &srcBytes); + + text = json::stringify(&map, false, ""); + } + { + auto map = json::parse(text); + EXPECT_EQ(map->get("name"), name); + EXPECT_EQ(map->get("year"), year); + EXPECT_FLOAT_EQ(map->get("score"), score); + auto b64string = map->get("data"); + + auto bytes = util::base64_decode(b64string); + EXPECT_EQ(bytes.size(), bytesSize); + for (int i = 0; i < bytesSize; i++) { + EXPECT_EQ(bytes[i], srcBytes[i]); + } + } +}