Bug 511754 - make nsZipItems point at ZipCentral references to mmapped jar area r=tglek
--- a/modules/libjar/nsJAR.cpp
+++ b/modules/libjar/nsJAR.cpp
@@ -232,39 +232,39 @@ nsJAR::Extract(const char *zipEntry, nsI
//XXX is always FILE_DIR_NOT_EMPTY, we can remove
//XXX |rv == NS_ERROR_FAILURE| - bug 322183 needs to be completely
//XXX fixed before that can happen
rv = localFile->Remove(PR_FALSE);
if (rv == NS_ERROR_FILE_DIR_NOT_EMPTY ||
rv == NS_ERROR_FAILURE)
return rv;
- if (item->isDirectory)
+ if (item->IsDirectory())
{
- rv = localFile->Create(nsIFile::DIRECTORY_TYPE, item->mode);
+ rv = localFile->Create(nsIFile::DIRECTORY_TYPE, item->Mode());
//XXX Do this in nsZipArchive? It would be nice to keep extraction
//XXX code completely there, but that would require a way to get a
//XXX PRDir from localFile.
}
else
{
PRFileDesc* fd;
- rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, item->mode, &fd);
+ rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, item->Mode(), &fd);
if (NS_FAILED(rv)) return rv;
// ExtractFile also closes the fd handle and resolves the symlink if needed
nsCAutoString path;
rv = outFile->GetNativePath(path);
if (NS_FAILED(rv)) return rv;
rv = mZip.ExtractFile(item, path.get(), fd);
}
if (NS_FAILED(rv)) return rv;
- PRTime prtime = GetModTime(item->date, item->time);
+ PRTime prtime = GetModTime(item->Date(), item->Time());
// nsIFile needs milliseconds, while prtime is in microseconds.
PRTime conversion = LL_ZERO;
PRTime newTime = LL_ZERO;
LL_I2L(conversion, PR_USEC_PER_MSEC);
LL_DIV(newTime, prtime, conversion);
// non-fatal if this fails, ignore errors
outFile->SetLastModifiedTime(newTime);
@@ -331,17 +331,17 @@ nsJAR::GetInputStreamWithSpec(const nsAC
if (!item) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
}
nsJARInputStream* jis = new nsJARInputStream();
// addref now so we can call InitFile/InitDirectory()
NS_ENSURE_TRUE(jis, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*result = jis);
nsresult rv = NS_OK;
- if (!item || item->isDirectory) {
+ if (!item || item->IsDirectory()) {
rv = jis->InitDirectory(this, aJarDirSpec, aEntryName);
} else {
rv = jis->InitFile(this, item);
}
if (NS_FAILED(rv)) {
NS_RELEASE(*result);
}
return rv;
@@ -889,19 +889,19 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsJAREnume
//----------------------------------------------
// nsJAREnumerator::HasMore
//----------------------------------------------
NS_IMETHODIMP
nsJAREnumerator::HasMore(PRBool* aResult)
{
// try to get the next element
- if (!mCurr) {
+ if (!mName) {
NS_ASSERTION(mFind, "nsJAREnumerator: Missing zipFind.");
- nsresult rv = mFind->FindNext( &mCurr );
+ nsresult rv = mFind->FindNext( &mName, &mNameLen );
if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
*aResult = PR_FALSE; // No more matches available
return NS_OK;
}
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); // no error translation
}
*aResult = PR_TRUE;
@@ -910,38 +910,38 @@ nsJAREnumerator::HasMore(PRBool* aResult
//----------------------------------------------
// nsJAREnumerator::GetNext
//----------------------------------------------
NS_IMETHODIMP
nsJAREnumerator::GetNext(nsACString& aResult)
{
// check if the current item is "stale"
- if (!mCurr) {
+ if (!mName) {
PRBool bMore;
nsresult rv = HasMore(&bMore);
if (NS_FAILED(rv) || !bMore)
return NS_ERROR_FAILURE; // no error translation
}
- aResult = mCurr;
- mCurr = 0; // we just gave this one away
+ aResult.Assign(mName, mNameLen);
+ mName = 0; // we just gave this one away
return NS_OK;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARItem, nsIZipEntry)
nsJARItem::nsJARItem(nsZipItem* aZipItem)
- : mSize(aZipItem->size),
- mRealsize(aZipItem->realsize),
- mCrc32(aZipItem->crc32),
- mDate(aZipItem->date),
- mTime(aZipItem->time),
- mCompression(aZipItem->compression),
- mIsDirectory(aZipItem->isDirectory),
+ : mSize(aZipItem->Size()),
+ mRealsize(aZipItem->RealSize()),
+ mCrc32(aZipItem->CRC32()),
+ mDate(aZipItem->Date()),
+ mTime(aZipItem->Time()),
+ mCompression(aZipItem->Compression()),
+ mIsDirectory(aZipItem->IsDirectory()),
mIsSynthetic(aZipItem->isSynthetic)
{
}
//------------------------------------------
// nsJARItem::GetCompression
//------------------------------------------
NS_IMETHODIMP
--- a/modules/libjar/nsJAR.h
+++ b/modules/libjar/nsJAR.h
@@ -181,40 +181,41 @@ public:
virtual ~nsJARItem() {}
private:
PRUint32 mSize; /* size in original file */
PRUint32 mRealsize; /* inflated size */
PRUint32 mCrc32;
PRUint16 mDate;
PRUint16 mTime;
- PRUint8 mCompression;
+ PRUint16 mCompression;
PRPackedBool mIsDirectory;
PRPackedBool mIsSynthetic;
};
/**
* nsJAREnumerator
*
* Enumerates a list of files in a zip archive
* (based on a pattern match in its member nsZipFind).
*/
class nsJAREnumerator : public nsIUTF8StringEnumerator
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIUTF8STRINGENUMERATOR
- nsJAREnumerator(nsZipFind *aFind) : mFind(aFind), mCurr(nsnull) {
+ nsJAREnumerator(nsZipFind *aFind) : mFind(aFind), mName(nsnull) {
NS_ASSERTION(mFind, "nsJAREnumerator: Missing zipFind.");
}
private:
nsZipFind *mFind;
- const char* mCurr; // pointer to an name owned by mArchive -- DON'T delete
+ const char* mName; // pointer to an name owned by mArchive -- DON'T delete
+ PRUint16 mNameLen;
~nsJAREnumerator() { delete mFind; }
};
////////////////////////////////////////////////////////////////////////////////
#if defined(DEBUG_warren) || defined(DEBUG_jband)
#define ZIP_CACHE_HIT_RATE
--- a/modules/libjar/nsJARInputStream.cpp
+++ b/modules/libjar/nsJARInputStream.cpp
@@ -63,40 +63,39 @@ nsJARInputStream::InitFile(nsJAR *aJar,
{
nsresult rv = NS_OK;
NS_ABORT_IF_FALSE(aJar, "Argument may not be null");
NS_ABORT_IF_FALSE(item, "Argument may not be null");
// Mark it as closed, in case something fails in initialisation
mMode = MODE_CLOSED;
//-- prepare for the compression type
- switch (item->compression) {
+ switch (item->Compression()) {
case STORED:
mMode = MODE_COPY;
break;
case DEFLATED:
rv = gZlibInit(&mZs);
NS_ENSURE_SUCCESS(rv, rv);
mMode = MODE_INFLATE;
- mOutSize = item->realsize;
- mInCrc = item->crc32;
+ mInCrc = item->CRC32();
mOutCrc = crc32(0L, Z_NULL, 0);
break;
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
// Must keep handle to filepointer and mmap structure as long as we need access to the mmapped data
mFd = aJar->mZip.GetFD();
mZs.next_in = aJar->mZip.GetData(item);
- mZs.avail_in = item->size;
- mOutSize = item->realsize;
+ mZs.avail_in = item->Size();
+ mOutSize = item->RealSize();
mZs.total_out = 0;
return NS_OK;
}
nsresult
nsJARInputStream::InitDirectory(nsJAR* aJar,
const nsACString& aJarDirSpec,
const char* aDir)
@@ -145,19 +144,20 @@ nsJARInputStream::InitDirectory(nsJAR* a
++curr;
}
nsCAutoString pattern = escDirName + NS_LITERAL_CSTRING("?*~") +
escDirName + NS_LITERAL_CSTRING("?*/?*");
rv = mJar->mZip.FindInit(pattern.get(), &find);
if (NS_FAILED(rv)) return rv;
const char *name;
- while ((rv = find->FindNext( &name )) == NS_OK) {
- // No need to copy string, just share the one from nsZipArchive
- mArray.AppendElement(nsDependentCString(name));
+ PRUint16 nameLen;
+ while ((rv = find->FindNext( &name, &nameLen )) == NS_OK) {
+ // Must copy, to make it zero-terminated
+ mArray.AppendElement(nsCString(name,nameLen));
}
delete find;
if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST && NS_FAILED(rv)) {
return NS_ERROR_FAILURE; // no error translation
}
// Sort it
@@ -339,17 +339,17 @@ nsJARInputStream::ReadDirectory(char* aB
const char * entryName = mArray[mArrPos].get();
PRUint32 entryNameLen = mArray[mArrPos].Length();
nsZipItem* ze = mJar->mZip.GetItem(entryName);
NS_ENSURE_TRUE(ze, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST);
// Last Modified Time
PRExplodedTime tm;
- PR_ExplodeTime(GetModTime(ze->date, ze->time), PR_GMTParameters, &tm);
+ PR_ExplodeTime(GetModTime(ze->Date(), ze->Time()), PR_GMTParameters, &tm);
char itemLastModTime[65];
PR_FormatTimeUSEnglish(itemLastModTime,
sizeof(itemLastModTime),
" %a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ",
&tm);
// write a 201: line to the buffer for this item
// 200: filename content-length last-modified file-type
@@ -359,19 +359,19 @@ nsJARInputStream::ReadDirectory(char* aB
// of the directory name as the offset into the string
// NS_EscapeURL adds the escaped URL to the give string buffer
NS_EscapeURL(entryName + mNameLen,
entryNameLen - mNameLen,
esc_Minimal | esc_AlwaysCopy,
mBuffer);
mBuffer.Append(' ');
- mBuffer.AppendInt(ze->realsize, 10);
+ mBuffer.AppendInt(ze->RealSize(), 10);
mBuffer.Append(itemLastModTime); // starts/ends with ' '
- if (ze->isDirectory)
+ if (ze->IsDirectory())
mBuffer.AppendLiteral("DIRECTORY\n");
else
mBuffer.AppendLiteral("FILE\n");
}
// Copy up to the desired amount of data to buffer
numRead += CopyDataToBuffer(aBuffer, aCount);
}
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -44,27 +44,25 @@
/*
* This module implements a simple archive extractor for the PKZIP format.
*
* The underlying nsZipArchive is NOT thread-safe. Do not pass references
* or pointers to it across thread boundaries.
*/
-
#define READTYPE PRInt32
#include "zlib.h"
#include "nsISupportsUtils.h"
#include "nsRecyclingAllocator.h"
#include "prio.h"
#include "plstr.h"
#include "prlog.h"
#include "stdlib.h"
#include "nsWildCard.h"
-#include "zipstruct.h"
#include "nsZipArchive.h"
/**
* Global allocator used with zlib. Destroyed in module shutdown.
*/
#define NBUCKETS 6
nsRecyclingAllocator *gZlibAllocator = NULL;
@@ -95,22 +93,26 @@ nsRecyclingAllocator *gZlibAllocator = N
# ifndef S_IFLNK
# define S_IFLNK 0120000
# endif
# ifndef PATH_MAX
# define PATH_MAX 1024
# endif
#endif /* XP_UNIX */
-static PRUint16 xtoint(unsigned char *ii);
-static PRUint32 xtolong(unsigned char *ll);
-static PRUint16 ExtractMode(unsigned char *ll);
-static PRUint32 HashName(const char* aName);
+
+static const PRUint32 kMaxNameLength = PATH_MAX; /* Maximum name length */
+// For synthetic zip entries. Date/time corresponds to 1980-01-01 00:00.
+static const PRUint16 kSyntheticTime = 0;
+static const PRUint16 kSyntheticDate = (1 + (1 << 5) + (0 << 9));
+
+static PRUint16 xtoint(const unsigned char *ii);
+static PRUint32 xtolong(const unsigned char *ll);
+static PRUint32 HashName(const char* aName, PRUint16 nameLen);
#if defined(XP_UNIX) || defined(XP_BEOS)
-static PRBool IsSymlink(unsigned char *ll);
static nsresult ResolveSymlink(const char *path);
#endif
//***********************************************************
// Allocators for use with zlib
//
// Use a recycling allocator, for re-use of of the zlib buffers.
// For every inflation the following allocations are done:
@@ -238,26 +240,26 @@ nsresult nsZipArchive::Test(const char *
nsZipItem* currItem;
if (aEntryName) // only test specified item
{
currItem = GetItem(aEntryName);
if (!currItem)
return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
//-- don't test (synthetic) directory items
- if (currItem->isDirectory)
+ if (currItem->IsDirectory())
return NS_OK;
return ExtractFile(currItem, 0, 0);
}
// test all items in archive
for (int i = 0; i < ZIP_TABSIZE; i++) {
for (currItem = mFiles[i]; currItem; currItem = currItem->next) {
//-- don't test (synthetic) directory items
- if (currItem->isDirectory)
+ if (currItem->IsDirectory())
continue;
nsresult rv = ExtractFile(currItem, 0, 0);
if (rv != NS_OK)
return rv;
}
}
return NS_OK;
@@ -286,29 +288,30 @@ nsresult nsZipArchive::CloseArchive()
}
//---------------------------------------------
// nsZipArchive::GetItem
//---------------------------------------------
nsZipItem* nsZipArchive::GetItem(const char * aEntryName)
{
if (aEntryName) {
+ PRUint32 len = strlen(aEntryName);
//-- If the request is for a directory, make sure that synthetic entries
//-- are created for the directories without their own entry.
if (!mBuiltSynthetics) {
- PRUint32 len = strlen(aEntryName);
if ((len > 0) && (aEntryName[len-1] == '/')) {
if (BuildSynthetics() != NS_OK)
return 0;
}
}
- nsZipItem* item = mFiles[ HashName(aEntryName) ];
+ nsZipItem* item = mFiles[ HashName(aEntryName, len) ];
while (item) {
- if (!strcmp(aEntryName, item->name))
+ if ((len == item->nameLength) &&
+ (!memcmp(aEntryName, item->Name(), len)))
return item; //-- found it
item = item->next;
}
}
return 0;
}
//---------------------------------------------
@@ -323,22 +326,22 @@ nsresult nsZipArchive::ExtractFile(nsZip
{
if (!item)
return NS_ERROR_ILLEGAL_VALUE;
if (!mFd)
return NS_ERROR_FAILURE;
// Directory extraction is handled in nsJAR::Extract,
// so the item to be extracted should never be a directory
- PR_ASSERT(!item->isDirectory);
+ PR_ASSERT(!item->IsDirectory());
nsresult rv;
//-- extract the file using the appropriate method
- switch(item->compression)
+ switch(item->Compression())
{
case STORED:
rv = CopyItemToDisk(item, aFd);
break;
case DEFLATED:
rv = InflateItem(item, aFd);
break;
@@ -349,17 +352,17 @@ nsresult nsZipArchive::ExtractFile(nsZip
}
//-- delete the file on errors, or resolve symlink if needed
if (aFd) {
PR_Close(aFd);
if (rv != NS_OK)
PR_Delete(outname);
#if defined(XP_UNIX) || defined(XP_BEOS)
- else if (item->isSymlink)
+ else if (item->IsSymlink())
rv = ResolveSymlink(outname);
#endif
}
return rv;
}
//---------------------------------------------
@@ -418,41 +421,49 @@ nsZipArchive::FindInit(const char * aPat
return NS_OK;
}
//---------------------------------------------
// nsZipFind::FindNext
//---------------------------------------------
-nsresult nsZipFind::FindNext(const char ** aResult)
+nsresult nsZipFind::FindNext(const char ** aResult, PRUint16 *aNameLen)
{
- if (!mArchive || !aResult)
+ if (!mArchive || !aResult || !aNameLen)
return NS_ERROR_ILLEGAL_VALUE;
*aResult = 0;
+ *aNameLen = 0;
// we start from last match, look for next
while (mSlot < ZIP_TABSIZE)
{
// move to next in current chain, or move to new slot
mItem = mItem ? mItem->next : mArchive->mFiles[mSlot];
PRBool found = PR_FALSE;
if (!mItem)
++mSlot; // no more in this chain, move to next slot
else if (!mPattern)
found = PR_TRUE; // always match
else if (mRegExp)
- found = (NS_WildCardMatch(mItem->name, mPattern, PR_FALSE) == MATCH);
+ {
+ char buf[kMaxNameLength+1];
+ memcpy(buf, mItem->Name(), mItem->nameLength);
+ buf[mItem->nameLength]='\0';
+ found = (NS_WildCardMatch(buf, mPattern, PR_FALSE) == MATCH);
+ }
else
- found = (PL_strcmp(mItem->name, mPattern) == 0);
-
+ found = ((mItem->nameLength == strlen(mPattern)) &&
+ (memcmp(mItem->Name(), mPattern, mItem->nameLength) == 0));
if (found) {
- *aResult = mItem->name;
+ // Need also to return the name length, as it is NOT zero-terminatdd...
+ *aResult = mItem->Name();
+ *aNameLen = mItem->nameLength;
return NS_OK;
}
}
return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
}
#if defined(XP_UNIX) || defined(XP_BEOS)
@@ -478,102 +489,83 @@ static nsresult ResolveSymlink(const cha
return NS_OK;
}
#endif
//***********************************************************
// nsZipArchive -- private implementation
//***********************************************************
-#define BR_BUF_SIZE 1024 /* backward read buffer size */
-
//---------------------------------------------
// nsZipArchive::CreateZipItem
//---------------------------------------------
-nsZipItem* nsZipArchive::CreateZipItem(PRUint16 namelen)
+nsZipItem* nsZipArchive::CreateZipItem()
{
- // sizeof(nsZipItem) includes space for name's null byte
// Arena allocate the nsZipItem
void *mem;
- PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsZipItem)+namelen);
+ PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsZipItem));
return (nsZipItem*)mem;
}
//---------------------------------------------
// nsZipArchive::BuildFileList
//---------------------------------------------
nsresult nsZipArchive::BuildFileList()
{
// Get archive size using end pos
PRUint8* buf;
- PRUint8* endp = mFd->mFileData + mFd->mLen;
+ PRUint8* startp = mFd->mFileData;
+ PRUint8* endp = startp + mFd->mLen;
for (buf = endp - ZIPEND_SIZE; xtolong(buf) != ENDSIG; buf--)
{
- if (buf == mFd->mFileData) {
+ if (buf == startp) {
// We're at the beginning of the file, and still no sign
// of the end signature. File must be corrupted!
return NS_ERROR_FILE_CORRUPTED;
}
}
- PRUint32 central = xtolong(((ZipEnd *)buf)->offset_central_dir);
+ PRUint32 centralOffset = xtolong(((ZipEnd *)buf)->offset_central_dir);
//-- Read the central directory headers
- buf = mFd->mFileData + central;
+ buf = startp + centralOffset;
PRUint32 sig = xtolong(buf);
while (sig == CENTRALSIG) {
// Make sure there is enough data available.
if (endp - buf < ZIPCENTRAL_SIZE)
return NS_ERROR_FILE_CORRUPTED;
// Read the fixed-size data.
ZipCentral* central = (ZipCentral*)buf;
PRUint16 namelen = xtoint(central->filename_len);
PRUint16 extralen = xtoint(central->extrafield_len);
PRUint16 commentlen = xtoint(central->commentfield_len);
+ // Point to the next item at the top of loop
+ buf += ZIPCENTRAL_SIZE + namelen + extralen + commentlen;
+
// Sanity check variable sizes and refuse to deal with
// anything too big: it's likely a corrupt archive.
- if (namelen > BR_BUF_SIZE || extralen > BR_BUF_SIZE || commentlen > 2*BR_BUF_SIZE)
+ if (namelen > kMaxNameLength || buf >= endp)
return NS_ERROR_FILE_CORRUPTED;
- nsZipItem* item = CreateZipItem(namelen);
+ nsZipItem* item = CreateZipItem();
if (!item)
return NS_ERROR_OUT_OF_MEMORY;
- item->headerOffset = xtolong(central->localhdr_offset);
- item->size = xtolong(central->size);
- item->realsize = xtolong(central->orglen);
- item->crc32 = xtolong(central->crc32);
- item->time = xtoint(central->time);
- item->date = xtoint(central->date);
- item->isSynthetic = PR_FALSE;
- item->compression = PR_MIN(xtoint(central->method), UNSUPPORTED);
- item->mode = ExtractMode(central->external_attributes);
-#if defined(XP_UNIX) || defined(XP_BEOS)
- // Check if item is a symlink
- item->isSymlink = IsSymlink(central->external_attributes);
-#endif
-
- buf += ZIPCENTRAL_SIZE;
-
- // Get the item name
- memcpy(item->name, buf, namelen);
- item->name[namelen] = 0;
- // An item whose name ends with '/' is a directory
- item->isDirectory = ('/' == item->name[namelen - 1]);
+ item->central = central;
+ item->nameLength = namelen;
+ item->isSynthetic = false;
// Add item to file table
- PRUint32 hash = HashName(item->name);
+ PRUint32 hash = HashName(item->Name(), namelen);
item->next = mFiles[hash];
mFiles[hash] = item;
- // Point to the next item at the top of loop
- buf += namelen + extralen + commentlen;
sig = xtolong(buf);
} /* while reading central directory records */
if (sig != ENDSIG)
return NS_ERROR_FILE_CORRUPTED;
return NS_OK;
}
@@ -596,74 +588,50 @@ nsresult nsZipArchive::BuildSynthetics()
continue;
//-- add entries for directories in the current item's path
//-- go from end to beginning, because then we can stop trying
//-- to create diritems if we find that the diritem we want to
//-- create already exists
//-- start just before the last char so as to not add the item
//-- twice if it's a directory
- PRUint16 namelen = strlen(item->name);
- for (char* p = item->name + namelen - 2; p >= item->name; p--)
+ PRUint16 namelen = item->nameLength;
+ const char *name = item->Name();
+ for (PRUint16 dirlen = namelen - 1; dirlen > 0; dirlen--)
{
- if ('/' != *p)
+ if (name[dirlen-1] != '/')
continue;
- // See whether we need to create any more implicit directories,
- // because if we don't we can avoid a lot of work.
- // We can even avoid (de)allocating space for a bogus dirname with
- // a little trickery -- save the char at item->name[dirnamelen],
- // set it to 0, compare the strings, and restore the saved
- // char when done
- const PRUint32 dirnamelen = p + 1 - item->name;
- const char savedChar = item->name[dirnamelen];
- item->name[dirnamelen] = 0;
-
- // Is the directory in the file table?
- PRUint32 hash = HashName(item->name);
+ // Is the directory already in the file table?
+ PRUint32 hash = HashName(item->Name(), dirlen);
PRBool found = PR_FALSE;
for (nsZipItem* zi = mFiles[hash]; zi != NULL; zi = zi->next)
{
- if (0 == strcmp(item->name, zi->name))
+ if ((dirlen == zi->nameLength) &&
+ (0 == memcmp(item->Name(), zi->Name(), dirlen)))
{
// we've already added this dir and all its parents
found = PR_TRUE;
break;
}
}
-
- // restore the char immediately
- item->name[dirnamelen] = savedChar;
-
// if the directory was found, break out of the directory
// creation loop now that we know all implicit directories
// are there -- otherwise, start creating the zip item
if (found)
break;
- nsZipItem* diritem = CreateZipItem(dirnamelen);
+ nsZipItem* diritem = CreateZipItem();
if (!diritem)
return NS_ERROR_OUT_OF_MEMORY;
- memcpy(diritem->name, item->name, dirnamelen);
- diritem->name[dirnamelen] = 0;
-
- diritem->isDirectory = PR_TRUE;
- diritem->isSynthetic = PR_TRUE;
- diritem->compression = STORED;
- diritem->size = diritem->realsize = 0;
- diritem->crc32 = 0;
- diritem->mode = 0755;
-
- // Set an obviously wrong last-modified date/time, because
- // finding something more accurate like the most recent
- // last-modified date/time of the dir's contents is a lot
- // of effort. The date/time corresponds to 1980-01-01 00:00.
- diritem->time = 0;
- diritem->date = 1 + (1 << 5) + (0 << 9);
+ // Point to the central record of the original item for the name part.
+ diritem->central = item->central;
+ diritem->nameLength = dirlen;
+ diritem->isSynthetic = true;
// add diritem to the file table
diritem->next = mFiles[hash];
mFiles[hash] = diritem;
} /* end processing of dirs in item's name */
}
}
return NS_OK;
@@ -680,62 +648,64 @@ nsZipHandle* nsZipArchive::GetFD()
// nsZipArchive::GetData
//---------------------------------------------
PRUint8* nsZipArchive::GetData(nsZipItem* aItem)
{
PR_ASSERT (aItem);
//-- read local header to get variable length values and calculate
//-- the real data offset
- if (aItem->headerOffset + ZIPLOCAL_SIZE > mFd->mLen)
+ PRUint32 len = mFd->mLen;
+ PRUint8* data = mFd->mFileData;
+ PRUint32 offset = aItem->LocalOffset();
+ if (offset + ZIPLOCAL_SIZE > len)
return nsnull;
// -- check signature before using the structure, in case the zip file is corrupt
- ZipLocal* Local = (ZipLocal*)(mFd->mFileData + aItem->headerOffset);
+ ZipLocal* Local = (ZipLocal*)(data + offset);
if ((xtolong(Local->signature) != LOCALSIG))
return nsnull;
//-- NOTE: extralen is different in central header and local header
//-- for archives created using the Unix "zip" utility. To set
//-- the offset accurately we need the _local_ extralen.
- PRUint32 dataOffset = aItem->headerOffset +
- ZIPLOCAL_SIZE +
- xtoint(Local->filename_len) +
- xtoint(Local->extrafield_len);
+ offset += ZIPLOCAL_SIZE +
+ xtoint(Local->filename_len) +
+ xtoint(Local->extrafield_len);
// -- check if there is enough source data in the file
- if (dataOffset + aItem->size > mFd->mLen)
+ if (offset + aItem->Size() > len)
return nsnull;
- return mFd->mFileData + dataOffset;
+ return data + offset;
}
//---------------------------------------------
// nsZipArchive::CopyItemToDisk
//---------------------------------------------
nsresult
nsZipArchive::CopyItemToDisk(nsZipItem *item, PRFileDesc* outFD)
{
PR_ASSERT(item);
//-- get to the start of file's data
const PRUint8* itemData = GetData(item);
if (!itemData)
return NS_ERROR_FILE_CORRUPTED;
- if (outFD && PR_Write(outFD, itemData, item->size) < (READTYPE)item->size)
+ if (outFD && PR_Write(outFD, itemData, item->Size()) < (READTYPE)item->Size())
{
//-- Couldn't write all the data (disk full?)
return NS_ERROR_FILE_DISK_FULL;
}
//-- Calculate crc
- PRUint32 crc = crc32(0L, (const unsigned char*)itemData, item->size);
+ PRUint32 crc = crc32(0L, (const unsigned char*)itemData, item->Size());
//-- verify crc32
- if (crc != item->crc32)
+ if (crc != item->CRC32())
return NS_ERROR_FILE_CORRUPTED;
return NS_OK;
}
//---------------------------------------------
// nsZipArchive::InflateItem
@@ -753,17 +723,17 @@ nsresult nsZipArchive::InflateItem(nsZip
//-- set up the inflate
z_stream zs;
nsresult status = gZlibInit(&zs);
if (status != NS_OK)
return NS_ERROR_FAILURE;
//-- inflate loop
- zs.avail_in = item->size;
+ zs.avail_in = item->Size();
zs.next_in = (Bytef*)GetData(item);
if (!zs.next_in)
return NS_ERROR_FILE_CORRUPTED;
PRUint32 crc = crc32(0L, Z_NULL, 0);
int zerr = Z_OK;
while (zerr == Z_OK)
{
@@ -787,17 +757,17 @@ nsresult nsZipArchive::InflateItem(nsZip
break;
}
} // while
//-- free zlib internal state
inflateEnd(&zs);
//-- verify crc32
- if ((status == NS_OK) && (crc != item->crc32))
+ if ((status == NS_OK) && (crc != item->CRC32()))
{
status = NS_ERROR_FILE_CORRUPTED;
}
return status;
}
//------------------------------------------
// nsZipArchive constructor and destructor
@@ -845,70 +815,100 @@ nsZipFind::~nsZipFind()
// helper functions
//------------------------------------------
/*
* HashName
*
* returns a hash key for the entry name
*/
-static PRUint32 HashName(const char* aName)
+static PRUint32 HashName(const char* aName, PRUint16 len)
{
PR_ASSERT(aName != 0);
+ const PRUint8* p = (const PRUint8*)aName;
+ const PRUint8* endp = p + len;
PRUint32 val = 0;
- for (PRUint8* c = (PRUint8*)aName; *c != 0; c++) {
- val = val*37 + *c;
+ while (p != endp) {
+ val = val*37 + *p++;
}
return (val % ZIP_TABSIZE);
}
/*
* x t o i n t
*
* Converts a two byte ugly endianed integer
* to our platform's integer.
*/
-static PRUint16 xtoint (unsigned char *ii)
+static PRUint16 xtoint (const unsigned char *ii)
{
return (PRUint16) ((ii [0]) | (ii [1] << 8));
}
/*
* x t o l o n g
*
* Converts a four byte ugly endianed integer
* to our platform's integer.
*/
-static PRUint32 xtolong (unsigned char *ll)
+static PRUint32 xtolong (const unsigned char *ll)
{
return (PRUint32)( (ll [0] << 0) |
(ll [1] << 8) |
(ll [2] << 16) |
(ll [3] << 24) );
}
-/*
- * ExtractMode
- *
- * Extracts bits 17-24 from a 32-bit unsigned long
- * representation of the external attributes field.
- * Subsequently it tacks on the implicit user-read
- * bit.
- */
-static PRUint16 ExtractMode(unsigned char *ll)
+PRUint32 const nsZipItem::LocalOffset()
+{
+ return xtolong(central->localhdr_offset);
+}
+
+PRUint32 const nsZipItem::Size()
+{
+ return isSynthetic ? 0 : xtolong(central->size);
+}
+
+PRUint32 const nsZipItem::RealSize()
+{
+ return isSynthetic ? 0 : xtolong(central->orglen);
+}
+
+PRUint32 const nsZipItem::CRC32()
+{
+ return isSynthetic ? 0 : xtolong(central->crc32);
+}
+
+PRUint16 const nsZipItem::Date()
{
- return ((PRUint16)(ll[2])) | 0x0100;
+ return isSynthetic ? kSyntheticDate : xtoint(central->date);
+}
+
+PRUint16 const nsZipItem::Time()
+{
+ return isSynthetic ? kSyntheticTime : xtoint(central->time);
+}
+
+PRUint16 const nsZipItem::Compression()
+{
+ return isSynthetic ? STORED : xtoint(central->method);
+}
+
+bool const nsZipItem::IsDirectory()
+{
+ return isSynthetic || ((nameLength > 0) && ('/' == Name()[nameLength - 1]));
+}
+
+PRUint16 const nsZipItem::Mode()
+{
+ if (isSynthetic) return 0755;
+ return ((PRUint16)(central->external_attributes[2]) | 0x100);
}
#if defined(XP_UNIX) || defined(XP_BEOS)
-/*
- *
- * Return true if the attributes are for a symbolic link
- *
- */
-
-static PRBool IsSymlink(unsigned char *ll)
+bool const nsZipItem::IsSymlink()
{
- return ((xtoint(ll+2) & S_IFMT) == S_IFLNK);
+ if (isSynthetic) return false;
+ return (xtoint(central->external_attributes+2) & S_IFMT) == S_IFLNK;
}
#endif
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -38,26 +38,24 @@
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsZipArchive_h_
#define nsZipArchive_h_
-#define ZIP_MAGIC 0x5A49505FL /* "ZIP_" */
-#define ZIPFIND_MAGIC 0x5A495046L /* "ZIPF" */
#define ZIP_TABSIZE 256
-/* We really want to be a (multiple of) 4K for optimal file IO */
#define ZIP_BUFLEN (4*1024) /* Used as output buffer when deflating items to a file */
-#define PL_ARENA_CONST_ALIGN_MASK 7
+#define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
#include "plarena.h"
#include "zlib.h"
+#include "zipstruct.h"
#include "nsAutoPtr.h"
class nsZipFind;
struct PRFileDesc;
/**
* This file defines some of the basic structures used by libjar to
@@ -75,40 +73,39 @@ struct PRFileDesc;
*/
/**
* nsZipItem -- a helper struct for nsZipArchive
*
* each nsZipItem represents one file in the archive and all the
* information needed to manipulate it.
*/
-struct nsZipItem
+class nsZipItem
{
- nsZipItem* next;
-
- PRUint32 headerOffset;
- PRUint32 size; /* size in original file */
- PRUint32 realsize; /* inflated size */
- PRUint32 crc32;
+public:
+ const char* Name() { return ((const char*)central) + ZIPCENTRAL_SIZE; }
- /*
- * Keep small items together, to avoid overhead.
- */
- PRUint16 time;
- PRUint16 date;
- PRUint16 mode;
- PRUint8 compression;
- bool isDirectory;
- bool isSynthetic; /* whether item is an actual zip entry or was
- generated as part of a real entry's path */
+ PRUint32 const LocalOffset();
+ PRUint32 const Size();
+ PRUint32 const RealSize();
+ PRUint32 const CRC32();
+ PRUint16 const Date();
+ PRUint16 const Time();
+ PRUint16 const Compression();
+ bool const IsDirectory();
+ PRUint16 const Mode();
+
#if defined(XP_UNIX) || defined(XP_BEOS)
- bool isSymlink;
+ bool const IsSymlink();
#endif
- char name[1]; /* actually, bigger than 1 */
+ nsZipItem* next;
+ const ZipCentral* central;
+ PRUint16 nameLength;
+ bool isSynthetic;
};
class nsZipHandle;
/**
* nsZipArchive -- a class for reading the PKZIP file format.
*
*/
@@ -206,17 +203,17 @@ private:
// file handle
nsRefPtr<nsZipHandle> mFd;
//--- private methods ---
nsZipArchive& operator=(const nsZipArchive& rhs); // prevent assignments
nsZipArchive(const nsZipArchive& rhs); // prevent copies
- nsZipItem* CreateZipItem(PRUint16 namelen);
+ nsZipItem* CreateZipItem();
nsresult BuildFileList();
nsresult BuildSynthetics();
nsresult CopyItemToDisk(nsZipItem* item, PRFileDesc* outFD);
nsresult InflateItem(nsZipItem* item, PRFileDesc* outFD);
};
class nsZipHandle {
@@ -247,17 +244,17 @@ private:
* a helper class for nsZipArchive, representing a search
*/
class nsZipFind
{
public:
nsZipFind(nsZipArchive* aZip, char* aPattern, PRBool regExp);
~nsZipFind();
- nsresult FindNext(const char ** aResult);
+ nsresult FindNext(const char** aResult, PRUint16* aNameLen);
private:
nsZipArchive* mArchive;
char* mPattern;
nsZipItem* mItem;
PRUint16 mSlot;
PRPackedBool mRegExp;