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