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