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