blob: a96c6834172ea7ddbfa02993a08d06f648621186 [file] [log] [blame]
Kevin Rocard93250d12012-07-19 17:48:30 +02001/*
Patrick Benavoli68a91282011-08-31 11:23:23 +02002 * INTEL CONFIDENTIAL
3 * Copyright © 2011 Intel
4 * Corporation All Rights Reserved.
5 *
6 * The source code contained or described herein and all documents related to
7 * the source code ("Material") are owned by Intel Corporation or its suppliers
8 * or licensors. Title to the Material remains with Intel Corporation or its
9 * suppliers and licensors. The Material contains trade secrets and proprietary
10 * and confidential information of Intel or its suppliers and licensors. The
11 * Material is protected by worldwide copyright and trade secret laws and
12 * treaty provisions. No part of the Material may be used, copied, reproduced,
13 * modified, published, uploaded, posted, transmitted, distributed, or
14 * disclosed in any way without Intel’s prior express written permission.
15 *
16 * No license under any patent, copyright, trade secret or other intellectual
17 * property right is granted to or conferred upon you by disclosure or delivery
18 * of the Materials, either expressly, by implication, inducement, estoppel or
19 * otherwise. Any license under such intellectual property rights must be
20 * express and approved by Intel in writing.
21 *
Patrick Benavoli68a91282011-08-31 11:23:23 +020022 * CREATED: 2011-06-01
23 * UPDATED: 2011-07-27
Patrick Benavoli68a91282011-08-31 11:23:23 +020024 */
25#include "Element.h"
Kevin Rocard7f265822012-12-07 18:51:22 +010026#include "XmlElementSerializingContext.h"
27#include "ElementLibrary.h"
28#include "ErrorContext.h"
Patrick Benavoli68a91282011-08-31 11:23:23 +020029#include <assert.h>
30#include <stdio.h>
31#include <stdarg.h>
Patrick Benavoli2ecf9002011-08-31 11:23:24 +020032#include <sstream>
Patrick Benavoli68a91282011-08-31 11:23:23 +020033
34CElement::CElement(const string& strName) : _strName(strName), _pParent(NULL)
35{
36}
37
38CElement::~CElement()
39{
40 removeChildren();
41}
42
43// Logging
Kevin Rocardace81f82012-12-11 16:19:17 +010044void CElement::log_info(const string& strMessage, ...) const
Patrick Benavoli68a91282011-08-31 11:23:23 +020045{
46 char acBuffer[512];
47 va_list listPointer;
48
49 va_start(listPointer, strMessage);
50
51 vsnprintf(acBuffer, sizeof(acBuffer), strMessage.c_str(), listPointer);
52
53 va_end(listPointer);
54
Kevin Rocardace81f82012-12-11 16:19:17 +010055 doLog(false, acBuffer);
Patrick Benavoli68a91282011-08-31 11:23:23 +020056}
57
Kevin Rocardace81f82012-12-11 16:19:17 +010058void CElement::log_warning(const string& strMessage, ...) const
59{
60 char acBuffer[512];
61 va_list listPointer;
62
63 va_start(listPointer, strMessage);
64
65 vsnprintf(acBuffer, sizeof(acBuffer), strMessage.c_str(), listPointer);
66
67 va_end(listPointer);
68
69 doLog(true, acBuffer);
70}
71
Kevin Rocard36299362013-02-04 14:57:47 +010072// Log each element of the string list
73void CElement::log_table(bool bIsWarning, const list<string> lstrMessage) const
74{
75 list<string>::const_iterator iterator(lstrMessage.begin());
76 list<string>::const_iterator end(lstrMessage.end());
77
78 while (iterator != end) {
79 // Log current list element
80 doLog(bIsWarning, iterator->c_str());
81 ++iterator;
82 }
83}
84
Kevin Rocardace81f82012-12-11 16:19:17 +010085void CElement::doLog(bool bIsWarning, const string& strLog) const
Patrick Benavoli68a91282011-08-31 11:23:23 +020086{
87 assert(_pParent);
88
89 // Propagate till root
Kevin Rocardace81f82012-12-11 16:19:17 +010090 _pParent->doLog(bIsWarning, strLog);
Patrick Benavoli68a91282011-08-31 11:23:23 +020091}
92
93void CElement::nestLog() const
94{
95 assert(_pParent);
96
97 // Propagate till root
98 _pParent->nestLog();
99}
100
101void CElement::unnestLog() const
102{
103 assert(_pParent);
104
105 // Propagate till root
106 _pParent->unnestLog();
107}
108
109
110void CElement::setDescription(const string& strDescription)
111{
112 _strDescription = strDescription;
113}
114
115const string& CElement::getDescription() const
116{
117 return _strDescription;
118}
119
120bool CElement::childrenAreDynamic() const
121{
122 // By default, children are searched and not created during xml parsing
123 return false;
124}
125
126bool CElement::init(string& strError)
127{
128 uint32_t uiIndex;
129
130 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
131
132 CElement* pElement = _childArray[uiIndex];;
133
134 if (!pElement->init(strError)) {
135
136 return false;
137 }
138 }
139
140 return true;
141}
142
143void CElement::dumpContent(string& strContent, CErrorContext& errorContext, const uint32_t uiDepth) const
144{
145 string strIndent;
146
147 // Level
148 uint32_t uiNbIndents = uiDepth;
149
150 while (uiNbIndents--) {
151
152 strIndent += " ";
153 }
154 // Type
155 strContent += strIndent + "- " + getKind();
156
157 // Name
158 if (!_strName.empty()) {
159
160 strContent += ": " + getName();
161 }
162
163 // Value
164 string strValue;
165 logValue(strValue, errorContext);
166
167 if (!strValue.empty()) {
168
169 strContent += " = " + strValue;
170 }
171
172 strContent += "\n";
173
174 uint32_t uiIndex;
175
176 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
177
178 _childArray[uiIndex]->dumpContent(strContent, errorContext, uiDepth + 1);
179 }
180}
181
Patrick Benavoli2ecf9002011-08-31 11:23:24 +0200182// Element properties
183void CElement::showProperties(string& strResult) const
184{
185 strResult = "\n";
186 strResult += "Kind: " + getKind() + "\n";
187}
188
189// Conversion utilities
190string CElement::toString(uint32_t uiValue)
191{
192 ostringstream ostr;
193
194 ostr << uiValue;
195
196 return ostr.str();
197}
198
Guillaume Denneulin95331562012-09-27 15:13:10 +0200199string CElement::toString(uint64_t uiValue)
200{
201 ostringstream ostr;
202
203 ostr << uiValue;
204
205 return ostr.str();
206}
207
Patrick Benavoli2ecf9002011-08-31 11:23:24 +0200208string CElement::toString(int32_t iValue)
209{
210 ostringstream ostr;
211
212 ostr << iValue;
213
214 return ostr.str();
215}
216
Patrick Benavoliee65e6d2011-11-20 18:52:24 +0100217string CElement::toString(double dValue)
218{
219 ostringstream ostr;
220
221 ostr << dValue;
222
223 return ostr.str();
224}
225
Patrick Benavoli2ecf9002011-08-31 11:23:24 +0200226// Content dumping
Patrick Benavoli68a91282011-08-31 11:23:23 +0200227void CElement::logValue(string& strValue, CErrorContext& errorContext) const
228{
229 (void)strValue;
230 (void)errorContext;
231}
232
233// From IXmlSink
234bool CElement::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
235{
236 // Propagate through children
237 CXmlElement::CChildIterator childIterator(xmlElement);
238
239 // Context
240 CXmlElementSerializingContext& elementSerializingContext = static_cast<CXmlElementSerializingContext&>(serializingContext);
241
242 CXmlElement childElement;
243
244 while (childIterator.next(childElement)) {
245
246 CElement* pChild;
247
248 if (!childrenAreDynamic()) {
249
250 pChild = findChildOfKind(childElement.getType());
251
252 if (!pChild) {
253
Patrick Benavoli065264a2011-11-20 15:46:41 +0100254 elementSerializingContext.setError("Unable to handle XML element: " + childElement.getPath());
Patrick Benavoli68a91282011-08-31 11:23:23 +0200255
256 return false;
257 }
258
259 } else {
260 // Child needs creation
261 pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
262
263 if (pChild) {
264
265 // Store created child!
266 addChild(pChild);
267 } else {
268
269 elementSerializingContext.setError("Unable to create XML element " + childElement.getPath());
270
271 return false;
272 }
273 }
274
275 // Dig
276 if (!pChild->fromXml(childElement, elementSerializingContext)) {
277
278 return false;
279 }
280 }
281
282 return true;
283}
284
285// From IXmlSource
286void CElement::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
287{
288 // Browse children and propagate
289 uint32_t uiNbChildren = getNbChildren();
290 uint32_t uiChild;
291
292 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
293
294 const CElement* pChild = _childArray[uiChild];
295
296 // Create corresponding child element
297 CXmlElement xmlChildElement;
298
299 xmlElement.createChild(xmlChildElement, pChild->getKind());
300
301 // Set attributes
302 pChild->setXmlNameAttribute(xmlChildElement);
303
304
305 // Propagate
306 pChild->toXml(xmlChildElement, serializingContext);
307 }
308}
309
310void 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
322void CElement::setName(const string& strName)
323{
324 _strName = strName;
325}
326
327const string& CElement::getName() const
328{
329 return _strName;
330}
331
332bool CElement::rename(const string& strName, string& strError)
333{
334 // Check for conflict with brotherhood if relevant
335 if (_pParent && _pParent->childrenAreDynamic()) {
336
337 uint32_t uiParentChild;
338 uint32_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
359string CElement::getPathName() const
360{
361 if (!_strName.empty()) {
362
363 return _strName;
364 } else {
365
366 return getKind();
367 }
368}
369
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200370// Hierarchy
Patrick Benavoli68a91282011-08-31 11:23:23 +0200371void CElement::addChild(CElement* pChild)
372{
373 _childArray.push_back(pChild);
374
375 pChild->_pParent = this;
376}
377
378CElement* CElement::getChild(uint32_t uiIndex)
379{
380 assert(uiIndex <= _childArray.size());
381
382 return _childArray[uiIndex];
383}
384
385const CElement* CElement::getChild(uint32_t uiIndex) const
386{
387 assert(uiIndex <= _childArray.size());
388
389 return _childArray[uiIndex];
390}
391
392CElement* CElement::getLastChild()
393{
394 uint32_t uiNbChildren = getNbChildren();
395
396 assert(uiNbChildren);
397
398 return _childArray[uiNbChildren - 1];
399}
400
401bool CElement::removeChild(CElement* pChild)
402{
403 ChildArrayIterator it;
404
405 for (it = _childArray.begin(); it != _childArray.end(); ++it) {
406
407 CElement* pElement = *it;
408
409 if (pElement == pChild) {
410
411 _childArray.erase(it);
412
413 return true;
414 }
415 }
416 return false;
417}
418
419void CElement::listChildren(string& strChildList) const
420{
421 strChildList = "\n";
422
423 // Get list of children names
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->getName() + "\n";
432 }
433}
434
435string CElement::listQualifiedPaths(bool bDive, uint32_t uiLevel) const
436{
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200437 uint32_t uiNbChildren = getNbChildren();
438 string strResult;
439
440 // Dive Will cause only leaf nodes to be printed
441 if (!bDive || !uiNbChildren) {
442
443 strResult = getQualifiedPath() + "\n";
444 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200445
446 if (bDive || !uiLevel) {
447 // Get list of children paths
Patrick Benavoli68a91282011-08-31 11:23:23 +0200448 uint32_t uiChild;
449
450 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
451
452 const CElement* pChild = _childArray[uiChild];
453
454 strResult += pChild->listQualifiedPaths(bDive, uiLevel + 1);
455 }
456 }
457 return strResult;
458}
459
460void CElement::listChildrenPaths(string& strChildList) const
461{
Patrick Benavoli68a91282011-08-31 11:23:23 +0200462 // Get list of children paths
463 uint32_t uiNbChildren = getNbChildren();
464 uint32_t uiChild;
465
466 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
467
468 const CElement* pChild = _childArray[uiChild];
469
470 strChildList += pChild->getPath() + "\n";
471 }
472}
473
474uint32_t CElement::getNbChildren() const
475{
476 return _childArray.size();
477}
478
479const CElement* CElement::getParent() const
480{
481 return _pParent;
482}
483
484CElement* CElement::getParent()
485{
486 return _pParent;
487}
488
489void CElement::clean()
490{
491 if (childrenAreDynamic()) {
492
493 removeChildren();
494 } else {
495 // Just propagate
496 uint32_t uiIndex;
497
498 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
499
500 _childArray[uiIndex]->clean();
501 }
502 }
503}
504
505void CElement::removeChildren()
506{
507 // Delete in reverse order
508 ChildArrayReverseIterator it;
509
510 for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
511
512 delete *it;
513 }
514 _childArray.clear();
515}
516
517const CElement* CElement::findDescendant(CPathNavigator& pathNavigator) const
518{
519 string* pStrChildName = pathNavigator.next();
520
521 if (!pStrChildName) {
522
523 return this;
524 }
525
526 const CElement* pChild = findChild(*pStrChildName);
527
528 if (!pChild) {
529
530 return NULL;
531 }
532
533 return pChild->findDescendant(pathNavigator);
534}
535
536CElement* CElement::findDescendant(CPathNavigator& pathNavigator)
537{
538 string* pStrChildName = pathNavigator.next();
539
540 if (!pStrChildName) {
541
542 return this;
543 }
544
545 CElement* pChild = findChild(*pStrChildName);
546
547 if (!pChild) {
548
549 return NULL;
550 }
551
552 return pChild->findDescendant(pathNavigator);
553}
554
555bool CElement::isDescendantOf(const CElement* pCandidateAscendant) const
556{
557 if (!_pParent) {
558
559 return false;
560 }
561 if (_pParent == pCandidateAscendant) {
562
563 return true;
564 }
565 return _pParent->isDescendantOf(pCandidateAscendant);
566}
567
568CElement* CElement::findAscendantOfKind(const string& strKind)
569{
570 if (!_pParent) {
571
572 return NULL;
573 }
574
575 if (_pParent->getKind() == strKind) {
576
577 return _pParent;
578 }
579 return _pParent->findAscendantOfKind(strKind);
580}
581
582CElement* 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
599const 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
616CElement* 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
633const 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
650CElement* CElement::getRoot()
651{
652 if (!_pParent) {
653
654 return this;
655 }
656 return _pParent->getRoot();
657}
658
659const CElement* CElement::getRoot() const
660{
661 if (!_pParent) {
662
663 return this;
664 }
665 return _pParent->getRoot();
666}
667
668string CElement::getPath() const
669{
670 // Take out root element from the path
671 if (_pParent && _pParent->_pParent) {
672
673 return _pParent->getPath() + "/" + getPathName();
674 }
675 return "/" + getPathName();
676}
677
678string CElement::getQualifiedPath() const
679{
680 return getPath() + " [" + getKind() + "]";
681}
682
683uint32_t CElement::getDepth() const
684{
685 if (_pParent) {
686
687 return _pParent->getDepth() + 1;
688 }
689
690 return 0;
691}
692
693// Checksum for integrity checks
694uint8_t CElement::computeStructureChecksum() const
695{
696 // Base checksum computation on element kind
697 string strKind = getKind();
698
699 // Get element kind
700 const char* pcData = strKind.c_str();
701
702 // Cumulate
703 uint8_t uiChecksum = 0;
704
705 while (*pcData) {
706
707 uiChecksum += *pcData++;
708 }
709
710 // Propagate
711 uint32_t uiIndex;
712 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
713
714 const CElement* pChild = _childArray[uiIndex];
715
716 uiChecksum += pChild->computeStructureChecksum();
717 }
718
719 return uiChecksum;
720}
721
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200722// Utility to underline
723void CElement::appendTitle(string& strTo, const string& strTitle)
724{
725 strTo += "\n" + strTitle + "\n";
726
727 uint32_t uiLength = strTitle.size();
728
729 while (uiLength--) {
730
Patrick Benavoli1387bda2011-08-31 11:23:24 +0200731 strTo += "=";
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200732 }
733 strTo += "\n";
734}