| /* |
| * Copyright (c) 2011-2015, Intel Corporation |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, this |
| * list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation and/or |
| * other materials provided with the distribution. |
| * |
| * 3. Neither the name of the copyright holder nor the names of its contributors |
| * may be used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| #include "Element.h" |
| #include "XmlElementSerializingContext.h" |
| #include "ElementLibrary.h" |
| #include "ErrorContext.hpp" |
| #include <algorithm> |
| #include <assert.h> |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| |
| using std::string; |
| |
| const std::string CElement::gDescriptionPropertyName = "Description"; |
| |
| CElement::CElement(const string &strName) : _strName(strName) |
| { |
| } |
| |
| CElement::~CElement() |
| { |
| removeChildren(); |
| } |
| |
| void CElement::setDescription(const string &strDescription) |
| { |
| _strDescription = strDescription; |
| } |
| |
| const string &CElement::getDescription() const |
| { |
| return _strDescription; |
| } |
| |
| bool CElement::childrenAreDynamic() const |
| { |
| // By default, children are searched and not created during xml parsing |
| return false; |
| } |
| |
| bool CElement::init(string &strError) |
| { |
| |
| for (CElement *child : _childArray) { |
| |
| if (!child->init(strError)) { |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| string CElement::dumpContent(utility::ErrorContext &errorContext, const size_t depth) const |
| { |
| string output; |
| string strIndent; |
| |
| // Level |
| size_t indents = depth; |
| |
| while (indents--) { |
| |
| strIndent += " "; |
| } |
| // Type |
| output += strIndent + "- " + getKind(); |
| |
| // Name |
| if (!_strName.empty()) { |
| |
| output += ": " + getName(); |
| } |
| |
| // Value |
| string strValue = logValue(errorContext); |
| |
| if (!strValue.empty()) { |
| |
| output += " = " + strValue; |
| } |
| |
| output += "\n"; |
| |
| for (CElement *pChild : _childArray) { |
| |
| output += pChild->dumpContent(errorContext, depth + 1); |
| } |
| |
| return output; |
| } |
| |
| // Element properties |
| void CElement::showProperties(string &strResult) const |
| { |
| strResult += "Kind: " + getKind() + "\n"; |
| showDescriptionProperty(strResult); |
| } |
| |
| void CElement::showDescriptionProperty(std::string &strResult) const |
| { |
| if (!getDescription().empty()) { |
| strResult += gDescriptionPropertyName + ": " + getDescription() + "\n"; |
| } |
| } |
| |
| // Content dumping |
| string CElement::logValue(utility::ErrorContext & /*ctx*/) const |
| { |
| return ""; |
| } |
| |
| // From IXmlSink |
| bool CElement::fromXml(const CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) |
| { |
| xmlElement.getAttribute(gDescriptionPropertyName, _strDescription); |
| |
| // Propagate through children |
| CXmlElement::CChildIterator childIterator(xmlElement); |
| |
| CXmlElement childElement; |
| |
| while (childIterator.next(childElement)) { |
| |
| CElement *pChild; |
| |
| if (!childrenAreDynamic()) { |
| |
| pChild = findChildOfKind(childElement.getType()); |
| |
| if (!pChild) { |
| |
| serializingContext.setError("Unable to handle XML element: " + |
| childElement.getPath()); |
| |
| return false; |
| } |
| |
| } else { |
| // Child needs creation |
| pChild = createChild(childElement, serializingContext); |
| |
| if (!pChild) { |
| |
| return false; |
| } |
| } |
| |
| // Dig |
| if (!pChild->fromXml(childElement, serializingContext)) { |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| void CElement::childrenToXml(CXmlElement &xmlElement, |
| CXmlSerializingContext &serializingContext) const |
| { |
| // Browse children and propagate |
| for (CElement *pChild : _childArray) { |
| |
| // Create corresponding child element |
| CXmlElement xmlChildElement; |
| |
| xmlElement.createChild(xmlChildElement, pChild->getXmlElementName()); |
| |
| // Propagate |
| pChild->toXml(xmlChildElement, serializingContext); |
| } |
| } |
| |
| void CElement::toXml(CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) const |
| { |
| setXmlNameAttribute(xmlElement); |
| setXmlDescriptionAttribute(xmlElement); |
| childrenToXml(xmlElement, serializingContext); |
| } |
| |
| void CElement::setXmlDescriptionAttribute(CXmlElement &xmlElement) const |
| { |
| const string &description = getDescription(); |
| if (!description.empty()) { |
| xmlElement.setAttribute(gDescriptionPropertyName, description); |
| } |
| } |
| |
| void CElement::setXmlNameAttribute(CXmlElement &xmlElement) const |
| { |
| // By default, set Name attribute if any |
| string strName = getName(); |
| |
| if (!strName.empty()) { |
| |
| xmlElement.setNameAttribute(strName); |
| } |
| } |
| |
| // Name |
| void CElement::setName(const string &strName) |
| { |
| _strName = strName; |
| } |
| |
| const string &CElement::getName() const |
| { |
| return _strName; |
| } |
| |
| bool CElement::rename(const string &strName, string &strError) |
| { |
| // Check for conflict with brotherhood if relevant |
| if (_pParent && _pParent->childrenAreDynamic()) { |
| |
| for (CElement *pParentChild : _pParent->_childArray) { |
| |
| if (pParentChild != this && pParentChild->getName() == strName) { |
| |
| // Conflict |
| strError = "Name conflicts with brother element"; |
| |
| return false; |
| } |
| } |
| } |
| // Change name |
| setName(strName); |
| |
| return true; |
| } |
| |
| string CElement::getPathName() const |
| { |
| if (!_strName.empty()) { |
| |
| return _strName; |
| } else { |
| |
| return getKind(); |
| } |
| } |
| |
| // Hierarchy |
| void CElement::addChild(CElement *pChild) |
| { |
| _childArray.push_back(pChild); |
| |
| pChild->_pParent = this; |
| } |
| |
| CElement *CElement::getChild(size_t index) |
| { |
| assert(index <= _childArray.size()); |
| |
| return _childArray[index]; |
| } |
| |
| const CElement *CElement::getChild(size_t index) const |
| { |
| assert(index <= _childArray.size()); |
| |
| return _childArray[index]; |
| } |
| |
| CElement *CElement::createChild(const CXmlElement &childElement, |
| CXmlSerializingContext &serializingContext) |
| { |
| // Context |
| CXmlElementSerializingContext &elementSerializingContext = |
| static_cast<CXmlElementSerializingContext &>(serializingContext); |
| |
| // Child needs creation |
| CElement *pChild = elementSerializingContext.getElementLibrary()->createElement(childElement); |
| |
| if (!pChild) { |
| |
| elementSerializingContext.setError("Unable to create XML element " + |
| childElement.getPath()); |
| |
| return NULL; |
| } |
| // Store created child! |
| addChild(pChild); |
| |
| return pChild; |
| } |
| |
| bool CElement::removeChild(CElement *pChild) |
| { |
| auto childIt = find(begin(_childArray), end(_childArray), pChild); |
| if (childIt != end(_childArray)) { |
| |
| _childArray.erase(childIt); |
| return true; |
| } |
| return false; |
| } |
| |
| void CElement::listChildren(string &strChildList) const |
| { |
| // Get list of children names |
| for (CElement *pChild : _childArray) { |
| |
| strChildList += pChild->getName() + "\n"; |
| } |
| } |
| |
| string CElement::listQualifiedPaths(bool bDive, size_t level) const |
| { |
| string strResult; |
| |
| // Dive Will cause only leaf nodes to be printed |
| if (!bDive || !getNbChildren()) { |
| |
| strResult = getQualifiedPath() + "\n"; |
| } |
| |
| if (bDive || !level) { |
| // Get list of children paths |
| for (CElement *pChild : _childArray) { |
| |
| strResult += pChild->listQualifiedPaths(bDive, level + 1); |
| } |
| } |
| return strResult; |
| } |
| |
| void CElement::listChildrenPaths(string &strChildList) const |
| { |
| // Get list of children paths |
| for (CElement *pChild : _childArray) { |
| |
| strChildList += pChild->getPath() + "\n"; |
| } |
| } |
| |
| size_t CElement::getNbChildren() const |
| { |
| return _childArray.size(); |
| } |
| |
| const CElement *CElement::getParent() const |
| { |
| return _pParent; |
| } |
| |
| CElement *CElement::getParent() |
| { |
| return _pParent; |
| } |
| |
| void CElement::clean() |
| { |
| if (childrenAreDynamic()) { |
| |
| removeChildren(); |
| } else { |
| // Just propagate |
| for (CElement *pChild : _childArray) { |
| |
| pChild->clean(); |
| } |
| } |
| } |
| |
| void CElement::removeChildren() |
| { |
| // Delete in reverse order |
| ChildArrayReverseIterator it; |
| |
| for (it = _childArray.rbegin(); it != _childArray.rend(); ++it) { |
| |
| delete *it; |
| } |
| _childArray.clear(); |
| } |
| |
| const CElement *CElement::findDescendant(CPathNavigator &pathNavigator) const |
| { |
| string *pStrChildName = pathNavigator.next(); |
| |
| if (!pStrChildName) { |
| |
| return this; |
| } |
| |
| const CElement *pChild = findChild(*pStrChildName); |
| |
| if (!pChild) { |
| |
| return NULL; |
| } |
| |
| return pChild->findDescendant(pathNavigator); |
| } |
| |
| CElement *CElement::findDescendant(CPathNavigator &pathNavigator) |
| { |
| string *pStrChildName = pathNavigator.next(); |
| |
| if (!pStrChildName) { |
| |
| return this; |
| } |
| |
| CElement *pChild = findChild(*pStrChildName); |
| |
| if (!pChild) { |
| |
| return NULL; |
| } |
| |
| return pChild->findDescendant(pathNavigator); |
| } |
| |
| bool CElement::isDescendantOf(const CElement *pCandidateAscendant) const |
| { |
| if (!_pParent) { |
| |
| return false; |
| } |
| if (_pParent == pCandidateAscendant) { |
| |
| return true; |
| } |
| return _pParent->isDescendantOf(pCandidateAscendant); |
| } |
| |
| CElement *CElement::findChild(const string &strName) |
| { |
| for (CElement *pChild : _childArray) { |
| |
| if (pChild->getPathName() == strName) { |
| |
| return pChild; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const CElement *CElement::findChild(const string &strName) const |
| { |
| for (CElement *pChild : _childArray) { |
| |
| if (pChild->getPathName() == strName) { |
| |
| return pChild; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| CElement *CElement::findChildOfKind(const string &strKind) |
| { |
| for (CElement *pChild : _childArray) { |
| |
| if (pChild->getKind() == strKind) { |
| |
| return pChild; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const CElement *CElement::findChildOfKind(const string &strKind) const |
| { |
| for (CElement *pChild : _childArray) { |
| |
| if (pChild->getKind() == strKind) { |
| |
| return pChild; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| string CElement::getPath() const |
| { |
| // Take out root element from the path |
| if (_pParent && _pParent->_pParent) { |
| |
| return _pParent->getPath() + "/" + getPathName(); |
| } |
| return "/" + getPathName(); |
| } |
| |
| string CElement::getQualifiedPath() const |
| { |
| return getPath() + " [" + getKind() + "]"; |
| } |
| |
| string CElement::getXmlElementName() const |
| { |
| // Default to element kind |
| return getKind(); |
| } |