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