blob: 2c8393d00c5b8cf2782ccea7abd841e615663679 [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
295// From IXmlSource
296void CElement::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
297{
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
311 // Set attributes
312 pChild->setXmlNameAttribute(xmlChildElement);
313
314
315 // Propagate
316 pChild->toXml(xmlChildElement, serializingContext);
317 }
318}
319
320void CElement::setXmlNameAttribute(CXmlElement& xmlElement) const
321{
322 // By default, set Name attribute if any
323 string strName = getName();
324
325 if (!strName.empty()) {
326
327 xmlElement.setNameAttribute(strName);
328 }
329}
330
331// Name
332void CElement::setName(const string& strName)
333{
334 _strName = strName;
335}
336
337const string& CElement::getName() const
338{
339 return _strName;
340}
341
342bool CElement::rename(const string& strName, string& strError)
343{
344 // Check for conflict with brotherhood if relevant
345 if (_pParent && _pParent->childrenAreDynamic()) {
346
347 uint32_t uiParentChild;
348 uint32_t uiParentNbChildren = _pParent->getNbChildren();
349
350 for (uiParentChild = 0; uiParentChild < uiParentNbChildren; uiParentChild++) {
351
352 const CElement* pParentChild = _pParent->getChild(uiParentChild);
353
354 if (pParentChild != this && pParentChild->getName() == strName) {
355
356 // Conflict
357 strError = "Name conflicts with brother element";
358
359 return false;
360 }
361 }
362 }
363 // Change name
364 setName(strName);
365
366 return true;
367}
368
369string CElement::getPathName() const
370{
371 if (!_strName.empty()) {
372
373 return _strName;
374 } else {
375
376 return getKind();
377 }
378}
379
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200380// Hierarchy
Patrick Benavoli68a91282011-08-31 11:23:23 +0200381void CElement::addChild(CElement* pChild)
382{
383 _childArray.push_back(pChild);
384
385 pChild->_pParent = this;
386}
387
388CElement* CElement::getChild(uint32_t uiIndex)
389{
390 assert(uiIndex <= _childArray.size());
391
392 return _childArray[uiIndex];
393}
394
395const CElement* CElement::getChild(uint32_t uiIndex) const
396{
397 assert(uiIndex <= _childArray.size());
398
399 return _childArray[uiIndex];
400}
401
402CElement* CElement::getLastChild()
403{
404 uint32_t uiNbChildren = getNbChildren();
405
406 assert(uiNbChildren);
407
408 return _childArray[uiNbChildren - 1];
409}
410
Guillaume Denneulin3ba083e2014-01-31 15:09:42 +0100411CElement* CElement::createChild(const CXmlElement& childElement,
412 CXmlSerializingContext& serializingContext)
413{
414 // Context
415 CXmlElementSerializingContext& elementSerializingContext =
416 static_cast<CXmlElementSerializingContext&>(serializingContext);
417
418 // Child needs creation
419 CElement* pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
420
421 if (!pChild) {
422
423 elementSerializingContext.setError(
424 "Unable to create XML element " + childElement.getPath());
425
426 return NULL;
427 }
428 // Store created child!
429 addChild(pChild);
430
431 return pChild;
432}
433
Patrick Benavoli68a91282011-08-31 11:23:23 +0200434bool CElement::removeChild(CElement* pChild)
435{
436 ChildArrayIterator it;
437
438 for (it = _childArray.begin(); it != _childArray.end(); ++it) {
439
440 CElement* pElement = *it;
441
442 if (pElement == pChild) {
443
444 _childArray.erase(it);
445
446 return true;
447 }
448 }
449 return false;
450}
451
452void CElement::listChildren(string& strChildList) const
453{
454 strChildList = "\n";
455
456 // Get list of children names
457 uint32_t uiNbChildren = getNbChildren();
458 uint32_t uiChild;
459
460 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
461
462 const CElement* pChild = _childArray[uiChild];
463
464 strChildList += pChild->getName() + "\n";
465 }
466}
467
468string CElement::listQualifiedPaths(bool bDive, uint32_t uiLevel) const
469{
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200470 uint32_t uiNbChildren = getNbChildren();
471 string strResult;
472
473 // Dive Will cause only leaf nodes to be printed
474 if (!bDive || !uiNbChildren) {
475
476 strResult = getQualifiedPath() + "\n";
477 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200478
479 if (bDive || !uiLevel) {
480 // Get list of children paths
Patrick Benavoli68a91282011-08-31 11:23:23 +0200481 uint32_t uiChild;
482
483 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
484
485 const CElement* pChild = _childArray[uiChild];
486
487 strResult += pChild->listQualifiedPaths(bDive, uiLevel + 1);
488 }
489 }
490 return strResult;
491}
492
493void CElement::listChildrenPaths(string& strChildList) const
494{
Patrick Benavoli68a91282011-08-31 11:23:23 +0200495 // Get list of children paths
496 uint32_t uiNbChildren = getNbChildren();
497 uint32_t uiChild;
498
499 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
500
501 const CElement* pChild = _childArray[uiChild];
502
503 strChildList += pChild->getPath() + "\n";
504 }
505}
506
507uint32_t CElement::getNbChildren() const
508{
509 return _childArray.size();
510}
511
512const CElement* CElement::getParent() const
513{
514 return _pParent;
515}
516
517CElement* CElement::getParent()
518{
519 return _pParent;
520}
521
522void CElement::clean()
523{
524 if (childrenAreDynamic()) {
525
526 removeChildren();
527 } else {
528 // Just propagate
529 uint32_t uiIndex;
530
531 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
532
533 _childArray[uiIndex]->clean();
534 }
535 }
536}
537
538void CElement::removeChildren()
539{
540 // Delete in reverse order
541 ChildArrayReverseIterator it;
542
543 for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
544
545 delete *it;
546 }
547 _childArray.clear();
548}
549
550const CElement* CElement::findDescendant(CPathNavigator& pathNavigator) const
551{
552 string* pStrChildName = pathNavigator.next();
553
554 if (!pStrChildName) {
555
556 return this;
557 }
558
559 const CElement* pChild = findChild(*pStrChildName);
560
561 if (!pChild) {
562
563 return NULL;
564 }
565
566 return pChild->findDescendant(pathNavigator);
567}
568
569CElement* CElement::findDescendant(CPathNavigator& pathNavigator)
570{
571 string* pStrChildName = pathNavigator.next();
572
573 if (!pStrChildName) {
574
575 return this;
576 }
577
578 CElement* pChild = findChild(*pStrChildName);
579
580 if (!pChild) {
581
582 return NULL;
583 }
584
585 return pChild->findDescendant(pathNavigator);
586}
587
588bool CElement::isDescendantOf(const CElement* pCandidateAscendant) const
589{
590 if (!_pParent) {
591
592 return false;
593 }
594 if (_pParent == pCandidateAscendant) {
595
596 return true;
597 }
598 return _pParent->isDescendantOf(pCandidateAscendant);
599}
600
601CElement* CElement::findAscendantOfKind(const string& strKind)
602{
603 if (!_pParent) {
604
605 return NULL;
606 }
607
608 if (_pParent->getKind() == strKind) {
609
610 return _pParent;
611 }
612 return _pParent->findAscendantOfKind(strKind);
613}
614
615CElement* CElement::findChild(const string& strName)
616{
617 uint32_t uiIndex;
618
619 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
620
621 CElement* pElement = _childArray[uiIndex];
622
623 if (pElement->getPathName() == strName) {
624
625 return pElement;
626 }
627 }
628
629 return NULL;
630}
631
632const CElement* CElement::findChild(const string& strName) const
633{
634 uint32_t uiIndex;
635
636 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
637
638 const CElement* pElement = _childArray[uiIndex];
639
640 if (pElement->getPathName() == strName) {
641
642 return pElement;
643 }
644 }
645
646 return NULL;
647}
648
649CElement* CElement::findChildOfKind(const string& strKind)
650{
651 uint32_t uiIndex;
652
653 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
654
655 CElement* pElement = _childArray[uiIndex];
656
657 if (pElement->getKind() == strKind) {
658
659 return pElement;
660 }
661 }
662
663 return NULL;
664}
665
666const CElement* CElement::findChildOfKind(const string& strKind) const
667{
668 uint32_t uiIndex;
669
670 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
671
672 const CElement* pElement = _childArray[uiIndex];;
673
674 if (pElement->getKind() == strKind) {
675
676 return pElement;
677 }
678 }
679
680 return NULL;
681}
682
683CElement* CElement::getRoot()
684{
685 if (!_pParent) {
686
687 return this;
688 }
689 return _pParent->getRoot();
690}
691
692const CElement* CElement::getRoot() const
693{
694 if (!_pParent) {
695
696 return this;
697 }
698 return _pParent->getRoot();
699}
700
701string CElement::getPath() const
702{
703 // Take out root element from the path
704 if (_pParent && _pParent->_pParent) {
705
706 return _pParent->getPath() + "/" + getPathName();
707 }
708 return "/" + getPathName();
709}
710
711string CElement::getQualifiedPath() const
712{
713 return getPath() + " [" + getKind() + "]";
714}
715
716uint32_t CElement::getDepth() const
717{
718 if (_pParent) {
719
720 return _pParent->getDepth() + 1;
721 }
722
723 return 0;
724}
725
726// Checksum for integrity checks
727uint8_t CElement::computeStructureChecksum() const
728{
729 // Base checksum computation on element kind
730 string strKind = getKind();
731
732 // Get element kind
733 const char* pcData = strKind.c_str();
734
735 // Cumulate
736 uint8_t uiChecksum = 0;
737
738 while (*pcData) {
739
740 uiChecksum += *pcData++;
741 }
742
743 // Propagate
744 uint32_t uiIndex;
745 for (uiIndex = 0; uiIndex < _childArray.size(); uiIndex++) {
746
747 const CElement* pChild = _childArray[uiIndex];
748
749 uiChecksum += pChild->computeStructureChecksum();
750 }
751
752 return uiChecksum;
753}
754
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200755// Utility to underline
756void CElement::appendTitle(string& strTo, const string& strTitle)
757{
758 strTo += "\n" + strTitle + "\n";
759
760 uint32_t uiLength = strTitle.size();
761
762 while (uiLength--) {
763
Patrick Benavoli1387bda2011-08-31 11:23:24 +0200764 strTo += "=";
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200765 }
766 strTo += "\n";
767}