1/*
2 * Copyright 2013-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
6#define _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
7
8
9#include <new>
10
11#include <Referenceable.h>
12
13#include <CompressionAlgorithm.h>
14#include <package/hpkg/DataReader.h>
15
16
17namespace BPackageKit {
18
19namespace BHPKG {
20
21
22class BErrorOutput;
23
24
25namespace BPrivate {
26
27
28template<typename Parameters>
29struct GenericCompressionAlgorithmOwner : BReferenceable {
30	BCompressionAlgorithm*	algorithm;
31	Parameters*				parameters;
32
33	GenericCompressionAlgorithmOwner(BCompressionAlgorithm* algorithm,
34		Parameters* parameters)
35		:
36		algorithm(algorithm),
37		parameters(parameters)
38	{
39	}
40
41	~GenericCompressionAlgorithmOwner()
42	{
43		delete algorithm;
44		delete parameters;
45	}
46
47	static GenericCompressionAlgorithmOwner* Create(
48		BCompressionAlgorithm* algorithm, Parameters* parameters)
49	{
50		GenericCompressionAlgorithmOwner* owner
51			= new(std::nothrow) GenericCompressionAlgorithmOwner(algorithm,
52				parameters);
53		if (owner == NULL) {
54			delete algorithm;
55			delete parameters;
56		}
57
58		return owner;
59	}
60};
61
62typedef GenericCompressionAlgorithmOwner<BCompressionParameters>
63	CompressionAlgorithmOwner;
64typedef GenericCompressionAlgorithmOwner<BDecompressionParameters>
65	DecompressionAlgorithmOwner;
66
67
68class PackageFileHeapAccessorBase : public BAbstractBufferedDataReader {
69public:
70			class OffsetArray;
71
72public:
73								PackageFileHeapAccessorBase(
74									BErrorOutput* errorOutput,
75									BPositionIO* file, off_t heapOffset,
76									DecompressionAlgorithmOwner*
77										decompressionAlgorithm);
78	virtual						~PackageFileHeapAccessorBase();
79
80			off_t				HeapOffset() const
81									{ return fHeapOffset; }
82			off_t				CompressedHeapSize() const
83									{ return fCompressedHeapSize; }
84			uint64				UncompressedHeapSize() const
85									{ return fUncompressedHeapSize; }
86			size_t				ChunkSize() const
87									{ return kChunkSize; }
88
89			// normally used after cloning a PackageFileHeapReader only
90			void				SetErrorOutput(BErrorOutput* errorOutput)
91									{ fErrorOutput = errorOutput; }
92			void				SetFile(BPositionIO* file)
93									{ fFile = file; }
94
95	// BAbstractBufferedDataReader
96	virtual	status_t			ReadDataToOutput(off_t offset,
97									size_t size, BDataIO* output);
98
99public:
100	static	const size_t		kChunkSize = 64 * 1024;
101#if defined(_KERNEL_MODE)
102	static	void*				sChunkCache;
103#endif
104
105protected:
106	virtual	status_t			ReadAndDecompressChunk(size_t chunkIndex,
107									void* compressedDataBuffer,
108									void* uncompressedDataBuffer) = 0;
109			status_t			ReadAndDecompressChunkData(uint64 offset,
110									size_t compressedSize,
111									size_t uncompressedSize,
112									void* compressedDataBuffer,
113									void* uncompressedDataBuffer);
114			status_t			DecompressChunkData(
115									void* compressedDataBuffer,
116									size_t compressedSize,
117									void* uncompressedDataBuffer,
118									size_t uncompressedSize);
119			status_t			ReadFileData(uint64 offset, void* buffer,
120									size_t size);
121
122protected:
123			BErrorOutput*		fErrorOutput;
124			BPositionIO*		fFile;
125			off_t				fHeapOffset;
126			uint64				fCompressedHeapSize;
127			uint64				fUncompressedHeapSize;
128			DecompressionAlgorithmOwner* fDecompressionAlgorithm;
129};
130
131
132/*!	Stores the chunk offsets in a compact way, while still providing quick
133	access.
134	- The object doesn't store the number of chunks/offsets it contains. During
135	  initialization the chunk count is provided. Later, when getting an offset,
136	  the caller is responsible for ensuring a valid index.
137	- The first (index 0) chunk offset is omitted, since it is always 0.
138	- The chunk offsets that fit in a 32 bit number use only one 32 bit element
139	  in the offsets array.
140	- The chunk offsets that don't fit in a 32 bit number use two elements in
141	  the offsets array.
142	Memory use is one pointer, if the chunk count is <= 1 (uncompressed heap size
143	<= 64 KiB). Afterwards it's one pointer plus 32 bit per chunk as long as the
144	last offset still fits 32 bit (compressed heap size < 4GiB). For any further
145	chunks it is 64 bit per chunk. So, for the common case we use sizeof(void*)
146	plus 1 KiB per 16 MiB of uncompressed heap, or about 64 KiB per 1 GiB. Which
147	seems reasonable for packagefs to keep in memory.
148 */
149class PackageFileHeapAccessorBase::OffsetArray {
150public:
151								OffsetArray();
152								~OffsetArray();
153
154			bool				InitUncompressedChunksOffsets(
155									size_t totalChunkCount);
156			bool				InitChunksOffsets(size_t totalChunkCount,
157									size_t baseIndex, const uint16* chunkSizes,
158									size_t chunkCount);
159
160			bool				Init(size_t totalChunkCount,
161									const OffsetArray& other);
162									// "copy" init
163
164			uint64				operator[](size_t index) const;
165
166private:
167	static	uint32*				_AllocateOffsetArray(size_t totalChunkCount,
168									size_t offset32BitChunkCount);
169
170private:
171			uint32*				fOffsets;
172									// - NULL, if chunkCount <= 1
173									// - element 0 contains the number of 32 bit
174									//   offsets that follow, or is 0, when all
175									//   offsets are 32 bit only
176									// - the following offsets use two elements
177									//   each (lower followed by upper 32 bit)
178									//   to represent the 64 bit value
179};
180
181
182inline uint64
183PackageFileHeapAccessorBase::OffsetArray::operator[](size_t index) const
184{
185	if (index == 0)
186		return 0;
187
188	if (fOffsets[0] == 0 || index < fOffsets[0])
189		return fOffsets[index];
190
191	index += index - fOffsets[0];
192	return fOffsets[index] | ((uint64)fOffsets[index + 1] << 32);
193}
194
195
196}	// namespace BPrivate
197
198}	// namespace BHPKG
199
200}	// namespace BPackageKit
201
202
203#endif	// _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
204