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 dlclose(xmlFuncHandle_->libHandle);
125 xmlFuncHandle_ = nullptr;
126 AUDIO_INFO_LOG("Libxml2 close success");
127 }
128 }
129
GetHandle()130 std::shared_ptr<XmlFuncHandle> DlopenUtils::GetHandle()
131 {
132 std::lock_guard<std::mutex> lock(dlMutex_);
133 return xmlFuncHandle_;
134 }
135
Create()136 std::shared_ptr<AudioXmlNode> AudioXmlNode::Create()
137 {
138 return std::make_shared<AudioXmlNodeInner>();
139 }
140
GetChildrenNode()141 std::shared_ptr<AudioXmlNode> AudioXmlNodeInner::GetChildrenNode()
142 {
143 std::shared_ptr<AudioXmlNodeInner> copyNode = std::make_shared<AudioXmlNodeInner>(*this);
144 copyNode->MoveToChildren();
145 return copyNode;
146 }
147
GetCopyNode()148 std::shared_ptr<AudioXmlNode> AudioXmlNodeInner::GetCopyNode()
149 {
150 return std::make_shared<AudioXmlNodeInner>(*this);
151 }
152
AudioXmlNodeInner()153 AudioXmlNodeInner::AudioXmlNodeInner()
154 {
155 CHECK_AND_RETURN_LOG(DlopenUtils::Init(), "open so fail!");
156 xmlFuncHandle_ = DlopenUtils::GetHandle();
157 CHECK_AND_RETURN_LOG(xmlFuncHandle_ != nullptr, "get xmlFuncHandle failed!");
158 }
159
AudioXmlNodeInner(const AudioXmlNodeInner & obj)160 AudioXmlNodeInner::AudioXmlNodeInner(const AudioXmlNodeInner &obj)
161 {
162 // only the main node has doc and freedoc() when destruct
163 doc_ = nullptr;
164 curNode_ = obj.curNode_;
165 CHECK_AND_RETURN_LOG(DlopenUtils::Init(), "open so fail!");
166 xmlFuncHandle_ = DlopenUtils::GetHandle();
167 }
168
operator =(const AudioXmlNodeInner & obj)169 AudioXmlNodeInner &AudioXmlNodeInner::operator=(const AudioXmlNodeInner &obj)
170 {
171 // only the main node has doc and freedoc() when destruct
172 doc_ = nullptr;
173 curNode_ = obj.curNode_;
174 if (!DlopenUtils::Init()) {
175 AUDIO_INFO_LOG("init openUtils fail!");
176 }
177 xmlFuncHandle_ = DlopenUtils::GetHandle();
178 return *this;
179 }
180
~AudioXmlNodeInner()181 AudioXmlNodeInner::~AudioXmlNodeInner()
182 {
183 if (xmlFuncHandle_ != nullptr && doc_ != nullptr) {
184 xmlFuncHandle_->xmlFreeDoc(doc_);
185 doc_ = nullptr;
186 }
187 curNode_ = nullptr;
188 xmlFuncHandle_ = nullptr;
189 DlopenUtils::DeInit();
190 }
191
Config(const char * fileName,const char * encoding,int32_t options)192 int32_t AudioXmlNodeInner::Config(const char *fileName, const char *encoding, int32_t options)
193 {
194 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, ERROR, "xmlFuncHandle is nullptr!");
195 doc_ = xmlFuncHandle_->xmlReadFile(fileName, encoding, options);
196 CHECK_AND_RETURN_RET_LOG(doc_ != nullptr, ERROR, "xmlReadFile failed! fileName :%{public}s", fileName);
197 curNode_ = xmlFuncHandle_->xmlDocGetRootElement(doc_);
198 CHECK_AND_RETURN_RET_LOG(curNode_ != nullptr, ERROR, "xmlDocGetRootElement failed!");
199 return SUCCESS;
200 }
201
MoveToNext()202 void AudioXmlNodeInner::MoveToNext()
203 {
204 CHECK_AND_RETURN_LOG(curNode_ != nullptr, "curNode_ is nullptr! Cannot MoveToNext!");
205 curNode_ = curNode_->next;
206 }
207
MoveToChildren()208 void AudioXmlNodeInner::MoveToChildren()
209 {
210 CHECK_AND_RETURN_LOG(curNode_ != nullptr, "curNode_ is nullptr! Cannot MoveToChildren!");
211 curNode_ = curNode_->children;
212 }
213
IsNodeValid()214 bool AudioXmlNodeInner::IsNodeValid()
215 {
216 return curNode_ != nullptr;
217 }
218
219 // need check curNode_ isvalid before use
HasProp(const char * propName)220 bool AudioXmlNodeInner::HasProp(const char *propName)
221 {
222 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, false, "xmlFuncHandle is nullptr!");
223 return xmlFuncHandle_->xmlHasProp(curNode_, reinterpret_cast<const xmlChar*>(propName));
224 }
225
226 // need check curNode_ isvalid before use
GetProp(const char * propName,std::string & result)227 int32_t AudioXmlNodeInner::GetProp(const char *propName, std::string &result)
228 {
229 result = "";
230 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, ERROR, "xmlFuncHandle is nullptr!");
231 auto xmlFunc = reinterpret_cast<xmlChar *(*)(const xmlNode *node, const xmlChar *propName)>
232 (dlsym(xmlFuncHandle_->libHandle, "xmlGetProp"));
233 xmlChar *tempValue = xmlFunc(curNode_, reinterpret_cast<const xmlChar*>(propName));
234 CHECK_AND_RETURN_RET_LOG(tempValue != nullptr, ERROR, "GetProp Fail! curNode has no prop: %{public}s", propName);
235 result = reinterpret_cast<char*>(tempValue);
236 return SUCCESS;
237 }
238
GetContent(std::string & result)239 int32_t AudioXmlNodeInner::GetContent(std::string &result)
240 {
241 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, ERROR, "xmlFuncHandle is nullptr!");
242 xmlChar *tempContent = xmlFuncHandle_->xmlNodeGetContent(curNode_);
243 CHECK_AND_RETURN_RET_LOG(tempContent != nullptr, ERROR, "GetContent Fail!");
244 result = reinterpret_cast<char*>(tempContent);
245 return SUCCESS;
246 }
247
GetName()248 std::string AudioXmlNodeInner::GetName()
249 {
250 CHECK_AND_RETURN_RET_LOG(curNode_ != nullptr, "", "curNode_ is nullptr! Cannot GetName!");
251 return reinterpret_cast<char*>(const_cast<xmlChar*>(curNode_->name));
252 }
253
FreeDoc()254 void AudioXmlNodeInner::FreeDoc()
255 {
256 CHECK_AND_RETURN_LOG(xmlFuncHandle_ != nullptr, "xmlFuncHandle is nullptr!");
257 if (doc_ != nullptr) {
258 xmlFuncHandle_->xmlFreeDoc(doc_);
259 doc_ = nullptr;
260 }
261 }
262
FreeProp(char * propName)263 void AudioXmlNodeInner::FreeProp(char *propName)
264 {
265 CHECK_AND_RETURN_LOG(xmlFuncHandle_ != nullptr, "xmlFuncHandle is nullptr!");
266 xmlFuncHandle_->xmlFree(reinterpret_cast<xmlChar*>(propName));
267 }
268
StrcmpXml(const xmlChar * propName1,const xmlChar * propName2)269 int32_t AudioXmlNodeInner::StrcmpXml(const xmlChar *propName1, const xmlChar *propName2)
270 {
271 CHECK_AND_RETURN_RET_LOG(xmlFuncHandle_ != nullptr, 1, "xmlFuncHandle is nullptr!");
272 return xmlFuncHandle_->xmlStrcmp(propName1, propName2);
273 }
274
CompareName(const char * propName)275 bool AudioXmlNodeInner::CompareName(const char *propName)
276 {
277 CHECK_AND_RETURN_RET_LOG(curNode_ != nullptr, false, "curNode_ is nullptr! Cannot CompareName!");
278 return curNode_->type == XML_ELEMENT_NODE &&
279 (StrcmpXml(curNode_->name, reinterpret_cast<const xmlChar*>(propName)) == 0);
280 }
281
IsElementNode()282 bool AudioXmlNodeInner::IsElementNode()
283 {
284 CHECK_AND_RETURN_RET_LOG(curNode_ != nullptr, false, "curNode_ is nullptr! Cannot CompareElementNode!");
285 return curNode_->type == XML_ELEMENT_NODE;
286 }
287
288 } // namespace AudioStandard
289 } // namespace OHOS
290