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