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/. */
6 #ifndef nsZipArchive_h_
7 #define nsZipArchive_h_
9 #include "mozilla/Attributes.h"
11 #define ZIP_TABSIZE 256
12 #define ZIP_BUFLEN (4*1024) /* Used as output buffer when deflating items to a file */
14 #ifndef PL_ARENA_CONST_ALIGN_MASK
15 #define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
20 #include "zipstruct.h"
21 #include "nsAutoPtr.h"
23 #include "nsISupportsImpl.h" // For mozilla::ThreadSafeAutoRefCnt
24 #include "mozilla/FileUtils.h"
25 #include "mozilla/FileLocation.h"
27 #if defined(XP_WIN) && defined(_MSC_VER)
28 #define MOZ_WIN_MEM_TRY_BEGIN __try {
29 #define MOZ_WIN_MEM_TRY_CATCH(cmd) } \
30 __except(GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR ? \
31 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) \
33 NS_WARNING("EXCEPTION_IN_PAGE_ERROR in " __FUNCTION__); \
37 #define MOZ_WIN_MEM_TRY_BEGIN {
38 #define MOZ_WIN_MEM_TRY_CATCH(cmd) }
45 * This file defines some of the basic structures used by libjar to
46 * read Zip files. It makes use of zlib in order to do the decompression.
48 * A few notes on the classes/structs:
49 * nsZipArchive represents a single Zip file, and maintains an index
50 * of all the items in the file.
51 * nsZipItem represents a single item (file) in the Zip archive.
52 * nsZipFind represents the metadata involved in doing a search,
53 * and current state of the iteration of found objects.
54 * 'MT''safe' reading from the zipfile is performed through JARInputStream,
55 * which maintains its own file descriptor, allowing for multiple reads
56 * concurrently from the same zip file.
60 * nsZipItem -- a helper struct for nsZipArchive
62 * each nsZipItem represents one file in the archive and all the
63 * information needed to manipulate it.
68 const char* Name() { return ((const char*)central
) + ZIPCENTRAL_SIZE
; }
70 uint32_t LocalOffset();
76 uint16_t Compression();
79 const uint8_t* GetExtraField(uint16_t aTag
, uint16_t *aBlockSize
);
87 const ZipCentral
* central
;
95 * nsZipArchive -- a class for reading the PKZIP file format.
100 friend class nsZipFind
;
103 /** constructing does not open the archive. See OpenArchive() */
106 /** destructing the object closes the archive */
112 * It's an error to call this more than once on the same nsZipArchive
113 * object. If we were allowed to use exceptions this would have been
114 * part of the constructor
116 * @param aZipHandle The nsZipHandle used to access the zip
117 * @param aFd Optional PRFileDesc for Windows readahead optimization
118 * @return status code
120 nsresult
OpenArchive(nsZipHandle
*aZipHandle
, PRFileDesc
*aFd
= nullptr);
125 * Convenience function that generates nsZipHandle
127 * @param aFile The file used to access the zip
128 * @return status code
130 nsresult
OpenArchive(nsIFile
*aFile
);
133 * Test the integrity of items in this archive by running
134 * a CRC check after extracting each item into a memory
135 * buffer. If an entry name is supplied only the
136 * specified item is tested. Else, if null is supplied
137 * then all the items in the archive are tested.
139 * @return status code
141 nsresult
Test(const char *aEntryName
);
144 * Closes an open archive.
146 nsresult
CloseArchive();
150 * @param aEntryName Name of file in the archive
151 * @return pointer to nsZipItem
153 nsZipItem
* GetItem(const char * aEntryName
);
158 * @param zipEntry Name of file in archive to extract
159 * @param outFD Filedescriptor to write contents to
160 * @param outname Name of file to write to
161 * @return status code
163 nsresult
ExtractFile(nsZipItem
* zipEntry
, const char *outname
, PRFileDesc
* outFD
);
168 * Initializes a search for files in the archive. FindNext() returns
169 * the actual matches. The nsZipFind must be deleted when you're done
171 * @param aPattern a string or RegExp pattern to search for
172 * (may be nullptr to find all files in archive)
173 * @param aFind a pointer to a pointer to a structure used
174 * in FindNext. In the case of an error this
175 * will be set to nullptr.
176 * @return status code
178 nsresult
FindInit(const char * aPattern
, nsZipFind
** aFind
);
181 * Gets an undependent handle to the mapped file.
183 nsZipHandle
* GetFD();
186 * Get pointer to the data of the item.
187 * @param aItem Pointer to nsZipItem
188 * reutrns null when zip file is corrupt.
190 const uint8_t* GetData(nsZipItem
* aItem
);
192 bool GetComment(nsACString
&aComment
);
195 * Gets the amount of memory taken up by the archive's mapping.
198 int64_t SizeOfMapping();
203 NS_METHOD_(nsrefcnt
) AddRef(void);
204 NS_METHOD_(nsrefcnt
) Release(void);
207 //--- private members ---
208 mozilla::ThreadSafeAutoRefCnt mRefCnt
; /* ref count */
211 nsZipItem
* mFiles
[ZIP_TABSIZE
];
214 const char* mCommentPtr
;
215 uint16_t mCommentLen
;
217 // Whether we synthesized the directory entries
218 bool mBuiltSynthetics
;
221 nsRefPtr
<nsZipHandle
> mFd
;
223 // file URI, for logging
227 //--- private methods ---
228 nsZipItem
* CreateZipItem();
229 nsresult
BuildFileList(PRFileDesc
*aFd
= nullptr);
230 nsresult
BuildSynthetics();
232 nsZipArchive
& operator=(const nsZipArchive
& rhs
) MOZ_DELETE
;
233 nsZipArchive(const nsZipArchive
& rhs
) MOZ_DELETE
;
239 * a helper class for nsZipArchive, representing a search
244 nsZipFind(nsZipArchive
* aZip
, char* aPattern
, bool regExp
);
247 nsresult
FindNext(const char** aResult
, uint16_t* aNameLen
);
250 nsRefPtr
<nsZipArchive
> mArchive
;
256 nsZipFind
& operator=(const nsZipFind
& rhs
) MOZ_DELETE
;
257 nsZipFind(const nsZipFind
& rhs
) MOZ_DELETE
;
261 * nsZipCursor -- a low-level class for reading the individual items in a zip.
266 * Initializes the cursor
268 * @param aItem Item of interest
269 * @param aZip Archive
270 * @param aBuf Buffer used for decompression.
271 * This determines the maximum Read() size in the compressed case.
272 * @param aBufSize Buffer size
273 * @param doCRC When set to true Read() will check crc
275 nsZipCursor(nsZipItem
*aItem
, nsZipArchive
*aZip
, uint8_t* aBuf
= nullptr, uint32_t aBufSize
= 0, bool doCRC
= false);
280 * Performs reads. In the compressed case it uses aBuf(passed in constructor), for stored files
281 * it returns a zero-copy buffer.
283 * @param aBytesRead Outparam for number of bytes read.
284 * @return data read or nullptr if item is corrupted.
286 uint8_t* Read(uint32_t *aBytesRead
) {
287 return ReadOrCopy(aBytesRead
, false);
291 * Performs a copy. It always uses aBuf(passed in constructor).
293 * @param aBytesRead Outparam for number of bytes read.
294 * @return data read or nullptr if item is corrupted.
296 uint8_t* Copy(uint32_t *aBytesRead
) {
297 return ReadOrCopy(aBytesRead
, true);
301 /* Actual implementation for both Read and Copy above */
302 uint8_t* ReadOrCopy(uint32_t *aBytesRead
, bool aCopy
);
313 * nsZipItemPtr - a RAII convenience class for reading the individual items in a zip.
314 * It reads whole files and does zero-copy IO for stored files. A buffer is allocated
316 * Do not use when the file may be very large.
318 class nsZipItemPtr_base
{
321 * Initializes the reader
323 * @param aZip Archive
324 * @param aEntryName Archive membername
325 * @param doCRC When set to true Read() will check crc
327 nsZipItemPtr_base(nsZipArchive
*aZip
, const char *aEntryName
, bool doCRC
);
329 uint32_t Length() const {
334 nsRefPtr
<nsZipHandle
> mZipHandle
;
335 nsAutoArrayPtr
<uint8_t> mAutoBuf
;
341 class nsZipItemPtr
: public nsZipItemPtr_base
{
343 nsZipItemPtr(nsZipArchive
*aZip
, const char *aEntryName
, bool doCRC
= false) : nsZipItemPtr_base(aZip
, aEntryName
, doCRC
) { }
345 * @return buffer containing the whole zip member or nullptr on error.
346 * The returned buffer is owned by nsZipItemReader.
348 const T
* Buffer() const {
349 return (const T
*)mReturnBuf
;
352 operator const T
*() const {
357 * Relinquish ownership of zip member if compressed.
358 * Copy member into a new buffer if uncompressed.
359 * @return a buffer with whole zip member. It is caller's responsibility to free() it.
364 // In uncompressed mmap case, give up buffer
365 if (mAutoBuf
.get() == mReturnBuf
) {
366 mReturnBuf
= nullptr;
367 return (T
*) mAutoBuf
.forget();
369 T
*ret
= (T
*) malloc(Length());
370 memcpy(ret
, mReturnBuf
, Length());
371 mReturnBuf
= nullptr;
377 friend class nsZipArchive
;
378 friend class mozilla::FileLocation
;
380 static nsresult
Init(nsIFile
*file
, nsZipHandle
**ret
,
381 PRFileDesc
**aFd
= nullptr);
382 static nsresult
Init(nsZipArchive
*zip
, const char *entry
,
385 NS_METHOD_(nsrefcnt
) AddRef(void);
386 NS_METHOD_(nsrefcnt
) Release(void);
388 int64_t SizeOfMapping();
391 const uint8_t * mFileData
; /* pointer to mmaped file */
392 uint32_t mLen
; /* length of file and memory mapped area */
393 mozilla::FileLocation mFile
; /* source file if any, for logging */
399 PRFileMap
* mMap
; /* nspr datastructure for mmap */
400 nsAutoPtr
<nsZipItemPtr
<uint8_t> > mBuf
;
401 mozilla::ThreadSafeAutoRefCnt mRefCnt
; /* ref count */
405 nsresult
gZlibInit(z_stream
*zs
);
407 #endif /* nsZipArchive_h_ */