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 "Element.h"
31 #include "XmlElementSerializingContext.h"
32 #include "ElementLibrary.h"
33 #include "ErrorContext.h"
34 #include <assert.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 
39 using std::string;
40 
41 const std::string CElement::gDescriptionPropertyName = "Description";
42 
CElement(const string & strName)43 CElement::CElement(const string& strName) : _strName(strName), _pParent(NULL)
44 {
45 }
46 
~CElement()47 CElement::~CElement()
48 {
49     removeChildren();
50 }
51 
52 // Logging
log_info(const char * strMessage,...) const53 void CElement::log_info(const char* strMessage, ...) const
54 {
55     char *pacBuffer;
56     va_list listPointer;
57 
58     va_start(listPointer, strMessage);
59 
60     vasprintf(&pacBuffer,  strMessage, listPointer);
61 
62     va_end(listPointer);
63 
64     if (pacBuffer != NULL) {
65         doLog(false, pacBuffer);
66     }
67 
68     free(pacBuffer);
69 }
70 
log_warning(const char * strMessage,...) const71 void CElement::log_warning(const char* strMessage, ...) const
72 {
73     char *pacBuffer;
74     va_list listPointer;
75 
76     va_start(listPointer, strMessage);
77 
78     vasprintf(&pacBuffer,  strMessage, listPointer);
79 
80     va_end(listPointer);
81 
82     if (pacBuffer != NULL) {
83         doLog(true, pacBuffer);
84     }
85 
86     free(pacBuffer);
87 }
88 
89 // Log each element of the string list
log_table(bool bIsWarning,const std::list<string> lstrMessage) const90 void CElement::log_table(bool bIsWarning, const std::list<string> lstrMessage) const
91 {
92     std::list<string>::const_iterator iterator(lstrMessage.begin());
93     std::list<string>::const_iterator end(lstrMessage.end());
94 
95     while (iterator != end) {
96         // Log current list element
97         doLog(bIsWarning, iterator->c_str());
98         ++iterator;
99     }
100 }
101 
doLog(bool bIsWarning,const string & strLog) const102 void CElement::doLog(bool bIsWarning, const string& strLog) const
103 {
104     assert(_pParent);
105 
106     // Propagate till root
107     _pParent->doLog(bIsWarning, strLog);
108 }
109 
nestLog() const110 void CElement::nestLog() const
111 {
112     assert(_pParent);
113 
114     // Propagate till root
115     _pParent->nestLog();
116 }
117 
unnestLog() const118 void CElement::unnestLog() const
119 {
120     assert(_pParent);
121 
122     // Propagate till root
123     _pParent->unnestLog();
124 }
125 
126 
setDescription(const string & strDescription)127 void CElement::setDescription(const string& strDescription)
128 {
129     _strDescription = strDescription;
130 }
131 
getDescription() const132 const string& CElement::getDescription() const
133 {
134     return _strDescription;
135 }
136 
childrenAreDynamic() const137 bool CElement::childrenAreDynamic() const
138 {
139     // By default, children are searched and not created during xml parsing
140     return false;
141 }
142 
init(string & strError)143 bool CElement::init(string& strError)
144 {
145     uint32_t uiIndex;
146 
147     for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
148 
149         CElement* pElement = _childArray[uiIndex];;
150 
151         if (!pElement->init(strError)) {
152 
153             return false;
154         }
155     }
156 
157     return true;
158 }
159 
dumpContent(string & strContent,CErrorContext & errorContext,const uint32_t uiDepth) const160 void CElement::dumpContent(string& strContent, CErrorContext& errorContext, const uint32_t uiDepth) const
161 {
162     string strIndent;
163 
164     // Level
165     uint32_t uiNbIndents = uiDepth;
166 
167     while (uiNbIndents--) {
168 
169         strIndent += "    ";
170     }
171     // Type
172     strContent += strIndent + "- " + getKind();
173 
174     // Name
175     if (!_strName.empty()) {
176 
177         strContent += ": " + getName();
178     }
179 
180     // Value
181     string strValue;
182     logValue(strValue, errorContext);
183 
184     if (!strValue.empty()) {
185 
186         strContent += " = " + strValue;
187     }
188 
189     strContent += "\n";
190 
191     uint32_t uiIndex;
192 
193     for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
194 
195         _childArray[uiIndex]->dumpContent(strContent, errorContext, uiDepth + 1);
196     }
197 }
198 
199 // Element properties
showProperties(string & strResult) const200 void CElement::showProperties(string& strResult) const
201 {
202     strResult = "\n";
203     strResult += "Kind: " + getKind() + "\n";
204     showDescriptionProperty(strResult);
205 }
206 
showDescriptionProperty(std::string & strResult) const207 void CElement::showDescriptionProperty(std::string &strResult) const
208 {
209     if (!getDescription().empty()) {
210         strResult += gDescriptionPropertyName + ": " + getDescription() + "\n";
211     }
212 }
213 
214 // Content dumping
logValue(string & strValue,CErrorContext & errorContext) const215 void CElement::logValue(string& strValue, CErrorContext& errorContext) const
216 {
217     (void)strValue;
218     (void)errorContext;
219 }
220 
221 // From IXmlSink
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)222 bool CElement::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
223 {
224     setDescription(getXmlDescriptionAttribute(xmlElement));
225 
226     // Propagate through children
227     CXmlElement::CChildIterator childIterator(xmlElement);
228 
229     // Context
230     CXmlElementSerializingContext& elementSerializingContext = static_cast<CXmlElementSerializingContext&>(serializingContext);
231 
232     CXmlElement childElement;
233 
234     while (childIterator.next(childElement)) {
235 
236         CElement* pChild;
237 
238         if (!childrenAreDynamic()) {
239 
240             pChild = findChildOfKind(childElement.getType());
241 
242             if (!pChild) {
243 
244                 elementSerializingContext.setError("Unable to handle XML element: " + childElement.getPath());
245 
246                 return false;
247             }
248 
249         } else {
250             // Child needs creation
251             pChild = createChild(childElement, serializingContext);
252 
253             if (!pChild) {
254 
255                 return false;
256             }
257         }
258 
259         // Dig
260         if (!pChild->fromXml(childElement, elementSerializingContext)) {
261 
262             return false;
263         }
264     }
265 
266     return true;
267 }
268 
childrenToXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const269 void CElement::childrenToXml(CXmlElement& xmlElement,
270                              CXmlSerializingContext& serializingContext) const
271 {
272     // Browse children and propagate
273     size_t uiNbChildren = getNbChildren();
274     size_t uiChild;
275 
276     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
277 
278         const CElement* pChild = _childArray[uiChild];
279 
280         // Create corresponding child element
281         CXmlElement xmlChildElement;
282 
283         xmlElement.createChild(xmlChildElement, pChild->getKind());
284 
285         // Propagate
286         pChild->toXml(xmlChildElement, serializingContext);
287     }
288 }
289 
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const290 void CElement::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
291 {
292     setXmlNameAttribute(xmlElement);
293     setXmlDescriptionAttribute(xmlElement);
294     childrenToXml(xmlElement, serializingContext);
295 }
296 
setXmlDescriptionAttribute(CXmlElement & xmlElement) const297 void CElement::setXmlDescriptionAttribute(CXmlElement& xmlElement) const
298 {
299     const string &description = getDescription();
300     if (!description.empty()) {
301         xmlElement.setAttributeString(gDescriptionPropertyName, description);
302     }
303 }
304 
getXmlDescriptionAttribute(const CXmlElement & xmlElement) const305 string CElement::getXmlDescriptionAttribute(const CXmlElement& xmlElement) const
306 {
307     return xmlElement.getAttributeString(gDescriptionPropertyName);
308 }
309 
setXmlNameAttribute(CXmlElement & xmlElement) const310 void CElement::setXmlNameAttribute(CXmlElement& xmlElement) const
311 {
312     // By default, set Name attribute if any
313     string strName = getName();
314 
315     if (!strName.empty()) {
316 
317         xmlElement.setNameAttribute(strName);
318     }
319 }
320 
321 // Name
setName(const string & strName)322 void CElement::setName(const string& strName)
323 {
324     _strName = strName;
325 }
326 
getName() const327 const string& CElement::getName() const
328 {
329     return _strName;
330 }
331 
rename(const string & strName,string & strError)332 bool CElement::rename(const string& strName, string& strError)
333 {
334     // Check for conflict with brotherhood if relevant
335     if (_pParent && _pParent->childrenAreDynamic()) {
336 
337         size_t uiParentChild;
338         size_t uiParentNbChildren = _pParent->getNbChildren();
339 
340         for (uiParentChild = 0; uiParentChild < uiParentNbChildren; uiParentChild++) {
341 
342             const CElement* pParentChild = _pParent->getChild(uiParentChild);
343 
344             if (pParentChild != this && pParentChild->getName() == strName) {
345 
346                 // Conflict
347                 strError = "Name conflicts with brother element";
348 
349                 return false;
350             }
351         }
352     }
353     // Change name
354     setName(strName);
355 
356     return true;
357 }
358 
getPathName() const359 string CElement::getPathName() const
360 {
361     if (!_strName.empty()) {
362 
363         return _strName;
364     } else {
365 
366         return getKind();
367     }
368 }
369 
370 // Hierarchy
addChild(CElement * pChild)371 void CElement::addChild(CElement* pChild)
372 {
373     _childArray.push_back(pChild);
374 
375     pChild->_pParent = this;
376 }
377 
getChild(size_t uiIndex)378 CElement* CElement::getChild(size_t uiIndex)
379 {
380     assert(uiIndex <= _childArray.size());
381 
382     return _childArray[uiIndex];
383 }
384 
getChild(size_t uiIndex) const385 const CElement* CElement::getChild(size_t uiIndex) const
386 {
387     assert(uiIndex <= _childArray.size());
388 
389     return _childArray[uiIndex];
390 }
391 
createChild(const CXmlElement & childElement,CXmlSerializingContext & serializingContext)392 CElement* CElement::createChild(const CXmlElement& childElement,
393                                 CXmlSerializingContext& serializingContext)
394 {
395     // Context
396     CXmlElementSerializingContext& elementSerializingContext =
397             static_cast<CXmlElementSerializingContext&>(serializingContext);
398 
399     // Child needs creation
400     CElement* pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
401 
402     if (!pChild) {
403 
404         elementSerializingContext.setError(
405                     "Unable to create XML element " + childElement.getPath());
406 
407         return NULL;
408     }
409     // Store created child!
410     addChild(pChild);
411 
412     return pChild;
413 }
414 
removeChild(CElement * pChild)415 bool CElement::removeChild(CElement* pChild)
416 {
417     ChildArrayIterator it;
418 
419     for (it = _childArray.begin(); it != _childArray.end(); ++it) {
420 
421         CElement* pElement = *it;
422 
423         if (pElement == pChild) {
424 
425             _childArray.erase(it);
426 
427             return true;
428         }
429     }
430     return false;
431 }
432 
listChildren(string & strChildList) const433 void CElement::listChildren(string& strChildList) const
434 {
435     strChildList = "\n";
436 
437     // Get list of children names
438     size_t uiNbChildren = getNbChildren();
439     size_t uiChild;
440 
441     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
442 
443         const CElement* pChild = _childArray[uiChild];
444 
445         strChildList += pChild->getName() + "\n";
446     }
447 }
448 
listQualifiedPaths(bool bDive,uint32_t uiLevel) const449 string CElement::listQualifiedPaths(bool bDive, uint32_t uiLevel) const
450 {
451     size_t uiNbChildren = getNbChildren();
452     string strResult;
453 
454     // Dive Will cause only leaf nodes to be printed
455     if (!bDive || !uiNbChildren) {
456 
457         strResult = getQualifiedPath() + "\n";
458     }
459 
460     if (bDive || !uiLevel) {
461         // Get list of children paths
462         size_t uiChild;
463 
464         for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
465 
466             const CElement* pChild = _childArray[uiChild];
467 
468             strResult += pChild->listQualifiedPaths(bDive, uiLevel + 1);
469         }
470     }
471     return strResult;
472 }
473 
listChildrenPaths(string & strChildList) const474 void CElement::listChildrenPaths(string& strChildList) const
475 {
476     // Get list of children paths
477     size_t uiNbChildren = getNbChildren();
478     size_t uiChild;
479 
480     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
481 
482         const CElement* pChild = _childArray[uiChild];
483 
484         strChildList += pChild->getPath() + "\n";
485     }
486 }
487 
getNbChildren() const488 size_t CElement::getNbChildren() const
489 {
490     return _childArray.size();
491 }
492 
getParent() const493 const CElement* CElement::getParent() const
494 {
495     return _pParent;
496 }
497 
getParent()498 CElement* CElement::getParent()
499 {
500     return _pParent;
501 }
502 
clean()503 void CElement::clean()
504 {
505     if (childrenAreDynamic()) {
506 
507         removeChildren();
508     } else {
509         // Just propagate
510         uint32_t uiIndex;
511 
512         for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
513 
514             _childArray[uiIndex]->clean();
515         }
516     }
517 }
518 
removeChildren()519 void CElement::removeChildren()
520 {
521     // Delete in reverse order
522     ChildArrayReverseIterator it;
523 
524     for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
525 
526         delete *it;
527     }
528     _childArray.clear();
529 }
530 
findDescendant(CPathNavigator & pathNavigator) const531 const CElement* CElement::findDescendant(CPathNavigator& pathNavigator) const
532 {
533     string* pStrChildName = pathNavigator.next();
534 
535     if (!pStrChildName) {
536 
537         return this;
538     }
539 
540     const CElement* pChild = findChild(*pStrChildName);
541 
542     if (!pChild) {
543 
544         return NULL;
545     }
546 
547     return pChild->findDescendant(pathNavigator);
548 }
549 
findDescendant(CPathNavigator & pathNavigator)550 CElement* CElement::findDescendant(CPathNavigator& pathNavigator)
551 {
552     string* pStrChildName = pathNavigator.next();
553 
554     if (!pStrChildName) {
555 
556         return this;
557     }
558 
559     CElement* pChild = findChild(*pStrChildName);
560 
561     if (!pChild) {
562 
563         return NULL;
564     }
565 
566     return pChild->findDescendant(pathNavigator);
567 }
568 
isDescendantOf(const CElement * pCandidateAscendant) const569 bool CElement::isDescendantOf(const CElement* pCandidateAscendant) const
570 {
571     if (!_pParent) {
572 
573         return false;
574     }
575     if (_pParent == pCandidateAscendant) {
576 
577         return true;
578     }
579     return _pParent->isDescendantOf(pCandidateAscendant);
580 }
581 
findChild(const string & strName)582 CElement* CElement::findChild(const string& strName)
583 {
584     uint32_t uiIndex;
585 
586     for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
587 
588         CElement* pElement = _childArray[uiIndex];
589 
590         if (pElement->getPathName() == strName) {
591 
592             return pElement;
593         }
594     }
595 
596     return NULL;
597 }
598 
findChild(const string & strName) const599 const CElement* CElement::findChild(const string& strName) const
600 {
601     uint32_t uiIndex;
602 
603     for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
604 
605         const CElement* pElement = _childArray[uiIndex];
606 
607         if (pElement->getPathName() == strName) {
608 
609             return pElement;
610         }
611     }
612 
613     return NULL;
614 }
615 
findChildOfKind(const string & strKind)616 CElement* CElement::findChildOfKind(const string& strKind)
617 {
618     uint32_t uiIndex;
619 
620     for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
621 
622         CElement* pElement = _childArray[uiIndex];
623 
624         if (pElement->getKind() == strKind) {
625 
626             return pElement;
627         }
628     }
629 
630     return NULL;
631 }
632 
findChildOfKind(const string & strKind) const633 const CElement* CElement::findChildOfKind(const string& strKind) const
634 {
635     uint32_t uiIndex;
636 
637     for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
638 
639         const CElement* pElement = _childArray[uiIndex];;
640 
641         if (pElement->getKind() == strKind) {
642 
643             return pElement;
644         }
645     }
646 
647     return NULL;
648 }
649 
getPath() const650 string CElement::getPath() const
651 {
652     // Take out root element from the path
653     if (_pParent && _pParent->_pParent) {
654 
655         return _pParent->getPath() + "/" + getPathName();
656     }
657     return "/" + getPathName();
658 }
659 
getQualifiedPath() const660 string CElement::getQualifiedPath() const
661 {
662     return getPath() + " [" + getKind() + "]";
663 }
664 
getDepth() const665 uint32_t CElement::getDepth() const
666 {
667     if (_pParent) {
668 
669         return _pParent->getDepth() + 1;
670     }
671 
672     return 0;
673 }
674 
675 // Checksum for integrity checks
computeStructureChecksum() const676 uint8_t CElement::computeStructureChecksum() const
677 {
678     // Base checksum computation on element kind
679     string strKind = getKind();
680 
681     // Get element kind
682     const char* pcData = strKind.c_str();
683 
684     // Cumulate
685     uint8_t uiChecksum = 0;
686 
687     while (*pcData) {
688 
689         uiChecksum += *pcData++;
690     }
691 
692     // Propagate
693     uint32_t uiIndex;
694     for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
695 
696         const CElement* pChild = _childArray[uiIndex];
697 
698         uiChecksum += pChild->computeStructureChecksum();
699     }
700 
701     return uiChecksum;
702 }
703