• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
startGroup(const std::string & name)29 void JsonSerializer::startGroup(const std::string &name)
30 {
31     mGroupValueStack.push(SortedValueGroup());
32     mGroupNameStack.push(name);
33 }
34 
endGroup()35 void JsonSerializer::endGroup()
36 {
37     ASSERT(!mGroupValueStack.empty());
38     ASSERT(!mGroupNameStack.empty());
39 
40     rapidjson::Value group = makeValueGroup(mGroupValueStack.top());
41     std::string name       = mGroupNameStack.top();
42 
43     mGroupValueStack.pop();
44     mGroupNameStack.pop();
45 
46     addValue(name, std::move(group));
47 }
48 
addBlob(const std::string & name,const uint8_t * blob,size_t length)49 void JsonSerializer::addBlob(const std::string &name, const uint8_t *blob, size_t length)
50 {
51     addBlobWithMax(name, blob, length, 16);
52 }
53 
addBlobWithMax(const std::string & name,const uint8_t * blob,size_t length,size_t maxSerializedLength)54 void JsonSerializer::addBlobWithMax(const std::string &name,
55                                     const uint8_t *blob,
56                                     size_t length,
57                                     size_t maxSerializedLength)
58 {
59     unsigned char hash[angle::base::kSHA1Length];
60     angle::base::SHA1HashBytes(blob, length, hash);
61     std::ostringstream os;
62 
63     // Since we don't want to de-serialize the data we just store a checksum of the blob
64     os << "SHA1:";
65     static constexpr char kASCII[] = "0123456789ABCDEF";
66     for (size_t i = 0; i < angle::base::kSHA1Length; ++i)
67     {
68         os << kASCII[hash[i] & 0xf] << kASCII[hash[i] >> 4];
69     }
70 
71     std::ostringstream hashName;
72     hashName << name << "-hash";
73     addString(hashName.str(), os.str());
74 
75     std::vector<uint8_t> data(
76         (length < maxSerializedLength) ? length : static_cast<size_t>(maxSerializedLength));
77     std::copy(blob, blob + data.size(), data.begin());
78 
79     std::ostringstream rawName;
80     rawName << name << "-raw[0-" << data.size() - 1 << ']';
81     addVector(rawName.str(), data);
82 }
83 
addCString(const std::string & name,const char * value)84 void JsonSerializer::addCString(const std::string &name, const char *value)
85 {
86     rapidjson::Value tag(name.c_str(), mAllocator);
87     rapidjson::Value val(value, mAllocator);
88     addValue(name, std::move(val));
89 }
90 
addString(const std::string & name,const std::string & value)91 void JsonSerializer::addString(const std::string &name, const std::string &value)
92 {
93     addCString(name, value.c_str());
94 }
95 
addVectorOfStrings(const std::string & name,const std::vector<std::string> & value)96 void JsonSerializer::addVectorOfStrings(const std::string &name,
97                                         const std::vector<std::string> &value)
98 {
99     rapidjson::Value arrayValue(rapidjson::kArrayType);
100     arrayValue.SetArray();
101 
102     for (const std::string &v : value)
103     {
104         rapidjson::Value str(v.c_str(), mAllocator);
105         arrayValue.PushBack(str, mAllocator);
106     }
107 
108     addValue(name, std::move(arrayValue));
109 }
110 
addBool(const std::string & name,bool value)111 void JsonSerializer::addBool(const std::string &name, bool value)
112 {
113     rapidjson::Value boolValue(value);
114     addValue(name, std::move(boolValue));
115 }
116 
addHexValue(const std::string & name,int value)117 void JsonSerializer::addHexValue(const std::string &name, int value)
118 {
119     // JSON doesn't support hex values, so write it as a string
120     std::stringstream hexStream;
121     hexStream << "0x" << std::uppercase << std::setfill('0') << std::setw(4) << std::hex << value;
122     addCString(name, hexStream.str().c_str());
123 }
124 
data()125 const char *JsonSerializer::data()
126 {
127     ensureEndDocument();
128     return mResult.c_str();
129 }
130 
getData()131 std::vector<uint8_t> JsonSerializer::getData()
132 {
133     ensureEndDocument();
134     return std::vector<uint8_t>(mResult.begin(), mResult.end());
135 }
136 
ensureEndDocument()137 void JsonSerializer::ensureEndDocument()
138 {
139     if (!mResult.empty())
140     {
141         return;
142     }
143 
144     std::stringstream os;
145     js::OStreamWrapper osw(os);
146     js::PrettyWriter<js::OStreamWrapper> prettyOs(osw);
147     mDoc.Accept(prettyOs);
148     mResult = os.str();
149 }
150 
length()151 size_t JsonSerializer::length()
152 {
153     ensureEndDocument();
154     return mResult.length();
155 }
156 
makeValueGroup(SortedValueGroup & group)157 rapidjson::Value JsonSerializer::makeValueGroup(SortedValueGroup &group)
158 {
159     rapidjson::Value valueGroup(js::kObjectType);
160     for (auto &it : group)
161     {
162         rapidjson::Value tag(it.first.c_str(), mAllocator);
163         valueGroup.AddMember(tag, it.second, mAllocator);
164     }
165     return valueGroup;
166 }
167 
addValue(const std::string & name,rapidjson::Value && value)168 void JsonSerializer::addValue(const std::string &name, rapidjson::Value &&value)
169 {
170     if (!mGroupValueStack.empty())
171     {
172         mGroupValueStack.top().insert(std::make_pair(name, std::move(value)));
173     }
174     else
175     {
176         rapidjson::Value nameValue(name, mAllocator);
177         mDoc.AddMember(nameValue, std::move(value), mAllocator);
178     }
179 }
180 }  // namespace angle
181