summaryrefslogtreecommitdiffstats
path: root/modules/libjar/nsZipArchive.h
diff options
context:
space:
mode:
Diffstat (limited to 'modules/libjar/nsZipArchive.h')
-rw-r--r--modules/libjar/nsZipArchive.h436
1 files changed, 436 insertions, 0 deletions
diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h
new file mode 100644
index 000000000..2de679032
--- /dev/null
+++ b/modules/libjar/nsZipArchive.h
@@ -0,0 +1,436 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsZipArchive_h_
+#define nsZipArchive_h_
+
+#include "mozilla/Attributes.h"
+
+#define ZIP_TABSIZE 256
+#define ZIP_BUFLEN (4*1024) /* Used as output buffer when deflating items to a file */
+
+#include "plarena.h"
+#include "zlib.h"
+#include "zipstruct.h"
+#include "nsAutoPtr.h"
+#include "nsIFile.h"
+#include "nsISupportsImpl.h" // For mozilla::ThreadSafeAutoRefCnt
+#include "mozilla/FileUtils.h"
+#include "mozilla/FileLocation.h"
+#include "mozilla/UniquePtr.h"
+
+#ifdef HAVE_SEH_EXCEPTIONS
+#define MOZ_WIN_MEM_TRY_BEGIN __try {
+#define MOZ_WIN_MEM_TRY_CATCH(cmd) } \
+ __except(GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR ? \
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) \
+ { \
+ NS_WARNING("unexpected EXCEPTION_IN_PAGE_ERROR"); \
+ cmd; \
+ }
+#else
+#define MOZ_WIN_MEM_TRY_BEGIN {
+#define MOZ_WIN_MEM_TRY_CATCH(cmd) }
+#endif
+
+class nsZipFind;
+struct PRFileDesc;
+
+/**
+ * This file defines some of the basic structures used by libjar to
+ * read Zip files. It makes use of zlib in order to do the decompression.
+ *
+ * A few notes on the classes/structs:
+ * nsZipArchive represents a single Zip file, and maintains an index
+ * of all the items in the file.
+ * nsZipItem represents a single item (file) in the Zip archive.
+ * nsZipFind represents the metadata involved in doing a search,
+ * and current state of the iteration of found objects.
+ * 'MT''safe' reading from the zipfile is performed through JARInputStream,
+ * which maintains its own file descriptor, allowing for multiple reads
+ * concurrently from the same zip file.
+ */
+
+/**
+ * nsZipItem -- a helper struct for nsZipArchive
+ *
+ * each nsZipItem represents one file in the archive and all the
+ * information needed to manipulate it.
+ */
+class nsZipItem final
+{
+public:
+ nsZipItem();
+
+ const char* Name() { return ((const char*)central) + ZIPCENTRAL_SIZE; }
+
+ uint32_t LocalOffset();
+ uint32_t Size();
+ uint32_t RealSize();
+ uint32_t CRC32();
+ uint16_t Date();
+ uint16_t Time();
+ uint16_t Compression();
+ bool IsDirectory();
+ uint16_t Mode();
+ const uint8_t* GetExtraField(uint16_t aTag, uint16_t *aBlockSize);
+ PRTime LastModTime();
+
+#ifdef XP_UNIX
+ bool IsSymlink();
+#endif
+
+ nsZipItem* next;
+ const ZipCentral* central;
+ uint16_t nameLength;
+ bool isSynthetic;
+};
+
+class nsZipHandle;
+
+/**
+ * nsZipArchive -- a class for reading the PKZIP file format.
+ *
+ */
+class nsZipArchive final
+{
+ friend class nsZipFind;
+
+ /** destructing the object closes the archive */
+ ~nsZipArchive();
+
+public:
+ static const char* sFileCorruptedReason;
+
+ /** constructing does not open the archive. See OpenArchive() */
+ nsZipArchive();
+
+ /**
+ * OpenArchive
+ *
+ * It's an error to call this more than once on the same nsZipArchive
+ * object. If we were allowed to use exceptions this would have been
+ * part of the constructor
+ *
+ * @param aZipHandle The nsZipHandle used to access the zip
+ * @param aFd Optional PRFileDesc for Windows readahead optimization
+ * @return status code
+ */
+ nsresult OpenArchive(nsZipHandle *aZipHandle, PRFileDesc *aFd = nullptr);
+
+ /**
+ * OpenArchive
+ *
+ * Convenience function that generates nsZipHandle
+ *
+ * @param aFile The file used to access the zip
+ * @return status code
+ */
+ nsresult OpenArchive(nsIFile *aFile);
+
+ /**
+ * Test the integrity of items in this archive by running
+ * a CRC check after extracting each item into a memory
+ * buffer. If an entry name is supplied only the
+ * specified item is tested. Else, if null is supplied
+ * then all the items in the archive are tested.
+ *
+ * @return status code
+ */
+ nsresult Test(const char *aEntryName);
+
+ /**
+ * Closes an open archive.
+ */
+ nsresult CloseArchive();
+
+ /**
+ * GetItem
+ * @param aEntryName Name of file in the archive
+ * @return pointer to nsZipItem
+ */
+ nsZipItem* GetItem(const char * aEntryName);
+
+ /**
+ * ExtractFile
+ *
+ * @param zipEntry Name of file in archive to extract
+ * @param outFD Filedescriptor to write contents to
+ * @param outname Name of file to write to
+ * @return status code
+ */
+ nsresult ExtractFile(nsZipItem * zipEntry, const char *outname, PRFileDesc * outFD);
+
+ /**
+ * FindInit
+ *
+ * Initializes a search for files in the archive. FindNext() returns
+ * the actual matches. The nsZipFind must be deleted when you're done
+ *
+ * @param aPattern a string or RegExp pattern to search for
+ * (may be nullptr to find all files in archive)
+ * @param aFind a pointer to a pointer to a structure used
+ * in FindNext. In the case of an error this
+ * will be set to nullptr.
+ * @return status code
+ */
+ nsresult FindInit(const char * aPattern, nsZipFind** aFind);
+
+ /*
+ * Gets an undependent handle to the mapped file.
+ */
+ nsZipHandle* GetFD();
+
+ /**
+ * Gets the data offset.
+ * @param aItem Pointer to nsZipItem
+ * returns 0 on failure.
+ */
+ uint32_t GetDataOffset(nsZipItem* aItem);
+
+ /**
+ * Get pointer to the data of the item.
+ * @param aItem Pointer to nsZipItem
+ * reutrns null when zip file is corrupt.
+ */
+ const uint8_t* GetData(nsZipItem* aItem);
+
+ bool GetComment(nsACString &aComment);
+
+ /**
+ * Gets the amount of memory taken up by the archive's mapping.
+ * @return the size
+ */
+ int64_t SizeOfMapping();
+
+ /*
+ * Refcounting
+ */
+ NS_METHOD_(MozExternalRefCountType) AddRef(void);
+ NS_METHOD_(MozExternalRefCountType) Release(void);
+
+private:
+ //--- private members ---
+ mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */
+ NS_DECL_OWNINGTHREAD
+
+ nsZipItem* mFiles[ZIP_TABSIZE];
+ PLArenaPool mArena;
+
+ const char* mCommentPtr;
+ uint16_t mCommentLen;
+
+ // Whether we synthesized the directory entries
+ bool mBuiltSynthetics;
+
+ // file handle
+ RefPtr<nsZipHandle> mFd;
+
+ // file URI, for logging
+ nsCString mURI;
+
+private:
+ //--- private methods ---
+ nsZipItem* CreateZipItem();
+ nsresult BuildFileList(PRFileDesc *aFd = nullptr);
+ nsresult BuildSynthetics();
+
+ nsZipArchive& operator=(const nsZipArchive& rhs) = delete;
+ nsZipArchive(const nsZipArchive& rhs) = delete;
+};
+
+/**
+ * nsZipFind
+ *
+ * a helper class for nsZipArchive, representing a search
+ */
+class nsZipFind final
+{
+public:
+ nsZipFind(nsZipArchive* aZip, char* aPattern, bool regExp);
+ ~nsZipFind();
+
+ nsresult FindNext(const char** aResult, uint16_t* aNameLen);
+
+private:
+ RefPtr<nsZipArchive> mArchive;
+ char* mPattern;
+ nsZipItem* mItem;
+ uint16_t mSlot;
+ bool mRegExp;
+
+ nsZipFind& operator=(const nsZipFind& rhs) = delete;
+ nsZipFind(const nsZipFind& rhs) = delete;
+};
+
+/**
+ * nsZipCursor -- a low-level class for reading the individual items in a zip.
+ */
+class nsZipCursor final
+{
+public:
+ /**
+ * Initializes the cursor
+ *
+ * @param aItem Item of interest
+ * @param aZip Archive
+ * @param aBuf Buffer used for decompression.
+ * This determines the maximum Read() size in the compressed case.
+ * @param aBufSize Buffer size
+ * @param doCRC When set to true Read() will check crc
+ */
+ nsZipCursor(nsZipItem *aItem, nsZipArchive *aZip, uint8_t* aBuf = nullptr, uint32_t aBufSize = 0, bool doCRC = false);
+
+ ~nsZipCursor();
+
+ /**
+ * Performs reads. In the compressed case it uses aBuf(passed in constructor), for stored files
+ * it returns a zero-copy buffer.
+ *
+ * @param aBytesRead Outparam for number of bytes read.
+ * @return data read or nullptr if item is corrupted.
+ */
+ uint8_t* Read(uint32_t *aBytesRead) {
+ return ReadOrCopy(aBytesRead, false);
+ }
+
+ /**
+ * Performs a copy. It always uses aBuf(passed in constructor).
+ *
+ * @param aBytesRead Outparam for number of bytes read.
+ * @return data read or nullptr if item is corrupted.
+ */
+ uint8_t* Copy(uint32_t *aBytesRead) {
+ return ReadOrCopy(aBytesRead, true);
+ }
+
+private:
+ /* Actual implementation for both Read and Copy above */
+ uint8_t* ReadOrCopy(uint32_t *aBytesRead, bool aCopy);
+
+ nsZipItem *mItem;
+ uint8_t *mBuf;
+ uint32_t mBufSize;
+ z_stream mZs;
+ uint32_t mCRC;
+ bool mDoCRC;
+};
+
+/**
+ * nsZipItemPtr - a RAII convenience class for reading the individual items in a zip.
+ * It reads whole files and does zero-copy IO for stored files. A buffer is allocated
+ * for decompression.
+ * Do not use when the file may be very large.
+ */
+class nsZipItemPtr_base
+{
+public:
+ /**
+ * Initializes the reader
+ *
+ * @param aZip Archive
+ * @param aEntryName Archive membername
+ * @param doCRC When set to true Read() will check crc
+ */
+ nsZipItemPtr_base(nsZipArchive *aZip, const char *aEntryName, bool doCRC);
+
+ uint32_t Length() const {
+ return mReadlen;
+ }
+
+protected:
+ RefPtr<nsZipHandle> mZipHandle;
+ mozilla::UniquePtr<uint8_t[]> mAutoBuf;
+ uint8_t *mReturnBuf;
+ uint32_t mReadlen;
+};
+
+template <class T>
+class nsZipItemPtr final : public nsZipItemPtr_base
+{
+ static_assert(sizeof(T) == sizeof(char),
+ "This class cannot be used with larger T without re-examining"
+ " a number of assumptions.");
+
+public:
+ nsZipItemPtr(nsZipArchive *aZip, const char *aEntryName, bool doCRC = false) : nsZipItemPtr_base(aZip, aEntryName, doCRC) { }
+ /**
+ * @return buffer containing the whole zip member or nullptr on error.
+ * The returned buffer is owned by nsZipItemReader.
+ */
+ const T* Buffer() const {
+ return (const T*)mReturnBuf;
+ }
+
+ operator const T*() const {
+ return Buffer();
+ }
+
+ /**
+ * Relinquish ownership of zip member if compressed.
+ * Copy member into a new buffer if uncompressed.
+ * @return a buffer with whole zip member. It is caller's responsibility to free() it.
+ */
+ mozilla::UniquePtr<T[]> Forget() {
+ if (!mReturnBuf)
+ return nullptr;
+ // In uncompressed mmap case, give up buffer
+ if (mAutoBuf.get() == mReturnBuf) {
+ mReturnBuf = nullptr;
+ return mozilla::UniquePtr<T[]>(reinterpret_cast<T*>(mAutoBuf.release()));
+ }
+ auto ret = mozilla::MakeUnique<T[]>(Length());
+ memcpy(ret.get(), mReturnBuf, Length());
+ mReturnBuf = nullptr;
+ return ret;
+ }
+};
+
+class nsZipHandle final
+{
+friend class nsZipArchive;
+friend class mozilla::FileLocation;
+public:
+ static nsresult Init(nsIFile *file, nsZipHandle **ret,
+ PRFileDesc **aFd = nullptr);
+ static nsresult Init(nsZipArchive *zip, const char *entry,
+ nsZipHandle **ret);
+ static nsresult Init(const uint8_t* aData, uint32_t aLen,
+ nsZipHandle **aRet);
+
+ NS_METHOD_(MozExternalRefCountType) AddRef(void);
+ NS_METHOD_(MozExternalRefCountType) Release(void);
+
+ int64_t SizeOfMapping();
+
+ nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
+
+protected:
+ const uint8_t * mFileData; /* pointer to zip data */
+ uint32_t mLen; /* length of zip data */
+ mozilla::FileLocation mFile; /* source file if any, for logging */
+
+private:
+ nsZipHandle();
+ ~nsZipHandle();
+
+ nsresult findDataStart();
+
+ PRFileMap * mMap; /* nspr datastructure for mmap */
+ mozilla::AutoFDClose mNSPRFileDesc;
+ nsAutoPtr<nsZipItemPtr<uint8_t> > mBuf;
+ mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */
+ NS_DECL_OWNINGTHREAD
+
+ const uint8_t * mFileStart; /* pointer to mmaped file */
+ uint32_t mTotalLen; /* total length of the mmaped file */
+
+ /* Magic number for CRX type expressed in Big Endian since it is a literal */
+ static const uint32_t kCRXMagic = 0x34327243;
+};
+
+nsresult gZlibInit(z_stream *zs);
+
+#endif /* nsZipArchive_h_ */