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