|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsZipArchive_h_ |
|
7 #define nsZipArchive_h_ |
|
8 |
|
9 #include "mozilla/Attributes.h" |
|
10 |
|
11 #define ZIP_TABSIZE 256 |
|
12 #define ZIP_BUFLEN (4*1024) /* Used as output buffer when deflating items to a file */ |
|
13 |
|
14 #include "plarena.h" |
|
15 #include "zlib.h" |
|
16 #include "zipstruct.h" |
|
17 #include "nsAutoPtr.h" |
|
18 #include "nsIFile.h" |
|
19 #include "nsISupportsImpl.h" // For mozilla::ThreadSafeAutoRefCnt |
|
20 #include "mozilla/FileUtils.h" |
|
21 #include "mozilla/FileLocation.h" |
|
22 |
|
23 #if defined(XP_WIN) && defined(_MSC_VER) |
|
24 #define MOZ_WIN_MEM_TRY_BEGIN __try { |
|
25 #define MOZ_WIN_MEM_TRY_CATCH(cmd) } \ |
|
26 __except(GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR ? \ |
|
27 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) \ |
|
28 { \ |
|
29 NS_WARNING("EXCEPTION_IN_PAGE_ERROR in " __FUNCTION__); \ |
|
30 cmd; \ |
|
31 } |
|
32 #else |
|
33 #define MOZ_WIN_MEM_TRY_BEGIN { |
|
34 #define MOZ_WIN_MEM_TRY_CATCH(cmd) } |
|
35 #endif |
|
36 |
|
37 class nsZipFind; |
|
38 struct PRFileDesc; |
|
39 |
|
40 /** |
|
41 * This file defines some of the basic structures used by libjar to |
|
42 * read Zip files. It makes use of zlib in order to do the decompression. |
|
43 * |
|
44 * A few notes on the classes/structs: |
|
45 * nsZipArchive represents a single Zip file, and maintains an index |
|
46 * of all the items in the file. |
|
47 * nsZipItem represents a single item (file) in the Zip archive. |
|
48 * nsZipFind represents the metadata involved in doing a search, |
|
49 * and current state of the iteration of found objects. |
|
50 * 'MT''safe' reading from the zipfile is performed through JARInputStream, |
|
51 * which maintains its own file descriptor, allowing for multiple reads |
|
52 * concurrently from the same zip file. |
|
53 */ |
|
54 |
|
55 /** |
|
56 * nsZipItem -- a helper struct for nsZipArchive |
|
57 * |
|
58 * each nsZipItem represents one file in the archive and all the |
|
59 * information needed to manipulate it. |
|
60 */ |
|
61 class nsZipItem |
|
62 { |
|
63 public: |
|
64 const char* Name() { return ((const char*)central) + ZIPCENTRAL_SIZE; } |
|
65 |
|
66 uint32_t LocalOffset(); |
|
67 uint32_t Size(); |
|
68 uint32_t RealSize(); |
|
69 uint32_t CRC32(); |
|
70 uint16_t Date(); |
|
71 uint16_t Time(); |
|
72 uint16_t Compression(); |
|
73 bool IsDirectory(); |
|
74 uint16_t Mode(); |
|
75 const uint8_t* GetExtraField(uint16_t aTag, uint16_t *aBlockSize); |
|
76 PRTime LastModTime(); |
|
77 |
|
78 #ifdef XP_UNIX |
|
79 bool IsSymlink(); |
|
80 #endif |
|
81 |
|
82 nsZipItem* next; |
|
83 const ZipCentral* central; |
|
84 uint16_t nameLength; |
|
85 bool isSynthetic; |
|
86 }; |
|
87 |
|
88 class nsZipHandle; |
|
89 |
|
90 /** |
|
91 * nsZipArchive -- a class for reading the PKZIP file format. |
|
92 * |
|
93 */ |
|
94 class nsZipArchive |
|
95 { |
|
96 friend class nsZipFind; |
|
97 |
|
98 public: |
|
99 /** constructing does not open the archive. See OpenArchive() */ |
|
100 nsZipArchive(); |
|
101 |
|
102 /** destructing the object closes the archive */ |
|
103 ~nsZipArchive(); |
|
104 |
|
105 /** |
|
106 * OpenArchive |
|
107 * |
|
108 * It's an error to call this more than once on the same nsZipArchive |
|
109 * object. If we were allowed to use exceptions this would have been |
|
110 * part of the constructor |
|
111 * |
|
112 * @param aZipHandle The nsZipHandle used to access the zip |
|
113 * @param aFd Optional PRFileDesc for Windows readahead optimization |
|
114 * @return status code |
|
115 */ |
|
116 nsresult OpenArchive(nsZipHandle *aZipHandle, PRFileDesc *aFd = nullptr); |
|
117 |
|
118 /** |
|
119 * OpenArchive |
|
120 * |
|
121 * Convenience function that generates nsZipHandle |
|
122 * |
|
123 * @param aFile The file used to access the zip |
|
124 * @return status code |
|
125 */ |
|
126 nsresult OpenArchive(nsIFile *aFile); |
|
127 |
|
128 /** |
|
129 * Test the integrity of items in this archive by running |
|
130 * a CRC check after extracting each item into a memory |
|
131 * buffer. If an entry name is supplied only the |
|
132 * specified item is tested. Else, if null is supplied |
|
133 * then all the items in the archive are tested. |
|
134 * |
|
135 * @return status code |
|
136 */ |
|
137 nsresult Test(const char *aEntryName); |
|
138 |
|
139 /** |
|
140 * Closes an open archive. |
|
141 */ |
|
142 nsresult CloseArchive(); |
|
143 |
|
144 /** |
|
145 * GetItem |
|
146 * @param aEntryName Name of file in the archive |
|
147 * @return pointer to nsZipItem |
|
148 */ |
|
149 nsZipItem* GetItem(const char * aEntryName); |
|
150 |
|
151 /** |
|
152 * ExtractFile |
|
153 * |
|
154 * @param zipEntry Name of file in archive to extract |
|
155 * @param outFD Filedescriptor to write contents to |
|
156 * @param outname Name of file to write to |
|
157 * @return status code |
|
158 */ |
|
159 nsresult ExtractFile(nsZipItem * zipEntry, const char *outname, PRFileDesc * outFD); |
|
160 |
|
161 /** |
|
162 * FindInit |
|
163 * |
|
164 * Initializes a search for files in the archive. FindNext() returns |
|
165 * the actual matches. The nsZipFind must be deleted when you're done |
|
166 * |
|
167 * @param aPattern a string or RegExp pattern to search for |
|
168 * (may be nullptr to find all files in archive) |
|
169 * @param aFind a pointer to a pointer to a structure used |
|
170 * in FindNext. In the case of an error this |
|
171 * will be set to nullptr. |
|
172 * @return status code |
|
173 */ |
|
174 nsresult FindInit(const char * aPattern, nsZipFind** aFind); |
|
175 |
|
176 /* |
|
177 * Gets an undependent handle to the mapped file. |
|
178 */ |
|
179 nsZipHandle* GetFD(); |
|
180 |
|
181 /** |
|
182 * Get pointer to the data of the item. |
|
183 * @param aItem Pointer to nsZipItem |
|
184 * reutrns null when zip file is corrupt. |
|
185 */ |
|
186 const uint8_t* GetData(nsZipItem* aItem); |
|
187 |
|
188 bool GetComment(nsACString &aComment); |
|
189 |
|
190 /** |
|
191 * Gets the amount of memory taken up by the archive's mapping. |
|
192 * @return the size |
|
193 */ |
|
194 int64_t SizeOfMapping(); |
|
195 |
|
196 /* |
|
197 * Refcounting |
|
198 */ |
|
199 NS_METHOD_(MozExternalRefCountType) AddRef(void); |
|
200 NS_METHOD_(MozExternalRefCountType) Release(void); |
|
201 |
|
202 private: |
|
203 //--- private members --- |
|
204 mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */ |
|
205 NS_DECL_OWNINGTHREAD |
|
206 |
|
207 nsZipItem* mFiles[ZIP_TABSIZE]; |
|
208 PLArenaPool mArena; |
|
209 |
|
210 const char* mCommentPtr; |
|
211 uint16_t mCommentLen; |
|
212 |
|
213 // Whether we synthesized the directory entries |
|
214 bool mBuiltSynthetics; |
|
215 |
|
216 // file handle |
|
217 nsRefPtr<nsZipHandle> mFd; |
|
218 |
|
219 // file URI, for logging |
|
220 nsCString mURI; |
|
221 |
|
222 private: |
|
223 //--- private methods --- |
|
224 nsZipItem* CreateZipItem(); |
|
225 nsresult BuildFileList(PRFileDesc *aFd = nullptr); |
|
226 nsresult BuildSynthetics(); |
|
227 |
|
228 nsZipArchive& operator=(const nsZipArchive& rhs) MOZ_DELETE; |
|
229 nsZipArchive(const nsZipArchive& rhs) MOZ_DELETE; |
|
230 }; |
|
231 |
|
232 /** |
|
233 * nsZipFind |
|
234 * |
|
235 * a helper class for nsZipArchive, representing a search |
|
236 */ |
|
237 class nsZipFind |
|
238 { |
|
239 public: |
|
240 nsZipFind(nsZipArchive* aZip, char* aPattern, bool regExp); |
|
241 ~nsZipFind(); |
|
242 |
|
243 nsresult FindNext(const char** aResult, uint16_t* aNameLen); |
|
244 |
|
245 private: |
|
246 nsRefPtr<nsZipArchive> mArchive; |
|
247 char* mPattern; |
|
248 nsZipItem* mItem; |
|
249 uint16_t mSlot; |
|
250 bool mRegExp; |
|
251 |
|
252 nsZipFind& operator=(const nsZipFind& rhs) MOZ_DELETE; |
|
253 nsZipFind(const nsZipFind& rhs) MOZ_DELETE; |
|
254 }; |
|
255 |
|
256 /** |
|
257 * nsZipCursor -- a low-level class for reading the individual items in a zip. |
|
258 */ |
|
259 class nsZipCursor { |
|
260 public: |
|
261 /** |
|
262 * Initializes the cursor |
|
263 * |
|
264 * @param aItem Item of interest |
|
265 * @param aZip Archive |
|
266 * @param aBuf Buffer used for decompression. |
|
267 * This determines the maximum Read() size in the compressed case. |
|
268 * @param aBufSize Buffer size |
|
269 * @param doCRC When set to true Read() will check crc |
|
270 */ |
|
271 nsZipCursor(nsZipItem *aItem, nsZipArchive *aZip, uint8_t* aBuf = nullptr, uint32_t aBufSize = 0, bool doCRC = false); |
|
272 |
|
273 ~nsZipCursor(); |
|
274 |
|
275 /** |
|
276 * Performs reads. In the compressed case it uses aBuf(passed in constructor), for stored files |
|
277 * it returns a zero-copy buffer. |
|
278 * |
|
279 * @param aBytesRead Outparam for number of bytes read. |
|
280 * @return data read or nullptr if item is corrupted. |
|
281 */ |
|
282 uint8_t* Read(uint32_t *aBytesRead) { |
|
283 return ReadOrCopy(aBytesRead, false); |
|
284 } |
|
285 |
|
286 /** |
|
287 * Performs a copy. It always uses aBuf(passed in constructor). |
|
288 * |
|
289 * @param aBytesRead Outparam for number of bytes read. |
|
290 * @return data read or nullptr if item is corrupted. |
|
291 */ |
|
292 uint8_t* Copy(uint32_t *aBytesRead) { |
|
293 return ReadOrCopy(aBytesRead, true); |
|
294 } |
|
295 |
|
296 private: |
|
297 /* Actual implementation for both Read and Copy above */ |
|
298 uint8_t* ReadOrCopy(uint32_t *aBytesRead, bool aCopy); |
|
299 |
|
300 nsZipItem *mItem; |
|
301 uint8_t *mBuf; |
|
302 uint32_t mBufSize; |
|
303 z_stream mZs; |
|
304 uint32_t mCRC; |
|
305 bool mDoCRC; |
|
306 }; |
|
307 |
|
308 /** |
|
309 * nsZipItemPtr - a RAII convenience class for reading the individual items in a zip. |
|
310 * It reads whole files and does zero-copy IO for stored files. A buffer is allocated |
|
311 * for decompression. |
|
312 * Do not use when the file may be very large. |
|
313 */ |
|
314 class nsZipItemPtr_base { |
|
315 public: |
|
316 /** |
|
317 * Initializes the reader |
|
318 * |
|
319 * @param aZip Archive |
|
320 * @param aEntryName Archive membername |
|
321 * @param doCRC When set to true Read() will check crc |
|
322 */ |
|
323 nsZipItemPtr_base(nsZipArchive *aZip, const char *aEntryName, bool doCRC); |
|
324 |
|
325 uint32_t Length() const { |
|
326 return mReadlen; |
|
327 } |
|
328 |
|
329 protected: |
|
330 nsRefPtr<nsZipHandle> mZipHandle; |
|
331 nsAutoArrayPtr<uint8_t> mAutoBuf; |
|
332 uint8_t *mReturnBuf; |
|
333 uint32_t mReadlen; |
|
334 }; |
|
335 |
|
336 template <class T> |
|
337 class nsZipItemPtr : public nsZipItemPtr_base { |
|
338 public: |
|
339 nsZipItemPtr(nsZipArchive *aZip, const char *aEntryName, bool doCRC = false) : nsZipItemPtr_base(aZip, aEntryName, doCRC) { } |
|
340 /** |
|
341 * @return buffer containing the whole zip member or nullptr on error. |
|
342 * The returned buffer is owned by nsZipItemReader. |
|
343 */ |
|
344 const T* Buffer() const { |
|
345 return (const T*)mReturnBuf; |
|
346 } |
|
347 |
|
348 operator const T*() const { |
|
349 return Buffer(); |
|
350 } |
|
351 |
|
352 /** |
|
353 * Relinquish ownership of zip member if compressed. |
|
354 * Copy member into a new buffer if uncompressed. |
|
355 * @return a buffer with whole zip member. It is caller's responsibility to free() it. |
|
356 */ |
|
357 T* Forget() { |
|
358 if (!mReturnBuf) |
|
359 return nullptr; |
|
360 // In uncompressed mmap case, give up buffer |
|
361 if (mAutoBuf.get() == mReturnBuf) { |
|
362 mReturnBuf = nullptr; |
|
363 return (T*) mAutoBuf.forget(); |
|
364 } |
|
365 T *ret = (T*) malloc(Length()); |
|
366 memcpy(ret, mReturnBuf, Length()); |
|
367 mReturnBuf = nullptr; |
|
368 return ret; |
|
369 } |
|
370 }; |
|
371 |
|
372 class nsZipHandle { |
|
373 friend class nsZipArchive; |
|
374 friend class mozilla::FileLocation; |
|
375 public: |
|
376 static nsresult Init(nsIFile *file, nsZipHandle **ret, |
|
377 PRFileDesc **aFd = nullptr); |
|
378 static nsresult Init(nsZipArchive *zip, const char *entry, |
|
379 nsZipHandle **ret); |
|
380 |
|
381 NS_METHOD_(MozExternalRefCountType) AddRef(void); |
|
382 NS_METHOD_(MozExternalRefCountType) Release(void); |
|
383 |
|
384 int64_t SizeOfMapping(); |
|
385 |
|
386 protected: |
|
387 const uint8_t * mFileData; /* pointer to mmaped file */ |
|
388 uint32_t mLen; /* length of file and memory mapped area */ |
|
389 mozilla::FileLocation mFile; /* source file if any, for logging */ |
|
390 |
|
391 private: |
|
392 nsZipHandle(); |
|
393 ~nsZipHandle(); |
|
394 |
|
395 PRFileMap * mMap; /* nspr datastructure for mmap */ |
|
396 nsAutoPtr<nsZipItemPtr<uint8_t> > mBuf; |
|
397 mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */ |
|
398 NS_DECL_OWNINGTHREAD |
|
399 }; |
|
400 |
|
401 nsresult gZlibInit(z_stream *zs); |
|
402 |
|
403 #endif /* nsZipArchive_h_ */ |