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 fFlags(0), 318 fFD(-1), 319 fFinished(false), 320 fDataWriter(NULL) 321 { 322 } 323 324 325 WriterImplBase::~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 337 status_t 338 WriterImplBase::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 362 void 363 WriterImplBase::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 540 void 541 WriterImplBase::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.Revision() != 0) { 581 PackageAttribute* versionRevision = new PackageAttribute( 582 B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION, 583 B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT); 584 versionRevision->unsignedInt = version.Revision(); 585 versionMajor->children.Add(versionRevision); 586 } 587 } 588 589 590 void 591 WriterImplBase::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 618 int32 619 WriterImplBase::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 662 int32 663 WriterImplBase::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 677 void 678 WriterImplBase::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 742 void 743 WriterImplBase::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 757 void 758 WriterImplBase::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 775 void 776 WriterImplBase::_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