1 /*
2 * Copyright (c) 2025 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 #ifndef LOG_TAG
17 #define LOG_TAG "AudioXmlNode"
18 #endif
19
20 #include "audio_xml_parser.h"
21
22 #include <dlfcn.h>
23 #include <string>
24 #include <map>
25 #include <set>
26 #include <atomic>
27 #include <mutex>
28 #include <libxml/parser.h>
29 #include <libxml/tree.h>
30
31 #include "audio_errors.h"
32 #include "audio_common_log.h"
33 namespace OHOS {
34 namespace AudioStandard {
35
36 const char *LIBXML_SO_PATH = "libxml2.z.so";
37
38 struct XmlFuncHandle {
39 void *libHandle = nullptr;
40 xmlDoc *(*xmlReadFile)(const char *fileName, const char *encoding, int32_t options);
41 xmlNode *(*xmlDocGetRootElement)(xmlDoc *doc);
42 bool (*xmlHasProp)(const xmlNode *node, const xmlChar *propName);
43 xmlChar *(*xmlGetProp)(const xmlNode *node, const xmlChar *propName);
44 void (*xmlFreeDoc)(xmlDoc *doc);
45 void (*xmlFree)(xmlChar *content);
46 void (*xmlCleanupParser)();
47 int32_t (*xmlStrcmp)(const xmlChar *propName1, const xmlChar *propName2);
48 xmlChar *(*xmlNodeGetContent)(const xmlNode *cur);
49 };
50
51 std::atomic<int32_t> DlopenUtils::refCount_{0};
52 std::shared_ptr<XmlFuncHandle> DlopenUtils::xmlFuncHandle_ = nullptr;
53 std::mutex DlopenUtils::dlMutex_;
54
55 class AudioXmlNodeInner : public AudioXmlNode {
56 public:
57 AudioXmlNodeInner();
58 AudioXmlNodeInner(const AudioXmlNodeInner &obj);
59 AudioXmlNodeInner &operator=(const AudioXmlNodeInner &obj);
60 ~AudioXmlNodeInner() override;
61
62 std::shared_ptr<AudioXmlNode> GetChildrenNode() override;
63 std::shared_ptr<AudioXmlNode> GetCopyNode() override;
64 int32_t Config(const char *fileName, const char *encoding, int32_t options) override;
65 void MoveToNext() override;
66 void MoveToChildren() override;
67
68 bool IsNodeValid() override;
69 bool CompareName(const char *propName) override;
70 bool IsElementNode() override;
71 bool HasProp(const char *propName) override;
72 int32_t GetProp(const char *propName, std::string &result) override;
73 int32_t GetContent(std::string &result) override;
74 std::string GetName() override;
75
76 void FreeDoc() override;
77 void FreeProp(char *propName) override;
78
79 private:
80 int32_t StrcmpXml(const xmlChar *propName1, const xmlChar *propName2);
81 xmlDoc *doc_ = nullptr;
82 xmlNode *curNode_ = nullptr;
83 std::shared_ptr<XmlFuncHandle> xmlFuncHandle_ = nullptr;
84 };
85
Init()86 bool DlopenUtils::Init()
87 {
88 std::lock_guard<std::mutex> lock(dlMutex_);
89 if (refCount_.load() == 0) {
90 void *libHandle = dlopen(LIBXML_SO_PATH, RTLD_NOW);
91 CHECK_AND_RETURN_RET_LOG(libHandle != nullptr, false, "dlopen failed!");
92 xmlFuncHandle_ = std::make_shared<XmlFuncHandle>();
93 xmlFuncHandle_->libHandle = libHandle;
94 xmlFuncHandle_->xmlReadFile =
95 reinterpret_cast<decltype(xmlFuncHandle_->xmlReadFile)>(dlsym(libHandle, "xmlReadFile"));
96 xmlFuncHandle_->xmlDocGetRootElement =
97 reinterpret_cast<decltype(xmlFuncHandle_->xmlDocGetRootElement)>(dlsym(libHandle, "xmlDocGetRootElement"));
98 xmlFuncHandle_->xmlHasProp =
99 reinterpret_cast<decltype(xmlFuncHandle_->xmlHasProp)>(dlsym(libHandle, "xmlHasProp"));
100 xmlFuncHandle_->xmlGetProp =
101 reinterpret_cast<decltype(xmlFuncHandle_->xmlGetProp)>(dlsym(libHandle, "xmlGetProp"));
102 xmlFuncHandle_->xmlFreeDoc =
103 reinterpret_cast<decltype(xmlFuncHandle_->xmlFreeDoc)>(dlsym(libHandle, "xmlFreeDoc"));
104 xmlFuncHandle_->xmlFree =
105 reinterpret_cast<decltype(xmlFuncHandle_->xmlFree)>(dlsym(libHandle, "xmlFree"));
106 xmlFuncHandle_->xmlCleanupParser =
107 reinterpret_cast<decltype(xmlFuncHandle_->xmlCleanupParser)>(dlsym(libHandle, "xmlCleanupParser"));
108 xmlFuncHandle_->xmlStrcmp =
109 reinterpret_cast<decltype(xmlFuncHandle_->xmlStrcmp)>(dlsym(libHandle, "xmlStrcmp"));
110 xmlFuncHandle_->xmlNodeGetContent =
111 reinterpret_cast<decltype(xmlFuncHandle_->xmlNodeGetContent)>(dlsym(libHandle, "xmlNodeGetContent"));
112 AUDIO_INFO_LOG("Libxml2 open success");
113 }
114 refCount_.store(refCount_.load() + 1);
115 return true;
116 }
117
DeInit()118 void DlopenUtils::DeInit()
119 {
120 std::lock_guard<std::mutex> lock(dlMutex_);
121 refCount_.store(refCount_.load() - 1);
122 if (refCount_.load() == 0 && xmlFuncHandle_.use_count() == 1) {
123 xmlFuncHandle_->xmlCleanupParser();
124 #ifndef TEST_COVERAGE
125 dlclose(xmlFuncHandle_->libHandle);
126 #endif
127 xmlFuncHandle_ = nullptr;
128 AUDIO_INFO_LOG("Libxml2 close success");
129 }
130 }
131
GetHandle()132 std::shared_ptr<XmlFuncHandle> DlopenUtils::GetHandle()
133 {
134 std::lock_guard<std::mutex> lock(dlMutex_);
135 return xmlFuncHandle_;
136 }
137
Create()138 std::shared_ptr<AudioXmlNode> AudioXmlNode::Create()
139 {
140 return std::make_shared<AudioXmlNodeInner>();
141 }
142
GetChildrenNode()143 std::shared_ptr<AudioXmlNode> AudioXmlNodeInner::GetChildrenNode()
144 {
145 std::shared_ptr<AudioXmlNodeInner> copyNode = std::make_shared<AudioXmlNodeInner>(*this);
146 copyNode->MoveToChildren();
147 return copyNode;
148 }
149
GetCopyNode()150 std::shared_ptr<AudioXmlNode> AudioXmlNodeInner::GetCopyNode()
151 {
152 return std::make_shared<AudioXmlNodeInner>(*this);
153 }
154
AudioXmlNodeInner()155 AudioXmlNodeInner::AudioXmlNodeInner()
156 {
157 CHECK_AND_RETURN_LOG(DlopenUtils::Init(), "open so fail!");
158 xmlFuncHandle_ = DlopenUtils::GetHandle();
159 CHECK_AND_RETURN_LOG(xmlFuncHandle_ != nullptr, "get xmlFuncHandle failed!");
160 }
161
AudioXmlNodeInner(const AudioXmlNodeInner & obj)162 AudioXmlNodeInner::AudioXmlNodeInner(const AudioXmlNodeInner &obj)
163 {
164 // only the main node has doc and freedoc() when destruct
165 doc_ = nullptr;
166 curNode_ = obj.curNode_;
167 CHECK_AND_RETURN_LOG(DlopenUtils::Init(), "open so fail!");
168 xmlFuncHandle_ = DlopenUtils::GetHandle();
169 }
170
operator =(const AudioXmlNodeInner & obj)171 AudioXmlNodeInner &AudioXmlNodeInner::operator=(const AudioXmlNodeInner &obj)
172 {
173 // only the main node has doc and freedoc() when destruct
174 doc_ = nullptr;
175 curNode_ = obj.curNode_;
176 if (!DlopenUtils::Init()) {
177 AUDIO_INFO_LOG("init openUtils fail!");
178 }
179 xmlFuncHandle_ = DlopenUtils::GetHandle();
180 return *this;
181 }
182
~AudioXmlNodeInner()183 AudioXmlNodeInner::~AudioXmlNodeInner()
184 {
185 if (xmlFuncHandle_ != nullptr && doc_ != nullptr) {
186 xmlFuncHandle_->xmlFreeDoc(doc_);
187 doc_ = nullptr;
188 }
189 curNode_ = nullptr;
190 xmlFuncHandle_ = nullptr;
191 DlopenUtils::DeInit();
192 }
193
Config(const char * fileName,const char * encoding,int32_t options)194 int32_t AudioXmlNodeInner::Config(const char *fileName, const char *encoding, int32_t options)
195 {
196 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, ERROR, "xmlFuncHandle is nullptr!");
197 doc_ = xmlFuncHandle_->xmlReadFile(fileName, encoding, options);
198 CHECK_AND_RETURN_RET_LOG(doc_ != nullptr, ERROR, "xmlReadFile failed! fileName :%{public}s", fileName);
199 curNode_ = xmlFuncHandle_->xmlDocGetRootElement(doc_);
200 CHECK_AND_RETURN_RET_LOG(curNode_ != nullptr, ERROR, "xmlDocGetRootElement failed!");
201 return SUCCESS;
202 }
203
MoveToNext()204 void AudioXmlNodeInner::MoveToNext()
205 {
206 CHECK_AND_RETURN_LOG(curNode_ != nullptr, "curNode_ is nullptr! Cannot MoveToNext!");
207 curNode_ = curNode_->next;
208 }
209
MoveToChildren()210 void AudioXmlNodeInner::MoveToChildren()
211 {
212 CHECK_AND_RETURN_LOG(curNode_ != nullptr, "curNode_ is nullptr! Cannot MoveToChildren!");
213 curNode_ = curNode_->children;
214 }
215
IsNodeValid()216 bool AudioXmlNodeInner::IsNodeValid()
217 {
218 return curNode_ != nullptr;
219 }
220
221 // need check curNode_ isvalid before use
HasProp(const char * propName)222 bool AudioXmlNodeInner::HasProp(const char *propName)
223 {
224 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, false, "xmlFuncHandle is nullptr!");
225 return xmlFuncHandle_->xmlHasProp(curNode_, reinterpret_cast<const xmlChar*>(propName));
226 }
227
228 // need check curNode_ isvalid before use
GetProp(const char * propName,std::string & result)229 int32_t AudioXmlNodeInner::GetProp(const char *propName, std::string &result)
230 {
231 result = "";
232 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, ERROR, "xmlFuncHandle is nullptr!");
233 auto xmlFunc = reinterpret_cast<xmlChar *(*)(const xmlNode *node, const xmlChar *propName)>
234 (dlsym(xmlFuncHandle_->libHandle, "xmlGetProp"));
235 xmlChar *tempValue = xmlFunc(curNode_, reinterpret_cast<const xmlChar*>(propName));
236 CHECK_AND_RETURN_RET_LOG(tempValue != nullptr, ERROR, "GetProp Fail! curNode has no prop: %{public}s", propName);
237 result = reinterpret_cast<char*>(tempValue);
238 return SUCCESS;
239 }
240
GetContent(std::string & result)241 int32_t AudioXmlNodeInner::GetContent(std::string &result)
242 {
243 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, ERROR, "xmlFuncHandle is nullptr!");
244 xmlChar *tempContent = xmlFuncHandle_->xmlNodeGetContent(curNode_);
245 CHECK_AND_RETURN_RET_LOG(tempContent != nullptr, ERROR, "GetContent Fail!");
246 result = reinterpret_cast<char*>(tempContent);
247 return SUCCESS;
248 }
249
GetName()250 std::string AudioXmlNodeInner::GetName()
251 {
252 CHECK_AND_RETURN_RET_LOG(curNode_ != nullptr, "", "curNode_ is nullptr! Cannot GetName!");
253 return reinterpret_cast<char*>(const_cast<xmlChar*>(curNode_->name));
254 }
255
FreeDoc()256 void AudioXmlNodeInner::FreeDoc()
257 {
258 CHECK_AND_RETURN_LOG(xmlFuncHandle_ != nullptr, "xmlFuncHandle is nullptr!");
259 if (doc_ != nullptr) {
260 xmlFuncHandle_->xmlFreeDoc(doc_);
261 doc_ = nullptr;
262 }
263 }
264
FreeProp(char * propName)265 void AudioXmlNodeInner::FreeProp(char *propName)
266 {
267 CHECK_AND_RETURN_LOG(xmlFuncHandle_ != nullptr, "xmlFuncHandle is nullptr!");
268 xmlFuncHandle_->xmlFree(reinterpret_cast<xmlChar*>(propName));
269 }
270
StrcmpXml(const xmlChar * propName1,const xmlChar * propName2)271 int32_t AudioXmlNodeInner::StrcmpXml(const xmlChar *propName1, const xmlChar *propName2)
272 {
273 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, 1, "xmlFuncHandle is nullptr!");
274 return xmlFuncHandle_->xmlStrcmp(propName1, propName2);
275 }
276
CompareName(const char * propName)277 bool AudioXmlNodeInner::CompareName(const char *propName)
278 {
279 CHECK_AND_RETURN_RET_LOG(curNode_ != nullptr, false, "curNode_ is nullptr! Cannot CompareName!");
280 return curNode_->type == XML_ELEMENT_NODE &&
281 (StrcmpXml(curNode_->name, reinterpret_cast<const xmlChar*>(propName)) == 0);
282 }
283
IsElementNode()284 bool AudioXmlNodeInner::IsElementNode()
285 {
286 CHECK_AND_RETURN_RET_LOG(curNode_ != nullptr, false, "curNode_ is nullptr! Cannot CompareElementNode!");
287 return curNode_->type == XML_ELEMENT_NODE;
288 }
289
290 } // namespace AudioStandard
291 } // namespace OHOS
292