aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/compactbinary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zencore/compactbinary.cpp')
-rw-r--r--src/zencore/compactbinary.cpp160
1 files changed, 142 insertions, 18 deletions
diff --git a/src/zencore/compactbinary.cpp b/src/zencore/compactbinary.cpp
index 416b49f62..5e8ce22ed 100644
--- a/src/zencore/compactbinary.cpp
+++ b/src/zencore/compactbinary.cpp
@@ -1472,6 +1472,40 @@ class CbJsonWriter
public:
explicit CbJsonWriter(StringBuilderBase& InBuilder) : Builder(InBuilder) { NewLineAndIndent << LINE_TERMINATOR_ANSI; }
+ void BeginObject()
+ {
+ Builder << '{';
+ NewLineAndIndent << '\t';
+ NeedsNewLine = true;
+ }
+
+ void EndObject()
+ {
+ NewLineAndIndent.RemoveSuffix(1);
+ if (NeedsComma)
+ {
+ WriteOptionalNewLine();
+ }
+ Builder << '}';
+ }
+
+ void BeginArray()
+ {
+ Builder << '[';
+ NewLineAndIndent << '\t';
+ NeedsNewLine = true;
+ }
+
+ void EndArray()
+ {
+ NewLineAndIndent.RemoveSuffix(1);
+ if (NeedsComma)
+ {
+ WriteOptionalNewLine();
+ }
+ Builder << ']';
+ }
+
void WriteField(CbFieldView Field)
{
using namespace std::literals;
@@ -1493,37 +1527,23 @@ public:
case CbFieldType::Object:
case CbFieldType::UniformObject:
{
- Builder << '{';
- NewLineAndIndent << '\t';
- NeedsNewLine = true;
+ BeginObject();
for (CbFieldView It : Field)
{
WriteField(It);
}
- NewLineAndIndent.RemoveSuffix(1);
- if (NeedsComma)
- {
- WriteOptionalNewLine();
- }
- Builder << '}';
+ EndObject();
}
break;
case CbFieldType::Array:
case CbFieldType::UniformArray:
{
- Builder << '[';
- NewLineAndIndent << '\t';
- NeedsNewLine = true;
+ BeginArray();
for (CbFieldView It : Field)
{
WriteField(It);
}
- NewLineAndIndent.RemoveSuffix(1);
- if (NeedsComma)
- {
- WriteOptionalNewLine();
- }
- Builder << ']';
+ EndArray();
}
break;
case CbFieldType::Binary:
@@ -1744,6 +1764,62 @@ CompactBinaryToJson(const CbArrayView& Array, StringBuilderBase& Builder)
Writer.WriteField(Array.AsFieldView());
}
+void
+CompactBinaryToJson(MemoryView Data, StringBuilderBase& InBuilder)
+{
+ std::vector<CbFieldView> Fields = ReadCompactBinaryStream(Data);
+ CbJsonWriter Writer(InBuilder);
+ if (!Fields.empty())
+ {
+ if (Fields.size() == 1)
+ {
+ Writer.WriteField(Fields[0]);
+ return;
+ }
+ bool UseTopLevelObject = Fields[0].HasName();
+ if (UseTopLevelObject)
+ {
+ Writer.BeginObject();
+ }
+ else
+ {
+ Writer.BeginArray();
+ }
+ for (const CbFieldView& Field : Fields)
+ {
+ Writer.WriteField(Field);
+ }
+ if (UseTopLevelObject)
+ {
+ Writer.EndObject();
+ }
+ else
+ {
+ Writer.EndArray();
+ }
+ }
+}
+
+std::vector<CbFieldView>
+ReadCompactBinaryStream(MemoryView Data)
+{
+ std::vector<CbFieldView> Result;
+ const uint8_t* Buffer = reinterpret_cast<const uint8_t*>(Data.GetData());
+ uint64_t Offset = 0;
+ const uint64_t Size = Data.GetSize();
+ while (Offset < Size)
+ {
+ if (ValidateCompactBinary(MemoryView(Buffer + Offset, Size - Offset), CbValidateMode::Default) != CbValidateError::None)
+ {
+ break;
+ }
+ CbFieldView Field(Buffer + Offset);
+ Offset += Field.GetSize();
+ Result.emplace_back(std::move(Field));
+ }
+ return Result;
+}
+
//////////////////////////////////////////////////////////////////////////
class CbJsonReader
@@ -2136,6 +2212,8 @@ TEST_CASE("uson.null")
TEST_CASE("uson.json")
{
+ using namespace std::literals;
+
SUBCASE("string")
{
CbObjectWriter Writer;
@@ -2208,6 +2286,52 @@ TEST_CASE("uson.json")
CHECK(FloatValue == 0);
CHECK(DoubleValue == 0);
}
+
+ SUBCASE("stream")
+ {
+ const auto MakeObject = [&](std::string_view Name, const std::vector<int>& Fields) -> CbObject {
+ CbWriter Writer;
+ Writer.SetName(Name);
+ Writer.BeginObject();
+ for (const auto& Field : Fields)
+ {
+ Writer.AddInteger(fmt::format("{}", Field), Field);
+ }
+ Writer.EndObject();
+ return Writer.Save().AsObject();
+ };
+
+ std::vector<uint8_t> Buffer;
+
+ auto AppendToBuffer = [&](const void* Data, size_t Count) {
+ const uint8_t* AppendBytes = reinterpret_cast<const uint8_t*>(Data);
+ Buffer.insert(Buffer.end(), AppendBytes, AppendBytes + Count);
+ };
+
+ auto Append = [&](const CbFieldView& Field) {
+ Field.WriteToStream([&](const void* Data, size_t Count) {
+ const uint8_t* AppendBytes = reinterpret_cast<const uint8_t*>(Data);
+ Buffer.insert(Buffer.end(), AppendBytes, AppendBytes + Count);
+ });
+ };
+
+ CbObject DataObjects[] = {MakeObject("Empty object"sv, {}),
+ MakeObject("OneField object"sv, {5}),
+ MakeObject("TwoField object"sv, {-5, 999}),
+ MakeObject("ThreeField object"sv, {1, 2, -129})};
+ for (const CbObject& Object : DataObjects)
+ {
+ Object.AsField().WriteToStream(AppendToBuffer);
+ }
+
+ ExtendableStringBuilder<128> Sb;
+ CompactBinaryToJson(MemoryView(Buffer.data(), Buffer.size()), Sb);
+ std::string JsonText = Sb.ToString().c_str();
+ std::string JsonError;
+ json11::Json Json = json11::Json::parse(JsonText, JsonError);
+ std::string ParsedJsonString = Json.dump();
+ CHECK(!ParsedJsonString.empty());
+ }
}
TEST_CASE("uson.datetime")