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