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