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