WriterImplBase.cpp revision 796343ed
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	fParameters(),
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		&& (Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) == 0) {
240		unlink(fFileName);
241	}
242}
243
244
245status_t
246WriterImplBase::Init(const char* fileName,
247	const BPackageWriterParameters& parameters)
248{
249	fParameters = parameters;
250
251	if (fPackageStringCache.Init() != B_OK)
252		throw std::bad_alloc();
253
254	// open file (don't truncate in update mode)
255	int openMode = O_RDWR;
256	if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) == 0)
257		openMode |= O_CREAT | O_TRUNC;
258
259	fFD = open(fileName, openMode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
260	if (fFD < 0) {
261		fErrorOutput->PrintError("Failed to open %s file \"%s\": %s\n",
262			fFileType, fileName, strerror(errno));
263		return errno;
264	}
265
266	fFileName = fileName;
267
268	// create heap writer
269	fHeapWriter = new PackageFileHeapWriter(fErrorOutput, FD(),
270		sizeof(hpkg_header), fParameters.CompressionLevel());
271	fHeapWriter->Init();
272	fDataWriter = fHeapWriter->DataWriter();
273
274	return B_OK;
275}
276
277
278void
279WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
280	const BPackageInfo& packageInfo)
281{
282	// name
283	PackageAttribute* name = new PackageAttribute(
284		B_HPKG_ATTRIBUTE_ID_PACKAGE_NAME, B_HPKG_ATTRIBUTE_TYPE_STRING,
285		B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
286	name->string = fPackageStringCache.Get(packageInfo.Name().String());
287	attributeList.Add(name);
288
289	// summary
290	PackageAttribute* summary = new PackageAttribute(
291		B_HPKG_ATTRIBUTE_ID_PACKAGE_SUMMARY, B_HPKG_ATTRIBUTE_TYPE_STRING,
292		B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
293	summary->string = fPackageStringCache.Get(packageInfo.Summary().String());
294	attributeList.Add(summary);
295
296	// description
297	PackageAttribute* description = new PackageAttribute(
298		B_HPKG_ATTRIBUTE_ID_PACKAGE_DESCRIPTION, B_HPKG_ATTRIBUTE_TYPE_STRING,
299		B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
300	description->string
301		= fPackageStringCache.Get(packageInfo.Description().String());
302	attributeList.Add(description);
303
304	// vendor
305	PackageAttribute* vendor = new PackageAttribute(
306		B_HPKG_ATTRIBUTE_ID_PACKAGE_VENDOR, B_HPKG_ATTRIBUTE_TYPE_STRING,
307		B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
308	vendor->string = fPackageStringCache.Get(packageInfo.Vendor().String());
309	attributeList.Add(vendor);
310
311	// packager
312	PackageAttribute* packager = new PackageAttribute(
313		B_HPKG_ATTRIBUTE_ID_PACKAGE_PACKAGER, B_HPKG_ATTRIBUTE_TYPE_STRING,
314		B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
315	packager->string = fPackageStringCache.Get(packageInfo.Packager().String());
316	attributeList.Add(packager);
317
318	// base package (optional)
319	if (!packageInfo.BasePackage().IsEmpty()) {
320		PackageAttribute* basePackage = new PackageAttribute(
321			B_HPKG_ATTRIBUTE_ID_PACKAGE_BASE_PACKAGE,
322			B_HPKG_ATTRIBUTE_TYPE_STRING,
323			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
324		basePackage->string
325			= fPackageStringCache.Get(packageInfo.BasePackage());
326		attributeList.Add(basePackage);
327	}
328
329	// flags
330	PackageAttribute* flags = new PackageAttribute(
331		B_HPKG_ATTRIBUTE_ID_PACKAGE_FLAGS, B_HPKG_ATTRIBUTE_TYPE_UINT,
332		B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT);
333	flags->unsignedInt = packageInfo.Flags();
334	attributeList.Add(flags);
335
336	// architecture
337	PackageAttribute* architecture = new PackageAttribute(
338		B_HPKG_ATTRIBUTE_ID_PACKAGE_ARCHITECTURE, B_HPKG_ATTRIBUTE_TYPE_UINT,
339		B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
340	architecture->unsignedInt = packageInfo.Architecture();
341	attributeList.Add(architecture);
342
343	// version
344	RegisterPackageVersion(attributeList, packageInfo.Version());
345
346	// copyright list
347	const BStringList& copyrightList = packageInfo.CopyrightList();
348	for (int i = 0; i < copyrightList.CountStrings(); ++i) {
349		PackageAttribute* copyright = new PackageAttribute(
350			B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT, B_HPKG_ATTRIBUTE_TYPE_STRING,
351			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
352		copyright->string = fPackageStringCache.Get(copyrightList.StringAt(i));
353		attributeList.Add(copyright);
354	}
355
356	// license list
357	const BStringList& licenseList = packageInfo.LicenseList();
358	for (int i = 0; i < licenseList.CountStrings(); ++i) {
359		PackageAttribute* license = new PackageAttribute(
360			B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE, B_HPKG_ATTRIBUTE_TYPE_STRING,
361			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
362		license->string = fPackageStringCache.Get(licenseList.StringAt(i));
363		attributeList.Add(license);
364	}
365
366	// URL list
367	const BStringList& urlList = packageInfo.URLList();
368	for (int i = 0; i < urlList.CountStrings(); ++i) {
369		PackageAttribute* url = new PackageAttribute(
370			B_HPKG_ATTRIBUTE_ID_PACKAGE_URL, B_HPKG_ATTRIBUTE_TYPE_STRING,
371			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
372		url->string = fPackageStringCache.Get(urlList.StringAt(i));
373		attributeList.Add(url);
374	}
375
376	// source URL list
377	const BStringList& sourceURLList = packageInfo.SourceURLList();
378	for (int i = 0; i < sourceURLList.CountStrings(); ++i) {
379		PackageAttribute* url = new PackageAttribute(
380			B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL,
381			B_HPKG_ATTRIBUTE_TYPE_STRING,
382			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
383		url->string = fPackageStringCache.Get(sourceURLList.StringAt(i));
384		attributeList.Add(url);
385	}
386
387	// provides list
388	const BObjectList<BPackageResolvable>& providesList
389		= packageInfo.ProvidesList();
390	for (int i = 0; i < providesList.CountItems(); ++i) {
391		BPackageResolvable* resolvable = providesList.ItemAt(i);
392		bool hasVersion = resolvable->Version().InitCheck() == B_OK;
393		bool hasCompatibleVersion
394			= resolvable->CompatibleVersion().InitCheck() == B_OK;
395
396		PackageAttribute* provides = new PackageAttribute(
397			B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES, B_HPKG_ATTRIBUTE_TYPE_STRING,
398			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
399		provides->string = fPackageStringCache.Get(resolvable->Name().String());
400		attributeList.Add(provides);
401
402		if (hasVersion)
403			RegisterPackageVersion(provides->children, resolvable->Version());
404
405		if (hasCompatibleVersion) {
406			RegisterPackageVersion(provides->children,
407				resolvable->CompatibleVersion(),
408				B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE);
409		}
410	}
411
412	// requires list
413	RegisterPackageResolvableExpressionList(attributeList,
414		packageInfo.RequiresList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES);
415
416	// supplements list
417	RegisterPackageResolvableExpressionList(attributeList,
418		packageInfo.SupplementsList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS);
419
420	// conflicts list
421	RegisterPackageResolvableExpressionList(attributeList,
422		packageInfo.ConflictsList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS);
423
424	// freshens list
425	RegisterPackageResolvableExpressionList(attributeList,
426		packageInfo.FreshensList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS);
427
428	// replaces list
429	const BStringList& replacesList = packageInfo.ReplacesList();
430	for (int i = 0; i < replacesList.CountStrings(); ++i) {
431		PackageAttribute* replaces = new PackageAttribute(
432			B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES, B_HPKG_ATTRIBUTE_TYPE_STRING,
433			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
434		replaces->string = fPackageStringCache.Get(replacesList.StringAt(i));
435		attributeList.Add(replaces);
436	}
437
438	// checksum (optional, only exists in repositories)
439	if (packageInfo.Checksum().Length() > 0) {
440		PackageAttribute* checksum = new PackageAttribute(
441			B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM, B_HPKG_ATTRIBUTE_TYPE_STRING,
442			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
443		checksum->string
444			= fPackageStringCache.Get(packageInfo.Checksum().String());
445		attributeList.Add(checksum);
446	}
447
448	// install path (optional)
449	if (!packageInfo.InstallPath().IsEmpty()) {
450		PackageAttribute* installPath = new PackageAttribute(
451			B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH,
452			B_HPKG_ATTRIBUTE_TYPE_STRING,
453			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
454		installPath->string = fPackageStringCache.Get(
455			packageInfo.InstallPath().String());
456		attributeList.Add(installPath);
457	}
458}
459
460
461void
462WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList,
463	const BPackageVersion& version, BHPKGAttributeID attributeID)
464{
465	PackageAttribute* versionMajor = new PackageAttribute(
466		attributeID, B_HPKG_ATTRIBUTE_TYPE_STRING,
467		B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
468	versionMajor->string = fPackageStringCache.Get(version.Major().String());
469	attributeList.Add(versionMajor);
470
471	if (version.Minor().Length() > 0) {
472		PackageAttribute* versionMinor = new PackageAttribute(
473			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR,
474			B_HPKG_ATTRIBUTE_TYPE_STRING,
475			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
476		versionMinor->string
477			= fPackageStringCache.Get(version.Minor().String());
478		versionMajor->children.Add(versionMinor);
479
480		if (version.Micro().Length() > 0) {
481			PackageAttribute* versionMicro = new PackageAttribute(
482				B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO,
483				B_HPKG_ATTRIBUTE_TYPE_STRING,
484				B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
485			versionMicro->string
486				= fPackageStringCache.Get(version.Micro().String());
487			versionMajor->children.Add(versionMicro);
488		}
489	}
490
491	if (!version.PreRelease().IsEmpty()) {
492		PackageAttribute* preRelease = new PackageAttribute(
493			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE,
494			B_HPKG_ATTRIBUTE_TYPE_STRING,
495			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
496		preRelease->string
497			= fPackageStringCache.Get(version.PreRelease().String());
498		versionMajor->children.Add(preRelease);
499	}
500
501	if (version.Revision() != 0) {
502		PackageAttribute* versionRevision = new PackageAttribute(
503			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION,
504			B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT);
505		versionRevision->unsignedInt = version.Revision();
506		versionMajor->children.Add(versionRevision);
507	}
508}
509
510
511void
512WriterImplBase::RegisterPackageResolvableExpressionList(
513	PackageAttributeList& attributeList,
514	const BObjectList<BPackageResolvableExpression>& expressionList, uint8 id)
515{
516	for (int i = 0; i < expressionList.CountItems(); ++i) {
517		BPackageResolvableExpression* resolvableExpr = expressionList.ItemAt(i);
518		bool hasVersion = resolvableExpr->Version().InitCheck() == B_OK;
519
520		PackageAttribute* name = new PackageAttribute((BHPKGAttributeID)id,
521			B_HPKG_ATTRIBUTE_TYPE_STRING,
522			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
523		name->string = fPackageStringCache.Get(resolvableExpr->Name().String());
524		attributeList.Add(name);
525
526		if (hasVersion) {
527			PackageAttribute* op = new PackageAttribute(
528				B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR,
529				B_HPKG_ATTRIBUTE_TYPE_UINT,
530				B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
531			op->unsignedInt = resolvableExpr->Operator();
532			name->children.Add(op);
533			RegisterPackageVersion(name->children, resolvableExpr->Version());
534		}
535	}
536}
537
538
539int32
540WriterImplBase::WriteCachedStrings(const StringCache& cache,
541	uint32 minUsageCount)
542{
543	// create an array of the cached strings
544	int32 count = cache.CountElements();
545	CachedString** cachedStrings = new CachedString*[count];
546	ArrayDeleter<CachedString*> cachedStringsDeleter(cachedStrings);
547
548	int32 index = 0;
549	for (CachedStringTable::Iterator it = cache.GetIterator();
550			CachedString* string = it.Next();) {
551		cachedStrings[index++] = string;
552	}
553
554	// sort it by descending usage count
555	std::sort(cachedStrings, cachedStrings + count, CachedStringUsageGreater());
556
557	// assign the indices and write entries to disk
558	int32 stringsWritten = 0;
559	for (int32 i = 0; i < count; i++) {
560		CachedString* cachedString = cachedStrings[i];
561
562		// empty strings must be stored inline, as they can't be distinguished
563		// from the end-marker!
564		if (strlen(cachedString->string) == 0)
565			continue;
566
567		// strings that are used only once are better stored inline
568		if (cachedString->usageCount < minUsageCount)
569			break;
570
571		WriteString(cachedString->string);
572
573		cachedString->index = stringsWritten++;
574	}
575
576	// write a terminating 0 byte
577	Write<uint8>(0);
578
579	return stringsWritten;
580}
581
582
583int32
584WriterImplBase::WritePackageAttributes(
585	const PackageAttributeList& packageAttributes,
586	uint32& _stringsLengthUncompressed)
587{
588	// write the cached strings
589	uint64 startOffset = fHeapWriter->UncompressedHeapSize();
590	uint32 stringsCount = WriteCachedStrings(fPackageStringCache, 2);
591	_stringsLengthUncompressed
592		= fHeapWriter->UncompressedHeapSize() - startOffset;
593
594	_WritePackageAttributes(packageAttributes);
595
596	return stringsCount;
597}
598
599
600void
601WriterImplBase::WriteAttributeValue(const AttributeValue& value, uint8 encoding)
602{
603	switch (value.type) {
604		case B_HPKG_ATTRIBUTE_TYPE_INT:
605		case B_HPKG_ATTRIBUTE_TYPE_UINT:
606		{
607			uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT
608				? (uint64)value.signedInt : value.unsignedInt;
609
610			switch (encoding) {
611				case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT:
612					Write<uint8>((uint8)intValue);
613					break;
614				case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT:
615					Write<uint16>(
616						B_HOST_TO_BENDIAN_INT16((uint16)intValue));
617					break;
618				case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT:
619					Write<uint32>(
620						B_HOST_TO_BENDIAN_INT32((uint32)intValue));
621					break;
622				case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT:
623					Write<uint64>(
624						B_HOST_TO_BENDIAN_INT64((uint64)intValue));
625					break;
626				default:
627				{
628					fErrorOutput->PrintError("WriteAttributeValue(): invalid "
629						"encoding %d for int value type %d\n", encoding,
630						value.type);
631					throw status_t(B_BAD_VALUE);
632				}
633			}
634
635			break;
636		}
637
638		case B_HPKG_ATTRIBUTE_TYPE_STRING:
639		{
640			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE)
641				WriteUnsignedLEB128(value.string->index);
642			else
643				WriteString(value.string->string);
644			break;
645		}
646
647		case B_HPKG_ATTRIBUTE_TYPE_RAW:
648		{
649			WriteUnsignedLEB128(value.data.size);
650			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP)
651				WriteUnsignedLEB128(value.data.offset);
652			else
653				fDataWriter->WriteDataThrows(value.data.raw, value.data.size);
654			break;
655		}
656
657		default:
658			fErrorOutput->PrintError(
659				"WriteAttributeValue(): invalid value type: %d\n", value.type);
660			throw status_t(B_BAD_VALUE);
661	}
662}
663
664
665void
666WriterImplBase::WriteUnsignedLEB128(uint64 value)
667{
668	uint8 bytes[10];
669	int32 count = 0;
670	do {
671		uint8 byte = value & 0x7f;
672		value >>= 7;
673		bytes[count++] = byte | (value != 0 ? 0x80 : 0);
674	} while (value != 0);
675
676	fDataWriter->WriteDataThrows(bytes, count);
677}
678
679
680void
681WriterImplBase::RawWriteBuffer(const void* buffer, size_t size, off_t offset)
682{
683	ssize_t bytesWritten = pwrite(fFD, buffer, size, offset);
684	if (bytesWritten < 0) {
685		fErrorOutput->PrintError(
686			"RawWriteBuffer(%p, %lu) failed to write data: %s\n", buffer, size,
687			strerror(errno));
688		throw status_t(errno);
689	}
690	if ((size_t)bytesWritten != size) {
691		fErrorOutput->PrintError(
692			"RawWriteBuffer(%p, %lu) failed to write all data\n", buffer, size);
693		throw status_t(B_ERROR);
694	}
695}
696
697
698void
699WriterImplBase::_WritePackageAttributes(
700	const PackageAttributeList& packageAttributes)
701{
702	DoublyLinkedList<PackageAttribute>::ConstIterator it
703		= packageAttributes.GetIterator();
704	while (PackageAttribute* attribute = it.Next()) {
705		uint8 encoding = attribute->ApplicableEncoding();
706
707		// write tag
708		WriteUnsignedLEB128(compose_attribute_tag(
709			attribute->id, attribute->type, encoding,
710			!attribute->children.IsEmpty()));
711
712		// write value
713		WriteAttributeValue(*attribute, encoding);
714
715		if (!attribute->children.IsEmpty())
716			_WritePackageAttributes(attribute->children);
717	}
718
719	WriteUnsignedLEB128(0);
720}
721
722
723}	// namespace BPrivate
724
725}	// namespace BHPKG
726
727}	// namespace BPackageKit
728