xref: /aosp_15_r20/external/angle/src/common/serializer/JsonSerializer.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // JsonSerializer.cpp: Implementation of a JSON based serializer
7*8975f5c5SAndroid Build Coastguard Worker // Note that for binary blob data only a checksum is stored so that
8*8975f5c5SAndroid Build Coastguard Worker // a lossless  deserialization is not supported.
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "JsonSerializer.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
13*8975f5c5SAndroid Build Coastguard Worker 
14*8975f5c5SAndroid Build Coastguard Worker #include <anglebase/sha1.h>
15*8975f5c5SAndroid Build Coastguard Worker #include <rapidjson/document.h>
16*8975f5c5SAndroid Build Coastguard Worker #include <rapidjson/filewritestream.h>
17*8975f5c5SAndroid Build Coastguard Worker #include <rapidjson/ostreamwrapper.h>
18*8975f5c5SAndroid Build Coastguard Worker #include <rapidjson/prettywriter.h>
19*8975f5c5SAndroid Build Coastguard Worker 
20*8975f5c5SAndroid Build Coastguard Worker namespace angle
21*8975f5c5SAndroid Build Coastguard Worker {
22*8975f5c5SAndroid Build Coastguard Worker 
23*8975f5c5SAndroid Build Coastguard Worker namespace js = rapidjson;
24*8975f5c5SAndroid Build Coastguard Worker 
JsonSerializer()25*8975f5c5SAndroid Build Coastguard Worker JsonSerializer::JsonSerializer() : mDoc(js::kObjectType), mAllocator(mDoc.GetAllocator()) {}
26*8975f5c5SAndroid Build Coastguard Worker 
~JsonSerializer()27*8975f5c5SAndroid Build Coastguard Worker JsonSerializer::~JsonSerializer() {}
28*8975f5c5SAndroid Build Coastguard Worker 
startGroup(const std::string & name)29*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::startGroup(const std::string &name)
30*8975f5c5SAndroid Build Coastguard Worker {
31*8975f5c5SAndroid Build Coastguard Worker     mGroupValueStack.push(SortedValueGroup());
32*8975f5c5SAndroid Build Coastguard Worker     mGroupNameStack.push(name);
33*8975f5c5SAndroid Build Coastguard Worker }
34*8975f5c5SAndroid Build Coastguard Worker 
endGroup()35*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::endGroup()
36*8975f5c5SAndroid Build Coastguard Worker {
37*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mGroupValueStack.empty());
38*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mGroupNameStack.empty());
39*8975f5c5SAndroid Build Coastguard Worker 
40*8975f5c5SAndroid Build Coastguard Worker     rapidjson::Value group = makeValueGroup(mGroupValueStack.top());
41*8975f5c5SAndroid Build Coastguard Worker     std::string name       = mGroupNameStack.top();
42*8975f5c5SAndroid Build Coastguard Worker 
43*8975f5c5SAndroid Build Coastguard Worker     mGroupValueStack.pop();
44*8975f5c5SAndroid Build Coastguard Worker     mGroupNameStack.pop();
45*8975f5c5SAndroid Build Coastguard Worker 
46*8975f5c5SAndroid Build Coastguard Worker     addValue(name, std::move(group));
47*8975f5c5SAndroid Build Coastguard Worker }
48*8975f5c5SAndroid Build Coastguard Worker 
addBlob(const std::string & name,const uint8_t * blob,size_t length)49*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::addBlob(const std::string &name, const uint8_t *blob, size_t length)
50*8975f5c5SAndroid Build Coastguard Worker {
51*8975f5c5SAndroid Build Coastguard Worker     addBlobWithMax(name, blob, length, 16);
52*8975f5c5SAndroid Build Coastguard Worker }
53*8975f5c5SAndroid Build Coastguard Worker 
addBlobWithMax(const std::string & name,const uint8_t * blob,size_t length,size_t maxSerializedLength)54*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::addBlobWithMax(const std::string &name,
55*8975f5c5SAndroid Build Coastguard Worker                                     const uint8_t *blob,
56*8975f5c5SAndroid Build Coastguard Worker                                     size_t length,
57*8975f5c5SAndroid Build Coastguard Worker                                     size_t maxSerializedLength)
58*8975f5c5SAndroid Build Coastguard Worker {
59*8975f5c5SAndroid Build Coastguard Worker     unsigned char hash[angle::base::kSHA1Length];
60*8975f5c5SAndroid Build Coastguard Worker     angle::base::SHA1HashBytes(blob, length, hash);
61*8975f5c5SAndroid Build Coastguard Worker     std::ostringstream os;
62*8975f5c5SAndroid Build Coastguard Worker 
63*8975f5c5SAndroid Build Coastguard Worker     // Since we don't want to de-serialize the data we just store a checksum of the blob
64*8975f5c5SAndroid Build Coastguard Worker     os << "SHA1:";
65*8975f5c5SAndroid Build Coastguard Worker     static constexpr char kASCII[] = "0123456789ABCDEF";
66*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = 0; i < angle::base::kSHA1Length; ++i)
67*8975f5c5SAndroid Build Coastguard Worker     {
68*8975f5c5SAndroid Build Coastguard Worker         os << kASCII[hash[i] & 0xf] << kASCII[hash[i] >> 4];
69*8975f5c5SAndroid Build Coastguard Worker     }
70*8975f5c5SAndroid Build Coastguard Worker 
71*8975f5c5SAndroid Build Coastguard Worker     std::ostringstream hashName;
72*8975f5c5SAndroid Build Coastguard Worker     hashName << name << "-hash";
73*8975f5c5SAndroid Build Coastguard Worker     addString(hashName.str(), os.str());
74*8975f5c5SAndroid Build Coastguard Worker 
75*8975f5c5SAndroid Build Coastguard Worker     std::vector<uint8_t> data(
76*8975f5c5SAndroid Build Coastguard Worker         (length < maxSerializedLength) ? length : static_cast<size_t>(maxSerializedLength));
77*8975f5c5SAndroid Build Coastguard Worker     std::copy(blob, blob + data.size(), data.begin());
78*8975f5c5SAndroid Build Coastguard Worker 
79*8975f5c5SAndroid Build Coastguard Worker     std::ostringstream rawName;
80*8975f5c5SAndroid Build Coastguard Worker     rawName << name << "-raw[0-" << data.size() - 1 << ']';
81*8975f5c5SAndroid Build Coastguard Worker     addVector(rawName.str(), data);
82*8975f5c5SAndroid Build Coastguard Worker }
83*8975f5c5SAndroid Build Coastguard Worker 
addCString(const std::string & name,const char * value)84*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::addCString(const std::string &name, const char *value)
85*8975f5c5SAndroid Build Coastguard Worker {
86*8975f5c5SAndroid Build Coastguard Worker     rapidjson::Value tag(name.c_str(), mAllocator);
87*8975f5c5SAndroid Build Coastguard Worker     rapidjson::Value val(value, mAllocator);
88*8975f5c5SAndroid Build Coastguard Worker     addValue(name, std::move(val));
89*8975f5c5SAndroid Build Coastguard Worker }
90*8975f5c5SAndroid Build Coastguard Worker 
addString(const std::string & name,const std::string & value)91*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::addString(const std::string &name, const std::string &value)
92*8975f5c5SAndroid Build Coastguard Worker {
93*8975f5c5SAndroid Build Coastguard Worker     addCString(name, value.c_str());
94*8975f5c5SAndroid Build Coastguard Worker }
95*8975f5c5SAndroid Build Coastguard Worker 
addVectorOfStrings(const std::string & name,const std::vector<std::string> & value)96*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::addVectorOfStrings(const std::string &name,
97*8975f5c5SAndroid Build Coastguard Worker                                         const std::vector<std::string> &value)
98*8975f5c5SAndroid Build Coastguard Worker {
99*8975f5c5SAndroid Build Coastguard Worker     rapidjson::Value arrayValue(rapidjson::kArrayType);
100*8975f5c5SAndroid Build Coastguard Worker     arrayValue.SetArray();
101*8975f5c5SAndroid Build Coastguard Worker 
102*8975f5c5SAndroid Build Coastguard Worker     for (const std::string &v : value)
103*8975f5c5SAndroid Build Coastguard Worker     {
104*8975f5c5SAndroid Build Coastguard Worker         rapidjson::Value str(v.c_str(), mAllocator);
105*8975f5c5SAndroid Build Coastguard Worker         arrayValue.PushBack(str, mAllocator);
106*8975f5c5SAndroid Build Coastguard Worker     }
107*8975f5c5SAndroid Build Coastguard Worker 
108*8975f5c5SAndroid Build Coastguard Worker     addValue(name, std::move(arrayValue));
109*8975f5c5SAndroid Build Coastguard Worker }
110*8975f5c5SAndroid Build Coastguard Worker 
addBool(const std::string & name,bool value)111*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::addBool(const std::string &name, bool value)
112*8975f5c5SAndroid Build Coastguard Worker {
113*8975f5c5SAndroid Build Coastguard Worker     rapidjson::Value boolValue(value);
114*8975f5c5SAndroid Build Coastguard Worker     addValue(name, std::move(boolValue));
115*8975f5c5SAndroid Build Coastguard Worker }
116*8975f5c5SAndroid Build Coastguard Worker 
addHexValue(const std::string & name,int value)117*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::addHexValue(const std::string &name, int value)
118*8975f5c5SAndroid Build Coastguard Worker {
119*8975f5c5SAndroid Build Coastguard Worker     // JSON doesn't support hex values, so write it as a string
120*8975f5c5SAndroid Build Coastguard Worker     std::stringstream hexStream;
121*8975f5c5SAndroid Build Coastguard Worker     hexStream << "0x" << std::uppercase << std::setfill('0') << std::setw(4) << std::hex << value;
122*8975f5c5SAndroid Build Coastguard Worker     addCString(name, hexStream.str().c_str());
123*8975f5c5SAndroid Build Coastguard Worker }
124*8975f5c5SAndroid Build Coastguard Worker 
data()125*8975f5c5SAndroid Build Coastguard Worker const char *JsonSerializer::data()
126*8975f5c5SAndroid Build Coastguard Worker {
127*8975f5c5SAndroid Build Coastguard Worker     ensureEndDocument();
128*8975f5c5SAndroid Build Coastguard Worker     return mResult.c_str();
129*8975f5c5SAndroid Build Coastguard Worker }
130*8975f5c5SAndroid Build Coastguard Worker 
getData()131*8975f5c5SAndroid Build Coastguard Worker std::vector<uint8_t> JsonSerializer::getData()
132*8975f5c5SAndroid Build Coastguard Worker {
133*8975f5c5SAndroid Build Coastguard Worker     ensureEndDocument();
134*8975f5c5SAndroid Build Coastguard Worker     return std::vector<uint8_t>(mResult.begin(), mResult.end());
135*8975f5c5SAndroid Build Coastguard Worker }
136*8975f5c5SAndroid Build Coastguard Worker 
ensureEndDocument()137*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::ensureEndDocument()
138*8975f5c5SAndroid Build Coastguard Worker {
139*8975f5c5SAndroid Build Coastguard Worker     if (!mResult.empty())
140*8975f5c5SAndroid Build Coastguard Worker     {
141*8975f5c5SAndroid Build Coastguard Worker         return;
142*8975f5c5SAndroid Build Coastguard Worker     }
143*8975f5c5SAndroid Build Coastguard Worker 
144*8975f5c5SAndroid Build Coastguard Worker     std::stringstream os;
145*8975f5c5SAndroid Build Coastguard Worker     js::OStreamWrapper osw(os);
146*8975f5c5SAndroid Build Coastguard Worker     js::PrettyWriter<js::OStreamWrapper> prettyOs(osw);
147*8975f5c5SAndroid Build Coastguard Worker     mDoc.Accept(prettyOs);
148*8975f5c5SAndroid Build Coastguard Worker     mResult = os.str();
149*8975f5c5SAndroid Build Coastguard Worker }
150*8975f5c5SAndroid Build Coastguard Worker 
length()151*8975f5c5SAndroid Build Coastguard Worker size_t JsonSerializer::length()
152*8975f5c5SAndroid Build Coastguard Worker {
153*8975f5c5SAndroid Build Coastguard Worker     ensureEndDocument();
154*8975f5c5SAndroid Build Coastguard Worker     return mResult.length();
155*8975f5c5SAndroid Build Coastguard Worker }
156*8975f5c5SAndroid Build Coastguard Worker 
makeValueGroup(SortedValueGroup & group)157*8975f5c5SAndroid Build Coastguard Worker rapidjson::Value JsonSerializer::makeValueGroup(SortedValueGroup &group)
158*8975f5c5SAndroid Build Coastguard Worker {
159*8975f5c5SAndroid Build Coastguard Worker     rapidjson::Value valueGroup(js::kObjectType);
160*8975f5c5SAndroid Build Coastguard Worker     for (auto &it : group)
161*8975f5c5SAndroid Build Coastguard Worker     {
162*8975f5c5SAndroid Build Coastguard Worker         rapidjson::Value tag(it.first.c_str(), mAllocator);
163*8975f5c5SAndroid Build Coastguard Worker         valueGroup.AddMember(tag, it.second, mAllocator);
164*8975f5c5SAndroid Build Coastguard Worker     }
165*8975f5c5SAndroid Build Coastguard Worker     return valueGroup;
166*8975f5c5SAndroid Build Coastguard Worker }
167*8975f5c5SAndroid Build Coastguard Worker 
addValue(const std::string & name,rapidjson::Value && value)168*8975f5c5SAndroid Build Coastguard Worker void JsonSerializer::addValue(const std::string &name, rapidjson::Value &&value)
169*8975f5c5SAndroid Build Coastguard Worker {
170*8975f5c5SAndroid Build Coastguard Worker     if (!mGroupValueStack.empty())
171*8975f5c5SAndroid Build Coastguard Worker     {
172*8975f5c5SAndroid Build Coastguard Worker         mGroupValueStack.top().insert(std::make_pair(name, std::move(value)));
173*8975f5c5SAndroid Build Coastguard Worker     }
174*8975f5c5SAndroid Build Coastguard Worker     else
175*8975f5c5SAndroid Build Coastguard Worker     {
176*8975f5c5SAndroid Build Coastguard Worker         rapidjson::Value nameValue(name, mAllocator);
177*8975f5c5SAndroid Build Coastguard Worker         mDoc.AddMember(nameValue, std::move(value), mAllocator);
178*8975f5c5SAndroid Build Coastguard Worker     }
179*8975f5c5SAndroid Build Coastguard Worker }
180*8975f5c5SAndroid Build Coastguard Worker }  // namespace angle
181