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