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