Bug 533038 - 2. Generalize nsZipArchive and nsZipHandle to read from different sources, r=taras a=blocking-beta6
authorMichael Wu <mwu@mozilla.com>
Wed, 08 Sep 2010 20:37:34 -0700
changeset 52249 4958e6add3c936fe32cffccfe6b2377c766cc9e8
parent 52248 203419a57194e54853acb780adcbbb732d9fffe3
child 52250 b32655a792347a55bd5831f8250805d3b936cb2f
push id15580
push usermwu@mozilla.com
push dateThu, 09 Sep 2010 03:42:33 +0000
treeherdermozilla-central@a26593abc145 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstaras, blocking-beta6
bugs533038
milestone2.0b6pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 533038 - 2. Generalize nsZipArchive and nsZipHandle to read from different sources, r=taras a=blocking-beta6
modules/libjar/nsJARInputStream.cpp
modules/libjar/nsZipArchive.cpp
modules/libjar/nsZipArchive.h
startupcache/StartupCache.cpp
--- a/modules/libjar/nsJARInputStream.cpp
+++ b/modules/libjar/nsJARInputStream.cpp
@@ -83,17 +83,17 @@ nsJARInputStream::InitFile(nsJAR *aJar, 
            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.next_in = (Bytef *)aJar->mZip.GetData(item);
     if (!mZs.next_in)
         return NS_ERROR_FILE_CORRUPTED;
     mZs.avail_in = item->Size();
     mOutSize = item->RealSize();
     mZs.total_out = 0;
     return NS_OK;
 }
 
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -170,109 +170,137 @@ nsZipHandle::nsZipHandle()
   , mRefCnt(0)
 {
   MOZ_COUNT_CTOR(nsZipHandle);
 }
 
 NS_IMPL_THREADSAFE_ADDREF(nsZipHandle)
 NS_IMPL_THREADSAFE_RELEASE(nsZipHandle)
 
-nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret)
+nsresult nsZipHandle::Init(nsILocalFile *file, nsZipHandle **ret)
 {
+  mozilla::AutoFDClose fd;
+  nsresult rv = file->OpenNSPRFileDesc(PR_RDONLY, 0000, &fd);
+  if (NS_FAILED(rv))
+    return rv;
+
   PRInt64 size = PR_Available64(fd);
   if (size >= PR_INT32_MAX)
     return NS_ERROR_FILE_TOO_BIG;
 
   PRFileMap *map = PR_CreateFileMap(fd, size, PR_PROT_READONLY);
   if (!map)
     return NS_ERROR_FAILURE;
   
   PRUint8 *buf = (PRUint8*) PR_MemMap(map, 0, (PRUint32) size);
   // Bug 525755: PR_MemMap fails when fd points at something other than a normal file.
   if (!buf) {
     PR_CloseFileMap(map);
     return NS_ERROR_FAILURE;
   }
 
-  nsZipHandle *handle = new nsZipHandle();
+  nsRefPtr<nsZipHandle> handle = new nsZipHandle();
   if (!handle) {
     PR_MemUnmap(buf, size);
     PR_CloseFileMap(map);
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   handle->mMap = map;
+  handle->mFile = file;
   handle->mLen = (PRUint32) size;
   handle->mFileData = buf;
-  handle->AddRef();
-  *ret = handle;
+  *ret = handle.forget().get();
+  return NS_OK;
+}
+
+nsresult nsZipHandle::Init(nsZipArchive *zip, const char *entry,
+                           nsZipHandle **ret)
+{
+  nsRefPtr<nsZipHandle> handle = new nsZipHandle();
+  if (!handle)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  handle->mBuf = new nsZipItemPtr<PRUint8>(zip, entry);
+  if (!handle->mBuf)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  handle->mMap = nsnull;
+  handle->mLen = handle->mBuf->Length();
+  handle->mFileData = handle->mBuf->Buffer();
+  *ret = handle.forget().get();
   return NS_OK;
 }
 
 nsZipHandle::~nsZipHandle()
 {
-  if (mFileData) {
-    PR_MemUnmap(mFileData, mLen);
+  if (mMap) {
+    PR_MemUnmap((void *)mFileData, mLen);
     PR_CloseFileMap(mMap);
-    mFileData = nsnull;
-    mMap = nsnull;
   }
+  mFileData = nsnull;
+  mMap = nsnull;
+  mBuf = nsnull;
   MOZ_COUNT_DTOR(nsZipHandle);
 }
 
 //***********************************************************
 //      nsZipArchive  --  public methods
 //***********************************************************
 
 //---------------------------------------------
 //  nsZipArchive::OpenArchive
 //---------------------------------------------
-nsresult nsZipArchive::OpenArchive(nsIFile *aZipFile)
+nsresult nsZipArchive::OpenArchive(nsZipHandle *aZipHandle)
 {
-  nsresult rv;
-  nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aZipFile, &rv);
-  if (NS_FAILED(rv)) return rv;
-
-  PRFileDesc* fd;
-  rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0000, &fd);
-  if (NS_FAILED(rv)) return rv;
-
-  rv = nsZipHandle::Init(fd, getter_AddRefs(mFd));
-  PR_Close(fd);
-  if (NS_FAILED(rv))
-    return rv;
+  mFd = aZipHandle;
 
   // Initialize our arena
   PL_INIT_ARENA_POOL(&mArena, "ZipArena", ZIP_ARENABLOCKSIZE);
 
   //-- get table of contents for archive
-  rv = BuildFileList();
+  nsresult rv = BuildFileList();
   char *env = PR_GetEnv("MOZ_JAR_LOG_DIR");
-  if (env && NS_SUCCEEDED(rv)) {
+  if (env && NS_SUCCEEDED(rv) && aZipHandle->mFile) {
     nsCOMPtr<nsILocalFile> logFile;
     nsresult rv2 = NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), PR_FALSE, getter_AddRefs(logFile));
     
     if (!NS_SUCCEEDED(rv2))
       return rv;
 
     // Create a directory for the log (in case it doesn't exist)
     logFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
 
     nsAutoString name;
-    localFile->GetLeafName(name);
+    aZipHandle->mFile->GetLeafName(name);
     name.Append(NS_LITERAL_STRING(".log"));
     logFile->Append(name);
 
+    PRFileDesc* fd;
     rv2 = logFile->OpenNSPRFileDesc(PR_WRONLY|PR_CREATE_FILE|PR_APPEND, 0644, &fd);
     if (NS_SUCCEEDED(rv2))
       mLog = fd;
   }
   return rv;
 }
 
+nsresult nsZipArchive::OpenArchive(nsIFile *aFile)
+{
+  nsresult rv;
+  nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsRefPtr<nsZipHandle> handle;
+  rv = nsZipHandle::Init(localFile, getter_AddRefs(handle));
+  if (NS_FAILED(rv))
+    return rv;
+
+  return OpenArchive(handle);
+}
+
 //---------------------------------------------
 //  nsZipArchive::Test
 //---------------------------------------------
 nsresult nsZipArchive::Test(const char *aEntryName)
 {
   nsZipItem* currItem;
 
   if (aEntryName) // only test specified item
@@ -557,19 +585,19 @@ nsZipItem* nsZipArchive::CreateZipItem()
 //---------------------------------------------
 //  nsZipArchive::BuildFileList
 //---------------------------------------------
 nsresult nsZipArchive::BuildFileList()
 {
   NS_TIME_FUNCTION;
 
   // Get archive size using end pos
-  PRUint8* buf;
-  PRUint8* startp = mFd->mFileData;
-  PRUint8* endp = startp + mFd->mLen;
+  const PRUint8* buf;
+  const PRUint8* startp = mFd->mFileData;
+  const PRUint8* endp = startp + mFd->mLen;
   
   PRUint32 centralOffset = 1;
   if (mFd->mLen > ZIPCENTRAL_SIZE && *(PRUint32*)(startp + centralOffset) == CENTRALSIG) {
     // Success means optimized jar layout from bug 559961 is in effect
   } else {
     for (buf = endp - ZIPEND_SIZE; buf > startp; buf--)
       {
         if (xtolong(buf) == ENDSIG) {
@@ -701,23 +729,23 @@ nsZipHandle* nsZipArchive::GetFD()
   if (!mFd)
     return NULL;
   return mFd.get();
 }
 
 //---------------------------------------------
 // nsZipArchive::GetData
 //---------------------------------------------
-PRUint8* nsZipArchive::GetData(nsZipItem* aItem)
+const PRUint8* nsZipArchive::GetData(nsZipItem* aItem)
 {
   PR_ASSERT (aItem);
   //-- read local header to get variable length values and calculate
   //-- the real data offset
   PRUint32 len = mFd->mLen;
-  PRUint8* data = mFd->mFileData;
+  const 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*)(data + offset);
   if ((xtolong(Local->signature) != LOCALSIG))
     return nsnull;
@@ -732,17 +760,17 @@ PRUint8* nsZipArchive::GetData(nsZipItem
   // -- check if there is enough source data in the file
   if (offset + aItem->Size() > len)
     return nsnull;
 
   return data + offset;
 }
 
 PRBool 
-nsZipArchive::CheckCRC(nsZipItem* aItem, PRUint8* aItemData) {
+nsZipArchive::CheckCRC(nsZipItem* aItem, const PRUint8* aItemData) {
   PRUint32 crc = crc32(0, (const unsigned char*)aItemData, aItem->Size());
   return crc == aItem->CRC32();
 }
 
 //------------------------------------------
 // nsZipArchive constructor and destructor
 //------------------------------------------
 
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -128,20 +128,30 @@ public:
 
   /** 
    * 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   fd            File descriptor of file to open
+   * @param   aZipHandle  The nsZipHandle used to access the zip
    * @return  status code
    */
-  nsresult OpenArchive(nsIFile *aZipFile);
+  nsresult OpenArchive(nsZipHandle *aZipHandle);
+
+  /** 
+   * 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.
    *
@@ -191,19 +201,19 @@ public:
    */
   nsZipHandle* GetFD();
 
   /**
    * Get pointer to the data of the item.
    * @param   aItem       Pointer to nsZipItem
    * reutrns null when zip file is corrupt.
    */
-  PRUint8* GetData(nsZipItem* aItem);
+  const PRUint8* GetData(nsZipItem* aItem);
 
-  PRBool CheckCRC(nsZipItem* aItem, PRUint8* aData);
+  PRBool CheckCRC(nsZipItem* aItem, const PRUint8* aData);
 
 private:
   //--- private members ---
 
   nsZipItem*    mFiles[ZIP_TABSIZE];
   PLArenaPool   mArena;
 
   // Whether we synthesized the directory entries
@@ -220,37 +230,16 @@ private:
   nsZipArchive& operator=(const nsZipArchive& rhs); // prevent assignments
   nsZipArchive(const nsZipArchive& rhs);            // prevent copies
 
   nsZipItem*        CreateZipItem();
   nsresult          BuildFileList();
   nsresult          BuildSynthetics();
 };
 
-class nsZipHandle {
-friend class nsZipArchive;
-public:
-  static nsresult Init(PRFileDesc *fd, nsZipHandle **ret NS_OUTPARAM);
-
-  NS_METHOD_(nsrefcnt) AddRef(void);
-  NS_METHOD_(nsrefcnt) Release(void);
-
-protected:
-  PRUint8 *    mFileData; /* pointer to mmaped file */
-  PRUint32     mLen;      /* length of file and memory mapped area */
-
-private:
-  nsZipHandle();
-  ~nsZipHandle();
-
-  PRFileMap *  mMap;      /* nspr datastructure for mmap */
-  nsrefcnt     mRefCnt;   /* ref count */
-};
-
-
 /** 
  * nsZipFind 
  *
  * a helper class for nsZipArchive, representing a search
  */
 class nsZipFind
 {
 public:
@@ -303,17 +292,17 @@ private:
   nsZipItem *mItem; 
   PRUint8  *mBuf; 
   PRUint32  mBufSize; 
   z_stream  mZs;
   PRUint32 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:
   /**
@@ -348,11 +337,35 @@ public:
     return (const T*)mReturnBuf;
   }
 
   operator const T*() const {
     return Buffer();
   }
 };
 
+class nsZipHandle {
+friend class nsZipArchive;
+public:
+  static nsresult Init(nsILocalFile *file, nsZipHandle **ret NS_OUTPARAM);
+  static nsresult Init(nsZipArchive *zip, const char *entry,
+                       nsZipHandle **ret NS_OUTPARAM);
+
+  NS_METHOD_(nsrefcnt) AddRef(void);
+  NS_METHOD_(nsrefcnt) Release(void);
+
+protected:
+  const PRUint8 * mFileData; /* pointer to mmaped file */
+  PRUint32        mLen;      /* length of file and memory mapped area */
+  nsCOMPtr<nsILocalFile> mFile; /* source file if any, for logging */
+
+private:
+  nsZipHandle();
+  ~nsZipHandle();
+
+  PRFileMap *                       mMap;    /* nspr datastructure for mmap */
+  nsAutoPtr<nsZipItemPtr<PRUint8> > mBuf;
+  nsrefcnt                          mRefCnt; /* ref count */
+};
+
 nsresult gZlibInit(z_stream *zs);
 
 #endif /* nsZipArchive_h_ */
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -219,17 +219,17 @@ StartupCache::GetBuffer(const char* id, 
       data = entry->data;
       len = entry->size;
     }
   }
 
   if (!data && mArchive) {
     nsZipItem* zipItem = mArchive->GetItem(id);
     if (zipItem) {
-      PRUint8* itemData = mArchive->GetData(zipItem);
+      const PRUint8* itemData = mArchive->GetData(zipItem);
       if (!itemData || !mArchive->CheckCRC(zipItem, itemData)) {
         NS_WARNING("StartupCache file corrupted!");
         InvalidateCache();
         return NS_ERROR_FILE_CORRUPTED;
       }
 
       len = zipItem->Size();
       data = (char*) itemData;