Home | History | Annotate | Download | only in parameter
      1 /*
      2  * Copyright (c) 2011-2015, 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.hpp"
     34 #include <algorithm>
     35 #include <assert.h>
     36 #include <stdio.h>
     37 #include <stdarg.h>
     38 #include <stdlib.h>
     39 
     40 using std::string;
     41 
     42 const std::string CElement::gDescriptionPropertyName = "Description";
     43 
     44 CElement::CElement(const string &strName) : _strName(strName)
     45 {
     46 }
     47 
     48 CElement::~CElement()
     49 {
     50     removeChildren();
     51 }
     52 
     53 void CElement::setDescription(const string &strDescription)
     54 {
     55     _strDescription = strDescription;
     56 }
     57 
     58 const string &CElement::getDescription() const
     59 {
     60     return _strDescription;
     61 }
     62 
     63 bool CElement::childrenAreDynamic() const
     64 {
     65     // By default, children are searched and not created during xml parsing
     66     return false;
     67 }
     68 
     69 bool CElement::init(string &strError)
     70 {
     71 
     72     for (CElement *child : _childArray) {
     73 
     74         if (!child->init(strError)) {
     75 
     76             return false;
     77         }
     78     }
     79 
     80     return true;
     81 }
     82 
     83 string CElement::dumpContent(utility::ErrorContext &errorContext, const size_t depth) const
     84 {
     85     string output;
     86     string strIndent;
     87 
     88     // Level
     89     size_t indents = depth;
     90 
     91     while (indents--) {
     92 
     93         strIndent += "    ";
     94     }
     95     // Type
     96     output += strIndent + "- " + getKind();
     97 
     98     // Name
     99     if (!_strName.empty()) {
    100 
    101         output += ": " + getName();
    102     }
    103 
    104     // Value
    105     string strValue = logValue(errorContext);
    106 
    107     if (!strValue.empty()) {
    108 
    109         output += " = " + strValue;
    110     }
    111 
    112     output += "\n";
    113 
    114     for (CElement *pChild : _childArray) {
    115 
    116         output += pChild->dumpContent(errorContext, depth + 1);
    117     }
    118 
    119     return output;
    120 }
    121 
    122 // Element properties
    123 void CElement::showProperties(string &strResult) const
    124 {
    125     strResult += "Kind: " + getKind() + "\n";
    126     showDescriptionProperty(strResult);
    127 }
    128 
    129 void CElement::showDescriptionProperty(std::string &strResult) const
    130 {
    131     if (!getDescription().empty()) {
    132         strResult += gDescriptionPropertyName + ": " + getDescription() + "\n";
    133     }
    134 }
    135 
    136 // Content dumping
    137 string CElement::logValue(utility::ErrorContext & /*ctx*/) const
    138 {
    139     return "";
    140 }
    141 
    142 // From IXmlSink
    143 bool CElement::fromXml(const CXmlElement &xmlElement, CXmlSerializingContext &serializingContext)
    144 {
    145     xmlElement.getAttribute(gDescriptionPropertyName, _strDescription);
    146 
    147     // Propagate through children
    148     CXmlElement::CChildIterator childIterator(xmlElement);
    149 
    150     CXmlElement childElement;
    151 
    152     while (childIterator.next(childElement)) {
    153 
    154         CElement *pChild;
    155 
    156         if (!childrenAreDynamic()) {
    157 
    158             pChild = findChildOfKind(childElement.getType());
    159 
    160             if (!pChild) {
    161 
    162                 serializingContext.setError("Unable to handle XML element: " +
    163                                             childElement.getPath());
    164 
    165                 return false;
    166             }
    167 
    168         } else {
    169             // Child needs creation
    170             pChild = createChild(childElement, serializingContext);
    171 
    172             if (!pChild) {
    173 
    174                 return false;
    175             }
    176         }
    177 
    178         // Dig
    179         if (!pChild->fromXml(childElement, serializingContext)) {
    180 
    181             return false;
    182         }
    183     }
    184 
    185     return true;
    186 }
    187 
    188 void CElement::childrenToXml(CXmlElement &xmlElement,
    189                              CXmlSerializingContext &serializingContext) const
    190 {
    191     // Browse children and propagate
    192     for (CElement *pChild : _childArray) {
    193 
    194         // Create corresponding child element
    195         CXmlElement xmlChildElement;
    196 
    197         xmlElement.createChild(xmlChildElement, pChild->getXmlElementName());
    198 
    199         // Propagate
    200         pChild->toXml(xmlChildElement, serializingContext);
    201     }
    202 }
    203 
    204 void CElement::toXml(CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) const
    205 {
    206     setXmlNameAttribute(xmlElement);
    207     setXmlDescriptionAttribute(xmlElement);
    208     childrenToXml(xmlElement, serializingContext);
    209 }
    210 
    211 void CElement::setXmlDescriptionAttribute(CXmlElement &xmlElement) const
    212 {
    213     const string &description = getDescription();
    214     if (!description.empty()) {
    215         xmlElement.setAttribute(gDescriptionPropertyName, description);
    216     }
    217 }
    218 
    219 void CElement::setXmlNameAttribute(CXmlElement &xmlElement) const
    220 {
    221     // By default, set Name attribute if any
    222     string strName = getName();
    223 
    224     if (!strName.empty()) {
    225 
    226         xmlElement.setNameAttribute(strName);
    227     }
    228 }
    229 
    230 // Name
    231 void CElement::setName(const string &strName)
    232 {
    233     _strName = strName;
    234 }
    235 
    236 const string &CElement::getName() const
    237 {
    238     return _strName;
    239 }
    240 
    241 bool CElement::rename(const string &strName, string &strError)
    242 {
    243     // Check for conflict with brotherhood if relevant
    244     if (_pParent && _pParent->childrenAreDynamic()) {
    245 
    246         for (CElement *pParentChild : _pParent->_childArray) {
    247 
    248             if (pParentChild != this && pParentChild->getName() == strName) {
    249 
    250                 // Conflict
    251                 strError = "Name conflicts with brother element";
    252 
    253                 return false;
    254             }
    255         }
    256     }
    257     // Change name
    258     setName(strName);
    259 
    260     return true;
    261 }
    262 
    263 string CElement::getPathName() const
    264 {
    265     if (!_strName.empty()) {
    266 
    267         return _strName;
    268     } else {
    269 
    270         return getKind();
    271     }
    272 }
    273 
    274 // Hierarchy
    275 void CElement::addChild(CElement *pChild)
    276 {
    277     _childArray.push_back(pChild);
    278 
    279     pChild->_pParent = this;
    280 }
    281 
    282 CElement *CElement::getChild(size_t index)
    283 {
    284     assert(index <= _childArray.size());
    285 
    286     return _childArray[index];
    287 }
    288 
    289 const CElement *CElement::getChild(size_t index) const
    290 {
    291     assert(index <= _childArray.size());
    292 
    293     return _childArray[index];
    294 }
    295 
    296 CElement *CElement::createChild(const CXmlElement &childElement,
    297                                 CXmlSerializingContext &serializingContext)
    298 {
    299     // Context
    300     CXmlElementSerializingContext &elementSerializingContext =
    301         static_cast<CXmlElementSerializingContext &>(serializingContext);
    302 
    303     // Child needs creation
    304     CElement *pChild = elementSerializingContext.getElementLibrary()->createElement(childElement);
    305 
    306     if (!pChild) {
    307 
    308         elementSerializingContext.setError("Unable to create XML element " +
    309                                            childElement.getPath());
    310 
    311         return NULL;
    312     }
    313     // Store created child!
    314     addChild(pChild);
    315 
    316     return pChild;
    317 }
    318 
    319 bool CElement::removeChild(CElement *pChild)
    320 {
    321     auto childIt = find(begin(_childArray), end(_childArray), pChild);
    322     if (childIt != end(_childArray)) {
    323 
    324         _childArray.erase(childIt);
    325         return true;
    326     }
    327     return false;
    328 }
    329 
    330 void CElement::listChildren(string &strChildList) const
    331 {
    332     // Get list of children names
    333     for (CElement *pChild : _childArray) {
    334 
    335         strChildList += pChild->getName() + "\n";
    336     }
    337 }
    338 
    339 string CElement::listQualifiedPaths(bool bDive, size_t level) const
    340 {
    341     string strResult;
    342 
    343     // Dive Will cause only leaf nodes to be printed
    344     if (!bDive || !getNbChildren()) {
    345 
    346         strResult = getQualifiedPath() + "\n";
    347     }
    348 
    349     if (bDive || !level) {
    350         // Get list of children paths
    351         for (CElement *pChild : _childArray) {
    352 
    353             strResult += pChild->listQualifiedPaths(bDive, level + 1);
    354         }
    355     }
    356     return strResult;
    357 }
    358 
    359 void CElement::listChildrenPaths(string &strChildList) const
    360 {
    361     // Get list of children paths
    362     for (CElement *pChild : _childArray) {
    363 
    364         strChildList += pChild->getPath() + "\n";
    365     }
    366 }
    367 
    368 size_t CElement::getNbChildren() const
    369 {
    370     return _childArray.size();
    371 }
    372 
    373 const CElement *CElement::getParent() const
    374 {
    375     return _pParent;
    376 }
    377 
    378 CElement *CElement::getParent()
    379 {
    380     return _pParent;
    381 }
    382 
    383 void CElement::clean()
    384 {
    385     if (childrenAreDynamic()) {
    386 
    387         removeChildren();
    388     } else {
    389         // Just propagate
    390         for (CElement *pChild : _childArray) {
    391 
    392             pChild->clean();
    393         }
    394     }
    395 }
    396 
    397 void CElement::removeChildren()
    398 {
    399     // Delete in reverse order
    400     ChildArrayReverseIterator it;
    401 
    402     for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) {
    403 
    404         delete *it;
    405     }
    406     _childArray.clear();
    407 }
    408 
    409 const CElement *CElement::findDescendant(CPathNavigator &pathNavigator) const
    410 {
    411     string *pStrChildName = pathNavigator.next();
    412 
    413     if (!pStrChildName) {
    414 
    415         return this;
    416     }
    417 
    418     const CElement *pChild = findChild(*pStrChildName);
    419 
    420     if (!pChild) {
    421 
    422         return NULL;
    423     }
    424 
    425     return pChild->findDescendant(pathNavigator);
    426 }
    427 
    428 CElement *CElement::findDescendant(CPathNavigator &pathNavigator)
    429 {
    430     string *pStrChildName = pathNavigator.next();
    431 
    432     if (!pStrChildName) {
    433 
    434         return this;
    435     }
    436 
    437     CElement *pChild = findChild(*pStrChildName);
    438 
    439     if (!pChild) {
    440 
    441         return NULL;
    442     }
    443 
    444     return pChild->findDescendant(pathNavigator);
    445 }
    446 
    447 bool CElement::isDescendantOf(const CElement *pCandidateAscendant) const
    448 {
    449     if (!_pParent) {
    450 
    451         return false;
    452     }
    453     if (_pParent == pCandidateAscendant) {
    454 
    455         return true;
    456     }
    457     return _pParent->isDescendantOf(pCandidateAscendant);
    458 }
    459 
    460 CElement *CElement::findChild(const string &strName)
    461 {
    462     for (CElement *pChild : _childArray) {
    463 
    464         if (pChild->getPathName() == strName) {
    465 
    466             return pChild;
    467         }
    468     }
    469 
    470     return NULL;
    471 }
    472 
    473 const CElement *CElement::findChild(const string &strName) const
    474 {
    475     for (CElement *pChild : _childArray) {
    476 
    477         if (pChild->getPathName() == strName) {
    478 
    479             return pChild;
    480         }
    481     }
    482 
    483     return NULL;
    484 }
    485 
    486 CElement *CElement::findChildOfKind(const string &strKind)
    487 {
    488     for (CElement *pChild : _childArray) {
    489 
    490         if (pChild->getKind() == strKind) {
    491 
    492             return pChild;
    493         }
    494     }
    495 
    496     return NULL;
    497 }
    498 
    499 const CElement *CElement::findChildOfKind(const string &strKind) const
    500 {
    501     for (CElement *pChild : _childArray) {
    502 
    503         if (pChild->getKind() == strKind) {
    504 
    505             return pChild;
    506         }
    507     }
    508 
    509     return NULL;
    510 }
    511 
    512 string CElement::getPath() const
    513 {
    514     // Take out root element from the path
    515     if (_pParent && _pParent->_pParent) {
    516 
    517         return _pParent->getPath() + "/" + getPathName();
    518     }
    519     return "/" + getPathName();
    520 }
    521 
    522 string CElement::getQualifiedPath() const
    523 {
    524     return getPath() + " [" + getKind() + "]";
    525 }
    526 
    527 string CElement::getXmlElementName() const
    528 {
    529     // Default to element kind
    530     return getKind();
    531 }
    532