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