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