1 /* 2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <package/PackageInfo.h> 8 9 #include <ctype.h> 10 #include <stdlib.h> 11 #include <string.h> 12 13 #include <new> 14 15 #include <File.h> 16 #include <Entry.h> 17 18 19 namespace BPackageKit { 20 21 22 namespace { 23 24 25 enum TokenType { 26 TOKEN_WORD, 27 TOKEN_QUOTED_STRING, 28 TOKEN_OPERATOR_ASSIGN, 29 TOKEN_OPERATOR_LESS, 30 TOKEN_OPERATOR_LESS_EQUAL, 31 TOKEN_OPERATOR_EQUAL, 32 TOKEN_OPERATOR_NOT_EQUAL, 33 TOKEN_OPERATOR_GREATER_EQUAL, 34 TOKEN_OPERATOR_GREATER, 35 TOKEN_OPEN_BRACE, 36 TOKEN_CLOSE_BRACE, 37 TOKEN_ITEM_SEPARATOR, 38 // 39 TOKEN_EOF, 40 }; 41 42 43 struct ParseError { 44 BString message; 45 const char* pos; 46 47 ParseError(const BString& _message, const char* _pos) 48 : message(_message), pos(_pos) 49 { 50 } 51 }; 52 53 54 } // anonymous namespace 55 56 57 /* 58 * Parses a ".PackageInfo" file and fills a BPackageInfo object with the 59 * package info elements found. 60 */ 61 class BPackageInfo::Parser { 62 public: 63 Parser(ParseErrorListener* listener = NULL); 64 65 status_t Parse(const BString& packageInfoString, 66 BPackageInfo* packageInfo); 67 68 private: 69 struct Token; 70 struct ListElementParser; 71 friend struct ListElementParser; 72 73 Token _NextToken(); 74 void _RewindTo(const Token& token); 75 76 void _ParseStringValue(BString* value); 77 uint32 _ParseFlags(); 78 void _ParseArchitectureValue( 79 BPackageArchitecture* value); 80 void _ParseVersionValue(BPackageVersion* value, 81 bool releaseIsOptional); 82 void _ParseList(ListElementParser& elementParser, 83 bool allowSingleNonListElement); 84 void _ParseStringList(BStringList* value, 85 bool allowQuotedStrings = true, 86 bool convertToLowerCase = false); 87 void _ParseResolvableList( 88 BObjectList<BPackageResolvable>* value); 89 void _ParseResolvableExprList( 90 BObjectList<BPackageResolvableExpression>* 91 value); 92 93 void _Parse(BPackageInfo* packageInfo); 94 95 private: 96 ParseErrorListener* fListener; 97 const char* fPos; 98 }; 99 100 101 struct BPackageInfo::Parser::Token { 102 TokenType type; 103 BString text; 104 const char* pos; 105 106 Token(TokenType _type, const char* _pos, int length = 0) 107 : type(_type), pos(_pos) 108 { 109 if (length != 0) { 110 text.SetTo(pos, length); 111 112 if (type == TOKEN_QUOTED_STRING) { 113 // unescape value of quoted string 114 char* value = text.LockBuffer(length); 115 if (value == NULL) 116 return; 117 int index = 0; 118 int newIndex = 0; 119 bool lastWasEscape = false; 120 while (char c = value[index++]) { 121 if (lastWasEscape) { 122 lastWasEscape = false; 123 // map \n to newline and \t to tab 124 if (c == 'n') 125 c = '\n'; 126 else if (c == 't') 127 c = '\t'; 128 } else if (c == '\\') { 129 lastWasEscape = true; 130 continue; 131 } 132 value[newIndex++] = c; 133 } 134 value[newIndex] = '\0'; 135 text.UnlockBuffer(newIndex); 136 } 137 } 138 } 139 140 operator bool() const 141 { 142 return type != TOKEN_EOF; 143 } 144 }; 145 146 147 struct BPackageInfo::Parser::ListElementParser { 148 virtual void operator()(const Token& token) = 0; 149 }; 150 151 152 BPackageInfo::ParseErrorListener::~ParseErrorListener() 153 { 154 } 155 156 157 BPackageInfo::Parser::Parser(ParseErrorListener* listener) 158 : 159 fListener(listener), 160 fPos(NULL) 161 { 162 } 163 164 165 status_t 166 BPackageInfo::Parser::Parse(const BString& packageInfoString, 167 BPackageInfo* packageInfo) 168 { 169 if (packageInfo == NULL) 170 return B_BAD_VALUE; 171 172 fPos = packageInfoString.String(); 173 174 try { 175 _Parse(packageInfo); 176 } catch (const ParseError& error) { 177 if (fListener != NULL) { 178 // map error position to line and column 179 int line = 1; 180 int column; 181 int32 offset = error.pos - packageInfoString.String(); 182 int32 newlinePos = packageInfoString.FindLast('\n', offset - 1); 183 if (newlinePos < 0) 184 column = offset; 185 else { 186 column = offset - newlinePos; 187 do { 188 line++; 189 newlinePos = packageInfoString.FindLast('\n', 190 newlinePos - 1); 191 } while (newlinePos >= 0); 192 } 193 fListener->OnError(error.message, line, column); 194 } 195 return B_BAD_DATA; 196 } catch (const std::bad_alloc& e) { 197 if (fListener != NULL) 198 fListener->OnError("out of memory", 0, 0); 199 return B_NO_MEMORY; 200 } 201 202 return B_OK; 203 } 204 205 206 BPackageInfo::Parser::Token 207 BPackageInfo::Parser::_NextToken() 208 { 209 // Eat any whitespace or comments. Also eat ';' -- they have the same 210 // function as newlines. We remember the last encountered ';' or '\n' and 211 // return it as a token afterwards. 212 const char* itemSeparatorPos = NULL; 213 bool inComment = false; 214 while ((inComment && *fPos != '\0') || isspace(*fPos) || *fPos == ';' 215 || *fPos == '#') { 216 if (*fPos == '#') { 217 inComment = true; 218 } else if (*fPos == '\n') { 219 itemSeparatorPos = fPos; 220 inComment = false; 221 } else if (!inComment && *fPos == ';') 222 itemSeparatorPos = fPos; 223 fPos++; 224 } 225 226 if (itemSeparatorPos != NULL) { 227 return Token(TOKEN_ITEM_SEPARATOR, itemSeparatorPos); 228 } 229 230 const char* tokenPos = fPos; 231 switch (*fPos) { 232 case '\0': 233 return Token(TOKEN_EOF, fPos); 234 235 case '{': 236 fPos++; 237 return Token(TOKEN_OPEN_BRACE, tokenPos); 238 239 case '}': 240 fPos++; 241 return Token(TOKEN_CLOSE_BRACE, tokenPos); 242 243 case '<': 244 fPos++; 245 if (*fPos == '=') { 246 fPos++; 247 return Token(TOKEN_OPERATOR_LESS_EQUAL, tokenPos, 2); 248 } 249 return Token(TOKEN_OPERATOR_LESS, tokenPos, 1); 250 251 case '=': 252 fPos++; 253 if (*fPos == '=') { 254 fPos++; 255 return Token(TOKEN_OPERATOR_EQUAL, tokenPos, 2); 256 } 257 return Token(TOKEN_OPERATOR_ASSIGN, tokenPos, 1); 258 259 case '!': 260 if (fPos[1] == '=') { 261 fPos += 2; 262 return Token(TOKEN_OPERATOR_NOT_EQUAL, tokenPos, 2); 263 } 264 break; 265 266 case '>': 267 fPos++; 268 if (*fPos == '=') { 269 fPos++; 270 return Token(TOKEN_OPERATOR_GREATER_EQUAL, tokenPos, 2); 271 } 272 return Token(TOKEN_OPERATOR_GREATER, tokenPos, 1); 273 274 case '"': 275 case '\'': 276 { 277 char quoteChar = *fPos; 278 fPos++; 279 const char* start = fPos; 280 // anything until the next quote is part of the value 281 bool lastWasEscape = false; 282 while ((*fPos != quoteChar || lastWasEscape) && *fPos != '\0') { 283 if (lastWasEscape) 284 lastWasEscape = false; 285 else if (*fPos == '\\') 286 lastWasEscape = true; 287 fPos++; 288 } 289 if (*fPos != quoteChar) 290 throw ParseError("unterminated quoted-string", tokenPos); 291 const char* end = fPos++; 292 return Token(TOKEN_QUOTED_STRING, start, end - start); 293 } 294 295 default: 296 { 297 const char* start = fPos; 298 while (isalnum(*fPos) || *fPos == '.' || *fPos == '-' 299 || *fPos == '_' || *fPos == ':' || *fPos == '+') { 300 fPos++; 301 } 302 if (fPos == start) 303 break; 304 return Token(TOKEN_WORD, start, fPos - start); 305 } 306 } 307 308 BString error = BString("unknown token '") << *fPos << "' encountered"; 309 throw ParseError(error.String(), fPos); 310 } 311 312 313 void 314 BPackageInfo::Parser::_RewindTo(const Token& token) 315 { 316 fPos = token.pos; 317 } 318 319 320 void 321 BPackageInfo::Parser::_ParseStringValue(BString* value) 322 { 323 Token string = _NextToken(); 324 if (string.type != TOKEN_QUOTED_STRING && string.type != TOKEN_WORD) 325 throw ParseError("expected quoted-string or word", string.pos); 326 327 *value = string.text; 328 } 329 330 331 void 332 BPackageInfo::Parser::_ParseArchitectureValue(BPackageArchitecture* value) 333 { 334 Token arch = _NextToken(); 335 if (arch.type == TOKEN_WORD) { 336 for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) { 337 if (arch.text.ICompare(BPackageInfo::kArchitectureNames[i]) == 0) { 338 *value = (BPackageArchitecture)i; 339 return; 340 } 341 } 342 } 343 344 BString error("architecture must be one of: ["); 345 for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) { 346 if (i > 0) 347 error << ","; 348 error << BPackageInfo::kArchitectureNames[i]; 349 } 350 error << "]"; 351 throw ParseError(error, arch.pos); 352 } 353 354 355 void 356 BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value, 357 bool releaseIsOptional) 358 { 359 Token word = _NextToken(); 360 if (word.type != TOKEN_WORD) 361 throw ParseError("expected word (a version)", word.pos); 362 363 // get the release number 364 uint8 release = 0; 365 int32 lastDashPos = word.text.FindLast('-'); 366 if (lastDashPos >= 0) { 367 // Might be either the release number or, if that is optional, a 368 // pre-release. The former always is a number, the latter starts with a 369 // non-digit. 370 if (isdigit(word.text[lastDashPos + 1])) { 371 int number = atoi(word.text.String() + lastDashPos + 1); 372 if (number <= 0 || number > 99) { 373 throw ParseError("release number must be from 1-99", 374 word.pos + word.text.Length()); 375 } 376 release = number; 377 word.text.Truncate(lastDashPos); 378 lastDashPos = word.text.FindLast('-'); 379 } 380 } 381 382 if (release == 0 && !releaseIsOptional) { 383 throw ParseError("expected release number (-<number> suffix)", 384 word.pos + word.text.Length()); 385 } 386 387 // get the pre-release string 388 BString preRelease; 389 if (lastDashPos >= 0) { 390 if (isdigit(word.text[lastDashPos + 1])) { 391 throw ParseError("pre-release number must not start with a digit", 392 word.pos + word.text.Length()); 393 } 394 395 word.text.CopyInto(preRelease, lastDashPos + 1, word.text.Length()); 396 word.text.Truncate(lastDashPos); 397 } 398 399 // get major, minor, and micro strings 400 BString major; 401 BString minor; 402 BString micro; 403 int32 firstDotPos = word.text.FindFirst('.'); 404 if (firstDotPos < 0) 405 major = word.text; 406 else { 407 word.text.CopyInto(major, 0, firstDotPos); 408 int32 secondDotPos = word.text.FindFirst('.', firstDotPos + 1); 409 if (secondDotPos == firstDotPos + 1) 410 throw ParseError("expected minor version", word.pos + secondDotPos); 411 412 if (secondDotPos < 0) 413 word.text.CopyInto(minor, firstDotPos + 1, word.text.Length()); 414 else { 415 word.text.CopyInto(minor, firstDotPos + 1, 416 secondDotPos - (firstDotPos + 1)); 417 word.text.CopyInto(micro, secondDotPos + 1, word.text.Length()); 418 } 419 } 420 421 value->SetTo(major, minor, micro, preRelease, release); 422 } 423 424 425 void 426 BPackageInfo::Parser::_ParseList(ListElementParser& elementParser, 427 bool allowSingleNonListElement) 428 { 429 Token openBracket = _NextToken(); 430 if (openBracket.type != TOKEN_OPEN_BRACE) { 431 if (!allowSingleNonListElement) 432 throw ParseError("expected start of list ('[')", openBracket.pos); 433 434 elementParser(openBracket); 435 return; 436 } 437 438 while (true) { 439 Token token = _NextToken(); 440 if (token.type == TOKEN_CLOSE_BRACE) 441 return; 442 443 if (token.type == TOKEN_ITEM_SEPARATOR) 444 continue; 445 446 elementParser(token); 447 } 448 } 449 450 451 void 452 BPackageInfo::Parser::_ParseStringList(BStringList* value, 453 bool allowQuotedStrings, bool convertToLowerCase) 454 { 455 struct StringParser : public ListElementParser { 456 BStringList* value; 457 bool allowQuotedStrings; 458 bool convertToLowerCase; 459 460 StringParser(BStringList* value, bool allowQuotedStrings, 461 bool convertToLowerCase) 462 : 463 value(value), 464 allowQuotedStrings(allowQuotedStrings), 465 convertToLowerCase(convertToLowerCase) 466 { 467 } 468 469 virtual void operator()(const Token& token) 470 { 471 if (allowQuotedStrings) { 472 if (token.type != TOKEN_QUOTED_STRING 473 && token.type != TOKEN_WORD) { 474 throw ParseError("expected quoted-string or word", 475 token.pos); 476 } 477 } else { 478 if (token.type != TOKEN_WORD) 479 throw ParseError("expected word", token.pos); 480 } 481 482 BString element(token.text); 483 if (convertToLowerCase) 484 element.ToLower(); 485 486 value->Add(element); 487 } 488 } stringParser(value, allowQuotedStrings, convertToLowerCase); 489 490 _ParseList(stringParser, true); 491 } 492 493 494 uint32 495 BPackageInfo::Parser::_ParseFlags() 496 { 497 struct FlagParser : public ListElementParser { 498 uint32 flags; 499 500 FlagParser() 501 : 502 flags(0) 503 { 504 } 505 506 virtual void operator()(const Token& token) 507 { 508 if (token.type != TOKEN_WORD) 509 throw ParseError("expected word (a flag)", token.pos); 510 511 if (token.text.ICompare("approve_license") == 0) 512 flags |= B_PACKAGE_FLAG_APPROVE_LICENSE; 513 else if (token.text.ICompare("system_package") == 0) 514 flags |= B_PACKAGE_FLAG_SYSTEM_PACKAGE; 515 else { 516 throw ParseError( 517 "expected 'approve_license' or 'system_package'", 518 token.pos); 519 } 520 } 521 } flagParser; 522 523 _ParseList(flagParser, true); 524 525 return flagParser.flags; 526 } 527 528 529 void 530 BPackageInfo::Parser::_ParseResolvableList( 531 BObjectList<BPackageResolvable>* value) 532 { 533 struct ResolvableParser : public ListElementParser { 534 Parser& parser; 535 BObjectList<BPackageResolvable>* value; 536 537 ResolvableParser(Parser& parser_, 538 BObjectList<BPackageResolvable>* value_) 539 : 540 parser(parser_), 541 value(value_) 542 { 543 } 544 545 virtual void operator()(const Token& token) 546 { 547 if (token.type != TOKEN_WORD) { 548 throw ParseError("expected word (a resolvable name)", 549 token.pos); 550 } 551 552 BPackageResolvableType type = B_PACKAGE_RESOLVABLE_TYPE_DEFAULT; 553 int32 colonPos = token.text.FindFirst(':'); 554 if (colonPos >= 0) { 555 BString typeName(token.text, colonPos); 556 for (int i = 0; i < B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT; ++i) { 557 if (typeName.ICompare(BPackageResolvable::kTypeNames[i]) 558 == 0) { 559 type = (BPackageResolvableType)i; 560 break; 561 } 562 } 563 if (type == B_PACKAGE_RESOLVABLE_TYPE_DEFAULT) { 564 BString error("resolvable type (<type>:) must be one of ["); 565 for (int i = 1; i < B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT; 566 ++i) { 567 if (i > 1) 568 error << ","; 569 error << BPackageResolvable::kTypeNames[i]; 570 } 571 error << "]"; 572 throw ParseError(error, token.pos); 573 } 574 } 575 576 // parse version 577 BPackageVersion version; 578 Token op = parser._NextToken(); 579 if (op.type == TOKEN_OPERATOR_ASSIGN) { 580 parser._ParseVersionValue(&version, true); 581 } else if (op.type == TOKEN_ITEM_SEPARATOR 582 || op.type == TOKEN_CLOSE_BRACE) { 583 parser._RewindTo(op); 584 } else 585 throw ParseError("expected '=', comma or ']'", op.pos); 586 587 // parse compatible version 588 BPackageVersion compatibleVersion; 589 Token compatible = parser._NextToken(); 590 if (compatible.type == TOKEN_WORD 591 && (compatible.text == "compat" 592 || compatible.text == "compatible")) { 593 op = parser._NextToken(); 594 if (op.type == TOKEN_OPERATOR_GREATER_EQUAL) { 595 parser._ParseVersionValue(&compatibleVersion, true); 596 } else 597 parser._RewindTo(compatible); 598 } else 599 parser._RewindTo(compatible); 600 601 value->AddItem(new BPackageResolvable(token.text, type, version, 602 compatibleVersion)); 603 } 604 } resolvableParser(*this, value); 605 606 _ParseList(resolvableParser, false); 607 } 608 609 610 void 611 BPackageInfo::Parser::_ParseResolvableExprList( 612 BObjectList<BPackageResolvableExpression>* value) 613 { 614 struct ResolvableExpressionParser : public ListElementParser { 615 Parser& parser; 616 BObjectList<BPackageResolvableExpression>* value; 617 618 ResolvableExpressionParser(Parser& parser_, 619 BObjectList<BPackageResolvableExpression>* value_) 620 : 621 parser(parser_), 622 value(value_) 623 { 624 } 625 626 virtual void operator()(const Token& token) 627 { 628 if (token.type != TOKEN_WORD) { 629 throw ParseError("expected word (a resolvable name)", 630 token.pos); 631 } 632 633 BPackageVersion version; 634 Token op = parser._NextToken(); 635 if (op.type == TOKEN_OPERATOR_LESS 636 || op.type == TOKEN_OPERATOR_LESS_EQUAL 637 || op.type == TOKEN_OPERATOR_EQUAL 638 || op.type == TOKEN_OPERATOR_NOT_EQUAL 639 || op.type == TOKEN_OPERATOR_GREATER_EQUAL 640 || op.type == TOKEN_OPERATOR_GREATER) { 641 parser._ParseVersionValue(&version, true); 642 } else if (op.type == TOKEN_ITEM_SEPARATOR 643 || op.type == TOKEN_CLOSE_BRACE) { 644 parser._RewindTo(op); 645 } else { 646 throw ParseError( 647 "expected '<', '<=', '==', '!=', '>=', '>', comma or ']'", 648 op.pos); 649 } 650 651 BPackageResolvableOperator resolvableOperator 652 = (BPackageResolvableOperator)(op.type - TOKEN_OPERATOR_LESS); 653 654 value->AddItem(new BPackageResolvableExpression(token.text, 655 resolvableOperator, version)); 656 } 657 } resolvableExpressionParser(*this, value); 658 659 _ParseList(resolvableExpressionParser, false); 660 } 661 662 663 void 664 BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo) 665 { 666 bool seen[B_PACKAGE_INFO_ENUM_COUNT]; 667 for (int i = 0; i < B_PACKAGE_INFO_ENUM_COUNT; ++i) 668 seen[i] = false; 669 670 const char* const* names = BPackageInfo::kElementNames; 671 672 while (Token t = _NextToken()) { 673 if (t.type == TOKEN_ITEM_SEPARATOR) 674 continue; 675 676 if (t.type != TOKEN_WORD) 677 throw ParseError("expected word (a variable name)", t.pos); 678 679 BPackageInfoAttributeID attribute = B_PACKAGE_INFO_ENUM_COUNT; 680 for (int i = 0; i < B_PACKAGE_INFO_ENUM_COUNT; i++) { 681 if (names[i] != NULL && t.text.ICompare(names[i]) == 0) { 682 attribute = (BPackageInfoAttributeID)i; 683 break; 684 } 685 } 686 687 if (attribute == B_PACKAGE_INFO_ENUM_COUNT) { 688 BString error = BString("unknown attribute \"") << t.text << '"'; 689 throw ParseError(error, t.pos); 690 } 691 692 if (seen[attribute]) { 693 BString error = BString(names[attribute]) << " already seen!"; 694 throw ParseError(error, t.pos); 695 } 696 697 switch (attribute) { 698 case B_PACKAGE_INFO_NAME: 699 { 700 BString name; 701 _ParseStringValue(&name); 702 packageInfo->SetName(name); 703 break; 704 } 705 706 case B_PACKAGE_INFO_SUMMARY: 707 { 708 BString summary; 709 _ParseStringValue(&summary); 710 if (summary.FindFirst('\n') >= 0) 711 throw ParseError("the summary contains linebreaks", t.pos); 712 packageInfo->SetSummary(summary); 713 break; 714 } 715 716 case B_PACKAGE_INFO_DESCRIPTION: 717 _ParseStringValue(&packageInfo->fDescription); 718 break; 719 720 case B_PACKAGE_INFO_VENDOR: 721 _ParseStringValue(&packageInfo->fVendor); 722 break; 723 724 case B_PACKAGE_INFO_PACKAGER: 725 _ParseStringValue(&packageInfo->fPackager); 726 break; 727 728 case B_PACKAGE_INFO_ARCHITECTURE: 729 _ParseArchitectureValue(&packageInfo->fArchitecture); 730 break; 731 732 case B_PACKAGE_INFO_VERSION: 733 _ParseVersionValue(&packageInfo->fVersion, false); 734 break; 735 736 case B_PACKAGE_INFO_COPYRIGHTS: 737 _ParseStringList(&packageInfo->fCopyrightList); 738 break; 739 740 case B_PACKAGE_INFO_LICENSES: 741 _ParseStringList(&packageInfo->fLicenseList); 742 break; 743 744 case B_PACKAGE_INFO_URLS: 745 _ParseStringList(&packageInfo->fURLList); 746 break; 747 748 case B_PACKAGE_INFO_SOURCE_URLS: 749 _ParseStringList(&packageInfo->fSourceURLList); 750 break; 751 752 case B_PACKAGE_INFO_PROVIDES: 753 _ParseResolvableList(&packageInfo->fProvidesList); 754 break; 755 756 case B_PACKAGE_INFO_REQUIRES: 757 _ParseResolvableExprList(&packageInfo->fRequiresList); 758 break; 759 760 case B_PACKAGE_INFO_SUPPLEMENTS: 761 _ParseResolvableExprList(&packageInfo->fSupplementsList); 762 break; 763 764 case B_PACKAGE_INFO_CONFLICTS: 765 _ParseResolvableExprList(&packageInfo->fConflictsList); 766 break; 767 768 case B_PACKAGE_INFO_FRESHENS: 769 _ParseResolvableExprList(&packageInfo->fFreshensList); 770 break; 771 772 case B_PACKAGE_INFO_REPLACES: 773 _ParseStringList(&packageInfo->fReplacesList, false, true); 774 break; 775 776 case B_PACKAGE_INFO_FLAGS: 777 packageInfo->SetFlags(_ParseFlags()); 778 break; 779 780 default: 781 // can never get here 782 break; 783 } 784 785 seen[attribute] = true; 786 } 787 788 // everything up to and including 'provides' is mandatory 789 for (int i = 0; i <= B_PACKAGE_INFO_PROVIDES; ++i) { 790 if (!seen[i]) { 791 BString error = BString(names[i]) << " is not being set anywhere!"; 792 throw ParseError(error, fPos); 793 } 794 } 795 } 796 797 798 const char* BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = { 799 "name", 800 "summary", 801 "description", 802 "vendor", 803 "packager", 804 "architecture", 805 "version", 806 "copyrights", 807 "licenses", 808 "provides", 809 "requires", 810 "supplements", 811 "conflicts", 812 "freshens", 813 "replaces", 814 "flags", 815 "urls", 816 "source-urls", 817 "checksum", // not being parsed, computed externally 818 NULL, // install-path -- not settable via .PackageInfo 819 }; 820 821 822 const char* 823 BPackageInfo::kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = { 824 "any", 825 "x86", 826 "x86_gcc2", 827 }; 828 829 830 BPackageInfo::BPackageInfo() 831 : 832 fFlags(0), 833 fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT), 834 fCopyrightList(5), 835 fLicenseList(5), 836 fURLList(5), 837 fSourceURLList(5), 838 fProvidesList(20, true), 839 fRequiresList(20, true), 840 fSupplementsList(20, true), 841 fConflictsList(5, true), 842 fFreshensList(5, true), 843 fReplacesList(5) 844 { 845 } 846 847 848 BPackageInfo::~BPackageInfo() 849 { 850 } 851 852 853 status_t 854 BPackageInfo::ReadFromConfigFile(const BEntry& packageInfoEntry, 855 ParseErrorListener* listener) 856 { 857 status_t result = packageInfoEntry.InitCheck(); 858 if (result != B_OK) 859 return result; 860 861 BFile file(&packageInfoEntry, B_READ_ONLY); 862 if ((result = file.InitCheck()) != B_OK) 863 return result; 864 865 return ReadFromConfigFile(file, listener); 866 } 867 868 869 status_t 870 BPackageInfo::ReadFromConfigFile(BFile& packageInfoFile, 871 ParseErrorListener* listener) 872 { 873 off_t size; 874 status_t result = packageInfoFile.GetSize(&size); 875 if (result != B_OK) 876 return result; 877 878 BString packageInfoString; 879 char* buffer = packageInfoString.LockBuffer(size); 880 if (buffer == NULL) 881 return B_NO_MEMORY; 882 883 if ((result = packageInfoFile.Read(buffer, size)) < size) { 884 packageInfoString.UnlockBuffer(0); 885 return result >= 0 ? B_IO_ERROR : result; 886 } 887 888 buffer[size] = '\0'; 889 packageInfoString.UnlockBuffer(size); 890 891 return ReadFromConfigString(packageInfoString, listener); 892 } 893 894 895 status_t 896 BPackageInfo::ReadFromConfigString(const BString& packageInfoString, 897 ParseErrorListener* listener) 898 { 899 Clear(); 900 901 Parser parser(listener); 902 return parser.Parse(packageInfoString, this); 903 } 904 905 906 status_t 907 BPackageInfo::InitCheck() const 908 { 909 if (fName.Length() == 0 || fSummary.Length() == 0 910 || fDescription.Length() == 0 || fVendor.Length() == 0 911 || fPackager.Length() == 0 912 || fArchitecture == B_PACKAGE_ARCHITECTURE_ENUM_COUNT 913 || fVersion.InitCheck() != B_OK 914 || fCopyrightList.IsEmpty() || fLicenseList.IsEmpty() 915 || fProvidesList.IsEmpty()) 916 return B_NO_INIT; 917 918 return B_OK; 919 } 920 921 922 const BString& 923 BPackageInfo::Name() const 924 { 925 return fName; 926 } 927 928 929 const BString& 930 BPackageInfo::Summary() const 931 { 932 return fSummary; 933 } 934 935 936 const BString& 937 BPackageInfo::Description() const 938 { 939 return fDescription; 940 } 941 942 943 const BString& 944 BPackageInfo::Vendor() const 945 { 946 return fVendor; 947 } 948 949 950 const BString& 951 BPackageInfo::Packager() const 952 { 953 return fPackager; 954 } 955 956 957 const BString& 958 BPackageInfo::Checksum() const 959 { 960 return fChecksum; 961 } 962 963 964 const BString& 965 BPackageInfo::InstallPath() const 966 { 967 return fInstallPath; 968 } 969 970 971 uint32 972 BPackageInfo::Flags() const 973 { 974 return fFlags; 975 } 976 977 978 BPackageArchitecture 979 BPackageInfo::Architecture() const 980 { 981 return fArchitecture; 982 } 983 984 985 const BPackageVersion& 986 BPackageInfo::Version() const 987 { 988 return fVersion; 989 } 990 991 992 const BStringList& 993 BPackageInfo::CopyrightList() const 994 { 995 return fCopyrightList; 996 } 997 998 999 const BStringList& 1000 BPackageInfo::LicenseList() const 1001 { 1002 return fLicenseList; 1003 } 1004 1005 1006 const BStringList& 1007 BPackageInfo::URLList() const 1008 { 1009 return fURLList; 1010 } 1011 1012 1013 const BStringList& 1014 BPackageInfo::SourceURLList() const 1015 { 1016 return fSourceURLList; 1017 } 1018 1019 1020 const BObjectList<BPackageResolvable>& 1021 BPackageInfo::ProvidesList() const 1022 { 1023 return fProvidesList; 1024 } 1025 1026 1027 const BObjectList<BPackageResolvableExpression>& 1028 BPackageInfo::RequiresList() const 1029 { 1030 return fRequiresList; 1031 } 1032 1033 1034 const BObjectList<BPackageResolvableExpression>& 1035 BPackageInfo::SupplementsList() const 1036 { 1037 return fSupplementsList; 1038 } 1039 1040 1041 const BObjectList<BPackageResolvableExpression>& 1042 BPackageInfo::ConflictsList() const 1043 { 1044 return fConflictsList; 1045 } 1046 1047 1048 const BObjectList<BPackageResolvableExpression>& 1049 BPackageInfo::FreshensList() const 1050 { 1051 return fFreshensList; 1052 } 1053 1054 1055 const BStringList& 1056 BPackageInfo::ReplacesList() const 1057 { 1058 return fReplacesList; 1059 } 1060 1061 1062 void 1063 BPackageInfo::SetName(const BString& name) 1064 { 1065 fName = name; 1066 fName.ToLower(); 1067 } 1068 1069 1070 void 1071 BPackageInfo::SetSummary(const BString& summary) 1072 { 1073 fSummary = summary; 1074 } 1075 1076 1077 void 1078 BPackageInfo::SetDescription(const BString& description) 1079 { 1080 fDescription = description; 1081 } 1082 1083 1084 void 1085 BPackageInfo::SetVendor(const BString& vendor) 1086 { 1087 fVendor = vendor; 1088 } 1089 1090 1091 void 1092 BPackageInfo::SetPackager(const BString& packager) 1093 { 1094 fPackager = packager; 1095 } 1096 1097 1098 void 1099 BPackageInfo::SetChecksum(const BString& checksum) 1100 { 1101 fChecksum = checksum; 1102 } 1103 1104 1105 void 1106 BPackageInfo::SetInstallPath(const BString& installPath) 1107 { 1108 fInstallPath = installPath; 1109 } 1110 1111 1112 void 1113 BPackageInfo::SetVersion(const BPackageVersion& version) 1114 { 1115 fVersion = version; 1116 } 1117 1118 1119 void 1120 BPackageInfo::SetFlags(uint32 flags) 1121 { 1122 fFlags = flags; 1123 } 1124 1125 1126 void 1127 BPackageInfo::SetArchitecture(BPackageArchitecture architecture) 1128 { 1129 fArchitecture = architecture; 1130 } 1131 1132 1133 void 1134 BPackageInfo::ClearCopyrightList() 1135 { 1136 fCopyrightList.MakeEmpty(); 1137 } 1138 1139 1140 status_t 1141 BPackageInfo::AddCopyright(const BString& copyright) 1142 { 1143 return fCopyrightList.Add(copyright) ? B_OK : B_ERROR; 1144 } 1145 1146 1147 void 1148 BPackageInfo::ClearLicenseList() 1149 { 1150 fLicenseList.MakeEmpty(); 1151 } 1152 1153 1154 status_t 1155 BPackageInfo::AddLicense(const BString& license) 1156 { 1157 return fLicenseList.Add(license) ? B_OK : B_ERROR; 1158 } 1159 1160 1161 void 1162 BPackageInfo::ClearURLList() 1163 { 1164 fURLList.MakeEmpty(); 1165 } 1166 1167 1168 status_t 1169 BPackageInfo::AddURL(const BString& url) 1170 { 1171 return fURLList.Add(url) ? B_OK : B_NO_MEMORY; 1172 } 1173 1174 1175 void 1176 BPackageInfo::ClearSourceURLList() 1177 { 1178 fSourceURLList.MakeEmpty(); 1179 } 1180 1181 1182 status_t 1183 BPackageInfo::AddSourceURL(const BString& url) 1184 { 1185 return fSourceURLList.Add(url) ? B_OK : B_NO_MEMORY; 1186 } 1187 1188 1189 void 1190 BPackageInfo::ClearProvidesList() 1191 { 1192 fProvidesList.MakeEmpty(); 1193 } 1194 1195 1196 status_t 1197 BPackageInfo::AddProvides(const BPackageResolvable& provides) 1198 { 1199 BPackageResolvable* newProvides 1200 = new (std::nothrow) BPackageResolvable(provides); 1201 if (newProvides == NULL) 1202 return B_NO_MEMORY; 1203 1204 return fProvidesList.AddItem(newProvides) ? B_OK : B_ERROR; 1205 } 1206 1207 1208 void 1209 BPackageInfo::ClearRequiresList() 1210 { 1211 fRequiresList.MakeEmpty(); 1212 } 1213 1214 1215 status_t 1216 BPackageInfo::AddRequires(const BPackageResolvableExpression& requires) 1217 { 1218 BPackageResolvableExpression* newRequires 1219 = new (std::nothrow) BPackageResolvableExpression(requires); 1220 if (newRequires == NULL) 1221 return B_NO_MEMORY; 1222 1223 return fRequiresList.AddItem(newRequires) ? B_OK : B_ERROR; 1224 } 1225 1226 1227 void 1228 BPackageInfo::ClearSupplementsList() 1229 { 1230 fSupplementsList.MakeEmpty(); 1231 } 1232 1233 1234 status_t 1235 BPackageInfo::AddSupplements(const BPackageResolvableExpression& supplements) 1236 { 1237 BPackageResolvableExpression* newSupplements 1238 = new (std::nothrow) BPackageResolvableExpression(supplements); 1239 if (newSupplements == NULL) 1240 return B_NO_MEMORY; 1241 1242 return fSupplementsList.AddItem(newSupplements) ? B_OK : B_ERROR; 1243 } 1244 1245 1246 void 1247 BPackageInfo::ClearConflictsList() 1248 { 1249 fConflictsList.MakeEmpty(); 1250 } 1251 1252 1253 status_t 1254 BPackageInfo::AddConflicts(const BPackageResolvableExpression& conflicts) 1255 { 1256 BPackageResolvableExpression* newConflicts 1257 = new (std::nothrow) BPackageResolvableExpression(conflicts); 1258 if (newConflicts == NULL) 1259 return B_NO_MEMORY; 1260 1261 return fConflictsList.AddItem(newConflicts) ? B_OK : B_ERROR; 1262 } 1263 1264 1265 void 1266 BPackageInfo::ClearFreshensList() 1267 { 1268 fFreshensList.MakeEmpty(); 1269 } 1270 1271 1272 status_t 1273 BPackageInfo::AddFreshens(const BPackageResolvableExpression& freshens) 1274 { 1275 BPackageResolvableExpression* newFreshens 1276 = new (std::nothrow) BPackageResolvableExpression(freshens); 1277 if (newFreshens == NULL) 1278 return B_NO_MEMORY; 1279 1280 return fFreshensList.AddItem(newFreshens) ? B_OK : B_ERROR; 1281 } 1282 1283 1284 void 1285 BPackageInfo::ClearReplacesList() 1286 { 1287 fReplacesList.MakeEmpty(); 1288 } 1289 1290 1291 status_t 1292 BPackageInfo::AddReplaces(const BString& replaces) 1293 { 1294 return fReplacesList.Add(BString(replaces).ToLower()) ? B_OK : B_ERROR; 1295 } 1296 1297 1298 void 1299 BPackageInfo::Clear() 1300 { 1301 fName.Truncate(0); 1302 fSummary.Truncate(0); 1303 fDescription.Truncate(0); 1304 fVendor.Truncate(0); 1305 fPackager.Truncate(0); 1306 fChecksum.Truncate(0); 1307 fInstallPath.Truncate(0); 1308 fFlags = 0; 1309 fArchitecture = B_PACKAGE_ARCHITECTURE_ENUM_COUNT; 1310 fVersion.Clear(); 1311 fCopyrightList.MakeEmpty(); 1312 fLicenseList.MakeEmpty(); 1313 fURLList.MakeEmpty(); 1314 fSourceURLList.MakeEmpty(); 1315 fRequiresList.MakeEmpty(); 1316 fProvidesList.MakeEmpty(); 1317 fSupplementsList.MakeEmpty(); 1318 fConflictsList.MakeEmpty(); 1319 fFreshensList.MakeEmpty(); 1320 fReplacesList.MakeEmpty(); 1321 } 1322 1323 1324 /*static*/ status_t 1325 BPackageInfo::GetArchitectureByName(const BString& name, 1326 BPackageArchitecture& _architecture) 1327 { 1328 for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) { 1329 if (name.ICompare(kArchitectureNames[i]) == 0) { 1330 _architecture = (BPackageArchitecture)i; 1331 return B_OK; 1332 } 1333 } 1334 return B_NAME_NOT_FOUND; 1335 } 1336 1337 } // namespace BPackageKit 1338