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