• 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 
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