1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/modules/libjar/nsZipArchive.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,403 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef nsZipArchive_h_ 1.10 +#define nsZipArchive_h_ 1.11 + 1.12 +#include "mozilla/Attributes.h" 1.13 + 1.14 +#define ZIP_TABSIZE 256 1.15 +#define ZIP_BUFLEN (4*1024) /* Used as output buffer when deflating items to a file */ 1.16 + 1.17 +#include "plarena.h" 1.18 +#include "zlib.h" 1.19 +#include "zipstruct.h" 1.20 +#include "nsAutoPtr.h" 1.21 +#include "nsIFile.h" 1.22 +#include "nsISupportsImpl.h" // For mozilla::ThreadSafeAutoRefCnt 1.23 +#include "mozilla/FileUtils.h" 1.24 +#include "mozilla/FileLocation.h" 1.25 + 1.26 +#if defined(XP_WIN) && defined(_MSC_VER) 1.27 +#define MOZ_WIN_MEM_TRY_BEGIN __try { 1.28 +#define MOZ_WIN_MEM_TRY_CATCH(cmd) } \ 1.29 + __except(GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR ? \ 1.30 + EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) \ 1.31 + { \ 1.32 + NS_WARNING("EXCEPTION_IN_PAGE_ERROR in " __FUNCTION__); \ 1.33 + cmd; \ 1.34 + } 1.35 +#else 1.36 +#define MOZ_WIN_MEM_TRY_BEGIN { 1.37 +#define MOZ_WIN_MEM_TRY_CATCH(cmd) } 1.38 +#endif 1.39 + 1.40 +class nsZipFind; 1.41 +struct PRFileDesc; 1.42 + 1.43 +/** 1.44 + * This file defines some of the basic structures used by libjar to 1.45 + * read Zip files. It makes use of zlib in order to do the decompression. 1.46 + * 1.47 + * A few notes on the classes/structs: 1.48 + * nsZipArchive represents a single Zip file, and maintains an index 1.49 + * of all the items in the file. 1.50 + * nsZipItem represents a single item (file) in the Zip archive. 1.51 + * nsZipFind represents the metadata involved in doing a search, 1.52 + * and current state of the iteration of found objects. 1.53 + * 'MT''safe' reading from the zipfile is performed through JARInputStream, 1.54 + * which maintains its own file descriptor, allowing for multiple reads 1.55 + * concurrently from the same zip file. 1.56 + */ 1.57 + 1.58 +/** 1.59 + * nsZipItem -- a helper struct for nsZipArchive 1.60 + * 1.61 + * each nsZipItem represents one file in the archive and all the 1.62 + * information needed to manipulate it. 1.63 + */ 1.64 +class nsZipItem 1.65 +{ 1.66 +public: 1.67 + const char* Name() { return ((const char*)central) + ZIPCENTRAL_SIZE; } 1.68 + 1.69 + uint32_t LocalOffset(); 1.70 + uint32_t Size(); 1.71 + uint32_t RealSize(); 1.72 + uint32_t CRC32(); 1.73 + uint16_t Date(); 1.74 + uint16_t Time(); 1.75 + uint16_t Compression(); 1.76 + bool IsDirectory(); 1.77 + uint16_t Mode(); 1.78 + const uint8_t* GetExtraField(uint16_t aTag, uint16_t *aBlockSize); 1.79 + PRTime LastModTime(); 1.80 + 1.81 +#ifdef XP_UNIX 1.82 + bool IsSymlink(); 1.83 +#endif 1.84 + 1.85 + nsZipItem* next; 1.86 + const ZipCentral* central; 1.87 + uint16_t nameLength; 1.88 + bool isSynthetic; 1.89 +}; 1.90 + 1.91 +class nsZipHandle; 1.92 + 1.93 +/** 1.94 + * nsZipArchive -- a class for reading the PKZIP file format. 1.95 + * 1.96 + */ 1.97 +class nsZipArchive 1.98 +{ 1.99 + friend class nsZipFind; 1.100 + 1.101 +public: 1.102 + /** constructing does not open the archive. See OpenArchive() */ 1.103 + nsZipArchive(); 1.104 + 1.105 + /** destructing the object closes the archive */ 1.106 + ~nsZipArchive(); 1.107 + 1.108 + /** 1.109 + * OpenArchive 1.110 + * 1.111 + * It's an error to call this more than once on the same nsZipArchive 1.112 + * object. If we were allowed to use exceptions this would have been 1.113 + * part of the constructor 1.114 + * 1.115 + * @param aZipHandle The nsZipHandle used to access the zip 1.116 + * @param aFd Optional PRFileDesc for Windows readahead optimization 1.117 + * @return status code 1.118 + */ 1.119 + nsresult OpenArchive(nsZipHandle *aZipHandle, PRFileDesc *aFd = nullptr); 1.120 + 1.121 + /** 1.122 + * OpenArchive 1.123 + * 1.124 + * Convenience function that generates nsZipHandle 1.125 + * 1.126 + * @param aFile The file used to access the zip 1.127 + * @return status code 1.128 + */ 1.129 + nsresult OpenArchive(nsIFile *aFile); 1.130 + 1.131 + /** 1.132 + * Test the integrity of items in this archive by running 1.133 + * a CRC check after extracting each item into a memory 1.134 + * buffer. If an entry name is supplied only the 1.135 + * specified item is tested. Else, if null is supplied 1.136 + * then all the items in the archive are tested. 1.137 + * 1.138 + * @return status code 1.139 + */ 1.140 + nsresult Test(const char *aEntryName); 1.141 + 1.142 + /** 1.143 + * Closes an open archive. 1.144 + */ 1.145 + nsresult CloseArchive(); 1.146 + 1.147 + /** 1.148 + * GetItem 1.149 + * @param aEntryName Name of file in the archive 1.150 + * @return pointer to nsZipItem 1.151 + */ 1.152 + nsZipItem* GetItem(const char * aEntryName); 1.153 + 1.154 + /** 1.155 + * ExtractFile 1.156 + * 1.157 + * @param zipEntry Name of file in archive to extract 1.158 + * @param outFD Filedescriptor to write contents to 1.159 + * @param outname Name of file to write to 1.160 + * @return status code 1.161 + */ 1.162 + nsresult ExtractFile(nsZipItem * zipEntry, const char *outname, PRFileDesc * outFD); 1.163 + 1.164 + /** 1.165 + * FindInit 1.166 + * 1.167 + * Initializes a search for files in the archive. FindNext() returns 1.168 + * the actual matches. The nsZipFind must be deleted when you're done 1.169 + * 1.170 + * @param aPattern a string or RegExp pattern to search for 1.171 + * (may be nullptr to find all files in archive) 1.172 + * @param aFind a pointer to a pointer to a structure used 1.173 + * in FindNext. In the case of an error this 1.174 + * will be set to nullptr. 1.175 + * @return status code 1.176 + */ 1.177 + nsresult FindInit(const char * aPattern, nsZipFind** aFind); 1.178 + 1.179 + /* 1.180 + * Gets an undependent handle to the mapped file. 1.181 + */ 1.182 + nsZipHandle* GetFD(); 1.183 + 1.184 + /** 1.185 + * Get pointer to the data of the item. 1.186 + * @param aItem Pointer to nsZipItem 1.187 + * reutrns null when zip file is corrupt. 1.188 + */ 1.189 + const uint8_t* GetData(nsZipItem* aItem); 1.190 + 1.191 + bool GetComment(nsACString &aComment); 1.192 + 1.193 + /** 1.194 + * Gets the amount of memory taken up by the archive's mapping. 1.195 + * @return the size 1.196 + */ 1.197 + int64_t SizeOfMapping(); 1.198 + 1.199 + /* 1.200 + * Refcounting 1.201 + */ 1.202 + NS_METHOD_(MozExternalRefCountType) AddRef(void); 1.203 + NS_METHOD_(MozExternalRefCountType) Release(void); 1.204 + 1.205 +private: 1.206 + //--- private members --- 1.207 + mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */ 1.208 + NS_DECL_OWNINGTHREAD 1.209 + 1.210 + nsZipItem* mFiles[ZIP_TABSIZE]; 1.211 + PLArenaPool mArena; 1.212 + 1.213 + const char* mCommentPtr; 1.214 + uint16_t mCommentLen; 1.215 + 1.216 + // Whether we synthesized the directory entries 1.217 + bool mBuiltSynthetics; 1.218 + 1.219 + // file handle 1.220 + nsRefPtr<nsZipHandle> mFd; 1.221 + 1.222 + // file URI, for logging 1.223 + nsCString mURI; 1.224 + 1.225 +private: 1.226 + //--- private methods --- 1.227 + nsZipItem* CreateZipItem(); 1.228 + nsresult BuildFileList(PRFileDesc *aFd = nullptr); 1.229 + nsresult BuildSynthetics(); 1.230 + 1.231 + nsZipArchive& operator=(const nsZipArchive& rhs) MOZ_DELETE; 1.232 + nsZipArchive(const nsZipArchive& rhs) MOZ_DELETE; 1.233 +}; 1.234 + 1.235 +/** 1.236 + * nsZipFind 1.237 + * 1.238 + * a helper class for nsZipArchive, representing a search 1.239 + */ 1.240 +class nsZipFind 1.241 +{ 1.242 +public: 1.243 + nsZipFind(nsZipArchive* aZip, char* aPattern, bool regExp); 1.244 + ~nsZipFind(); 1.245 + 1.246 + nsresult FindNext(const char** aResult, uint16_t* aNameLen); 1.247 + 1.248 +private: 1.249 + nsRefPtr<nsZipArchive> mArchive; 1.250 + char* mPattern; 1.251 + nsZipItem* mItem; 1.252 + uint16_t mSlot; 1.253 + bool mRegExp; 1.254 + 1.255 + nsZipFind& operator=(const nsZipFind& rhs) MOZ_DELETE; 1.256 + nsZipFind(const nsZipFind& rhs) MOZ_DELETE; 1.257 +}; 1.258 + 1.259 +/** 1.260 + * nsZipCursor -- a low-level class for reading the individual items in a zip. 1.261 + */ 1.262 +class nsZipCursor { 1.263 +public: 1.264 + /** 1.265 + * Initializes the cursor 1.266 + * 1.267 + * @param aItem Item of interest 1.268 + * @param aZip Archive 1.269 + * @param aBuf Buffer used for decompression. 1.270 + * This determines the maximum Read() size in the compressed case. 1.271 + * @param aBufSize Buffer size 1.272 + * @param doCRC When set to true Read() will check crc 1.273 + */ 1.274 + nsZipCursor(nsZipItem *aItem, nsZipArchive *aZip, uint8_t* aBuf = nullptr, uint32_t aBufSize = 0, bool doCRC = false); 1.275 + 1.276 + ~nsZipCursor(); 1.277 + 1.278 + /** 1.279 + * Performs reads. In the compressed case it uses aBuf(passed in constructor), for stored files 1.280 + * it returns a zero-copy buffer. 1.281 + * 1.282 + * @param aBytesRead Outparam for number of bytes read. 1.283 + * @return data read or nullptr if item is corrupted. 1.284 + */ 1.285 + uint8_t* Read(uint32_t *aBytesRead) { 1.286 + return ReadOrCopy(aBytesRead, false); 1.287 + } 1.288 + 1.289 + /** 1.290 + * Performs a copy. It always uses aBuf(passed in constructor). 1.291 + * 1.292 + * @param aBytesRead Outparam for number of bytes read. 1.293 + * @return data read or nullptr if item is corrupted. 1.294 + */ 1.295 + uint8_t* Copy(uint32_t *aBytesRead) { 1.296 + return ReadOrCopy(aBytesRead, true); 1.297 + } 1.298 + 1.299 +private: 1.300 + /* Actual implementation for both Read and Copy above */ 1.301 + uint8_t* ReadOrCopy(uint32_t *aBytesRead, bool aCopy); 1.302 + 1.303 + nsZipItem *mItem; 1.304 + uint8_t *mBuf; 1.305 + uint32_t mBufSize; 1.306 + z_stream mZs; 1.307 + uint32_t mCRC; 1.308 + bool mDoCRC; 1.309 +}; 1.310 + 1.311 +/** 1.312 + * nsZipItemPtr - a RAII convenience class for reading the individual items in a zip. 1.313 + * It reads whole files and does zero-copy IO for stored files. A buffer is allocated 1.314 + * for decompression. 1.315 + * Do not use when the file may be very large. 1.316 + */ 1.317 +class nsZipItemPtr_base { 1.318 +public: 1.319 + /** 1.320 + * Initializes the reader 1.321 + * 1.322 + * @param aZip Archive 1.323 + * @param aEntryName Archive membername 1.324 + * @param doCRC When set to true Read() will check crc 1.325 + */ 1.326 + nsZipItemPtr_base(nsZipArchive *aZip, const char *aEntryName, bool doCRC); 1.327 + 1.328 + uint32_t Length() const { 1.329 + return mReadlen; 1.330 + } 1.331 + 1.332 +protected: 1.333 + nsRefPtr<nsZipHandle> mZipHandle; 1.334 + nsAutoArrayPtr<uint8_t> mAutoBuf; 1.335 + uint8_t *mReturnBuf; 1.336 + uint32_t mReadlen; 1.337 +}; 1.338 + 1.339 +template <class T> 1.340 +class nsZipItemPtr : public nsZipItemPtr_base { 1.341 +public: 1.342 + nsZipItemPtr(nsZipArchive *aZip, const char *aEntryName, bool doCRC = false) : nsZipItemPtr_base(aZip, aEntryName, doCRC) { } 1.343 + /** 1.344 + * @return buffer containing the whole zip member or nullptr on error. 1.345 + * The returned buffer is owned by nsZipItemReader. 1.346 + */ 1.347 + const T* Buffer() const { 1.348 + return (const T*)mReturnBuf; 1.349 + } 1.350 + 1.351 + operator const T*() const { 1.352 + return Buffer(); 1.353 + } 1.354 + 1.355 + /** 1.356 + * Relinquish ownership of zip member if compressed. 1.357 + * Copy member into a new buffer if uncompressed. 1.358 + * @return a buffer with whole zip member. It is caller's responsibility to free() it. 1.359 + */ 1.360 + T* Forget() { 1.361 + if (!mReturnBuf) 1.362 + return nullptr; 1.363 + // In uncompressed mmap case, give up buffer 1.364 + if (mAutoBuf.get() == mReturnBuf) { 1.365 + mReturnBuf = nullptr; 1.366 + return (T*) mAutoBuf.forget(); 1.367 + } 1.368 + T *ret = (T*) malloc(Length()); 1.369 + memcpy(ret, mReturnBuf, Length()); 1.370 + mReturnBuf = nullptr; 1.371 + return ret; 1.372 + } 1.373 +}; 1.374 + 1.375 +class nsZipHandle { 1.376 +friend class nsZipArchive; 1.377 +friend class mozilla::FileLocation; 1.378 +public: 1.379 + static nsresult Init(nsIFile *file, nsZipHandle **ret, 1.380 + PRFileDesc **aFd = nullptr); 1.381 + static nsresult Init(nsZipArchive *zip, const char *entry, 1.382 + nsZipHandle **ret); 1.383 + 1.384 + NS_METHOD_(MozExternalRefCountType) AddRef(void); 1.385 + NS_METHOD_(MozExternalRefCountType) Release(void); 1.386 + 1.387 + int64_t SizeOfMapping(); 1.388 + 1.389 +protected: 1.390 + const uint8_t * mFileData; /* pointer to mmaped file */ 1.391 + uint32_t mLen; /* length of file and memory mapped area */ 1.392 + mozilla::FileLocation mFile; /* source file if any, for logging */ 1.393 + 1.394 +private: 1.395 + nsZipHandle(); 1.396 + ~nsZipHandle(); 1.397 + 1.398 + PRFileMap * mMap; /* nspr datastructure for mmap */ 1.399 + nsAutoPtr<nsZipItemPtr<uint8_t> > mBuf; 1.400 + mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */ 1.401 + NS_DECL_OWNINGTHREAD 1.402 +}; 1.403 + 1.404 +nsresult gZlibInit(z_stream *zs); 1.405 + 1.406 +#endif /* nsZipArchive_h_ */