WriterImplBase.cpp revision b2709d8a0abeca4e08ed63d2f421ffac320e1a29
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	fFD(-1),
318	fFinished(false),
319	fDataWriter(NULL)
320{
321}
322
323
324WriterImplBase::~WriterImplBase()
325{
326	if (fFD >= 0)
327		close(fFD);
328
329	if (!fFinished && fFileName != NULL)
330		unlink(fFileName);
331}
332
333
334status_t
335WriterImplBase::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
355void
356WriterImplBase::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	// provides list
435	const BObjectList<BPackageResolvable>& providesList
436		= packageInfo.ProvidesList();
437	for (int i = 0; i < providesList.CountItems(); ++i) {
438		BPackageResolvable* resolvable = providesList.ItemAt(i);
439		bool hasVersion = resolvable->Version().InitCheck() == B_OK;
440		bool hasCompatibleVersion
441			= resolvable->CompatibleVersion().InitCheck() == B_OK;
442
443		PackageAttribute* provides = new PackageAttribute(
444			B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES, B_HPKG_ATTRIBUTE_TYPE_STRING,
445			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
446		provides->string = fPackageStringCache.Get(resolvable->Name().String());
447		attributeList.Add(provides);
448
449		PackageAttribute* providesType = new PackageAttribute(
450			B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_TYPE,
451			B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
452		providesType->unsignedInt = resolvable->Type();
453		provides->children.Add(providesType);
454
455		if (hasVersion)
456			RegisterPackageVersion(provides->children, resolvable->Version());
457
458		if (hasCompatibleVersion) {
459			RegisterPackageVersion(provides->children,
460				resolvable->CompatibleVersion(),
461				B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE);
462		}
463	}
464
465	// requires list
466	RegisterPackageResolvableExpressionList(attributeList,
467		packageInfo.RequiresList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES);
468
469	// supplements list
470	RegisterPackageResolvableExpressionList(attributeList,
471		packageInfo.SupplementsList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS);
472
473	// conflicts list
474	RegisterPackageResolvableExpressionList(attributeList,
475		packageInfo.ConflictsList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS);
476
477	// freshens list
478	RegisterPackageResolvableExpressionList(attributeList,
479		packageInfo.FreshensList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS);
480
481	// replaces list
482	const BObjectList<BString>& replacesList = packageInfo.ReplacesList();
483	for (int i = 0; i < replacesList.CountItems(); ++i) {
484		PackageAttribute* replaces = new PackageAttribute(
485			B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES, B_HPKG_ATTRIBUTE_TYPE_STRING,
486			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
487		replaces->string
488			= fPackageStringCache.Get(replacesList.ItemAt(i)->String());
489		attributeList.Add(replaces);
490	}
491
492	// checksum (optional, only exists in repositories)
493	if (packageInfo.Checksum().Length() > 0) {
494		PackageAttribute* checksum = new PackageAttribute(
495			B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM, B_HPKG_ATTRIBUTE_TYPE_STRING,
496			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
497		checksum->string
498			= fPackageStringCache.Get(packageInfo.Checksum().String());
499		attributeList.Add(checksum);
500	}
501}
502
503
504void
505WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList,
506	const BPackageVersion& version, BHPKGAttributeID attributeID)
507{
508	PackageAttribute* versionMajor = new PackageAttribute(
509		attributeID, B_HPKG_ATTRIBUTE_TYPE_STRING,
510		B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
511	versionMajor->string = fPackageStringCache.Get(version.Major().String());
512	attributeList.Add(versionMajor);
513
514	if (version.Minor().Length() > 0) {
515		PackageAttribute* versionMinor = new PackageAttribute(
516			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR,
517			B_HPKG_ATTRIBUTE_TYPE_STRING,
518			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
519		versionMinor->string
520			= fPackageStringCache.Get(version.Minor().String());
521		versionMajor->children.Add(versionMinor);
522
523		if (version.Micro().Length() > 0) {
524			PackageAttribute* versionMicro = new PackageAttribute(
525				B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO,
526				B_HPKG_ATTRIBUTE_TYPE_STRING,
527				B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
528			versionMicro->string
529				= fPackageStringCache.Get(version.Micro().String());
530			versionMajor->children.Add(versionMicro);
531		}
532	}
533
534	if (!version.PreRelease().IsEmpty()) {
535		PackageAttribute* preRelease = new PackageAttribute(
536			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE,
537			B_HPKG_ATTRIBUTE_TYPE_STRING,
538			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
539		preRelease->string
540			= fPackageStringCache.Get(version.PreRelease().String());
541		versionMajor->children.Add(preRelease);
542	}
543
544	if (version.Release() != 0) {
545		PackageAttribute* versionRelease = new PackageAttribute(
546			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE,
547			B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
548		versionRelease->unsignedInt = version.Release();
549		versionMajor->children.Add(versionRelease);
550	}
551}
552
553
554void
555WriterImplBase::RegisterPackageResolvableExpressionList(
556	PackageAttributeList& attributeList,
557	const BObjectList<BPackageResolvableExpression>& expressionList, uint8 id)
558{
559	for (int i = 0; i < expressionList.CountItems(); ++i) {
560		BPackageResolvableExpression* resolvableExpr = expressionList.ItemAt(i);
561		bool hasVersion = resolvableExpr->Version().InitCheck() == B_OK;
562
563		PackageAttribute* name = new PackageAttribute((BHPKGAttributeID)id,
564			B_HPKG_ATTRIBUTE_TYPE_STRING,
565			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
566		name->string = fPackageStringCache.Get(resolvableExpr->Name().String());
567		attributeList.Add(name);
568
569		if (hasVersion) {
570			PackageAttribute* op = new PackageAttribute(
571				B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR,
572				B_HPKG_ATTRIBUTE_TYPE_UINT,
573				B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
574			op->unsignedInt = resolvableExpr->Operator();
575			name->children.Add(op);
576			RegisterPackageVersion(name->children, resolvableExpr->Version());
577		}
578	}
579}
580
581
582int32
583WriterImplBase::WriteCachedStrings(const StringCache& cache,
584	uint32 minUsageCount)
585{
586	// create an array of the cached strings
587	int32 count = cache.CountElements();
588	CachedString** cachedStrings = new CachedString*[count];
589	ArrayDeleter<CachedString*> cachedStringsDeleter(cachedStrings);
590
591	int32 index = 0;
592	for (CachedStringTable::Iterator it = cache.GetIterator();
593			CachedString* string = it.Next();) {
594		cachedStrings[index++] = string;
595	}
596
597	// sort it by descending usage count
598	std::sort(cachedStrings, cachedStrings + count, CachedStringUsageGreater());
599
600	// assign the indices and write entries to disk
601	int32 stringsWritten = 0;
602	for (int32 i = 0; i < count; i++) {
603		CachedString* cachedString = cachedStrings[i];
604
605		// empty strings must be stored inline, as they can't be distinguished
606		// from the end-marker!
607		if (strlen(cachedString->string) == 0)
608			continue;
609
610		// strings that are used only once are better stored inline
611		if (cachedString->usageCount < minUsageCount)
612			break;
613
614		WriteString(cachedString->string);
615
616		cachedString->index = stringsWritten++;
617	}
618
619	// write a terminating 0 byte
620	Write<uint8>(0);
621
622	return stringsWritten;
623}
624
625
626int32
627WriterImplBase::WritePackageAttributes(
628	const PackageAttributeList& packageAttributes,
629	uint32& _stringsLengthUncompressed)
630{
631	// write the cached strings
632	uint32 stringsCount = WriteCachedStrings(fPackageStringCache, 2);
633	_stringsLengthUncompressed = DataWriter()->BytesWritten();
634
635	_WritePackageAttributes(packageAttributes);
636
637	return stringsCount;
638}
639
640
641void
642WriterImplBase::WriteAttributeValue(const AttributeValue& value, uint8 encoding)
643{
644	switch (value.type) {
645		case B_HPKG_ATTRIBUTE_TYPE_INT:
646		case B_HPKG_ATTRIBUTE_TYPE_UINT:
647		{
648			uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT
649				? (uint64)value.signedInt : value.unsignedInt;
650
651			switch (encoding) {
652				case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT:
653					Write<uint8>((uint8)intValue);
654					break;
655				case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT:
656					Write<uint16>(
657						B_HOST_TO_BENDIAN_INT16((uint16)intValue));
658					break;
659				case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT:
660					Write<uint32>(
661						B_HOST_TO_BENDIAN_INT32((uint32)intValue));
662					break;
663				case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT:
664					Write<uint64>(
665						B_HOST_TO_BENDIAN_INT64((uint64)intValue));
666					break;
667				default:
668				{
669					fErrorOutput->PrintError("WriteAttributeValue(): invalid "
670						"encoding %d for int value type %d\n", encoding,
671						value.type);
672					throw status_t(B_BAD_VALUE);
673				}
674			}
675
676			break;
677		}
678
679		case B_HPKG_ATTRIBUTE_TYPE_STRING:
680		{
681			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE)
682				WriteUnsignedLEB128(value.string->index);
683			else
684				WriteString(value.string->string);
685			break;
686		}
687
688		case B_HPKG_ATTRIBUTE_TYPE_RAW:
689		{
690			WriteUnsignedLEB128(value.data.size);
691			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP)
692				WriteUnsignedLEB128(value.data.offset);
693			else
694				fDataWriter->WriteDataThrows(value.data.raw, value.data.size);
695			break;
696		}
697
698		default:
699			fErrorOutput->PrintError(
700				"WriteAttributeValue(): invalid value type: %d\n", value.type);
701			throw status_t(B_BAD_VALUE);
702	}
703}
704
705
706void
707WriterImplBase::WriteUnsignedLEB128(uint64 value)
708{
709	uint8 bytes[10];
710	int32 count = 0;
711	do {
712		uint8 byte = value & 0x7f;
713		value >>= 7;
714		bytes[count++] = byte | (value != 0 ? 0x80 : 0);
715	} while (value != 0);
716
717	fDataWriter->WriteDataThrows(bytes, count);
718}
719
720
721void
722WriterImplBase::WriteBuffer(const void* buffer, size_t size, off_t offset)
723{
724	ssize_t bytesWritten = pwrite(fFD, buffer, size, offset);
725	if (bytesWritten < 0) {
726		fErrorOutput->PrintError(
727			"WriteBuffer(%p, %lu) failed to write data: %s\n", buffer, size,
728			strerror(errno));
729		throw status_t(errno);
730	}
731	if ((size_t)bytesWritten != size) {
732		fErrorOutput->PrintError(
733			"WriteBuffer(%p, %lu) failed to write all data\n", buffer, size);
734		throw status_t(B_ERROR);
735	}
736}
737
738
739void
740WriterImplBase::_WritePackageAttributes(
741	const PackageAttributeList& packageAttributes)
742{
743	DoublyLinkedList<PackageAttribute>::ConstIterator it
744		= packageAttributes.GetIterator();
745	while (PackageAttribute* attribute = it.Next()) {
746		uint8 encoding = attribute->ApplicableEncoding();
747
748		// write tag
749		WriteUnsignedLEB128(HPKG_ATTRIBUTE_TAG_COMPOSE(
750			attribute->id, attribute->type, encoding,
751			!attribute->children.IsEmpty()));
752
753		// write value
754		WriteAttributeValue(*attribute, encoding);
755
756		if (!attribute->children.IsEmpty())
757			_WritePackageAttributes(attribute->children);
758	}
759
760	WriteUnsignedLEB128(0);
761}
762
763
764}	// namespace BPrivate
765
766}	// namespace BHPKG
767
768}	// namespace BPackageKit
769