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