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 // checksum (optional, only exists in repositories) 563 _AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM, 564 packageInfo.Checksum(), attributeList); 565 566 // install path (optional) 567 _AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH, 568 packageInfo.InstallPath(), attributeList); 569 } 570 571 572 void 573 WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList, 574 const BPackageVersion& version, BHPKGAttributeID attributeID) 575 { 576 PackageAttribute* versionMajor = AddStringAttribute(attributeID, 577 version.Major(), attributeList); 578 579 if (!version.Minor().IsEmpty()) { 580 AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR, 581 version.Minor(), versionMajor->children); 582 _AddStringAttributeIfNotEmpty( 583 B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO, version.Micro(), 584 versionMajor->children); 585 } 586 587 _AddStringAttributeIfNotEmpty( 588 B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE, 589 version.PreRelease(), versionMajor->children); 590 591 if (version.Revision() != 0) { 592 PackageAttribute* versionRevision = new PackageAttribute( 593 B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION, 594 B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT); 595 versionRevision->unsignedInt = version.Revision(); 596 versionMajor->children.Add(versionRevision); 597 } 598 } 599 600 601 void 602 WriterImplBase::RegisterPackageResolvableExpressionList( 603 PackageAttributeList& attributeList, 604 const BObjectList<BPackageResolvableExpression>& expressionList, uint8 id) 605 { 606 for (int i = 0; i < expressionList.CountItems(); ++i) { 607 BPackageResolvableExpression* resolvableExpr = expressionList.ItemAt(i); 608 PackageAttribute* name = AddStringAttribute((BHPKGAttributeID)id, 609 resolvableExpr->Name(), attributeList); 610 611 if (resolvableExpr->Version().InitCheck() == B_OK) { 612 PackageAttribute* op = new PackageAttribute( 613 B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR, 614 B_HPKG_ATTRIBUTE_TYPE_UINT, 615 B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); 616 op->unsignedInt = resolvableExpr->Operator(); 617 name->children.Add(op); 618 RegisterPackageVersion(name->children, resolvableExpr->Version()); 619 } 620 } 621 } 622 623 624 WriterImplBase::PackageAttribute* 625 WriterImplBase::AddStringAttribute(BHPKGAttributeID id, const BString& value, 626 DoublyLinkedList<PackageAttribute>& list) 627 { 628 PackageAttribute* attribute = new PackageAttribute(id, 629 B_HPKG_ATTRIBUTE_TYPE_STRING, B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); 630 attribute->string = fPackageStringCache.Get(value); 631 list.Add(attribute); 632 return attribute; 633 } 634 635 636 int32 637 WriterImplBase::WriteCachedStrings(const StringCache& cache, 638 uint32 minUsageCount) 639 { 640 // create an array of the cached strings 641 int32 count = cache.CountElements(); 642 CachedString** cachedStrings = new CachedString*[count]; 643 ArrayDeleter<CachedString*> cachedStringsDeleter(cachedStrings); 644 645 int32 index = 0; 646 for (CachedStringTable::Iterator it = cache.GetIterator(); 647 CachedString* string = it.Next();) { 648 cachedStrings[index++] = string; 649 } 650 651 // sort it by descending usage count 652 std::sort(cachedStrings, cachedStrings + count, CachedStringUsageGreater()); 653 654 // assign the indices and write entries to disk 655 int32 stringsWritten = 0; 656 for (int32 i = 0; i < count; i++) { 657 CachedString* cachedString = cachedStrings[i]; 658 659 // empty strings must be stored inline, as they can't be distinguished 660 // from the end-marker! 661 if (strlen(cachedString->string) == 0) 662 continue; 663 664 // strings that are used only once are better stored inline 665 if (cachedString->usageCount < minUsageCount) 666 break; 667 668 WriteString(cachedString->string); 669 670 cachedString->index = stringsWritten++; 671 } 672 673 // write a terminating 0 byte 674 Write<uint8>(0); 675 676 return stringsWritten; 677 } 678 679 680 int32 681 WriterImplBase::WritePackageAttributes( 682 const PackageAttributeList& packageAttributes, 683 uint32& _stringsLengthUncompressed) 684 { 685 // write the cached strings 686 uint64 startOffset = fHeapWriter->UncompressedHeapSize(); 687 uint32 stringsCount = WriteCachedStrings(fPackageStringCache, 2); 688 _stringsLengthUncompressed 689 = fHeapWriter->UncompressedHeapSize() - startOffset; 690 691 _WritePackageAttributes(packageAttributes); 692 693 return stringsCount; 694 } 695 696 697 void 698 WriterImplBase::WriteAttributeValue(const AttributeValue& value, uint8 encoding) 699 { 700 switch (value.type) { 701 case B_HPKG_ATTRIBUTE_TYPE_INT: 702 case B_HPKG_ATTRIBUTE_TYPE_UINT: 703 { 704 uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT 705 ? (uint64)value.signedInt : value.unsignedInt; 706 707 switch (encoding) { 708 case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: 709 Write<uint8>((uint8)intValue); 710 break; 711 case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: 712 Write<uint16>( 713 B_HOST_TO_BENDIAN_INT16((uint16)intValue)); 714 break; 715 case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: 716 Write<uint32>( 717 B_HOST_TO_BENDIAN_INT32((uint32)intValue)); 718 break; 719 case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: 720 Write<uint64>( 721 B_HOST_TO_BENDIAN_INT64((uint64)intValue)); 722 break; 723 default: 724 { 725 fErrorOutput->PrintError("WriteAttributeValue(): invalid " 726 "encoding %d for int value type %d\n", encoding, 727 value.type); 728 throw status_t(B_BAD_VALUE); 729 } 730 } 731 732 break; 733 } 734 735 case B_HPKG_ATTRIBUTE_TYPE_STRING: 736 { 737 if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) 738 WriteUnsignedLEB128(value.string->index); 739 else 740 WriteString(value.string->string); 741 break; 742 } 743 744 case B_HPKG_ATTRIBUTE_TYPE_RAW: 745 { 746 WriteUnsignedLEB128(value.data.size); 747 if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) 748 WriteUnsignedLEB128(value.data.offset); 749 else 750 fHeapWriter->AddDataThrows(value.data.raw, value.data.size); 751 break; 752 } 753 754 default: 755 fErrorOutput->PrintError( 756 "WriteAttributeValue(): invalid value type: %d\n", value.type); 757 throw status_t(B_BAD_VALUE); 758 } 759 } 760 761 762 void 763 WriterImplBase::WriteUnsignedLEB128(uint64 value) 764 { 765 uint8 bytes[10]; 766 int32 count = 0; 767 do { 768 uint8 byte = value & 0x7f; 769 value >>= 7; 770 bytes[count++] = byte | (value != 0 ? 0x80 : 0); 771 } while (value != 0); 772 773 fHeapWriter->AddDataThrows(bytes, count); 774 } 775 776 777 void 778 WriterImplBase::RawWriteBuffer(const void* buffer, size_t size, off_t offset) 779 { 780 status_t error = fFile->WriteAtExactly(offset, buffer, size); 781 if (error != B_OK) { 782 fErrorOutput->PrintError( 783 "RawWriteBuffer(%p, %lu) failed to write data: %s\n", buffer, size, 784 strerror(error)); 785 throw error; 786 } 787 } 788 789 790 void 791 WriterImplBase::_AddStringAttributeList(BHPKGAttributeID id, 792 const BStringList& value, DoublyLinkedList<PackageAttribute>& list) 793 { 794 for (int32 i = 0; i < value.CountStrings(); i++) 795 AddStringAttribute(id, value.StringAt(i), list); 796 } 797 798 799 void 800 WriterImplBase::_WritePackageAttributes( 801 const PackageAttributeList& packageAttributes) 802 { 803 DoublyLinkedList<PackageAttribute>::ConstIterator it 804 = packageAttributes.GetIterator(); 805 while (PackageAttribute* attribute = it.Next()) { 806 uint8 encoding = attribute->ApplicableEncoding(); 807 808 // write tag 809 WriteUnsignedLEB128(compose_attribute_tag( 810 attribute->id, attribute->type, encoding, 811 !attribute->children.IsEmpty())); 812 813 // write value 814 WriteAttributeValue(*attribute, encoding); 815 816 if (!attribute->children.IsEmpty()) 817 _WritePackageAttributes(attribute->children); 818 } 819 820 WriteUnsignedLEB128(0); 821 } 822 823 824 } // namespace BPrivate 825 826 } // namespace BHPKG 827 828 } // namespace BPackageKit 829