• 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         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