blob: 8981ba9881d7678c9d1975f0b48e0d7d8b29bdfd [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
Patrick Benavoliee65e6d2011-11-20 18:52:24 +0100187string CElement::toString(double dValue)
188{
189 ostringstream ostr;
190
191 ostr << dValue;
192
193 return ostr.str();
194}
195
Patrick Benavoli2ecf9002011-08-31 11:23:24 +0200196// Content dumping
Patrick Benavoli68a91282011-08-31 11:23:23 +0200197void CElement::logValue(string& strValue, CErrorContext& errorContext) const
198{
199 (void)strValue;
200 (void)errorContext;
201}
202
203// From IXmlSink
204bool CElement::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
205{
206 // Propagate through children
207 CXmlElement::CChildIterator childIterator(xmlElement);
208
209 // Context
210 CXmlElementSerializingContext& elementSerializingContext = static_cast<CXmlElementSerializingContext&>(serializingContext);
211
212 CXmlElement childElement;
213
214 while (childIterator.next(childElement)) {
215
216 CElement* pChild;
217
218 if (!childrenAreDynamic()) {
219
220 pChild = findChildOfKind(childElement.getType());
221
222 if (!pChild) {
223
Patrick Benavoli065264a2011-11-20 15:46:41 +0100224 elementSerializingContext.setError("Unable to handle XML element: " + childElement.getPath());
Patrick Benavoli68a91282011-08-31 11:23:23 +0200225
226 return false;
227 }
228
229 } else {
230 // Child needs creation
231 pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
232
233 if (pChild) {
234
235 // Store created child!
236 addChild(pChild);
237 } else {
238
239 elementSerializingContext.setError("Unable to create XML element " + childElement.getPath());
240
241 return false;
242 }
243 }
244
245 // Dig
246 if (!pChild->fromXml(childElement, elementSerializingContext)) {
247
248 return false;
249 }
250 }
251
252 return true;
253}
254
255// From IXmlSource
256void CElement::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
257{
258 // Browse children and propagate
259 uint32_t uiNbChildren = getNbChildren();
260 uint32_t uiChild;
261
262 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
263
264 const CElement* pChild = _childArray[uiChild];
265
266 // Create corresponding child element
267 CXmlElement xmlChildElement;
268
269 xmlElement.createChild(xmlChildElement, pChild->getKind());
270
271 // Set attributes
272 pChild->setXmlNameAttribute(xmlChildElement);
273
274
275 // Propagate
276 pChild->toXml(xmlChildElement, serializingContext);
277 }
278}
279
280void CElement::setXmlNameAttribute(CXmlElement& xmlElement) const
281{
282 // By default, set Name attribute if any
283 string strName = getName();
284
285 if (!strName.empty()) {
286
287 xmlElement.setNameAttribute(strName);
288 }
289}
290
291// Name
292void CElement::setName(const string& strName)
293{
294 _strName = strName;
295}
296
297const string& CElement::getName() const
298{
299 return _strName;
300}
301
302bool CElement::rename(const string& strName, string& strError)
303{
304 // Check for conflict with brotherhood if relevant
305 if (_pParent && _pParent->childrenAreDynamic()) {
306
307 uint32_t uiParentChild;
308 uint32_t uiParentNbChildren = _pParent->getNbChildren();
309
310 for (uiParentChild = 0; uiParentChild < uiParentNbChildren; uiParentChild++) {
311
312 const CElement* pParentChild = _pParent->getChild(uiParentChild);
313
314 if (pParentChild != this && pParentChild->getName() == strName) {
315
316 // Conflict
317 strError = "Name conflicts with brother element";
318
319 return false;
320 }
321 }
322 }
323 // Change name
324 setName(strName);
325
326 return true;
327}
328
329string CElement::getPathName() const
330{
331 if (!_strName.empty()) {
332
333 return _strName;
334 } else {
335
336 return getKind();
337 }
338}
339
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200340// Hierarchy
Patrick Benavoli68a91282011-08-31 11:23:23 +0200341void CElement::addChild(CElement* pChild)
342{
343 _childArray.push_back(pChild);
344
345 pChild->_pParent = this;
346}
347
348CElement* CElement::getChild(uint32_t uiIndex)
349{
350 assert(uiIndex <= _childArray.size());
351
352 return _childArray[uiIndex];
353}
354
355const CElement* CElement::getChild(uint32_t uiIndex) const
356{
357 assert(uiIndex <= _childArray.size());
358
359 return _childArray[uiIndex];
360}
361
362CElement* CElement::getLastChild()
363{
364 uint32_t uiNbChildren = getNbChildren();
365
366 assert(uiNbChildren);
367
368 return _childArray[uiNbChildren - 1];
369}
370
371bool CElement::removeChild(CElement* pChild)
372{
373 ChildArrayIterator it;
374
375 for (it = _childArray.begin(); it != _childArray.end(); ++it) {
376
377 CElement* pElement = *it;
378
379 if (pElement == pChild) {
380
381 _childArray.erase(it);
382
383 return true;
384 }
385 }
386 return false;
387}
388
389void CElement::listChildren(string& strChildList) const
390{
391 strChildList = "\n";
392
393 // Get list of children names
394 uint32_t uiNbChildren = getNbChildren();
395 uint32_t uiChild;
396
397 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
398
399 const CElement* pChild = _childArray[uiChild];
400
401 strChildList += pChild->getName() + "\n";
402 }
403}
404
405string CElement::listQualifiedPaths(bool bDive, uint32_t uiLevel) const
406{
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200407 uint32_t uiNbChildren = getNbChildren();
408 string strResult;
409
410 // Dive Will cause only leaf nodes to be printed
411 if (!bDive || !uiNbChildren) {
412
413 strResult = getQualifiedPath() + "\n";
414 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200415
416 if (bDive || !uiLevel) {
417 // Get list of children paths
Patrick Benavoli68a91282011-08-31 11:23:23 +0200418 uint32_t uiChild;
419
420 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
421
422 const CElement* pChild = _childArray[uiChild];
423
424 strResult += pChild->listQualifiedPaths(bDive, uiLevel + 1);
425 }
426 }
427 return strResult;
428}
429
430void CElement::listChildrenPaths(string& strChildList) const
431{
Patrick Benavoli68a91282011-08-31 11:23:23 +0200432 // Get list of children paths
433 uint32_t uiNbChildren = getNbChildren();
434 uint32_t uiChild;
435
436 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
437
438 const CElement* pChild = _childArray[uiChild];
439
440 strChildList += pChild->getPath() + "\n";
441 }
442}
443
444uint32_t CElement::getNbChildren() const
445{
446 return _childArray.size();
447}
448
449const CElement* CElement::getParent() const
450{
451 return _pParent;
452}
453
454CElement* CElement::getParent()
455{
456 return _pParent;
457}
458
459void CElement::clean()
460{
461 if (childrenAreDynamic()) {
462
463 removeChildren();
464 } else {
465 // Just propagate
466 uint32_t uiIndex;
467
468 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
469
470 _childArray[uiIndex]->clean();
471 }
472 }
473}
474
475void CElement::removeChildren()
476{
477 // Delete in reverse order
478 ChildArrayReverseIterator it;
479
480 for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
481
482 delete *it;
483 }
484 _childArray.clear();
485}
486
487const CElement* CElement::findDescendant(CPathNavigator& pathNavigator) const
488{
489 string* pStrChildName = pathNavigator.next();
490
491 if (!pStrChildName) {
492
493 return this;
494 }
495
496 const CElement* pChild = findChild(*pStrChildName);
497
498 if (!pChild) {
499
500 return NULL;
501 }
502
503 return pChild->findDescendant(pathNavigator);
504}
505
506CElement* CElement::findDescendant(CPathNavigator& pathNavigator)
507{
508 string* pStrChildName = pathNavigator.next();
509
510 if (!pStrChildName) {
511
512 return this;
513 }
514
515 CElement* pChild = findChild(*pStrChildName);
516
517 if (!pChild) {
518
519 return NULL;
520 }
521
522 return pChild->findDescendant(pathNavigator);
523}
524
525bool CElement::isDescendantOf(const CElement* pCandidateAscendant) const
526{
527 if (!_pParent) {
528
529 return false;
530 }
531 if (_pParent == pCandidateAscendant) {
532
533 return true;
534 }
535 return _pParent->isDescendantOf(pCandidateAscendant);
536}
537
538CElement* CElement::findAscendantOfKind(const string& strKind)
539{
540 if (!_pParent) {
541
542 return NULL;
543 }
544
545 if (_pParent->getKind() == strKind) {
546
547 return _pParent;
548 }
549 return _pParent->findAscendantOfKind(strKind);
550}
551
552CElement* CElement::findChild(const string& strName)
553{
554 uint32_t uiIndex;
555
556 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
557
558 CElement* pElement = _childArray[uiIndex];
559
560 if (pElement->getPathName() == strName) {
561
562 return pElement;
563 }
564 }
565
566 return NULL;
567}
568
569const CElement* CElement::findChild(const string& strName) const
570{
571 uint32_t uiIndex;
572
573 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
574
575 const CElement* pElement = _childArray[uiIndex];
576
577 if (pElement->getPathName() == strName) {
578
579 return pElement;
580 }
581 }
582
583 return NULL;
584}
585
586CElement* CElement::findChildOfKind(const string& strKind)
587{
588 uint32_t uiIndex;
589
590 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
591
592 CElement* pElement = _childArray[uiIndex];
593
594 if (pElement->getKind() == strKind) {
595
596 return pElement;
597 }
598 }
599
600 return NULL;
601}
602
603const CElement* CElement::findChildOfKind(const string& strKind) const
604{
605 uint32_t uiIndex;
606
607 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
608
609 const CElement* pElement = _childArray[uiIndex];;
610
611 if (pElement->getKind() == strKind) {
612
613 return pElement;
614 }
615 }
616
617 return NULL;
618}
619
620CElement* CElement::getRoot()
621{
622 if (!_pParent) {
623
624 return this;
625 }
626 return _pParent->getRoot();
627}
628
629const CElement* CElement::getRoot() const
630{
631 if (!_pParent) {
632
633 return this;
634 }
635 return _pParent->getRoot();
636}
637
638string CElement::getPath() const
639{
640 // Take out root element from the path
641 if (_pParent && _pParent->_pParent) {
642
643 return _pParent->getPath() + "/" + getPathName();
644 }
645 return "/" + getPathName();
646}
647
648string CElement::getQualifiedPath() const
649{
650 return getPath() + " [" + getKind() + "]";
651}
652
653uint32_t CElement::getDepth() const
654{
655 if (_pParent) {
656
657 return _pParent->getDepth() + 1;
658 }
659
660 return 0;
661}
662
663// Checksum for integrity checks
664uint8_t CElement::computeStructureChecksum() const
665{
666 // Base checksum computation on element kind
667 string strKind = getKind();
668
669 // Get element kind
670 const char* pcData = strKind.c_str();
671
672 // Cumulate
673 uint8_t uiChecksum = 0;
674
675 while (*pcData) {
676
677 uiChecksum += *pcData++;
678 }
679
680 // Propagate
681 uint32_t uiIndex;
682 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
683
684 const CElement* pChild = _childArray[uiIndex];
685
686 uiChecksum += pChild->computeStructureChecksum();
687 }
688
689 return uiChecksum;
690}
691
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200692// Utility to underline
693void CElement::appendTitle(string& strTo, const string& strTitle)
694{
695 strTo += "\n" + strTitle + "\n";
696
697 uint32_t uiLength = strTitle.size();
698
699 while (uiLength--) {
700
Patrick Benavoli1387bda2011-08-31 11:23:24 +0200701 strTo += "=";
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200702 }
703 strTo += "\n";
704}