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