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