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