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