• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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