• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2011-2015, 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 "Element.h"
31 #include "XmlElementSerializingContext.h"
32 #include "ElementLibrary.h"
33 #include "ErrorContext.hpp"
34 #include "PfError.hpp"
35 #include <algorithm>
36 #include <assert.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39 #include <stdlib.h>
40 
41 using std::string;
42 
43 const std::string CElement::gDescriptionPropertyName = "Description";
44 
CElement(const string & strName)45 CElement::CElement(const string &strName) : _strName(strName)
46 {
47 }
48 
~CElement()49 CElement::~CElement()
50 {
51     removeChildren();
52 }
53 
setDescription(const string & strDescription)54 void CElement::setDescription(const string &strDescription)
55 {
56     _strDescription = strDescription;
57 }
58 
getDescription() const59 const string &CElement::getDescription() const
60 {
61     return _strDescription;
62 }
63 
childrenAreDynamic() const64 bool CElement::childrenAreDynamic() const
65 {
66     // By default, children are searched and not created during xml parsing
67     return false;
68 }
69 
init(string & strError)70 bool CElement::init(string &strError)
71 {
72 
73     for (CElement *child : _childArray) {
74 
75         if (!child->init(strError)) {
76 
77             return false;
78         }
79     }
80 
81     return true;
82 }
83 
dumpContent(utility::ErrorContext & errorContext,const size_t depth) const84 string CElement::dumpContent(utility::ErrorContext &errorContext, const size_t depth) const
85 {
86     string output;
87     string strIndent;
88 
89     // Level
90     size_t indents = depth;
91 
92     while (indents--) {
93 
94         strIndent += "    ";
95     }
96     // Type
97     output += strIndent + "- " + getKind();
98 
99     // Name
100     if (!_strName.empty()) {
101 
102         output += ": " + getName();
103     }
104 
105     // Value
106     string strValue = logValue(errorContext);
107 
108     if (!strValue.empty()) {
109 
110         output += " = " + strValue;
111     }
112 
113     output += "\n";
114 
115     for (CElement *pChild : _childArray) {
116 
117         output += pChild->dumpContent(errorContext, depth + 1);
118     }
119 
120     return output;
121 }
122 
123 // Element properties
showProperties(string & strResult) const124 void CElement::showProperties(string &strResult) const
125 {
126     strResult += "Kind: " + getKind() + "\n";
127     showDescriptionProperty(strResult);
128 }
129 
showDescriptionProperty(std::string & strResult) const130 void CElement::showDescriptionProperty(std::string &strResult) const
131 {
132     if (!getDescription().empty()) {
133         strResult += gDescriptionPropertyName + ": " + getDescription() + "\n";
134     }
135 }
136 
137 // Content dumping
logValue(utility::ErrorContext &) const138 string CElement::logValue(utility::ErrorContext & /*ctx*/) const
139 {
140     return "";
141 }
142 
143 // From IXmlSink
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)144 bool CElement::fromXml(const CXmlElement &xmlElement,
145                        CXmlSerializingContext &serializingContext) try {
146     xmlElement.getAttribute(gDescriptionPropertyName, _strDescription);
147 
148     // Propagate through children
149     CXmlElement::CChildIterator childIterator(xmlElement);
150 
151     CXmlElement childElement;
152 
153     while (childIterator.next(childElement)) {
154 
155         CElement *pChild;
156 
157         if (!childrenAreDynamic()) {
158 
159             pChild = findChildOfKind(childElement.getType());
160 
161             if (!pChild) {
162 
163                 serializingContext.setError("Unable to handle XML element: " +
164                                             childElement.getPath());
165 
166                 return false;
167             }
168 
169         } else {
170             // Child needs creation
171             pChild = createChild(childElement, serializingContext);
172 
173             if (!pChild) {
174 
175                 return false;
176             }
177         }
178 
179         // Dig
180         if (!pChild->fromXml(childElement, serializingContext)) {
181 
182             return false;
183         }
184     }
185 
186     return true;
187 } catch (const PfError &e) {
188     serializingContext.appendLineToError(e.what());
189     return false;
190 }
191 
childrenToXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const192 void CElement::childrenToXml(CXmlElement &xmlElement,
193                              CXmlSerializingContext &serializingContext) const
194 {
195     // Browse children and propagate
196     for (CElement *pChild : _childArray) {
197 
198         // Create corresponding child element
199         CXmlElement xmlChildElement;
200 
201         xmlElement.createChild(xmlChildElement, pChild->getXmlElementName());
202 
203         // Propagate
204         pChild->toXml(xmlChildElement, serializingContext);
205     }
206 }
207 
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const208 void CElement::toXml(CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) const
209 {
210     setXmlNameAttribute(xmlElement);
211     setXmlDescriptionAttribute(xmlElement);
212     childrenToXml(xmlElement, serializingContext);
213 }
214 
setXmlDescriptionAttribute(CXmlElement & xmlElement) const215 void CElement::setXmlDescriptionAttribute(CXmlElement &xmlElement) const
216 {
217     const string &description = getDescription();
218     if (!description.empty()) {
219         xmlElement.setAttribute(gDescriptionPropertyName, description);
220     }
221 }
222 
setXmlNameAttribute(CXmlElement & xmlElement) const223 void CElement::setXmlNameAttribute(CXmlElement &xmlElement) const
224 {
225     // By default, set Name attribute if any
226     string strName = getName();
227 
228     if (!strName.empty()) {
229 
230         xmlElement.setNameAttribute(strName);
231     }
232 }
233 
234 // Name
setName(const string & strName)235 void CElement::setName(const string &strName)
236 {
237     _strName = strName;
238 }
239 
getName() const240 const string &CElement::getName() const
241 {
242     return _strName;
243 }
244 
rename(const string & strName,string & strError)245 bool CElement::rename(const string &strName, string &strError)
246 {
247     // Check for conflict with brotherhood if relevant
248     if (_pParent && _pParent->childrenAreDynamic()) {
249 
250         for (CElement *pParentChild : _pParent->_childArray) {
251 
252             if (pParentChild != this && pParentChild->getName() == strName) {
253 
254                 // Conflict
255                 strError = "Name conflicts with brother element";
256 
257                 return false;
258             }
259         }
260     }
261     // Change name
262     setName(strName);
263 
264     return true;
265 }
266 
getPathName() const267 string CElement::getPathName() const
268 {
269     if (!_strName.empty()) {
270 
271         return _strName;
272     } else {
273 
274         return getKind();
275     }
276 }
277 
278 // Hierarchy
addChild(CElement * pChild)279 void CElement::addChild(CElement *pChild)
280 {
281     _childArray.push_back(pChild);
282 
283     pChild->_pParent = this;
284 }
285 
getChild(size_t index)286 CElement *CElement::getChild(size_t index)
287 {
288     assert(index <= _childArray.size());
289 
290     return _childArray[index];
291 }
292 
getChild(size_t index) const293 const CElement *CElement::getChild(size_t index) const
294 {
295     assert(index <= _childArray.size());
296 
297     return _childArray[index];
298 }
299 
createChild(const CXmlElement & childElement,CXmlSerializingContext & serializingContext)300 CElement *CElement::createChild(const CXmlElement &childElement,
301                                 CXmlSerializingContext &serializingContext)
302 {
303     // Context
304     CXmlElementSerializingContext &elementSerializingContext =
305         static_cast<CXmlElementSerializingContext &>(serializingContext);
306 
307     // Child needs creation
308     CElement *pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
309 
310     if (!pChild) {
311 
312         elementSerializingContext.setError("Unable to create XML element " +
313                                            childElement.getPath());
314 
315         return nullptr;
316     }
317     // Store created child!
318     addChild(pChild);
319 
320     return pChild;
321 }
322 
removeChild(CElement * pChild)323 bool CElement::removeChild(CElement *pChild)
324 {
325     auto childIt = find(begin(_childArray), end(_childArray), pChild);
326     if (childIt != end(_childArray)) {
327 
328         _childArray.erase(childIt);
329         return true;
330     }
331     return false;
332 }
333 
listChildren(string & strChildList) const334 void CElement::listChildren(string &strChildList) const
335 {
336     // Get list of children names
337     for (CElement *pChild : _childArray) {
338 
339         strChildList += pChild->getName() + "\n";
340     }
341 }
342 
listQualifiedPaths(bool bDive,size_t level) const343 string CElement::listQualifiedPaths(bool bDive, size_t level) const
344 {
345     string strResult;
346 
347     // Dive Will cause only leaf nodes to be printed
348     if (!bDive || !getNbChildren()) {
349 
350         strResult = getQualifiedPath() + "\n";
351     }
352 
353     if (bDive || !level) {
354         // Get list of children paths
355         for (CElement *pChild : _childArray) {
356 
357             strResult += pChild->listQualifiedPaths(bDive, level + 1);
358         }
359     }
360     return strResult;
361 }
362 
listChildrenPaths(string & strChildList) const363 void CElement::listChildrenPaths(string &strChildList) const
364 {
365     // Get list of children paths
366     for (CElement *pChild : _childArray) {
367 
368         strChildList += pChild->getPath() + "\n";
369     }
370 }
371 
getNbChildren() const372 size_t CElement::getNbChildren() const
373 {
374     return _childArray.size();
375 }
376 
getParent() const377 const CElement *CElement::getParent() const
378 {
379     return _pParent;
380 }
381 
getParent()382 CElement *CElement::getParent()
383 {
384     return _pParent;
385 }
386 
clean()387 void CElement::clean()
388 {
389     if (childrenAreDynamic()) {
390 
391         removeChildren();
392     } else {
393         // Just propagate
394         for (CElement *pChild : _childArray) {
395 
396             pChild->clean();
397         }
398     }
399 }
400 
removeChildren()401 void CElement::removeChildren()
402 {
403     // Delete in reverse order
404     ChildArrayReverseIterator it;
405 
406     for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
407 
408         delete *it;
409     }
410     _childArray.clear();
411 }
412 
findDescendant(CPathNavigator & pathNavigator) const413 const CElement *CElement::findDescendant(CPathNavigator &pathNavigator) const
414 {
415     string *pStrChildName = pathNavigator.next();
416 
417     if (!pStrChildName) {
418 
419         return this;
420     }
421 
422     const CElement *pChild = findChild(*pStrChildName);
423 
424     if (!pChild) {
425 
426         return nullptr;
427     }
428 
429     return pChild->findDescendant(pathNavigator);
430 }
431 
findDescendant(CPathNavigator & pathNavigator)432 CElement *CElement::findDescendant(CPathNavigator &pathNavigator)
433 {
434     string *pStrChildName = pathNavigator.next();
435 
436     if (!pStrChildName) {
437 
438         return this;
439     }
440 
441     CElement *pChild = findChild(*pStrChildName);
442 
443     if (!pChild) {
444 
445         return nullptr;
446     }
447 
448     return pChild->findDescendant(pathNavigator);
449 }
450 
isDescendantOf(const CElement * pCandidateAscendant) const451 bool CElement::isDescendantOf(const CElement *pCandidateAscendant) const
452 {
453     if (!_pParent) {
454 
455         return false;
456     }
457     if (_pParent == pCandidateAscendant) {
458 
459         return true;
460     }
461     return _pParent->isDescendantOf(pCandidateAscendant);
462 }
463 
findChild(const string & strName)464 CElement *CElement::findChild(const string &strName)
465 {
466     for (CElement *pChild : _childArray) {
467 
468         if (pChild->getPathName() == strName) {
469 
470             return pChild;
471         }
472     }
473 
474     return nullptr;
475 }
476 
findChild(const string & strName) const477 const CElement *CElement::findChild(const string &strName) const
478 {
479     for (CElement *pChild : _childArray) {
480 
481         if (pChild->getPathName() == strName) {
482 
483             return pChild;
484         }
485     }
486 
487     return nullptr;
488 }
489 
findChildOfKind(const string & strKind)490 CElement *CElement::findChildOfKind(const string &strKind)
491 {
492     for (CElement *pChild : _childArray) {
493 
494         if (pChild->getKind() == strKind) {
495 
496             return pChild;
497         }
498     }
499 
500     return nullptr;
501 }
502 
findChildOfKind(const string & strKind) const503 const CElement *CElement::findChildOfKind(const string &strKind) const
504 {
505     for (CElement *pChild : _childArray) {
506 
507         if (pChild->getKind() == strKind) {
508 
509             return pChild;
510         }
511     }
512 
513     return nullptr;
514 }
515 
getPath() const516 string CElement::getPath() const
517 {
518     // Take out root element from the path
519     if (_pParent && _pParent->_pParent) {
520 
521         return _pParent->getPath() + "/" + getPathName();
522     }
523     return "/" + getPathName();
524 }
525 
getQualifiedPath() const526 string CElement::getQualifiedPath() const
527 {
528     return getPath() + " [" + getKind() + "]";
529 }
530 
getXmlElementName() const531 string CElement::getXmlElementName() const
532 {
533     // Default to element kind
534     return getKind();
535 }
536