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 17 namespace BPackageKit { 18 19 namespace BHPKG { 20 21 22 class BErrorOutput; 23 24 25 namespace BPrivate { 26 27 28 template<typename Parameters> 29 struct 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 62 typedef GenericCompressionAlgorithmOwner<BCompressionParameters> 63 CompressionAlgorithmOwner; 64 typedef GenericCompressionAlgorithmOwner<BDecompressionParameters> 65 DecompressionAlgorithmOwner; 66 67 68 class PackageFileHeapAccessorBase : public BAbstractBufferedDataReader { 69 public: 70 class OffsetArray; 71 72 public: 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 99 public: 100 static const size_t kChunkSize = 64 * 1024; 101 #if defined(_KERNEL_MODE) 102 static void* sChunkCache; 103 #endif 104 105 protected: 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 122 protected: 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 */ 149 class PackageFileHeapAccessorBase::OffsetArray { 150 public: 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 166 private: 167 static uint32* _AllocateOffsetArray(size_t totalChunkCount, 168 size_t offset32BitChunkCount); 169 170 private: 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 182 inline uint64 183 PackageFileHeapAccessorBase::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