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