1 /*
2  * Copyright (c) 2011-2014, Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software without
17  * specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 #include "XmlElement.h"
31 #include <libxml/tree.h>
32 #include "convert.hpp"
33 #include <stdlib.h>
34 
35 using std::string;
36 
CXmlElement(_xmlNode * pXmlElement)37 CXmlElement::CXmlElement(_xmlNode *pXmlElement) : _pXmlElement(pXmlElement)
38 {
39 }
40 
CXmlElement()41 CXmlElement::CXmlElement() : _pXmlElement(NULL)
42 {
43 }
44 
setXmlElement(_xmlNode * pXmlElement)45 void CXmlElement::setXmlElement(_xmlNode *pXmlElement)
46 {
47     _pXmlElement = pXmlElement;
48 }
49 
getType() const50 string CXmlElement::getType() const
51 {
52     return (const char *)_pXmlElement->name;
53 }
54 
getPath() const55 string CXmlElement::getPath() const
56 {
57     string strPathElement = "/" + getType();
58 
59     if (hasAttribute("Name")) {
60 
61         strPathElement += "[@Name=" + getNameAttribute() + "]";
62     }
63 
64     CXmlElement parentElement;
65 
66     if (getParentElement(parentElement)) {
67 
68         // Done
69         return parentElement.getPath() + strPathElement;
70     }
71     return strPathElement;
72 }
73 
hasAttribute(const string & strAttributeName) const74 bool CXmlElement::hasAttribute(const string &strAttributeName) const
75 {
76     return xmlHasProp(_pXmlElement, (const xmlChar *)strAttributeName.c_str()) != NULL;
77 }
78 
79 template <>
getAttribute(const string & name,string & value) const80 bool CXmlElement::getAttribute<std::string>(const string &name, string &value) const
81 {
82     if (!hasAttribute(name)) {
83         return false;
84     }
85 
86     string backup = value;
87     xmlChar *pucXmlValue = xmlGetProp((xmlNode *)_pXmlElement, (const xmlChar *)name.c_str());
88     if (pucXmlValue == NULL) {
89         value = backup;
90         return false;
91     }
92 
93     value = (const char *)pucXmlValue;
94 
95     xmlFree(pucXmlValue);
96 
97     return true;
98 }
99 
100 template <typename T>
getAttribute(const std::string & name,T & value) const101 bool CXmlElement::getAttribute(const std::string &name, T &value) const
102 {
103     std::string rawValue;
104     if (!getAttribute(name, rawValue)) {
105         return false;
106     }
107 
108     T backup = value;
109     if (!convertTo<T>(rawValue, value)) {
110         value = backup;
111         return false;
112     }
113 
114     return true;
115 }
116 
getNameAttribute() const117 string CXmlElement::getNameAttribute() const
118 {
119     string attribute;
120     getAttribute("Name", attribute);
121     return attribute;
122 }
123 
getTextContent() const124 string CXmlElement::getTextContent() const
125 {
126     xmlChar *pucXmlContent = xmlNodeGetContent(_pXmlElement);
127     if (pucXmlContent == NULL) {
128         return "";
129     }
130 
131     string strContent((const char *)pucXmlContent);
132 
133     xmlFree(pucXmlContent);
134 
135     return strContent;
136 }
137 
getChildElement(const string & strType,CXmlElement & childElement) const138 bool CXmlElement::getChildElement(const string &strType, CXmlElement &childElement) const
139 {
140     CChildIterator childIterator(*this);
141 
142     while (childIterator.next(childElement)) {
143 
144         if (childElement.getType() == strType) {
145 
146             return true;
147         }
148     }
149     return false;
150 }
151 
getChildElement(const string & strType,const string & strNameAttribute,CXmlElement & childElement) const152 bool CXmlElement::getChildElement(const string &strType, const string &strNameAttribute,
153                                   CXmlElement &childElement) const
154 {
155     CChildIterator childIterator(*this);
156 
157     while (childIterator.next(childElement)) {
158 
159         if ((childElement.getType() == strType) &&
160             (childElement.getNameAttribute() == strNameAttribute)) {
161 
162             return true;
163         }
164     }
165     return false;
166 }
167 
getNbChildElements() const168 size_t CXmlElement::getNbChildElements() const
169 {
170     CXmlElement childElement;
171     size_t uiNbChildren = 0;
172 
173     CChildIterator childIterator(*this);
174 
175     while (childIterator.next(childElement)) {
176 
177         uiNbChildren++;
178     }
179     return uiNbChildren;
180 }
181 
getParentElement(CXmlElement & parentElement) const182 bool CXmlElement::getParentElement(CXmlElement &parentElement) const
183 {
184     _xmlNode *pXmlNode = _pXmlElement->parent;
185 
186     if (pXmlNode->type == XML_ELEMENT_NODE) {
187 
188         parentElement.setXmlElement(pXmlNode);
189 
190         return true;
191     }
192     return false;
193 }
194 
195 template <>
setAttribute(const string & name,const bool & value)196 void CXmlElement::setAttribute<bool>(const string &name, const bool &value)
197 {
198     setAttribute(name, value ? "true" : "false");
199 }
200 
201 template <>
setAttribute(const string & name,const string & value)202 void CXmlElement::setAttribute<std::string>(const string &name, const string &value)
203 {
204     setAttribute(name, value.c_str());
205 }
206 
207 // This method exists for 2 reasons:
208 //  - at link time, all calls to setAttribute(const string&, const char [N])
209 //    for any value of N will all resolve to this method; this prevents the
210 //    need for one template instance per value of N.
211 //  - the libxml2 API takes a C-style string anyway.
setAttribute(const string & name,const char * value)212 void CXmlElement::setAttribute(const string &name, const char *value)
213 {
214     xmlNewProp(_pXmlElement, BAD_CAST name.c_str(), BAD_CAST value);
215 }
216 
217 template <typename T>
setAttribute(const std::string & name,const T & value)218 void CXmlElement::setAttribute(const std::string &name, const T &value)
219 {
220     setAttribute(name, std::to_string(value).c_str());
221 }
222 
setNameAttribute(const string & strValue)223 void CXmlElement::setNameAttribute(const string &strValue)
224 {
225     setAttribute("Name", strValue);
226 }
227 
setTextContent(const string & strContent)228 void CXmlElement::setTextContent(const string &strContent)
229 {
230     xmlAddChild(_pXmlElement, xmlNewText(BAD_CAST strContent.c_str()));
231 }
232 
233 // Child creation
createChild(CXmlElement & childElement,const string & strType)234 void CXmlElement::createChild(CXmlElement &childElement, const string &strType)
235 {
236 #ifdef LIBXML_TREE_ENABLED
237     xmlNodePtr pChildNode = xmlNewChild(_pXmlElement, NULL, BAD_CAST strType.c_str(), NULL);
238 
239     childElement.setXmlElement(pChildNode);
240 #endif
241 }
242 
243 // Child iteration
CChildIterator(const CXmlElement & xmlElement)244 CXmlElement::CChildIterator::CChildIterator(const CXmlElement &xmlElement)
245     : _pCurNode(xmlElement._pXmlElement->children)
246 {
247 }
248 
next(CXmlElement & xmlChildElement)249 bool CXmlElement::CChildIterator::next(CXmlElement &xmlChildElement)
250 {
251     while (_pCurNode) {
252 
253         if (_pCurNode->type == XML_ELEMENT_NODE) {
254 
255             xmlChildElement.setXmlElement(_pCurNode);
256 
257             _pCurNode = _pCurNode->next;
258 
259             return true;
260         }
261         _pCurNode = _pCurNode->next;
262     }
263 
264     return false;
265 }
266 
267 template bool CXmlElement::getAttribute(const std::string &name, std::string &value) const;
268 template bool CXmlElement::getAttribute(const std::string &name, bool &value) const;
269 template bool CXmlElement::getAttribute(const std::string &name, short &value) const;
270 template bool CXmlElement::getAttribute(const std::string &name, unsigned short &value) const;
271 template bool CXmlElement::getAttribute(const std::string &name, int &value) const;
272 template bool CXmlElement::getAttribute(const std::string &name, unsigned int &value) const;
273 template bool CXmlElement::getAttribute(const std::string &name, long &value) const;
274 template bool CXmlElement::getAttribute(const std::string &name, unsigned long &value) const;
275 template bool CXmlElement::getAttribute(const std::string &name, long long &value) const;
276 template bool CXmlElement::getAttribute(const std::string &name, unsigned long long &value) const;
277 template bool CXmlElement::getAttribute(const std::string &name, float &value) const;
278 template bool CXmlElement::getAttribute(const std::string &name, double &value) const;
279 
280 template void CXmlElement::setAttribute(const std::string &name, const std::string &value);
281 template void CXmlElement::setAttribute(const std::string &name, const bool &value);
282 template void CXmlElement::setAttribute(const std::string &name, const short &value);
283 template void CXmlElement::setAttribute(const std::string &name, const unsigned short &value);
284 template void CXmlElement::setAttribute(const std::string &name, const int &value);
285 template void CXmlElement::setAttribute(const std::string &name, const unsigned int &value);
286 template void CXmlElement::setAttribute(const std::string &name, const long &value);
287 template void CXmlElement::setAttribute(const std::string &name, const unsigned long &value);
288 template void CXmlElement::setAttribute(const std::string &name, const long long &value);
289 template void CXmlElement::setAttribute(const std::string &name, const unsigned long long &value);
290 template void CXmlElement::setAttribute(const std::string &name, const float &value);
291 template void CXmlElement::setAttribute(const std::string &name, const double &value);
292