1 /* 2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <package/hpkg/WriterImplBase.h> 8 9 #include <errno.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 15 #include <algorithm> 16 #include <new> 17 18 #include <ByteOrder.h> 19 #include <File.h> 20 21 #include <AutoDeleter.h> 22 #include <ZlibCompressionAlgorithm.h> 23 #ifdef ZSTD_ENABLED 24 #include <ZstdCompressionAlgorithm.h> 25 #endif 26 27 #include <package/hpkg/DataReader.h> 28 #include <package/hpkg/ErrorOutput.h> 29 30 #include <package/hpkg/HPKGDefsPrivate.h> 31 32 33 namespace BPackageKit { 34 35 namespace BHPKG { 36 37 namespace BPrivate { 38 39 40 // #pragma mark - AttributeValue 41 42 43 WriterImplBase::AttributeValue::AttributeValue() 44 : 45 type(B_HPKG_ATTRIBUTE_TYPE_INVALID), 46 encoding(-1) 47 { 48 } 49 50 51 WriterImplBase::AttributeValue::~AttributeValue() 52 { 53 } 54 55 56 void 57 WriterImplBase::AttributeValue::SetTo(int8 value) 58 { 59 signedInt = value; 60 type = B_HPKG_ATTRIBUTE_TYPE_INT; 61 } 62 63 64 void 65 WriterImplBase::AttributeValue::SetTo(uint8 value) 66 { 67 unsignedInt = value; 68 type = B_HPKG_ATTRIBUTE_TYPE_UINT; 69 } 70 71 72 void 73 WriterImplBase::AttributeValue::SetTo(int16 value) 74 { 75 signedInt = value; 76 type = B_HPKG_ATTRIBUTE_TYPE_INT; 77 } 78 79 80 void 81 WriterImplBase::AttributeValue::SetTo(uint16 value) 82 { 83 unsignedInt = value; 84 type = B_HPKG_ATTRIBUTE_TYPE_UINT; 85 } 86 87 88 void 89 WriterImplBase::AttributeValue::SetTo(int32 value) 90 { 91 signedInt = value; 92 type = B_HPKG_ATTRIBUTE_TYPE_INT; 93 } 94 95 96 void 97 WriterImplBase::AttributeValue::SetTo(uint32 value) 98 { 99 unsignedInt = value; 100 type = B_HPKG_ATTRIBUTE_TYPE_UINT; 101 } 102 103 104 void 105 WriterImplBase::AttributeValue::SetTo(int64 value) 106 { 107 signedInt = value; 108 type = B_HPKG_ATTRIBUTE_TYPE_INT; 109 } 110 111 112 void 113 WriterImplBase::AttributeValue::SetTo(uint64 value) 114 { 115 unsignedInt = value; 116 type = B_HPKG_ATTRIBUTE_TYPE_UINT; 117 } 118 119 120 void 121 WriterImplBase::AttributeValue::SetTo(CachedString* value) 122 { 123 string = value; 124 type = B_HPKG_ATTRIBUTE_TYPE_STRING; 125 } 126 127 128 void 129 WriterImplBase::AttributeValue::SetToData(uint64 size, uint64 offset) 130 { 131 data.size = size; 132 data.offset = offset; 133 type = B_HPKG_ATTRIBUTE_TYPE_RAW; 134 encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP; 135 } 136 137 138 void 139 WriterImplBase::AttributeValue::SetToData(uint64 size, const void* rawData) 140 { 141 data.size = size; 142 if (size > 0) 143 memcpy(data.raw, rawData, size); 144 type = B_HPKG_ATTRIBUTE_TYPE_RAW; 145 encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE; 146 } 147 148 149 uint8 150 WriterImplBase::AttributeValue::ApplicableEncoding() const 151 { 152 switch (type) { 153 case B_HPKG_ATTRIBUTE_TYPE_INT: 154 return _ApplicableIntEncoding(signedInt >= 0 155 ? (uint64)signedInt << 1 156 : (uint64)(-(signedInt + 1) << 1)); 157 case B_HPKG_ATTRIBUTE_TYPE_UINT: 158 return _ApplicableIntEncoding(unsignedInt); 159 case B_HPKG_ATTRIBUTE_TYPE_STRING: 160 return string->index >= 0 161 ? B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE 162 : B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE; 163 case B_HPKG_ATTRIBUTE_TYPE_RAW: 164 return encoding; 165 default: 166 return 0; 167 } 168 } 169 170 171 /*static*/ uint8 172 WriterImplBase::AttributeValue::_ApplicableIntEncoding(uint64 value) 173 { 174 if (value <= 0xff) 175 return B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT; 176 if (value <= 0xffff) 177 return B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT; 178 if (value <= 0xffffffff) 179 return B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT; 180 181 return B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT; 182 } 183 184 185 // #pragma mark - PackageAttribute 186 187 188 WriterImplBase::PackageAttribute::PackageAttribute(BHPKGAttributeID id_, 189 uint8 type_, uint8 encoding_) 190 : 191 id(id_) 192 { 193 type = type_; 194 encoding = encoding_; 195 } 196 197 198 WriterImplBase::PackageAttribute::~PackageAttribute() 199 { 200 _DeleteChildren(); 201 } 202 203 204 void 205 WriterImplBase::PackageAttribute::AddChild(PackageAttribute* child) 206 { 207 children.Add(child); 208 } 209 210 211 void 212 WriterImplBase::PackageAttribute::_DeleteChildren() 213 { 214 while (PackageAttribute* child = children.RemoveHead()) 215 delete child; 216 } 217 218 219 // #pragma mark - WriterImplBase 220 221 222 WriterImplBase::WriterImplBase(const char* fileType, BErrorOutput* errorOutput) 223 : 224 fHeapWriter(NULL), 225 fCompressionAlgorithm(NULL), 226 fCompressionParameters(NULL), 227 fDecompressionAlgorithm(NULL), 228 fDecompressionParameters(NULL), 229 fFileType(fileType), 230 fErrorOutput(errorOutput), 231 fFileName(NULL), 232 fParameters(), 233 fFile(NULL), 234 fOwnsFile(false), 235 fFinished(false) 236 { 237 } 238 239 240 WriterImplBase::~WriterImplBase() 241 { 242 delete fHeapWriter; 243 delete fCompressionAlgorithm; 244 delete fCompressionParameters; 245 delete fDecompressionAlgorithm; 246 delete fDecompressionParameters; 247 248 if (fOwnsFile) 249 delete fFile; 250 251 if (!fFinished && fFileName != NULL 252 && (Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) == 0) { 253 unlink(fFileName); 254 } 255 } 256 257 258 status_t 259 WriterImplBase::Init(BPositionIO* file, bool keepFile, const char* fileName, 260 const BPackageWriterParameters& parameters) 261 { 262 fParameters = parameters; 263 264 if (fPackageStringCache.Init() != B_OK) 265 throw std::bad_alloc(); 266 267 if (file == NULL) { 268 if (fileName == NULL) 269 return B_BAD_VALUE; 270 271 // open file (don't truncate in update mode) 272 int openMode = O_RDWR; 273 if ((parameters.Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) == 0) 274 openMode |= O_CREAT | O_TRUNC; 275 276 BFile* newFile = new BFile; 277 status_t error = newFile->SetTo(fileName, openMode); 278 if (error != B_OK) { 279 fErrorOutput->PrintError("Failed to open %s file \"%s\": %s\n", 280 fFileType, fileName, strerror(errno)); 281 delete newFile; 282 return error; 283 } 284 285 fFile = newFile; 286 fOwnsFile = true; 287 } else { 288 fFile = file; 289 fOwnsFile = keepFile; 290 } 291 292 fFileName = fileName; 293 294 return B_OK; 295 } 296 297 298 status_t 299 WriterImplBase::InitHeapReader(size_t headerSize) 300 { 301 // allocate the compression/decompression algorithm 302 CompressionAlgorithmOwner* compressionAlgorithm = NULL; 303 BReference<CompressionAlgorithmOwner> compressionAlgorithmReference; 304 305 DecompressionAlgorithmOwner* decompressionAlgorithm = NULL; 306 BReference<DecompressionAlgorithmOwner> decompressionAlgorithmReference; 307 308 switch (fParameters.Compression()) { 309 case B_HPKG_COMPRESSION_NONE: 310 break; 311 case B_HPKG_COMPRESSION_ZLIB: 312 compressionAlgorithm = CompressionAlgorithmOwner::Create( 313 new(std::nothrow) BZlibCompressionAlgorithm, 314 new(std::nothrow) BZlibCompressionParameters( 315 fParameters.CompressionLevel())); 316 compressionAlgorithmReference.SetTo(compressionAlgorithm, true); 317 318 decompressionAlgorithm = DecompressionAlgorithmOwner::Create( 319 new(std::nothrow) BZlibCompressionAlgorithm, 320 new(std::nothrow) BZlibDecompressionParameters); 321 decompressionAlgorithmReference.SetTo(decompressionAlgorithm, true); 322 323 if (compressionAlgorithm == NULL 324 || compressionAlgorithm->algorithm == NULL 325 || compressionAlgorithm->parameters == NULL 326 || decompressionAlgorithm == NULL 327 || decompressionAlgorithm->algorithm == NULL 328 || decompressionAlgorithm->parameters == NULL) { 329 throw std::bad_alloc(); 330 } 331 break; 332 #ifdef ZSTD_ENABLED 333 case B_HPKG_COMPRESSION_ZSTD: 334 compressionAlgorithm = CompressionAlgorithmOwner::Create( 335 new(std::nothrow) BZstdCompressionAlgorithm, 336 new(std::nothrow) BZstdCompressionParameters( 337 fParameters.CompressionLevel())); 338 compressionAlgorithmReference.SetTo(compressionAlgorithm, true); 339 340 decompressionAlgorithm = DecompressionAlgorithmOwner::Create( 341 new(std::nothrow) BZstdCompressionAlgorithm, 342 new(std::nothrow) BZstdDecompressionParameters); 343 decompressionAlgorithmReference.SetTo(decompressionAlgorithm, true); 344 345 if (compressionAlgorithm == NULL 346 || compressionAlgorithm->algorithm == NULL 347 || compressionAlgorithm->parameters == NULL 348 || decompressionAlgorithm == NULL 349 || decompressionAlgorithm->algorithm == NULL 350 || decompressionAlgorithm->parameters == NULL) { 351 throw std::bad_alloc(); 352 } 353 break; 354 #endif 355 default: 356 fErrorOutput->PrintError("Error: Invalid heap compression\n"); 357 return B_BAD_VALUE; 358 } 359 360 // create heap writer 361 fHeapWriter = new PackageFileHeapWriter(fErrorOutput, fFile, headerSize, 362 compressionAlgorithm, decompressionAlgorithm); 363 fHeapWriter->Init(); 364 365 return B_OK; 366 } 367 368 369 void 370 WriterImplBase::SetCompression(uint32 compression) 371 { 372 fParameters.SetCompression(compression); 373 } 374 375 376 void 377 WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList, 378 const BPackageInfo& packageInfo) 379 { 380 // name 381 AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_NAME, packageInfo.Name(), 382 attributeList); 383 384 // summary 385 AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_SUMMARY, 386 packageInfo.Summary(), attributeList); 387 388 // description 389 AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_DESCRIPTION, 390 packageInfo.Description(), attributeList); 391 392 // vendor 393 AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_VENDOR, 394 packageInfo.Vendor(), attributeList); 395 396 // packager 397 AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_PACKAGER, 398 packageInfo.Packager(), attributeList); 399 400 // base package (optional) 401 _AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_BASE_PACKAGE, 402 packageInfo.BasePackage(), attributeList); 403 404 // flags 405 PackageAttribute* flags = new PackageAttribute( 406 B_HPKG_ATTRIBUTE_ID_PACKAGE_FLAGS, B_HPKG_ATTRIBUTE_TYPE_UINT, 407 B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT); 408 flags->unsignedInt = packageInfo.Flags(); 409 attributeList.Add(flags); 410 411 // architecture 412 PackageAttribute* architecture = new PackageAttribute( 413 B_HPKG_ATTRIBUTE_ID_PACKAGE_ARCHITECTURE, B_HPKG_ATTRIBUTE_TYPE_UINT, 414 B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); 415 architecture->unsignedInt = packageInfo.Architecture(); 416 attributeList.Add(architecture); 417 418 // version 419 RegisterPackageVersion(attributeList, packageInfo.Version()); 420 421 // copyright list 422 _AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT, 423 packageInfo.CopyrightList(), attributeList); 424 425 // license list 426 _AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE, 427 packageInfo.LicenseList(), attributeList); 428 429 // URL list 430 _AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_URL, 431 packageInfo.URLList(), attributeList); 432 433 // source URL list 434 _AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL, 435 packageInfo.SourceURLList(), attributeList); 436 437 // provides list 438 const BObjectList<BPackageResolvable>& providesList 439 = packageInfo.ProvidesList(); 440 for (int i = 0; i < providesList.CountItems(); ++i) { 441 BPackageResolvable* resolvable = providesList.ItemAt(i); 442 bool hasVersion = resolvable->Version().InitCheck() == B_OK; 443 bool hasCompatibleVersion 444 = resolvable->CompatibleVersion().InitCheck() == B_OK; 445 446 PackageAttribute* provides = AddStringAttribute( 447 B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES, resolvable->Name(), 448 attributeList); 449 450 if (hasVersion) 451 RegisterPackageVersion(provides->children, resolvable->Version()); 452 453 if (hasCompatibleVersion) { 454 RegisterPackageVersion(provides->children, 455 resolvable->CompatibleVersion(), 456 B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE); 457 } 458 } 459 460 // requires list 461 RegisterPackageResolvableExpressionList(attributeList, 462 packageInfo.RequiresList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES); 463 464 // supplements list 465 RegisterPackageResolvableExpressionList(attributeList, 466 packageInfo.SupplementsList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS); 467 468 // conflicts list 469 RegisterPackageResolvableExpressionList(attributeList, 470 packageInfo.ConflictsList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS); 471 472 // freshens list 473 RegisterPackageResolvableExpressionList(attributeList, 474 packageInfo.FreshensList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS); 475 476 // replaces list 477 _AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES, 478 packageInfo.ReplacesList(), attributeList); 479 480 // global writable file info list 481 const BObjectList<BGlobalWritableFileInfo>& globalWritableFileInfos 482 = packageInfo.GlobalWritableFileInfos(); 483 for (int32 i = 0; i < globalWritableFileInfos.CountItems(); ++i) { 484 BGlobalWritableFileInfo* info = globalWritableFileInfos.ItemAt(i); 485 PackageAttribute* attribute = AddStringAttribute( 486 B_HPKG_ATTRIBUTE_ID_PACKAGE_GLOBAL_WRITABLE_FILE, info->Path(), 487 attributeList); 488 489 if (info->IsDirectory()) { 490 PackageAttribute* isDirectoryAttribute = new PackageAttribute( 491 B_HPKG_ATTRIBUTE_ID_PACKAGE_IS_WRITABLE_DIRECTORY, 492 B_HPKG_ATTRIBUTE_TYPE_UINT, 493 B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); 494 isDirectoryAttribute->unsignedInt = 1; 495 attribute->children.Add(isDirectoryAttribute); 496 } 497 498 if (info->IsIncluded()) { 499 PackageAttribute* updateTypeAttribute = new PackageAttribute( 500 B_HPKG_ATTRIBUTE_ID_PACKAGE_WRITABLE_FILE_UPDATE_TYPE, 501 B_HPKG_ATTRIBUTE_TYPE_UINT, 502 B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); 503 updateTypeAttribute->unsignedInt = info->UpdateType(); 504 attribute->children.Add(updateTypeAttribute); 505 } 506 } 507 508 // user settings file info list 509 const BObjectList<BUserSettingsFileInfo>& userSettingsFileInfos 510 = packageInfo.UserSettingsFileInfos(); 511 for (int32 i = 0; i < userSettingsFileInfos.CountItems(); ++i) { 512 BUserSettingsFileInfo* info = userSettingsFileInfos.ItemAt(i); 513 PackageAttribute* attribute = AddStringAttribute( 514 B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_SETTINGS_FILE, info->Path(), 515 attributeList); 516 517 if (info->IsDirectory()) { 518 PackageAttribute* isDirectoryAttribute = new PackageAttribute( 519 B_HPKG_ATTRIBUTE_ID_PACKAGE_IS_WRITABLE_DIRECTORY, 520 B_HPKG_ATTRIBUTE_TYPE_UINT, 521 B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); 522 isDirectoryAttribute->unsignedInt = 1; 523 attribute->children.Add(isDirectoryAttribute); 524 } else { 525 _AddStringAttributeIfNotEmpty( 526 B_HPKG_ATTRIBUTE_ID_PACKAGE_SETTINGS_FILE_TEMPLATE, 527 info->TemplatePath(), attribute->children); 528 } 529 } 530 531 // user list 532 const BObjectList<BUser>& users = packageInfo.Users(); 533 for (int32 i = 0; i < users.CountItems(); ++i) { 534 const BUser* user = users.ItemAt(i); 535 PackageAttribute* attribute = AddStringAttribute( 536 B_HPKG_ATTRIBUTE_ID_PACKAGE_USER, user->Name(), attributeList); 537 538 _AddStringAttributeIfNotEmpty( 539 B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_REAL_NAME, user->RealName(), 540 attribute->children); 541 _AddStringAttributeIfNotEmpty( 542 B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_HOME, user->Home(), 543 attribute->children); 544 _AddStringAttributeIfNotEmpty( 545 B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_SHELL, user->Shell(), 546 attribute->children); 547 548 for (int32 k = 0; k < user->Groups().CountStrings(); k++) { 549 AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_GROUP, 550 user->Groups().StringAt(k), attribute->children); 551 } 552 } 553 554 // group list 555 _AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_GROUP, 556 packageInfo.Groups(), attributeList); 557 558 // post install script list 559 _AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_POST_INSTALL_SCRIPT, 560 packageInfo.PostInstallScripts(), attributeList); 561 562 // pre uninstall script list 563 _AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_PRE_UNINSTALL_SCRIPT, 564 packageInfo.PreUninstallScripts(), attributeList); 565 566 // checksum (optional, only exists in repositories) 567 _AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM, 568 packageInfo.Checksum(), attributeList); 569 570 // install path (optional) 571 _AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH, 572 packageInfo.InstallPath(), attributeList); 573 } 574 575 576 void 577 WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList, 578 const BPackageVersion& version, BHPKGAttributeID attributeID) 579 { 580 PackageAttribute* versionMajor = AddStringAttribute(attributeID, 581 version.Major(), attributeList); 582 583 if (!version.Minor().IsEmpty()) { 584 AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR, 585 version.Minor(), versionMajor->children); 586 _AddStringAttributeIfNotEmpty( 587 B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO, version.Micro(), 588 versionMajor->children); 589 } 590 591 _AddStringAttributeIfNotEmpty( 592 B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE, 593 version.PreRelease(), versionMajor->children); 594 595 if (version.Revision() != 0) { 596 PackageAttribute* versionRevision = new PackageAttribute( 597 B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION, 598 B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT); 599 versionRevision->unsignedInt = version.Revision(); 600 versionMajor->children.Add(versionRevision); 601 } 602 } 603 604 605 void 606 WriterImplBase::RegisterPackageResolvableExpressionList( 607 PackageAttributeList& attributeList, 608 const BObjectList<BPackageResolvableExpression>& expressionList, uint8 id) 609 { 610 for (int i = 0; i < expressionList.CountItems(); ++i) { 611 BPackageResolvableExpression* resolvableExpr = expressionList.ItemAt(i); 612 PackageAttribute* name = AddStringAttribute((BHPKGAttributeID)id, 613 resolvableExpr->Name(), attributeList); 614 615 if (resolvableExpr->Version().InitCheck() == B_OK) { 616 PackageAttribute* op = new PackageAttribute( 617 B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR, 618 B_HPKG_ATTRIBUTE_TYPE_UINT, 619 B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); 620 op->unsignedInt = resolvableExpr->Operator(); 621 name->children.Add(op); 622 RegisterPackageVersion(name->children, resolvableExpr->Version()); 623 } 624 } 625 } 626 627 628 WriterImplBase::PackageAttribute* 629 WriterImplBase::AddStringAttribute(BHPKGAttributeID id, const BString& value, 630 DoublyLinkedList<PackageAttribute>& list) 631 { 632 PackageAttribute* attribute = new PackageAttribute(id, 633 B_HPKG_ATTRIBUTE_TYPE_STRING, B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); 634 attribute->string = fPackageStringCache.Get(value); 635 list.Add(attribute); 636 return attribute; 637 } 638 639 640 int32 641 WriterImplBase::WriteCachedStrings(const StringCache& cache, 642 uint32 minUsageCount) 643 { 644 // create an array of the cached strings 645 int32 count = cache.CountElements(); 646 CachedString** cachedStrings = new CachedString*[count]; 647 ArrayDeleter<CachedString*> cachedStringsDeleter(cachedStrings); 648 649 int32 index = 0; 650 for (CachedStringTable::Iterator it = cache.GetIterator(); 651 CachedString* string = it.Next();) { 652 cachedStrings[index++] = string; 653 } 654 655 // sort it by descending usage count 656 std::sort(cachedStrings, cachedStrings + count, CachedStringUsageGreater()); 657 658 // assign the indices and write entries to disk 659 int32 stringsWritten = 0; 660 for (int32 i = 0; i < count; i++) { 661 CachedString* cachedString = cachedStrings[i]; 662 663 // empty strings must be stored inline, as they can't be distinguished 664 // from the end-marker! 665 if (strlen(cachedString->string) == 0) 666 continue; 667 668 // strings that are used only once are better stored inline 669 if (cachedString->usageCount < minUsageCount) 670 break; 671 672 WriteString(cachedString->string); 673 674 cachedString->index = stringsWritten++; 675 } 676 677 // write a terminating 0 byte 678 Write<uint8>(0); 679 680 return stringsWritten; 681 } 682 683 684 int32 685 WriterImplBase::WritePackageAttributes( 686 const PackageAttributeList& packageAttributes, 687 uint32& _stringsLengthUncompressed) 688 { 689 // write the cached strings 690 uint64 startOffset = fHeapWriter->UncompressedHeapSize(); 691 uint32 stringsCount = WriteCachedStrings(fPackageStringCache, 2); 692 _stringsLengthUncompressed 693 = fHeapWriter->UncompressedHeapSize() - startOffset; 694 695 _WritePackageAttributes(packageAttributes); 696 697 return stringsCount; 698 } 699 700 701 void 702 WriterImplBase::WriteAttributeValue(const AttributeValue& value, uint8 encoding) 703 { 704 switch (value.type) { 705 case B_HPKG_ATTRIBUTE_TYPE_INT: 706 case B_HPKG_ATTRIBUTE_TYPE_UINT: 707 { 708 uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT 709 ? (uint64)value.signedInt : value.unsignedInt; 710 711 switch (encoding) { 712 case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: 713 Write<uint8>((uint8)intValue); 714 break; 715 case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: 716 Write<uint16>( 717 B_HOST_TO_BENDIAN_INT16((uint16)intValue)); 718 break; 719 case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: 720 Write<uint32>( 721 B_HOST_TO_BENDIAN_INT32((uint32)intValue)); 722 break; 723 case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: 724 Write<uint64>( 725 B_HOST_TO_BENDIAN_INT64((uint64)intValue)); 726 break; 727 default: 728 { 729 fErrorOutput->PrintError("WriteAttributeValue(): invalid " 730 "encoding %d for int value type %d\n", encoding, 731 value.type); 732 throw status_t(B_BAD_VALUE); 733 } 734 } 735 736 break; 737 } 738 739 case B_HPKG_ATTRIBUTE_TYPE_STRING: 740 { 741 if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) 742 WriteUnsignedLEB128(value.string->index); 743 else 744 WriteString(value.string->string); 745 break; 746 } 747 748 case B_HPKG_ATTRIBUTE_TYPE_RAW: 749 { 750 WriteUnsignedLEB128(value.data.size); 751 if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) 752 WriteUnsignedLEB128(value.data.offset); 753 else 754 fHeapWriter->AddDataThrows(value.data.raw, value.data.size); 755 break; 756 } 757 758 default: 759 fErrorOutput->PrintError( 760 "WriteAttributeValue(): invalid value type: %d\n", value.type); 761 throw status_t(B_BAD_VALUE); 762 } 763 } 764 765 766 void 767 WriterImplBase::WriteUnsignedLEB128(uint64 value) 768 { 769 uint8 bytes[10]; 770 int32 count = 0; 771 do { 772 uint8 byte = value & 0x7f; 773 value >>= 7; 774 bytes[count++] = byte | (value != 0 ? 0x80 : 0); 775 } while (value != 0); 776 777 fHeapWriter->AddDataThrows(bytes, count); 778 } 779 780 781 void 782 WriterImplBase::RawWriteBuffer(const void* buffer, size_t size, off_t offset) 783 { 784 status_t error = fFile->WriteAtExactly(offset, buffer, size); 785 if (error != B_OK) { 786 fErrorOutput->PrintError( 787 "RawWriteBuffer(%p, %lu) failed to write data: %s\n", buffer, size, 788 strerror(error)); 789 throw error; 790 } 791 } 792 793 794 void 795 WriterImplBase::_AddStringAttributeList(BHPKGAttributeID id, 796 const BStringList& value, DoublyLinkedList<PackageAttribute>& list) 797 { 798 for (int32 i = 0; i < value.CountStrings(); i++) 799 AddStringAttribute(id, value.StringAt(i), list); 800 } 801 802 803 void 804 WriterImplBase::_WritePackageAttributes( 805 const PackageAttributeList& packageAttributes) 806 { 807 DoublyLinkedList<PackageAttribute>::ConstIterator it 808 = packageAttributes.GetIterator(); 809 while (PackageAttribute* attribute = it.Next()) { 810 uint8 encoding = attribute->ApplicableEncoding(); 811 812 // write tag 813 WriteUnsignedLEB128(compose_attribute_tag( 814 attribute->id, attribute->type, encoding, 815 !attribute->children.IsEmpty())); 816 817 // write value 818 WriteAttributeValue(*attribute, encoding); 819 820 if (!attribute->children.IsEmpty()) 821 _WritePackageAttributes(attribute->children); 822 } 823 824 WriteUnsignedLEB128(0); 825 } 826 827 828 } // namespace BPrivate 829 830 } // namespace BHPKG 831 832 } // namespace BPackageKit 833