1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "solid_xml.h"
17 #include<iostream>
18 #include<regex>
19 #include "securec.h"
20
21 namespace OHOS {
22 namespace Global {
23 namespace Restool {
24 using namespace std;
25 const uint8_t SolidXml::SOLID_XML_MAGIC[] = "SolidXml";
26 const uint32_t SolidXml::SOLID_XML_MAGIC_LENGTH =
27 (sizeof(SolidXml::SOLID_XML_MAGIC) / sizeof(uint32_t) + 1) * sizeof(uint32_t);
28
SolidXml(const string & xmlPath,map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & keys)29 SolidXml::SolidXml(const string &xmlPath, map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &keys)
30 : xmlPath_(xmlPath), keys_(keys)
31 {
32 }
33
~SolidXml()34 SolidXml::~SolidXml()
35 {
36 }
37
GenerateSolidXml(const string & filePath)38 bool SolidXml::GenerateSolidXml(const string &filePath)
39 {
40 xmlKeepBlanksDefault(0);
41 xmlDocPtr doc = xmlParseFile(xmlPath_.c_str());
42 if (doc == nullptr) {
43 return false;
44 }
45
46 xmlNodePtr rootNode = xmlDocGetRootElement(doc);
47 if (rootNode == nullptr) {
48 xmlFreeDoc(doc);
49 return false;
50 }
51 auto root = make_shared<XmlNode>();
52 nodes_.push_back(root);
53 Compile(rootNode, root);
54 xmlFreeDoc(doc);
55 return SaveToFile(filePath);
56 }
57
FlushNodeKeys(const string & filePath,map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & newKeys)58 bool SolidXml::FlushNodeKeys(const string &filePath, map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &newKeys)
59 {
60 if (!LoadFromFile(xmlPath_)) {
61 cerr << "Error: load " << xmlPath_ << " fail." << endl;
62 return false;
63 }
64
65 bool firstNode = true;
66 for (auto &node : nodes_) {
67 if (!node->FlushIndex(keys_, newKeys)) {
68 cerr << "Error: flush node key fail, '" << xmlPath_ << "'" << endl;
69 return false;
70 }
71 if (firstNode && !FlushXmlnsKey(newKeys)) {
72 return false;
73 }
74 firstNode = false;
75 }
76
77 for (auto &attr : attributes_) {
78 if (!attr->FlushIndex(keys_, newKeys)) {
79 cerr << "Error: flush attibutes key fail, '" << xmlPath_ << "'" << endl;
80 return false;
81 }
82 }
83 return SaveToFile(filePath);
84 }
85
86 // below private
Compile(const xmlNodePtr nodePtr,shared_ptr<XmlNode> & node)87 void SolidXml::Compile(const xmlNodePtr nodePtr, shared_ptr<XmlNode> &node)
88 {
89 if (nodePtr->type == XML_COMMENT_NODE) {
90 if (nodePtr->next) {
91 Compile(nodePtr->next, node);
92 }
93 return;
94 }
95
96 string name(reinterpret_cast<const char *>(nodePtr->name));
97 node->SetName(keys_[XmlKeyNode::KeyType::NODE]->PushKey(name));
98 CompileNameSpace(nodePtr, node);
99 CompileAttr(nodePtr->properties, node);
100
101 if (nodePtr->children) {
102 if (nodePtr->children->type == XML_TEXT_NODE) {
103 string content(reinterpret_cast<const char *>(nodePtr->children->content));
104 node->SetValue(keys_[XmlKeyNode::KeyType::CONTENT]->PushKey(content));
105 } else {
106 auto child = make_shared<XmlNode>();
107 nodes_.push_back(child);
108 node->SetChild(nodes_.size() - 1);
109 Compile(nodePtr->children, child);
110 }
111 }
112
113 if (nodePtr->next) {
114 auto brother = make_shared<XmlNode>();
115 nodes_.push_back(brother);
116 node->SetBrother(nodes_.size() - 1);
117 Compile(nodePtr->next, brother);
118 }
119 }
120
CompileAttr(const xmlAttrPtr attrPtr,shared_ptr<XmlNode> & node)121 void SolidXml::CompileAttr(const xmlAttrPtr attrPtr, shared_ptr<XmlNode> &node)
122 {
123 if (attrPtr == nullptr) {
124 return;
125 }
126
127 xmlChar *xmlValue = xmlNodeListGetString(attrPtr->doc, attrPtr->children, 1);
128 string value(reinterpret_cast<const char *>(xmlValue));
129 PretreatmentAttr(value);
130 xmlFree(xmlValue);
131 string name(reinterpret_cast<const char *>(attrPtr->name));
132 auto attr = make_shared<Node>();
133 attributes_.push_back(attr);
134 attr->SetName(keys_[XmlKeyNode::KeyType::ATTRIBUTE]->PushKey(name));
135 attr->SetValue(keys_[XmlKeyNode::KeyType::CONSTANT]->PushKey(value));
136 if (attrPtr->ns != nullptr && attrPtr->ns->prefix != nullptr) {
137 string nameSpace(reinterpret_cast<const char *>(attrPtr->ns->prefix));
138 attr->SetNameSpace(keys_[XmlKeyNode::KeyType::NODE]->PushKey(nameSpace));
139 }
140 node->AddAttribute(attributes_.size() - 1);
141 CompileAttr(attrPtr->next, node);
142 }
143
CompileNameSpace(const xmlNodePtr nodePtr,shared_ptr<XmlNode> & node)144 void SolidXml::CompileNameSpace(const xmlNodePtr nodePtr, shared_ptr<XmlNode> &node)
145 {
146 if (nodePtr->ns && nodePtr->ns->prefix) {
147 string nameSpace(reinterpret_cast<const char *>(nodePtr->ns->prefix));
148 node->SetNameSpace(keys_[XmlKeyNode::KeyType::NODE]->PushKey(nameSpace));
149 }
150
151 auto nsDef = nodePtr->nsDef;
152 while (nsDef) {
153 string nameSpace;
154 string href;
155 if (nsDef->prefix) {
156 nameSpace = string(reinterpret_cast<const char *>(nsDef->prefix));
157 }
158 if (nsDef->href) {
159 href = string(reinterpret_cast<const char *>(nsDef->href));
160 }
161 int32_t nameSpaceIndex = keys_[XmlKeyNode::KeyType::NODE]->PushKey(nameSpace);
162 int32_t herfIndex = keys_[XmlKeyNode::KeyType::NODE]->PushKey(href);
163 AddNampeSpaceDef(nameSpaceIndex, herfIndex);
164 nsDef = nsDef->next;
165 }
166 }
167
RawData(ofstream & out) const168 void SolidXml::Node::RawData(ofstream &out) const
169 {
170 out.write(reinterpret_cast<const char *>(&nameSpace_), sizeof(int32_t));
171 out.write(reinterpret_cast<const char *>(&name_), sizeof(int32_t));
172 out.write(reinterpret_cast<const char *>(&value_), sizeof(int32_t));
173 }
174
RawData(ofstream & out) const175 void SolidXml::XmlNode::RawData(ofstream &out) const
176 {
177 SolidXml::Node::RawData(out);
178 out.write(reinterpret_cast<const char *>(&child_), sizeof(int32_t));
179 out.write(reinterpret_cast<const char *>(&brother_), sizeof(int32_t));
180 int32_t attrStart = attributes_.size();
181 int32_t attrCount = attributes_.size();
182 if (!attributes_.empty()) {
183 attrStart = attributes_.at(0);
184 }
185 out.write(reinterpret_cast<const char *>(&attrStart), sizeof(int32_t));
186 out.write(reinterpret_cast<const char *>(&attrCount), sizeof(int32_t));
187 }
188
LoadFrom(ifstream & in)189 bool SolidXml::Node::LoadFrom(ifstream &in)
190 {
191 CHECK_IO(in.read(reinterpret_cast<char *>(&nameSpace_), sizeof(int32_t)))
192 CHECK_IO(in.read(reinterpret_cast<char *>(&name_), sizeof(int32_t)));
193 CHECK_IO(in.read(reinterpret_cast<char *>(&value_), sizeof(int32_t)));
194 return true;
195 }
196
LoadFrom(ifstream & in)197 bool SolidXml::XmlNode::LoadFrom(ifstream &in)
198 {
199 if (!SolidXml::Node::LoadFrom(in)) {
200 return false;
201 }
202 CHECK_IO(in.read(reinterpret_cast<char *>(&child_), sizeof(int32_t)));
203 CHECK_IO(in.read(reinterpret_cast<char *>(&brother_), sizeof(int32_t)));
204 int32_t attrStart = 0;
205 int32_t attrCount = 0;
206 CHECK_IO(in.read(reinterpret_cast<char *>(&attrStart), sizeof(int32_t)));
207 CHECK_IO(in.read(reinterpret_cast<char *>(&attrCount), sizeof(int32_t)));
208 for (int32_t i = attrStart; i < attrStart + attrCount; i++) {
209 attributes_.push_back(i);
210 }
211 return true;
212 }
213
FlushIndex(const map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & oldKeys,map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & newKeys)214 bool SolidXml::Node::FlushIndex(const map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &oldKeys,
215 map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &newKeys)
216 {
217 if (!ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::NODE, nameSpace_) ||
218 !ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::ATTRIBUTE, name_) ||
219 !ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::CONSTANT, value_)) {
220 return false;
221 }
222 return true;
223 }
224
FlushIndex(const map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & oldKeys,map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & newKeys)225 bool SolidXml::XmlNode::FlushIndex(const map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &oldKeys,
226 map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &newKeys)
227 {
228 if (!ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::NODE, nameSpace_) ||
229 !ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::NODE, name_) ||
230 !ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::CONTENT, value_)) {
231 return false;
232 }
233 return true;
234 }
235
AddNampeSpaceDef(int32_t nameSpace,int32_t href)236 void SolidXml::AddNampeSpaceDef(int32_t nameSpace, int32_t href)
237 {
238 nameSpaces_.push_back(nameSpace);
239 hrefs_.push_back(href);
240 }
241
SaveToFile(const std::string & filePath) const242 bool SolidXml::SaveToFile(const std::string &filePath) const
243 {
244 ofstream out(filePath, ofstream::out | ofstream::binary);
245 if (!out.is_open()) {
246 cerr << "Error: open fail," << filePath << endl;
247 return false;
248 }
249
250 // write solid xml header
251 uint8_t magic[SOLID_XML_MAGIC_LENGTH] = {0};
252 if (memcpy_s(magic, SOLID_XML_MAGIC_LENGTH, SOLID_XML_MAGIC, sizeof(SOLID_XML_MAGIC)) != EOK) {
253 cerr << "Error: SolidXml::SaveToFile memcpy_s fail." << endl;
254 return false;
255 }
256 uint32_t version = 1;
257 uint32_t numOfNodes = nodes_.size();
258 uint32_t numOfAttributes = attributes_.size();
259 uint32_t numOfNameSpaces = nameSpaces_.size();
260 out.write(reinterpret_cast<const char *>(magic), SOLID_XML_MAGIC_LENGTH);
261 out.write(reinterpret_cast<const char *>(&version), sizeof(uint32_t));
262 out.write(reinterpret_cast<const char *>(&numOfNodes), sizeof(uint32_t));
263 out.write(reinterpret_cast<const char *>(&numOfAttributes), sizeof(uint32_t));
264 out.write(reinterpret_cast<const char *>(&numOfNameSpaces), sizeof(uint32_t));
265
266 // write node
267 for (const auto &node : nodes_) {
268 node->RawData(out);
269 }
270
271 // write attribute
272 for (const auto &attribute : attributes_) {
273 attribute->RawData(out);
274 }
275
276 // write namespace
277 for (const auto &nameSpace : nameSpaces_) {
278 out.write(reinterpret_cast<const char *>(&nameSpace), sizeof(int32_t));
279 }
280
281 // write href
282 for (const auto &href : hrefs_) {
283 out.write(reinterpret_cast<const char *>(&href), sizeof(int32_t));
284 }
285 return true;
286 }
287
PretreatmentAttr(string & value) const288 void SolidXml::PretreatmentAttr(string &value) const
289 {
290 regex ref("^\\$\\+id:");
291 smatch result;
292 if (!regex_search(value, result, ref)) {
293 return;
294 }
295 value.replace(0, result[0].str().length(), "$id:");
296 }
297
LoadFromFile(const string & sxmlPath)298 bool SolidXml::LoadFromFile(const string &sxmlPath)
299 {
300 ifstream in(sxmlPath, ifstream::in | ifstream::binary);
301 if (!in.is_open()) {
302 cerr << "Error: open fail," << sxmlPath << endl;
303 return false;
304 }
305
306 char header[SOLID_XML_MAGIC_LENGTH];
307 CHECK_IO(in.read(header, SOLID_XML_MAGIC_LENGTH));
308
309 uint32_t version = 0;
310 CHECK_IO(in.read(reinterpret_cast<char *>(&version), sizeof(uint32_t)));
311
312 uint32_t numOfNodes = 0;
313 CHECK_IO(in.read(reinterpret_cast<char *>(&numOfNodes), sizeof(uint32_t)));
314
315 uint32_t numOfAttributes = 0;
316 CHECK_IO(in.read(reinterpret_cast<char *>(&numOfAttributes), sizeof(uint32_t)));
317
318 uint32_t numOfNameSpaces = 0;
319 CHECK_IO(in.read(reinterpret_cast<char *>(&numOfNameSpaces), sizeof(uint32_t)));
320
321 for (uint32_t i = 0; i < numOfNodes; i++) {
322 auto xmlNode = make_shared<XmlNode>();
323 if (!xmlNode->LoadFrom(in)) {
324 return false;
325 }
326 nodes_.push_back(xmlNode);
327 }
328
329 for (uint32_t i = 0; i < numOfAttributes; i++) {
330 auto attr = make_shared<Node>();
331 if (!attr->LoadFrom(in)) {
332 return false;
333 }
334 attributes_.push_back(attr);
335 }
336
337 for (uint32_t i = 0; i < numOfNameSpaces; i++) {
338 int32_t nameSpace = -1;
339 CHECK_IO(in.read(reinterpret_cast<char *>(&nameSpace), sizeof(int32_t)));
340 nameSpaces_.push_back(nameSpace);
341 }
342
343 for (uint32_t i = 0; i < numOfNameSpaces; i++) {
344 int32_t href = -1;
345 CHECK_IO(in.read(reinterpret_cast<char *>(&href), sizeof(int32_t)));
346 hrefs_.push_back(href);
347 }
348 return true;
349 }
350
ChangeToNewKey(const map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & oldKeys,map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & newKeys,XmlKeyNode::KeyType keyType,int32_t & keyId)351 bool SolidXml::ChangeToNewKey(const map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &oldKeys,
352 map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &newKeys,
353 XmlKeyNode::KeyType keyType, int32_t &keyId)
354 {
355 if (keyId <= 0) {
356 return true;
357 }
358
359 string value;
360 if (!oldKeys.at(keyType)->GetKeyValue(keyId, value)) {
361 return false;
362 }
363
364 keyId = newKeys[keyType]->PushKey(value);
365 return true;
366 }
367
FlushXmlnsKey(map<XmlKeyNode::KeyType,shared_ptr<XmlKeyNode>> & newKeys)368 bool SolidXml::FlushXmlnsKey(map<XmlKeyNode::KeyType, shared_ptr<XmlKeyNode>> &newKeys)
369 {
370 if (nameSpaces_.size() != hrefs_.size()) {
371 return false;
372 }
373
374 for (uint32_t i = 0; i < nameSpaces_.size(); i++) {
375 if (!ChangeToNewKey(keys_, newKeys, XmlKeyNode::KeyType::NODE, nameSpaces_[i]) ||
376 !ChangeToNewKey(keys_, newKeys, XmlKeyNode::KeyType::NODE, hrefs_[i])) {
377 cerr << "Error: flush namespace key fail, '" << xmlPath_ << "'" << endl;
378 return false;
379 }
380 }
381 return true;
382 }
383 }
384 }
385 }
386