mozglue/linker/Zip.h

branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
equal deleted inserted replaced
-1:000000000000 0:1380aa59c9e4
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 Zip_h
6 #define Zip_h
7
8 #include <cstring>
9 #include <stdint.h>
10 #include <vector>
11 #include <zlib.h>
12 #include "Utils.h"
13 #include "mozilla/RefPtr.h"
14
15 /**
16 * Forward declaration
17 */
18 class ZipCollection;
19
20 /**
21 * Class to handle access to Zip archive streams. The Zip archive is mapped
22 * in memory, and streams are direct references to that mapped memory.
23 * Zip files are assumed to be correctly formed. No boundary checks are
24 * performed, which means hand-crafted malicious Zip archives can make the
25 * code fail in bad ways. However, since the only intended use is to load
26 * libraries from Zip archives, there is no interest in making this code
27 * safe, since the libraries could contain malicious code anyways.
28 */
29 class Zip: public mozilla::AtomicRefCounted<Zip>
30 {
31 public:
32 MOZ_DECLARE_REFCOUNTED_TYPENAME(Zip)
33 /**
34 * Create a Zip instance for the given file name. Returns nullptr in case
35 * of failure.
36 */
37 static mozilla::TemporaryRef<Zip> Create(const char *filename);
38
39 /**
40 * Create a Zip instance using the given buffer.
41 */
42 static mozilla::TemporaryRef<Zip> Create(void *buffer, size_t size) {
43 return Create(nullptr, buffer, size);
44 }
45
46 private:
47 static mozilla::TemporaryRef<Zip> Create(const char *filename,
48 void *buffer, size_t size);
49
50 /**
51 * Private constructor
52 */
53 Zip(const char *filename, void *buffer, size_t size);
54
55 public:
56 /**
57 * Destructor
58 */
59 ~Zip();
60
61 /**
62 * Class used to access Zip archive item streams
63 */
64 class Stream
65 {
66 public:
67 /**
68 * Stream types
69 */
70 enum Type {
71 STORE = 0,
72 DEFLATE = 8
73 };
74
75 /**
76 * Constructor
77 */
78 Stream(): compressedBuf(nullptr), compressedSize(0), uncompressedSize(0)
79 , type(STORE) { }
80
81 /**
82 * Getters
83 */
84 const void *GetBuffer() { return compressedBuf; }
85 size_t GetSize() { return compressedSize; }
86 size_t GetUncompressedSize() { return uncompressedSize; }
87 Type GetType() { return type; }
88
89 /**
90 * Returns a z_stream for use with inflate functions using the given
91 * buffer as inflate output. The caller is expected to allocate enough
92 * memory for the Stream uncompressed size.
93 */
94 z_stream GetZStream(void *buf)
95 {
96 z_stream zStream;
97 memset(&zStream, 0, sizeof(zStream));
98 zStream.avail_in = compressedSize;
99 zStream.next_in = reinterpret_cast<Bytef *>(
100 const_cast<void *>(compressedBuf));
101 zStream.avail_out = uncompressedSize;
102 zStream.next_out = static_cast<Bytef *>(buf);
103 return zStream;
104 }
105
106 protected:
107 friend class Zip;
108 const void *compressedBuf;
109 size_t compressedSize;
110 size_t uncompressedSize;
111 Type type;
112 };
113
114 /**
115 * Returns a stream from the Zip archive.
116 */
117 bool GetStream(const char *path, Stream *out) const;
118
119 /**
120 * Returns the file name of the archive
121 */
122 const char *GetName() const
123 {
124 return name;
125 }
126
127 private:
128 /* File name of the archive */
129 char *name;
130 /* Address where the Zip archive is mapped */
131 void *mapped;
132 /* Size of the archive */
133 size_t size;
134
135 /**
136 * Strings (file names, comments, etc.) in the Zip headers are NOT zero
137 * terminated. This class is a helper around them.
138 */
139 class StringBuf
140 {
141 public:
142 /**
143 * Constructor
144 */
145 StringBuf(const char *buf, size_t length): buf(buf), length(length) { }
146
147 /**
148 * Returns whether the string has the same content as the given zero
149 * terminated string.
150 */
151 bool Equals(const char *str) const
152 {
153 return strncmp(str, buf, length) == 0;
154 }
155
156 private:
157 const char *buf;
158 size_t length;
159 };
160
161 /* All the following types need to be packed */
162 #pragma pack(1)
163 public:
164 /**
165 * A Zip archive is an aggregate of entities which all start with a
166 * signature giving their type. This template is to be used as a base
167 * class for these entities.
168 */
169 template <typename T>
170 class SignedEntity
171 {
172 public:
173 /**
174 * Equivalent to reinterpret_cast<const T *>(buf), with an additional
175 * check of the signature.
176 */
177 static const T *validate(const void *buf)
178 {
179 const T *ret = static_cast<const T *>(buf);
180 if (ret->signature == T::magic)
181 return ret;
182 return nullptr;
183 }
184
185 SignedEntity(uint32_t magic): signature(magic) { }
186 private:
187 le_uint32 signature;
188 };
189
190 private:
191 /**
192 * Header used to describe a Local File entry. The header is followed by
193 * the file name and an extra field, then by the data stream.
194 */
195 struct LocalFile: public SignedEntity<LocalFile>
196 {
197 /* Signature for a Local File header */
198 static const uint32_t magic = 0x04034b50;
199
200 /**
201 * Returns the file name
202 */
203 StringBuf GetName() const
204 {
205 return StringBuf(reinterpret_cast<const char *>(this) + sizeof(*this),
206 filenameSize);
207 }
208
209 /**
210 * Returns a pointer to the data associated with this header
211 */
212 const void *GetData() const
213 {
214 return reinterpret_cast<const char *>(this) + sizeof(*this)
215 + filenameSize + extraFieldSize;
216 }
217
218 le_uint16 minVersion;
219 le_uint16 generalFlag;
220 le_uint16 compression;
221 le_uint16 lastModifiedTime;
222 le_uint16 lastModifiedDate;
223 le_uint32 CRC32;
224 le_uint32 compressedSize;
225 le_uint32 uncompressedSize;
226 le_uint16 filenameSize;
227 le_uint16 extraFieldSize;
228 };
229
230 /**
231 * In some cases, when a zip archive is created, compressed size and CRC
232 * are not known when writing the Local File header. In these cases, the
233 * 3rd bit of the general flag in the Local File header is set, and there
234 * is an additional header following the compressed data.
235 */
236 struct DataDescriptor: public SignedEntity<DataDescriptor>
237 {
238 /* Signature for a Data Descriptor header */
239 static const uint32_t magic = 0x08074b50;
240
241 le_uint32 CRC32;
242 le_uint32 compressedSize;
243 le_uint32 uncompressedSize;
244 };
245
246 /**
247 * Header used to describe a Central Directory Entry. The header is
248 * followed by the file name, an extra field, and a comment.
249 */
250 struct DirectoryEntry: public SignedEntity<DirectoryEntry>
251 {
252 /* Signature for a Central Directory Entry header */
253 static const uint32_t magic = 0x02014b50;
254
255 /**
256 * Returns the file name
257 */
258 StringBuf GetName() const
259 {
260 return StringBuf(reinterpret_cast<const char *>(this) + sizeof(*this),
261 filenameSize);
262 }
263
264 /**
265 * Returns the Central Directory Entry following this one.
266 */
267 const DirectoryEntry *GetNext() const
268 {
269 return validate(reinterpret_cast<const char *>(this) + sizeof(*this)
270 + filenameSize + extraFieldSize + fileCommentSize);
271 }
272
273 le_uint16 creatorVersion;
274 le_uint16 minVersion;
275 le_uint16 generalFlag;
276 le_uint16 compression;
277 le_uint16 lastModifiedTime;
278 le_uint16 lastModifiedDate;
279 le_uint32 CRC32;
280 le_uint32 compressedSize;
281 le_uint32 uncompressedSize;
282 le_uint16 filenameSize;
283 le_uint16 extraFieldSize;
284 le_uint16 fileCommentSize;
285 le_uint16 diskNum;
286 le_uint16 internalAttributes;
287 le_uint32 externalAttributes;
288 le_uint32 offset;
289 };
290
291 /**
292 * Header used to describe the End of Central Directory Record.
293 */
294 struct CentralDirectoryEnd: public SignedEntity<CentralDirectoryEnd>
295 {
296 /* Signature for the End of Central Directory Record */
297 static const uint32_t magic = 0x06054b50;
298
299 le_uint16 diskNum;
300 le_uint16 startDisk;
301 le_uint16 recordsOnDisk;
302 le_uint16 records;
303 le_uint32 size;
304 le_uint32 offset;
305 le_uint16 commentSize;
306 };
307 #pragma pack()
308
309 /**
310 * Returns the first Directory entry
311 */
312 const DirectoryEntry *GetFirstEntry() const;
313
314 /* Pointer to the Local File Entry following the last one GetStream() used.
315 * This is used by GetStream to avoid scanning the Directory Entries when the
316 * requested entry is that one. */
317 mutable const LocalFile *nextFile;
318
319 /* Likewise for the next Directory entry */
320 mutable const DirectoryEntry *nextDir;
321
322 /* Pointer to the Directory entries */
323 mutable const DirectoryEntry *entries;
324 };
325
326 /**
327 * Class for bookkeeping Zip instances
328 */
329 class ZipCollection
330 {
331 public:
332 static ZipCollection Singleton;
333
334 /**
335 * Get a Zip instance for the given path. If there is an existing one
336 * already, return that one, otherwise create a new one.
337 */
338 static mozilla::TemporaryRef<Zip> GetZip(const char *path);
339
340 protected:
341 friend class Zip;
342 /**
343 * Register the given Zip instance. This method is meant to be called
344 * by Zip::Create.
345 */
346 static void Register(Zip *zip);
347
348 /**
349 * Forget about the given Zip instance. This method is meant to be called
350 * by the Zip destructor.
351 */
352 static void Forget(Zip *zip);
353
354 private:
355 /* Zip instances bookkept in this collection */
356 std::vector<Zip *> zips;
357 };
358
359 #endif /* Zip_h */

mercurial