1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // JsonSerializer.cpp: Implementation of a JSON based serializer
7 // Note that for binary blob data only a checksum is stored so that
8 // a lossless deserialization is not supported.
9
10 #include "JsonSerializer.h"
11
12 #include "common/debug.h"
13
14 #include <anglebase/sha1.h>
15 #include <rapidjson/document.h>
16 #include <rapidjson/filewritestream.h>
17 #include <rapidjson/ostreamwrapper.h>
18 #include <rapidjson/prettywriter.h>
19
20 namespace angle
21 {
22
23 namespace js = rapidjson;
24
JsonSerializer()25 JsonSerializer::JsonSerializer() : mDoc(js::kObjectType), mAllocator(mDoc.GetAllocator()) {}
26
~JsonSerializer()27 JsonSerializer::~JsonSerializer() {}
28
startDocument(const std::string & name)29 void JsonSerializer::startDocument(const std::string &name)
30 {
31 startGroup(name);
32 }
33
startGroup(const std::string & name)34 void JsonSerializer::startGroup(const std::string &name)
35 {
36 mGroupValueStack.push(SortedValueGroup());
37 mGroupNameStack.push(name);
38 }
39
endGroup()40 void JsonSerializer::endGroup()
41 {
42 SortedValueGroup group = std::move(mGroupValueStack.top());
43 std::string name = std::move(mGroupNameStack.top());
44 mGroupValueStack.pop();
45 mGroupNameStack.pop();
46
47 mGroupValueStack.top().insert(std::make_pair(name, makeValueGroup(group)));
48 }
49
addBlob(const std::string & name,const uint8_t * blob,size_t length)50 void JsonSerializer::addBlob(const std::string &name, const uint8_t *blob, size_t length)
51 {
52 unsigned char hash[angle::base::kSHA1Length];
53 angle::base::SHA1HashBytes(blob, length, hash);
54 std::ostringstream os;
55
56 // Since we don't want to de-serialize the data we just store a checksume
57 // of the blob
58 os << "SHA1:";
59 static constexpr char kASCII[] = "0123456789ABCDEF";
60 for (size_t i = 0; i < angle::base::kSHA1Length; ++i)
61 {
62 os << kASCII[hash[i] & 0xf] << kASCII[hash[i] >> 4];
63 }
64
65 std::ostringstream hash_name;
66 hash_name << name << "-hash";
67 addString(hash_name.str(), os.str());
68
69 std::vector<uint8_t> data(length < 16 ? length : (size_t)16);
70 std::copy(blob, blob + data.size(), data.begin());
71
72 std::ostringstream raw_name;
73 raw_name << name << "-raw[0-" << data.size() - 1 << ']';
74 addVector(raw_name.str(), data);
75 }
76
addCString(const std::string & name,const char * value)77 void JsonSerializer::addCString(const std::string &name, const char *value)
78 {
79 rapidjson::Value tag(name.c_str(), mAllocator);
80 rapidjson::Value val(value, mAllocator);
81 mGroupValueStack.top().insert(std::make_pair(name, std::move(val)));
82 }
83
addString(const std::string & name,const std::string & value)84 void JsonSerializer::addString(const std::string &name, const std::string &value)
85 {
86 addCString(name, value.c_str());
87 }
88
addVectorOfStrings(const std::string & name,const std::vector<std::string> & value)89 void JsonSerializer::addVectorOfStrings(const std::string &name,
90 const std::vector<std::string> &value)
91 {
92 rapidjson::Value array(rapidjson::kArrayType);
93 array.SetArray();
94
95 for (const std::string &v : value)
96 {
97 rapidjson::Value str(v.c_str(), mAllocator);
98 array.PushBack(str, mAllocator);
99 }
100
101 mGroupValueStack.top().insert(std::make_pair(name, std::move(array)));
102 }
103
data() const104 const char *JsonSerializer::data() const
105 {
106 return mResult.c_str();
107 }
108
getData() const109 std::vector<uint8_t> JsonSerializer::getData() const
110 {
111 return std::vector<uint8_t>(mResult.begin(), mResult.end());
112 }
113
endDocument()114 void JsonSerializer::endDocument()
115 {
116 // finalize last group
117 ASSERT(!mGroupValueStack.empty());
118 ASSERT(!mGroupNameStack.empty());
119
120 rapidjson::Value name_value(mGroupNameStack.top().c_str(), mAllocator);
121 mDoc.AddMember(name_value, makeValueGroup(mGroupValueStack.top()), mAllocator);
122
123 mGroupValueStack.pop();
124 mGroupNameStack.pop();
125 ASSERT(mGroupValueStack.empty());
126 ASSERT(mGroupNameStack.empty());
127
128 std::stringstream os;
129 js::OStreamWrapper osw(os);
130 js::PrettyWriter<js::OStreamWrapper> pretty_os(osw);
131 mDoc.Accept(pretty_os);
132 mResult = os.str();
133 }
134
length() const135 size_t JsonSerializer::length() const
136 {
137 return mResult.length();
138 }
139
makeValueGroup(SortedValueGroup & group)140 rapidjson::Value JsonSerializer::makeValueGroup(SortedValueGroup &group)
141 {
142 rapidjson::Value valueGroup(js::kObjectType);
143 for (auto &it : group)
144 {
145 rapidjson::Value tag(it.first.c_str(), mAllocator);
146 valueGroup.AddMember(tag, it.second, mAllocator);
147 }
148 return valueGroup;
149 }
150
151 } // namespace angle
152