blob: 915bc6565e97c9c523bbf51f95788a39ae68852c [file] [log] [blame]
Patrick Benavoli68a91282011-08-31 11:23:23 +02001/* <auto_header>
2 * <FILENAME>
3 *
4 * INTEL CONFIDENTIAL
5 * Copyright © 2011 Intel
6 * Corporation All Rights Reserved.
7 *
8 * The source code contained or described herein and all documents related to
9 * the source code ("Material") are owned by Intel Corporation or its suppliers
10 * or licensors. Title to the Material remains with Intel Corporation or its
11 * suppliers and licensors. The Material contains trade secrets and proprietary
12 * and confidential information of Intel or its suppliers and licensors. The
13 * Material is protected by worldwide copyright and trade secret laws and
14 * treaty provisions. No part of the Material may be used, copied, reproduced,
15 * modified, published, uploaded, posted, transmitted, distributed, or
16 * disclosed in any way without Intel’s prior express written permission.
17 *
18 * No license under any patent, copyright, trade secret or other intellectual
19 * property right is granted to or conferred upon you by disclosure or delivery
20 * of the Materials, either expressly, by implication, inducement, estoppel or
21 * otherwise. Any license under such intellectual property rights must be
22 * express and approved by Intel in writing.
23 *
24 * AUTHOR: Patrick Benavoli (patrickx.benavoli@intel.com)
25 * CREATED: 2011-06-01
26 * UPDATED: 2011-07-27
27 *
28 *
29 * </auto_header>
30 */
31#include "Element.h"
32#include <assert.h>
33#include <stdio.h>
34#include <stdarg.h>
Patrick Benavoli2ecf9002011-08-31 11:23:24 +020035#include <sstream>
Patrick Benavoli68a91282011-08-31 11:23:23 +020036#include "XmlElementSerializingContext.h"
37#include "ElementLibrary.h"
38#include "ErrorContext.h"
39
40CElement::CElement(const string& strName) : _strName(strName), _pParent(NULL)
41{
42}
43
44CElement::~CElement()
45{
46 removeChildren();
47}
48
49// Logging
50void CElement::log(const string& strMessage, ...) const
51{
52 char acBuffer[512];
53 va_list listPointer;
54
55 va_start(listPointer, strMessage);
56
57 vsnprintf(acBuffer, sizeof(acBuffer), strMessage.c_str(), listPointer);
58
59 va_end(listPointer);
60
61 doLog(acBuffer);
62}
63
64void CElement::doLog(const string& strLog) const
65{
66 assert(_pParent);
67
68 // Propagate till root
69 _pParent->doLog(strLog);
70}
71
72void CElement::nestLog() const
73{
74 assert(_pParent);
75
76 // Propagate till root
77 _pParent->nestLog();
78}
79
80void CElement::unnestLog() const
81{
82 assert(_pParent);
83
84 // Propagate till root
85 _pParent->unnestLog();
86}
87
88
89void CElement::setDescription(const string& strDescription)
90{
91 _strDescription = strDescription;
92}
93
94const string& CElement::getDescription() const
95{
96 return _strDescription;
97}
98
99bool CElement::childrenAreDynamic() const
100{
101 // By default, children are searched and not created during xml parsing
102 return false;
103}
104
105bool CElement::init(string& strError)
106{
107 uint32_t uiIndex;
108
109 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
110
111 CElement* pElement = _childArray[uiIndex];;
112
113 if (!pElement->init(strError)) {
114
115 return false;
116 }
117 }
118
119 return true;
120}
121
122void CElement::dumpContent(string& strContent, CErrorContext& errorContext, const uint32_t uiDepth) const
123{
124 string strIndent;
125
126 // Level
127 uint32_t uiNbIndents = uiDepth;
128
129 while (uiNbIndents--) {
130
131 strIndent += " ";
132 }
133 // Type
134 strContent += strIndent + "- " + getKind();
135
136 // Name
137 if (!_strName.empty()) {
138
139 strContent += ": " + getName();
140 }
141
142 // Value
143 string strValue;
144 logValue(strValue, errorContext);
145
146 if (!strValue.empty()) {
147
148 strContent += " = " + strValue;
149 }
150
151 strContent += "\n";
152
153 uint32_t uiIndex;
154
155 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
156
157 _childArray[uiIndex]->dumpContent(strContent, errorContext, uiDepth + 1);
158 }
159}
160
Patrick Benavoli2ecf9002011-08-31 11:23:24 +0200161// Element properties
162void CElement::showProperties(string& strResult) const
163{
164 strResult = "\n";
165 strResult += "Kind: " + getKind() + "\n";
166}
167
168// Conversion utilities
169string CElement::toString(uint32_t uiValue)
170{
171 ostringstream ostr;
172
173 ostr << uiValue;
174
175 return ostr.str();
176}
177
178string CElement::toString(int32_t iValue)
179{
180 ostringstream ostr;
181
182 ostr << iValue;
183
184 return ostr.str();
185}
186
187// Content dumping
Patrick Benavoli68a91282011-08-31 11:23:23 +0200188void CElement::logValue(string& strValue, CErrorContext& errorContext) const
189{
190 (void)strValue;
191 (void)errorContext;
192}
193
194// From IXmlSink
195bool CElement::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
196{
197 // Propagate through children
198 CXmlElement::CChildIterator childIterator(xmlElement);
199
200 // Context
201 CXmlElementSerializingContext& elementSerializingContext = static_cast<CXmlElementSerializingContext&>(serializingContext);
202
203 CXmlElement childElement;
204
205 while (childIterator.next(childElement)) {
206
207 CElement* pChild;
208
209 if (!childrenAreDynamic()) {
210
211 pChild = findChildOfKind(childElement.getType());
212
213 if (!pChild) {
214
215 elementSerializingContext.setError("XML Path not found: " + xmlElement.getPath());
216
217 return false;
218 }
219
220 } else {
221 // Child needs creation
222 pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
223
224 if (pChild) {
225
226 // Store created child!
227 addChild(pChild);
228 } else {
229
230 elementSerializingContext.setError("Unable to create XML element " + childElement.getPath());
231
232 return false;
233 }
234 }
235
236 // Dig
237 if (!pChild->fromXml(childElement, elementSerializingContext)) {
238
239 return false;
240 }
241 }
242
243 return true;
244}
245
246// From IXmlSource
247void CElement::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
248{
249 // Browse children and propagate
250 uint32_t uiNbChildren = getNbChildren();
251 uint32_t uiChild;
252
253 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
254
255 const CElement* pChild = _childArray[uiChild];
256
257 // Create corresponding child element
258 CXmlElement xmlChildElement;
259
260 xmlElement.createChild(xmlChildElement, pChild->getKind());
261
262 // Set attributes
263 pChild->setXmlNameAttribute(xmlChildElement);
264
265
266 // Propagate
267 pChild->toXml(xmlChildElement, serializingContext);
268 }
269}
270
271void CElement::setXmlNameAttribute(CXmlElement& xmlElement) const
272{
273 // By default, set Name attribute if any
274 string strName = getName();
275
276 if (!strName.empty()) {
277
278 xmlElement.setNameAttribute(strName);
279 }
280}
281
282// Name
283void CElement::setName(const string& strName)
284{
285 _strName = strName;
286}
287
288const string& CElement::getName() const
289{
290 return _strName;
291}
292
293bool CElement::rename(const string& strName, string& strError)
294{
295 // Check for conflict with brotherhood if relevant
296 if (_pParent && _pParent->childrenAreDynamic()) {
297
298 uint32_t uiParentChild;
299 uint32_t uiParentNbChildren = _pParent->getNbChildren();
300
301 for (uiParentChild = 0; uiParentChild < uiParentNbChildren; uiParentChild++) {
302
303 const CElement* pParentChild = _pParent->getChild(uiParentChild);
304
305 if (pParentChild != this && pParentChild->getName() == strName) {
306
307 // Conflict
308 strError = "Name conflicts with brother element";
309
310 return false;
311 }
312 }
313 }
314 // Change name
315 setName(strName);
316
317 return true;
318}
319
320string CElement::getPathName() const
321{
322 if (!_strName.empty()) {
323
324 return _strName;
325 } else {
326
327 return getKind();
328 }
329}
330
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200331// Hierarchy
Patrick Benavoli68a91282011-08-31 11:23:23 +0200332void CElement::addChild(CElement* pChild)
333{
334 _childArray.push_back(pChild);
335
336 pChild->_pParent = this;
337}
338
339CElement* CElement::getChild(uint32_t uiIndex)
340{
341 assert(uiIndex <= _childArray.size());
342
343 return _childArray[uiIndex];
344}
345
346const CElement* CElement::getChild(uint32_t uiIndex) const
347{
348 assert(uiIndex <= _childArray.size());
349
350 return _childArray[uiIndex];
351}
352
353CElement* CElement::getLastChild()
354{
355 uint32_t uiNbChildren = getNbChildren();
356
357 assert(uiNbChildren);
358
359 return _childArray[uiNbChildren - 1];
360}
361
362bool CElement::removeChild(CElement* pChild)
363{
364 ChildArrayIterator it;
365
366 for (it = _childArray.begin(); it != _childArray.end(); ++it) {
367
368 CElement* pElement = *it;
369
370 if (pElement == pChild) {
371
372 _childArray.erase(it);
373
374 return true;
375 }
376 }
377 return false;
378}
379
380void CElement::listChildren(string& strChildList) const
381{
382 strChildList = "\n";
383
384 // Get list of children names
385 uint32_t uiNbChildren = getNbChildren();
386 uint32_t uiChild;
387
388 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
389
390 const CElement* pChild = _childArray[uiChild];
391
392 strChildList += pChild->getName() + "\n";
393 }
394}
395
396string CElement::listQualifiedPaths(bool bDive, uint32_t uiLevel) const
397{
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200398 uint32_t uiNbChildren = getNbChildren();
399 string strResult;
400
401 // Dive Will cause only leaf nodes to be printed
402 if (!bDive || !uiNbChildren) {
403
404 strResult = getQualifiedPath() + "\n";
405 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200406
407 if (bDive || !uiLevel) {
408 // Get list of children paths
Patrick Benavoli68a91282011-08-31 11:23:23 +0200409 uint32_t uiChild;
410
411 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
412
413 const CElement* pChild = _childArray[uiChild];
414
415 strResult += pChild->listQualifiedPaths(bDive, uiLevel + 1);
416 }
417 }
418 return strResult;
419}
420
421void CElement::listChildrenPaths(string& strChildList) const
422{
Patrick Benavoli68a91282011-08-31 11:23:23 +0200423 // Get list of children paths
424 uint32_t uiNbChildren = getNbChildren();
425 uint32_t uiChild;
426
427 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
428
429 const CElement* pChild = _childArray[uiChild];
430
431 strChildList += pChild->getPath() + "\n";
432 }
433}
434
435uint32_t CElement::getNbChildren() const
436{
437 return _childArray.size();
438}
439
440const CElement* CElement::getParent() const
441{
442 return _pParent;
443}
444
445CElement* CElement::getParent()
446{
447 return _pParent;
448}
449
450void CElement::clean()
451{
452 if (childrenAreDynamic()) {
453
454 removeChildren();
455 } else {
456 // Just propagate
457 uint32_t uiIndex;
458
459 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
460
461 _childArray[uiIndex]->clean();
462 }
463 }
464}
465
466void CElement::removeChildren()
467{
468 // Delete in reverse order
469 ChildArrayReverseIterator it;
470
471 for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
472
473 delete *it;
474 }
475 _childArray.clear();
476}
477
478const CElement* CElement::findDescendant(CPathNavigator& pathNavigator) const
479{
480 string* pStrChildName = pathNavigator.next();
481
482 if (!pStrChildName) {
483
484 return this;
485 }
486
487 const CElement* pChild = findChild(*pStrChildName);
488
489 if (!pChild) {
490
491 return NULL;
492 }
493
494 return pChild->findDescendant(pathNavigator);
495}
496
497CElement* CElement::findDescendant(CPathNavigator& pathNavigator)
498{
499 string* pStrChildName = pathNavigator.next();
500
501 if (!pStrChildName) {
502
503 return this;
504 }
505
506 CElement* pChild = findChild(*pStrChildName);
507
508 if (!pChild) {
509
510 return NULL;
511 }
512
513 return pChild->findDescendant(pathNavigator);
514}
515
516bool CElement::isDescendantOf(const CElement* pCandidateAscendant) const
517{
518 if (!_pParent) {
519
520 return false;
521 }
522 if (_pParent == pCandidateAscendant) {
523
524 return true;
525 }
526 return _pParent->isDescendantOf(pCandidateAscendant);
527}
528
529CElement* CElement::findAscendantOfKind(const string& strKind)
530{
531 if (!_pParent) {
532
533 return NULL;
534 }
535
536 if (_pParent->getKind() == strKind) {
537
538 return _pParent;
539 }
540 return _pParent->findAscendantOfKind(strKind);
541}
542
543CElement* CElement::findChild(const string& strName)
544{
545 uint32_t uiIndex;
546
547 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
548
549 CElement* pElement = _childArray[uiIndex];
550
551 if (pElement->getPathName() == strName) {
552
553 return pElement;
554 }
555 }
556
557 return NULL;
558}
559
560const CElement* CElement::findChild(const string& strName) const
561{
562 uint32_t uiIndex;
563
564 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
565
566 const CElement* pElement = _childArray[uiIndex];
567
568 if (pElement->getPathName() == strName) {
569
570 return pElement;
571 }
572 }
573
574 return NULL;
575}
576
577CElement* CElement::findChildOfKind(const string& strKind)
578{
579 uint32_t uiIndex;
580
581 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
582
583 CElement* pElement = _childArray[uiIndex];
584
585 if (pElement->getKind() == strKind) {
586
587 return pElement;
588 }
589 }
590
591 return NULL;
592}
593
594const CElement* CElement::findChildOfKind(const string& strKind) const
595{
596 uint32_t uiIndex;
597
598 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
599
600 const CElement* pElement = _childArray[uiIndex];;
601
602 if (pElement->getKind() == strKind) {
603
604 return pElement;
605 }
606 }
607
608 return NULL;
609}
610
611CElement* CElement::getRoot()
612{
613 if (!_pParent) {
614
615 return this;
616 }
617 return _pParent->getRoot();
618}
619
620const CElement* CElement::getRoot() const
621{
622 if (!_pParent) {
623
624 return this;
625 }
626 return _pParent->getRoot();
627}
628
629string CElement::getPath() const
630{
631 // Take out root element from the path
632 if (_pParent && _pParent->_pParent) {
633
634 return _pParent->getPath() + "/" + getPathName();
635 }
636 return "/" + getPathName();
637}
638
639string CElement::getQualifiedPath() const
640{
641 return getPath() + " [" + getKind() + "]";
642}
643
644uint32_t CElement::getDepth() const
645{
646 if (_pParent) {
647
648 return _pParent->getDepth() + 1;
649 }
650
651 return 0;
652}
653
654// Checksum for integrity checks
655uint8_t CElement::computeStructureChecksum() const
656{
657 // Base checksum computation on element kind
658 string strKind = getKind();
659
660 // Get element kind
661 const char* pcData = strKind.c_str();
662
663 // Cumulate
664 uint8_t uiChecksum = 0;
665
666 while (*pcData) {
667
668 uiChecksum += *pcData++;
669 }
670
671 // Propagate
672 uint32_t uiIndex;
673 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
674
675 const CElement* pChild = _childArray[uiIndex];
676
677 uiChecksum += pChild->computeStructureChecksum();
678 }
679
680 return uiChecksum;
681}
682
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200683// Utility to underline
684void CElement::appendTitle(string& strTo, const string& strTitle)
685{
686 strTo += "\n" + strTitle + "\n";
687
688 uint32_t uiLength = strTitle.size();
689
690 while (uiLength--) {
691
692 strTo += "─";
693 }
694 strTo += "\n";
695}