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