Bug 511754 - make nsZipItems point at ZipCentral references to mmapped jar area r=tglek
authorAlfred Kayser <alfredkayser@gmail.com>
Sat, 17 Oct 2009 17:54:54 +0200
changeset 33990 092b0f9e39a3e3ff5dcc6b92146e0f3a8ecefa88
parent 33989 06cecc61ffeb269dc03b86272cfb33e4c0479626
child 33997 345e1c07d64db201ff0ed16dbab4486e371f58fd
push idunknown
push userunknown
push dateunknown
reviewerstglek
bugs511754
milestone1.9.3a1pre
Bug 511754 - make nsZipItems point at ZipCentral references to mmapped jar area r=tglek
modules/libjar/nsJAR.cpp
modules/libjar/nsJAR.h
modules/libjar/nsJARInputStream.cpp
modules/libjar/nsZipArchive.cpp
modules/libjar/nsZipArchive.h
--- 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;