blob: e5987e1d14d43b425bba588269e259e7df8af885 [file] [log] [blame]
David Wagnerb76c9d62014-02-05 18:30:24 +01001/*
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.
Patrick Benavoli68a91282011-08-31 11:23:23 +020029 */
30#include "Element.h"
Kevin Rocard7f265822012-12-07 18:51:22 +010031#include "XmlElementSerializingContext.h"
32#include "ElementLibrary.h"
33#include "ErrorContext.h"
Patrick Benavoli68a91282011-08-31 11:23:23 +020034#include <assert.h>
35#include <stdio.h>
36#include <stdarg.h>
Guillaume Denneulin2aab8712013-12-03 14:27:41 +010037#include <stdlib.h>
Patrick Benavoli2ecf9002011-08-31 11:23:24 +020038#include <sstream>
Patrick Benavoli68a91282011-08-31 11:23:23 +020039
40CElement::CElement(const string& strName) : _strName(strName), _pParent(NULL)
41{
42}
43
44CElement::~CElement()
45{
46 removeChildren();
47}
48
49// Logging
Kevin Rocardace81f82012-12-11 16:19:17 +010050void CElement::log_info(const string& strMessage, ...) const
Patrick Benavoli68a91282011-08-31 11:23:23 +020051{
Guillaume Denneulin2aab8712013-12-03 14:27:41 +010052 char *pacBuffer;
Patrick Benavoli68a91282011-08-31 11:23:23 +020053 va_list listPointer;
54
55 va_start(listPointer, strMessage);
56
Guillaume Denneulin2aab8712013-12-03 14:27:41 +010057 vasprintf(&pacBuffer, strMessage.c_str(), listPointer);
Patrick Benavoli68a91282011-08-31 11:23:23 +020058
59 va_end(listPointer);
60
Guillaume Denneulin2aab8712013-12-03 14:27:41 +010061 doLog(false, pacBuffer);
62
63 free(pacBuffer);
Patrick Benavoli68a91282011-08-31 11:23:23 +020064}
65
Kevin Rocardace81f82012-12-11 16:19:17 +010066void CElement::log_warning(const string& strMessage, ...) const
67{
Guillaume Denneulin2aab8712013-12-03 14:27:41 +010068 char *pacBuffer;
Kevin Rocardace81f82012-12-11 16:19:17 +010069 va_list listPointer;
70
71 va_start(listPointer, strMessage);
72
Guillaume Denneulin2aab8712013-12-03 14:27:41 +010073 vasprintf(&pacBuffer, strMessage.c_str(), listPointer);
Kevin Rocardace81f82012-12-11 16:19:17 +010074
75 va_end(listPointer);
76
Guillaume Denneulin2aab8712013-12-03 14:27:41 +010077 doLog(true, pacBuffer);
78
79 free(pacBuffer);
Kevin Rocardace81f82012-12-11 16:19:17 +010080}
81
Kevin Rocard36299362013-02-04 14:57:47 +010082// Log each element of the string list
83void CElement::log_table(bool bIsWarning, const list<string> lstrMessage) const
84{
85 list<string>::const_iterator iterator(lstrMessage.begin());
86 list<string>::const_iterator end(lstrMessage.end());
87
88 while (iterator != end) {
89 // Log current list element
90 doLog(bIsWarning, iterator->c_str());
91 ++iterator;
92 }
93}
94
Kevin Rocardace81f82012-12-11 16:19:17 +010095void CElement::doLog(bool bIsWarning, const string& strLog) const
Patrick Benavoli68a91282011-08-31 11:23:23 +020096{
97 assert(_pParent);
98
99 // Propagate till root
Kevin Rocardace81f82012-12-11 16:19:17 +0100100 _pParent->doLog(bIsWarning, strLog);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200101}
102
103void CElement::nestLog() const
104{
105 assert(_pParent);
106
107 // Propagate till root
108 _pParent->nestLog();
109}
110
111void CElement::unnestLog() const
112{
113 assert(_pParent);
114
115 // Propagate till root
116 _pParent->unnestLog();
117}
118
119
120void CElement::setDescription(const string& strDescription)
121{
122 _strDescription = strDescription;
123}
124
125const string& CElement::getDescription() const
126{
127 return _strDescription;
128}
129
130bool CElement::childrenAreDynamic() const
131{
132 // By default, children are searched and not created during xml parsing
133 return false;
134}
135
136bool CElement::init(string& strError)
137{
138 uint32_t uiIndex;
139
140 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
141
142 CElement* pElement = _childArray[uiIndex];;
143
144 if (!pElement->init(strError)) {
145
146 return false;
147 }
148 }
149
150 return true;
151}
152
153void CElement::dumpContent(string& strContent, CErrorContext& errorContext, const uint32_t uiDepth) const
154{
155 string strIndent;
156
157 // Level
158 uint32_t uiNbIndents = uiDepth;
159
160 while (uiNbIndents--) {
161
162 strIndent += " ";
163 }
164 // Type
165 strContent += strIndent + "- " + getKind();
166
167 // Name
168 if (!_strName.empty()) {
169
170 strContent += ": " + getName();
171 }
172
173 // Value
174 string strValue;
175 logValue(strValue, errorContext);
176
177 if (!strValue.empty()) {
178
179 strContent += " = " + strValue;
180 }
181
182 strContent += "\n";
183
184 uint32_t uiIndex;
185
186 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
187
188 _childArray[uiIndex]->dumpContent(strContent, errorContext, uiDepth + 1);
189 }
190}
191
Patrick Benavoli2ecf9002011-08-31 11:23:24 +0200192// Element properties
193void CElement::showProperties(string& strResult) const
194{
195 strResult = "\n";
196 strResult += "Kind: " + getKind() + "\n";
197}
198
199// Conversion utilities
200string CElement::toString(uint32_t uiValue)
201{
202 ostringstream ostr;
203
204 ostr << uiValue;
205
206 return ostr.str();
207}
208
Guillaume Denneulin95331562012-09-27 15:13:10 +0200209string CElement::toString(uint64_t uiValue)
210{
211 ostringstream ostr;
212
213 ostr << uiValue;
214
215 return ostr.str();
216}
217
Patrick Benavoli2ecf9002011-08-31 11:23:24 +0200218string CElement::toString(int32_t iValue)
219{
220 ostringstream ostr;
221
222 ostr << iValue;
223
224 return ostr.str();
225}
226
Patrick Benavoliee65e6d2011-11-20 18:52:24 +0100227string CElement::toString(double dValue)
228{
229 ostringstream ostr;
230
231 ostr << dValue;
232
233 return ostr.str();
234}
235
Patrick Benavoli2ecf9002011-08-31 11:23:24 +0200236// Content dumping
Patrick Benavoli68a91282011-08-31 11:23:23 +0200237void CElement::logValue(string& strValue, CErrorContext& errorContext) const
238{
239 (void)strValue;
240 (void)errorContext;
241}
242
243// From IXmlSink
244bool CElement::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
245{
246 // Propagate through children
247 CXmlElement::CChildIterator childIterator(xmlElement);
248
249 // Context
250 CXmlElementSerializingContext& elementSerializingContext = static_cast<CXmlElementSerializingContext&>(serializingContext);
251
252 CXmlElement childElement;
253
254 while (childIterator.next(childElement)) {
255
256 CElement* pChild;
257
258 if (!childrenAreDynamic()) {
259
260 pChild = findChildOfKind(childElement.getType());
261
262 if (!pChild) {
263
Patrick Benavoli065264a2011-11-20 15:46:41 +0100264 elementSerializingContext.setError("Unable to handle XML element: " + childElement.getPath());
Patrick Benavoli68a91282011-08-31 11:23:23 +0200265
266 return false;
267 }
268
269 } else {
270 // Child needs creation
Guillaume Denneulin3ba083e2014-01-31 15:09:42 +0100271 pChild = createChild(childElement, serializingContext);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200272
Guillaume Denneulin3ba083e2014-01-31 15:09:42 +0100273 if (!pChild) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200274
275 return false;
276 }
277 }
278
279 // Dig
280 if (!pChild->fromXml(childElement, elementSerializingContext)) {
281
282 return false;
283 }
284 }
285
286 return true;
287}
288
289// From IXmlSource
290void CElement::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
291{
292 // Browse children and propagate
293 uint32_t uiNbChildren = getNbChildren();
294 uint32_t uiChild;
295
296 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
297
298 const CElement* pChild = _childArray[uiChild];
299
300 // Create corresponding child element
301 CXmlElement xmlChildElement;
302
303 xmlElement.createChild(xmlChildElement, pChild->getKind());
304
305 // Set attributes
306 pChild->setXmlNameAttribute(xmlChildElement);
307
308
309 // Propagate
310 pChild->toXml(xmlChildElement, serializingContext);
311 }
312}
313
314void CElement::setXmlNameAttribute(CXmlElement& xmlElement) const
315{
316 // By default, set Name attribute if any
317 string strName = getName();
318
319 if (!strName.empty()) {
320
321 xmlElement.setNameAttribute(strName);
322 }
323}
324
325// Name
326void CElement::setName(const string& strName)
327{
328 _strName = strName;
329}
330
331const string& CElement::getName() const
332{
333 return _strName;
334}
335
336bool CElement::rename(const string& strName, string& strError)
337{
338 // Check for conflict with brotherhood if relevant
339 if (_pParent && _pParent->childrenAreDynamic()) {
340
341 uint32_t uiParentChild;
342 uint32_t uiParentNbChildren = _pParent->getNbChildren();
343
344 for (uiParentChild = 0; uiParentChild < uiParentNbChildren; uiParentChild++) {
345
346 const CElement* pParentChild = _pParent->getChild(uiParentChild);
347
348 if (pParentChild != this && pParentChild->getName() == strName) {
349
350 // Conflict
351 strError = "Name conflicts with brother element";
352
353 return false;
354 }
355 }
356 }
357 // Change name
358 setName(strName);
359
360 return true;
361}
362
363string CElement::getPathName() const
364{
365 if (!_strName.empty()) {
366
367 return _strName;
368 } else {
369
370 return getKind();
371 }
372}
373
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200374// Hierarchy
Patrick Benavoli68a91282011-08-31 11:23:23 +0200375void CElement::addChild(CElement* pChild)
376{
377 _childArray.push_back(pChild);
378
379 pChild->_pParent = this;
380}
381
382CElement* CElement::getChild(uint32_t uiIndex)
383{
384 assert(uiIndex <= _childArray.size());
385
386 return _childArray[uiIndex];
387}
388
389const CElement* CElement::getChild(uint32_t uiIndex) const
390{
391 assert(uiIndex <= _childArray.size());
392
393 return _childArray[uiIndex];
394}
395
396CElement* CElement::getLastChild()
397{
398 uint32_t uiNbChildren = getNbChildren();
399
400 assert(uiNbChildren);
401
402 return _childArray[uiNbChildren - 1];
403}
404
Guillaume Denneulin3ba083e2014-01-31 15:09:42 +0100405CElement* CElement::createChild(const CXmlElement& childElement,
406 CXmlSerializingContext& serializingContext)
407{
408 // Context
409 CXmlElementSerializingContext& elementSerializingContext =
410 static_cast<CXmlElementSerializingContext&>(serializingContext);
411
412 // Child needs creation
413 CElement* pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
414
415 if (!pChild) {
416
417 elementSerializingContext.setError(
418 "Unable to create XML element " + childElement.getPath());
419
420 return NULL;
421 }
422 // Store created child!
423 addChild(pChild);
424
425 return pChild;
426}
427
Patrick Benavoli68a91282011-08-31 11:23:23 +0200428bool CElement::removeChild(CElement* pChild)
429{
430 ChildArrayIterator it;
431
432 for (it = _childArray.begin(); it != _childArray.end(); ++it) {
433
434 CElement* pElement = *it;
435
436 if (pElement == pChild) {
437
438 _childArray.erase(it);
439
440 return true;
441 }
442 }
443 return false;
444}
445
446void CElement::listChildren(string& strChildList) const
447{
448 strChildList = "\n";
449
450 // Get list of children names
451 uint32_t uiNbChildren = getNbChildren();
452 uint32_t uiChild;
453
454 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
455
456 const CElement* pChild = _childArray[uiChild];
457
458 strChildList += pChild->getName() + "\n";
459 }
460}
461
462string CElement::listQualifiedPaths(bool bDive, uint32_t uiLevel) const
463{
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200464 uint32_t uiNbChildren = getNbChildren();
465 string strResult;
466
467 // Dive Will cause only leaf nodes to be printed
468 if (!bDive || !uiNbChildren) {
469
470 strResult = getQualifiedPath() + "\n";
471 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200472
473 if (bDive || !uiLevel) {
474 // Get list of children paths
Patrick Benavoli68a91282011-08-31 11:23:23 +0200475 uint32_t uiChild;
476
477 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
478
479 const CElement* pChild = _childArray[uiChild];
480
481 strResult += pChild->listQualifiedPaths(bDive, uiLevel + 1);
482 }
483 }
484 return strResult;
485}
486
487void CElement::listChildrenPaths(string& strChildList) const
488{
Patrick Benavoli68a91282011-08-31 11:23:23 +0200489 // Get list of children paths
490 uint32_t uiNbChildren = getNbChildren();
491 uint32_t uiChild;
492
493 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
494
495 const CElement* pChild = _childArray[uiChild];
496
497 strChildList += pChild->getPath() + "\n";
498 }
499}
500
501uint32_t CElement::getNbChildren() const
502{
503 return _childArray.size();
504}
505
506const CElement* CElement::getParent() const
507{
508 return _pParent;
509}
510
511CElement* CElement::getParent()
512{
513 return _pParent;
514}
515
516void CElement::clean()
517{
518 if (childrenAreDynamic()) {
519
520 removeChildren();
521 } else {
522 // Just propagate
523 uint32_t uiIndex;
524
525 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
526
527 _childArray[uiIndex]->clean();
528 }
529 }
530}
531
532void CElement::removeChildren()
533{
534 // Delete in reverse order
535 ChildArrayReverseIterator it;
536
537 for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
538
539 delete *it;
540 }
541 _childArray.clear();
542}
543
544const CElement* CElement::findDescendant(CPathNavigator& pathNavigator) const
545{
546 string* pStrChildName = pathNavigator.next();
547
548 if (!pStrChildName) {
549
550 return this;
551 }
552
553 const CElement* pChild = findChild(*pStrChildName);
554
555 if (!pChild) {
556
557 return NULL;
558 }
559
560 return pChild->findDescendant(pathNavigator);
561}
562
563CElement* CElement::findDescendant(CPathNavigator& pathNavigator)
564{
565 string* pStrChildName = pathNavigator.next();
566
567 if (!pStrChildName) {
568
569 return this;
570 }
571
572 CElement* pChild = findChild(*pStrChildName);
573
574 if (!pChild) {
575
576 return NULL;
577 }
578
579 return pChild->findDescendant(pathNavigator);
580}
581
582bool CElement::isDescendantOf(const CElement* pCandidateAscendant) const
583{
584 if (!_pParent) {
585
586 return false;
587 }
588 if (_pParent == pCandidateAscendant) {
589
590 return true;
591 }
592 return _pParent->isDescendantOf(pCandidateAscendant);
593}
594
595CElement* CElement::findAscendantOfKind(const string& strKind)
596{
597 if (!_pParent) {
598
599 return NULL;
600 }
601
602 if (_pParent->getKind() == strKind) {
603
604 return _pParent;
605 }
606 return _pParent->findAscendantOfKind(strKind);
607}
608
609CElement* CElement::findChild(const string& strName)
610{
611 uint32_t uiIndex;
612
613 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
614
615 CElement* pElement = _childArray[uiIndex];
616
617 if (pElement->getPathName() == strName) {
618
619 return pElement;
620 }
621 }
622
623 return NULL;
624}
625
626const CElement* CElement::findChild(const string& strName) const
627{
628 uint32_t uiIndex;
629
630 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
631
632 const CElement* pElement = _childArray[uiIndex];
633
634 if (pElement->getPathName() == strName) {
635
636 return pElement;
637 }
638 }
639
640 return NULL;
641}
642
643CElement* CElement::findChildOfKind(const string& strKind)
644{
645 uint32_t uiIndex;
646
647 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
648
649 CElement* pElement = _childArray[uiIndex];
650
651 if (pElement->getKind() == strKind) {
652
653 return pElement;
654 }
655 }
656
657 return NULL;
658}
659
660const CElement* CElement::findChildOfKind(const string& strKind) const
661{
662 uint32_t uiIndex;
663
664 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
665
666 const CElement* pElement = _childArray[uiIndex];;
667
668 if (pElement->getKind() == strKind) {
669
670 return pElement;
671 }
672 }
673
674 return NULL;
675}
676
677CElement* CElement::getRoot()
678{
679 if (!_pParent) {
680
681 return this;
682 }
683 return _pParent->getRoot();
684}
685
686const CElement* CElement::getRoot() const
687{
688 if (!_pParent) {
689
690 return this;
691 }
692 return _pParent->getRoot();
693}
694
695string CElement::getPath() const
696{
697 // Take out root element from the path
698 if (_pParent && _pParent->_pParent) {
699
700 return _pParent->getPath() + "/" + getPathName();
701 }
702 return "/" + getPathName();
703}
704
705string CElement::getQualifiedPath() const
706{
707 return getPath() + " [" + getKind() + "]";
708}
709
710uint32_t CElement::getDepth() const
711{
712 if (_pParent) {
713
714 return _pParent->getDepth() + 1;
715 }
716
717 return 0;
718}
719
720// Checksum for integrity checks
721uint8_t CElement::computeStructureChecksum() const
722{
723 // Base checksum computation on element kind
724 string strKind = getKind();
725
726 // Get element kind
727 const char* pcData = strKind.c_str();
728
729 // Cumulate
730 uint8_t uiChecksum = 0;
731
732 while (*pcData) {
733
734 uiChecksum += *pcData++;
735 }
736
737 // Propagate
738 uint32_t uiIndex;
739 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
740
741 const CElement* pChild = _childArray[uiIndex];
742
743 uiChecksum += pChild->computeStructureChecksum();
744 }
745
746 return uiChecksum;
747}
748
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200749// Utility to underline
750void CElement::appendTitle(string& strTo, const string& strTitle)
751{
752 strTo += "\n" + strTitle + "\n";
753
754 uint32_t uiLength = strTitle.size();
755
756 while (uiLength--) {
757
Patrick Benavoli1387bda2011-08-31 11:23:24 +0200758 strTo += "=";
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200759 }
760 strTo += "\n";
761}