• 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 "preferences_xml_utils.h"
17 
18 #include <sys/stat.h>
19 
20 #include <cerrno>
21 #include <cstring>
22 
23 #include "libxml/parser.h"
24 #include "logger.h"
25 
26 #include "adaptor.h"
27 
28 namespace OHOS {
29 namespace NativePreferences {
30 static bool ParseNodeElement(const xmlNode *node, Element &element);
31 static bool ParsePrimitiveNodeElement(const xmlNode *node, Element &element);
32 static bool ParseStringNodeElement(const xmlNode *node, Element &element);
33 static bool ParseArrayNodeElement(const xmlNode *node, Element &element);
34 static xmlNode *CreateElementNode(Element &element);
35 static xmlNode *CreatePrimitiveNode(Element &element);
36 static xmlNode *CreateStringNode(Element &element);
37 static xmlNode *CreateArrayNode(Element &element);
38 /* static */
ReadSettingXml(const std::string & fileName,std::vector<Element> & settings)39 bool PreferencesXmlUtils::ReadSettingXml(const std::string &fileName, std::vector<Element> &settings)
40 {
41     LOG_DEBUG("Read setting xml %{private}s start.", fileName.c_str());
42     if (fileName.size() == 0) {
43         LOG_ERROR("The length of the file name is 0.");
44         return false;
45     }
46     char path[PATH_MAX + 1] = { 0x00 };
47     if (strlen(fileName.c_str()) > PATH_MAX || REALPATH(fileName.c_str(), path, PATH_MAX) == nullptr) {
48         LOG_ERROR("The file name is incorrect.");
49         return false;
50     }
51     const char *pathString = path;
52     xmlDoc *doc = xmlReadFile(pathString, "UTF-8", XML_PARSE_NOBLANKS);
53     if (doc == nullptr) {
54         LOG_ERROR("The file name is incorrect.");
55         return false;
56     }
57 
58     xmlNode *root = xmlDocGetRootElement(doc);
59     if (!root || xmlStrcmp(root->name, reinterpret_cast<const xmlChar *>("preferences"))) {
60         xmlFreeDoc(doc);
61         LOG_ERROR("Failed to obtain the XML root element.");
62         return false;
63     }
64 
65     bool success = true;
66     const xmlNode *cur = nullptr;
67     for (cur = root->children; cur != nullptr; cur = cur->next) {
68         Element element;
69 
70         if (ParseNodeElement(cur, element)) {
71             settings.push_back(element);
72         } else {
73             success = false;
74             LOG_ERROR("The error occurred during getting xml child elements.");
75             break;
76         }
77     }
78 
79     /* free the document */
80     xmlFreeDoc(doc);
81     LOG_DEBUG("Read setting xml %{private}s end.", fileName.c_str());
82     return success;
83 }
84 
85 /* static */
ParseNodeElement(const xmlNode * node,Element & element)86 bool ParseNodeElement(const xmlNode *node, Element &element)
87 {
88     if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("int"))
89         || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("long"))
90         || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("bool"))
91         || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("float"))
92         || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("double"))) {
93         return ParsePrimitiveNodeElement(node, element);
94     }
95 
96     if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("string"))) {
97         return ParseStringNodeElement(node, element);
98     }
99 
100     if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("boolArray"))
101         || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("stringArray"))
102         || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("doubleArray"))
103         || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("set"))) {
104         return ParseArrayNodeElement(node, element);
105     }
106 
107     LOG_ERROR("An unsupported element type was encountered in parsing = %{public}s.", node->name);
108     return false;
109 }
110 
111 /* static */
ParsePrimitiveNodeElement(const xmlNode * node,Element & element)112 bool ParsePrimitiveNodeElement(const xmlNode *node, Element &element)
113 {
114     if (node == nullptr) {
115         return false;
116     }
117 
118     xmlChar *key = xmlGetProp(node, reinterpret_cast<const xmlChar *>("key"));
119     xmlChar *value = xmlGetProp(node, reinterpret_cast<const xmlChar *>("value"));
120 
121     bool success = false;
122     if (value != nullptr) {
123         element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
124         if (key != nullptr) {
125             element.key_ = std::string(reinterpret_cast<char *>(key));
126         }
127         element.value_ = std::string(reinterpret_cast<char *>(value));
128         success = true;
129     } else {
130         LOG_ERROR("Failed to obtain a valid key or value when parsing %{public}s.", node->name);
131     }
132 
133     if (key != nullptr) {
134         xmlFree(key);
135     }
136     if (value != nullptr) {
137         xmlFree(value);
138     }
139     return success;
140 }
141 
142 /* static */
ParseStringNodeElement(const xmlNode * node,Element & element)143 bool ParseStringNodeElement(const xmlNode *node, Element &element)
144 {
145     if (node == nullptr) {
146         return false;
147     }
148 
149     xmlChar *key = xmlGetProp(node, (const xmlChar *)"key");
150     xmlChar *text = xmlNodeGetContent(node);
151 
152     bool success = false;
153     if (text != nullptr) {
154         element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
155         if (key != nullptr) {
156             element.key_ = std::string(reinterpret_cast<char *>(key));
157         }
158         element.value_ = std::string(reinterpret_cast<char *>(text));
159         success = true;
160     } else {
161         LOG_ERROR("Failed to obtain a valid key or value when parsing a String element.");
162     }
163 
164     if (key != nullptr) {
165         xmlFree(key);
166     }
167     if (text != nullptr) {
168         xmlFree(text);
169     }
170     return success;
171 }
172 
173 /* static */
ParseArrayNodeElement(const xmlNode * node,Element & element)174 bool ParseArrayNodeElement(const xmlNode *node, Element &element)
175 {
176     if (node == nullptr) {
177         return false;
178     }
179 
180     xmlChar *key = xmlGetProp(node, (const xmlChar *)"key");
181     const xmlNode *children = node->children;
182 
183     bool success = false;
184     if (key != nullptr) {
185         element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
186         element.key_ = std::string(reinterpret_cast<char *>(key));
187 
188         const xmlNode *cur = nullptr;
189         bool finishTravelChild = true;
190         for (cur = children; cur != nullptr; cur = cur->next) {
191             Element child;
192             if (ParseNodeElement(cur, child)) {
193                 element.children_.push_back(child);
194             } else {
195                 finishTravelChild = false;
196                 LOG_ERROR("Failed to parse the Array element and could not be completed successfully.");
197                 break;
198             }
199         }
200         success = finishTravelChild;
201     } else {
202         LOG_ERROR("Failed to obtain a valid key or value when parsing a Array element.");
203     }
204 
205     if (key != nullptr) {
206         xmlFree(key);
207     }
208     return success;
209 }
210 
211 /* static */
WriteSettingXml(const std::string & fileName,std::vector<Element> & settings)212 bool PreferencesXmlUtils::WriteSettingXml(const std::string &fileName, std::vector<Element> &settings)
213 {
214     LOG_DEBUG("Write setting xml %{private}s start.", fileName.c_str());
215     if (fileName.size() == 0) {
216         LOG_ERROR("The length of the file name is 0.");
217         return false;
218     }
219 
220     // define doc and root Node
221     xmlDoc *doc = xmlNewDoc(BAD_CAST "1.0");
222     if (doc == nullptr) {
223         LOG_ERROR("Failed to initialize the xmlDoc.");
224         return false;
225     }
226     xmlNode *root_node = xmlNewNode(NULL, BAD_CAST "preferences");
227     if (root_node == nullptr) {
228         LOG_ERROR("The xmlDoc failed to initialize the root node.");
229         xmlFreeDoc(doc);
230         return false;
231     }
232     xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "1.0");
233 
234     // set root node
235     xmlDocSetRootElement(doc, root_node);
236 
237     // set children node
238     for (Element element : settings) {
239         xmlNode *node = CreateElementNode(element);
240         if (node == nullptr) {
241             LOG_ERROR("The xmlDoc failed to initialize the element node.");
242             xmlFreeDoc(doc);
243             return false;
244         }
245         if (root_node == nullptr || xmlAddChild(root_node, node) == nullptr) {
246             /* free node in case of error */
247             LOG_ERROR("The xmlDoc failed to add the child node.");
248             xmlFreeNode(node);
249             xmlFreeDoc(doc);
250             return false;
251         }
252     }
253 
254     /* 1: formatting spaces are added. */
255     int result = xmlSaveFormatFileEnc(fileName.c_str(), doc, "UTF-8", 1);
256 
257     xmlFreeDoc(doc);
258 
259     if (result > 0) {
260         LimitXmlPermission(fileName);
261     }
262 
263     LOG_DEBUG("Write setting xml %{private}s end.", fileName.c_str());
264     return (result > 0) ? true : false;
265 }
266 
267 /* static */
CreateElementNode(Element & element)268 xmlNode *CreateElementNode(Element &element)
269 {
270     if ((element.tag_.compare("int") == 0) || (element.tag_.compare("long") == 0)
271         || (element.tag_.compare("float") == 0) || (element.tag_.compare("bool") == 0)
272         || (element.tag_.compare("double") == 0)) {
273         return CreatePrimitiveNode(element);
274     }
275 
276     if (element.tag_.compare("string") == 0) {
277         return CreateStringNode(element);
278     }
279 
280     if ((element.tag_.compare("doubleArray") == 0) || (element.tag_.compare("stringArray") == 0)
281         || (element.tag_.compare("boolArray") == 0)) {
282         return CreateArrayNode(element);
283     }
284 
285     LOG_ERROR("An unsupported element type was encountered in parsing = %{public}s.", element.tag_.c_str());
286     return nullptr;
287 }
288 
289 /* static */
CreatePrimitiveNode(Element & element)290 xmlNode *CreatePrimitiveNode(Element &element)
291 {
292     xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str());
293     if (node == nullptr) {
294         LOG_ERROR("The xmlDoc failed to initialize the primitive element node.");
295         return nullptr;
296     }
297     if (!element.key_.empty()) {
298         const char *key = element.key_.c_str();
299         xmlNewProp(node, BAD_CAST "key", BAD_CAST key);
300     }
301 
302     const char *value = element.value_.c_str();
303     xmlNewProp(node, BAD_CAST "value", BAD_CAST value);
304     return node;
305 }
306 
CreateStringNode(Element & element)307 xmlNode *CreateStringNode(Element &element)
308 {
309     xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str());
310     if (node == nullptr) {
311         LOG_ERROR("The xmlDoc failed to initialize the string element node.");
312         return nullptr;
313     }
314 
315     if (!element.key_.empty()) {
316         const char *key = element.key_.c_str();
317         xmlNewProp(node, BAD_CAST "key", BAD_CAST key);
318     }
319 
320     const char *value = element.value_.c_str();
321     xmlNodePtr text = xmlNewText(BAD_CAST value);
322     if (xmlAddChild(node, text) == nullptr) {
323         xmlFreeNode(text);
324     }
325     return node;
326 }
327 
CreateArrayNode(Element & element)328 xmlNode *CreateArrayNode(Element &element)
329 {
330     xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str());
331     if (node == nullptr) {
332         LOG_ERROR("The xmlDoc failed to initialize the array element node.");
333         return nullptr;
334     }
335 
336     const char *key = element.key_.c_str();
337     xmlNewProp(node, BAD_CAST "key", BAD_CAST key);
338 
339     Element flag = element.children_[0];
340     if ((flag.tag_.compare("bool") == 0) || (flag.tag_.compare("double") == 0)) {
341         for (Element &child : element.children_) {
342             xmlNode *childNode = CreatePrimitiveNode(child);
343             if (childNode == nullptr) {
344                 continue;
345             }
346             if (xmlAddChild(node, childNode) == nullptr) {
347                 xmlFreeNode(childNode);
348             }
349         }
350     } else if (flag.tag_.compare("string") == 0) {
351         for (Element child : element.children_) {
352             xmlNode *childNode = CreateStringNode(child);
353             if (childNode == nullptr) {
354                 continue;
355             }
356             if (xmlAddChild(node, childNode) == nullptr) {
357                 xmlFreeNode(childNode);
358             }
359         }
360     }
361     return node;
362 }
363 
LimitXmlPermission(const std::string & fileName)364 void PreferencesXmlUtils::LimitXmlPermission(const std::string &fileName)
365 {
366     /* clear execute permission of owner, clear execute permission of group, clear all permission of group. */
367     struct stat fileStat = { 0 };
368     if (stat(fileName.c_str(), &fileStat) != 0) {
369         LOG_ERROR("Failed to obtain stat of file, errno:%{public}d.", errno);
370         return;
371     }
372     if ((fileStat.st_mode & (S_IXUSR | S_IXGRP | S_IRWXO)) != 0) {
373         int result = chmod(fileName.c_str(), fileStat.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
374         if (result != 0) {
375             LOG_ERROR("Failed to chmod file, errno:%{public}d.", errno);
376         }
377     }
378 }
379 
XmlInitParser()380 void PreferencesXmlUtils::XmlInitParser()
381 {
382     xmlInitParser();
383     LOG_DEBUG("Xml parser get ready.");
384 }
385 
XmlCleanupParser()386 void PreferencesXmlUtils::XmlCleanupParser()
387 {
388     xmlCleanupParser();
389     LOG_DEBUG("Xml parser clean up.");
390 }
391 } // End of namespace NativePreferences
392 } // End of namespace OHOS