From 5fb1c6ff1f55fe4094a761b653041b3a0b9abf1d Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Sun, 30 Jan 2011 15:05:38 +0000 Subject: [PATCH] Refactored hpkg implementation to provide some separation between public and private API (still far from ideal, but a start): * moved several HPKG-classes into the public namespace BPackageKit::HPKG * added fImpl-wrappers around PackageReader and PackageWriter to hide most of the gory details * adjusted 'package'-binary and packagefs accordingly git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40320 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/package/hpkg/BlockBufferCache.h | 49 + headers/os/package/hpkg/BufferCache.h | 54 + .../{private => os}/package/hpkg/DataOutput.h | 22 +- .../{private => os}/package/hpkg/DataReader.h | 30 +- .../package/hpkg/ErrorOutput.h | 18 +- headers/os/package/hpkg/HPKGDefs.h | 77 + .../package/hpkg/PackageAttributeValue.h | 44 +- .../os/package/hpkg/PackageContentHandler.h | 55 + .../package/hpkg/PackageData.h | 20 +- headers/os/package/hpkg/PackageDataReader.h | 61 + .../package/hpkg/PackageEntry.h | 30 +- .../package/hpkg/PackageEntryAttribute.h | 22 +- headers/os/package/hpkg/PackageReader.h | 51 + headers/os/package/hpkg/PackageWriter.h | 42 + .../private/package/hpkg/BlockBufferCache.h | 71 - .../package/hpkg/BlockBufferCacheImpl.h | 66 + .../hpkg/{BufferCache.h => CachedBuffer.h} | 35 +- headers/private/package/hpkg/FDCloser.h | 14 +- .../private/package/hpkg/PackageDataReader.h | 65 - .../{PackageReader.h => PackageReaderImpl.h} | 69 +- .../{PackageWriter.h => PackageWriterImpl.h} | 36 +- headers/private/package/hpkg/Stacker.h | 10 +- headers/private/package/hpkg/Strings.h | 10 +- .../package/hpkg/ZlibCompressionBase.h | 10 +- headers/private/package/hpkg/ZlibCompressor.h | 21 +- .../private/package/hpkg/ZlibDecompressor.h | 21 +- headers/private/package/hpkg/haiku_package.h | 62 +- .../packagefs/BlockBufferCacheKernel.cpp | 2 +- .../packagefs/BlockBufferCacheKernel.h | 11 +- .../file_systems/packagefs/GlobalFactory.cpp | 4 +- .../file_systems/packagefs/GlobalFactory.h | 16 +- .../kernel/file_systems/packagefs/Jamfile | 8 +- .../file_systems/packagefs/PackageFile.cpp | 23 +- .../file_systems/packagefs/PackageFile.h | 6 +- .../file_systems/packagefs/PackageLeafNode.h | 2 +- .../packagefs/PackageNodeAttribute.cpp | 2 +- .../packagefs/PackageNodeAttribute.h | 8 +- .../kernel/file_systems/packagefs/Volume.cpp | 19 +- .../packagefs/kernel_interface.cpp | 18 +- src/bin/package/BlockBufferCacheNoLock.cpp | 33 + src/bin/package/BlockBufferCacheNoLock.h | 26 + src/bin/package/Jamfile | 1 + src/bin/package/StandardErrorOutput.h | 4 +- src/bin/package/command_create.cpp | 6 +- src/bin/package/command_dump.cpp | 15 +- src/bin/package/command_extract.cpp | 37 +- src/bin/package/command_list.cpp | 15 +- src/kits/package/Jamfile | 5 + src/kits/package/hpkg/BlockBufferCache.cpp | 202 +-- .../package/hpkg/BlockBufferCacheImpl.cpp | 197 +++ src/kits/package/hpkg/BufferCache.cpp | 31 +- src/kits/package/hpkg/CachedBuffer.cpp | 39 + src/kits/package/hpkg/DataOutput.cpp | 18 +- src/kits/package/hpkg/DataReader.cpp | 30 +- src/kits/package/hpkg/ErrorOutput.cpp | 12 +- .../package/hpkg/PackageContentHandler.cpp | 33 + src/kits/package/hpkg/PackageData.cpp | 19 +- src/kits/package/hpkg/PackageDataReader.cpp | 56 +- src/kits/package/hpkg/PackageEntry.cpp | 10 +- .../package/hpkg/PackageEntryAttribute.cpp | 10 +- src/kits/package/hpkg/PackageReader.cpp | 1369 +-------------- src/kits/package/hpkg/PackageReaderImpl.cpp | 1378 +++++++++++++++ src/kits/package/hpkg/PackageWriter.cpp | 1501 +--------------- src/kits/package/hpkg/PackageWriterImpl.cpp | 1524 +++++++++++++++++ src/kits/package/hpkg/Strings.cpp | 4 +- src/kits/package/hpkg/ZlibCompressionBase.cpp | 4 +- src/kits/package/hpkg/ZlibCompressor.cpp | 6 +- src/kits/package/hpkg/ZlibDecompressor.cpp | 6 +- 68 files changed, 4138 insertions(+), 3637 deletions(-) create mode 100644 headers/os/package/hpkg/BlockBufferCache.h create mode 100644 headers/os/package/hpkg/BufferCache.h rename headers/{private => os}/package/hpkg/DataOutput.h (61%) rename headers/{private => os}/package/hpkg/DataReader.h (62%) rename headers/{private => os}/package/hpkg/ErrorOutput.h (62%) create mode 100644 headers/os/package/hpkg/HPKGDefs.h rename headers/{private => os}/package/hpkg/PackageAttributeValue.h (68%) create mode 100644 headers/os/package/hpkg/PackageContentHandler.h rename headers/{private => os}/package/hpkg/PackageData.h (82%) create mode 100644 headers/os/package/hpkg/PackageDataReader.h rename headers/{private => os}/package/hpkg/PackageEntry.h (79%) rename headers/{private => os}/package/hpkg/PackageEntryAttribute.h (55%) create mode 100644 headers/os/package/hpkg/PackageReader.h create mode 100644 headers/os/package/hpkg/PackageWriter.h delete mode 100644 headers/private/package/hpkg/BlockBufferCache.h create mode 100644 headers/private/package/hpkg/BlockBufferCacheImpl.h rename headers/private/package/hpkg/{BufferCache.h => CachedBuffer.h} (59%) delete mode 100644 headers/private/package/hpkg/PackageDataReader.h rename headers/private/package/hpkg/{PackageReader.h => PackageReaderImpl.h} (71%) rename headers/private/package/hpkg/{PackageWriter.h => PackageWriterImpl.h} (85%) create mode 100644 src/bin/package/BlockBufferCacheNoLock.cpp create mode 100644 src/bin/package/BlockBufferCacheNoLock.h create mode 100644 src/kits/package/hpkg/BlockBufferCacheImpl.cpp create mode 100644 src/kits/package/hpkg/CachedBuffer.cpp create mode 100644 src/kits/package/hpkg/PackageContentHandler.cpp create mode 100644 src/kits/package/hpkg/PackageReaderImpl.cpp create mode 100644 src/kits/package/hpkg/PackageWriterImpl.cpp diff --git a/headers/os/package/hpkg/BlockBufferCache.h b/headers/os/package/hpkg/BlockBufferCache.h new file mode 100644 index 0000000000..ca3776629d --- /dev/null +++ b/headers/os/package/hpkg/BlockBufferCache.h @@ -0,0 +1,49 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__BLOCK_BUFFER_CACHE_H_ +#define _PACKAGE__HPKG__BLOCK_BUFFER_CACHE_H_ + + +#include + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +namespace BPrivate { + class BlockBufferCacheImpl; +} +using BPrivate::BlockBufferCacheImpl; + + +class BBlockBufferCache : public BBufferCache, public BBufferCacheLockable { +public: + BBlockBufferCache(size_t blockSize, + uint32 maxCachedBlocks); + virtual ~BBlockBufferCache(); + + virtual status_t Init(); + + virtual CachedBuffer* GetBuffer(size_t size, + CachedBuffer** owner = NULL, + bool* _newBuffer = NULL); + virtual void PutBufferAndCache(CachedBuffer** owner); + virtual void PutBuffer(CachedBuffer** owner); + +private: + BlockBufferCacheImpl* fImpl; +}; + + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__BLOCK_BUFFER_CACHE_H_ diff --git a/headers/os/package/hpkg/BufferCache.h b/headers/os/package/hpkg/BufferCache.h new file mode 100644 index 0000000000..6b6de6ffac --- /dev/null +++ b/headers/os/package/hpkg/BufferCache.h @@ -0,0 +1,54 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__BUFFER_CACHE_H_ +#define _PACKAGE__HPKG__BUFFER_CACHE_H_ + + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +namespace BPrivate { + class CachedBuffer; +} +using BPrivate::CachedBuffer; + + +class BBufferCache { +public: + virtual ~BBufferCache(); + + virtual CachedBuffer* GetBuffer(size_t size, + CachedBuffer** owner = NULL, + bool* _newBuffer = NULL) = 0; + virtual void PutBufferAndCache(CachedBuffer** owner) = 0; + // caller is buffer owner and wants the + // buffer cached, if possible + virtual void PutBuffer(CachedBuffer** owner) = 0; + // puts the buffer for good, owner might + // have called PutBufferAndCache() before + // and might not own a buffer anymore +}; + + +class BBufferCacheLockable { +public: + virtual ~BBufferCacheLockable(); + + virtual bool Lock() = 0; + virtual void Unlock() = 0; +}; + + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__BUFFER_CACHE_H_ diff --git a/headers/private/package/hpkg/DataOutput.h b/headers/os/package/hpkg/DataOutput.h similarity index 61% rename from headers/private/package/hpkg/DataOutput.h rename to headers/os/package/hpkg/DataOutput.h index 646834ccef..5606a1177f 100644 --- a/headers/private/package/hpkg/DataOutput.h +++ b/headers/os/package/hpkg/DataOutput.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef DATA_OUTPUT_H -#define DATA_OUTPUT_H +#ifndef _PACKAGE__HPKG__DATA_OUTPUT_H_ +#define _PACKAGE__HPKG__DATA_OUTPUT_H_ #include @@ -11,22 +11,20 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -class DataOutput { +class BDataOutput { public: - virtual ~DataOutput(); + virtual ~BDataOutput(); virtual status_t WriteData(const void* buffer, size_t size) = 0; }; -class BufferDataOutput : public DataOutput { +class BBufferDataOutput : public BDataOutput { public: - BufferDataOutput(void* buffer, size_t size); + BBufferDataOutput(void* buffer, size_t size); size_t BytesWritten() const { return fBytesWritten; } @@ -39,11 +37,9 @@ private: }; -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // DATA_OUTPUT_H +#endif // _PACKAGE__HPKG__DATA_OUTPUT_H_ diff --git a/headers/private/package/hpkg/DataReader.h b/headers/os/package/hpkg/DataReader.h similarity index 62% rename from headers/private/package/hpkg/DataReader.h rename to headers/os/package/hpkg/DataReader.h index 86493362bd..1e7cddd204 100644 --- a/headers/private/package/hpkg/DataReader.h +++ b/headers/os/package/hpkg/DataReader.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef DATA_READER_H -#define DATA_READER_H +#ifndef _PACKAGE__HPKG__DATA_READER_H_ +#define _PACKAGE__HPKG__DATA_READER_H_ #include @@ -11,23 +11,21 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -class DataReader { +class BDataReader { public: - virtual ~DataReader(); + virtual ~BDataReader(); virtual status_t ReadData(off_t offset, void* buffer, size_t size) = 0; }; -class FDDataReader : public DataReader { +class BFDDataReader : public BDataReader { public: - FDDataReader(int fd); + BFDDataReader(int fd); virtual status_t ReadData(off_t offset, void* buffer, size_t size); @@ -37,9 +35,9 @@ private: }; -class AttributeDataReader : public DataReader { +class BAttributeDataReader : public BDataReader { public: - AttributeDataReader(int fd, + BAttributeDataReader(int fd, const char* attribute, uint32 type); virtual status_t ReadData(off_t offset, void* buffer, @@ -52,9 +50,9 @@ private: }; -class BufferDataReader : public DataReader { +class BBufferDataReader : public BDataReader { public: - BufferDataReader(const void* data, size_t size); + BBufferDataReader(const void* data, size_t size); virtual status_t ReadData(off_t offset, void* buffer, size_t size); @@ -65,11 +63,9 @@ private: }; -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // DATA_READER_H +#endif // _PACKAGE__HPKG__DATA_READER_H_ diff --git a/headers/private/package/hpkg/ErrorOutput.h b/headers/os/package/hpkg/ErrorOutput.h similarity index 62% rename from headers/private/package/hpkg/ErrorOutput.h rename to headers/os/package/hpkg/ErrorOutput.h index bbb066e0dd..09fbbbb19c 100644 --- a/headers/private/package/hpkg/ErrorOutput.h +++ b/headers/os/package/hpkg/ErrorOutput.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef ERROR_OUTPUT_H -#define ERROR_OUTPUT_H +#ifndef _PACKAGE__HPKG__ERROR_OUTPUT_H_ +#define _PACKAGE__HPKG__ERROR_OUTPUT_H_ #include @@ -13,14 +13,12 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -class ErrorOutput { +class BErrorOutput { public: - virtual ~ErrorOutput(); + virtual ~BErrorOutput(); virtual void PrintErrorVarArgs(const char* format, va_list args) = 0; @@ -28,11 +26,9 @@ public: }; -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // ERROR_OUTPUT_H +#endif // _PACKAGE__HPKG__PACKAGE_OUTPUT_H_ diff --git a/headers/os/package/hpkg/HPKGDefs.h b/headers/os/package/hpkg/HPKGDefs.h new file mode 100644 index 0000000000..e6a983f5a7 --- /dev/null +++ b/headers/os/package/hpkg/HPKGDefs.h @@ -0,0 +1,77 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__HPKG_DEFS_H_ +#define _PACKAGE__HPKG__HPKG_DEFS_H_ + + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +// magic, version +enum { + B_HPKG_MAGIC = 'hpkg', + B_HPKG_VERSION = 1 +}; + + +// attribute types +enum { + // types + B_HPKG_ATTRIBUTE_TYPE_INVALID = 0, + B_HPKG_ATTRIBUTE_TYPE_INT = 1, + B_HPKG_ATTRIBUTE_TYPE_UINT = 2, + B_HPKG_ATTRIBUTE_TYPE_STRING = 3, + B_HPKG_ATTRIBUTE_TYPE_RAW = 4 +}; + + +// attribute encodings +enum { + // signed/unsigned int encodings + B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT = 0, + B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT = 1, + B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT = 2, + B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT = 3, + + // string encodings + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE = 0, + // null-terminated string + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE = 1, + // unsigned LEB128 index into string table + + // raw data encodings + B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE = 0, + // unsigned LEB128 size, raw bytes + B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP = 1 + // unsigned LEB128 size, unsigned LEB128 offset into the heap +}; + + +// maximum number of bytes of data to be encoded inline; more will be allocated +// on the heap +#define B_HPKG_MAX_INLINE_DATA_SIZE 8 + + +// name of file containing package information (in package's root folder) +#define B_HPKG_PACKAGE_INFO_FILE_NAME ".PackageInfo" + + +// default values +enum { + B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB = 64 * 1024 +}; + + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__HPKG_DEFS_H_ diff --git a/headers/private/package/hpkg/PackageAttributeValue.h b/headers/os/package/hpkg/PackageAttributeValue.h similarity index 68% rename from headers/private/package/hpkg/PackageAttributeValue.h rename to headers/os/package/hpkg/PackageAttributeValue.h index dfded18b42..8322cbb9c4 100644 --- a/headers/private/package/hpkg/PackageAttributeValue.h +++ b/headers/os/package/hpkg/PackageAttributeValue.h @@ -2,23 +2,21 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef PACKAGE_ATTRIBUTE_VALUE_H -#define PACKAGE_ATTRIBUTE_VALUE_H +#ifndef _PACKAGE__HPKG__PACKAGE_ATTRIBUTE_VALUE_H_ +#define _PACKAGE__HPKG__PACKAGE_ATTRIBUTE_VALUE_H_ #include -#include +#include namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -struct PackageAttributeValue { +struct BPackageAttributeValue { union { int64 signedInt; uint64 unsignedInt; @@ -35,7 +33,7 @@ struct PackageAttributeValue { uint8 encoding; public: - inline PackageAttributeValue(); + inline BPackageAttributeValue(); inline void SetTo(int8 value); inline void SetTo(uint8 value); @@ -51,7 +49,7 @@ public: }; -PackageAttributeValue::PackageAttributeValue() +BPackageAttributeValue::BPackageAttributeValue() : type(B_HPKG_ATTRIBUTE_TYPE_INVALID) { @@ -59,7 +57,7 @@ PackageAttributeValue::PackageAttributeValue() void -PackageAttributeValue::SetTo(int8 value) +BPackageAttributeValue::SetTo(int8 value) { signedInt = value; type = B_HPKG_ATTRIBUTE_TYPE_INT; @@ -67,7 +65,7 @@ PackageAttributeValue::SetTo(int8 value) void -PackageAttributeValue::SetTo(uint8 value) +BPackageAttributeValue::SetTo(uint8 value) { unsignedInt = value; type = B_HPKG_ATTRIBUTE_TYPE_UINT; @@ -75,7 +73,7 @@ PackageAttributeValue::SetTo(uint8 value) void -PackageAttributeValue::SetTo(int16 value) +BPackageAttributeValue::SetTo(int16 value) { signedInt = value; type = B_HPKG_ATTRIBUTE_TYPE_INT; @@ -83,7 +81,7 @@ PackageAttributeValue::SetTo(int16 value) void -PackageAttributeValue::SetTo(uint16 value) +BPackageAttributeValue::SetTo(uint16 value) { unsignedInt = value; type = B_HPKG_ATTRIBUTE_TYPE_UINT; @@ -91,7 +89,7 @@ PackageAttributeValue::SetTo(uint16 value) void -PackageAttributeValue::SetTo(int32 value) +BPackageAttributeValue::SetTo(int32 value) { signedInt = value; type = B_HPKG_ATTRIBUTE_TYPE_INT; @@ -99,7 +97,7 @@ PackageAttributeValue::SetTo(int32 value) void -PackageAttributeValue::SetTo(uint32 value) +BPackageAttributeValue::SetTo(uint32 value) { unsignedInt = value; type = B_HPKG_ATTRIBUTE_TYPE_UINT; @@ -107,7 +105,7 @@ PackageAttributeValue::SetTo(uint32 value) void -PackageAttributeValue::SetTo(int64 value) +BPackageAttributeValue::SetTo(int64 value) { signedInt = value; type = B_HPKG_ATTRIBUTE_TYPE_INT; @@ -115,7 +113,7 @@ PackageAttributeValue::SetTo(int64 value) void -PackageAttributeValue::SetTo(uint64 value) +BPackageAttributeValue::SetTo(uint64 value) { unsignedInt = value; type = B_HPKG_ATTRIBUTE_TYPE_UINT; @@ -123,7 +121,7 @@ PackageAttributeValue::SetTo(uint64 value) void -PackageAttributeValue::SetTo(const char* value) +BPackageAttributeValue::SetTo(const char* value) { string = value; type = B_HPKG_ATTRIBUTE_TYPE_STRING; @@ -131,7 +129,7 @@ PackageAttributeValue::SetTo(const char* value) void -PackageAttributeValue::SetToData(uint64 size, uint64 offset) +BPackageAttributeValue::SetToData(uint64 size, uint64 offset) { data.size = size; data.offset = offset; @@ -141,7 +139,7 @@ PackageAttributeValue::SetToData(uint64 size, uint64 offset) void -PackageAttributeValue::SetToData(uint64 size, const void* rawData) +BPackageAttributeValue::SetToData(uint64 size, const void* rawData) { data.size = size; if (size > 0) @@ -151,11 +149,9 @@ PackageAttributeValue::SetToData(uint64 size, const void* rawData) } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // PACKAGE_ATTRIBUTE_VALUE_H +#endif // _PACKAGE__HPKG__PACKAGE_ATTRIBUTE_VALUE_H_ diff --git a/headers/os/package/hpkg/PackageContentHandler.h b/headers/os/package/hpkg/PackageContentHandler.h new file mode 100644 index 0000000000..637a51dc9e --- /dev/null +++ b/headers/os/package/hpkg/PackageContentHandler.h @@ -0,0 +1,55 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__PACKAGE_CONTENT_HANDLER_H_ +#define _PACKAGE__HPKG__PACKAGE_CONTENT_HANDLER_H_ + + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +class BPackageAttributeValue; +class BPackageEntry; +class BPackageEntryAttribute; + + +class BLowLevelPackageContentHandler { +public: + virtual ~BLowLevelPackageContentHandler(); + + virtual status_t HandleAttribute(const char* attributeName, + const BPackageAttributeValue& value, + void* parentToken, void*& _token) = 0; + virtual status_t HandleAttributeDone(const char* attributeName, + const BPackageAttributeValue& value, + void* token) = 0; + + virtual void HandleErrorOccurred() = 0; +}; + + +class BPackageContentHandler { +public: + virtual ~BPackageContentHandler(); + + virtual status_t HandleEntry(BPackageEntry* entry) = 0; + virtual status_t HandleEntryAttribute(BPackageEntry* entry, + BPackageEntryAttribute* attribute) = 0; + virtual status_t HandleEntryDone(BPackageEntry* entry) = 0; + + virtual void HandleErrorOccurred() = 0; +}; + + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__PACKAGE_CONTENT_HANDLER_H_ diff --git a/headers/private/package/hpkg/PackageData.h b/headers/os/package/hpkg/PackageData.h similarity index 82% rename from headers/private/package/hpkg/PackageData.h rename to headers/os/package/hpkg/PackageData.h index c239a82a01..b692170926 100644 --- a/headers/private/package/hpkg/PackageData.h +++ b/headers/os/package/hpkg/PackageData.h @@ -2,23 +2,21 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef PACKAGE_DATA_H -#define PACKAGE_DATA_H +#ifndef _PACKAGE__HPKG__PACKAGE_DATA_H_ +#define _PACKAGE__HPKG__PACKAGE_DATA_H_ -#include +#include namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -class PackageData { +class BPackageData { public: - PackageData(); + BPackageData(); uint64 CompressedSize() const { return fCompressedSize; } @@ -56,11 +54,9 @@ private: }; -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // PACKAGE_DATA_H +#endif // _PACKAGE__HPKG__PACKAGE_DATA_H_ diff --git a/headers/os/package/hpkg/PackageDataReader.h b/headers/os/package/hpkg/PackageDataReader.h new file mode 100644 index 0000000000..3e205ab905 --- /dev/null +++ b/headers/os/package/hpkg/PackageDataReader.h @@ -0,0 +1,61 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__PACKAGE_DATA_READER_H_ +#define _PACKAGE__HPKG__PACKAGE_DATA_READER_H_ + + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +class BBufferCache; +class BDataOutput; +class BPackageData; + + +class BPackageDataReader : public BDataReader { +public: + BPackageDataReader(BDataReader* dataReader); + virtual ~BPackageDataReader(); + + virtual status_t Init(const BPackageData& data) = 0; + + virtual status_t ReadData(off_t offset, void* buffer, + size_t size); + virtual status_t ReadDataToOutput(off_t offset, size_t size, + BDataOutput* output) = 0; + + virtual uint64 Size() const = 0; + virtual size_t BlockSize() const = 0; + +protected: + BDataReader* fDataReader; +}; + + +class BPackageDataReaderFactory { +public: + BPackageDataReaderFactory( + BBufferCache* bufferCache); + + status_t CreatePackageDataReader(BDataReader* dataReader, + const BPackageData& data, + BPackageDataReader*& _reader); + +private: + BBufferCache* fBufferCache; +}; + + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__PACKAGE_DATA_READER_H_ diff --git a/headers/private/package/hpkg/PackageEntry.h b/headers/os/package/hpkg/PackageEntry.h similarity index 79% rename from headers/private/package/hpkg/PackageEntry.h rename to headers/os/package/hpkg/PackageEntry.h index c1bc00c792..633cd0e491 100644 --- a/headers/private/package/hpkg/PackageEntry.h +++ b/headers/os/package/hpkg/PackageEntry.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef PACKAGE_ENTRY_H -#define PACKAGE_ENTRY_H +#ifndef _PACKAGE__HPKG__PACKAGE_ENTRY_H_ +#define _PACKAGE__HPKG__PACKAGE_ENTRY_H_ #include @@ -13,17 +13,15 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -class PackageEntry { +class BPackageEntry { public: - PackageEntry(PackageEntry* parent, + BPackageEntry(BPackageEntry* parent, const char* name); - const PackageEntry* Parent() const { return fParent; } + const BPackageEntry* Parent() const { return fParent; } const char* Name() const { return fName; } void* UserToken() const { return fUserToken; } @@ -36,7 +34,7 @@ public: const timespec& CreationTime() const { return fCreationTime; } - PackageData& Data() { return fData; } + BPackageData& Data() { return fData; } const char* SymlinkPath() const { return fSymlinkPath; } @@ -62,37 +60,35 @@ public: void SetSymlinkPath(const char* path) { fSymlinkPath = path; } private: - PackageEntry* fParent; + BPackageEntry* fParent; const char* fName; void* fUserToken; mode_t fMode; timespec fAccessTime; timespec fModifiedTime; timespec fCreationTime; - PackageData fData; + BPackageData fData; const char* fSymlinkPath; }; inline void -PackageEntry::SetType(uint32 type) +BPackageEntry::SetType(uint32 type) { fMode = (fMode & ~(uint32)S_IFMT) | (type & S_IFMT); } inline void -PackageEntry::SetPermissions(uint32 permissions) +BPackageEntry::SetPermissions(uint32 permissions) { fMode = (fMode & ~(uint32)ALLPERMS) | (permissions & ALLPERMS); } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // PACKAGE_ENTRY_H +#endif // _PACKAGE__HPKG__PACKAGE_ENTRY_H_ diff --git a/headers/private/package/hpkg/PackageEntryAttribute.h b/headers/os/package/hpkg/PackageEntryAttribute.h similarity index 55% rename from headers/private/package/hpkg/PackageEntryAttribute.h rename to headers/os/package/hpkg/PackageEntryAttribute.h index 3094a3d82a..d40ca6f799 100644 --- a/headers/private/package/hpkg/PackageEntryAttribute.h +++ b/headers/os/package/hpkg/PackageEntryAttribute.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef PACKAGE_ENTRY_ATTRIBUTE_H -#define PACKAGE_ENTRY_ATTRIBUTE_H +#ifndef _PACKAGE__HPKG__PACKAGE_ENTRY_ATTRIBUTE_H_ +#define _PACKAGE__HPKG__PACKAGE_ENTRY_ATTRIBUTE_H_ #include @@ -11,34 +11,30 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -class PackageEntryAttribute { +class BPackageEntryAttribute { public: - PackageEntryAttribute(const char* name); + BPackageEntryAttribute(const char* name); const char* Name() const { return fName; } uint32 Type() const { return fType; } - PackageData& Data() { return fData; } + BPackageData& Data() { return fData; } void SetType(uint32 type) { fType = type; } private: const char* fName; uint32 fType; - PackageData fData; + BPackageData fData; }; -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // PACKAGE_ENTRY_ATTRIBUTE_H +#endif // _PACKAGE__HPKG__PACKAGE_ENTRY_ATTRIBUTE_H_ diff --git a/headers/os/package/hpkg/PackageReader.h b/headers/os/package/hpkg/PackageReader.h new file mode 100644 index 0000000000..c8dda4c80b --- /dev/null +++ b/headers/os/package/hpkg/PackageReader.h @@ -0,0 +1,51 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__PACKAGE_READER_H_ +#define _PACKAGE__HPKG__PACKAGE_READER_H_ + + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +namespace BPrivate { + class PackageReaderImpl; +} +using BPrivate::PackageReaderImpl; + +class BErrorOutput; +class BLowLevelPackageContentHandler; +class BPackageContentHandler; + + +class BPackageReader { +public: + BPackageReader( + BErrorOutput* errorOutput); + ~BPackageReader(); + + status_t Init(const char* fileName); + status_t Init(int fd, bool keepFD); + status_t ParseContent( + BPackageContentHandler* contentHandler); + status_t ParseContent(BLowLevelPackageContentHandler* + contentHandler); + + int PackageFileFD(); +private: + PackageReaderImpl* fImpl; +}; + + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__PRIVATE__PACKAGE_READER_H_ diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h new file mode 100644 index 0000000000..51f372181a --- /dev/null +++ b/headers/os/package/hpkg/PackageWriter.h @@ -0,0 +1,42 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__PACKAGE_WRITER_H_ +#define _PACKAGE__HPKG__PACKAGE_WRITER_H_ + + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +namespace BPrivate { + class PackageWriterImpl; +} +using BPrivate::PackageWriterImpl; + + +class BPackageWriter { +public: + BPackageWriter(); + ~BPackageWriter(); + + status_t Init(const char* fileName); + status_t AddEntry(const char* fileName); + status_t Finish(); + +private: + PackageWriterImpl* fImpl; +}; + + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__PACKAGE_WRITER_H_ diff --git a/headers/private/package/hpkg/BlockBufferCache.h b/headers/private/package/hpkg/BlockBufferCache.h deleted file mode 100644 index 137e3ea20a..0000000000 --- a/headers/private/package/hpkg/BlockBufferCache.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ -#ifndef _PACKAGE__HPKG__BLOCK_BUFFER_CACHE_H_ -#define _PACKAGE__HPKG__BLOCK_BUFFER_CACHE_H_ - - -#include - - -namespace BPackageKit { - -namespace BHaikuPackage { - -namespace BPrivate { - - -class BlockBufferCache : public BufferCache { -public: - BlockBufferCache(size_t blockSize, - uint32 maxCachedBlocks); - virtual ~BlockBufferCache(); - - virtual status_t Init(); - - virtual CachedBuffer* GetBuffer(size_t size, - CachedBuffer** owner = NULL, - bool* _newBuffer = NULL); - virtual void PutBufferAndCache(CachedBuffer** owner); - virtual void PutBuffer(CachedBuffer** owner); - - virtual bool Lock() = 0; - virtual void Unlock() = 0; - -private: - typedef DoublyLinkedList BufferList; - -private: - CachedBuffer* _AllocateBuffer(size_t size, - CachedBuffer** owner, bool* _newBuffer); - // object must not be locked - -private: - size_t fBlockSize; - uint32 fMaxCachedBlocks; - uint32 fAllocatedBlocks; - BufferList fUnusedBuffers; - BufferList fCachedBuffers; -}; - - -class BlockBufferCacheNoLock : public BlockBufferCache { -public: - BlockBufferCacheNoLock(size_t blockSize, - uint32 maxCachedBlocks); - virtual ~BlockBufferCacheNoLock(); - - virtual bool Lock(); - virtual void Unlock(); -}; - - -} // namespace BPrivate - -} // namespace BHaikuPackage - -} // namespace BPackageKit - - -#endif // _PACKAGE__HPKG__BLOCK_BUFFER_CACHE_H_ diff --git a/headers/private/package/hpkg/BlockBufferCacheImpl.h b/headers/private/package/hpkg/BlockBufferCacheImpl.h new file mode 100644 index 0000000000..221120a58f --- /dev/null +++ b/headers/private/package/hpkg/BlockBufferCacheImpl.h @@ -0,0 +1,66 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__PRIVATE__BLOCK_BUFFER_CACHE_H_ +#define _PACKAGE__HPKG__PRIVATE__BLOCK_BUFFER_CACHE_H_ + + +#include + +#include + +#include + + +namespace BPackageKit { + +namespace BHPKG { + +namespace BPrivate { + + +class CachedBuffer; + + +class BlockBufferCacheImpl : public BBufferCache { +public: + BlockBufferCacheImpl(size_t blockSize, + uint32 maxCachedBlocks, + BBufferCacheLockable* lockable); + ~BlockBufferCacheImpl(); + + status_t Init(); + + CachedBuffer* GetBuffer(size_t size, + CachedBuffer** owner = NULL, + bool* _newBuffer = NULL); + void PutBufferAndCache(CachedBuffer** owner); + void PutBuffer(CachedBuffer** owner); + +private: + typedef DoublyLinkedList BufferList; + +private: + CachedBuffer* _AllocateBuffer(size_t size, + CachedBuffer** owner, bool* _newBuffer); + // object must not be locked + +private: + size_t fBlockSize; + uint32 fMaxCachedBlocks; + uint32 fAllocatedBlocks; + BufferList fUnusedBuffers; + BufferList fCachedBuffers; + BBufferCacheLockable* fLockable; +}; + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__PRIVATE__BLOCK_BUFFER_CACHE_H_ diff --git a/headers/private/package/hpkg/BufferCache.h b/headers/private/package/hpkg/CachedBuffer.h similarity index 59% rename from headers/private/package/hpkg/BufferCache.h rename to headers/private/package/hpkg/CachedBuffer.h index e3ca3b9b44..9eed663cba 100644 --- a/headers/private/package/hpkg/BufferCache.h +++ b/headers/private/package/hpkg/CachedBuffer.h @@ -2,18 +2,20 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef _PACKAGE__HPKG__BUFFER_CACHE_H_ -#define _PACKAGE__HPKG__BUFFER_CACHE_H_ +#ifndef _PACKAGE__HPKG__PRIVATE__BUFFER_CACHE_H_ +#define _PACKAGE__HPKG__PRIVATE__BUFFER_CACHE_H_ #include #include +#include + namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -43,26 +45,9 @@ private: }; -class BufferCache { -public: - virtual ~BufferCache(); - - virtual CachedBuffer* GetBuffer(size_t size, - CachedBuffer** owner = NULL, - bool* _newBuffer = NULL) = 0; - virtual void PutBufferAndCache(CachedBuffer** owner) = 0; - // caller is buffer owner and wants the - // buffer cached, if possible - virtual void PutBuffer(CachedBuffer** owner) = 0; - // puts the buffer for good, owner might - // have called PutBufferAndCache() before - // and might not own a buffer anymore -}; - - class CachedBufferPutter { public: - CachedBufferPutter(BufferCache* cache, CachedBuffer** owner) + CachedBufferPutter(BBufferCache* cache, CachedBuffer** owner) : fCache(cache), fOwner(owner), @@ -70,7 +55,7 @@ public: { } - CachedBufferPutter(BufferCache* cache, CachedBuffer* buffer) + CachedBufferPutter(BBufferCache* cache, CachedBuffer* buffer) : fCache(cache), fOwner(NULL), @@ -89,7 +74,7 @@ public: } private: - BufferCache* fCache; + BBufferCache* fCache; CachedBuffer** fOwner; CachedBuffer* fBuffer; }; @@ -97,9 +82,9 @@ private: } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // _PACKAGE__HPKG__BUFFER_CACHE_H_ +#endif // _PACKAGE__HPKG__PRIVATE__BUFFER_CACHE_H_ diff --git a/headers/private/package/hpkg/FDCloser.h b/headers/private/package/hpkg/FDCloser.h index 79a4dbefab..afb4e7b5c2 100644 --- a/headers/private/package/hpkg/FDCloser.h +++ b/headers/private/package/hpkg/FDCloser.h @@ -2,15 +2,13 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef FD_CLOSER_H -#define FD_CLOSER_H +#ifndef _PACKAGE__HPKG__FD_CLOSER_H_ +#define _PACKAGE__HPKG__FD_CLOSER_H_ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { struct FDCloser { @@ -31,11 +29,9 @@ private: }; -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // FD_CLOSER_H +#endif // _PACKAGE__HPKG__FD_CLOSER_H_ diff --git a/headers/private/package/hpkg/PackageDataReader.h b/headers/private/package/hpkg/PackageDataReader.h deleted file mode 100644 index 7913792356..0000000000 --- a/headers/private/package/hpkg/PackageDataReader.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ -#ifndef PACKAGE_DATA_READER_H -#define PACKAGE_DATA_READER_H - - -#include - - -namespace BPackageKit { - -namespace BHaikuPackage { - -namespace BPrivate { - - -class BufferCache; -class DataOutput; -class PackageData; - - -class PackageDataReader : public DataReader { -public: - PackageDataReader(DataReader* dataReader); - virtual ~PackageDataReader(); - - virtual status_t Init(const PackageData& data) = 0; - - virtual status_t ReadData(off_t offset, void* buffer, - size_t size); - virtual status_t ReadDataToOutput(off_t offset, size_t size, - DataOutput* output) = 0; - - virtual uint64 Size() const = 0; - virtual size_t BlockSize() const = 0; - -protected: - DataReader* fDataReader; -}; - - -class PackageDataReaderFactory { -public: - PackageDataReaderFactory( - BufferCache* bufferCache); - - status_t CreatePackageDataReader(DataReader* dataReader, - const PackageData& data, - PackageDataReader*& _reader); - -private: - BufferCache* fBufferCache; -}; - - -} // namespace BPrivate - -} // namespace BHaikuPackage - -} // namespace BPackageKit - - -#endif // PACKAGE_DATA_READER_H diff --git a/headers/private/package/hpkg/PackageReader.h b/headers/private/package/hpkg/PackageReaderImpl.h similarity index 71% rename from headers/private/package/hpkg/PackageReader.h rename to headers/private/package/hpkg/PackageReaderImpl.h index cdb6f2d8d6..c8735dbd97 100644 --- a/headers/private/package/hpkg/PackageReader.h +++ b/headers/private/package/hpkg/PackageReaderImpl.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef PACKAGE_READER_H -#define PACKAGE_READER_H +#ifndef _PACKAGE__HPKG__PRIVATE__PACKAGE_READER_IMPL_H_ +#define _PACKAGE__HPKG__PRIVATE__PACKAGE_READER_IMPL_H_ #include @@ -11,59 +11,34 @@ #include #include +#include +#include namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { + + +class BPackageEntry; +class BPackageEntryAttribute; +class BErrorOutput; + namespace BPrivate { -class ErrorOutput; -class PackageEntry; -class PackageEntryAttribute; - - -class LowLevelPackageContentHandler { +class PackageReaderImpl { public: - virtual ~LowLevelPackageContentHandler(); - - virtual status_t HandleAttribute(const char* attributeName, - const PackageAttributeValue& value, - void* parentToken, void*& _token) = 0; - virtual status_t HandleAttributeDone(const char* attributeName, - const PackageAttributeValue& value, - void* token) = 0; - - virtual void HandleErrorOccurred() = 0; -}; - - -class PackageContentHandler { -public: - virtual ~PackageContentHandler(); - - virtual status_t HandleEntry(PackageEntry* entry) = 0; - virtual status_t HandleEntryAttribute(PackageEntry* entry, - PackageEntryAttribute* attribute) = 0; - virtual status_t HandleEntryDone(PackageEntry* entry) = 0; - - virtual void HandleErrorOccurred() = 0; -}; - - -class PackageReader { -public: - PackageReader(ErrorOutput* errorOutput); - ~PackageReader(); + PackageReaderImpl( + BErrorOutput* errorOutput); + ~PackageReaderImpl(); status_t Init(const char* fileName); status_t Init(int fd, bool keepFD); status_t ParseContent( - PackageContentHandler* contentHandler); - status_t ParseContent( - LowLevelPackageContentHandler* + BPackageContentHandler* contentHandler); + status_t ParseContent(BLowLevelPackageContentHandler* contentHandler); int PackageFileFD() { return fFD; } @@ -81,7 +56,7 @@ private: struct PackageAttributeHandler; struct PackageContentListHandler; - typedef PackageAttributeValue AttributeValue; + typedef BPackageAttributeValue AttributeValue; typedef SinglyLinkedList AttributeHandlerList; private: @@ -128,7 +103,7 @@ private: inline AttributeHandler* _PopAttributeHandler(); private: - ErrorOutput* fErrorOutput; + BErrorOutput* fErrorOutput; int fFD; bool fOwnsFD; @@ -164,7 +139,7 @@ private: template status_t -PackageReader::_Read(Type& _value) +PackageReaderImpl::_Read(Type& _value) { return _ReadTOCBuffer(&_value, sizeof(Type)); } @@ -172,9 +147,9 @@ PackageReader::_Read(Type& _value) } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // PACKAGE_READER_H +#endif // _PACKAGE__HPKG__PRIVATE__PACKAGE_READER_IMPL_H_ diff --git a/headers/private/package/hpkg/PackageWriter.h b/headers/private/package/hpkg/PackageWriterImpl.h similarity index 85% rename from headers/private/package/hpkg/PackageWriter.h rename to headers/private/package/hpkg/PackageWriterImpl.h index 1f8354e2e0..2d4e40ec84 100644 --- a/headers/private/package/hpkg/PackageWriter.h +++ b/headers/private/package/hpkg/PackageWriterImpl.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef PACKAGE_WRITER_H -#define PACKAGE_WRITER_H +#ifndef _PACKAGE__HPKG__PRIVATE__PACKAGE_WRITER_IMPL_H_ +#define _PACKAGE__HPKG__PRIVATE__PACKAGE_WRITER_IMPL_H_ #include @@ -14,23 +14,25 @@ namespace BPackageKit { -namespace BHaikuPackage { + +class BPackageInfo; + + +namespace BHPKG { + + +class BDataReader; + namespace BPrivate { -class DataReader; struct hpkg_header; -namespace BPackageKit { - class BPackageInfo; -} - - -class PackageWriter { +class PackageWriterImpl { public: - PackageWriter(); - ~PackageWriter(); + PackageWriterImpl(); + ~PackageWriterImpl(); status_t Init(const char* fileName); status_t AddEntry(const char* fileName); @@ -104,10 +106,10 @@ private: AttributeType* _GetAttributeType(const char* attributeName, uint8 type); - status_t _AddData(DataReader& dataReader, off_t size); - status_t _WriteUncompressedData(DataReader& dataReader, + status_t _AddData(BDataReader& dataReader, off_t size); + status_t _WriteUncompressedData(BDataReader& dataReader, off_t size, uint64 writeOffset); - status_t _WriteZlibCompressedData(DataReader& dataReader, + status_t _WriteZlibCompressedData(BDataReader& dataReader, off_t size, uint64 writeOffset, uint64& _compressedSize); @@ -134,9 +136,9 @@ private: } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // PACKAGE_WRITER_H +#endif // _PACKAGE__HPKG__PRIVATE__PACKAGE_WRITER_IMPL_H_ diff --git a/headers/private/package/hpkg/Stacker.h b/headers/private/package/hpkg/Stacker.h index 34bcd178eb..f874cd4091 100644 --- a/headers/private/package/hpkg/Stacker.h +++ b/headers/private/package/hpkg/Stacker.h @@ -2,13 +2,13 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef STACKER_H -#define STACKER_H +#ifndef _PACKAGE__HPKG__PRIVATE__STACKER_H_ +#define _PACKAGE__HPKG__PRIVATE__STACKER_H_ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -46,9 +46,9 @@ private: } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // STACKER_H +#endif // _PACKAGE__HPKG__PRIVATE__STACKER_H_ diff --git a/headers/private/package/hpkg/Strings.h b/headers/private/package/hpkg/Strings.h index 78d03c0e97..275ab183eb 100644 --- a/headers/private/package/hpkg/Strings.h +++ b/headers/private/package/hpkg/Strings.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef STRINGS_H -#define STRINGS_H +#ifndef _PACKAGE__HPKG__PRIVATE__STRINGS_H_ +#define _PACKAGE__HPKG__PRIVATE__STRINGS_H_ #include @@ -11,7 +11,7 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -88,9 +88,9 @@ struct CachedStringUsageGreater { } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // STRINGS_H +#endif // _PACKAGE__HPKG__PRIVATE__STRINGS_H_ diff --git a/headers/private/package/hpkg/ZlibCompressionBase.h b/headers/private/package/hpkg/ZlibCompressionBase.h index 960f4186cd..786e579908 100644 --- a/headers/private/package/hpkg/ZlibCompressionBase.h +++ b/headers/private/package/hpkg/ZlibCompressionBase.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef ZLIB_COMPRESSION_BASE_H -#define ZLIB_COMPRESSION_BASE_H +#ifndef _PACKAGE__HPKG__PRIVATE__ZLIB_COMPRESSION_BASE_H_ +#define _PACKAGE__HPKG__PRIVATE__ZLIB_COMPRESSION_BASE_H_ #include @@ -11,7 +11,7 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -24,9 +24,9 @@ public: } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // ZLIB_COMPRESSION_BASE_H +#endif // _PACKAGE__HPKG__PRIVATE__ZLIB_COMPRESSION_BASE_H_ diff --git a/headers/private/package/hpkg/ZlibCompressor.h b/headers/private/package/hpkg/ZlibCompressor.h index cd28c66185..d29abdd056 100644 --- a/headers/private/package/hpkg/ZlibCompressor.h +++ b/headers/private/package/hpkg/ZlibCompressor.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef ZLIB_COMPRESSOR_H -#define ZLIB_COMPRESSOR_H +#ifndef _PACKAGE__HPKG__PRIVATE__ZLIB_COMPRESSOR_H_ +#define _PACKAGE__HPKG__PRIVATE__ZLIB_COMPRESSOR_H_ #include @@ -13,17 +13,18 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { + + +class BDataOutput; + namespace BPrivate { -class DataOutput; - - class ZlibCompressor : public ZlibCompressionBase { public: - ZlibCompressor(DataOutput* output); + ZlibCompressor(BDataOutput* output); ~ZlibCompressor(); status_t Init(); @@ -37,16 +38,16 @@ public: private: z_stream fStream; - DataOutput* fOutput; + BDataOutput* fOutput; bool fStreamInitialized; }; } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // ZLIB_COMPRESSOR_H +#endif // _PACKAGE__HPKG__PRIVATE__ZLIB_COMPRESSOR_H_ diff --git a/headers/private/package/hpkg/ZlibDecompressor.h b/headers/private/package/hpkg/ZlibDecompressor.h index 8d7b0c225c..8d4556b236 100644 --- a/headers/private/package/hpkg/ZlibDecompressor.h +++ b/headers/private/package/hpkg/ZlibDecompressor.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef ZLIB_DECOMPRESSOR_H -#define ZLIB_DECOMPRESSOR_H +#ifndef _PACKAGE__HPKG__PRIVATE__ZLIB_DECOMPRESSOR_H_ +#define _PACKAGE__HPKG__PRIVATE__ZLIB_DECOMPRESSOR_H_ #include @@ -13,17 +13,18 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { + + +class BDataOutput; + namespace BPrivate { -class DataOutput; - - class ZlibDecompressor : public ZlibCompressionBase { public: - ZlibDecompressor(DataOutput* output); + ZlibDecompressor(BDataOutput* output); ~ZlibDecompressor(); status_t Init(); @@ -38,7 +39,7 @@ public: private: z_stream fStream; - DataOutput* fOutput; + BDataOutput* fOutput; bool fStreamInitialized; bool fFinished; }; @@ -46,9 +47,9 @@ private: } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // ZLIB_DECOMPRESSOR_H +#endif // _PACKAGE__HPKG__PRIVATE__ZLIB_DECOMPRESSOR_H_ diff --git a/headers/private/package/hpkg/haiku_package.h b/headers/private/package/hpkg/haiku_package.h index 48315f1b30..1910d03010 100644 --- a/headers/private/package/hpkg/haiku_package.h +++ b/headers/private/package/hpkg/haiku_package.h @@ -2,16 +2,18 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef _HAIKU_PACKAGE_H -#define _HAIKU_PACKAGE_H +#ifndef _PACKAGE__HPKG__PRIVATE__HAIKU_PACKAGE_H_ +#define _PACKAGE__HPKG__PRIVATE__HAIKU_PACKAGE_H_ #include +#include + namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -40,13 +42,6 @@ struct hpkg_header { }; -// magic, version -enum { - B_HPKG_MAGIC = 'hpkg', - B_HPKG_VERSION = 1 -}; - - // compression types enum { B_HPKG_COMPRESSION_NONE = 0, @@ -54,39 +49,6 @@ enum { }; -// attribute types -enum { - // types - B_HPKG_ATTRIBUTE_TYPE_INVALID = 0, - B_HPKG_ATTRIBUTE_TYPE_INT = 1, - B_HPKG_ATTRIBUTE_TYPE_UINT = 2, - B_HPKG_ATTRIBUTE_TYPE_STRING = 3, - B_HPKG_ATTRIBUTE_TYPE_RAW = 4 -}; - - -// attribute encodings -enum { - // signed/unsigned int encodings - B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT = 0, - B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT = 1, - B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT = 2, - B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT = 3, - - // string encodings - B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE = 0, - // null-terminated string - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE = 1, - // unsigned LEB128 index into string table - - // raw data encodings - B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE = 0, - // unsigned LEB128 size, raw bytes - B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP = 1 - // unsigned LEB128 size, unsigned LEB128 offset into the heap -}; - - // attribute tag arithmetics #define B_HPKG_ATTRIBUTE_TAG_COMPOSE(index, encoding, hasChildren) \ (((uint64(index) << 3) | uint64(encoding) << 1 \ @@ -143,15 +105,6 @@ enum { }; -// maximum number of bytes of data to be encoded inline; more will be allocated -// on the heap -#define B_HPKG_MAX_INLINE_DATA_SIZE 8 - - -// name of file containing package information (in package's root folder) -#define B_HPKG_PACKAGE_INFO_FILE_NAME ".PackageInfo" - - // default values enum { B_HPKG_DEFAULT_FILE_TYPE = B_HPKG_FILE_TYPE_FILE, @@ -159,15 +112,14 @@ enum { B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS = 0755, B_HPKG_DEFAULT_SYMLINK_PERMISSIONS = 0777, B_HPKG_DEFAULT_DATA_COMPRESSION = B_HPKG_COMPRESSION_NONE, - B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB = 64 * 1024 }; } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit -#endif // _HAIKU_PACKAGE_H +#endif // _PACKAGE__HPKG__PRIVATE__HAIKU_PACKAGE_H_ diff --git a/src/add-ons/kernel/file_systems/packagefs/BlockBufferCacheKernel.cpp b/src/add-ons/kernel/file_systems/packagefs/BlockBufferCacheKernel.cpp index 57c63f91b1..fdc27b847d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/BlockBufferCacheKernel.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/BlockBufferCacheKernel.cpp @@ -10,7 +10,7 @@ BlockBufferCacheKernel::BlockBufferCacheKernel(size_t blockSize, uint32 maxCachedBlocks) : - BlockBufferCache(blockSize, maxCachedBlocks) + BlockBufferCacheImpl(blockSize, maxCachedBlocks, this) { mutex_init(&fLock, "BlockBufferCache"); } diff --git a/src/add-ons/kernel/file_systems/packagefs/BlockBufferCacheKernel.h b/src/add-ons/kernel/file_systems/packagefs/BlockBufferCacheKernel.h index 4f80a476f7..3756e02119 100644 --- a/src/add-ons/kernel/file_systems/packagefs/BlockBufferCacheKernel.h +++ b/src/add-ons/kernel/file_systems/packagefs/BlockBufferCacheKernel.h @@ -6,15 +6,18 @@ #define BLOCK_BUFFER_CACHE_KERNEL_H -#include +#include -#include +#include +#include -using BPackageKit::BHaikuPackage::BPrivate::BlockBufferCache; +using BPackageKit::BHPKG::BBufferCacheLockable; +using BPackageKit::BHPKG::BPrivate::BlockBufferCacheImpl; -class BlockBufferCacheKernel : public BlockBufferCache { +class BlockBufferCacheKernel + : public BlockBufferCacheImpl, BBufferCacheLockable { public: BlockBufferCacheKernel(size_t blockSize, uint32 maxCachedBlocks); diff --git a/src/add-ons/kernel/file_systems/packagefs/GlobalFactory.cpp b/src/add-ons/kernel/file_systems/packagefs/GlobalFactory.cpp index 9646e9f6b8..c501079d70 100644 --- a/src/add-ons/kernel/file_systems/packagefs/GlobalFactory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/GlobalFactory.cpp @@ -66,8 +66,8 @@ GlobalFactory::Default() status_t -GlobalFactory::CreatePackageDataReader(DataReader* dataReader, - const PackageData& data, PackageDataReader*& _reader) +GlobalFactory::CreatePackageDataReader(BDataReader* dataReader, + const BPackageData& data, BPackageDataReader*& _reader) { return fPackageDataReaderFactory.CreatePackageDataReader(dataReader, data, _reader); diff --git a/src/add-ons/kernel/file_systems/packagefs/GlobalFactory.h b/src/add-ons/kernel/file_systems/packagefs/GlobalFactory.h index bf8b3faa54..546d8be0a8 100644 --- a/src/add-ons/kernel/file_systems/packagefs/GlobalFactory.h +++ b/src/add-ons/kernel/file_systems/packagefs/GlobalFactory.h @@ -6,13 +6,17 @@ #define GLOBAL_FACTORY_H -#include +#include #include #include "BlockBufferCacheKernel.h" -using namespace BPackageKit::BHaikuPackage::BPrivate; +using BPackageKit::BHPKG::BDataReader; +using BPackageKit::BHPKG::BPackageData; +using BPackageKit::BHPKG::BPackageDataReader; +using BPackageKit::BHPKG::BPackageDataReaderFactory; +using BPackageKit::BHPKG::B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; class GlobalFactory { @@ -25,9 +29,9 @@ public: static void DeleteDefault(); static GlobalFactory* Default(); - status_t CreatePackageDataReader(DataReader* dataReader, - const PackageData& data, - PackageDataReader*& _reader); + status_t CreatePackageDataReader(BDataReader* dataReader, + const BPackageData& data, + BPackageDataReader*& _reader); private: status_t _Init(); @@ -36,7 +40,7 @@ private: static GlobalFactory* sDefaultInstance; BlockBufferCacheKernel fBufferCache; - PackageDataReaderFactory fPackageDataReaderFactory; + BPackageDataReaderFactory fPackageDataReaderFactory; }; #endif // GLOBAL_FACTORY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 7b0f5d085c..77345e8e09 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -29,16 +29,18 @@ HAIKU_PACKAGE_FS_SOURCES = ; HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES = - BlockBufferCache.cpp + BlockBufferCacheImpl.cpp BufferCache.cpp + CachedBuffer.cpp DataOutput.cpp DataReader.cpp ErrorOutput.cpp - PackageEntryAttribute.cpp + PackageContentHandler.cpp PackageData.cpp PackageDataReader.cpp PackageEntry.cpp - PackageReader.cpp + PackageEntryAttribute.cpp + PackageReaderImpl.cpp # compression ZlibCompressionBase.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp index 52cd63f65d..d61f36b533 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -20,13 +21,13 @@ #include "Package.h" -using namespace BPackageKit::BHaikuPackage::BPrivate; +using namespace BPackageKit::BHPKG; // #pragma mark - DataAccessor -struct PackageFile::IORequestOutput : DataOutput { +struct PackageFile::IORequestOutput : BDataOutput { public: IORequestOutput(io_request* request) : @@ -45,7 +46,7 @@ private: struct PackageFile::DataAccessor { - DataAccessor(PackageData* data) + DataAccessor(BPackageData* data) : fData(data), fDataReader(NULL), @@ -65,17 +66,17 @@ struct PackageFile::DataAccessor { status_t Init(dev_t deviceID, ino_t nodeID, int fd) { - // create a DataReader for the compressed data + // create a BDataReader for the compressed data if (fData->IsEncodedInline()) { - fDataReader = new(std::nothrow) BufferDataReader( + fDataReader = new(std::nothrow) BBufferDataReader( fData->InlineData(), fData->CompressedSize()); } else - fDataReader = new(std::nothrow) FDDataReader(fd); + fDataReader = new(std::nothrow) BFDDataReader(fd); if (fDataReader == NULL) RETURN_ERROR(B_NO_MEMORY); - // create a PackageDataReader + // create a BPackageDataReader status_t error = GlobalFactory::Default()->CreatePackageDataReader( fDataReader, *fData, fReader); if (error != B_OK) @@ -125,9 +126,9 @@ struct PackageFile::DataAccessor { private: mutex fLock; - PackageData* fData; - DataReader* fDataReader; - PackageDataReader* fReader; + BPackageData* fData; + BDataReader* fDataReader; + BPackageDataReader* fReader; void* fFileCache; }; @@ -135,7 +136,7 @@ private: // #pragma mark - PackageFile -PackageFile::PackageFile(Package* package, mode_t mode, const PackageData& data) +PackageFile::PackageFile(Package* package, mode_t mode, const BPackageData& data) : PackageLeafNode(package, mode), fData(data), diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFile.h b/src/add-ons/kernel/file_systems/packagefs/PackageFile.h index 6d27352d93..cf577e9bb9 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFile.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFile.h @@ -11,13 +11,13 @@ #include "PackageLeafNode.h" -using BPackageKit::BHaikuPackage::BPrivate::PackageData; +using BPackageKit::BHPKG::BPackageData; class PackageFile : public PackageLeafNode { public: PackageFile(Package* package, mode_t mode, - const PackageData& data); + const BPackageData& data); virtual ~PackageFile(); virtual status_t VFSInit(dev_t deviceID, ino_t nodeID); @@ -34,7 +34,7 @@ private: struct DataAccessor; private: - PackageData fData; + BPackageData fData; DataAccessor* fDataAccessor; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h index 7b52fc6baa..b5fca3e0e2 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h @@ -11,7 +11,7 @@ #include -class PackageData; +class BPackageData; class PackageLeafNode : public PackageNode { diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp index 0e361bf347..8644546c1e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp @@ -11,7 +11,7 @@ PackageNodeAttribute::PackageNodeAttribute(PackageNode* parent, uint32 type, - const PackageData& data) + const BPackageData& data) : fData(data), fParent(parent), diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h index f75e8ec1fc..62dd9c5213 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h @@ -11,7 +11,7 @@ #include -using BPackageKit::BHaikuPackage::BPrivate::PackageData; +using BPackageKit::BHPKG::BPackageData; class PackageNode; @@ -20,19 +20,19 @@ class PackageNodeAttribute : public DoublyLinkedListLinkImpl { public: PackageNodeAttribute(PackageNode* parent, - uint32 type, const PackageData& data); + uint32 type, const BPackageData& data); ~PackageNodeAttribute(); PackageNode* Parent() const { return fParent; } const char* Name() const { return fName; } uint32 Type() const { return fType; } - const PackageData& Data() const { return fData; } + const BPackageData& Data() const { return fData; } status_t Init(const char* name); protected: - PackageData fData; + BPackageData fData; PackageNode* fParent; char* fName; uint32 fType; diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 48ddbc163f..5d2d6d7185 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "DebugSupport.h" #include "Directory.h" @@ -38,7 +38,8 @@ #include "PackageSymlink.h" -using namespace BPackageKit::BHaikuPackage::BPrivate; +using namespace BPackageKit::BHPKG; +using BPackageKit::BHPKG::BPrivate::PackageReaderImpl; // node ID of the root directory @@ -131,7 +132,7 @@ private: // #pragma mark - PackageLoaderErrorOutput -struct Volume::PackageLoaderErrorOutput : ErrorOutput { +struct Volume::PackageLoaderErrorOutput : BErrorOutput { PackageLoaderErrorOutput(Package* package) : fPackage(package) @@ -151,7 +152,7 @@ private: // #pragma mark - PackageLoaderContentHandler -struct Volume::PackageLoaderContentHandler : PackageContentHandler { +struct Volume::PackageLoaderContentHandler : BPackageContentHandler { PackageLoaderContentHandler(Package* package) : fPackage(package), @@ -164,7 +165,7 @@ struct Volume::PackageLoaderContentHandler : PackageContentHandler { return B_OK; } - virtual status_t HandleEntry(PackageEntry* entry) + virtual status_t HandleEntry(BPackageEntry* entry) { if (fErrorOccurred) return B_OK; @@ -228,8 +229,8 @@ struct Volume::PackageLoaderContentHandler : PackageContentHandler { return B_OK; } - virtual status_t HandleEntryAttribute(PackageEntry* entry, - PackageEntryAttribute* attribute) + virtual status_t HandleEntryAttribute(BPackageEntry* entry, + BPackageEntryAttribute* attribute) { if (fErrorOccurred) return B_OK; @@ -252,7 +253,7 @@ struct Volume::PackageLoaderContentHandler : PackageContentHandler { return B_OK; } - virtual status_t HandleEntryDone(PackageEntry* entry) + virtual status_t HandleEntryDone(BPackageEntry* entry) { return B_OK; } @@ -604,7 +605,7 @@ Volume::_LoadPackage(Package* package) // initialize package reader PackageLoaderErrorOutput errorOutput(package); - PackageReader packageReader(&errorOutput); + PackageReaderImpl packageReader(&errorOutput); status_t error = packageReader.Init(fd, false); if (error != B_OK) return error; diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index cd52cd6a11..0478c25f92 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -25,6 +25,10 @@ #include "Volume.h" +using BPackageKit::BHPKG::BBufferDataReader; +using BPackageKit::BHPKG::BFDDataReader; + + static const uint32 kOptimalIOSize = 64 * 1024; @@ -939,16 +943,16 @@ packagefs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) static status_t -read_package_data(const PackageData& data, DataReader* dataReader, off_t offset, +read_package_data(const BPackageData& data, BDataReader* dataReader, off_t offset, void* buffer, size_t* bufferSize) { - // create a PackageDataReader - PackageDataReader* reader; + // create a BPackageDataReader + BPackageDataReader* reader; status_t error = GlobalFactory::Default()->CreatePackageDataReader( dataReader, data, reader); if (error != B_OK) RETURN_ERROR(error); - ObjectDeleter readerDeleter(reader); + ObjectDeleter readerDeleter(reader); // check the offset if (offset < 0 || (uint64)offset > data.UncompressedSize()) @@ -983,10 +987,10 @@ packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, TOUCH(volume); TOUCH(node); - const PackageData& data = cookie->attribute->Data(); + const BPackageData& data = cookie->attribute->Data(); if (data.IsEncodedInline()) { // inline data - BufferDataReader dataReader(data.InlineData(), data.CompressedSize()); + BBufferDataReader dataReader(data.InlineData(), data.CompressedSize()); return read_package_data(data, &dataReader, offset, buffer, bufferSize); } @@ -996,7 +1000,7 @@ packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, RETURN_ERROR(fd); PackageCloser packageCloser(cookie->package); - FDDataReader dataReader(fd); + BFDDataReader dataReader(fd); return read_package_data(data, &dataReader, offset, buffer, bufferSize); } diff --git a/src/bin/package/BlockBufferCacheNoLock.cpp b/src/bin/package/BlockBufferCacheNoLock.cpp new file mode 100644 index 0000000000..6c741aad5e --- /dev/null +++ b/src/bin/package/BlockBufferCacheNoLock.cpp @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "BlockBufferCacheNoLock.h" + + +BlockBufferCacheNoLock::BlockBufferCacheNoLock(size_t blockSize, + uint32 maxCachedBlocks) + : + BBlockBufferCache(blockSize, maxCachedBlocks) +{ +} + + +BlockBufferCacheNoLock::~BlockBufferCacheNoLock() +{ +} + + +bool +BlockBufferCacheNoLock::Lock() +{ + return true; +} + + +void +BlockBufferCacheNoLock::Unlock() +{ +} diff --git a/src/bin/package/BlockBufferCacheNoLock.h b/src/bin/package/BlockBufferCacheNoLock.h new file mode 100644 index 0000000000..bf4c47b452 --- /dev/null +++ b/src/bin/package/BlockBufferCacheNoLock.h @@ -0,0 +1,26 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef BLOCK_BUFFER_CACHE_NO_LOCK_H +#define BLOCK_BUFFER_CACHE_NO_LOCK_H + + +#include + + +using BPackageKit::BHPKG::BBlockBufferCache; + + +class BlockBufferCacheNoLock : public BBlockBufferCache { +public: + BlockBufferCacheNoLock(size_t blockSize, + uint32 maxCachedBlocks); + virtual ~BlockBufferCacheNoLock(); + + virtual bool Lock(); + virtual void Unlock(); +}; + + +#endif // BLOCK_BUFFER_CACHE_NO_LOCK_H diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile index 70c4ae3568..dd787c71d6 100644 --- a/src/bin/package/Jamfile +++ b/src/bin/package/Jamfile @@ -6,6 +6,7 @@ DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ; # TODO: Remove when it is complete! BinCommand package : + BlockBufferCacheNoLock.cpp command_create.cpp command_dump.cpp command_extract.cpp diff --git a/src/bin/package/StandardErrorOutput.h b/src/bin/package/StandardErrorOutput.h index b1f34727e1..c619443180 100644 --- a/src/bin/package/StandardErrorOutput.h +++ b/src/bin/package/StandardErrorOutput.h @@ -9,10 +9,10 @@ #include -using BPackageKit::BHaikuPackage::BPrivate::ErrorOutput; +using BPackageKit::BHPKG::BErrorOutput; -class StandardErrorOutput : public ErrorOutput { +class StandardErrorOutput : public BErrorOutput { virtual void PrintErrorVarArgs(const char* format, va_list args); }; diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp index 73733f6400..133bb85ae6 100644 --- a/src/bin/package/command_create.cpp +++ b/src/bin/package/command_create.cpp @@ -14,14 +14,14 @@ #include #include -#include +#include #include #include "package.h" using BPackageKit::BPackageInfo; -using BPackageKit::BHaikuPackage::BPrivate::PackageWriter; +using BPackageKit::BHPKG::BPackageWriter; int @@ -65,7 +65,7 @@ command_create(int argc, const char* const* argv) int fileNameCount = argc - optind; // create package - PackageWriter packageWriter; + BPackageWriter packageWriter; status_t error = packageWriter.Init(packageFileName); printf("Init(): %s\n", strerror(error)); if (error != B_OK) diff --git a/src/bin/package/command_dump.cpp b/src/bin/package/command_dump.cpp index 486d80ba4c..02f4abe7cc 100644 --- a/src/bin/package/command_dump.cpp +++ b/src/bin/package/command_dump.cpp @@ -11,6 +11,9 @@ #include #include +#include +#include +#include #include #include #include @@ -19,10 +22,10 @@ #include "StandardErrorOutput.h" -using namespace BPackageKit::BHaikuPackage::BPrivate; +using namespace BPackageKit::BHPKG; -struct PackageContentDumpHandler : LowLevelPackageContentHandler { +struct PackageContentDumpHandler : BLowLevelPackageContentHandler { PackageContentDumpHandler() : fLevel(0), @@ -32,7 +35,7 @@ struct PackageContentDumpHandler : LowLevelPackageContentHandler { } virtual status_t HandleAttribute(const char* attributeName, - const PackageAttributeValue& value, void* parentToken, void*& _token) + const BPackageAttributeValue& value, void* parentToken, void*& _token) { if (fErrorOccurred) return B_OK; @@ -47,7 +50,7 @@ struct PackageContentDumpHandler : LowLevelPackageContentHandler { } virtual status_t HandleAttributeDone(const char* attributeName, - const PackageAttributeValue& value, void* token) + const BPackageAttributeValue& value, void* token) { if (fErrorOccurred) return B_OK; @@ -67,7 +70,7 @@ struct PackageContentDumpHandler : LowLevelPackageContentHandler { } private: - void _PrintValue(const PackageAttributeValue& value) + void _PrintValue(const BPackageAttributeValue& value) { switch (value.type) { case B_HPKG_ATTRIBUTE_TYPE_INT: @@ -139,7 +142,7 @@ command_dump(int argc, const char* const* argv) // open package StandardErrorOutput errorOutput; - PackageReader packageReader(&errorOutput); + BPackageReader packageReader(&errorOutput); status_t error = packageReader.Init(packageFileName); printf("Init(): %s\n", strerror(error)); if (error != B_OK) diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp index c149d75ccf..d29b089b24 100644 --- a/src/bin/package/command_extract.cpp +++ b/src/bin/package/command_extract.cpp @@ -21,21 +21,22 @@ #include -#include #include +#include #include #include #include #include +#include "BlockBufferCacheNoLock.h" #include "package.h" #include "StandardErrorOutput.h" -using namespace BPackageKit::BHaikuPackage::BPrivate; +using namespace BPackageKit::BHPKG; -struct PackageContentExtractHandler : PackageContentHandler { +struct PackageContentExtractHandler : BPackageContentHandler { PackageContentExtractHandler(int packageFileFD) : fBufferCache(B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, 2), @@ -65,7 +66,7 @@ struct PackageContentExtractHandler : PackageContentHandler { return B_OK; } - virtual status_t HandleEntry(PackageEntry* entry) + virtual status_t HandleEntry(BPackageEntry* entry) { // create a token Token* token = new(std::nothrow) Token; @@ -124,9 +125,9 @@ struct PackageContentExtractHandler : PackageContentHandler { // write data status_t error; - const PackageData& data = entry->Data(); + const BPackageData& data = entry->Data(); if (data.IsEncodedInline()) { - BufferDataReader dataReader(data.InlineData(), + BBufferDataReader dataReader(data.InlineData(), data.CompressedSize()); error = _ExtractFileData(&dataReader, data, fd); } else @@ -183,8 +184,8 @@ struct PackageContentExtractHandler : PackageContentHandler { return B_OK; } - virtual status_t HandleEntryAttribute(PackageEntry* entry, - PackageEntryAttribute* attribute) + virtual status_t HandleEntryAttribute(BPackageEntry* entry, + BPackageEntryAttribute* attribute) { int entryFD = ((Token*)entry->UserToken())->fd; @@ -201,9 +202,9 @@ struct PackageContentExtractHandler : PackageContentHandler { // write data status_t error; - const PackageData& data = attribute->Data(); + const BPackageData& data = attribute->Data(); if (data.IsEncodedInline()) { - BufferDataReader dataReader(data.InlineData(), + BBufferDataReader dataReader(data.InlineData(), data.CompressedSize()); error = _ExtractFileData(&dataReader, data, fd); } else @@ -215,7 +216,7 @@ struct PackageContentExtractHandler : PackageContentHandler { return B_OK; } - virtual status_t HandleEntryDone(PackageEntry* entry) + virtual status_t HandleEntryDone(BPackageEntry* entry) { if (Token* token = (Token*)entry->UserToken()) { delete token; @@ -248,16 +249,16 @@ private: }; private: - status_t _ExtractFileData(DataReader* dataReader, const PackageData& data, + status_t _ExtractFileData(BDataReader* dataReader, const BPackageData& data, int fd) { - // create a PackageDataReader - PackageDataReader* reader; - status_t error = PackageDataReaderFactory(&fBufferCache) + // create a BPackageDataReader + BPackageDataReader* reader; + status_t error = BPackageDataReaderFactory(&fBufferCache) .CreatePackageDataReader(dataReader, data, reader); if (error != B_OK) return error; - ObjectDeleter readerDeleter(reader); + ObjectDeleter readerDeleter(reader); // write the data off_t bytesRemaining = data.UncompressedSize(); @@ -293,7 +294,7 @@ private: private: BlockBufferCacheNoLock fBufferCache; - FDDataReader fPackageFileReader; + BFDDataReader fPackageFileReader; void* fDataBuffer; size_t fDataBufferSize; bool fErrorOccurred; @@ -339,7 +340,7 @@ command_extract(int argc, const char* const* argv) // open package StandardErrorOutput errorOutput; - PackageReader packageReader(&errorOutput); + BPackageReader packageReader(&errorOutput); status_t error = packageReader.Init(packageFileName); printf("Init(): %s\n", strerror(error)); if (error != B_OK) diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp index cb5461506a..9719673971 100644 --- a/src/bin/package/command_list.cpp +++ b/src/bin/package/command_list.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -19,10 +20,10 @@ #include "StandardErrorOutput.h" -using namespace BPackageKit::BHaikuPackage::BPrivate; +using namespace BPackageKit::BHPKG; -struct PackageContentListHandler : PackageContentHandler { +struct PackageContentListHandler : BPackageContentHandler { PackageContentListHandler(bool listAttributes) : fLevel(0), @@ -30,7 +31,7 @@ struct PackageContentListHandler : PackageContentHandler { { } - virtual status_t HandleEntry(PackageEntry* entry) + virtual status_t HandleEntry(BPackageEntry* entry) { fLevel++; @@ -74,8 +75,8 @@ struct PackageContentListHandler : PackageContentHandler { return B_OK; } - virtual status_t HandleEntryAttribute(PackageEntry* entry, - PackageEntryAttribute* attribute) + virtual status_t HandleEntryAttribute(BPackageEntry* entry, + BPackageEntryAttribute* attribute) { if (!fListAttribute) return B_OK; @@ -97,7 +98,7 @@ struct PackageContentListHandler : PackageContentHandler { return B_OK; } - virtual status_t HandleEntryDone(PackageEntry* entry) + virtual status_t HandleEntryDone(BPackageEntry* entry) { fLevel--; return B_OK; @@ -167,7 +168,7 @@ command_list(int argc, const char* const* argv) // open package StandardErrorOutput errorOutput; - PackageReader packageReader(&errorOutput); + BPackageReader packageReader(&errorOutput); status_t error = packageReader.Init(packageFileName); printf("Init(): %s\n", strerror(error)); if (error != B_OK) diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index 6a7900dda0..7553e5dd30 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -10,16 +10,21 @@ SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ; HPKG_SOURCES = BlockBufferCache.cpp + BlockBufferCacheImpl.cpp BufferCache.cpp + CachedBuffer.cpp DataOutput.cpp DataReader.cpp ErrorOutput.cpp + PackageContentHandler.cpp PackageData.cpp PackageDataReader.cpp PackageEntry.cpp PackageEntryAttribute.cpp PackageReader.cpp + PackageReaderImpl.cpp PackageWriter.cpp + PackageWriterImpl.cpp Strings.cpp # compression diff --git a/src/kits/package/hpkg/BlockBufferCache.cpp b/src/kits/package/hpkg/BlockBufferCache.cpp index fc8e9a4fd5..201b38358f 100644 --- a/src/kits/package/hpkg/BlockBufferCache.cpp +++ b/src/kits/package/hpkg/BlockBufferCache.cpp @@ -6,217 +6,67 @@ #include -#include #include -#include +#include namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -// #pragma mark - BlockBufferCache - - -BlockBufferCache::BlockBufferCache(size_t blockSize, uint32 maxCachedBlocks) +BBlockBufferCache::BBlockBufferCache(size_t blockSize, uint32 maxCachedBlocks) : - fBlockSize(blockSize), - fMaxCachedBlocks(maxCachedBlocks), - fAllocatedBlocks(0) + fImpl(new (std::nothrow) BlockBufferCacheImpl(blockSize, maxCachedBlocks, + this)) { } -BlockBufferCache::~BlockBufferCache() +BBlockBufferCache::~BBlockBufferCache() { - // delete all cached blocks - while (CachedBuffer* block = fCachedBuffers.RemoveHead()) - delete block; - - while (CachedBuffer* block = fUnusedBuffers.RemoveHead()) - delete block; + delete fImpl; } status_t -BlockBufferCache::Init() +BBlockBufferCache::Init() { - return B_OK; + if (fImpl == NULL) + return B_NO_MEMORY; + + return fImpl->Init(); } CachedBuffer* -BlockBufferCache::GetBuffer(size_t size, CachedBuffer** owner, bool* _newBuffer) -{ - // for sizes greater than the block size, we always allocate a new buffer - if (size > fBlockSize) - return _AllocateBuffer(size, owner, _newBuffer); - - AutoLocker locker(this); - - // if an owner is given and the buffer is still cached, return it - if (owner != NULL && *owner != NULL) { - CachedBuffer* buffer = *owner; - fCachedBuffers.Remove(buffer); - - if (_newBuffer != NULL) - *_newBuffer = false; - return buffer; - } - - // we need a new buffer -- try unused ones first - CachedBuffer* buffer = fUnusedBuffers.RemoveHead(); - if (buffer != NULL) { - buffer->SetOwner(owner); - - if (owner != NULL) - *owner = buffer; - if (_newBuffer != NULL) - *_newBuffer = true; - return buffer; - } - - // if we have already hit the max block limit, steal a cached block - if (fAllocatedBlocks >= fMaxCachedBlocks) { - buffer = fCachedBuffers.RemoveHead(); - if (buffer != NULL) { - buffer->SetCached(false); - *buffer->Owner() = NULL; - buffer->SetOwner(owner); - - if (owner != NULL) - *owner = buffer; - if (_newBuffer != NULL) - *_newBuffer = true; - return buffer; - } - } - - // allocate a new buffer - locker.Unlock(); - return _AllocateBuffer(size, owner, _newBuffer); -} - - -void -BlockBufferCache::PutBufferAndCache(CachedBuffer** owner) -{ - CachedBuffer* buffer = *owner; - - // always delete buffers with non-standard size - if (buffer->Size() != fBlockSize) { - *owner = NULL; - delete buffer; - return; - } - - AutoLocker locker(this); - - // queue the cached buffer - buffer->SetOwner(owner); - fCachedBuffers.Add(buffer); - buffer->SetCached(true); - - if (fAllocatedBlocks > fMaxCachedBlocks) { - // We have exceeded the limit -- we need to free a buffer. - CachedBuffer* otherBuffer = fUnusedBuffers.RemoveHead(); - if (otherBuffer == NULL) { - otherBuffer = fCachedBuffers.RemoveHead(); - *otherBuffer->Owner() = NULL; - otherBuffer->SetCached(false); - } - - delete otherBuffer; - } -} - - -void -BlockBufferCache::PutBuffer(CachedBuffer** owner) -{ - AutoLocker locker(this); - - CachedBuffer* buffer = *owner; - - if (buffer == NULL) - return; - - if (buffer->IsCached()) { - fCachedBuffers.Remove(buffer); - buffer->SetCached(false); - } - - buffer->SetOwner(NULL); - *owner = NULL; - - if (buffer->Size() == fBlockSize && fAllocatedBlocks < fMaxCachedBlocks) - fUnusedBuffers.Add(buffer); - else - delete buffer; -} - - -CachedBuffer* -BlockBufferCache::_AllocateBuffer(size_t size, CachedBuffer** owner, +BBlockBufferCache::GetBuffer(size_t size, CachedBuffer** owner, bool* _newBuffer) { - CachedBuffer* buffer = new(std::nothrow) CachedBuffer( - std::max(size, fBlockSize)); - if (buffer == NULL || buffer->Buffer() == NULL) { - delete buffer; + if (fImpl == NULL) return NULL; - } - buffer->SetOwner(owner); - - if (_newBuffer != NULL) - *_newBuffer = true; - - AutoLocker locker(this); - fAllocatedBlocks++; - - if (owner != NULL) - *owner = buffer; - - return buffer; -} - - -// #pragma mark - BlockBufferCacheNoLock - - -BlockBufferCacheNoLock::BlockBufferCacheNoLock(size_t blockSize, - uint32 maxCachedBlocks) - : - BlockBufferCache(blockSize, maxCachedBlocks) -{ -} - - -BlockBufferCacheNoLock::~BlockBufferCacheNoLock() -{ -} - - -bool -BlockBufferCacheNoLock::Lock() -{ - return true; + return fImpl->GetBuffer(size, owner, _newBuffer); } void -BlockBufferCacheNoLock::Unlock() +BBlockBufferCache::PutBufferAndCache(CachedBuffer** owner) { + if (fImpl != NULL) + fImpl->PutBufferAndCache(owner); } -} // namespace BPrivate +void +BBlockBufferCache::PutBuffer(CachedBuffer** owner) +{ + if (fImpl != NULL) + fImpl->PutBuffer(owner); +} -} // namespace BHaikuPackage + +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/BlockBufferCacheImpl.cpp b/src/kits/package/hpkg/BlockBufferCacheImpl.cpp new file mode 100644 index 0000000000..462788ba74 --- /dev/null +++ b/src/kits/package/hpkg/BlockBufferCacheImpl.cpp @@ -0,0 +1,197 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include + +#include + +#include + + +namespace BPackageKit { + +namespace BHPKG { + +namespace BPrivate { + + +// #pragma mark - BlockBufferCacheImpl + + +BlockBufferCacheImpl::BlockBufferCacheImpl(size_t blockSize, + uint32 maxCachedBlocks, BBufferCacheLockable* lockable) + : + fBlockSize(blockSize), + fMaxCachedBlocks(maxCachedBlocks), + fAllocatedBlocks(0), + fLockable(lockable) +{ +} + + +BlockBufferCacheImpl::~BlockBufferCacheImpl() +{ + // delete all cached blocks + while (CachedBuffer* block = fCachedBuffers.RemoveHead()) + delete block; + + while (CachedBuffer* block = fUnusedBuffers.RemoveHead()) + delete block; +} + + +status_t +BlockBufferCacheImpl::Init() +{ + return B_OK; +} + + +CachedBuffer* +BlockBufferCacheImpl::GetBuffer(size_t size, CachedBuffer** owner, bool* _newBuffer) +{ + // for sizes greater than the block size, we always allocate a new buffer + if (size > fBlockSize) + return _AllocateBuffer(size, owner, _newBuffer); + + AutoLocker locker(fLockable); + + // if an owner is given and the buffer is still cached, return it + if (owner != NULL && *owner != NULL) { + CachedBuffer* buffer = *owner; + fCachedBuffers.Remove(buffer); + + if (_newBuffer != NULL) + *_newBuffer = false; + return buffer; + } + + // we need a new buffer -- try unused ones first + CachedBuffer* buffer = fUnusedBuffers.RemoveHead(); + if (buffer != NULL) { + buffer->SetOwner(owner); + + if (owner != NULL) + *owner = buffer; + if (_newBuffer != NULL) + *_newBuffer = true; + return buffer; + } + + // if we have already hit the max block limit, steal a cached block + if (fAllocatedBlocks >= fMaxCachedBlocks) { + buffer = fCachedBuffers.RemoveHead(); + if (buffer != NULL) { + buffer->SetCached(false); + *buffer->Owner() = NULL; + buffer->SetOwner(owner); + + if (owner != NULL) + *owner = buffer; + if (_newBuffer != NULL) + *_newBuffer = true; + return buffer; + } + } + + // allocate a new buffer + locker.Unlock(); + return _AllocateBuffer(size, owner, _newBuffer); +} + + +void +BlockBufferCacheImpl::PutBufferAndCache(CachedBuffer** owner) +{ + CachedBuffer* buffer = *owner; + + // always delete buffers with non-standard size + if (buffer->Size() != fBlockSize) { + *owner = NULL; + delete buffer; + return; + } + + AutoLocker locker(fLockable); + + // queue the cached buffer + buffer->SetOwner(owner); + fCachedBuffers.Add(buffer); + buffer->SetCached(true); + + if (fAllocatedBlocks > fMaxCachedBlocks) { + // We have exceeded the limit -- we need to free a buffer. + CachedBuffer* otherBuffer = fUnusedBuffers.RemoveHead(); + if (otherBuffer == NULL) { + otherBuffer = fCachedBuffers.RemoveHead(); + *otherBuffer->Owner() = NULL; + otherBuffer->SetCached(false); + } + + delete otherBuffer; + } +} + + +void +BlockBufferCacheImpl::PutBuffer(CachedBuffer** owner) +{ + AutoLocker locker(fLockable); + + CachedBuffer* buffer = *owner; + + if (buffer == NULL) + return; + + if (buffer->IsCached()) { + fCachedBuffers.Remove(buffer); + buffer->SetCached(false); + } + + buffer->SetOwner(NULL); + *owner = NULL; + + if (buffer->Size() == fBlockSize && fAllocatedBlocks < fMaxCachedBlocks) + fUnusedBuffers.Add(buffer); + else + delete buffer; +} + + +CachedBuffer* +BlockBufferCacheImpl::_AllocateBuffer(size_t size, CachedBuffer** owner, + bool* _newBuffer) +{ + CachedBuffer* buffer = new(std::nothrow) CachedBuffer( + std::max(size, fBlockSize)); + if (buffer == NULL || buffer->Buffer() == NULL) { + delete buffer; + return NULL; + } + + buffer->SetOwner(owner); + + if (_newBuffer != NULL) + *_newBuffer = true; + + AutoLocker locker(fLockable); + fAllocatedBlocks++; + + if (owner != NULL) + *owner = buffer; + + return buffer; +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/BufferCache.cpp b/src/kits/package/hpkg/BufferCache.cpp index 6a77ee707e..8ada6b1cdd 100644 --- a/src/kits/package/hpkg/BufferCache.cpp +++ b/src/kits/package/hpkg/BufferCache.cpp @@ -6,45 +6,22 @@ #include -#include - namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -// #pragma mark - CachedBuffer - - -CachedBuffer::CachedBuffer(size_t size) - : - fOwner(NULL), - fBuffer(malloc(size)), - fSize(size), - fCached(false) +BBufferCache::~BBufferCache() { } -CachedBuffer::~CachedBuffer() -{ - free(fBuffer); -} - - -// #pragma mark - BufferCache - - -BufferCache::~BufferCache() +BBufferCacheLockable::~BBufferCacheLockable() { } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/CachedBuffer.cpp b/src/kits/package/hpkg/CachedBuffer.cpp new file mode 100644 index 0000000000..2ab19b7fad --- /dev/null +++ b/src/kits/package/hpkg/CachedBuffer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + + +namespace BPackageKit { + +namespace BHPKG { + +namespace BPrivate { + + +CachedBuffer::CachedBuffer(size_t size) + : + fOwner(NULL), + fBuffer(malloc(size)), + fSize(size), + fCached(false) +{ +} + + +CachedBuffer::~CachedBuffer() +{ + free(fBuffer); +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/DataOutput.cpp b/src/kits/package/hpkg/DataOutput.cpp index 03307c8670..00694b31cd 100644 --- a/src/kits/package/hpkg/DataOutput.cpp +++ b/src/kits/package/hpkg/DataOutput.cpp @@ -11,23 +11,21 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -// #pragma mark - DataOutput +// #pragma mark - BDataOutput -DataOutput::~DataOutput() +BDataOutput::~BDataOutput() { } -// #pragma mark - BufferDataOutput +// #pragma mark - BBufferDataOutput -BufferDataOutput::BufferDataOutput(void* buffer, size_t size) +BBufferDataOutput::BBufferDataOutput(void* buffer, size_t size) : fBuffer(buffer), fSize(size), @@ -37,7 +35,7 @@ BufferDataOutput::BufferDataOutput(void* buffer, size_t size) status_t -BufferDataOutput::WriteData(const void* buffer, size_t size) +BBufferDataOutput::WriteData(const void* buffer, size_t size) { if (size == 0) return B_OK; @@ -51,8 +49,6 @@ BufferDataOutput::WriteData(const void* buffer, size_t size) } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/DataReader.cpp b/src/kits/package/hpkg/DataReader.cpp index 7425d154ff..d5a2819ec2 100644 --- a/src/kits/package/hpkg/DataReader.cpp +++ b/src/kits/package/hpkg/DataReader.cpp @@ -15,23 +15,21 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -// #pragma mark - DataReader +// #pragma mark - BDataReader -DataReader::~DataReader() +BDataReader::~BDataReader() { } -// #pragma mark - FDDataReader +// #pragma mark - BFDDataReader -FDDataReader::FDDataReader(int fd) +BFDDataReader::BFDDataReader(int fd) : fFD(fd) { @@ -39,7 +37,7 @@ FDDataReader::FDDataReader(int fd) status_t -FDDataReader::ReadData(off_t offset, void* buffer, size_t size) +BFDDataReader::ReadData(off_t offset, void* buffer, size_t size) { ssize_t bytesRead = pread(fFD, buffer, size, offset); if (bytesRead < 0) @@ -48,10 +46,10 @@ FDDataReader::ReadData(off_t offset, void* buffer, size_t size) } -// #pragma mark - AttributeDataReader +// #pragma mark - BAttributeDataReader -AttributeDataReader::AttributeDataReader(int fd, const char* attribute, +BAttributeDataReader::BAttributeDataReader(int fd, const char* attribute, uint32 type) : fFD(fd), @@ -62,7 +60,7 @@ AttributeDataReader::AttributeDataReader(int fd, const char* attribute, status_t -AttributeDataReader::ReadData(off_t offset, void* buffer, size_t size) +BAttributeDataReader::ReadData(off_t offset, void* buffer, size_t size) { ssize_t bytesRead = fs_read_attr(fFD, fAttribute, fType, offset, buffer, size); @@ -72,10 +70,10 @@ AttributeDataReader::ReadData(off_t offset, void* buffer, size_t size) } -// #pragma mark - BufferDataReader +// #pragma mark - BBufferDataReader -BufferDataReader::BufferDataReader(const void* data, size_t size) +BBufferDataReader::BBufferDataReader(const void* data, size_t size) : fData(data), fSize(size) @@ -84,7 +82,7 @@ BufferDataReader::BufferDataReader(const void* data, size_t size) status_t -BufferDataReader::ReadData(off_t offset, void* buffer, size_t size) +BBufferDataReader::ReadData(off_t offset, void* buffer, size_t size) { if (size == 0) return B_OK; @@ -100,8 +98,6 @@ BufferDataReader::ReadData(off_t offset, void* buffer, size_t size) } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/ErrorOutput.cpp b/src/kits/package/hpkg/ErrorOutput.cpp index 0bcb98b268..449785405e 100644 --- a/src/kits/package/hpkg/ErrorOutput.cpp +++ b/src/kits/package/hpkg/ErrorOutput.cpp @@ -11,18 +11,16 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -ErrorOutput::~ErrorOutput() +BErrorOutput::~BErrorOutput() { } void -ErrorOutput::PrintError(const char* format, ...) +BErrorOutput::PrintError(const char* format, ...) { va_list args; va_start(args, format); @@ -31,8 +29,6 @@ ErrorOutput::PrintError(const char* format, ...) } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageContentHandler.cpp b/src/kits/package/hpkg/PackageContentHandler.cpp new file mode 100644 index 0000000000..9ce9ea8dce --- /dev/null +++ b/src/kits/package/hpkg/PackageContentHandler.cpp @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +// #pragma mark - BLowLevelPackageContentHandler + + +BLowLevelPackageContentHandler::~BLowLevelPackageContentHandler() +{ +} + + +// #pragma mark - BPackageContentHandler + + +BPackageContentHandler::~BPackageContentHandler() +{ +} + + +} // namespace BHPKG + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageData.cpp b/src/kits/package/hpkg/PackageData.cpp index 95e0d6aa70..f2aed96052 100644 --- a/src/kits/package/hpkg/PackageData.cpp +++ b/src/kits/package/hpkg/PackageData.cpp @@ -8,15 +8,18 @@ #include +#include + namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -PackageData::PackageData() +using namespace BPrivate; + + +BPackageData::BPackageData() : fCompressedSize(0), fUncompressedSize(0), @@ -28,7 +31,7 @@ PackageData::PackageData() void -PackageData::SetData(uint64 size, uint64 offset) +BPackageData::SetData(uint64 size, uint64 offset) { fUncompressedSize = fCompressedSize = size; fOffset = offset; @@ -37,7 +40,7 @@ PackageData::SetData(uint64 size, uint64 offset) void -PackageData::SetData(uint8 size, const void* data) +BPackageData::SetData(uint8 size, const void* data) { fUncompressedSize = fCompressedSize = size; if (size > 0) @@ -46,8 +49,6 @@ PackageData::SetData(uint8 size, const void* data) } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageDataReader.cpp b/src/kits/package/hpkg/PackageDataReader.cpp index 6875b04aac..ac4495cf08 100644 --- a/src/kits/package/hpkg/PackageDataReader.cpp +++ b/src/kits/package/hpkg/PackageDataReader.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -20,9 +21,10 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { -namespace BPrivate { + +using namespace BPrivate; // minimum/maximum zlib chunk size we consider sane @@ -36,25 +38,25 @@ static const size_t kUncompressedReaderBufferSize = B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; -// #pragma mark - PackageDataReader +// #pragma mark - BPackageDataReader -PackageDataReader::PackageDataReader(DataReader* dataReader) +BPackageDataReader::BPackageDataReader(BDataReader* dataReader) : fDataReader(dataReader) { } -PackageDataReader::~PackageDataReader() +BPackageDataReader::~BPackageDataReader() { } status_t -PackageDataReader::ReadData(off_t offset, void* buffer, size_t size) +BPackageDataReader::ReadData(off_t offset, void* buffer, size_t size) { - BufferDataOutput output(buffer, size); + BBufferDataOutput output(buffer, size); return ReadDataToOutput(offset, size, &output); } @@ -62,17 +64,17 @@ PackageDataReader::ReadData(off_t offset, void* buffer, size_t size) // #pragma mark - UncompressedPackageDataReader -class UncompressedPackageDataReader : public PackageDataReader { +class UncompressedPackageDataReader : public BPackageDataReader { public: - UncompressedPackageDataReader(DataReader* dataReader, - BufferCache* bufferCache) + UncompressedPackageDataReader(BDataReader* dataReader, + BBufferCache* bufferCache) : - PackageDataReader(dataReader), + BPackageDataReader(dataReader), fBufferCache(bufferCache) { } - status_t Init(const PackageData& data) + status_t Init(const BPackageData& data) { fOffset = data.Offset(); fSize = data.UncompressedSize(); @@ -105,7 +107,7 @@ public: } virtual status_t ReadDataToOutput(off_t offset, size_t size, - DataOutput* output) + BDataOutput* output) { if (size == 0) return B_OK; @@ -144,7 +146,7 @@ public: } private: - BufferCache* fBufferCache; + BBufferCache* fBufferCache; uint64 fOffset; uint64 fSize; }; @@ -153,11 +155,11 @@ private: // #pragma mark - ZlibPackageDataReader -class ZlibPackageDataReader : public PackageDataReader { +class ZlibPackageDataReader : public BPackageDataReader { public: - ZlibPackageDataReader(DataReader* dataReader, BufferCache* bufferCache) + ZlibPackageDataReader(BDataReader* dataReader, BBufferCache* bufferCache) : - PackageDataReader(dataReader), + BPackageDataReader(dataReader), fBufferCache(bufferCache), fUncompressBuffer(NULL), fOffsetTable(NULL) @@ -171,7 +173,7 @@ public: fBufferCache->PutBuffer(&fUncompressBuffer); } - status_t Init(const PackageData& data) + status_t Init(const BPackageData& data) { fOffset = data.Offset(); fCompressedSize = data.CompressedSize(); @@ -222,7 +224,7 @@ public: } virtual status_t ReadDataToOutput(off_t offset, size_t size, - DataOutput* output) + BDataOutput* output) { // check offset and size if (size == 0) @@ -398,7 +400,7 @@ private: } private: - BufferCache* fBufferCache; + BBufferCache* fBufferCache; CachedBuffer* fUncompressBuffer; int64 fUncompressedChunk; @@ -414,10 +416,10 @@ private: }; -// #pragma mark - PackageDataReaderFactory +// #pragma mark - BPackageDataReaderFactory -PackageDataReaderFactory::PackageDataReaderFactory(BufferCache* bufferCache) +BPackageDataReaderFactory::BPackageDataReaderFactory(BBufferCache* bufferCache) : fBufferCache(bufferCache) { @@ -425,10 +427,10 @@ PackageDataReaderFactory::PackageDataReaderFactory(BufferCache* bufferCache) status_t -PackageDataReaderFactory::CreatePackageDataReader(DataReader* dataReader, - const PackageData& data, PackageDataReader*& _reader) +BPackageDataReaderFactory::CreatePackageDataReader(BDataReader* dataReader, + const BPackageData& data, BPackageDataReader*& _reader) { - PackageDataReader* reader; + BPackageDataReader* reader; switch (data.Compression()) { case B_HPKG_COMPRESSION_NONE: @@ -457,8 +459,6 @@ PackageDataReaderFactory::CreatePackageDataReader(DataReader* dataReader, } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageEntry.cpp b/src/kits/package/hpkg/PackageEntry.cpp index e573475c99..5d12cfa3f2 100644 --- a/src/kits/package/hpkg/PackageEntry.cpp +++ b/src/kits/package/hpkg/PackageEntry.cpp @@ -9,12 +9,10 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -PackageEntry::PackageEntry(PackageEntry* parent, const char* name) +BPackageEntry::BPackageEntry(BPackageEntry* parent, const char* name) : fParent(parent), fName(name), @@ -31,8 +29,6 @@ PackageEntry::PackageEntry(PackageEntry* parent, const char* name) } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageEntryAttribute.cpp b/src/kits/package/hpkg/PackageEntryAttribute.cpp index bdd1f3ec29..8024ab47b3 100644 --- a/src/kits/package/hpkg/PackageEntryAttribute.cpp +++ b/src/kits/package/hpkg/PackageEntryAttribute.cpp @@ -9,12 +9,10 @@ namespace BPackageKit { -namespace BHaikuPackage { - -namespace BPrivate { +namespace BHPKG { -PackageEntryAttribute::PackageEntryAttribute(const char* name) +BPackageEntryAttribute::BPackageEntryAttribute(const char* name) : fName(name), fType(0) @@ -22,8 +20,6 @@ PackageEntryAttribute::PackageEntryAttribute(const char* name) } -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageReader.cpp b/src/kits/package/hpkg/PackageReader.cpp index d9b88e06e5..549bf2f9e6 100644 --- a/src/kits/package/hpkg/PackageReader.cpp +++ b/src/kits/package/hpkg/PackageReader.cpp @@ -6,1389 +6,80 @@ #include -#include -#include -#include -#include -#include -#include -#include - -#include #include -#include - -#include - -#include #include -#include -#include -#include -#include +#include namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { -namespace BPrivate { - -//#define TRACE(format...) printf(format) -#define TRACE(format...) do {} while (false) - - -// maximum TOC size we support reading -static const size_t kMaxTOCSize = 64 * 1024 * 1024; - -static const size_t kScratchBufferSize = 64 * 1024; - - -enum { - ATTRIBUTE_INDEX_DIRECTORY_ENTRY = 0, - ATTRIBUTE_INDEX_FILE_TYPE, - ATTRIBUTE_INDEX_FILE_PERMISSIONS, - ATTRIBUTE_INDEX_FILE_USER, - ATTRIBUTE_INDEX_FILE_GROUP, - ATTRIBUTE_INDEX_FILE_ATIME, - ATTRIBUTE_INDEX_FILE_MTIME, - ATTRIBUTE_INDEX_FILE_CRTIME, - ATTRIBUTE_INDEX_FILE_ATIME_NANOS, - ATTRIBUTE_INDEX_FILE_MTIME_NANOS, - ATTRIBUTE_INDEX_FILE_CRTIM_NANOS, - ATTRIBUTE_INDEX_FILE_ATTRIBUTE, - ATTRIBUTE_INDEX_FILE_ATTRIBUTE_TYPE, - ATTRIBUTE_INDEX_DATA, - ATTRIBUTE_INDEX_DATA_SIZE, - ATTRIBUTE_INDEX_DATA_COMPRESSION, - ATTRIBUTE_INDEX_DATA_CHUNK_SIZE, - ATTRIBUTE_INDEX_SYMLINK_PATH -}; - - -struct standard_attribute_index_entry { - const char* name; - uint8 type; - int8 index; -}; - -#undef MAKE_ATTRIBUTE_INDEX_ENTRY -#define MAKE_ATTRIBUTE_INDEX_ENTRY(name, type) \ - { B_HPKG_ATTRIBUTE_NAME_##name, B_HPKG_ATTRIBUTE_TYPE_##type, \ - ATTRIBUTE_INDEX_##name } - -static const standard_attribute_index_entry kStandardAttributeIndices[] = { - MAKE_ATTRIBUTE_INDEX_ENTRY(DIRECTORY_ENTRY, STRING), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_TYPE, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_PERMISSIONS, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_USER, STRING), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_GROUP, STRING), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_ATIME, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_MTIME, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_CRTIME, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_ATIME_NANOS, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_MTIME_NANOS, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_CRTIM_NANOS, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_ATTRIBUTE, STRING), - MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_ATTRIBUTE_TYPE, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(DATA, RAW), - MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_SIZE, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_COMPRESSION, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_CHUNK_SIZE, UINT), - MAKE_ATTRIBUTE_INDEX_ENTRY(SYMLINK_PATH, STRING), - {} -}; - - -// #pragma mark - LowLevelPackageContentHandler - - -LowLevelPackageContentHandler::~LowLevelPackageContentHandler() -{ -} - - -// #pragma mark - PackageContentHandler - - -PackageContentHandler::~PackageContentHandler() -{ -} - - -// #pragma mark - AttributeType - - -struct PackageReader::AttributeType { - uint8 type; - char name[0]; -}; - - -// #pragma mark - AttributeType - - -struct PackageReader::AttributeTypeReference { - AttributeType* type; - int32 standardIndex; -}; - - -// #pragma mark - AttributeHandler - - -struct PackageReader::AttributeHandlerContext { - ErrorOutput* errorOutput; - union { - PackageContentHandler* packageContentHandler; - LowLevelPackageContentHandler* lowLevelPackageContentHandler; - }; - bool hasLowLevelHandler; - - uint64 heapOffset; - uint64 heapSize; - - - AttributeHandlerContext(ErrorOutput* errorOutput, - PackageContentHandler* packageContentHandler) - : - errorOutput(errorOutput), - packageContentHandler(packageContentHandler), - hasLowLevelHandler(false) - { - } - - AttributeHandlerContext(ErrorOutput* errorOutput, - LowLevelPackageContentHandler* lowLevelPackageContentHandler) - : - errorOutput(errorOutput), - lowLevelPackageContentHandler(lowLevelPackageContentHandler), - hasLowLevelHandler(true) - { - } - - void ErrorOccurred() - { - if (hasLowLevelHandler) - lowLevelPackageContentHandler->HandleErrorOccurred(); - else - packageContentHandler->HandleErrorOccurred(); - } -}; - - -struct PackageReader::AttributeHandler - : SinglyLinkedListLinkImpl { - - virtual ~AttributeHandler() - { - } - - void SetLevel(int level) - { - fLevel = level; - } - - virtual status_t HandleChildAttribute(AttributeHandlerContext* context, - AttributeType* type, int8 typeIndex, const AttributeValue& value, - AttributeHandler** _handler) - { -TRACE("%*signored attribute \"%s\" (%u)\n", fLevel * 2, "", type->name, type->type); - return B_OK; - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - delete this; - return B_OK; - } - -protected: - int fLevel; -}; - - -struct PackageReader::IgnoreAttributeHandler : AttributeHandler { -}; - - -struct PackageReader::DataAttributeHandler : AttributeHandler { - DataAttributeHandler(PackageData* data) - : - fData(data) - { - } - - static status_t InitData(AttributeHandlerContext* context, - PackageData* data, const AttributeValue& value) - { - if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) - data->SetData(value.data.size, value.data.raw); - else - data->SetData(value.data.size, value.data.offset); - - data->SetUncompressedSize(value.data.size); - - return B_OK; - } - - static status_t Create(AttributeHandlerContext* context, - PackageData* data, const AttributeValue& value, - AttributeHandler*& _handler) - { - DataAttributeHandler* handler = new(std::nothrow) DataAttributeHandler( - data); - if (handler == NULL) - return B_NO_MEMORY; - - InitData(context, data, value); - - _handler = handler; - return B_OK; - } - - virtual status_t HandleChildAttribute(AttributeHandlerContext* context, - AttributeType* type, int8 typeIndex, const AttributeValue& value, - AttributeHandler** _handler) - { - switch (typeIndex) { - case ATTRIBUTE_INDEX_DATA_SIZE: - fData->SetUncompressedSize(value.unsignedInt); - return B_OK; - - case ATTRIBUTE_INDEX_DATA_COMPRESSION: - { - switch (value.unsignedInt) { - case B_HPKG_COMPRESSION_NONE: - case B_HPKG_COMPRESSION_ZLIB: - break; - default: - context->errorOutput->PrintError("Error: Invalid " - "compression type for data (%llu)\n", - value.unsignedInt); - return B_BAD_DATA; - } - - fData->SetCompression(value.unsignedInt); - return B_OK; - } - - case ATTRIBUTE_INDEX_DATA_CHUNK_SIZE: - fData->SetChunkSize(value.unsignedInt); - return B_OK; - } - - return AttributeHandler::HandleChildAttribute(context, type, typeIndex, - value, _handler); - } - -private: - PackageData* fData; -}; - - -struct PackageReader::AttributeAttributeHandler : AttributeHandler { - AttributeAttributeHandler(PackageEntry* entry, const char* name) - : - fEntry(entry), - fAttribute(name) - { - } - - virtual status_t HandleChildAttribute(AttributeHandlerContext* context, - AttributeType* type, int8 typeIndex, const AttributeValue& value, - AttributeHandler** _handler) - { - switch (typeIndex) { - case ATTRIBUTE_INDEX_DATA: - { - if (_handler != NULL) { - return DataAttributeHandler::Create(context, - &fAttribute.Data(), value, *_handler); - } - return DataAttributeHandler::InitData(context, &fAttribute.Data(), - value); - } - - case ATTRIBUTE_INDEX_FILE_ATTRIBUTE_TYPE: - fAttribute.SetType(value.unsignedInt); - return B_OK; - } - - return AttributeHandler::HandleChildAttribute(context, type, typeIndex, - value, _handler); - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - status_t error = context->packageContentHandler->HandleEntryAttribute( - fEntry, &fAttribute); - - delete this; - return error; - } - -private: - PackageEntry* fEntry; - PackageEntryAttribute fAttribute; -}; - - -struct PackageReader::EntryAttributeHandler : AttributeHandler { - EntryAttributeHandler(AttributeHandlerContext* context, - PackageEntry* parentEntry, const char* name) - : - fEntry(parentEntry, name), - fNotified(false) - { - _SetFileType(context, B_HPKG_DEFAULT_FILE_TYPE); - } - - static status_t Create(AttributeHandlerContext* context, - PackageEntry* parentEntry, const char* name, - AttributeHandler*& _handler) - { - // check name - if (name[0] == '\0' || strcmp(name, ".") == 0 - || strcmp(name, "..") == 0 || strchr(name, '/') != NULL) { - context->errorOutput->PrintError("Error: Invalid package: Invalid " - "entry name: \"%s\"\n", name); - return B_BAD_DATA; - } - - // create handler - EntryAttributeHandler* handler = new(std::nothrow) - EntryAttributeHandler(context, parentEntry, name); - if (handler == NULL) - return B_NO_MEMORY; - - _handler = handler; - return B_OK; - } - - virtual status_t HandleChildAttribute(AttributeHandlerContext* context, - AttributeType* type, int8 typeIndex, const AttributeValue& value, - AttributeHandler** _handler) - { - switch (typeIndex) { - case ATTRIBUTE_INDEX_DIRECTORY_ENTRY: - { - status_t error = _Notify(context); - if (error != B_OK) - return error; - -//TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string); - if (_handler != NULL) { - return EntryAttributeHandler::Create(context, &fEntry, - value.string, *_handler); - } - return B_OK; - } - - case ATTRIBUTE_INDEX_FILE_TYPE: - return _SetFileType(context, value.unsignedInt); - - case ATTRIBUTE_INDEX_FILE_PERMISSIONS: - fEntry.SetPermissions(value.unsignedInt); - return B_OK; - - case ATTRIBUTE_INDEX_FILE_USER: - case ATTRIBUTE_INDEX_FILE_GROUP: - // TODO:... - break; - - case ATTRIBUTE_INDEX_FILE_ATIME: - fEntry.SetAccessTime(value.unsignedInt); - return B_OK; - - case ATTRIBUTE_INDEX_FILE_MTIME: - fEntry.SetModifiedTime(value.unsignedInt); - return B_OK; - - case ATTRIBUTE_INDEX_FILE_CRTIME: - fEntry.SetCreationTime(value.unsignedInt); - return B_OK; - - case ATTRIBUTE_INDEX_FILE_ATIME_NANOS: - fEntry.SetAccessTimeNanos(value.unsignedInt); - return B_OK; - - case ATTRIBUTE_INDEX_FILE_MTIME_NANOS: - fEntry.SetModifiedTimeNanos(value.unsignedInt); - return B_OK; - - case ATTRIBUTE_INDEX_FILE_CRTIM_NANOS: - fEntry.SetCreationTimeNanos(value.unsignedInt); - return B_OK; - - case ATTRIBUTE_INDEX_FILE_ATTRIBUTE: - { - status_t error = _Notify(context); - if (error != B_OK) - return error; - - if (_handler != NULL) { - *_handler = new(std::nothrow) AttributeAttributeHandler( - &fEntry, value.string); - if (*_handler == NULL) - return B_NO_MEMORY; - return B_OK; - } else { - PackageEntryAttribute attribute(value.string); - return context->packageContentHandler->HandleEntryAttribute( - &fEntry, &attribute); - } - } - - case ATTRIBUTE_INDEX_DATA: - { - if (_handler != NULL) { - return DataAttributeHandler::Create(context, &fEntry.Data(), - value, *_handler); - } - return DataAttributeHandler::InitData(context, &fEntry.Data(), - value); - } - - case ATTRIBUTE_INDEX_SYMLINK_PATH: - { - fEntry.SetSymlinkPath(value.string); - return B_OK; - } - } - - return AttributeHandler::HandleChildAttribute(context, type, typeIndex, - value, _handler); - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - // notify if not done yet - status_t error = _Notify(context); - - // notify done - if (error == B_OK) - error = context->packageContentHandler->HandleEntryDone(&fEntry); - else - context->packageContentHandler->HandleEntryDone(&fEntry); - - delete this; - return error; - } - -private: - status_t _Notify(AttributeHandlerContext* context) - { - if (fNotified) - return B_OK; - - fNotified = true; - return context->packageContentHandler->HandleEntry(&fEntry); - } - - status_t _SetFileType(AttributeHandlerContext* context, uint64 fileType) - { - switch (fileType) { - case B_HPKG_FILE_TYPE_FILE: - fEntry.SetType(S_IFREG); - fEntry.SetPermissions(B_HPKG_DEFAULT_FILE_PERMISSIONS); - break; - case B_HPKG_FILE_TYPE_DIRECTORY: - fEntry.SetType(S_IFDIR); - fEntry.SetPermissions(B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS); - break; - case B_HPKG_FILE_TYPE_SYMLINK: - fEntry.SetType(S_IFLNK); - fEntry.SetPermissions(B_HPKG_DEFAULT_SYMLINK_PERMISSIONS); - break; - default: - context->errorOutput->PrintError("Error: Invalid file type for " - "package entry (%llu)\n", fileType); - return B_BAD_DATA; - } - return B_OK; - } - -private: - PackageEntry fEntry; - bool fNotified; -}; - - -struct PackageReader::RootAttributeHandler : AttributeHandler { - virtual status_t HandleChildAttribute(AttributeHandlerContext* context, - AttributeType* type, int8 typeIndex, const AttributeValue& value, - AttributeHandler** _handler) - { - if (typeIndex == ATTRIBUTE_INDEX_DIRECTORY_ENTRY) { -//TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string); - if (_handler != NULL) { - return EntryAttributeHandler::Create(context, NULL, - value.string, *_handler); - } - return B_OK; - } - - return AttributeHandler::HandleChildAttribute(context, type, typeIndex, - value, _handler); - } -}; - - -struct PackageReader::PackageAttributeHandler : AttributeHandler { - PackageAttributeHandler() - : - fToken(NULL), - fAttributeName(NULL) - { - } - - PackageAttributeHandler(const char* attributeName, - const PackageAttributeValue& value, void* token) - : - fToken(token), - fAttributeName(attributeName), - fValue(value) - { - } - - virtual status_t HandleChildAttribute(AttributeHandlerContext* context, - AttributeType* type, int8 typeIndex, const AttributeValue& value, - AttributeHandler** _handler) - { - // notify the content handler - void* token; - status_t error = context->lowLevelPackageContentHandler - ->HandleAttribute(type->name, value, fToken, token); - if (error != B_OK) - return error; - - // create a subhandler for the attribute, if it has children - if (_handler != NULL) { - *_handler = new(std::nothrow) PackageAttributeHandler(type->name, - value, token); - if (*_handler == NULL) { - context->lowLevelPackageContentHandler->HandleAttributeDone( - type->name, value, token); - return B_NO_MEMORY; - } - return B_OK; - } - - // no children -- just call the done hook - return context->lowLevelPackageContentHandler->HandleAttributeDone( - type->name, value, token); - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - if (fAttributeName != NULL) { - return context->lowLevelPackageContentHandler->HandleAttributeDone( - fAttributeName, fValue, fToken); - } - - return B_OK; - } - -private: - void* fToken; - const char* fAttributeName; - AttributeValue fValue; -}; - - -// #pragma mark - PackageReader - - -inline PackageReader::AttributeHandler* -PackageReader::_CurrentAttributeHandler() const -{ - return fAttributeHandlerStack->Head(); -} - - -inline void -PackageReader::_PushAttributeHandler(AttributeHandler* handler) -{ - fAttributeHandlerStack->Add(handler); -} - - -inline PackageReader::AttributeHandler* -PackageReader::_PopAttributeHandler() -{ - return fAttributeHandlerStack->RemoveHead(); -} - - -PackageReader::PackageReader(ErrorOutput* errorOutput) +BPackageReader::BPackageReader(BErrorOutput* errorOutput) : - fErrorOutput(errorOutput), - fFD(-1), - fOwnsFD(false), - fTOCSection(NULL), - fAttributeTypes(NULL), - fStrings(NULL), - fScratchBuffer(NULL), - fScratchBufferSize(0) + fImpl(new (std::nothrow) PackageReaderImpl(errorOutput)) { } -PackageReader::~PackageReader() +BPackageReader::~BPackageReader() { - if (fOwnsFD && fFD >= 0) - close(fFD); - - delete[] fScratchBuffer; - delete[] fStrings; - delete[] fAttributeTypes; - delete[] fTOCSection; + delete fImpl; } status_t -PackageReader::Init(const char* fileName) +BPackageReader::Init(const char* fileName) { - // open file - int fd = open(fileName, O_RDONLY); - if (fd < 0) { - fErrorOutput->PrintError("Error: Failed to open package file \"%s\": " - "%s\n", fileName, strerror(errno)); - return errno; - } + if (fImpl == NULL) + return B_NO_INIT; - return Init(fd, true); + return fImpl->Init(fileName); } status_t -PackageReader::Init(int fd, bool keepFD) +BPackageReader::Init(int fd, bool keepFD) { - fFD = fd; - fOwnsFD = keepFD; + if (fImpl == NULL) + return B_NO_INIT; - // stat it - struct stat st; - if (fstat(fFD, &st) < 0) { - fErrorOutput->PrintError("Error: Failed to access package file: %s\n", - strerror(errno)); - return errno; - } - - // read the header - hpkg_header header; - status_t error = _ReadBuffer(0, &header, sizeof(header)); - if (error != B_OK) - return error; - - // check the header - - // magic - if (B_BENDIAN_TO_HOST_INT32(header.magic) != B_HPKG_MAGIC) { - fErrorOutput->PrintError("Error: Invalid package file: Invalid " - "magic\n"); - return B_BAD_DATA; - } - - // header size - fHeapOffset = B_BENDIAN_TO_HOST_INT16(header.header_size); - if ((size_t)fHeapOffset < sizeof(hpkg_header)) { - fErrorOutput->PrintError("Error: Invalid package file: Invalid header " - "size (%llu)\n", fHeapOffset); - return B_BAD_DATA; - } - - // version - if (B_BENDIAN_TO_HOST_INT16(header.version) != B_HPKG_VERSION) { - fErrorOutput->PrintError("Error: Invalid/unsupported package file " - "version (%d)\n", B_BENDIAN_TO_HOST_INT16(header.version)); - return B_BAD_DATA; - } - - // total size - fTotalSize = B_BENDIAN_TO_HOST_INT64(header.total_size); - if (fTotalSize != (uint64)st.st_size) { - fErrorOutput->PrintError("Error: Invalid package file: Total size in " - "header (%llu) doesn't agree with total file size (%lld)\n", - fTotalSize, st.st_size); - return B_BAD_DATA; - } - - // package attributes length and compression - fPackageAttributesCompression - = B_BENDIAN_TO_HOST_INT32(header.attributes_compression); - fPackageAttributesCompressedLength - = B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed); - fPackageAttributesUncompressedLength - = B_BENDIAN_TO_HOST_INT32(header.attributes_length_uncompressed); - - if (const char* errorString = _CheckCompression( - fPackageAttributesCompression, fPackageAttributesCompressedLength, - fPackageAttributesUncompressedLength)) { - fErrorOutput->PrintError("Error: Invalid package file: package " - "attributes section: %s\n", errorString); - return B_BAD_DATA; - } - - // TOC length and compression - fTOCCompression = B_BENDIAN_TO_HOST_INT32(header.toc_compression); - fTOCCompressedLength - = B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed); - fTOCUncompressedLength - = B_BENDIAN_TO_HOST_INT64(header.toc_length_uncompressed); - - if (const char* errorString = _CheckCompression(fTOCCompression, - fTOCCompressedLength, fTOCUncompressedLength)) { - fErrorOutput->PrintError("Error: Invalid package file: TOC section: " - "%s\n", errorString); - return B_BAD_DATA; - } - - // TOC subsections - fTOCAttributeTypesLength - = B_BENDIAN_TO_HOST_INT64(header.toc_attribute_types_length); - fTOCAttributeTypesCount - = B_BENDIAN_TO_HOST_INT64(header.toc_attribute_types_count); - fTOCStringsLength = B_BENDIAN_TO_HOST_INT64(header.toc_strings_length); - fTOCStringsCount = B_BENDIAN_TO_HOST_INT64(header.toc_strings_count); - - if (fTOCAttributeTypesLength > fTOCUncompressedLength - || fTOCStringsLength > fTOCUncompressedLength - fTOCAttributeTypesLength - || fTOCAttributeTypesCount > fTOCAttributeTypesLength - || fTOCStringsCount > fTOCStringsLength) { - fErrorOutput->PrintError("Error: Invalid package file: Invalid TOC " - "subsections description\n"); - return B_BAD_DATA; - } - - // check whether the sections fit together - if (fPackageAttributesCompressedLength > fTotalSize - || fTOCCompressedLength - > fTotalSize - fPackageAttributesCompressedLength - || fHeapOffset - > fTotalSize - fPackageAttributesCompressedLength - - fTOCCompressedLength) { - fErrorOutput->PrintError("Error: Invalid package file: The sum of the " - "sections sizes is greater than the package size\n"); - return B_BAD_DATA; - } - - fPackageAttributesOffset = fTotalSize - fPackageAttributesCompressedLength; - fTOCSectionOffset = fPackageAttributesOffset - fTOCCompressedLength; - fHeapSize = fTOCSectionOffset - fHeapOffset; - - // TOC size sanity check - if (fTOCUncompressedLength > kMaxTOCSize) { - fErrorOutput->PrintError("Error: Package file TOC section size " - "is %llu bytes. This is beyond the reader's sanity limit\n", - fTOCUncompressedLength); - return B_UNSUPPORTED; - } - - // allocate a scratch buffer - fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize]; - if (fScratchBuffer == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); - return B_NO_MEMORY; - } - fScratchBufferSize = kScratchBufferSize; - - // read in the complete TOC - fTOCSection = new(std::nothrow) uint8[fTOCUncompressedLength]; - if (fTOCSection == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); - return B_NO_MEMORY; - } - - error = _ReadCompressedBuffer(fTOCSectionOffset, fTOCSection, - fTOCCompressedLength, fTOCUncompressedLength, fTOCCompression); - if (error != B_OK) - return error; - - // start parsing the TOC - fCurrentTOCOffset = 0; - - // attribute types - error = _ParseTOCAttributeTypes(); - if (error != B_OK) - return error; - fCurrentTOCOffset += fTOCAttributeTypesLength; - - // strings - error = _ParseTOCStrings(); - if (error != B_OK) - return error; - fCurrentTOCOffset += fTOCStringsLength; - - return B_OK; + return fImpl->Init(fd, keepFD); } status_t -PackageReader::ParseContent(PackageContentHandler* contentHandler) +BPackageReader::ParseContent(BPackageContentHandler* contentHandler) { - AttributeHandlerContext context(fErrorOutput, contentHandler); - RootAttributeHandler rootAttributeHandler; - return _ParseContent(&context, &rootAttributeHandler); + if (fImpl == NULL) + return B_NO_INIT; + + return fImpl->ParseContent(contentHandler); } status_t -PackageReader::ParseContent(LowLevelPackageContentHandler* contentHandler) +BPackageReader::ParseContent(BLowLevelPackageContentHandler* contentHandler) { - AttributeHandlerContext context(fErrorOutput, contentHandler); - PackageAttributeHandler rootAttributeHandler; - return _ParseContent(&context, &rootAttributeHandler); + if (fImpl == NULL) + return B_NO_INIT; + + return fImpl->ParseContent(contentHandler); } -const char* -PackageReader::_CheckCompression(uint32 compression, uint64 compressedLength, - uint64 uncompressedLength) const +int +BPackageReader::PackageFileFD() { - switch (compression) { - case B_HPKG_COMPRESSION_NONE: - if (compressedLength != uncompressedLength) { - return "Uncompressed, but compressed and uncompressed length " - "don't match"; - } - return NULL; + if (fImpl == NULL) + return -1; - case B_HPKG_COMPRESSION_ZLIB: - if (compressedLength >= uncompressedLength) { - return "Compressed, but compressed length is not less than " - "uncompressed length"; - } - return NULL; - - default: - return "Invalid compression algorithm ID"; - } + return fImpl->PackageFileFD(); } -status_t -PackageReader::_ParseTOCAttributeTypes() -{ - // allocate table - fAttributeTypes = new(std::nothrow) AttributeTypeReference[ - fTOCAttributeTypesCount]; - if (fAttributeTypes == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); - return B_NO_MEMORY; - } - - // parse the section and fill the table - uint8* position = fTOCSection + fCurrentTOCOffset; - uint8* sectionEnd = position + fTOCAttributeTypesLength; - uint32 index = 0; - while (true) { - if (position >= sectionEnd) { - fErrorOutput->PrintError("Error: Malformed TOC attribute types " - "section\n"); - return B_BAD_DATA; - } - - AttributeType* type = (AttributeType*)position; - - if (type->type == 0) { - if (position + 1 != sectionEnd) { - fErrorOutput->PrintError("Error: Excess bytes in TOC attribute " - "types section\n"); -TRACE("position: %p, sectionEnd: %p\n", position, sectionEnd); - return B_BAD_DATA; - } - - if (index != fTOCAttributeTypesCount) { - fErrorOutput->PrintError("Error: Invalid TOC attribute types " - "section: Less types than specified in the header\n"); - return B_BAD_DATA; - } - - return B_OK; - } - - if (index >= fTOCAttributeTypesCount) { - fErrorOutput->PrintError("Error: Invalid TOC attribute types " - "section: More types than specified in the header\n"); - return B_BAD_DATA; - } - - size_t nameLength = strnlen(type->name, - (char*)sectionEnd - type->name); - position = (uint8*)type->name + nameLength + 1; - fAttributeTypes[index].type = type; - fAttributeTypes[index].standardIndex = _GetStandardIndex(type); - index++; -TRACE("type: %u, \"%s\"\n", type->type, type->name); - } -} - - -status_t -PackageReader::_ParseTOCStrings() -{ - // allocate table - fStrings = new(std::nothrow) char*[fTOCStringsCount]; - if (fStrings == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); - return B_NO_MEMORY; - } - - // parse the section and fill the table - char* position = (char*)fTOCSection + fCurrentTOCOffset; - char* sectionEnd = position + fTOCStringsLength; - uint32 index = 0; - while (true) { - if (position >= sectionEnd) { - fErrorOutput->PrintError("Error: Malformed TOC strings section\n"); - return B_BAD_DATA; - } - - size_t stringLength = strnlen(position, (char*)sectionEnd - position); - - if (stringLength == 0) { - if (position + 1 != sectionEnd) { - fErrorOutput->PrintError("Error: Excess bytes in TOC strings " - "section\n"); -TRACE("position: %p, sectionEnd: %p\n", position, sectionEnd); - return B_BAD_DATA; - } - - if (index != fTOCStringsCount) { - fErrorOutput->PrintError("Error: Invalid TOC strings section: " - "Less strings than specified in the header\n"); - return B_BAD_DATA; - } - - return B_OK; - } - - if (index >= fTOCStringsCount) { - fErrorOutput->PrintError("Error: Invalid TOC strings section: " - "More strings than specified in the header\n"); - return B_BAD_DATA; - } - - fStrings[index++] = position; -TRACE("string: \"%s\"\n", position); - position += stringLength + 1; - } -} - - -status_t -PackageReader::_ParseContent(AttributeHandlerContext* context, - AttributeHandler* rootAttributeHandler) -{ - // parse the TOC - fCurrentTOCOffset = fTOCAttributeTypesLength + fTOCStringsLength; - - // prepare attribute handler context - context->heapOffset = fHeapOffset; - context->heapSize = fHeapSize; - - // init the attribute handler stack - AttributeHandlerList attributeHandlerStack; - fAttributeHandlerStack = &attributeHandlerStack; - fAttributeHandlerStack->Add(rootAttributeHandler); - rootAttributeHandler->SetLevel(0); - - status_t error = _ParseAttributeTree(context); - if (error == B_OK) { - if (fCurrentTOCOffset < fTOCUncompressedLength) { - fErrorOutput->PrintError("Error: %llu excess byte(s) in TOC " - "section\n", fTOCUncompressedLength - fCurrentTOCOffset); - error = B_BAD_DATA; - } - } - - // clean up on error - if (error != B_OK) { - context->ErrorOccurred(); - while (AttributeHandler* handler = _PopAttributeHandler()) { - if (handler != rootAttributeHandler) - handler->Delete(context); - } - return error; - } - - return B_OK; -} - - -status_t -PackageReader::_ParseAttributeTree(AttributeHandlerContext* context) -{ - int level = 0; - - while (true) { - uint64 tag; - status_t error = _ReadUnsignedLEB128(tag); - if (error != B_OK) - return error; - - if (tag == 0) { - AttributeHandler* handler = _PopAttributeHandler(); - if (level-- == 0) - return B_OK; - - error = handler->Delete(context); - if (error != B_OK) - return error; - - continue; - } - - // get the type - uint64 typeIndex = B_HPKG_ATTRIBUTE_TAG_INDEX(tag); - if (typeIndex >= fTOCAttributeTypesCount) { - fErrorOutput->PrintError("Error: Invalid TOC section: " - "Invalid attribute type index\n"); - return B_BAD_DATA; - } - AttributeTypeReference* type = fAttributeTypes + typeIndex; - - // get the value - AttributeValue value; - error = _ReadAttributeValue(type->type->type, - B_HPKG_ATTRIBUTE_TAG_ENCODING(tag), value); - if (error != B_OK) - return error; - - bool hasChildren = B_HPKG_ATTRIBUTE_TAG_HAS_CHILDREN(tag); - AttributeHandler* childHandler = NULL; - error = _CurrentAttributeHandler()->HandleChildAttribute(context, - type->type, type->standardIndex, value, - hasChildren ? &childHandler : NULL); - if (error != B_OK) - return error; - - // parse children - if (hasChildren) { - // create an ignore handler, if necessary - if (childHandler == NULL) { - childHandler = new(std::nothrow) IgnoreAttributeHandler; - if (childHandler == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); - return B_NO_MEMORY; - } - } - - childHandler->SetLevel(level); - _PushAttributeHandler(childHandler); - level++; - } - } -} - - -status_t -PackageReader::_ReadAttributeValue(uint8 type, uint8 encoding, - AttributeValue& _value) -{ - switch (type) { - case B_HPKG_ATTRIBUTE_TYPE_INT: - case B_HPKG_ATTRIBUTE_TYPE_UINT: - { - uint64 intValue; - status_t error; - - switch (encoding) { - case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: - { - uint8 value; - error = _Read(value); - intValue = value; - break; - } - case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: - { - uint16 value; - error = _Read(value); - intValue = B_BENDIAN_TO_HOST_INT16(value); - break; - } - case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: - { - uint32 value; - error = _Read(value); - intValue = B_BENDIAN_TO_HOST_INT32(value); - break; - } - case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: - { - uint64 value; - error = _Read(value); - intValue = B_BENDIAN_TO_HOST_INT64(value); - break; - } - default: - { - fErrorOutput->PrintError("Error: Invalid TOC section: " - "invalid encoding %d for int value type %d\n", encoding, - type); - return B_BAD_VALUE; - } - } - - if (error != B_OK) - return error; - - if (type == B_HPKG_ATTRIBUTE_TYPE_INT) - _value.SetTo((int64)intValue); - else - _value.SetTo(intValue); - - return B_OK; - } - - case B_HPKG_ATTRIBUTE_TYPE_STRING: - { - if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) { - uint64 index; - status_t error = _ReadUnsignedLEB128(index); - if (error != B_OK) - return error; - - if (index > fTOCStringsCount) { - fErrorOutput->PrintError("Error: Invalid TOC section: " - "string reference out of bounds\n"); - return B_BAD_DATA; - } - - _value.SetTo(fStrings[index]); - } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE) { - const char* string; - status_t error = _ReadString(string); - if (error != B_OK) - return error; - - _value.SetTo(string); - } else { - fErrorOutput->PrintError("Error: Invalid TOC section: invalid " - "string encoding (%u)\n", encoding); - return B_BAD_DATA; - } - - return B_OK; - } - - case B_HPKG_ATTRIBUTE_TYPE_RAW: - { - uint64 size; - status_t error = _ReadUnsignedLEB128(size); - if (error != B_OK) - return error; - - if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) { - uint64 offset; - error = _ReadUnsignedLEB128(offset); - if (error != B_OK) - return error; - - if (offset > fHeapSize || size > fHeapSize - offset) { - fErrorOutput->PrintError("Error: Invalid TOC section: " - "invalid data reference\n"); - return B_BAD_DATA; - } - - _value.SetToData(size, fHeapOffset + offset); - } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) { - if (size > B_HPKG_MAX_INLINE_DATA_SIZE) { - fErrorOutput->PrintError("Error: Invalid TOC section: " - "inline data too long\n"); - return B_BAD_DATA; - } - - const void* buffer; - error = _GetTOCBuffer(size, buffer); - if (error != B_OK) - return error; - _value.SetToData(size, buffer); - } else { - fErrorOutput->PrintError("Error: Invalid TOC section: invalid " - "raw encoding (%u)\n", encoding); - return B_BAD_DATA; - } - - return B_OK; - } - - default: - fErrorOutput->PrintError("Error: Invalid TOC section: invalid " - "value type: %d\n", type); - return B_BAD_DATA; - } -} - - -status_t -PackageReader::_ReadUnsignedLEB128(uint64& _value) -{ - uint64 result = 0; - int shift = 0; - while (true) { - uint8 byte; - status_t error = _Read(byte); - if (error != B_OK) - return error; - - result |= uint64(byte & 0x7f) << shift; - if ((byte & 0x80) == 0) - break; - shift += 7; - } - - _value = result; - return B_OK; -} - - -status_t -PackageReader::_ReadString(const char*& _string, size_t* _stringLength) -{ - const char* string = (const char*)fTOCSection + fCurrentTOCOffset; - size_t stringLength = strnlen(string, - fTOCUncompressedLength - fCurrentTOCOffset); - - if (stringLength == fTOCUncompressedLength - fCurrentTOCOffset) { - fErrorOutput->PrintError("_ReadString(): string extends beyond TOC " - "end\n"); - return B_BAD_DATA; - } - - _string = string; - if (_stringLength != NULL) - *_stringLength = stringLength; - - fCurrentTOCOffset += stringLength + 1; - return B_OK; -} - - -status_t -PackageReader::_GetTOCBuffer(size_t size, const void*& _buffer) -{ - if (size > fTOCUncompressedLength - fCurrentTOCOffset) { - fErrorOutput->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n", - size); - return B_BAD_DATA; - } - - _buffer = fTOCSection + fCurrentTOCOffset; - fCurrentTOCOffset += size; - return B_OK; -} - - -status_t -PackageReader::_ReadTOCBuffer(void* buffer, size_t size) -{ - if (size > fTOCUncompressedLength - fCurrentTOCOffset) { - fErrorOutput->PrintError("_ReadTOCBuffer(%lu): read beyond TOC end\n", - size); - return B_BAD_DATA; - } - - memcpy(buffer, fTOCSection + fCurrentTOCOffset, size); - fCurrentTOCOffset += size; - return B_OK; -} - - -status_t -PackageReader::_ReadBuffer(off_t offset, void* buffer, size_t size) -{ - ssize_t bytesRead = pread(fFD, buffer, size, offset); - if (bytesRead < 0) { - fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read data: " - "%s\n", buffer, size, strerror(errno)); - return errno; - } - if ((size_t)bytesRead != size) { - fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read all " - "data\n", buffer, size); - return B_ERROR; - } - - return B_OK; -} - - -status_t -PackageReader::_ReadCompressedBuffer(off_t offset, void* buffer, - size_t compressedSize, size_t uncompressedSize, uint32 compression) -{ - switch (compression) { - case B_HPKG_COMPRESSION_NONE: - return _ReadBuffer(offset, buffer, compressedSize); - - case B_HPKG_COMPRESSION_ZLIB: - { - // init the decompressor - BufferDataOutput bufferOutput(buffer, uncompressedSize); - ZlibDecompressor decompressor(&bufferOutput); - status_t error = decompressor.Init(); - if (error != B_OK) - return error; - - while (compressedSize > 0) { - // read compressed buffer - size_t toRead = std::min(compressedSize, fScratchBufferSize); - error = _ReadBuffer(offset, fScratchBuffer, toRead); - if (error != B_OK) - return error; - - // uncompress - error = decompressor.DecompressNext(fScratchBuffer, toRead); - if (error != B_OK) - return error; - - compressedSize -= toRead; - offset += toRead; - } - - error = decompressor.Finish(); - if (error != B_OK) - return error; - - // verify that all data have been read - if (bufferOutput.BytesWritten() != uncompressedSize) { - fErrorOutput->PrintError("Error: Missing bytes in uncompressed " - "buffer!\n"); - return B_BAD_DATA; - } - - return B_OK; - } - - default: - return B_BAD_DATA; - } -} - - -/*static*/ int8 -PackageReader::_GetStandardIndex(const AttributeType* type) -{ - // TODO: Building a hash table once would make the loopup faster. - for (int32 i = 0; kStandardAttributeIndices[i].name != NULL; i++) { - if (type->type == kStandardAttributeIndices[i].type - && strcmp(kStandardAttributeIndices[i].name, type->name) == 0) { - return i; - } - } - - return -1; -} - - -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageReaderImpl.cpp b/src/kits/package/hpkg/PackageReaderImpl.cpp new file mode 100644 index 0000000000..a349882aec --- /dev/null +++ b/src/kits/package/hpkg/PackageReaderImpl.cpp @@ -0,0 +1,1378 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + + +namespace BPackageKit { + +namespace BHPKG { + +namespace BPrivate { + + +//#define TRACE(format...) printf(format) +#define TRACE(format...) do {} while (false) + + +// maximum TOC size we support reading +static const size_t kMaxTOCSize = 64 * 1024 * 1024; + +static const size_t kScratchBufferSize = 64 * 1024; + + +enum { + ATTRIBUTE_INDEX_DIRECTORY_ENTRY = 0, + ATTRIBUTE_INDEX_FILE_TYPE, + ATTRIBUTE_INDEX_FILE_PERMISSIONS, + ATTRIBUTE_INDEX_FILE_USER, + ATTRIBUTE_INDEX_FILE_GROUP, + ATTRIBUTE_INDEX_FILE_ATIME, + ATTRIBUTE_INDEX_FILE_MTIME, + ATTRIBUTE_INDEX_FILE_CRTIME, + ATTRIBUTE_INDEX_FILE_ATIME_NANOS, + ATTRIBUTE_INDEX_FILE_MTIME_NANOS, + ATTRIBUTE_INDEX_FILE_CRTIM_NANOS, + ATTRIBUTE_INDEX_FILE_ATTRIBUTE, + ATTRIBUTE_INDEX_FILE_ATTRIBUTE_TYPE, + ATTRIBUTE_INDEX_DATA, + ATTRIBUTE_INDEX_DATA_SIZE, + ATTRIBUTE_INDEX_DATA_COMPRESSION, + ATTRIBUTE_INDEX_DATA_CHUNK_SIZE, + ATTRIBUTE_INDEX_SYMLINK_PATH +}; + + +struct standard_attribute_index_entry { + const char* name; + uint8 type; + int8 index; +}; + +#undef MAKE_ATTRIBUTE_INDEX_ENTRY +#define MAKE_ATTRIBUTE_INDEX_ENTRY(name, type) \ + { B_HPKG_ATTRIBUTE_NAME_##name, B_HPKG_ATTRIBUTE_TYPE_##type, \ + ATTRIBUTE_INDEX_##name } + +static const standard_attribute_index_entry kStandardAttributeIndices[] = { + MAKE_ATTRIBUTE_INDEX_ENTRY(DIRECTORY_ENTRY, STRING), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_TYPE, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_PERMISSIONS, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_USER, STRING), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_GROUP, STRING), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_ATIME, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_MTIME, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_CRTIME, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_ATIME_NANOS, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_MTIME_NANOS, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_CRTIM_NANOS, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_ATTRIBUTE, STRING), + MAKE_ATTRIBUTE_INDEX_ENTRY(FILE_ATTRIBUTE_TYPE, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(DATA, RAW), + MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_SIZE, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_COMPRESSION, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_CHUNK_SIZE, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(SYMLINK_PATH, STRING), + {} +}; + + +// #pragma mark - AttributeType + + +struct PackageReaderImpl::AttributeType { + uint8 type; + char name[0]; +}; + + +// #pragma mark - AttributeType + + +struct PackageReaderImpl::AttributeTypeReference { + AttributeType* type; + int32 standardIndex; +}; + + +// #pragma mark - AttributeHandler + + +struct PackageReaderImpl::AttributeHandlerContext { + BErrorOutput* errorOutput; + union { + BPackageContentHandler* packageContentHandler; + BLowLevelPackageContentHandler* lowLevelPackageContentHandler; + }; + bool hasLowLevelHandler; + + uint64 heapOffset; + uint64 heapSize; + + + AttributeHandlerContext(BErrorOutput* errorOutput, + BPackageContentHandler* packageContentHandler) + : + errorOutput(errorOutput), + packageContentHandler(packageContentHandler), + hasLowLevelHandler(false) + { + } + + AttributeHandlerContext(BErrorOutput* errorOutput, + BLowLevelPackageContentHandler* lowLevelPackageContentHandler) + : + errorOutput(errorOutput), + lowLevelPackageContentHandler(lowLevelPackageContentHandler), + hasLowLevelHandler(true) + { + } + + void ErrorOccurred() + { + if (hasLowLevelHandler) + lowLevelPackageContentHandler->HandleErrorOccurred(); + else + packageContentHandler->HandleErrorOccurred(); + } +}; + + +struct PackageReaderImpl::AttributeHandler + : SinglyLinkedListLinkImpl { + + virtual ~AttributeHandler() + { + } + + void SetLevel(int level) + { + fLevel = level; + } + + virtual status_t HandleChildAttribute(AttributeHandlerContext* context, + AttributeType* type, int8 typeIndex, const AttributeValue& value, + AttributeHandler** _handler) + { +TRACE("%*signored attribute \"%s\" (%u)\n", fLevel * 2, "", type->name, type->type); + return B_OK; + } + + virtual status_t Delete(AttributeHandlerContext* context) + { + delete this; + return B_OK; + } + +protected: + int fLevel; +}; + + +struct PackageReaderImpl::IgnoreAttributeHandler : AttributeHandler { +}; + + +struct PackageReaderImpl::DataAttributeHandler : AttributeHandler { + DataAttributeHandler(BPackageData* data) + : + fData(data) + { + } + + static status_t InitData(AttributeHandlerContext* context, + BPackageData* data, const AttributeValue& value) + { + if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) + data->SetData(value.data.size, value.data.raw); + else + data->SetData(value.data.size, value.data.offset); + + data->SetUncompressedSize(value.data.size); + + return B_OK; + } + + static status_t Create(AttributeHandlerContext* context, + BPackageData* data, const AttributeValue& value, + AttributeHandler*& _handler) + { + DataAttributeHandler* handler = new(std::nothrow) DataAttributeHandler( + data); + if (handler == NULL) + return B_NO_MEMORY; + + InitData(context, data, value); + + _handler = handler; + return B_OK; + } + + virtual status_t HandleChildAttribute(AttributeHandlerContext* context, + AttributeType* type, int8 typeIndex, const AttributeValue& value, + AttributeHandler** _handler) + { + switch (typeIndex) { + case ATTRIBUTE_INDEX_DATA_SIZE: + fData->SetUncompressedSize(value.unsignedInt); + return B_OK; + + case ATTRIBUTE_INDEX_DATA_COMPRESSION: + { + switch (value.unsignedInt) { + case B_HPKG_COMPRESSION_NONE: + case B_HPKG_COMPRESSION_ZLIB: + break; + default: + context->errorOutput->PrintError("Error: Invalid " + "compression type for data (%llu)\n", + value.unsignedInt); + return B_BAD_DATA; + } + + fData->SetCompression(value.unsignedInt); + return B_OK; + } + + case ATTRIBUTE_INDEX_DATA_CHUNK_SIZE: + fData->SetChunkSize(value.unsignedInt); + return B_OK; + } + + return AttributeHandler::HandleChildAttribute(context, type, typeIndex, + value, _handler); + } + +private: + BPackageData* fData; +}; + + +struct PackageReaderImpl::AttributeAttributeHandler : AttributeHandler { + AttributeAttributeHandler(BPackageEntry* entry, const char* name) + : + fEntry(entry), + fAttribute(name) + { + } + + virtual status_t HandleChildAttribute(AttributeHandlerContext* context, + AttributeType* type, int8 typeIndex, const AttributeValue& value, + AttributeHandler** _handler) + { + switch (typeIndex) { + case ATTRIBUTE_INDEX_DATA: + { + if (_handler != NULL) { + return DataAttributeHandler::Create(context, + &fAttribute.Data(), value, *_handler); + } + return DataAttributeHandler::InitData(context, &fAttribute.Data(), + value); + } + + case ATTRIBUTE_INDEX_FILE_ATTRIBUTE_TYPE: + fAttribute.SetType(value.unsignedInt); + return B_OK; + } + + return AttributeHandler::HandleChildAttribute(context, type, typeIndex, + value, _handler); + } + + virtual status_t Delete(AttributeHandlerContext* context) + { + status_t error = context->packageContentHandler->HandleEntryAttribute( + fEntry, &fAttribute); + + delete this; + return error; + } + +private: + BPackageEntry* fEntry; + BPackageEntryAttribute fAttribute; +}; + + +struct PackageReaderImpl::EntryAttributeHandler : AttributeHandler { + EntryAttributeHandler(AttributeHandlerContext* context, + BPackageEntry* parentEntry, const char* name) + : + fEntry(parentEntry, name), + fNotified(false) + { + _SetFileType(context, B_HPKG_DEFAULT_FILE_TYPE); + } + + static status_t Create(AttributeHandlerContext* context, + BPackageEntry* parentEntry, const char* name, + AttributeHandler*& _handler) + { + // check name + if (name[0] == '\0' || strcmp(name, ".") == 0 + || strcmp(name, "..") == 0 || strchr(name, '/') != NULL) { + context->errorOutput->PrintError("Error: Invalid package: Invalid " + "entry name: \"%s\"\n", name); + return B_BAD_DATA; + } + + // create handler + EntryAttributeHandler* handler = new(std::nothrow) + EntryAttributeHandler(context, parentEntry, name); + if (handler == NULL) + return B_NO_MEMORY; + + _handler = handler; + return B_OK; + } + + virtual status_t HandleChildAttribute(AttributeHandlerContext* context, + AttributeType* type, int8 typeIndex, const AttributeValue& value, + AttributeHandler** _handler) + { + switch (typeIndex) { + case ATTRIBUTE_INDEX_DIRECTORY_ENTRY: + { + status_t error = _Notify(context); + if (error != B_OK) + return error; + +//TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string); + if (_handler != NULL) { + return EntryAttributeHandler::Create(context, &fEntry, + value.string, *_handler); + } + return B_OK; + } + + case ATTRIBUTE_INDEX_FILE_TYPE: + return _SetFileType(context, value.unsignedInt); + + case ATTRIBUTE_INDEX_FILE_PERMISSIONS: + fEntry.SetPermissions(value.unsignedInt); + return B_OK; + + case ATTRIBUTE_INDEX_FILE_USER: + case ATTRIBUTE_INDEX_FILE_GROUP: + // TODO:... + break; + + case ATTRIBUTE_INDEX_FILE_ATIME: + fEntry.SetAccessTime(value.unsignedInt); + return B_OK; + + case ATTRIBUTE_INDEX_FILE_MTIME: + fEntry.SetModifiedTime(value.unsignedInt); + return B_OK; + + case ATTRIBUTE_INDEX_FILE_CRTIME: + fEntry.SetCreationTime(value.unsignedInt); + return B_OK; + + case ATTRIBUTE_INDEX_FILE_ATIME_NANOS: + fEntry.SetAccessTimeNanos(value.unsignedInt); + return B_OK; + + case ATTRIBUTE_INDEX_FILE_MTIME_NANOS: + fEntry.SetModifiedTimeNanos(value.unsignedInt); + return B_OK; + + case ATTRIBUTE_INDEX_FILE_CRTIM_NANOS: + fEntry.SetCreationTimeNanos(value.unsignedInt); + return B_OK; + + case ATTRIBUTE_INDEX_FILE_ATTRIBUTE: + { + status_t error = _Notify(context); + if (error != B_OK) + return error; + + if (_handler != NULL) { + *_handler = new(std::nothrow) AttributeAttributeHandler( + &fEntry, value.string); + if (*_handler == NULL) + return B_NO_MEMORY; + return B_OK; + } else { + BPackageEntryAttribute attribute(value.string); + return context->packageContentHandler->HandleEntryAttribute( + &fEntry, &attribute); + } + } + + case ATTRIBUTE_INDEX_DATA: + { + if (_handler != NULL) { + return DataAttributeHandler::Create(context, &fEntry.Data(), + value, *_handler); + } + return DataAttributeHandler::InitData(context, &fEntry.Data(), + value); + } + + case ATTRIBUTE_INDEX_SYMLINK_PATH: + { + fEntry.SetSymlinkPath(value.string); + return B_OK; + } + } + + return AttributeHandler::HandleChildAttribute(context, type, typeIndex, + value, _handler); + } + + virtual status_t Delete(AttributeHandlerContext* context) + { + // notify if not done yet + status_t error = _Notify(context); + + // notify done + if (error == B_OK) + error = context->packageContentHandler->HandleEntryDone(&fEntry); + else + context->packageContentHandler->HandleEntryDone(&fEntry); + + delete this; + return error; + } + +private: + status_t _Notify(AttributeHandlerContext* context) + { + if (fNotified) + return B_OK; + + fNotified = true; + return context->packageContentHandler->HandleEntry(&fEntry); + } + + status_t _SetFileType(AttributeHandlerContext* context, uint64 fileType) + { + switch (fileType) { + case B_HPKG_FILE_TYPE_FILE: + fEntry.SetType(S_IFREG); + fEntry.SetPermissions(B_HPKG_DEFAULT_FILE_PERMISSIONS); + break; + case B_HPKG_FILE_TYPE_DIRECTORY: + fEntry.SetType(S_IFDIR); + fEntry.SetPermissions(B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS); + break; + case B_HPKG_FILE_TYPE_SYMLINK: + fEntry.SetType(S_IFLNK); + fEntry.SetPermissions(B_HPKG_DEFAULT_SYMLINK_PERMISSIONS); + break; + default: + context->errorOutput->PrintError("Error: Invalid file type for " + "package entry (%llu)\n", fileType); + return B_BAD_DATA; + } + return B_OK; + } + +private: + BPackageEntry fEntry; + bool fNotified; +}; + + +struct PackageReaderImpl::RootAttributeHandler : AttributeHandler { + virtual status_t HandleChildAttribute(AttributeHandlerContext* context, + AttributeType* type, int8 typeIndex, const AttributeValue& value, + AttributeHandler** _handler) + { + if (typeIndex == ATTRIBUTE_INDEX_DIRECTORY_ENTRY) { +//TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string); + if (_handler != NULL) { + return EntryAttributeHandler::Create(context, NULL, + value.string, *_handler); + } + return B_OK; + } + + return AttributeHandler::HandleChildAttribute(context, type, typeIndex, + value, _handler); + } +}; + + +struct PackageReaderImpl::PackageAttributeHandler : AttributeHandler { + PackageAttributeHandler() + : + fToken(NULL), + fAttributeName(NULL) + { + } + + PackageAttributeHandler(const char* attributeName, + const BPackageAttributeValue& value, void* token) + : + fToken(token), + fAttributeName(attributeName), + fValue(value) + { + } + + virtual status_t HandleChildAttribute(AttributeHandlerContext* context, + AttributeType* type, int8 typeIndex, const AttributeValue& value, + AttributeHandler** _handler) + { + // notify the content handler + void* token; + status_t error = context->lowLevelPackageContentHandler + ->HandleAttribute(type->name, value, fToken, token); + if (error != B_OK) + return error; + + // create a subhandler for the attribute, if it has children + if (_handler != NULL) { + *_handler = new(std::nothrow) PackageAttributeHandler(type->name, + value, token); + if (*_handler == NULL) { + context->lowLevelPackageContentHandler->HandleAttributeDone( + type->name, value, token); + return B_NO_MEMORY; + } + return B_OK; + } + + // no children -- just call the done hook + return context->lowLevelPackageContentHandler->HandleAttributeDone( + type->name, value, token); + } + + virtual status_t Delete(AttributeHandlerContext* context) + { + if (fAttributeName != NULL) { + return context->lowLevelPackageContentHandler->HandleAttributeDone( + fAttributeName, fValue, fToken); + } + + return B_OK; + } + +private: + void* fToken; + const char* fAttributeName; + AttributeValue fValue; +}; + + +// #pragma mark - PackageReaderImpl + + +inline PackageReaderImpl::AttributeHandler* +PackageReaderImpl::_CurrentAttributeHandler() const +{ + return fAttributeHandlerStack->Head(); +} + + +inline void +PackageReaderImpl::_PushAttributeHandler(AttributeHandler* handler) +{ + fAttributeHandlerStack->Add(handler); +} + + +inline PackageReaderImpl::AttributeHandler* +PackageReaderImpl::_PopAttributeHandler() +{ + return fAttributeHandlerStack->RemoveHead(); +} + + +PackageReaderImpl::PackageReaderImpl(BErrorOutput* errorOutput) + : + fErrorOutput(errorOutput), + fFD(-1), + fOwnsFD(false), + fTOCSection(NULL), + fAttributeTypes(NULL), + fStrings(NULL), + fScratchBuffer(NULL), + fScratchBufferSize(0) +{ +} + + +PackageReaderImpl::~PackageReaderImpl() +{ + if (fOwnsFD && fFD >= 0) + close(fFD); + + delete[] fScratchBuffer; + delete[] fStrings; + delete[] fAttributeTypes; + delete[] fTOCSection; +} + + +status_t +PackageReaderImpl::Init(const char* fileName) +{ + // open file + int fd = open(fileName, O_RDONLY); + if (fd < 0) { + fErrorOutput->PrintError("Error: Failed to open package file \"%s\": " + "%s\n", fileName, strerror(errno)); + return errno; + } + + return Init(fd, true); +} + + +status_t +PackageReaderImpl::Init(int fd, bool keepFD) +{ + fFD = fd; + fOwnsFD = keepFD; + + // stat it + struct stat st; + if (fstat(fFD, &st) < 0) { + fErrorOutput->PrintError("Error: Failed to access package file: %s\n", + strerror(errno)); + return errno; + } + + // read the header + hpkg_header header; + status_t error = _ReadBuffer(0, &header, sizeof(header)); + if (error != B_OK) + return error; + + // check the header + + // magic + if (B_BENDIAN_TO_HOST_INT32(header.magic) != B_HPKG_MAGIC) { + fErrorOutput->PrintError("Error: Invalid package file: Invalid " + "magic\n"); + return B_BAD_DATA; + } + + // header size + fHeapOffset = B_BENDIAN_TO_HOST_INT16(header.header_size); + if ((size_t)fHeapOffset < sizeof(hpkg_header)) { + fErrorOutput->PrintError("Error: Invalid package file: Invalid header " + "size (%llu)\n", fHeapOffset); + return B_BAD_DATA; + } + + // version + if (B_BENDIAN_TO_HOST_INT16(header.version) != B_HPKG_VERSION) { + fErrorOutput->PrintError("Error: Invalid/unsupported package file " + "version (%d)\n", B_BENDIAN_TO_HOST_INT16(header.version)); + return B_BAD_DATA; + } + + // total size + fTotalSize = B_BENDIAN_TO_HOST_INT64(header.total_size); + if (fTotalSize != (uint64)st.st_size) { + fErrorOutput->PrintError("Error: Invalid package file: Total size in " + "header (%llu) doesn't agree with total file size (%lld)\n", + fTotalSize, st.st_size); + return B_BAD_DATA; + } + + // package attributes length and compression + fPackageAttributesCompression + = B_BENDIAN_TO_HOST_INT32(header.attributes_compression); + fPackageAttributesCompressedLength + = B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed); + fPackageAttributesUncompressedLength + = B_BENDIAN_TO_HOST_INT32(header.attributes_length_uncompressed); + + if (const char* errorString = _CheckCompression( + fPackageAttributesCompression, fPackageAttributesCompressedLength, + fPackageAttributesUncompressedLength)) { + fErrorOutput->PrintError("Error: Invalid package file: package " + "attributes section: %s\n", errorString); + return B_BAD_DATA; + } + + // TOC length and compression + fTOCCompression = B_BENDIAN_TO_HOST_INT32(header.toc_compression); + fTOCCompressedLength + = B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed); + fTOCUncompressedLength + = B_BENDIAN_TO_HOST_INT64(header.toc_length_uncompressed); + + if (const char* errorString = _CheckCompression(fTOCCompression, + fTOCCompressedLength, fTOCUncompressedLength)) { + fErrorOutput->PrintError("Error: Invalid package file: TOC section: " + "%s\n", errorString); + return B_BAD_DATA; + } + + // TOC subsections + fTOCAttributeTypesLength + = B_BENDIAN_TO_HOST_INT64(header.toc_attribute_types_length); + fTOCAttributeTypesCount + = B_BENDIAN_TO_HOST_INT64(header.toc_attribute_types_count); + fTOCStringsLength = B_BENDIAN_TO_HOST_INT64(header.toc_strings_length); + fTOCStringsCount = B_BENDIAN_TO_HOST_INT64(header.toc_strings_count); + + if (fTOCAttributeTypesLength > fTOCUncompressedLength + || fTOCStringsLength > fTOCUncompressedLength - fTOCAttributeTypesLength + || fTOCAttributeTypesCount > fTOCAttributeTypesLength + || fTOCStringsCount > fTOCStringsLength) { + fErrorOutput->PrintError("Error: Invalid package file: Invalid TOC " + "subsections description\n"); + return B_BAD_DATA; + } + + // check whether the sections fit together + if (fPackageAttributesCompressedLength > fTotalSize + || fTOCCompressedLength + > fTotalSize - fPackageAttributesCompressedLength + || fHeapOffset + > fTotalSize - fPackageAttributesCompressedLength + - fTOCCompressedLength) { + fErrorOutput->PrintError("Error: Invalid package file: The sum of the " + "sections sizes is greater than the package size\n"); + return B_BAD_DATA; + } + + fPackageAttributesOffset = fTotalSize - fPackageAttributesCompressedLength; + fTOCSectionOffset = fPackageAttributesOffset - fTOCCompressedLength; + fHeapSize = fTOCSectionOffset - fHeapOffset; + + // TOC size sanity check + if (fTOCUncompressedLength > kMaxTOCSize) { + fErrorOutput->PrintError("Error: Package file TOC section size " + "is %llu bytes. This is beyond the reader's sanity limit\n", + fTOCUncompressedLength); + return B_UNSUPPORTED; + } + + // allocate a scratch buffer + fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize]; + if (fScratchBuffer == NULL) { + fErrorOutput->PrintError("Error: Out of memory!\n"); + return B_NO_MEMORY; + } + fScratchBufferSize = kScratchBufferSize; + + // read in the complete TOC + fTOCSection = new(std::nothrow) uint8[fTOCUncompressedLength]; + if (fTOCSection == NULL) { + fErrorOutput->PrintError("Error: Out of memory!\n"); + return B_NO_MEMORY; + } + + error = _ReadCompressedBuffer(fTOCSectionOffset, fTOCSection, + fTOCCompressedLength, fTOCUncompressedLength, fTOCCompression); + if (error != B_OK) + return error; + + // start parsing the TOC + fCurrentTOCOffset = 0; + + // attribute types + error = _ParseTOCAttributeTypes(); + if (error != B_OK) + return error; + fCurrentTOCOffset += fTOCAttributeTypesLength; + + // strings + error = _ParseTOCStrings(); + if (error != B_OK) + return error; + fCurrentTOCOffset += fTOCStringsLength; + + return B_OK; +} + + +status_t +PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler) +{ + AttributeHandlerContext context(fErrorOutput, contentHandler); + RootAttributeHandler rootAttributeHandler; + return _ParseContent(&context, &rootAttributeHandler); +} + + +status_t +PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler) +{ + AttributeHandlerContext context(fErrorOutput, contentHandler); + PackageAttributeHandler rootAttributeHandler; + return _ParseContent(&context, &rootAttributeHandler); +} + + +const char* +PackageReaderImpl::_CheckCompression(uint32 compression, uint64 compressedLength, + uint64 uncompressedLength) const +{ + switch (compression) { + case B_HPKG_COMPRESSION_NONE: + if (compressedLength != uncompressedLength) { + return "Uncompressed, but compressed and uncompressed length " + "don't match"; + } + return NULL; + + case B_HPKG_COMPRESSION_ZLIB: + if (compressedLength >= uncompressedLength) { + return "Compressed, but compressed length is not less than " + "uncompressed length"; + } + return NULL; + + default: + return "Invalid compression algorithm ID"; + } +} + + +status_t +PackageReaderImpl::_ParseTOCAttributeTypes() +{ + // allocate table + fAttributeTypes = new(std::nothrow) AttributeTypeReference[ + fTOCAttributeTypesCount]; + if (fAttributeTypes == NULL) { + fErrorOutput->PrintError("Error: Out of memory!\n"); + return B_NO_MEMORY; + } + + // parse the section and fill the table + uint8* position = fTOCSection + fCurrentTOCOffset; + uint8* sectionEnd = position + fTOCAttributeTypesLength; + uint32 index = 0; + while (true) { + if (position >= sectionEnd) { + fErrorOutput->PrintError("Error: Malformed TOC attribute types " + "section\n"); + return B_BAD_DATA; + } + + AttributeType* type = (AttributeType*)position; + + if (type->type == 0) { + if (position + 1 != sectionEnd) { + fErrorOutput->PrintError("Error: Excess bytes in TOC attribute " + "types section\n"); +TRACE("position: %p, sectionEnd: %p\n", position, sectionEnd); + return B_BAD_DATA; + } + + if (index != fTOCAttributeTypesCount) { + fErrorOutput->PrintError("Error: Invalid TOC attribute types " + "section: Less types than specified in the header\n"); + return B_BAD_DATA; + } + + return B_OK; + } + + if (index >= fTOCAttributeTypesCount) { + fErrorOutput->PrintError("Error: Invalid TOC attribute types " + "section: More types than specified in the header\n"); + return B_BAD_DATA; + } + + size_t nameLength = strnlen(type->name, + (char*)sectionEnd - type->name); + position = (uint8*)type->name + nameLength + 1; + fAttributeTypes[index].type = type; + fAttributeTypes[index].standardIndex = _GetStandardIndex(type); + index++; +TRACE("type: %u, \"%s\"\n", type->type, type->name); + } +} + + +status_t +PackageReaderImpl::_ParseTOCStrings() +{ + // allocate table + fStrings = new(std::nothrow) char*[fTOCStringsCount]; + if (fStrings == NULL) { + fErrorOutput->PrintError("Error: Out of memory!\n"); + return B_NO_MEMORY; + } + + // parse the section and fill the table + char* position = (char*)fTOCSection + fCurrentTOCOffset; + char* sectionEnd = position + fTOCStringsLength; + uint32 index = 0; + while (true) { + if (position >= sectionEnd) { + fErrorOutput->PrintError("Error: Malformed TOC strings section\n"); + return B_BAD_DATA; + } + + size_t stringLength = strnlen(position, (char*)sectionEnd - position); + + if (stringLength == 0) { + if (position + 1 != sectionEnd) { + fErrorOutput->PrintError("Error: Excess bytes in TOC strings " + "section\n"); +TRACE("position: %p, sectionEnd: %p\n", position, sectionEnd); + return B_BAD_DATA; + } + + if (index != fTOCStringsCount) { + fErrorOutput->PrintError("Error: Invalid TOC strings section: " + "Less strings than specified in the header\n"); + return B_BAD_DATA; + } + + return B_OK; + } + + if (index >= fTOCStringsCount) { + fErrorOutput->PrintError("Error: Invalid TOC strings section: " + "More strings than specified in the header\n"); + return B_BAD_DATA; + } + + fStrings[index++] = position; +TRACE("string: \"%s\"\n", position); + position += stringLength + 1; + } +} + + +status_t +PackageReaderImpl::_ParseContent(AttributeHandlerContext* context, + AttributeHandler* rootAttributeHandler) +{ + // parse the TOC + fCurrentTOCOffset = fTOCAttributeTypesLength + fTOCStringsLength; + + // prepare attribute handler context + context->heapOffset = fHeapOffset; + context->heapSize = fHeapSize; + + // init the attribute handler stack + AttributeHandlerList attributeHandlerStack; + fAttributeHandlerStack = &attributeHandlerStack; + fAttributeHandlerStack->Add(rootAttributeHandler); + rootAttributeHandler->SetLevel(0); + + status_t error = _ParseAttributeTree(context); + if (error == B_OK) { + if (fCurrentTOCOffset < fTOCUncompressedLength) { + fErrorOutput->PrintError("Error: %llu excess byte(s) in TOC " + "section\n", fTOCUncompressedLength - fCurrentTOCOffset); + error = B_BAD_DATA; + } + } + + // clean up on error + if (error != B_OK) { + context->ErrorOccurred(); + while (AttributeHandler* handler = _PopAttributeHandler()) { + if (handler != rootAttributeHandler) + handler->Delete(context); + } + return error; + } + + return B_OK; +} + + +status_t +PackageReaderImpl::_ParseAttributeTree(AttributeHandlerContext* context) +{ + int level = 0; + + while (true) { + uint64 tag; + status_t error = _ReadUnsignedLEB128(tag); + if (error != B_OK) + return error; + + if (tag == 0) { + AttributeHandler* handler = _PopAttributeHandler(); + if (level-- == 0) + return B_OK; + + error = handler->Delete(context); + if (error != B_OK) + return error; + + continue; + } + + // get the type + uint64 typeIndex = B_HPKG_ATTRIBUTE_TAG_INDEX(tag); + if (typeIndex >= fTOCAttributeTypesCount) { + fErrorOutput->PrintError("Error: Invalid TOC section: " + "Invalid attribute type index\n"); + return B_BAD_DATA; + } + AttributeTypeReference* type = fAttributeTypes + typeIndex; + + // get the value + AttributeValue value; + error = _ReadAttributeValue(type->type->type, + B_HPKG_ATTRIBUTE_TAG_ENCODING(tag), value); + if (error != B_OK) + return error; + + bool hasChildren = B_HPKG_ATTRIBUTE_TAG_HAS_CHILDREN(tag); + AttributeHandler* childHandler = NULL; + error = _CurrentAttributeHandler()->HandleChildAttribute(context, + type->type, type->standardIndex, value, + hasChildren ? &childHandler : NULL); + if (error != B_OK) + return error; + + // parse children + if (hasChildren) { + // create an ignore handler, if necessary + if (childHandler == NULL) { + childHandler = new(std::nothrow) IgnoreAttributeHandler; + if (childHandler == NULL) { + fErrorOutput->PrintError("Error: Out of memory!\n"); + return B_NO_MEMORY; + } + } + + childHandler->SetLevel(level); + _PushAttributeHandler(childHandler); + level++; + } + } +} + + +status_t +PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, + AttributeValue& _value) +{ + switch (type) { + case B_HPKG_ATTRIBUTE_TYPE_INT: + case B_HPKG_ATTRIBUTE_TYPE_UINT: + { + uint64 intValue; + status_t error; + + switch (encoding) { + case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: + { + uint8 value; + error = _Read(value); + intValue = value; + break; + } + case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: + { + uint16 value; + error = _Read(value); + intValue = B_BENDIAN_TO_HOST_INT16(value); + break; + } + case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: + { + uint32 value; + error = _Read(value); + intValue = B_BENDIAN_TO_HOST_INT32(value); + break; + } + case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: + { + uint64 value; + error = _Read(value); + intValue = B_BENDIAN_TO_HOST_INT64(value); + break; + } + default: + { + fErrorOutput->PrintError("Error: Invalid TOC section: " + "invalid encoding %d for int value type %d\n", encoding, + type); + return B_BAD_VALUE; + } + } + + if (error != B_OK) + return error; + + if (type == B_HPKG_ATTRIBUTE_TYPE_INT) + _value.SetTo((int64)intValue); + else + _value.SetTo(intValue); + + return B_OK; + } + + case B_HPKG_ATTRIBUTE_TYPE_STRING: + { + if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) { + uint64 index; + status_t error = _ReadUnsignedLEB128(index); + if (error != B_OK) + return error; + + if (index > fTOCStringsCount) { + fErrorOutput->PrintError("Error: Invalid TOC section: " + "string reference out of bounds\n"); + return B_BAD_DATA; + } + + _value.SetTo(fStrings[index]); + } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE) { + const char* string; + status_t error = _ReadString(string); + if (error != B_OK) + return error; + + _value.SetTo(string); + } else { + fErrorOutput->PrintError("Error: Invalid TOC section: invalid " + "string encoding (%u)\n", encoding); + return B_BAD_DATA; + } + + return B_OK; + } + + case B_HPKG_ATTRIBUTE_TYPE_RAW: + { + uint64 size; + status_t error = _ReadUnsignedLEB128(size); + if (error != B_OK) + return error; + + if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) { + uint64 offset; + error = _ReadUnsignedLEB128(offset); + if (error != B_OK) + return error; + + if (offset > fHeapSize || size > fHeapSize - offset) { + fErrorOutput->PrintError("Error: Invalid TOC section: " + "invalid data reference\n"); + return B_BAD_DATA; + } + + _value.SetToData(size, fHeapOffset + offset); + } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) { + if (size > B_HPKG_MAX_INLINE_DATA_SIZE) { + fErrorOutput->PrintError("Error: Invalid TOC section: " + "inline data too long\n"); + return B_BAD_DATA; + } + + const void* buffer; + error = _GetTOCBuffer(size, buffer); + if (error != B_OK) + return error; + _value.SetToData(size, buffer); + } else { + fErrorOutput->PrintError("Error: Invalid TOC section: invalid " + "raw encoding (%u)\n", encoding); + return B_BAD_DATA; + } + + return B_OK; + } + + default: + fErrorOutput->PrintError("Error: Invalid TOC section: invalid " + "value type: %d\n", type); + return B_BAD_DATA; + } +} + + +status_t +PackageReaderImpl::_ReadUnsignedLEB128(uint64& _value) +{ + uint64 result = 0; + int shift = 0; + while (true) { + uint8 byte; + status_t error = _Read(byte); + if (error != B_OK) + return error; + + result |= uint64(byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + + _value = result; + return B_OK; +} + + +status_t +PackageReaderImpl::_ReadString(const char*& _string, size_t* _stringLength) +{ + const char* string = (const char*)fTOCSection + fCurrentTOCOffset; + size_t stringLength = strnlen(string, + fTOCUncompressedLength - fCurrentTOCOffset); + + if (stringLength == fTOCUncompressedLength - fCurrentTOCOffset) { + fErrorOutput->PrintError("_ReadString(): string extends beyond TOC " + "end\n"); + return B_BAD_DATA; + } + + _string = string; + if (_stringLength != NULL) + *_stringLength = stringLength; + + fCurrentTOCOffset += stringLength + 1; + return B_OK; +} + + +status_t +PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer) +{ + if (size > fTOCUncompressedLength - fCurrentTOCOffset) { + fErrorOutput->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n", + size); + return B_BAD_DATA; + } + + _buffer = fTOCSection + fCurrentTOCOffset; + fCurrentTOCOffset += size; + return B_OK; +} + + +status_t +PackageReaderImpl::_ReadTOCBuffer(void* buffer, size_t size) +{ + if (size > fTOCUncompressedLength - fCurrentTOCOffset) { + fErrorOutput->PrintError("_ReadTOCBuffer(%lu): read beyond TOC end\n", + size); + return B_BAD_DATA; + } + + memcpy(buffer, fTOCSection + fCurrentTOCOffset, size); + fCurrentTOCOffset += size; + return B_OK; +} + + +status_t +PackageReaderImpl::_ReadBuffer(off_t offset, void* buffer, size_t size) +{ + ssize_t bytesRead = pread(fFD, buffer, size, offset); + if (bytesRead < 0) { + fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read data: " + "%s\n", buffer, size, strerror(errno)); + return errno; + } + if ((size_t)bytesRead != size) { + fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read all " + "data\n", buffer, size); + return B_ERROR; + } + + return B_OK; +} + + +status_t +PackageReaderImpl::_ReadCompressedBuffer(off_t offset, void* buffer, + size_t compressedSize, size_t uncompressedSize, uint32 compression) +{ + switch (compression) { + case B_HPKG_COMPRESSION_NONE: + return _ReadBuffer(offset, buffer, compressedSize); + + case B_HPKG_COMPRESSION_ZLIB: + { + // init the decompressor + BBufferDataOutput bufferOutput(buffer, uncompressedSize); + ZlibDecompressor decompressor(&bufferOutput); + status_t error = decompressor.Init(); + if (error != B_OK) + return error; + + while (compressedSize > 0) { + // read compressed buffer + size_t toRead = std::min(compressedSize, fScratchBufferSize); + error = _ReadBuffer(offset, fScratchBuffer, toRead); + if (error != B_OK) + return error; + + // uncompress + error = decompressor.DecompressNext(fScratchBuffer, toRead); + if (error != B_OK) + return error; + + compressedSize -= toRead; + offset += toRead; + } + + error = decompressor.Finish(); + if (error != B_OK) + return error; + + // verify that all data have been read + if (bufferOutput.BytesWritten() != uncompressedSize) { + fErrorOutput->PrintError("Error: Missing bytes in uncompressed " + "buffer!\n"); + return B_BAD_DATA; + } + + return B_OK; + } + + default: + return B_BAD_DATA; + } +} + + +/*static*/ int8 +PackageReaderImpl::_GetStandardIndex(const AttributeType* type) +{ + // TODO: Building a hash table once would make the loopup faster. + for (int32 i = 0; kStandardAttributeIndices[i].name != NULL; i++) { + if (type->type == kStandardAttributeIndices[i].type + && strcmp(kStandardAttributeIndices[i].name, type->name) == 0) { + return i; + } + } + + return -1; +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageWriter.cpp b/src/kits/package/hpkg/PackageWriter.cpp index b1f0ba8a60..d34fe0f86a 100644 --- a/src/kits/package/hpkg/PackageWriter.cpp +++ b/src/kits/package/hpkg/PackageWriter.cpp @@ -1,1521 +1,64 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2011, Oliver Tappe * Distributed under the terms of the MIT License. */ #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include #include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include +#include namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { -namespace BPrivate { - -// minimum length of data we require before trying to zlib compress them -static const size_t kZlibCompressionSizeThreshold = 64; - - -// #pragma mark - Attributes - - -struct PackageWriter::AttributeValue { - union { - int64 signedInt; - uint64 unsignedInt; - CachedString* string; - struct { - uint64 size; - union { - uint64 offset; - uint8 raw[B_HPKG_MAX_INLINE_DATA_SIZE]; - }; - } data; - }; - uint8 type; - int8 encoding; - - AttributeValue() - : - type(B_HPKG_ATTRIBUTE_TYPE_INVALID), - encoding(-1) - { - } - - ~AttributeValue() - { - } - - void SetTo(int8 value) - { - signedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_INT; - } - - void SetTo(uint8 value) - { - unsignedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_UINT; - } - - void SetTo(int16 value) - { - signedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_INT; - } - - void SetTo(uint16 value) - { - unsignedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_UINT; - } - - void SetTo(int32 value) - { - signedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_INT; - } - - void SetTo(uint32 value) - { - unsignedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_UINT; - } - - void SetTo(int64 value) - { - signedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_INT; - } - - void SetTo(uint64 value) - { - unsignedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_UINT; - } - - void SetTo(CachedString* value) - { - string = value; - type = B_HPKG_ATTRIBUTE_TYPE_STRING; - } - - void SetToData(uint64 size, uint64 offset) - { - data.size = size; - data.offset = offset; - type = B_HPKG_ATTRIBUTE_TYPE_RAW; - encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP; - } - - void SetToData(uint64 size, const void* rawData) - { - data.size = size; - if (size > 0) - memcpy(data.raw, rawData, size); - type = B_HPKG_ATTRIBUTE_TYPE_RAW; - encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE; - } - - uint8 PreferredEncoding() const - { - switch (type) { - case B_HPKG_ATTRIBUTE_TYPE_INT: - return _PreferredIntEncoding(signedInt >= 0 - ? (uint64)signedInt << 1 - : (uint64)(-(signedInt + 1) << 1)); - case B_HPKG_ATTRIBUTE_TYPE_UINT: - return _PreferredIntEncoding(unsignedInt); - case B_HPKG_ATTRIBUTE_TYPE_STRING: - return string->index >= 0 - ? B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE - : B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE; - case B_HPKG_ATTRIBUTE_TYPE_RAW: - return encoding; - default: - return 0; - } - } - -private: - static uint8 _PreferredIntEncoding(uint64 value) - { - if (value <= 0xff) - return B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT; - if (value <= 0xffff) - return B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT; - if (value <= 0xffffffff) - return B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT; - - return B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT; - } -}; - - -struct PackageWriter::AttributeTypeKey { - const char* name; - uint8 type; - - AttributeTypeKey(const char* name, uint8 type) - : - name(name), - type(type) - { - } -}; - - -struct PackageWriter::AttributeType { - char* name; - uint8 type; - int32 index; - uint32 usageCount; - AttributeType* next; // hash table link - - AttributeType() - : - name(NULL), - type(B_HPKG_ATTRIBUTE_TYPE_INVALID), - index(-1), - usageCount(1) - { - } - - ~AttributeType() - { - free(name); - } - - bool Init(const char* name, uint8 type) - { - this->name = strdup(name); - if (this->name == NULL) - return false; - - this->type = type; - return true; - } -}; - - -struct PackageWriter::AttributeTypeHashDefinition { - typedef AttributeTypeKey KeyType; - typedef AttributeType ValueType; - - size_t HashKey(const AttributeTypeKey& key) const - { - return hash_string(key.name) ^ (uint32)key.type; - } - - size_t Hash(const AttributeType* value) const - { - return hash_string(value->name) ^ (uint32)value->type; - } - - bool Compare(const AttributeTypeKey& key, const AttributeType* value) const - { - return strcmp(value->name, key.name) == 0 && value->type == key.type; - } - - AttributeType*& GetLink(AttributeType* value) const - { - return value->next; - } -}; - - -struct PackageWriter::Attribute : public DoublyLinkedListLinkImpl { - AttributeType* type; - AttributeValue value; - DoublyLinkedList children; - - Attribute(AttributeType* type) - : - type(type) - { - } - - ~Attribute() - { - DeleteChildren(); - } - - void AddChild(Attribute* child) - { - children.Add(child); - } - - void DeleteChildren() - { - while (Attribute* child = children.RemoveHead()) - delete child; - } -}; - - -struct PackageWriter::AttributeTypeUsageGreater { - bool operator()(const AttributeType* a, const AttributeType* b) - { - return a->usageCount > b->usageCount; - } -}; - - -// #pragma mark - PackageWriter - - -struct PackageWriter::Entry : DoublyLinkedListLinkImpl { - Entry(char* name, size_t nameLength, bool isImplicit) - : - fName(name), - fNameLength(nameLength), - fIsImplicit(isImplicit) - { -printf("%p->Entry::Entry(\"%s\", %lu, %d)\n", this, name, nameLength, isImplicit); - } - - ~Entry() - { - DeleteChildren(); - free(fName); - } - - static Entry* Create(const char* name, size_t nameLength, bool isImplicit) - { - char* clonedName = (char*)malloc(nameLength + 1); - if (clonedName == NULL) - throw std::bad_alloc(); - memcpy(clonedName, name, nameLength); - clonedName[nameLength] = '\0'; - - Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, - isImplicit); - if (entry == NULL) { - free(clonedName); - throw std::bad_alloc(); - } - - return entry; - } - - const char* Name() const - { - return fName; - } - - bool IsImplicit() const - { - return fIsImplicit; - } - - void SetImplicit(bool isImplicit) - { - fIsImplicit = isImplicit; - } - - bool HasName(const char* name, size_t nameLength) - { - return nameLength == fNameLength - && strncmp(name, fName, nameLength) == 0; - } - - void AddChild(Entry* child) - { - fChildren.Add(child); - } - - void DeleteChildren() - { - while (Entry* child = fChildren.RemoveHead()) - delete child; - } - - Entry* GetChild(const char* name, size_t nameLength) const - { - EntryList::ConstIterator it = fChildren.GetIterator(); - while (Entry* child = it.Next()) { - if (child->HasName(name, nameLength)) - return child; - } - - return NULL; - } - - EntryList::ConstIterator ChildIterator() const - { - return fChildren.GetIterator(); - } - -private: - char* fName; - size_t fNameLength; - bool fIsImplicit; - EntryList fChildren; -}; - - -// #pragma mark - DataWriter - - -struct PackageWriter::DataWriter { - DataWriter() - : - fBytesWritten(0) - { - } - - virtual ~DataWriter() - { - } - - uint64 BytesWritten() const - { - return fBytesWritten; - } - - virtual status_t WriteDataNoThrow(const void* buffer, size_t size) = 0; - - inline void WriteDataThrows(const void* buffer, size_t size) - { - status_t error = WriteDataNoThrow(buffer, size); - if (error != B_OK) - throw status_t(error); - } - -protected: - uint64 fBytesWritten; -}; - - -struct PackageWriter::DummyDataWriter : DataWriter { - DummyDataWriter() - { - } - - virtual status_t WriteDataNoThrow(const void* buffer, size_t size) - { - fBytesWritten += size; - return B_OK; - } -}; - - -struct PackageWriter::FDDataWriter : DataWriter { - FDDataWriter(int fd, off_t offset) - : - fFD(fd), - fOffset(offset) - { - } - - virtual status_t WriteDataNoThrow(const void* buffer, size_t size) - { - ssize_t bytesWritten = pwrite(fFD, buffer, size, fOffset); - if (bytesWritten < 0) { - fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write data: %s\n", - buffer, size, strerror(errno)); - return errno; - } - if ((size_t)bytesWritten != size) { - fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write all data\n", - buffer, size); - return B_ERROR; - } - - fOffset += size; - fBytesWritten += size; - return B_OK; - } - - off_t Offset() const - { - return fOffset; - } - -private: - int fFD; - off_t fOffset; -}; - - -struct PackageWriter::ZlibDataWriter : DataWriter, private DataOutput { - ZlibDataWriter(DataWriter* dataWriter) - : - fDataWriter(dataWriter), - fCompressor(this) - { - } - - void Init() - { - status_t error = fCompressor.Init(); - if (error != B_OK) - throw status_t(error); - } - - void Finish() - { - status_t error = fCompressor.Finish(); - if (error != B_OK) - throw status_t(error); - } - - virtual status_t WriteDataNoThrow(const void* buffer, size_t size) - { - status_t error = fCompressor.CompressNext(buffer, size); - if (error == B_OK) - fBytesWritten += size; - return error; - } - -private: - // DataOutput - virtual status_t WriteData(const void* buffer, size_t size) - { - return fDataWriter->WriteDataNoThrow(buffer, size); - } - -private: - DataWriter* fDataWriter; - ZlibCompressor fCompressor; -}; - - -// #pragma mark - PackageWriter (Inline Methods) - - -template -inline void -PackageWriter::_Write(const Type& value) -{ - fDataWriter->WriteDataThrows(&value, sizeof(Type)); -} - - -inline void -PackageWriter::_WriteString(const char* string) -{ - fDataWriter->WriteDataThrows(string, strlen(string) + 1); -} - - -template -inline PackageWriter::Attribute* -PackageWriter::_AddAttribute(const char* attributeName, Type value) -{ - AttributeValue attributeValue; - attributeValue.SetTo(value); - return _AddAttribute(attributeName, attributeValue); -} - - -// #pragma mark - PackageWriter - - -PackageWriter::PackageWriter() +BPackageWriter::BPackageWriter() : - fFileName(NULL), - fFD(-1), - fFinished(false), - fDataBuffer(NULL), - fDataWriter(NULL), - fRootEntry(NULL), - fRootAttribute(NULL), - fTopAttribute(NULL), - fCachedStrings(NULL), - fAttributeTypes(NULL) + fImpl(new (std::nothrow) PackageWriterImpl()) { } -PackageWriter::~PackageWriter() +BPackageWriter::~BPackageWriter() { - delete fRootAttribute; - - if (fAttributeTypes != NULL) { - AttributeType* attributeType = fAttributeTypes->Clear(true); - while (attributeType != NULL) { - AttributeType* next = attributeType->next; - delete attributeType; - attributeType = next; - } - } - - if (fCachedStrings != NULL) { - CachedString* cachedString = fCachedStrings->Clear(true); - while (cachedString != NULL) { - CachedString* next = cachedString->next; - delete cachedString; - cachedString = next; - } - } - - delete fRootEntry; - - free(fDataBuffer); - - if (fFD >= 0) - close(fFD); - - if (!fFinished && fFileName != NULL) - unlink(fFileName); + delete fImpl; } status_t -PackageWriter::Init(const char* fileName) +BPackageWriter::Init(const char* fileName) { - try { - return _Init(fileName); - } catch (status_t error) { - return error; - } catch (std::bad_alloc) { - fprintf(stderr, "Out of memory!\n"); + if (fImpl == NULL) return B_NO_MEMORY; - } + + return fImpl->Init(fileName); } status_t -PackageWriter::AddEntry(const char* fileName) +BPackageWriter::AddEntry(const char* fileName) { - try { - return _RegisterEntry(fileName); - } catch (status_t error) { - return error; - } catch (std::bad_alloc) { - fprintf(stderr, "Out of memory!\n"); - return B_NO_MEMORY; - } + if (fImpl == NULL) + return B_NO_INIT; + + return fImpl->AddEntry(fileName); } status_t -PackageWriter::Finish() +BPackageWriter::Finish() { - try { - return _Finish(); - } catch (status_t error) { - return error; - } catch (std::bad_alloc) { - fprintf(stderr, "Out of memory!\n"); - return B_NO_MEMORY; - } + if (fImpl == NULL) + return B_NO_INIT; + + return fImpl->Finish(); } -status_t -PackageWriter::_Init(const char* fileName) -{ - // create hash tables - fCachedStrings = new CachedStringTable; - if (fCachedStrings->Init() != B_OK) - throw std::bad_alloc(); - - fAttributeTypes = new AttributeTypeTable; - if (fAttributeTypes->Init() != B_OK) - throw std::bad_alloc(); - - // allocate data buffer - fDataBufferSize = 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; - fDataBuffer = malloc(fDataBufferSize); - if (fDataBuffer == NULL) - throw std::bad_alloc(); - - // create entry list - fRootEntry = new Entry(NULL, 0, true); - - // open file - fFD = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (fFD < 0) { - fprintf(stderr, "Error: Failed to open package file \"%s\": %s\n", - fileName, strerror(errno)); - return errno; - } - - fRootAttribute = new Attribute(NULL); - - fFileName = fileName; - fHeapOffset = fHeapEnd = sizeof(hpkg_header); - fTopAttribute = fRootAttribute; - - return B_OK; -} - - -status_t -PackageWriter::_Finish() -{ - // write entries - for (EntryList::ConstIterator it = fRootEntry->ChildIterator(); - Entry* entry = it.Next();) { - _AddEntry(AT_FDCWD, entry, entry->Name()); - } - -printf("header size: %lu\n", sizeof(hpkg_header)); -printf("heap size: %lld\n", fHeapEnd - sizeof(hpkg_header)); - - hpkg_header header; - - // write the TOC and package attributes - _WriteTOC(header); - _WritePackageAttributes(header); - - off_t totalSize = fHeapEnd; -printf("total size: %lld\n", totalSize); - - // prepare the header - - // general - header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC); - header.header_size = B_HOST_TO_BENDIAN_INT16( - (uint16)sizeof(hpkg_header)); - header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION); - header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); - - // write the header - _WriteBuffer(&header, sizeof(hpkg_header), 0); - - fFinished = true; - return B_OK; -} - - -status_t -PackageWriter::_RegisterEntry(const char* fileName) -{ - if (*fileName == '\0') { - fprintf(stderr, "Error: Invalid empty file name\n"); - return B_BAD_VALUE; - } - - // add all components of the path - Entry* entry = fRootEntry; - while (*fileName != 0) { - const char* nextSlash = strchr(fileName, '/'); - // no slash, just add the file name - if (nextSlash == NULL) { - entry = _RegisterEntry(entry, fileName, strlen(fileName), false); - break; - } - - // find the start of the next component, skipping slashes - const char* nextComponent = nextSlash + 1; - while (*nextComponent == '/') - nextComponent++; - - if (nextSlash == fileName) { - // the FS root - entry = _RegisterEntry(entry, fileName, 1, - *nextComponent != '\0'); - } else { - entry = _RegisterEntry(entry, fileName, nextSlash - fileName, - *nextComponent != '\0'); - } - - fileName = nextComponent; - } - - return B_OK; -} - - -PackageWriter::Entry* -PackageWriter::_RegisterEntry(Entry* parent, const char* name, - size_t nameLength, bool isImplicit) -{ - // check the component name -- don't allow "." or ".." - if (name[0] == '.' - && (nameLength == 1 || (nameLength == 2 && name[1] == '.'))) { - fprintf(stderr, "Error: Invalid file name: \".\" and \"..\" " - "are not allowed as path components\n"); - throw status_t(B_BAD_VALUE); - } - - // the entry might already exist - Entry* entry = parent->GetChild(name, nameLength); - if (entry != NULL) { - // If the entry was implicit and is no longer, we mark it non-implicit - // and delete all of it's children. - if (entry->IsImplicit() && !isImplicit) { - entry->DeleteChildren(); - entry->SetImplicit(false); - } - } else { - // nope -- create it - entry = Entry::Create(name, nameLength, isImplicit); - parent->AddChild(entry); - } - - return entry; -} - - -void -PackageWriter::_WriteTOC(hpkg_header& header) -{ - // prepare the writer (zlib writer on top of a file writer) - off_t startOffset = fHeapEnd; - FDDataWriter realWriter(fFD, startOffset); - ZlibDataWriter zlibWriter(&realWriter); - fDataWriter = &zlibWriter; - zlibWriter.Init(); - - // write the sections - uint64 uncompressedAttributeTypesSize; - uint64 uncompressedStringsSize; - uint64 uncompressedMainSize; - int32 cachedStringsWritten = _WriteTOCSections( - uncompressedAttributeTypesSize, uncompressedStringsSize, - uncompressedMainSize); - - // finish the writer - zlibWriter.Finish(); - fHeapEnd = realWriter.Offset(); - fDataWriter = NULL; - -printf("attributes types size: %llu\n", uncompressedAttributeTypesSize); -printf("cached strings size: %llu\n", uncompressedStringsSize); -printf("TOC main size: %llu\n", uncompressedMainSize); - off_t endOffset = fHeapEnd; -printf("total TOC size: %llu (%llu)\n", endOffset - startOffset, zlibWriter.BytesWritten()); - - // update the header - - // TOC - header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB); - header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64( - endOffset - startOffset); - header.toc_length_uncompressed = B_HOST_TO_BENDIAN_INT64( - zlibWriter.BytesWritten()); - - // TOC subsections - header.toc_attribute_types_length = B_HOST_TO_BENDIAN_INT64( - uncompressedAttributeTypesSize); - header.toc_attribute_types_count = B_HOST_TO_BENDIAN_INT64( - fAttributeTypes->CountElements()); - header.toc_strings_length = B_HOST_TO_BENDIAN_INT64( - uncompressedStringsSize); - header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten); -} - - -int32 -PackageWriter::_WriteTOCSections(uint64& _attributeTypesSize, - uint64& _stringsSize, uint64& _mainSize) -{ - // write the attribute type abbreviations - uint64 attributeTypesOffset = fDataWriter->BytesWritten(); - _WriteAttributeTypes(); - - // write the cached strings - uint64 cachedStringsOffset = fDataWriter->BytesWritten(); - int32 cachedStringsWritten = _WriteCachedStrings(); - - // write the main TOC section - uint64 mainOffset = fDataWriter->BytesWritten(); - _WriteAttributeChildren(fRootAttribute); - - _attributeTypesSize = cachedStringsOffset - attributeTypesOffset; - _stringsSize = mainOffset - cachedStringsOffset; - _mainSize = fDataWriter->BytesWritten() - mainOffset; - - return cachedStringsWritten; -} - - -void -PackageWriter::_WriteAttributeTypes() -{ - // create an array of the attribute types - int32 attributeTypeCount = fAttributeTypes->CountElements(); - AttributeType** attributeTypes = new AttributeType*[attributeTypeCount]; - ArrayDeleter attributeTypesDeleter(attributeTypes); - - int32 index = 0; - for (AttributeTypeTable::Iterator it = fAttributeTypes->GetIterator(); - AttributeType* type = it.Next();) { - attributeTypes[index++] = type; - } - - // sort it by descending usage count - std::sort(attributeTypes, attributeTypes + attributeTypeCount, - AttributeTypeUsageGreater()); - - // assign the indices and write entries to disk - for (int32 i = 0; i < attributeTypeCount; i++) { - AttributeType* attributeType = attributeTypes[i]; - attributeType->index = i; - - _Write(attributeType->type); - _WriteString(attributeType->name); - } - - // write a terminating 0 byte - _Write(0); -} - - -int32 -PackageWriter::_WriteCachedStrings() -{ - // create an array of the cached strings - int32 count = fCachedStrings->CountElements(); - CachedString** cachedStrings = new CachedString*[count]; - ArrayDeleter cachedStringsDeleter(cachedStrings); - - int32 index = 0; - for (CachedStringTable::Iterator it = fCachedStrings->GetIterator(); - CachedString* string = it.Next();) { - cachedStrings[index++] = string; - } - - // sort it by descending usage count - std::sort(cachedStrings, cachedStrings + count, - CachedStringUsageGreater()); - - // assign the indices and write entries to disk - int32 stringsWritten = 0; - for (int32 i = 0; i < count; i++) { - CachedString* cachedString = cachedStrings[i]; - - // strings that are used only once are better stored inline - if (cachedString->usageCount < 2) - break; - - cachedString->index = i; - - _WriteString(cachedString->string); - stringsWritten++; - } - - // write a terminating 0 byte - _Write(0); - - return stringsWritten; -} - - -void -PackageWriter::_WriteAttributeChildren(Attribute* attribute) -{ - DoublyLinkedList::Iterator it - = attribute->children.GetIterator(); - while (Attribute* child = it.Next()) { - AttributeType* type = child->type; - - // write tag - uint8 encoding = child->value.PreferredEncoding(); - _WriteUnsignedLEB128(B_HPKG_ATTRIBUTE_TAG_COMPOSE(type->index, - encoding, !child->children.IsEmpty())); - - // write value - _WriteAttributeValue(child->value, encoding); - - if (!child->children.IsEmpty()) - _WriteAttributeChildren(child); - } - - _WriteUnsignedLEB128(0); -} - - -void -PackageWriter::_WritePackageAttributes(hpkg_header& header) -{ - // write the package attributes - off_t startOffset = fHeapEnd; - FDDataWriter realWriter(fFD, startOffset); - fDataWriter = &realWriter; - - _Write(0); - // TODO: Write them for real! - fHeapEnd = realWriter.Offset(); - fDataWriter = NULL; - - off_t endOffset = fHeapEnd; - -printf("package attributes size: %lld\n", endOffset - startOffset); - - // update the header - header.attributes_compression = B_HOST_TO_BENDIAN_INT32( - B_HPKG_COMPRESSION_NONE); - header.attributes_length_compressed - = B_HOST_TO_BENDIAN_INT32(endOffset - startOffset); - header.attributes_length_uncompressed - = header.attributes_length_compressed; - // TODO: Support compression! -} - - -void -PackageWriter::_WriteAttributeValue(const AttributeValue& value, uint8 encoding) -{ - switch (value.type) { - case B_HPKG_ATTRIBUTE_TYPE_INT: - case B_HPKG_ATTRIBUTE_TYPE_UINT: - { - uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT - ? (uint64)value.signedInt : value.unsignedInt; - - switch (encoding) { - case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: - _Write((uint8)intValue); - break; - case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: - _Write( - B_HOST_TO_BENDIAN_INT16((uint16)intValue)); - break; - case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: - _Write( - B_HOST_TO_BENDIAN_INT32((uint32)intValue)); - break; - case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: - _Write( - B_HOST_TO_BENDIAN_INT64((uint64)intValue)); - break; - default: - { - fprintf(stderr, "_WriteAttributeValue(): invalid " - "encoding %d for int value type %d\n", encoding, - value.type); - throw status_t(B_BAD_VALUE); - } - } - - break; - } - - case B_HPKG_ATTRIBUTE_TYPE_STRING: - { - if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) - _WriteUnsignedLEB128(value.string->index); - else - _WriteString(value.string->string); - break; - } - - case B_HPKG_ATTRIBUTE_TYPE_RAW: - { - _WriteUnsignedLEB128(value.data.size); - if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) - _WriteUnsignedLEB128(value.data.offset); - else - fDataWriter->WriteDataThrows(value.data.raw, value.data.size); - break; - } - - default: - fprintf(stderr, "_WriteAttributeValue(): invalid value type: " - "%d\n", value.type); - throw status_t(B_BAD_VALUE); - } -} - - -void -PackageWriter::_WriteUnsignedLEB128(uint64 value) -{ - uint8 bytes[10]; - int32 count = 0; - do { - uint8 byte = value & 0x7f; - value >>= 7; - bytes[count++] = byte | (value != 0 ? 0x80 : 0); - } while (value != 0); - - fDataWriter->WriteDataThrows(bytes, count); -} - - -void -PackageWriter::_WriteBuffer(const void* buffer, size_t size, off_t offset) -{ - ssize_t bytesWritten = pwrite(fFD, buffer, size, offset); - if (bytesWritten < 0) { - fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write data: %s\n", - buffer, size, strerror(errno)); - throw status_t(errno); - } - if ((size_t)bytesWritten != size) { - fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write all data\n", - buffer, size); - throw status_t(B_ERROR); - } -} - - -void -PackageWriter::_AddEntry(int dirFD, Entry* entry, const char* fileName) -{ -printf("PackageWriter::_AddEntry(%d, %p, \"%s\")\n", dirFD, entry, fileName); - bool isImplicitEntry = entry != NULL && entry->IsImplicit(); - - // open the node - int fd = openat(dirFD, fileName, - O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE)); - if (fd < 0) { - fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n", - fileName, strerror(errno)); - throw status_t(errno); - } - FDCloser fdCloser(fd); - - // stat the node - struct stat st; - if (fstat(fd, &st) < 0) { - fprintf(stderr, "Error: Failed to fstat() file \"%s\": %s\n", - fileName, strerror(errno)); - throw status_t(errno); - } - - // implicit entries must be directories - if (isImplicitEntry && !S_ISDIR(st.st_mode)) { - fprintf(stderr, "Error: Non-leaf path component \"%s\" is not a " - "directory\n", fileName); - throw status_t(B_BAD_VALUE); - } - - // check/translate the node type - uint8 fileType; - uint32 defaultPermissions; - if (S_ISREG(st.st_mode)) { - fileType = B_HPKG_FILE_TYPE_FILE; - defaultPermissions = B_HPKG_DEFAULT_FILE_PERMISSIONS; - } else if (S_ISLNK(st.st_mode)) { - fileType = B_HPKG_FILE_TYPE_SYMLINK; - defaultPermissions = B_HPKG_DEFAULT_SYMLINK_PERMISSIONS; - } else if (S_ISDIR(st.st_mode)) { - fileType = B_HPKG_FILE_TYPE_DIRECTORY; - defaultPermissions = B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS; - } else { - // unsupported node type - fprintf(stderr, "Error: Unsupported node type, entry: \"%s\"\n", - fileName); - throw status_t(B_UNSUPPORTED); - } - - // add attribute entry - Attribute* entryAttribute = _AddStringAttribute( - B_HPKG_ATTRIBUTE_NAME_DIRECTORY_ENTRY, fileName); - Stacker entryAttributeStacker(fTopAttribute, entryAttribute); - - // add stat data - if (fileType != B_HPKG_DEFAULT_FILE_TYPE) - _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_TYPE, fileType); - if (defaultPermissions != uint32(st.st_mode & ALLPERMS)) { - _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_PERMISSIONS, - uint32(st.st_mode & ALLPERMS)); - } - _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_ATIME, uint32(st.st_atime)); - _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_MTIME, uint32(st.st_mtime)); - _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_CRTIME, uint32(st.st_crtime)); - // TODO: File user/group! - - // add file data/symlink path - if (S_ISREG(st.st_mode)) { - // regular file -- add data - if (st.st_size > 0) { - FDDataReader dataReader(fd); - status_t error = _AddData(dataReader, st.st_size); - if (error != B_OK) - throw status_t(error); - } - } else if (S_ISLNK(st.st_mode)) { - // symlink -- add link address - char path[B_PATH_NAME_LENGTH + 1]; - ssize_t bytesRead = readlinkat(dirFD, fileName, path, - B_PATH_NAME_LENGTH); - if (bytesRead < 0) { - fprintf(stderr, "Error: Failed to read symlink \"%s\": %s\n", - fileName, strerror(errno)); - throw status_t(errno); - } - - path[bytesRead] = '\0'; - _AddStringAttribute(B_HPKG_ATTRIBUTE_NAME_SYMLINK_PATH, path); - } - - // add attributes - if (DIR* attrDir = fs_fopen_attr_dir(fd)) { - CObjectDeleter attrDirCloser(attrDir, fs_close_attr_dir); - - while (dirent* entry = readdir(attrDir)) { - attr_info attrInfo; - if (fs_stat_attr(fd, entry->d_name, &attrInfo) < 0) { - fprintf(stderr, "Error: Failed to stat attribute \"%s\" of " - "file \"%s\": %s\n", entry->d_name, fileName, - strerror(errno)); - throw status_t(errno); - } - - // create attribute entry - Attribute* attributeAttribute = _AddStringAttribute( - B_HPKG_ATTRIBUTE_NAME_FILE_ATTRIBUTE, entry->d_name); - Stacker attributeAttributeStacker(fTopAttribute, - attributeAttribute); - - // add type - _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_ATTRIBUTE_TYPE, - (uint32)attrInfo.type); - - // add data - AttributeDataReader dataReader(fd, entry->d_name, attrInfo.type); - status_t error = _AddData(dataReader, attrInfo.size); - if (error != B_OK) - throw status_t(error); - } - } - - if (S_ISDIR(st.st_mode)) { - // directory -- recursively add children - if (isImplicitEntry) { - // this is an implicit entry -- just add it's children - for (EntryList::ConstIterator it = entry->ChildIterator(); - Entry* child = it.Next();) { - _AddEntry(fd, child, child->Name()); - } - } else { - // we need to clone the directory FD for fdopendir() - int clonedFD = dup(fd); - if (clonedFD < 0) { - fprintf(stderr, "Error: Failed to dup() directory FD: %s\n", - strerror(errno)); - throw status_t(errno); - } - - DIR* dir = fdopendir(clonedFD); - if (dir == NULL) { - fprintf(stderr, "Error: Failed to open directory \"%s\": %s\n", - fileName, strerror(errno)); - close(clonedFD); - throw status_t(errno); - } - CObjectDeleter dirCloser(dir, closedir); - - while (dirent* entry = readdir(dir)) { - // skip "." and ".." - if (strcmp(entry->d_name, ".") == 0 - || strcmp(entry->d_name, "..") == 0) { - continue; - } - - _AddEntry(fd, NULL, entry->d_name); - } - } - } -} - - -PackageWriter::Attribute* -PackageWriter::_AddAttribute(const char* attributeName, - const AttributeValue& value) -{ - Attribute* attribute = new Attribute( - _GetAttributeType(attributeName, value.type)); - - attribute->value = value; - fTopAttribute->AddChild(attribute); - - return attribute; -} - - -PackageWriter::Attribute* -PackageWriter::_AddStringAttribute(const char* attributeName, const char* value) -{ - AttributeValue attributeValue; - attributeValue.SetTo(_GetCachedString(value)); - return _AddAttribute(attributeName, attributeValue); -} - - -PackageWriter::Attribute* -PackageWriter::_AddDataAttribute(const char* attributeName, uint64 dataSize, - uint64 dataOffset) -{ - AttributeValue attributeValue; - attributeValue.SetToData(dataSize, dataOffset); - return _AddAttribute(attributeName, attributeValue); -} - - -PackageWriter::Attribute* -PackageWriter::_AddDataAttribute(const char* attributeName, uint64 dataSize, - const uint8* data) -{ - AttributeValue attributeValue; - attributeValue.SetToData(dataSize, data); - return _AddAttribute(attributeName, attributeValue); -} - - -CachedString* -PackageWriter::_GetCachedString(const char* value) -{ - CachedString* string = fCachedStrings->Lookup(value); - if (string != NULL) { - string->usageCount++; - return string; - } - - string = new CachedString; - if (!string->Init(value)) { - delete string; - throw std::bad_alloc(); - } - - fCachedStrings->Insert(string); - return string; -} - - -PackageWriter::AttributeType* -PackageWriter::_GetAttributeType(const char* attributeName, uint8 type) -{ - AttributeType* attributeType = fAttributeTypes->Lookup( - AttributeTypeKey(attributeName, type)); - if (attributeType != NULL) { - attributeType->usageCount++; - return attributeType; - } - - attributeType = new AttributeType; - if (!attributeType->Init(attributeName, type)) { - delete attributeType; - throw std::bad_alloc(); - } - - fAttributeTypes->Insert(attributeType); - return attributeType; -} - - -status_t -PackageWriter::_AddData(DataReader& dataReader, off_t size) -{ - // add short data inline - if (size <= B_HPKG_MAX_INLINE_DATA_SIZE) { - uint8 buffer[B_HPKG_MAX_INLINE_DATA_SIZE]; - status_t error = dataReader.ReadData(0, buffer, size); - if (error != B_OK) { - fprintf(stderr, "Error: Failed to read data: %s\n", - strerror(error)); - return error; - } - - _AddDataAttribute(B_HPKG_ATTRIBUTE_NAME_DATA, size, buffer); - return B_OK; - } - - // longer data -- try to compress - uint64 dataOffset = fHeapEnd; - - uint64 compression = B_HPKG_COMPRESSION_NONE; - uint64 compressedSize; - - status_t error = _WriteZlibCompressedData(dataReader, size, dataOffset, - compressedSize); - if (error == B_OK) { - compression = B_HPKG_COMPRESSION_ZLIB; - } else { - error = _WriteUncompressedData(dataReader, size, dataOffset); - compressedSize = size; - } - if (error != B_OK) - return error; - - fHeapEnd = dataOffset + compressedSize; - - // add data attribute - Attribute* dataAttribute = _AddDataAttribute(B_HPKG_ATTRIBUTE_NAME_DATA, - compressedSize, dataOffset - fHeapOffset); - Stacker attributeAttributeStacker(fTopAttribute, dataAttribute); - - // if compressed, add compression attributes - if (compression != B_HPKG_COMPRESSION_NONE) { - _AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_COMPRESSION, compression); - _AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_SIZE, (uint64)size); - // uncompressed size - } - - return B_OK; -} - - -status_t -PackageWriter::_WriteUncompressedData(DataReader& dataReader, off_t size, - uint64 writeOffset) -{ - // copy the data to the heap - off_t readOffset = 0; - off_t remainingSize = size; - while (remainingSize > 0) { - // read data - size_t toCopy = std::min(remainingSize, (off_t)fDataBufferSize); - status_t error = dataReader.ReadData(readOffset, fDataBuffer, toCopy); - if (error != B_OK) { - fprintf(stderr, "Error: Failed to read data: %s\n", - strerror(error)); - return error; - } - - // write to heap - ssize_t bytesWritten = pwrite(fFD, fDataBuffer, toCopy, writeOffset); - if (bytesWritten < 0) { - fprintf(stderr, "Error: Failed to write data: %s\n", - strerror(errno)); - return errno; - } - if ((size_t)bytesWritten != toCopy) { - fprintf(stderr, "Error: Failed to write all data\n"); - return B_ERROR; - } - - remainingSize -= toCopy; - readOffset += toCopy; - writeOffset += toCopy; - } - - return B_OK; -} - - -status_t -PackageWriter::_WriteZlibCompressedData(DataReader& dataReader, off_t size, - uint64 writeOffset, uint64& _compressedSize) -{ - // Use zlib compression only for data large enough. - if (size < kZlibCompressionSizeThreshold) - return B_BAD_VALUE; - - // fDataBuffer is 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, so split it into - // two halves we can use for reading and compressing - const size_t chunkSize = B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; - uint8* inputBuffer = (uint8*)fDataBuffer; - uint8* outputBuffer = (uint8*)fDataBuffer + chunkSize; - - // account for the offset table - uint64 chunkCount = (size + (chunkSize - 1)) / chunkSize; - off_t offsetTableOffset = writeOffset; - uint64* offsetTable = NULL; - if (chunkCount > 1) { - offsetTable = new uint64[chunkCount - 1]; - writeOffset = offsetTableOffset + (chunkCount - 1) * sizeof(uint64); - } - ArrayDeleter offsetTableDeleter(offsetTable); - - const uint64 dataOffset = writeOffset; - const uint64 dataEndLimit = offsetTableOffset + size; - - // read the data, compress them and write them to the heap - off_t readOffset = 0; - off_t remainingSize = size; - uint64 chunkIndex = 0; - while (remainingSize > 0) { - // read data - size_t toCopy = std::min(remainingSize, (off_t)chunkSize); - status_t error = dataReader.ReadData(readOffset, inputBuffer, toCopy); - if (error != B_OK) { - fprintf(stderr, "Error: Failed to read data: %s\n", - strerror(error)); - return error; - } - - // compress - size_t compressedSize; - error = ZlibCompressor::CompressSingleBuffer(inputBuffer, toCopy, - outputBuffer, toCopy, compressedSize); - - const void* writeBuffer; - size_t bytesToWrite; - if (error == B_OK) { - writeBuffer = outputBuffer; - bytesToWrite = compressedSize; - } else { - if (error != B_BUFFER_OVERFLOW) - return error; - writeBuffer = inputBuffer; - bytesToWrite = toCopy; - } - - // check the total compressed data size - if (writeOffset + bytesToWrite >= dataEndLimit) - return B_BUFFER_OVERFLOW; - - if (chunkIndex > 0) - offsetTable[chunkIndex - 1] = writeOffset - dataOffset; - - // write to heap - ssize_t bytesWritten = pwrite(fFD, writeBuffer, bytesToWrite, - writeOffset); - if (bytesWritten < 0) { - fprintf(stderr, "Error: Failed to write data: %s\n", - strerror(errno)); - return errno; - } - if ((size_t)bytesWritten != bytesToWrite) { - fprintf(stderr, "Error: Failed to write all data\n"); - return B_ERROR; - } - - remainingSize -= toCopy; - readOffset += toCopy; - writeOffset += bytesToWrite; - chunkIndex++; - } - - // write the offset table - if (chunkCount > 1) { - size_t bytesToWrite = (chunkCount - 1) * sizeof(uint64); - ssize_t bytesWritten = pwrite(fFD, offsetTable, bytesToWrite, - offsetTableOffset); - if (bytesWritten < 0) { - fprintf(stderr, "Error: Failed to write data: %s\n", - strerror(errno)); - return errno; - } - if ((size_t)bytesWritten != bytesToWrite) { - fprintf(stderr, "Error: Failed to write all data\n"); - return B_ERROR; - } - } - - _compressedSize = writeOffset - offsetTableOffset; - return B_OK; -} - - -} // namespace BPrivate - -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp new file mode 100644 index 0000000000..b6f2fe5447 --- /dev/null +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -0,0 +1,1524 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + + +namespace BPackageKit { + +namespace BHPKG { + +namespace BPrivate { + + +// minimum length of data we require before trying to zlib compress them +static const size_t kZlibCompressionSizeThreshold = 64; + + +// #pragma mark - Attributes + + +struct PackageWriterImpl::AttributeValue { + union { + int64 signedInt; + uint64 unsignedInt; + CachedString* string; + struct { + uint64 size; + union { + uint64 offset; + uint8 raw[B_HPKG_MAX_INLINE_DATA_SIZE]; + }; + } data; + }; + uint8 type; + int8 encoding; + + AttributeValue() + : + type(B_HPKG_ATTRIBUTE_TYPE_INVALID), + encoding(-1) + { + } + + ~AttributeValue() + { + } + + void SetTo(int8 value) + { + signedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_INT; + } + + void SetTo(uint8 value) + { + unsignedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_UINT; + } + + void SetTo(int16 value) + { + signedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_INT; + } + + void SetTo(uint16 value) + { + unsignedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_UINT; + } + + void SetTo(int32 value) + { + signedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_INT; + } + + void SetTo(uint32 value) + { + unsignedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_UINT; + } + + void SetTo(int64 value) + { + signedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_INT; + } + + void SetTo(uint64 value) + { + unsignedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_UINT; + } + + void SetTo(CachedString* value) + { + string = value; + type = B_HPKG_ATTRIBUTE_TYPE_STRING; + } + + void SetToData(uint64 size, uint64 offset) + { + data.size = size; + data.offset = offset; + type = B_HPKG_ATTRIBUTE_TYPE_RAW; + encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP; + } + + void SetToData(uint64 size, const void* rawData) + { + data.size = size; + if (size > 0) + memcpy(data.raw, rawData, size); + type = B_HPKG_ATTRIBUTE_TYPE_RAW; + encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE; + } + + uint8 PreferredEncoding() const + { + switch (type) { + case B_HPKG_ATTRIBUTE_TYPE_INT: + return _PreferredIntEncoding(signedInt >= 0 + ? (uint64)signedInt << 1 + : (uint64)(-(signedInt + 1) << 1)); + case B_HPKG_ATTRIBUTE_TYPE_UINT: + return _PreferredIntEncoding(unsignedInt); + case B_HPKG_ATTRIBUTE_TYPE_STRING: + return string->index >= 0 + ? B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE + : B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE; + case B_HPKG_ATTRIBUTE_TYPE_RAW: + return encoding; + default: + return 0; + } + } + +private: + static uint8 _PreferredIntEncoding(uint64 value) + { + if (value <= 0xff) + return B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT; + if (value <= 0xffff) + return B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT; + if (value <= 0xffffffff) + return B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT; + + return B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT; + } +}; + + +struct PackageWriterImpl::AttributeTypeKey { + const char* name; + uint8 type; + + AttributeTypeKey(const char* name, uint8 type) + : + name(name), + type(type) + { + } +}; + + +struct PackageWriterImpl::AttributeType { + char* name; + uint8 type; + int32 index; + uint32 usageCount; + AttributeType* next; // hash table link + + AttributeType() + : + name(NULL), + type(B_HPKG_ATTRIBUTE_TYPE_INVALID), + index(-1), + usageCount(1) + { + } + + ~AttributeType() + { + free(name); + } + + bool Init(const char* name, uint8 type) + { + this->name = strdup(name); + if (this->name == NULL) + return false; + + this->type = type; + return true; + } +}; + + +struct PackageWriterImpl::AttributeTypeHashDefinition { + typedef AttributeTypeKey KeyType; + typedef AttributeType ValueType; + + size_t HashKey(const AttributeTypeKey& key) const + { + return hash_string(key.name) ^ (uint32)key.type; + } + + size_t Hash(const AttributeType* value) const + { + return hash_string(value->name) ^ (uint32)value->type; + } + + bool Compare(const AttributeTypeKey& key, const AttributeType* value) const + { + return strcmp(value->name, key.name) == 0 && value->type == key.type; + } + + AttributeType*& GetLink(AttributeType* value) const + { + return value->next; + } +}; + + +struct PackageWriterImpl::Attribute + : public DoublyLinkedListLinkImpl { + AttributeType* type; + AttributeValue value; + DoublyLinkedList children; + + Attribute(AttributeType* type) + : + type(type) + { + } + + ~Attribute() + { + DeleteChildren(); + } + + void AddChild(Attribute* child) + { + children.Add(child); + } + + void DeleteChildren() + { + while (Attribute* child = children.RemoveHead()) + delete child; + } +}; + + +struct PackageWriterImpl::AttributeTypeUsageGreater { + bool operator()(const AttributeType* a, const AttributeType* b) + { + return a->usageCount > b->usageCount; + } +}; + + +// #pragma mark - PackageWriterImpl + + +struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl { + Entry(char* name, size_t nameLength, bool isImplicit) + : + fName(name), + fNameLength(nameLength), + fIsImplicit(isImplicit) + { +printf("%p->Entry::Entry(\"%s\", %lu, %d)\n", this, name, nameLength, isImplicit); + } + + ~Entry() + { + DeleteChildren(); + free(fName); + } + + static Entry* Create(const char* name, size_t nameLength, bool isImplicit) + { + char* clonedName = (char*)malloc(nameLength + 1); + if (clonedName == NULL) + throw std::bad_alloc(); + memcpy(clonedName, name, nameLength); + clonedName[nameLength] = '\0'; + + Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, + isImplicit); + if (entry == NULL) { + free(clonedName); + throw std::bad_alloc(); + } + + return entry; + } + + const char* Name() const + { + return fName; + } + + bool IsImplicit() const + { + return fIsImplicit; + } + + void SetImplicit(bool isImplicit) + { + fIsImplicit = isImplicit; + } + + bool HasName(const char* name, size_t nameLength) + { + return nameLength == fNameLength + && strncmp(name, fName, nameLength) == 0; + } + + void AddChild(Entry* child) + { + fChildren.Add(child); + } + + void DeleteChildren() + { + while (Entry* child = fChildren.RemoveHead()) + delete child; + } + + Entry* GetChild(const char* name, size_t nameLength) const + { + EntryList::ConstIterator it = fChildren.GetIterator(); + while (Entry* child = it.Next()) { + if (child->HasName(name, nameLength)) + return child; + } + + return NULL; + } + + EntryList::ConstIterator ChildIterator() const + { + return fChildren.GetIterator(); + } + +private: + char* fName; + size_t fNameLength; + bool fIsImplicit; + EntryList fChildren; +}; + + +// #pragma mark - DataWriter + + +struct PackageWriterImpl::DataWriter { + DataWriter() + : + fBytesWritten(0) + { + } + + virtual ~DataWriter() + { + } + + uint64 BytesWritten() const + { + return fBytesWritten; + } + + virtual status_t WriteDataNoThrow(const void* buffer, size_t size) = 0; + + inline void WriteDataThrows(const void* buffer, size_t size) + { + status_t error = WriteDataNoThrow(buffer, size); + if (error != B_OK) + throw status_t(error); + } + +protected: + uint64 fBytesWritten; +}; + + +struct PackageWriterImpl::DummyDataWriter : DataWriter { + DummyDataWriter() + { + } + + virtual status_t WriteDataNoThrow(const void* buffer, size_t size) + { + fBytesWritten += size; + return B_OK; + } +}; + + +struct PackageWriterImpl::FDDataWriter : DataWriter { + FDDataWriter(int fd, off_t offset) + : + fFD(fd), + fOffset(offset) + { + } + + virtual status_t WriteDataNoThrow(const void* buffer, size_t size) + { + ssize_t bytesWritten = pwrite(fFD, buffer, size, fOffset); + if (bytesWritten < 0) { + fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write data: %s\n", + buffer, size, strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != size) { + fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write all data\n", + buffer, size); + return B_ERROR; + } + + fOffset += size; + fBytesWritten += size; + return B_OK; + } + + off_t Offset() const + { + return fOffset; + } + +private: + int fFD; + off_t fOffset; +}; + + +struct PackageWriterImpl::ZlibDataWriter : DataWriter, private BDataOutput { + ZlibDataWriter(DataWriter* dataWriter) + : + fDataWriter(dataWriter), + fCompressor(this) + { + } + + void Init() + { + status_t error = fCompressor.Init(); + if (error != B_OK) + throw status_t(error); + } + + void Finish() + { + status_t error = fCompressor.Finish(); + if (error != B_OK) + throw status_t(error); + } + + virtual status_t WriteDataNoThrow(const void* buffer, size_t size) + { + status_t error = fCompressor.CompressNext(buffer, size); + if (error == B_OK) + fBytesWritten += size; + return error; + } + +private: + // BDataOutput + virtual status_t WriteData(const void* buffer, size_t size) + { + return fDataWriter->WriteDataNoThrow(buffer, size); + } + +private: + DataWriter* fDataWriter; + ZlibCompressor fCompressor; +}; + + +// #pragma mark - PackageWriterImpl (Inline Methods) + + +template +inline void +PackageWriterImpl::_Write(const Type& value) +{ + fDataWriter->WriteDataThrows(&value, sizeof(Type)); +} + + +inline void +PackageWriterImpl::_WriteString(const char* string) +{ + fDataWriter->WriteDataThrows(string, strlen(string) + 1); +} + + +template +inline PackageWriterImpl::Attribute* +PackageWriterImpl::_AddAttribute(const char* attributeName, Type value) +{ + AttributeValue attributeValue; + attributeValue.SetTo(value); + return _AddAttribute(attributeName, attributeValue); +} + + +// #pragma mark - PackageWriterImpl + + +PackageWriterImpl::PackageWriterImpl() + : + fFileName(NULL), + fFD(-1), + fFinished(false), + fDataBuffer(NULL), + fDataWriter(NULL), + fRootEntry(NULL), + fRootAttribute(NULL), + fTopAttribute(NULL), + fCachedStrings(NULL), + fAttributeTypes(NULL) +{ +} + + +PackageWriterImpl::~PackageWriterImpl() +{ + delete fRootAttribute; + + if (fAttributeTypes != NULL) { + AttributeType* attributeType = fAttributeTypes->Clear(true); + while (attributeType != NULL) { + AttributeType* next = attributeType->next; + delete attributeType; + attributeType = next; + } + } + + if (fCachedStrings != NULL) { + CachedString* cachedString = fCachedStrings->Clear(true); + while (cachedString != NULL) { + CachedString* next = cachedString->next; + delete cachedString; + cachedString = next; + } + } + + delete fRootEntry; + + free(fDataBuffer); + + if (fFD >= 0) + close(fFD); + + if (!fFinished && fFileName != NULL) + unlink(fFileName); +} + + +status_t +PackageWriterImpl::Init(const char* fileName) +{ + try { + return _Init(fileName); + } catch (status_t error) { + return error; + } catch (std::bad_alloc) { + fprintf(stderr, "Out of memory!\n"); + return B_NO_MEMORY; + } +} + + +status_t +PackageWriterImpl::AddEntry(const char* fileName) +{ + try { + return _RegisterEntry(fileName); + } catch (status_t error) { + return error; + } catch (std::bad_alloc) { + fprintf(stderr, "Out of memory!\n"); + return B_NO_MEMORY; + } +} + + +status_t +PackageWriterImpl::Finish() +{ + try { + return _Finish(); + } catch (status_t error) { + return error; + } catch (std::bad_alloc) { + fprintf(stderr, "Out of memory!\n"); + return B_NO_MEMORY; + } +} + + +status_t +PackageWriterImpl::_Init(const char* fileName) +{ + // create hash tables + fCachedStrings = new CachedStringTable; + if (fCachedStrings->Init() != B_OK) + throw std::bad_alloc(); + + fAttributeTypes = new AttributeTypeTable; + if (fAttributeTypes->Init() != B_OK) + throw std::bad_alloc(); + + // allocate data buffer + fDataBufferSize = 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; + fDataBuffer = malloc(fDataBufferSize); + if (fDataBuffer == NULL) + throw std::bad_alloc(); + + // create entry list + fRootEntry = new Entry(NULL, 0, true); + + // open file + fFD = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fFD < 0) { + fprintf(stderr, "Error: Failed to open package file \"%s\": %s\n", + fileName, strerror(errno)); + return errno; + } + + fRootAttribute = new Attribute(NULL); + + fFileName = fileName; + fHeapOffset = fHeapEnd = sizeof(hpkg_header); + fTopAttribute = fRootAttribute; + + return B_OK; +} + + +status_t +PackageWriterImpl::_Finish() +{ + // write entries + for (EntryList::ConstIterator it = fRootEntry->ChildIterator(); + Entry* entry = it.Next();) { + _AddEntry(AT_FDCWD, entry, entry->Name()); + } + +printf("header size: %lu\n", sizeof(hpkg_header)); +printf("heap size: %lld\n", fHeapEnd - sizeof(hpkg_header)); + + hpkg_header header; + + // write the TOC and package attributes + _WriteTOC(header); + _WritePackageAttributes(header); + + off_t totalSize = fHeapEnd; +printf("total size: %lld\n", totalSize); + + // prepare the header + + // general + header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC); + header.header_size = B_HOST_TO_BENDIAN_INT16( + (uint16)sizeof(hpkg_header)); + header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION); + header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); + + // write the header + _WriteBuffer(&header, sizeof(hpkg_header), 0); + + fFinished = true; + return B_OK; +} + + +status_t +PackageWriterImpl::_RegisterEntry(const char* fileName) +{ + if (*fileName == '\0') { + fprintf(stderr, "Error: Invalid empty file name\n"); + return B_BAD_VALUE; + } + + // add all components of the path + Entry* entry = fRootEntry; + while (*fileName != 0) { + const char* nextSlash = strchr(fileName, '/'); + // no slash, just add the file name + if (nextSlash == NULL) { + entry = _RegisterEntry(entry, fileName, strlen(fileName), false); + break; + } + + // find the start of the next component, skipping slashes + const char* nextComponent = nextSlash + 1; + while (*nextComponent == '/') + nextComponent++; + + if (nextSlash == fileName) { + // the FS root + entry = _RegisterEntry(entry, fileName, 1, + *nextComponent != '\0'); + } else { + entry = _RegisterEntry(entry, fileName, nextSlash - fileName, + *nextComponent != '\0'); + } + + fileName = nextComponent; + } + + return B_OK; +} + + +PackageWriterImpl::Entry* +PackageWriterImpl::_RegisterEntry(Entry* parent, const char* name, + size_t nameLength, bool isImplicit) +{ + // check the component name -- don't allow "." or ".." + if (name[0] == '.' + && (nameLength == 1 || (nameLength == 2 && name[1] == '.'))) { + fprintf(stderr, "Error: Invalid file name: \".\" and \"..\" " + "are not allowed as path components\n"); + throw status_t(B_BAD_VALUE); + } + + // the entry might already exist + Entry* entry = parent->GetChild(name, nameLength); + if (entry != NULL) { + // If the entry was implicit and is no longer, we mark it non-implicit + // and delete all of it's children. + if (entry->IsImplicit() && !isImplicit) { + entry->DeleteChildren(); + entry->SetImplicit(false); + } + } else { + // nope -- create it + entry = Entry::Create(name, nameLength, isImplicit); + parent->AddChild(entry); + } + + return entry; +} + + +void +PackageWriterImpl::_WriteTOC(hpkg_header& header) +{ + // prepare the writer (zlib writer on top of a file writer) + off_t startOffset = fHeapEnd; + FDDataWriter realWriter(fFD, startOffset); + ZlibDataWriter zlibWriter(&realWriter); + fDataWriter = &zlibWriter; + zlibWriter.Init(); + + // write the sections + uint64 uncompressedAttributeTypesSize; + uint64 uncompressedStringsSize; + uint64 uncompressedMainSize; + int32 cachedStringsWritten = _WriteTOCSections( + uncompressedAttributeTypesSize, uncompressedStringsSize, + uncompressedMainSize); + + // finish the writer + zlibWriter.Finish(); + fHeapEnd = realWriter.Offset(); + fDataWriter = NULL; + +printf("attributes types size: %llu\n", uncompressedAttributeTypesSize); +printf("cached strings size: %llu\n", uncompressedStringsSize); +printf("TOC main size: %llu\n", uncompressedMainSize); + off_t endOffset = fHeapEnd; +printf("total TOC size: %llu (%llu)\n", endOffset - startOffset, zlibWriter.BytesWritten()); + + // update the header + + // TOC + header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB); + header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64( + endOffset - startOffset); + header.toc_length_uncompressed = B_HOST_TO_BENDIAN_INT64( + zlibWriter.BytesWritten()); + + // TOC subsections + header.toc_attribute_types_length = B_HOST_TO_BENDIAN_INT64( + uncompressedAttributeTypesSize); + header.toc_attribute_types_count = B_HOST_TO_BENDIAN_INT64( + fAttributeTypes->CountElements()); + header.toc_strings_length = B_HOST_TO_BENDIAN_INT64( + uncompressedStringsSize); + header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten); +} + + +int32 +PackageWriterImpl::_WriteTOCSections(uint64& _attributeTypesSize, + uint64& _stringsSize, uint64& _mainSize) +{ + // write the attribute type abbreviations + uint64 attributeTypesOffset = fDataWriter->BytesWritten(); + _WriteAttributeTypes(); + + // write the cached strings + uint64 cachedStringsOffset = fDataWriter->BytesWritten(); + int32 cachedStringsWritten = _WriteCachedStrings(); + + // write the main TOC section + uint64 mainOffset = fDataWriter->BytesWritten(); + _WriteAttributeChildren(fRootAttribute); + + _attributeTypesSize = cachedStringsOffset - attributeTypesOffset; + _stringsSize = mainOffset - cachedStringsOffset; + _mainSize = fDataWriter->BytesWritten() - mainOffset; + + return cachedStringsWritten; +} + + +void +PackageWriterImpl::_WriteAttributeTypes() +{ + // create an array of the attribute types + int32 attributeTypeCount = fAttributeTypes->CountElements(); + AttributeType** attributeTypes = new AttributeType*[attributeTypeCount]; + ArrayDeleter attributeTypesDeleter(attributeTypes); + + int32 index = 0; + for (AttributeTypeTable::Iterator it = fAttributeTypes->GetIterator(); + AttributeType* type = it.Next();) { + attributeTypes[index++] = type; + } + + // sort it by descending usage count + std::sort(attributeTypes, attributeTypes + attributeTypeCount, + AttributeTypeUsageGreater()); + + // assign the indices and write entries to disk + for (int32 i = 0; i < attributeTypeCount; i++) { + AttributeType* attributeType = attributeTypes[i]; + attributeType->index = i; + + _Write(attributeType->type); + _WriteString(attributeType->name); + } + + // write a terminating 0 byte + _Write(0); +} + + +int32 +PackageWriterImpl::_WriteCachedStrings() +{ + // create an array of the cached strings + int32 count = fCachedStrings->CountElements(); + CachedString** cachedStrings = new CachedString*[count]; + ArrayDeleter cachedStringsDeleter(cachedStrings); + + int32 index = 0; + for (CachedStringTable::Iterator it = fCachedStrings->GetIterator(); + CachedString* string = it.Next();) { + cachedStrings[index++] = string; + } + + // sort it by descending usage count + std::sort(cachedStrings, cachedStrings + count, + CachedStringUsageGreater()); + + // assign the indices and write entries to disk + int32 stringsWritten = 0; + for (int32 i = 0; i < count; i++) { + CachedString* cachedString = cachedStrings[i]; + + // strings that are used only once are better stored inline + if (cachedString->usageCount < 2) + break; + + cachedString->index = i; + + _WriteString(cachedString->string); + stringsWritten++; + } + + // write a terminating 0 byte + _Write(0); + + return stringsWritten; +} + + +void +PackageWriterImpl::_WriteAttributeChildren(Attribute* attribute) +{ + DoublyLinkedList::Iterator it + = attribute->children.GetIterator(); + while (Attribute* child = it.Next()) { + AttributeType* type = child->type; + + // write tag + uint8 encoding = child->value.PreferredEncoding(); + _WriteUnsignedLEB128(B_HPKG_ATTRIBUTE_TAG_COMPOSE(type->index, + encoding, !child->children.IsEmpty())); + + // write value + _WriteAttributeValue(child->value, encoding); + + if (!child->children.IsEmpty()) + _WriteAttributeChildren(child); + } + + _WriteUnsignedLEB128(0); +} + + +void +PackageWriterImpl::_WritePackageAttributes(hpkg_header& header) +{ + // write the package attributes + off_t startOffset = fHeapEnd; + FDDataWriter realWriter(fFD, startOffset); + fDataWriter = &realWriter; + + _Write(0); + // TODO: Write them for real! + fHeapEnd = realWriter.Offset(); + fDataWriter = NULL; + + off_t endOffset = fHeapEnd; + +printf("package attributes size: %lld\n", endOffset - startOffset); + + // update the header + header.attributes_compression = B_HOST_TO_BENDIAN_INT32( + B_HPKG_COMPRESSION_NONE); + header.attributes_length_compressed + = B_HOST_TO_BENDIAN_INT32(endOffset - startOffset); + header.attributes_length_uncompressed + = header.attributes_length_compressed; + // TODO: Support compression! +} + + +void +PackageWriterImpl::_WriteAttributeValue(const AttributeValue& value, + uint8 encoding) +{ + switch (value.type) { + case B_HPKG_ATTRIBUTE_TYPE_INT: + case B_HPKG_ATTRIBUTE_TYPE_UINT: + { + uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT + ? (uint64)value.signedInt : value.unsignedInt; + + switch (encoding) { + case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: + _Write((uint8)intValue); + break; + case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: + _Write( + B_HOST_TO_BENDIAN_INT16((uint16)intValue)); + break; + case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: + _Write( + B_HOST_TO_BENDIAN_INT32((uint32)intValue)); + break; + case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: + _Write( + B_HOST_TO_BENDIAN_INT64((uint64)intValue)); + break; + default: + { + fprintf(stderr, "_WriteAttributeValue(): invalid " + "encoding %d for int value type %d\n", encoding, + value.type); + throw status_t(B_BAD_VALUE); + } + } + + break; + } + + case B_HPKG_ATTRIBUTE_TYPE_STRING: + { + if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) + _WriteUnsignedLEB128(value.string->index); + else + _WriteString(value.string->string); + break; + } + + case B_HPKG_ATTRIBUTE_TYPE_RAW: + { + _WriteUnsignedLEB128(value.data.size); + if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) + _WriteUnsignedLEB128(value.data.offset); + else + fDataWriter->WriteDataThrows(value.data.raw, value.data.size); + break; + } + + default: + fprintf(stderr, "_WriteAttributeValue(): invalid value type: " + "%d\n", value.type); + throw status_t(B_BAD_VALUE); + } +} + + +void +PackageWriterImpl::_WriteUnsignedLEB128(uint64 value) +{ + uint8 bytes[10]; + int32 count = 0; + do { + uint8 byte = value & 0x7f; + value >>= 7; + bytes[count++] = byte | (value != 0 ? 0x80 : 0); + } while (value != 0); + + fDataWriter->WriteDataThrows(bytes, count); +} + + +void +PackageWriterImpl::_WriteBuffer(const void* buffer, size_t size, off_t offset) +{ + ssize_t bytesWritten = pwrite(fFD, buffer, size, offset); + if (bytesWritten < 0) { + fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write data: %s\n", + buffer, size, strerror(errno)); + throw status_t(errno); + } + if ((size_t)bytesWritten != size) { + fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write all data\n", + buffer, size); + throw status_t(B_ERROR); + } +} + + +void +PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName) +{ +printf("PackageWriter::_AddEntry(%d, %p, \"%s\")\n", dirFD, entry, fileName); + bool isImplicitEntry = entry != NULL && entry->IsImplicit(); + + // open the node + int fd = openat(dirFD, fileName, + O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE)); + if (fd < 0) { + fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n", + fileName, strerror(errno)); + throw status_t(errno); + } + FDCloser fdCloser(fd); + + // stat the node + struct stat st; + if (fstat(fd, &st) < 0) { + fprintf(stderr, "Error: Failed to fstat() file \"%s\": %s\n", + fileName, strerror(errno)); + throw status_t(errno); + } + + // implicit entries must be directories + if (isImplicitEntry && !S_ISDIR(st.st_mode)) { + fprintf(stderr, "Error: Non-leaf path component \"%s\" is not a " + "directory\n", fileName); + throw status_t(B_BAD_VALUE); + } + + // check/translate the node type + uint8 fileType; + uint32 defaultPermissions; + if (S_ISREG(st.st_mode)) { + fileType = B_HPKG_FILE_TYPE_FILE; + defaultPermissions = B_HPKG_DEFAULT_FILE_PERMISSIONS; + } else if (S_ISLNK(st.st_mode)) { + fileType = B_HPKG_FILE_TYPE_SYMLINK; + defaultPermissions = B_HPKG_DEFAULT_SYMLINK_PERMISSIONS; + } else if (S_ISDIR(st.st_mode)) { + fileType = B_HPKG_FILE_TYPE_DIRECTORY; + defaultPermissions = B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS; + } else { + // unsupported node type + fprintf(stderr, "Error: Unsupported node type, entry: \"%s\"\n", + fileName); + throw status_t(B_UNSUPPORTED); + } + + // add attribute entry + Attribute* entryAttribute = _AddStringAttribute( + B_HPKG_ATTRIBUTE_NAME_DIRECTORY_ENTRY, fileName); + Stacker entryAttributeStacker(fTopAttribute, entryAttribute); + + // add stat data + if (fileType != B_HPKG_DEFAULT_FILE_TYPE) + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_TYPE, fileType); + if (defaultPermissions != uint32(st.st_mode & ALLPERMS)) { + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_PERMISSIONS, + uint32(st.st_mode & ALLPERMS)); + } + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_ATIME, uint32(st.st_atime)); + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_MTIME, uint32(st.st_mtime)); + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_CRTIME, uint32(st.st_crtime)); + // TODO: File user/group! + + // add file data/symlink path + if (S_ISREG(st.st_mode)) { + // regular file -- add data + if (st.st_size > 0) { + BFDDataReader dataReader(fd); + status_t error = _AddData(dataReader, st.st_size); + if (error != B_OK) + throw status_t(error); + } + } else if (S_ISLNK(st.st_mode)) { + // symlink -- add link address + char path[B_PATH_NAME_LENGTH + 1]; + ssize_t bytesRead = readlinkat(dirFD, fileName, path, + B_PATH_NAME_LENGTH); + if (bytesRead < 0) { + fprintf(stderr, "Error: Failed to read symlink \"%s\": %s\n", + fileName, strerror(errno)); + throw status_t(errno); + } + + path[bytesRead] = '\0'; + _AddStringAttribute(B_HPKG_ATTRIBUTE_NAME_SYMLINK_PATH, path); + } + + // add attributes + if (DIR* attrDir = fs_fopen_attr_dir(fd)) { + CObjectDeleter attrDirCloser(attrDir, fs_close_attr_dir); + + while (dirent* entry = readdir(attrDir)) { + attr_info attrInfo; + if (fs_stat_attr(fd, entry->d_name, &attrInfo) < 0) { + fprintf(stderr, "Error: Failed to stat attribute \"%s\" of " + "file \"%s\": %s\n", entry->d_name, fileName, + strerror(errno)); + throw status_t(errno); + } + + // create attribute entry + Attribute* attributeAttribute = _AddStringAttribute( + B_HPKG_ATTRIBUTE_NAME_FILE_ATTRIBUTE, entry->d_name); + Stacker attributeAttributeStacker(fTopAttribute, + attributeAttribute); + + // add type + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_ATTRIBUTE_TYPE, + (uint32)attrInfo.type); + + // add data + BAttributeDataReader dataReader(fd, entry->d_name, attrInfo.type); + status_t error = _AddData(dataReader, attrInfo.size); + if (error != B_OK) + throw status_t(error); + } + } + + if (S_ISDIR(st.st_mode)) { + // directory -- recursively add children + if (isImplicitEntry) { + // this is an implicit entry -- just add it's children + for (EntryList::ConstIterator it = entry->ChildIterator(); + Entry* child = it.Next();) { + _AddEntry(fd, child, child->Name()); + } + } else { + // we need to clone the directory FD for fdopendir() + int clonedFD = dup(fd); + if (clonedFD < 0) { + fprintf(stderr, "Error: Failed to dup() directory FD: %s\n", + strerror(errno)); + throw status_t(errno); + } + + DIR* dir = fdopendir(clonedFD); + if (dir == NULL) { + fprintf(stderr, "Error: Failed to open directory \"%s\": %s\n", + fileName, strerror(errno)); + close(clonedFD); + throw status_t(errno); + } + CObjectDeleter dirCloser(dir, closedir); + + while (dirent* entry = readdir(dir)) { + // skip "." and ".." + if (strcmp(entry->d_name, ".") == 0 + || strcmp(entry->d_name, "..") == 0) { + continue; + } + + _AddEntry(fd, NULL, entry->d_name); + } + } + } +} + + +PackageWriterImpl::Attribute* +PackageWriterImpl::_AddAttribute(const char* attributeName, + const AttributeValue& value) +{ + Attribute* attribute = new Attribute( + _GetAttributeType(attributeName, value.type)); + + attribute->value = value; + fTopAttribute->AddChild(attribute); + + return attribute; +} + + +PackageWriterImpl::Attribute* +PackageWriterImpl::_AddStringAttribute(const char* attributeName, + const char* value) +{ + AttributeValue attributeValue; + attributeValue.SetTo(_GetCachedString(value)); + return _AddAttribute(attributeName, attributeValue); +} + + +PackageWriterImpl::Attribute* +PackageWriterImpl::_AddDataAttribute(const char* attributeName, uint64 dataSize, + uint64 dataOffset) +{ + AttributeValue attributeValue; + attributeValue.SetToData(dataSize, dataOffset); + return _AddAttribute(attributeName, attributeValue); +} + + +PackageWriterImpl::Attribute* +PackageWriterImpl::_AddDataAttribute(const char* attributeName, uint64 dataSize, + const uint8* data) +{ + AttributeValue attributeValue; + attributeValue.SetToData(dataSize, data); + return _AddAttribute(attributeName, attributeValue); +} + + +CachedString* +PackageWriterImpl::_GetCachedString(const char* value) +{ + CachedString* string = fCachedStrings->Lookup(value); + if (string != NULL) { + string->usageCount++; + return string; + } + + string = new CachedString; + if (!string->Init(value)) { + delete string; + throw std::bad_alloc(); + } + + fCachedStrings->Insert(string); + return string; +} + + +PackageWriterImpl::AttributeType* +PackageWriterImpl::_GetAttributeType(const char* attributeName, uint8 type) +{ + AttributeType* attributeType = fAttributeTypes->Lookup( + AttributeTypeKey(attributeName, type)); + if (attributeType != NULL) { + attributeType->usageCount++; + return attributeType; + } + + attributeType = new AttributeType; + if (!attributeType->Init(attributeName, type)) { + delete attributeType; + throw std::bad_alloc(); + } + + fAttributeTypes->Insert(attributeType); + return attributeType; +} + + +status_t +PackageWriterImpl::_AddData(BDataReader& dataReader, off_t size) +{ + // add short data inline + if (size <= B_HPKG_MAX_INLINE_DATA_SIZE) { + uint8 buffer[B_HPKG_MAX_INLINE_DATA_SIZE]; + status_t error = dataReader.ReadData(0, buffer, size); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to read data: %s\n", + strerror(error)); + return error; + } + + _AddDataAttribute(B_HPKG_ATTRIBUTE_NAME_DATA, size, buffer); + return B_OK; + } + + // longer data -- try to compress + uint64 dataOffset = fHeapEnd; + + uint64 compression = B_HPKG_COMPRESSION_NONE; + uint64 compressedSize; + + status_t error = _WriteZlibCompressedData(dataReader, size, dataOffset, + compressedSize); + if (error == B_OK) { + compression = B_HPKG_COMPRESSION_ZLIB; + } else { + error = _WriteUncompressedData(dataReader, size, dataOffset); + compressedSize = size; + } + if (error != B_OK) + return error; + + fHeapEnd = dataOffset + compressedSize; + + // add data attribute + Attribute* dataAttribute = _AddDataAttribute(B_HPKG_ATTRIBUTE_NAME_DATA, + compressedSize, dataOffset - fHeapOffset); + Stacker attributeAttributeStacker(fTopAttribute, dataAttribute); + + // if compressed, add compression attributes + if (compression != B_HPKG_COMPRESSION_NONE) { + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_COMPRESSION, compression); + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_SIZE, (uint64)size); + // uncompressed size + } + + return B_OK; +} + + +status_t +PackageWriterImpl::_WriteUncompressedData(BDataReader& dataReader, off_t size, + uint64 writeOffset) +{ + // copy the data to the heap + off_t readOffset = 0; + off_t remainingSize = size; + while (remainingSize > 0) { + // read data + size_t toCopy = std::min(remainingSize, (off_t)fDataBufferSize); + status_t error = dataReader.ReadData(readOffset, fDataBuffer, toCopy); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to read data: %s\n", + strerror(error)); + return error; + } + + // write to heap + ssize_t bytesWritten = pwrite(fFD, fDataBuffer, toCopy, writeOffset); + if (bytesWritten < 0) { + fprintf(stderr, "Error: Failed to write data: %s\n", + strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != toCopy) { + fprintf(stderr, "Error: Failed to write all data\n"); + return B_ERROR; + } + + remainingSize -= toCopy; + readOffset += toCopy; + writeOffset += toCopy; + } + + return B_OK; +} + + +status_t +PackageWriterImpl::_WriteZlibCompressedData(BDataReader& dataReader, off_t size, + uint64 writeOffset, uint64& _compressedSize) +{ + // Use zlib compression only for data large enough. + if (size < kZlibCompressionSizeThreshold) + return B_BAD_VALUE; + + // fDataBuffer is 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, so split it into + // two halves we can use for reading and compressing + const size_t chunkSize = B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; + uint8* inputBuffer = (uint8*)fDataBuffer; + uint8* outputBuffer = (uint8*)fDataBuffer + chunkSize; + + // account for the offset table + uint64 chunkCount = (size + (chunkSize - 1)) / chunkSize; + off_t offsetTableOffset = writeOffset; + uint64* offsetTable = NULL; + if (chunkCount > 1) { + offsetTable = new uint64[chunkCount - 1]; + writeOffset = offsetTableOffset + (chunkCount - 1) * sizeof(uint64); + } + ArrayDeleter offsetTableDeleter(offsetTable); + + const uint64 dataOffset = writeOffset; + const uint64 dataEndLimit = offsetTableOffset + size; + + // read the data, compress them and write them to the heap + off_t readOffset = 0; + off_t remainingSize = size; + uint64 chunkIndex = 0; + while (remainingSize > 0) { + // read data + size_t toCopy = std::min(remainingSize, (off_t)chunkSize); + status_t error = dataReader.ReadData(readOffset, inputBuffer, toCopy); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to read data: %s\n", + strerror(error)); + return error; + } + + // compress + size_t compressedSize; + error = ZlibCompressor::CompressSingleBuffer(inputBuffer, toCopy, + outputBuffer, toCopy, compressedSize); + + const void* writeBuffer; + size_t bytesToWrite; + if (error == B_OK) { + writeBuffer = outputBuffer; + bytesToWrite = compressedSize; + } else { + if (error != B_BUFFER_OVERFLOW) + return error; + writeBuffer = inputBuffer; + bytesToWrite = toCopy; + } + + // check the total compressed data size + if (writeOffset + bytesToWrite >= dataEndLimit) + return B_BUFFER_OVERFLOW; + + if (chunkIndex > 0) + offsetTable[chunkIndex - 1] = writeOffset - dataOffset; + + // write to heap + ssize_t bytesWritten = pwrite(fFD, writeBuffer, bytesToWrite, + writeOffset); + if (bytesWritten < 0) { + fprintf(stderr, "Error: Failed to write data: %s\n", + strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != bytesToWrite) { + fprintf(stderr, "Error: Failed to write all data\n"); + return B_ERROR; + } + + remainingSize -= toCopy; + readOffset += toCopy; + writeOffset += bytesToWrite; + chunkIndex++; + } + + // write the offset table + if (chunkCount > 1) { + size_t bytesToWrite = (chunkCount - 1) * sizeof(uint64); + ssize_t bytesWritten = pwrite(fFD, offsetTable, bytesToWrite, + offsetTableOffset); + if (bytesWritten < 0) { + fprintf(stderr, "Error: Failed to write data: %s\n", + strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != bytesToWrite) { + fprintf(stderr, "Error: Failed to write all data\n"); + return B_ERROR; + } + } + + _compressedSize = writeOffset - offsetTableOffset; + return B_OK; +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/Strings.cpp b/src/kits/package/hpkg/Strings.cpp index 1fbb51a76e..47a488634c 100644 --- a/src/kits/package/hpkg/Strings.cpp +++ b/src/kits/package/hpkg/Strings.cpp @@ -9,7 +9,7 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -36,6 +36,6 @@ hash_string(const char* string) } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/ZlibCompressionBase.cpp b/src/kits/package/hpkg/ZlibCompressionBase.cpp index 22f29005c6..4fe43377a9 100644 --- a/src/kits/package/hpkg/ZlibCompressionBase.cpp +++ b/src/kits/package/hpkg/ZlibCompressionBase.cpp @@ -13,7 +13,7 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -49,6 +49,6 @@ ZlibCompressionBase::TranslateZlibError(int error) } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/ZlibCompressor.cpp b/src/kits/package/hpkg/ZlibCompressor.cpp index 8bc2821d26..17801b4b4b 100644 --- a/src/kits/package/hpkg/ZlibCompressor.cpp +++ b/src/kits/package/hpkg/ZlibCompressor.cpp @@ -14,7 +14,7 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -22,7 +22,7 @@ namespace BPrivate { static const size_t kOutputBufferSize = 1024; -ZlibCompressor::ZlibCompressor(DataOutput* output) +ZlibCompressor::ZlibCompressor(BDataOutput* output) : fOutput(output), fStreamInitialized(false) @@ -180,6 +180,6 @@ ZlibCompressor::CompressSingleBuffer(const void* input, size_t inputSize, } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/ZlibDecompressor.cpp b/src/kits/package/hpkg/ZlibDecompressor.cpp index f092ae2e22..9b6235f357 100644 --- a/src/kits/package/hpkg/ZlibDecompressor.cpp +++ b/src/kits/package/hpkg/ZlibDecompressor.cpp @@ -14,7 +14,7 @@ namespace BPackageKit { -namespace BHaikuPackage { +namespace BHPKG { namespace BPrivate { @@ -23,7 +23,7 @@ namespace BPrivate { static const size_t kOutputBufferSize = 1024; -ZlibDecompressor::ZlibDecompressor(DataOutput* output) +ZlibDecompressor::ZlibDecompressor(BDataOutput* output) : fOutput(output), fStreamInitialized(false), @@ -187,6 +187,6 @@ ZlibDecompressor::DecompressSingleBuffer(const void* input, size_t inputSize, } // namespace BPrivate -} // namespace BHaikuPackage +} // namespace BHPKG } // namespace BPackageKit