WriterImplBase.cpp revision b3263ad3
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#include <unistd.h>
14
15#include <algorithm>
16#include <new>
17
18#include <ByteOrder.h>
19
20#include <AutoDeleter.h>
21#include <ZlibCompressionAlgorithm.h>
22
23#include <package/hpkg/DataReader.h>
24#include <package/hpkg/ErrorOutput.h>
25
26#include <package/hpkg/HPKGDefsPrivate.h>
27
28
29namespace BPackageKit {
30
31namespace BHPKG {
32
33namespace BPrivate {
34
35
36// #pragma mark - AttributeValue
37
38
39WriterImplBase::AttributeValue::AttributeValue()
40	:
41	type(B_HPKG_ATTRIBUTE_TYPE_INVALID),
42	encoding(-1)
43{
44}
45
46
47WriterImplBase::AttributeValue::~AttributeValue()
48{
49}
50
51
52void
53WriterImplBase::AttributeValue::SetTo(int8 value)
54{
55	signedInt = value;
56	type = B_HPKG_ATTRIBUTE_TYPE_INT;
57}
58
59
60void
61WriterImplBase::AttributeValue::SetTo(uint8 value)
62{
63	unsignedInt = value;
64	type = B_HPKG_ATTRIBUTE_TYPE_UINT;
65}
66
67
68void
69WriterImplBase::AttributeValue::SetTo(int16 value)
70{
71	signedInt = value;
72	type = B_HPKG_ATTRIBUTE_TYPE_INT;
73}
74
75
76void
77WriterImplBase::AttributeValue::SetTo(uint16 value)
78{
79	unsignedInt = value;
80	type = B_HPKG_ATTRIBUTE_TYPE_UINT;
81}
82
83
84void
85WriterImplBase::AttributeValue::SetTo(int32 value)
86{
87	signedInt = value;
88	type = B_HPKG_ATTRIBUTE_TYPE_INT;
89}
90
91
92void
93WriterImplBase::AttributeValue::SetTo(uint32 value)
94{
95	unsignedInt = value;
96	type = B_HPKG_ATTRIBUTE_TYPE_UINT;
97}
98
99
100void
101WriterImplBase::AttributeValue::SetTo(int64 value)
102{
103	signedInt = value;
104	type = B_HPKG_ATTRIBUTE_TYPE_INT;
105}
106
107
108void
109WriterImplBase::AttributeValue::SetTo(uint64 value)
110{
111	unsignedInt = value;
112	type = B_HPKG_ATTRIBUTE_TYPE_UINT;
113}
114
115
116void
117WriterImplBase::AttributeValue::SetTo(CachedString* value)
118{
119	string = value;
120	type = B_HPKG_ATTRIBUTE_TYPE_STRING;
121}
122
123
124void
125WriterImplBase::AttributeValue::SetToData(uint64 size, uint64 offset)
126{
127	data.size = size;
128	data.offset = offset;
129	type = B_HPKG_ATTRIBUTE_TYPE_RAW;
130	encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP;
131}
132
133
134void
135WriterImplBase::AttributeValue::SetToData(uint64 size, const void* rawData)
136{
137	data.size = size;
138	if (size > 0)
139		memcpy(data.raw, rawData, size);
140	type = B_HPKG_ATTRIBUTE_TYPE_RAW;
141	encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE;
142}
143
144
145uint8
146WriterImplBase::AttributeValue::ApplicableEncoding() const
147{
148	switch (type) {
149		case B_HPKG_ATTRIBUTE_TYPE_INT:
150			return _ApplicableIntEncoding(signedInt >= 0
151				? (uint64)signedInt << 1
152				: (uint64)(-(signedInt + 1) << 1));
153		case B_HPKG_ATTRIBUTE_TYPE_UINT:
154			return _ApplicableIntEncoding(unsignedInt);
155		case B_HPKG_ATTRIBUTE_TYPE_STRING:
156			return string->index >= 0
157				? B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE
158				: B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE;
159		case B_HPKG_ATTRIBUTE_TYPE_RAW:
160			return encoding;
161		default:
162			return 0;
163	}
164}
165
166
167/*static*/ uint8
168WriterImplBase::AttributeValue::_ApplicableIntEncoding(uint64 value)
169{
170	if (value <= 0xff)
171		return B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT;
172	if (value <= 0xffff)
173		return B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT;
174	if (value <= 0xffffffff)
175		return B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT;
176
177	return B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT;
178}
179
180
181// #pragma mark - PackageAttribute
182
183
184WriterImplBase::PackageAttribute::PackageAttribute(BHPKGAttributeID id_,
185	uint8 type_, uint8 encoding_)
186	:
187	id(id_)
188{
189	type = type_;
190	encoding = encoding_;
191}
192
193
194WriterImplBase::PackageAttribute::~PackageAttribute()
195{
196	_DeleteChildren();
197}
198
199
200void
201WriterImplBase::PackageAttribute::AddChild(PackageAttribute* child)
202{
203	children.Add(child);
204}
205
206
207void
208WriterImplBase::PackageAttribute::_DeleteChildren()
209{
210	while (PackageAttribute* child = children.RemoveHead())
211		delete child;
212}
213
214
215// #pragma mark - WriterImplBase
216
217
218WriterImplBase::WriterImplBase(const char* fileType, BErrorOutput* errorOutput)
219	:
220	fHeapWriter(NULL),
221	fCompressionAlgorithm(NULL),
222	fCompressionParameters(NULL),
223	fDecompressionAlgorithm(NULL),
224	fDecompressionParameters(NULL),
225	fFileType(fileType),
226	fErrorOutput(errorOutput),
227	fFileName(NULL),
228	fParameters(),
229	fFD(-1),
230	fFinished(false)
231{
232}
233
234
235WriterImplBase::~WriterImplBase()
236{
237	delete fHeapWriter;
238	delete fCompressionAlgorithm;
239	delete fCompressionParameters;
240	delete fDecompressionAlgorithm;
241	delete fDecompressionParameters;
242
243	if (fFD >= 0)
244		close(fFD);
245
246	if (!fFinished && fFileName != NULL
247		&& (Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) == 0) {
248		unlink(fFileName);
249	}
250}
251
252
253status_t
254WriterImplBase::Init(const char* fileName, size_t headerSize,
255	const BPackageWriterParameters& parameters)
256{
257	fParameters = parameters;
258
259	if (fPackageStringCache.Init() != B_OK)
260		throw std::bad_alloc();
261
262	// open file (don't truncate in update mode)
263	int openMode = O_RDWR;
264	if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) == 0)
265		openMode |= O_CREAT | O_TRUNC;
266
267	fFD = open(fileName, openMode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
268	if (fFD < 0) {
269		fErrorOutput->PrintError("Failed to open %s file \"%s\": %s\n",
270			fFileType, fileName, strerror(errno));
271		return errno;
272	}
273
274	fFileName = fileName;
275
276	DecompressionAlgorithmOwner* decompressionAlgorithm
277		= DecompressionAlgorithmOwner::Create(
278			new(std::nothrow) BZlibCompressionAlgorithm,
279			new(std::nothrow) BZlibDecompressionParameters);
280	BReference<DecompressionAlgorithmOwner> decompressionAlgorithmReference(
281		decompressionAlgorithm, true);
282
283	if (decompressionAlgorithm == NULL
284		|| decompressionAlgorithm->algorithm == NULL
285		|| decompressionAlgorithm->parameters == NULL) {
286		throw std::bad_alloc();
287	}
288
289	CompressionAlgorithmOwner* compressionAlgorithm = NULL;
290
291	if (fParameters.CompressionLevel() != B_HPKG_COMPRESSION_LEVEL_NONE) {
292		compressionAlgorithm = CompressionAlgorithmOwner::Create(
293			new(std::nothrow) BZlibCompressionAlgorithm,
294			new(std::nothrow) BZlibCompressionParameters(
295				fParameters.CompressionLevel()));
296
297		if (compressionAlgorithm == NULL
298			|| compressionAlgorithm->algorithm == NULL
299			|| compressionAlgorithm->parameters == NULL) {
300			throw std::bad_alloc();
301		}
302	}
303
304	BReference<CompressionAlgorithmOwner> compressionAlgorithmReference(
305		compressionAlgorithm, true);
306
307	// create heap writer
308	fHeapWriter = new PackageFileHeapWriter(fErrorOutput, FD(), headerSize,
309		compressionAlgorithm, decompressionAlgorithm);
310	fHeapWriter->Init();
311
312	return B_OK;
313}
314
315
316void
317WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
318	const BPackageInfo& packageInfo)
319{
320	// name
321	AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_NAME, packageInfo.Name(),
322		attributeList);
323
324	// summary
325	AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_SUMMARY,
326		packageInfo.Summary(), attributeList);
327
328	// description
329	AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_DESCRIPTION,
330		packageInfo.Description(), attributeList);
331
332	// vendor
333	AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_VENDOR,
334		packageInfo.Vendor(), attributeList);
335
336	// packager
337	AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_PACKAGER,
338		packageInfo.Packager(), attributeList);
339
340	// base package (optional)
341	_AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_BASE_PACKAGE,
342		packageInfo.BasePackage(), attributeList);
343
344	// flags
345	PackageAttribute* flags = new PackageAttribute(
346		B_HPKG_ATTRIBUTE_ID_PACKAGE_FLAGS, B_HPKG_ATTRIBUTE_TYPE_UINT,
347		B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT);
348	flags->unsignedInt = packageInfo.Flags();
349	attributeList.Add(flags);
350
351	// architecture
352	PackageAttribute* architecture = new PackageAttribute(
353		B_HPKG_ATTRIBUTE_ID_PACKAGE_ARCHITECTURE, B_HPKG_ATTRIBUTE_TYPE_UINT,
354		B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
355	architecture->unsignedInt = packageInfo.Architecture();
356	attributeList.Add(architecture);
357
358	// version
359	RegisterPackageVersion(attributeList, packageInfo.Version());
360
361	// copyright list
362	_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT,
363			packageInfo.CopyrightList(), attributeList);
364
365	// license list
366	_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE,
367		packageInfo.LicenseList(), attributeList);
368
369	// URL list
370	_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_URL,
371		packageInfo.URLList(), attributeList);
372
373	// source URL list
374	_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL,
375		packageInfo.SourceURLList(), attributeList);
376
377	// provides list
378	const BObjectList<BPackageResolvable>& providesList
379		= packageInfo.ProvidesList();
380	for (int i = 0; i < providesList.CountItems(); ++i) {
381		BPackageResolvable* resolvable = providesList.ItemAt(i);
382		bool hasVersion = resolvable->Version().InitCheck() == B_OK;
383		bool hasCompatibleVersion
384			= resolvable->CompatibleVersion().InitCheck() == B_OK;
385
386		PackageAttribute* provides = AddStringAttribute(
387			B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES, resolvable->Name(),
388			attributeList);
389
390		if (hasVersion)
391			RegisterPackageVersion(provides->children, resolvable->Version());
392
393		if (hasCompatibleVersion) {
394			RegisterPackageVersion(provides->children,
395				resolvable->CompatibleVersion(),
396				B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE);
397		}
398	}
399
400	// requires list
401	RegisterPackageResolvableExpressionList(attributeList,
402		packageInfo.RequiresList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES);
403
404	// supplements list
405	RegisterPackageResolvableExpressionList(attributeList,
406		packageInfo.SupplementsList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS);
407
408	// conflicts list
409	RegisterPackageResolvableExpressionList(attributeList,
410		packageInfo.ConflictsList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS);
411
412	// freshens list
413	RegisterPackageResolvableExpressionList(attributeList,
414		packageInfo.FreshensList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS);
415
416	// replaces list
417	_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES,
418		packageInfo.ReplacesList(), attributeList);
419
420	// global writable file info list
421	const BObjectList<BGlobalWritableFileInfo>& globalWritableFileInfos
422		= packageInfo.GlobalWritableFileInfos();
423	for (int32 i = 0; i < globalWritableFileInfos.CountItems(); ++i) {
424		BGlobalWritableFileInfo* info = globalWritableFileInfos.ItemAt(i);
425		PackageAttribute* attribute = AddStringAttribute(
426			B_HPKG_ATTRIBUTE_ID_PACKAGE_GLOBAL_WRITABLE_FILE, info->Path(),
427			attributeList);
428
429		if (info->IsDirectory()) {
430			PackageAttribute* isDirectoryAttribute = new PackageAttribute(
431				B_HPKG_ATTRIBUTE_ID_PACKAGE_IS_WRITABLE_DIRECTORY,
432				B_HPKG_ATTRIBUTE_TYPE_UINT,
433				B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
434			isDirectoryAttribute->unsignedInt = 1;
435			attribute->children.Add(isDirectoryAttribute);
436		}
437
438		if (info->IsIncluded()) {
439			PackageAttribute* updateTypeAttribute = new PackageAttribute(
440				B_HPKG_ATTRIBUTE_ID_PACKAGE_WRITABLE_FILE_UPDATE_TYPE,
441				B_HPKG_ATTRIBUTE_TYPE_UINT,
442				B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
443			updateTypeAttribute->unsignedInt = info->UpdateType();
444			attribute->children.Add(updateTypeAttribute);
445		}
446	}
447
448	// user settings file info list
449	const BObjectList<BUserSettingsFileInfo>& userSettingsFileInfos
450		= packageInfo.UserSettingsFileInfos();
451	for (int32 i = 0; i < userSettingsFileInfos.CountItems(); ++i) {
452		BUserSettingsFileInfo* info = userSettingsFileInfos.ItemAt(i);
453		PackageAttribute* attribute = AddStringAttribute(
454			B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_SETTINGS_FILE, info->Path(),
455			attributeList);
456
457		if (info->IsDirectory()) {
458			PackageAttribute* isDirectoryAttribute = new PackageAttribute(
459				B_HPKG_ATTRIBUTE_ID_PACKAGE_IS_WRITABLE_DIRECTORY,
460				B_HPKG_ATTRIBUTE_TYPE_UINT,
461				B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
462			isDirectoryAttribute->unsignedInt = 1;
463			attribute->children.Add(isDirectoryAttribute);
464		} else {
465			_AddStringAttributeIfNotEmpty(
466				B_HPKG_ATTRIBUTE_ID_PACKAGE_SETTINGS_FILE_TEMPLATE,
467				info->TemplatePath(), attribute->children);
468		}
469	}
470
471	// user list
472	const BObjectList<BUser>& users = packageInfo.Users();
473	for (int32 i = 0; i < users.CountItems(); ++i) {
474		const BUser* user = users.ItemAt(i);
475		PackageAttribute* attribute = AddStringAttribute(
476			B_HPKG_ATTRIBUTE_ID_PACKAGE_USER, user->Name(), attributeList);
477
478		_AddStringAttributeIfNotEmpty(
479			B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_REAL_NAME, user->RealName(),
480			attribute->children);
481		_AddStringAttributeIfNotEmpty(
482			B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_HOME, user->Home(),
483			attribute->children);
484		_AddStringAttributeIfNotEmpty(
485			B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_SHELL, user->Shell(),
486			attribute->children);
487
488		for (int32 k = 0; k < user->Groups().CountStrings(); k++) {
489			AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_GROUP,
490				user->Groups().StringAt(k), attribute->children);
491		}
492	}
493
494	// group list
495	_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_GROUP,
496		packageInfo.Groups(), attributeList);
497
498	// post install script list
499	_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_POST_INSTALL_SCRIPT,
500		packageInfo.PostInstallScripts(), attributeList);
501
502	// checksum (optional, only exists in repositories)
503	_AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM,
504		packageInfo.Checksum(), attributeList);
505
506	// install path (optional)
507	_AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH,
508		packageInfo.InstallPath(), attributeList);
509}
510
511
512void
513WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList,
514	const BPackageVersion& version, BHPKGAttributeID attributeID)
515{
516	PackageAttribute* versionMajor = AddStringAttribute(attributeID,
517		version.Major(), attributeList);
518
519	if (!version.Minor().IsEmpty()) {
520		AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR,
521			version.Minor(), versionMajor->children);
522		_AddStringAttributeIfNotEmpty(
523			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO, version.Micro(),
524			versionMajor->children);
525	}
526
527	_AddStringAttributeIfNotEmpty(
528		B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE,
529		version.PreRelease(), versionMajor->children);
530
531	if (version.Revision() != 0) {
532		PackageAttribute* versionRevision = new PackageAttribute(
533			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION,
534			B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT);
535		versionRevision->unsignedInt = version.Revision();
536		versionMajor->children.Add(versionRevision);
537	}
538}
539
540
541void
542WriterImplBase::RegisterPackageResolvableExpressionList(
543	PackageAttributeList& attributeList,
544	const BObjectList<BPackageResolvableExpression>& expressionList, uint8 id)
545{
546	for (int i = 0; i < expressionList.CountItems(); ++i) {
547		BPackageResolvableExpression* resolvableExpr = expressionList.ItemAt(i);
548		PackageAttribute* name = AddStringAttribute((BHPKGAttributeID)id,
549			resolvableExpr->Name(), attributeList);
550
551		if (resolvableExpr->Version().InitCheck() == B_OK) {
552			PackageAttribute* op = new PackageAttribute(
553				B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR,
554				B_HPKG_ATTRIBUTE_TYPE_UINT,
555				B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
556			op->unsignedInt = resolvableExpr->Operator();
557			name->children.Add(op);
558			RegisterPackageVersion(name->children, resolvableExpr->Version());
559		}
560	}
561}
562
563
564WriterImplBase::PackageAttribute*
565WriterImplBase::AddStringAttribute(BHPKGAttributeID id, const BString& value,
566	DoublyLinkedList<PackageAttribute>& list)
567{
568	PackageAttribute* attribute = new PackageAttribute(id,
569		B_HPKG_ATTRIBUTE_TYPE_STRING, B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
570	attribute->string = fPackageStringCache.Get(value);
571	list.Add(attribute);
572	return attribute;
573}
574
575
576int32
577WriterImplBase::WriteCachedStrings(const StringCache& cache,
578	uint32 minUsageCount)
579{
580	// create an array of the cached strings
581	int32 count = cache.CountElements();
582	CachedString** cachedStrings = new CachedString*[count];
583	ArrayDeleter<CachedString*> cachedStringsDeleter(cachedStrings);
584
585	int32 index = 0;
586	for (CachedStringTable::Iterator it = cache.GetIterator();
587			CachedString* string = it.Next();) {
588		cachedStrings[index++] = string;
589	}
590
591	// sort it by descending usage count
592	std::sort(cachedStrings, cachedStrings + count, CachedStringUsageGreater());
593
594	// assign the indices and write entries to disk
595	int32 stringsWritten = 0;
596	for (int32 i = 0; i < count; i++) {
597		CachedString* cachedString = cachedStrings[i];
598
599		// empty strings must be stored inline, as they can't be distinguished
600		// from the end-marker!
601		if (strlen(cachedString->string) == 0)
602			continue;
603
604		// strings that are used only once are better stored inline
605		if (cachedString->usageCount < minUsageCount)
606			break;
607
608		WriteString(cachedString->string);
609
610		cachedString->index = stringsWritten++;
611	}
612
613	// write a terminating 0 byte
614	Write<uint8>(0);
615
616	return stringsWritten;
617}
618
619
620int32
621WriterImplBase::WritePackageAttributes(
622	const PackageAttributeList& packageAttributes,
623	uint32& _stringsLengthUncompressed)
624{
625	// write the cached strings
626	uint64 startOffset = fHeapWriter->UncompressedHeapSize();
627	uint32 stringsCount = WriteCachedStrings(fPackageStringCache, 2);
628	_stringsLengthUncompressed
629		= fHeapWriter->UncompressedHeapSize() - startOffset;
630
631	_WritePackageAttributes(packageAttributes);
632
633	return stringsCount;
634}
635
636
637void
638WriterImplBase::WriteAttributeValue(const AttributeValue& value, uint8 encoding)
639{
640	switch (value.type) {
641		case B_HPKG_ATTRIBUTE_TYPE_INT:
642		case B_HPKG_ATTRIBUTE_TYPE_UINT:
643		{
644			uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT
645				? (uint64)value.signedInt : value.unsignedInt;
646
647			switch (encoding) {
648				case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT:
649					Write<uint8>((uint8)intValue);
650					break;
651				case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT:
652					Write<uint16>(
653						B_HOST_TO_BENDIAN_INT16((uint16)intValue));
654					break;
655				case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT:
656					Write<uint32>(
657						B_HOST_TO_BENDIAN_INT32((uint32)intValue));
658					break;
659				case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT:
660					Write<uint64>(
661						B_HOST_TO_BENDIAN_INT64((uint64)intValue));
662					break;
663				default:
664				{
665					fErrorOutput->PrintError("WriteAttributeValue(): invalid "
666						"encoding %d for int value type %d\n", encoding,
667						value.type);
668					throw status_t(B_BAD_VALUE);
669				}
670			}
671
672			break;
673		}
674
675		case B_HPKG_ATTRIBUTE_TYPE_STRING:
676		{
677			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE)
678				WriteUnsignedLEB128(value.string->index);
679			else
680				WriteString(value.string->string);
681			break;
682		}
683
684		case B_HPKG_ATTRIBUTE_TYPE_RAW:
685		{
686			WriteUnsignedLEB128(value.data.size);
687			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP)
688				WriteUnsignedLEB128(value.data.offset);
689			else
690				fHeapWriter->AddDataThrows(value.data.raw, value.data.size);
691			break;
692		}
693
694		default:
695			fErrorOutput->PrintError(
696				"WriteAttributeValue(): invalid value type: %d\n", value.type);
697			throw status_t(B_BAD_VALUE);
698	}
699}
700
701
702void
703WriterImplBase::WriteUnsignedLEB128(uint64 value)
704{
705	uint8 bytes[10];
706	int32 count = 0;
707	do {
708		uint8 byte = value & 0x7f;
709		value >>= 7;
710		bytes[count++] = byte | (value != 0 ? 0x80 : 0);
711	} while (value != 0);
712
713	fHeapWriter->AddDataThrows(bytes, count);
714}
715
716
717void
718WriterImplBase::RawWriteBuffer(const void* buffer, size_t size, off_t offset)
719{
720	ssize_t bytesWritten = pwrite(fFD, buffer, size, offset);
721	if (bytesWritten < 0) {
722		fErrorOutput->PrintError(
723			"RawWriteBuffer(%p, %lu) failed to write data: %s\n", buffer, size,
724			strerror(errno));
725		throw status_t(errno);
726	}
727	if ((size_t)bytesWritten != size) {
728		fErrorOutput->PrintError(
729			"RawWriteBuffer(%p, %lu) failed to write all data\n", buffer, size);
730		throw status_t(B_ERROR);
731	}
732}
733
734
735void
736WriterImplBase::_AddStringAttributeList(BHPKGAttributeID id,
737	const BStringList& value, DoublyLinkedList<PackageAttribute>& list)
738{
739	for (int32 i = 0; i < value.CountStrings(); i++)
740		AddStringAttribute(id, value.StringAt(i), list);
741}
742
743
744void
745WriterImplBase::_WritePackageAttributes(
746	const PackageAttributeList& packageAttributes)
747{
748	DoublyLinkedList<PackageAttribute>::ConstIterator it
749		= packageAttributes.GetIterator();
750	while (PackageAttribute* attribute = it.Next()) {
751		uint8 encoding = attribute->ApplicableEncoding();
752
753		// write tag
754		WriteUnsignedLEB128(compose_attribute_tag(
755			attribute->id, attribute->type, encoding,
756			!attribute->children.IsEmpty()));
757
758		// write value
759		WriteAttributeValue(*attribute, encoding);
760
761		if (!attribute->children.IsEmpty())
762			_WritePackageAttributes(attribute->children);
763	}
764
765	WriteUnsignedLEB128(0);
766}
767
768
769}	// namespace BPrivate
770
771}	// namespace BHPKG
772
773}	// namespace BPackageKit
774