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