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