Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #ifndef SeekableZStream_h |
michael@0 | 6 | #define SeekableZStream_h |
michael@0 | 7 | |
michael@0 | 8 | #include "Zip.h" |
michael@0 | 9 | |
michael@0 | 10 | /** |
michael@0 | 11 | * Seekable compressed stream are created by splitting the original |
michael@0 | 12 | * decompressed data in small chunks and compress these chunks |
michael@0 | 13 | * individually. |
michael@0 | 14 | * |
michael@0 | 15 | * The seekable compressed file format consists in a header defined below, |
michael@0 | 16 | * followed by a table of 32-bits words containing the offsets for each |
michael@0 | 17 | * individual compressed chunk, then followed by the compressed chunks. |
michael@0 | 18 | */ |
michael@0 | 19 | |
michael@0 | 20 | #pragma pack(1) |
michael@0 | 21 | struct SeekableZStreamHeader: public Zip::SignedEntity<SeekableZStreamHeader> |
michael@0 | 22 | { |
michael@0 | 23 | SeekableZStreamHeader() |
michael@0 | 24 | : Zip::SignedEntity<SeekableZStreamHeader>(magic) |
michael@0 | 25 | , totalSize(0), chunkSize(0), dictSize(0), nChunks(0), lastChunkSize(0) |
michael@0 | 26 | , windowBits(0), filter(0) { } |
michael@0 | 27 | |
michael@0 | 28 | /* Reuse Zip::SignedEntity to handle the magic number used in the Seekable |
michael@0 | 29 | * ZStream file format. The magic number is "SeZz". */ |
michael@0 | 30 | static const uint32_t magic = 0x7a5a6553; |
michael@0 | 31 | |
michael@0 | 32 | /* Total size of the stream, including the 4 magic bytes. */ |
michael@0 | 33 | le_uint32 totalSize; |
michael@0 | 34 | |
michael@0 | 35 | /* Chunk size */ |
michael@0 | 36 | le_uint16 chunkSize; |
michael@0 | 37 | |
michael@0 | 38 | /* Size of the dictionary */ |
michael@0 | 39 | le_uint16 dictSize; |
michael@0 | 40 | |
michael@0 | 41 | /* Number of chunks */ |
michael@0 | 42 | le_uint32 nChunks; |
michael@0 | 43 | |
michael@0 | 44 | /* Size of last chunk (> 0, <= Chunk size) */ |
michael@0 | 45 | le_uint16 lastChunkSize; |
michael@0 | 46 | |
michael@0 | 47 | /* windowBits value used when deflating */ |
michael@0 | 48 | signed char windowBits; |
michael@0 | 49 | |
michael@0 | 50 | /* Filter Id */ |
michael@0 | 51 | unsigned char filter; |
michael@0 | 52 | }; |
michael@0 | 53 | #pragma pack() |
michael@0 | 54 | |
michael@0 | 55 | static_assert(sizeof(SeekableZStreamHeader) == 5 * 4, |
michael@0 | 56 | "SeekableZStreamHeader should be 5 32-bits words"); |
michael@0 | 57 | |
michael@0 | 58 | /** |
michael@0 | 59 | * Helper class used to decompress Seekable ZStreams. |
michael@0 | 60 | */ |
michael@0 | 61 | class SeekableZStream { |
michael@0 | 62 | public: |
michael@0 | 63 | /* Initialize from the given buffer. Returns whether initialization |
michael@0 | 64 | * succeeded (true) or failed (false). */ |
michael@0 | 65 | bool Init(const void *buf, size_t length); |
michael@0 | 66 | |
michael@0 | 67 | /* Decompresses starting from the given chunk. The decompressed data is |
michael@0 | 68 | * stored at the given location. The given length, in bytes, indicates |
michael@0 | 69 | * how much data to decompress. If length is 0, then exactly one chunk |
michael@0 | 70 | * is decompressed. |
michael@0 | 71 | * Returns whether decompression succeeded (true) or failed (false). */ |
michael@0 | 72 | bool Decompress(void *where, size_t chunk, size_t length = 0); |
michael@0 | 73 | |
michael@0 | 74 | /* Decompresses the given chunk at the given address. If a length is given, |
michael@0 | 75 | * only decompresses that amount of data instead of the entire chunk. |
michael@0 | 76 | * Returns whether decompression succeeded (true) or failed (false). */ |
michael@0 | 77 | bool DecompressChunk(void *where, size_t chunk, size_t length = 0); |
michael@0 | 78 | |
michael@0 | 79 | /* Returns the uncompressed size of the complete zstream */ |
michael@0 | 80 | const size_t GetUncompressedSize() const |
michael@0 | 81 | { |
michael@0 | 82 | return (offsetTable.numElements() - 1) * chunkSize + lastChunkSize; |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | /* Returns the chunk size of the given chunk */ |
michael@0 | 86 | const size_t GetChunkSize(size_t chunk = 0) const { |
michael@0 | 87 | return (chunk == offsetTable.numElements() - 1) ? lastChunkSize : chunkSize; |
michael@0 | 88 | } |
michael@0 | 89 | |
michael@0 | 90 | /* Returns the number of chunks */ |
michael@0 | 91 | const size_t GetChunksNum() const { |
michael@0 | 92 | return offsetTable.numElements(); |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | /** |
michael@0 | 96 | * Filters used to improve compression rate. |
michael@0 | 97 | */ |
michael@0 | 98 | enum FilterDirection { |
michael@0 | 99 | FILTER, |
michael@0 | 100 | UNFILTER |
michael@0 | 101 | }; |
michael@0 | 102 | typedef void (*ZStreamFilter)(off_t, FilterDirection, |
michael@0 | 103 | unsigned char *, size_t); |
michael@0 | 104 | |
michael@0 | 105 | enum FilterId { |
michael@0 | 106 | NONE, |
michael@0 | 107 | BCJ_THUMB, |
michael@0 | 108 | BCJ_ARM, |
michael@0 | 109 | BCJ_X86, |
michael@0 | 110 | FILTER_MAX |
michael@0 | 111 | }; |
michael@0 | 112 | static ZStreamFilter GetFilter(FilterId id); |
michael@0 | 113 | |
michael@0 | 114 | static ZStreamFilter GetFilter(uint16_t id) { |
michael@0 | 115 | return GetFilter(static_cast<FilterId>(id)); |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | private: |
michael@0 | 119 | /* RAW Seekable SZtream buffer */ |
michael@0 | 120 | const unsigned char *buffer; |
michael@0 | 121 | |
michael@0 | 122 | /* Total size of the stream, including the 4 magic bytes. */ |
michael@0 | 123 | uint32_t totalSize; |
michael@0 | 124 | |
michael@0 | 125 | /* Chunk size */ |
michael@0 | 126 | uint32_t chunkSize; |
michael@0 | 127 | |
michael@0 | 128 | /* Size of last chunk (> 0, <= Chunk size) */ |
michael@0 | 129 | uint32_t lastChunkSize; |
michael@0 | 130 | |
michael@0 | 131 | /* windowBits value used when deflating */ |
michael@0 | 132 | int windowBits; |
michael@0 | 133 | |
michael@0 | 134 | /* Offsets table */ |
michael@0 | 135 | Array<le_uint32> offsetTable; |
michael@0 | 136 | |
michael@0 | 137 | /* Filter */ |
michael@0 | 138 | ZStreamFilter filter; |
michael@0 | 139 | |
michael@0 | 140 | /* Deflate dictionary */ |
michael@0 | 141 | Array<unsigned char> dictionary; |
michael@0 | 142 | }; |
michael@0 | 143 | |
michael@0 | 144 | inline void |
michael@0 | 145 | operator++(SeekableZStream::FilterId &other) |
michael@0 | 146 | { |
michael@0 | 147 | const int orig = static_cast<int>(other); |
michael@0 | 148 | other = static_cast<SeekableZStream::FilterId>(orig + 1); |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | #endif /* SeekableZStream_h */ |