Bug 1260836 - Add functionality to allow CRX files to be handled as ZIP files
MozReview-Commit-ID: 8cMxoqJPNlk
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -160,16 +160,18 @@ nsresult gZlibInit(z_stream *zs)
return NS_OK;
}
nsZipHandle::nsZipHandle()
: mFileData(nullptr)
, mLen(0)
, mMap(nullptr)
, mRefCnt(0)
+ , mFileStart(nullptr)
+ , mTotalLen(0)
{
MOZ_COUNT_CTOR(nsZipHandle);
}
NS_IMPL_ADDREF(nsZipHandle)
NS_IMPL_RELEASE(nsZipHandle)
nsresult nsZipHandle::Init(nsIFile *file, nsZipHandle **ret,
@@ -210,18 +212,19 @@ nsresult nsZipHandle::Init(nsIFile *file
if (aFd) {
*aFd = fd.forget();
}
#else
handle->mNSPRFileDesc = fd.forget();
#endif
handle->mMap = map;
handle->mFile.Init(file);
- handle->mLen = (uint32_t) size;
- handle->mFileData = buf;
+ handle->mTotalLen = (uint32_t) size;
+ handle->mFileStart = buf;
+ handle->findDataStart();
handle.forget(ret);
return NS_OK;
}
nsresult nsZipHandle::Init(nsZipArchive *zip, const char *entry,
nsZipHandle **ret)
{
RefPtr<nsZipHandle> handle = new nsZipHandle();
@@ -232,36 +235,78 @@ nsresult nsZipHandle::Init(nsZipArchive
if (!handle->mBuf)
return NS_ERROR_OUT_OF_MEMORY;
if (!handle->mBuf->Buffer())
return NS_ERROR_UNEXPECTED;
handle->mMap = nullptr;
handle->mFile.Init(zip, entry);
- handle->mLen = handle->mBuf->Length();
- handle->mFileData = handle->mBuf->Buffer();
+ handle->mTotalLen = handle->mBuf->Length();
+ handle->mFileStart = handle->mBuf->Buffer();
+ handle->findDataStart();
handle.forget(ret);
return NS_OK;
}
nsresult nsZipHandle::Init(const uint8_t* aData, uint32_t aLen,
nsZipHandle **aRet)
{
RefPtr<nsZipHandle> handle = new nsZipHandle();
- handle->mFileData = aData;
- handle->mLen = aLen;
+ handle->mFileStart = aData;
+ handle->mTotalLen = aLen;
+ handle->findDataStart();
handle.forget(aRet);
return NS_OK;
}
+// This function finds the start of the ZIP data. If the file is a regular ZIP,
+// this is just the start of the file. If the file is a CRX file, the start of
+// the data is after the CRX header.
+// CRX header reference: (CRX version 2)
+// Header requires little-endian byte ordering with 4-byte alignment.
+// 32 bits : magicNumber - Defined as a |char m[] = "Cr24"|.
+// Equivalent to |uint32_t m = 0x34327243|.
+// 32 bits : version - Unsigned integer representing the CRX file
+// format version. Currently equal to 2.
+// 32 bits : pubKeyLength - Unsigned integer representing the length
+// of the public key in bytes.
+// 32 bits : sigLength - Unsigned integer representing the length
+// of the signature in bytes.
+// pubKeyLength : publicKey - Contents of the author's public key.
+// sigLength : signature - Signature of the ZIP content.
+// Signature is created using the RSA
+// algorighm with the SHA-1 hash function.
+void nsZipHandle::findDataStart()
+{
+ // In the CRX header, integers are 32 bits. Our pointer to the file is of
+ // type |uint8_t|, which is guaranteed to be 8 bits.
+ const uint32_t CRXIntSize = 4;
+
+ if (mTotalLen > CRXIntSize * 4 && xtolong(mFileStart) == kCRXMagic) {
+ const uint8_t* headerData = mFileStart;
+ headerData += CRXIntSize * 2; // Skip magic number and version number
+ uint32_t pubKeyLength = xtolong(headerData);
+ headerData += CRXIntSize;
+ uint32_t sigLength = xtolong(headerData);
+ uint32_t headerSize = CRXIntSize * 4 + pubKeyLength + sigLength;
+ if (mTotalLen > headerSize) {
+ mLen = mTotalLen - headerSize;
+ mFileData = mFileStart + headerSize;
+ return;
+ }
+ }
+ mLen = mTotalLen;
+ mFileData = mFileStart;
+}
+
int64_t nsZipHandle::SizeOfMapping()
{
- return mLen;
+ return mTotalLen;
}
nsresult nsZipHandle::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc)
{
if (!aNSPRFileDesc) {
return NS_ERROR_ILLEGAL_VALUE;
}
@@ -271,19 +316,20 @@ nsresult nsZipHandle::GetNSPRFileDesc(PR
}
return NS_OK;
}
nsZipHandle::~nsZipHandle()
{
if (mMap) {
- PR_MemUnmap((void *)mFileData, mLen);
+ PR_MemUnmap((void *)mFileStart, mTotalLen);
PR_CloseFileMap(mMap);
}
+ mFileStart = nullptr;
mFileData = nullptr;
mMap = nullptr;
mBuf = nullptr;
MOZ_COUNT_DTOR(nsZipHandle);
}
//***********************************************************
// nsZipArchive -- public methods
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -403,26 +403,34 @@ public:
NS_METHOD_(MozExternalRefCountType) AddRef(void);
NS_METHOD_(MozExternalRefCountType) Release(void);
int64_t SizeOfMapping();
nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
protected:
- const uint8_t * mFileData; /* pointer to mmaped file */
- uint32_t mLen; /* length of file and memory mapped area */
+ 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();
+ void 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_ */