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