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