michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef SeekableZStream_h michael@0: #define SeekableZStream_h michael@0: michael@0: #include "Zip.h" michael@0: michael@0: /** michael@0: * Seekable compressed stream are created by splitting the original michael@0: * decompressed data in small chunks and compress these chunks michael@0: * individually. michael@0: * michael@0: * The seekable compressed file format consists in a header defined below, michael@0: * followed by a table of 32-bits words containing the offsets for each michael@0: * individual compressed chunk, then followed by the compressed chunks. michael@0: */ michael@0: michael@0: #pragma pack(1) michael@0: struct SeekableZStreamHeader: public Zip::SignedEntity michael@0: { michael@0: SeekableZStreamHeader() michael@0: : Zip::SignedEntity(magic) michael@0: , totalSize(0), chunkSize(0), dictSize(0), nChunks(0), lastChunkSize(0) michael@0: , windowBits(0), filter(0) { } michael@0: michael@0: /* Reuse Zip::SignedEntity to handle the magic number used in the Seekable michael@0: * ZStream file format. The magic number is "SeZz". */ michael@0: static const uint32_t magic = 0x7a5a6553; michael@0: michael@0: /* Total size of the stream, including the 4 magic bytes. */ michael@0: le_uint32 totalSize; michael@0: michael@0: /* Chunk size */ michael@0: le_uint16 chunkSize; michael@0: michael@0: /* Size of the dictionary */ michael@0: le_uint16 dictSize; michael@0: michael@0: /* Number of chunks */ michael@0: le_uint32 nChunks; michael@0: michael@0: /* Size of last chunk (> 0, <= Chunk size) */ michael@0: le_uint16 lastChunkSize; michael@0: michael@0: /* windowBits value used when deflating */ michael@0: signed char windowBits; michael@0: michael@0: /* Filter Id */ michael@0: unsigned char filter; michael@0: }; michael@0: #pragma pack() michael@0: michael@0: static_assert(sizeof(SeekableZStreamHeader) == 5 * 4, michael@0: "SeekableZStreamHeader should be 5 32-bits words"); michael@0: michael@0: /** michael@0: * Helper class used to decompress Seekable ZStreams. michael@0: */ michael@0: class SeekableZStream { michael@0: public: michael@0: /* Initialize from the given buffer. Returns whether initialization michael@0: * succeeded (true) or failed (false). */ michael@0: bool Init(const void *buf, size_t length); michael@0: michael@0: /* Decompresses starting from the given chunk. The decompressed data is michael@0: * stored at the given location. The given length, in bytes, indicates michael@0: * how much data to decompress. If length is 0, then exactly one chunk michael@0: * is decompressed. michael@0: * Returns whether decompression succeeded (true) or failed (false). */ michael@0: bool Decompress(void *where, size_t chunk, size_t length = 0); michael@0: michael@0: /* Decompresses the given chunk at the given address. If a length is given, michael@0: * only decompresses that amount of data instead of the entire chunk. michael@0: * Returns whether decompression succeeded (true) or failed (false). */ michael@0: bool DecompressChunk(void *where, size_t chunk, size_t length = 0); michael@0: michael@0: /* Returns the uncompressed size of the complete zstream */ michael@0: const size_t GetUncompressedSize() const michael@0: { michael@0: return (offsetTable.numElements() - 1) * chunkSize + lastChunkSize; michael@0: } michael@0: michael@0: /* Returns the chunk size of the given chunk */ michael@0: const size_t GetChunkSize(size_t chunk = 0) const { michael@0: return (chunk == offsetTable.numElements() - 1) ? lastChunkSize : chunkSize; michael@0: } michael@0: michael@0: /* Returns the number of chunks */ michael@0: const size_t GetChunksNum() const { michael@0: return offsetTable.numElements(); michael@0: } michael@0: michael@0: /** michael@0: * Filters used to improve compression rate. michael@0: */ michael@0: enum FilterDirection { michael@0: FILTER, michael@0: UNFILTER michael@0: }; michael@0: typedef void (*ZStreamFilter)(off_t, FilterDirection, michael@0: unsigned char *, size_t); michael@0: michael@0: enum FilterId { michael@0: NONE, michael@0: BCJ_THUMB, michael@0: BCJ_ARM, michael@0: BCJ_X86, michael@0: FILTER_MAX michael@0: }; michael@0: static ZStreamFilter GetFilter(FilterId id); michael@0: michael@0: static ZStreamFilter GetFilter(uint16_t id) { michael@0: return GetFilter(static_cast(id)); michael@0: } michael@0: michael@0: private: michael@0: /* RAW Seekable SZtream buffer */ michael@0: const unsigned char *buffer; michael@0: michael@0: /* Total size of the stream, including the 4 magic bytes. */ michael@0: uint32_t totalSize; michael@0: michael@0: /* Chunk size */ michael@0: uint32_t chunkSize; michael@0: michael@0: /* Size of last chunk (> 0, <= Chunk size) */ michael@0: uint32_t lastChunkSize; michael@0: michael@0: /* windowBits value used when deflating */ michael@0: int windowBits; michael@0: michael@0: /* Offsets table */ michael@0: Array offsetTable; michael@0: michael@0: /* Filter */ michael@0: ZStreamFilter filter; michael@0: michael@0: /* Deflate dictionary */ michael@0: Array dictionary; michael@0: }; michael@0: michael@0: inline void michael@0: operator++(SeekableZStream::FilterId &other) michael@0: { michael@0: const int orig = static_cast(other); michael@0: other = static_cast(orig + 1); michael@0: } michael@0: michael@0: #endif /* SeekableZStream_h */