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 102 protected: 103 virtual status_t ReadAndDecompressChunk(size_t chunkIndex, 104 void* compressedDataBuffer, 105 void* uncompressedDataBuffer) = 0; 106 status_t ReadAndDecompressChunkData(uint64 offset, 107 size_t compressedSize, 108 size_t uncompressedSize, 109 void* compressedDataBuffer, 110 void* uncompressedDataBuffer); 111 status_t DecompressChunkData( 112 void* compressedDataBuffer, 113 size_t compressedSize, 114 void* uncompressedDataBuffer, 115 size_t uncompressedSize); 116 status_t ReadFileData(uint64 offset, void* buffer, 117 size_t size); 118 119 protected: 120 BErrorOutput* fErrorOutput; 121 BPositionIO* fFile; 122 off_t fHeapOffset; 123 uint64 fCompressedHeapSize; 124 uint64 fUncompressedHeapSize; 125 DecompressionAlgorithmOwner* fDecompressionAlgorithm; 126 }; 127 128 129 /*! Stores the chunk offsets in a compact way, while still providing quick 130 access. 131 - The object doesn't store the number of chunks/offsets it contains. During 132 initialization the chunk count is provided. Later, when getting an offset, 133 the caller is responsible for ensuring a valid index. 134 - The first (index 0) chunk offset is omitted, since it is always 0. 135 - The chunk offsets that fit in a 32 bit number use only one 32 bit element 136 in the offsets array. 137 - The chunk offsets that don't fit in a 32 bit number use two elements in 138 the offsets array. 139 Memory use is one pointer, if the chunk count is <= 1 (uncompressed heap size 140 <= 64 KiB). Afterwards it's one pointer plus 32 bit per chunk as long as the 141 last offset still fits 32 bit (compressed heap size < 4GiB). For any further 142 chunks it is 64 bit per chunk. So, for the common case we use sizeof(void*) 143 plus 1 KiB per 16 MiB of uncompressed heap, or about 64 KiB per 1 GiB. Which 144 seems reasonable for packagefs to keep in memory. 145 */ 146 class PackageFileHeapAccessorBase::OffsetArray { 147 public: 148 OffsetArray(); 149 ~OffsetArray(); 150 151 bool InitUncompressedChunksOffsets( 152 size_t totalChunkCount); 153 bool InitChunksOffsets(size_t totalChunkCount, 154 size_t baseIndex, const uint16* chunkSizes, 155 size_t chunkCount); 156 157 bool Init(size_t totalChunkCount, 158 const OffsetArray& other); 159 // "copy" init 160 161 uint64 operator[](size_t index) const; 162 163 private: 164 static uint32* _AllocateOffsetArray(size_t totalChunkCount, 165 size_t offset32BitChunkCount); 166 167 private: 168 uint32* fOffsets; 169 // - NULL, if chunkCount <= 1 170 // - element 0 contains the number of 32 bit 171 // offsets that follow, or is 0, when all 172 // offsets are 32 bit only 173 // - the following offsets use two elements 174 // each (lower followed by upper 32 bit) 175 // to represent the 64 bit value 176 }; 177 178 179 inline uint64 180 PackageFileHeapAccessorBase::OffsetArray::operator[](size_t index) const 181 { 182 if (index == 0) 183 return 0; 184 185 if (fOffsets[0] == 0 || index < fOffsets[0]) 186 return fOffsets[index]; 187 188 index += index - fOffsets[0]; 189 return fOffsets[index] | ((uint64)fOffsets[index + 1] << 32); 190 } 191 192 193 } // namespace BPrivate 194 195 } // namespace BHPKG 196 197 } // namespace BPackageKit 198 199 200 #endif // _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_ 201