1 /* 2 * Copyright (c) 2007, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org> 7 */ 8 9 10 #include "PackageInfo.h" 11 12 #include <Alert.h> 13 #include <ByteOrder.h> 14 #include <FindDirectory.h> 15 #include <Path.h> 16 #include <kernel/OS.h> 17 18 19 // Macro reserved for later localization 20 #define T(x) x 21 22 const uint32 kSkipOffset = 33; 23 24 // Section constants 25 enum { 26 P_GROUPS_SECTION = 0, 27 P_PATH_SECTION, 28 P_USER_PATH_SECTION, 29 P_LICENSE_SECTION 30 }; 31 32 33 // Element constants 34 enum { 35 P_NONE = 0, 36 P_FILE, 37 P_DIRECTORY, 38 P_LINK 39 }; 40 41 42 PackageInfo::PackageInfo() 43 : 44 fStatus(B_NO_INIT), 45 fPackageFile(0), 46 fDescription(T("No package available.")), 47 fProfiles(2), 48 fHasImage(false) 49 { 50 } 51 52 53 PackageInfo::PackageInfo(const entry_ref *ref) 54 : 55 fStatus(B_NO_INIT), 56 fPackageFile(new BFile(ref, B_READ_ONLY)), 57 fDescription(T("No package selected.")), 58 fProfiles(2), 59 fHasImage(false) 60 { 61 fStatus = Parse(); 62 } 63 64 65 PackageInfo::~PackageInfo() 66 { 67 pkg_profile *iter = 0; 68 while (1) { 69 iter = static_cast<pkg_profile *>(fProfiles.RemoveItem((long int)0)); 70 if (iter) 71 delete iter; 72 else 73 break; 74 } 75 76 PkgItem *file = 0; 77 while (1) { 78 file = static_cast<PkgItem *>(fFiles.RemoveItem((long int)0)); 79 if (file) 80 delete file; 81 else 82 break; 83 } 84 85 if (fPackageFile) 86 delete fPackageFile; 87 } 88 89 90 status_t 91 PackageInfo::Parse() 92 { 93 // TODO: Clean up 94 if (!fPackageFile || fPackageFile->InitCheck() != B_OK) { 95 fStatus = B_ERROR; 96 return fStatus; 97 } 98 99 // Check for the presence of the first AlB tag - as the 'magic number'. 100 // This also ensures that the file header section is present - which 101 // is a crucial pkg section 102 char buffer[16]; 103 fPackageFile->Read(buffer, 8); 104 if (buffer[0] != 'A' || buffer[1] != 'l' || buffer[2] != 'B' 105 || buffer[3] != 0x1a) { 106 fStatus = B_ERROR; 107 return fStatus; 108 } 109 110 fHasImage = false; 111 112 // Parse all known parts of the given .pkg file 113 114 uint32 i; 115 int8 bytesRead; 116 off_t actualSize = 0; 117 fPackageFile->GetSize(&actualSize); 118 uint64 fileSize = 0; 119 120 const char padding[7] = { 0, 0, 0, 0, 0, 0, 0 }; 121 122 system_info sysinfo; 123 get_system_info(&sysinfo); 124 125 uint64 infoOffset = 0, groupsOffset = 0; 126 uint64 length = 0; 127 128 // Parse the file header 129 while (1) { 130 bytesRead = fPackageFile->Read(buffer, 7); 131 if (bytesRead != 7) { 132 fStatus = B_ERROR; 133 return fStatus; 134 } 135 136 if (!memcmp(buffer, "PhIn", 5)) { 137 } 138 else if (!memcmp(buffer, "FVer", 5)) { 139 // Not used right now 140 fPackageFile->Seek(4, SEEK_CUR); 141 parser_debug("FVer\n"); 142 } 143 else if (!memcmp(buffer, "AFla", 5)) { 144 // Not used right now TODO: Check what this tag is for 145 fPackageFile->Seek(8, SEEK_CUR); 146 parser_debug("AFla\n"); 147 } 148 else if (!memcmp(buffer, "FSiz", 5)) { 149 fPackageFile->Read(&fileSize, 8); 150 swap_data(B_UINT64_TYPE, &fileSize, sizeof(uint64), 151 B_SWAP_BENDIAN_TO_HOST); 152 parser_debug("FSiz %llu\n", fileSize); 153 } 154 else if (!memcmp(buffer, "COff", 5)) { 155 fPackageFile->Read(&infoOffset, 8); 156 swap_data(B_UINT64_TYPE, &infoOffset, sizeof(uint64), 157 B_SWAP_BENDIAN_TO_HOST); 158 parser_debug("COff %llu\n", infoOffset); 159 } 160 else if (!memcmp(buffer, "AOff", 5)) { 161 fPackageFile->Read(&groupsOffset, 8); 162 swap_data(B_UINT64_TYPE, &groupsOffset, sizeof(uint64), 163 B_SWAP_BENDIAN_TO_HOST); 164 parser_debug("AOff %llu\n", groupsOffset); 165 } 166 else if (!memcmp(buffer, padding, 7)) { 167 // This means the end of this section - we should move to the 168 // groups section. 169 if (groupsOffset) { 170 fPackageFile->Seek(groupsOffset, SEEK_SET); 171 } 172 parser_debug("End!\n"); 173 break; 174 } 175 else { 176 fStatus = B_ERROR; 177 return fStatus; 178 } 179 } 180 181 fPackageFile->Read(buffer, 7); 182 if (memcmp(buffer, "PkgA", 5) || !groupsOffset || !infoOffset) { 183 fStatus = B_ERROR; 184 return fStatus; 185 } 186 187 // Section header identifying constant byte sequences: 188 const char groupsMarker[7] = { 0, 0, 0, 1, 0, 0, 4 }; 189 const char idMarker[7] = { 0, 0, 0, 2, 0, 0, 4 }; 190 const char pathMarker[7] = { 0, 0, 0, 3, 0, 0, 4 }; 191 const char upathMarker[7] = { 0, 0, 0, 4, 0, 0, 4 }; 192 const char licenseMarker[7] = { 0, 0, 0, 18, 0, 0, 4 }; 193 const char descMarker[7] = { 0, 0, 0, 5, 0, 0, 2 }; 194 const char helpMarker[7] = { 0, 0, 0, 10, 0, 0, 3 }; 195 196 const char splashScreenMarker[7] = { 0, 0, 0, 8, 0, 0, 3 }; 197 const char disclaimerMarker[7] = { 0, 0, 0, 7, 0, 0, 3 }; 198 199 const char nameMarker[7] = { 0, 0, 0, 13, 0, 0, 2 }; 200 const char versionMarker[7] = { 0, 0, 0, 14, 0, 0, 2 }; 201 const char devMarker[7] = { 0, 0, 0, 15, 0, 0, 2 }; 202 const char shortDescMarker[7] = { 0, 0, 0, 17, 0, 0, 2 }; 203 204 int8 section = P_GROUPS_SECTION, installDirectoryFlag = 0; 205 206 pkg_profile group; 207 BList groups(3), userPaths(3), systemPaths(10); 208 bool groupStarted = false; 209 parser_debug("Package Info reached!\n"); 210 // TODO: Maybe checking whether the needed number of bytes are read 211 // everytime would be a good idea 212 213 // Parse the package info section 214 while (1) { 215 bytesRead = fPackageFile->Read(buffer, 7); 216 if (bytesRead != 7) { 217 parser_debug("EOF!\n"); 218 break; 219 } 220 221 if (!memcmp(buffer, groupsMarker, 7)) { 222 section = P_GROUPS_SECTION; 223 parser_debug("Got to Groups section\n"); 224 continue; 225 } 226 else if (!memcmp(buffer, pathMarker, 7)) { 227 section = P_PATH_SECTION; 228 parser_debug("Got to System Paths\n"); 229 continue; 230 } 231 else if (!memcmp(buffer, upathMarker, 7)) { 232 section = P_USER_PATH_SECTION; 233 parser_debug("Got to User Paths\n"); 234 continue; 235 } 236 else if (!memcmp(buffer, licenseMarker, 7)) { 237 section = P_LICENSE_SECTION; 238 parser_debug("Got to License\n"); 239 continue; 240 } // After this, non sectioned tags follow 241 else if (!memcmp(buffer, disclaimerMarker, 7)) { 242 uint64 length; 243 fPackageFile->Read(&length, 8); 244 swap_data(B_UINT64_TYPE, &length, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 245 246 uint64 original; 247 if (fPackageFile->Read(&original, 8) != 8) { 248 fStatus = B_ERROR; 249 return fStatus; 250 } 251 swap_data(B_UINT64_TYPE, &original, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 252 253 fPackageFile->Seek(4, SEEK_CUR); 254 255 uint8 *compressed = new uint8[length]; 256 if (fPackageFile->Read(compressed, length) != static_cast<int64>(length)) { 257 fStatus = B_ERROR; 258 delete compressed; 259 return fStatus; 260 } 261 262 uint8 *disclaimer = new uint8[original + 1]; 263 status_t ret = inflate_data(compressed, length, disclaimer, original); 264 disclaimer[original] = 0; 265 delete compressed; 266 if (ret != B_OK) { 267 fStatus = B_ERROR; 268 delete disclaimer; 269 return ret; 270 } 271 272 fDisclaimer = (char *)disclaimer; 273 delete disclaimer; 274 275 continue; 276 } 277 else if (!memcmp(buffer, splashScreenMarker, 7)) { 278 uint64 length; 279 fPackageFile->Read(&length, 8); 280 swap_data(B_UINT64_TYPE, &length, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 281 282 uint64 original; 283 if (fPackageFile->Read(&original, 8) != 8) { 284 fStatus = B_ERROR; 285 return fStatus; 286 } 287 swap_data(B_UINT64_TYPE, &original, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 288 289 fPackageFile->Seek(4, SEEK_CUR); 290 291 uint8 *compressed = new uint8[length]; 292 if (fPackageFile->Read(compressed, length) != static_cast<int64>(length)) { 293 fStatus = B_ERROR; 294 delete compressed; 295 return fStatus; 296 } 297 298 fImage.SetSize(original); 299 status_t ret = inflate_data(compressed, length, 300 static_cast<uint8 *>(const_cast<void *>(fImage.Buffer())), original); 301 delete compressed; 302 if (ret != B_OK) { 303 fStatus = B_ERROR; 304 return ret; 305 } 306 fHasImage = true; 307 continue; 308 } 309 310 switch (section) { 311 case P_PATH_SECTION: 312 { 313 if (!memcmp(buffer, "DPat", 5)) { 314 parser_debug("DPat\n"); 315 continue; 316 } 317 else if (!memcmp(buffer, "FDst", 5)) { 318 parser_debug("FDst - "); 319 directory_which dir; 320 if (fPackageFile->Read(&dir, 4) != 4) { 321 fStatus = B_ERROR; 322 return fStatus; 323 } 324 swap_data(B_UINT32_TYPE, &dir, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 325 BPath *path = new BPath(); 326 status_t ret = find_directory(dir, path); 327 if (ret != B_OK) { 328 fStatus = B_ERROR; 329 return fStatus; 330 } 331 332 parser_debug("%s\n", path->Path()); 333 334 systemPaths.AddItem(path); 335 } 336 else if (!memcmp(buffer, "PaNa", 5)) { 337 parser_debug("PaNa\n"); 338 if (fPackageFile->Read(&length, 4) != 4) { 339 fStatus = B_ERROR; 340 return fStatus; 341 } 342 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 343 // Since its a default, system path, we can ignore the path name 344 // - all information needed is beside the FDst tag. 345 fPackageFile->Seek(length, SEEK_CUR); 346 } 347 else if (!memcmp(buffer, padding, 7)) { 348 parser_debug("Padding!\n"); 349 continue; 350 } 351 else { 352 fStatus = B_ERROR; 353 return fStatus; 354 } 355 break; 356 } 357 358 case P_GROUPS_SECTION: 359 { 360 if (!memcmp(buffer, "IGrp", 5)) { 361 // Creata a new group 362 groupStarted = true; 363 group = pkg_profile(); 364 parser_debug("IGrp\n"); 365 } 366 else if (!memcmp(buffer, "GrpN", 5)) { 367 if (!groupStarted) { 368 fStatus = B_ERROR; 369 return fStatus; 370 } 371 372 parser_debug("GrpN\n"); 373 fPackageFile->Read(&length, 4); 374 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 375 376 char *name = new char[length + 1]; 377 fPackageFile->Read(name, length); 378 name[length] = 0; 379 group.name = name; 380 delete name; 381 } 382 else if (!memcmp(buffer, "GrpD", 5)) { 383 if (!groupStarted) { 384 fStatus = B_ERROR; 385 return fStatus; 386 } 387 388 parser_debug("GrpD\n"); 389 fPackageFile->Read(&length, 4); 390 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 391 392 char *desc = new char[length + 1]; 393 fPackageFile->Read(desc, length); 394 desc[length] = 0; 395 group.description = desc; 396 delete desc; 397 } 398 else if (!memcmp(buffer, "GrHt", 5)) { 399 if (!groupStarted) { 400 fStatus = B_ERROR; 401 return fStatus; 402 } 403 404 parser_debug("GrHt\n"); 405 // For now, we don't need group help 406 fPackageFile->Read(&length, 4); 407 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 408 fPackageFile->Seek(length, SEEK_CUR); 409 } 410 else if (!memcmp(buffer, padding, 5)) { 411 if (!groupStarted) { 412 parser_debug("No group - padding!\n"); 413 continue; 414 } 415 416 fProfiles.AddItem(new pkg_profile(group)); 417 parser_debug("Group added: %s %s\n", group.name.String(), 418 group.description.String()); 419 420 groupStarted = false; 421 } 422 else if (!memcmp(buffer, "GrId", 5)) { 423 uint32 id; 424 fPackageFile->Read(&id, 4); 425 swap_data(B_UINT32_TYPE, &id, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 426 427 parser_debug("GrId\n"); 428 429 if (id == 0xffffffff) 430 groups.AddItem(NULL); 431 else 432 groups.AddItem(fProfiles.ItemAt(id)); 433 } 434 else if (!memcmp(buffer, idMarker, 7) || 435 !memcmp(buffer, groupsMarker, 7)) { 436 parser_debug("Marker, jumping!\n"); 437 continue; 438 } 439 else { 440 fStatus = B_ERROR; 441 return fStatus; 442 } 443 break; 444 } 445 446 case P_LICENSE_SECTION: 447 { 448 if (!memcmp(buffer, "Lic?", 5)) { 449 parser_debug("Lic?\n"); 450 // This tag informs whether a license is present in the package 451 // or not. Since we don't care about licenses right now, just 452 // skip this section 453 fPackageFile->Seek(4, SEEK_CUR); 454 } 455 else if (!memcmp(buffer, "LicP", 5)) { 456 parser_debug("LicP\n"); 457 fPackageFile->Read(&length, 4); 458 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 459 460 fPackageFile->Seek(length, SEEK_CUR); 461 } 462 else if (!memcmp(buffer, padding, 7)) { 463 continue; 464 } 465 else if (!memcmp(buffer, descMarker, 7)) { 466 parser_debug("Description text reached\n"); 467 fPackageFile->Read(&length, 4); 468 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 469 470 char *description = new char[length + 1]; 471 fPackageFile->Read(description, length); 472 description[length] = 0; 473 fDescription = description; 474 475 // Truncate all leading newlines 476 for (i = 0;i < length;i++) 477 if (fDescription[i] != '\n') 478 break; 479 fDescription.Remove(0, i); 480 481 delete description; 482 parser_debug("Description text reached\n"); 483 484 // After this, there's a known size sequence of bytes, which meaning 485 // is yet to be determined. 486 487 // One is already known. The byte (or just its least significant bit) 488 // at offset 21 from the description text is responsible for the 489 // install folder existence information. If it is 0, there is no 490 // install folder, if it is 1 (or the least significant bit is set) 491 // it means we should install all 0xffffffff files/directories to 492 // the first directory existing in the package 493 fPackageFile->Seek(21, SEEK_CUR); 494 if (fPackageFile->Read(&installDirectoryFlag, 1) != 1) { 495 fStatus = B_ERROR; 496 return fStatus; 497 } 498 499 fPackageFile->Seek(11, SEEK_CUR); 500 } 501 else if (!memcmp(buffer, nameMarker, 7)) { 502 parser_debug("Package name reached\n"); 503 fPackageFile->Read(&length, 4); 504 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 505 506 char *name = new char[length + 1]; 507 fPackageFile->Read(name, length); 508 name[length] = 0; 509 fName = name; 510 delete name; 511 } 512 else if (!memcmp(buffer, versionMarker, 7)) { 513 parser_debug("Package version reached\n"); 514 fPackageFile->Read(&length, 4); 515 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 516 517 char *version = new char[length + 1]; 518 fPackageFile->Read(version, length); 519 version[length] = 0; 520 fVersion = version; 521 delete version; 522 } 523 else if (!memcmp(buffer, devMarker, 7)) { 524 parser_debug("Package developer reached\n"); 525 fPackageFile->Read(&length, 4); 526 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 527 528 char *dev = new char[length + 1]; 529 fPackageFile->Read(dev, length); 530 dev[length] = 0; 531 fDeveloper = dev; 532 delete dev; 533 } 534 else if (!memcmp(buffer, shortDescMarker, 7)) { 535 parser_debug("Package short description reached\n"); 536 fPackageFile->Read(&length, 4); 537 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 538 539 char *desc = new char[length + 1]; 540 fPackageFile->Read(desc, length); 541 desc[length] = 0; 542 fShortDesc = desc; 543 delete desc; 544 } 545 else if (!memcmp(buffer, helpMarker, 7)) { 546 // The help text is a stored in deflated state, preceded by a 64 bit 547 // compressed size, 64 bit inflated size and a 32 bit integer 548 // Since there was no discussion whether we need this help text, 549 // it will be skipped 550 parser_debug("Help text reached\n"); 551 //uint64 length64; 552 fPackageFile->Read(&length, 8); 553 swap_data(B_UINT64_TYPE, &length, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 554 555 fPackageFile->Seek(12 + length, SEEK_CUR); 556 } 557 break; 558 } 559 560 case P_USER_PATH_SECTION: 561 { 562 if (!memcmp(buffer, "DPat", 5)) { 563 parser_debug("DPat\n"); 564 continue; 565 } 566 else if (!memcmp(buffer, "PaNa", 5)) { 567 parser_debug("PaNa\n"); 568 fPackageFile->Read(&length, 4); 569 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 570 571 char *pathname = new char[length + 1]; 572 fPackageFile->Read(pathname, length); 573 pathname[length] = 0; 574 BString *path = new BString(pathname); 575 userPaths.AddItem(path); 576 delete pathname; 577 } 578 else if (!memcmp(buffer, padding, 7)) { 579 parser_debug("Padding!\n"); 580 continue; 581 } 582 else { 583 fStatus = B_ERROR; 584 return fStatus; 585 } 586 break; 587 } 588 } 589 } 590 591 BString nameString, mimeString, signatureString, linkString; 592 BString itemPath = "", installDirectory = ""; 593 uint32 directoryCount = 0; 594 595 uint8 element = P_NONE; 596 uint32 itemGroups = 0, path = 0, cust = 0, ctime = 0, mtime = 0, 597 platform = 0xffffffff; 598 uint64 offset = 0, size = 0, originalSize = 0, mode = 0; 599 uint8 pathType = P_INSTALL_PATH; 600 601 status_t ret; 602 603 fPackageFile->Seek(infoOffset, SEEK_SET); 604 605 // Parse package file data 606 while (1) { 607 bytesRead = fPackageFile->Read(buffer, 7); 608 if (bytesRead != 7) { 609 fStatus = B_ERROR; 610 return fStatus; 611 } 612 613 // TODO: Here's the deal... there seems to be a strange ScrI tag that 614 // seems to mean script files (check this). It seems exaclty the same 615 // as a normal file (just as script files are normal files) so for 616 // now I'm treating those as files. Check if it's correct! 617 // No, it isn't and I will fix this soon. 618 if (!memcmp(buffer, "FilI", 5) || !memcmp(buffer, "ScrI", 5)) { 619 parser_debug("FilI\n"); 620 element = P_FILE; 621 622 mimeString = ""; 623 nameString = ""; 624 signatureString = ""; 625 626 itemGroups = 0; 627 ctime = 0; 628 mtime = 0; 629 offset = 0; 630 itemGroups = 0; 631 cust = 0; 632 mode = 0; 633 platform = 0xffffffff; 634 635 size = 0; 636 originalSize = 0; 637 } 638 else if (!memcmp(buffer, "FldI", 5)) { 639 parser_debug("FldI\n"); 640 element = P_DIRECTORY; 641 642 nameString = ""; 643 644 itemGroups = 0; 645 ctime = 0; 646 mtime = 0; 647 offset = 0; 648 itemGroups = 0; 649 cust = 0; 650 platform = 0xffffffff; 651 652 size = 0; 653 originalSize = 0; 654 } 655 else if (!memcmp(buffer, "LnkI", 5)) { 656 parser_debug("LnkI\n"); 657 element = P_LINK; 658 659 nameString = ""; 660 linkString = ""; 661 662 itemGroups = 0; 663 ctime = 0; 664 mtime = 0; 665 offset = 0; 666 itemGroups = 0; 667 cust = 0; 668 platform = 0xffffffff; 669 670 size = 0; 671 originalSize = 0; 672 } 673 else if (!memcmp(buffer, "Name", 5)) { 674 if (element == P_NONE) { 675 fStatus = B_ERROR; 676 return fStatus; 677 } 678 679 parser_debug("Name\n"); 680 fPackageFile->Read(&length, 4); 681 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 682 683 char *name = new char[length + 1]; 684 fPackageFile->Read(name, length); 685 name[length] = 0; 686 687 nameString = name; 688 delete name; 689 } 690 else if (!memcmp(buffer, "Grps", 5)) { 691 if (element == P_NONE) { 692 fStatus = B_ERROR; 693 return fStatus; 694 } 695 696 parser_debug("Grps\n"); 697 fPackageFile->Read(&itemGroups, 4); 698 swap_data(B_UINT32_TYPE, &itemGroups, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 699 } 700 else if (!memcmp(buffer, "Dest", 5)) { 701 if (element == P_NONE) { 702 fStatus = B_ERROR; 703 return fStatus; 704 } 705 706 parser_debug("Dest\n"); 707 fPackageFile->Read(&path, 4); 708 swap_data(B_UINT32_TYPE, &path, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 709 } 710 else if (!memcmp(buffer, "Cust", 5)) { 711 if (element == P_NONE) { 712 fStatus = B_ERROR; 713 return fStatus; 714 } 715 716 parser_debug("Cust\n"); 717 fPackageFile->Read(&cust, 4); 718 swap_data(B_UINT32_TYPE, &cust, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 719 } 720 else if (!memcmp(buffer, "Repl", 5)) { 721 if (element == P_NONE) { 722 fStatus = B_ERROR; 723 return fStatus; 724 } 725 726 parser_debug("Repl\n"); 727 fPackageFile->Seek(4, SEEK_CUR); 728 // TODO: Should the replace philosophy depend on this flag? For now 729 // I always leave the decision to the user 730 } 731 else if (!memcmp(buffer, "Plat", 5)) { 732 if (element == P_NONE) { 733 fStatus = B_ERROR; 734 return fStatus; 735 } 736 737 parser_debug("Plat\n"); 738 fPackageFile->Read(&platform, 4); 739 swap_data(B_UINT32_TYPE, &platform, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 740 } 741 else if (!memcmp(buffer, "CTim", 5)) { 742 if (element == P_NONE) { 743 fStatus = B_ERROR; 744 return fStatus; 745 } 746 747 parser_debug("CTim\n"); 748 fPackageFile->Read(&ctime, 4); 749 swap_data(B_UINT32_TYPE, &ctime, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 750 } 751 else if (!memcmp(buffer, "MTim", 5)) { 752 if (element == P_NONE) { 753 fStatus = B_ERROR; 754 return fStatus; 755 } 756 757 parser_debug("MTim\n"); 758 fPackageFile->Read(&mtime, 4); 759 swap_data(B_UINT32_TYPE, &mtime, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 760 } 761 else if (!memcmp(buffer, "OffT", 5)) { 762 if (element == P_NONE) { 763 fStatus = B_ERROR; 764 return fStatus; 765 } 766 767 parser_debug("OffT\n"); 768 fPackageFile->Read(&offset, 8); 769 swap_data(B_UINT64_TYPE, &offset, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 770 } 771 else if (!memcmp(buffer, "Mime", 5)) { 772 if (element != P_FILE) { 773 fStatus = B_ERROR; 774 return fStatus; 775 } 776 777 fPackageFile->Read(&length, 4); 778 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 779 780 char *mime = new char[length + 1]; 781 fPackageFile->Read(mime, length); 782 mime[length] = 0; 783 parser_debug("Mime: %s\n", mime); 784 785 mimeString = mime; 786 delete mime; 787 } 788 else if (!memcmp(buffer, "CmpS", 5)) { 789 if (element == P_NONE) { 790 fStatus = B_ERROR; 791 return fStatus; 792 } 793 794 parser_debug("CmpS\n"); 795 fPackageFile->Read(&size, 8); 796 swap_data(B_UINT64_TYPE, &size, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 797 } 798 else if (!memcmp(buffer, "OrgS", 5)) { 799 if (element != P_FILE && element != P_LINK) { 800 fStatus = B_ERROR; 801 return fStatus; 802 } 803 804 parser_debug("OrgS\n"); 805 fPackageFile->Read(&originalSize, 8); 806 swap_data(B_UINT64_TYPE, &originalSize, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 807 } 808 else if (!memcmp(buffer, "VrsI", 5)) { 809 if (element != P_FILE) { 810 fStatus = B_ERROR; 811 return fStatus; 812 } 813 814 parser_debug("VrsI\n"); 815 fPackageFile->Seek(24, SEEK_CUR); 816 // TODO 817 // Also, check what those empty 20 bytes mean 818 } 819 else if (!memcmp(buffer, "Mode", 5)) { 820 if (element != P_FILE && element != P_LINK) { 821 fStatus = B_ERROR; 822 return fStatus; 823 } 824 825 parser_debug("Mode\n"); 826 fPackageFile->Read(&mode, 4); 827 swap_data(B_UINT32_TYPE, &mode, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 828 } 829 else if (!memcmp(buffer, "FDat", 5)) { 830 if (element != P_DIRECTORY) { 831 fStatus = B_ERROR; 832 return fStatus; 833 } 834 835 parser_debug("FDat\n"); 836 } 837 else if (!memcmp(buffer, "ASig", 5)) { 838 if (element != P_FILE) { 839 fStatus = B_ERROR; 840 return fStatus; 841 } 842 843 fPackageFile->Read(&length, 4); 844 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 845 846 char *signature = new char[length + 1]; 847 fPackageFile->Read(signature, length); 848 signature[length] = 0; 849 parser_debug("Signature: %s\n", signature); 850 851 signatureString = signature; 852 delete signature; 853 } 854 else if (!memcmp(buffer, "Link", 5)) { 855 if (element != P_LINK) { 856 fStatus = B_ERROR; 857 return fStatus; 858 } 859 860 fPackageFile->Read(&length, 4); 861 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 862 863 char *link = new char[length + 1]; 864 fPackageFile->Read(link, length); 865 link[length] = 0; 866 parser_debug("Link: %s\n", link); 867 868 linkString = link; 869 delete link; 870 } 871 else if (!memcmp(buffer, padding, 7)) { 872 PkgItem *item = 0; 873 874 parser_debug("Padding!\n"); 875 if (platform != 0xffffffff && 876 static_cast<platform_types>(platform) != sysinfo.platform_type) { 877 // If the file/directory/item's platform is different than the 878 // target platform (or different than the 'any' constant), ignore 879 // this file 880 } 881 else if (element == P_FILE) { 882 if (itemGroups && offset && size) { 883 BString dest = ""; 884 uint8 localType = pathType; 885 886 if (path == 0xfffffffe) 887 dest << itemPath << "/" << nameString.String(); 888 else if (path == 0xffffffff) { 889 localType = P_INSTALL_PATH; 890 dest = installDirectory; 891 dest << nameString; 892 } 893 else { 894 if (cust) { 895 BString *def = static_cast<BString *>(userPaths.ItemAt(path)); 896 if (!def) { 897 fStatus = B_ERROR; 898 return fStatus; 899 } 900 if ((*def)[0] == '/') 901 localType = P_SYSTEM_PATH; 902 else 903 localType = P_USER_PATH; 904 905 dest << *def << "/" << nameString; 906 } 907 else { 908 BPath *def = static_cast<BPath *>(systemPaths.ItemAt(path)); 909 if (!def) { 910 fStatus = B_ERROR; 911 return fStatus; 912 } 913 localType = P_SYSTEM_PATH; 914 915 dest << def->Path() << "/" << nameString; 916 } 917 } 918 919 item = new PkgFile(fPackageFile, dest, localType, ctime, mtime, 920 offset, size, originalSize, 0, mimeString, signatureString, mode); 921 parser_debug("Adding file: %s!\n", dest.String()); 922 } 923 } 924 else if (element == P_DIRECTORY) { 925 if (itemGroups) { 926 if (installDirectoryFlag != 0) { 927 if (installDirectoryFlag < 0) { // Normal directory 928 if (path == 0xfffffffe) { // Install to current directory 929 itemPath << "/" << nameString.String(); 930 directoryCount++; 931 } 932 else if (path == 0xffffffff) { // Install to install directory 933 pathType = P_INSTALL_PATH; 934 itemPath = installDirectory; 935 itemPath << nameString; 936 directoryCount = 1; 937 } 938 else { // Install to defined directory 939 if (cust) { 940 BString *def = static_cast<BString *>(userPaths.ItemAt(path)); 941 if (!def) { 942 fStatus = B_ERROR; 943 return fStatus; 944 } 945 if ((*def)[0] == '/') 946 pathType = P_SYSTEM_PATH; 947 else 948 pathType = P_USER_PATH; 949 950 itemPath = *def; 951 } 952 else { 953 BPath *def = static_cast<BPath *>(systemPaths.ItemAt(path)); 954 if (!def) { 955 fStatus = B_ERROR; 956 return fStatus; 957 } 958 pathType = P_SYSTEM_PATH; 959 960 itemPath = def->Path(); 961 } 962 963 itemPath << "/" << nameString; 964 directoryCount = 1; 965 } 966 } 967 else { // Install directory 968 if (path != 0xffffffff) { 969 fStatus = B_ERROR; 970 return fStatus; 971 } 972 973 installDirectory = nameString; 974 installDirectory << "/"; 975 pathType = P_INSTALL_PATH; 976 itemPath = nameString; 977 978 installDirectoryFlag = -1; 979 } 980 981 parser_debug("Adding the directory %s!\n", itemPath.String()); 982 item = new PkgDirectory(fPackageFile, itemPath, pathType, ctime, 983 mtime, offset, size); 984 } 985 else { 986 installDirectoryFlag = -1; 987 } 988 } 989 } 990 else if (element == P_LINK) { 991 if (itemGroups && linkString.Length()) { 992 BString dest = ""; 993 uint8 localType = pathType; 994 995 if (path == 0xfffffffe) 996 dest << itemPath << "/" << nameString.String(); 997 else if (path == 0xffffffff) { 998 localType = P_INSTALL_PATH; 999 dest = installDirectory; 1000 dest << nameString; 1001 } 1002 else { 1003 if (cust) { 1004 BString *def = static_cast<BString *>(userPaths.ItemAt(path)); 1005 if (!def) { 1006 fStatus = B_ERROR; 1007 return fStatus; 1008 } 1009 if ((*def)[0] == '/') 1010 localType = P_SYSTEM_PATH; 1011 else 1012 localType = P_USER_PATH; 1013 1014 dest << *def << "/" << nameString; 1015 } 1016 else { 1017 BPath *def = static_cast<BPath *>(systemPaths.ItemAt(path)); 1018 if (!def) { 1019 fStatus = B_ERROR; 1020 return fStatus; 1021 } 1022 localType = P_SYSTEM_PATH; 1023 1024 dest << def->Path() << "/" << nameString; 1025 } 1026 } 1027 1028 parser_debug("Adding link: %s!\n", dest.String()); 1029 item = new PkgLink(fPackageFile, dest, linkString, pathType, 1030 ctime, mtime, mode, offset, size); 1031 } 1032 } 1033 else { 1034 // If the directory tree count is equal to zero, this means all 1035 // directory trees have been closed and a padding sequence means the 1036 // end of the section 1037 if (directoryCount == 0) 1038 break; 1039 ret = itemPath.FindLast('/'); 1040 if (ret == B_ERROR) { 1041 itemPath = ""; 1042 } 1043 else { 1044 itemPath.Truncate(ret); 1045 } 1046 directoryCount--; 1047 } 1048 1049 if (item) { 1050 _AddItem(item, originalSize, itemGroups, path, cust); 1051 } 1052 1053 element = P_NONE; 1054 } 1055 else { 1056 fStatus = B_ERROR; 1057 return fStatus; 1058 } 1059 } 1060 1061 if (static_cast<uint64>(actualSize) != fileSize) { 1062 // Inform the user of a possible error 1063 int32 selection; 1064 BAlert *warning = new BAlert(T("filesize_wrong"), 1065 T("There seems to be a filesize mismatch in the package file. " 1066 "The package might be corrupted or have been modified after its " 1067 "creation. Do you still wish to continue?"), T("Yes"), T("No"), NULL, 1068 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 1069 selection = warning->Go(); 1070 1071 if (selection == 1) { 1072 fStatus = B_ERROR; 1073 return fStatus; 1074 } 1075 } 1076 1077 if (!groups.IsEmpty()) 1078 fProfiles = groups; 1079 1080 return B_OK; 1081 } 1082 1083 1084 void 1085 PackageInfo::_AddItem(PkgItem *item, uint64 size, uint32 groups, uint32 path, 1086 uint32 cust) 1087 { 1088 // Add the item to all groups it resides in 1089 uint32 i, n = fProfiles.CountItems(), mask = 1; 1090 pkg_profile *profile; 1091 1092 for (i = 0;i < n;i++) { 1093 if (groups & mask) { 1094 profile = static_cast<pkg_profile *>(fProfiles.ItemAt(i)); 1095 profile->items.AddItem(item); 1096 profile->space_needed += size; 1097 // If there is at least one non-predefined destination element 1098 // in the package, we give the user the ability to select the 1099 // installation directory. 1100 // If there are only predefined path files in the package, but 1101 // such defined by the user, the user will be able to select 1102 // the destination volume 1103 if (path == 0xffffffff) 1104 profile->path_type = P_INSTALL_PATH; 1105 else if (path < 0xfffffffe && 1106 profile->path_type != P_INSTALL_PATH) { 1107 if (cust) { 1108 profile->path_type = P_USER_PATH; 1109 } 1110 } 1111 } 1112 mask = mask << 1; 1113 } 1114 } 1115 1116 1117 // #pragma mark - 1118 1119 1120 pkg_profile::~pkg_profile() 1121 { 1122 PkgItem *iter = 0; 1123 while (1) { 1124 iter = static_cast<PkgItem *>(items.RemoveItem((long int)0)); 1125 if (iter) 1126 delete iter; 1127 else 1128 break; 1129 } 1130 } 1131 1132