Bug 695843 part 5 - Add a FileLocation class to either store a pair (zip, path) or a file, and do some operations on these. r=bsmedberg,mwu
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 08 Dec 2011 11:03:36 +0100
changeset 82247 616b0239a9fbb3297610f433fff79c9351b97aeb
parent 82246 692b6b2207b47648b1b4690c2c7134e3c7590632
child 82248 c5a971a7dc4dd45d6f828399aa3db665ff3d9474
push id21587
push userbmo@edmorley.co.uk
push dateThu, 08 Dec 2011 15:13:43 +0000
treeherdermozilla-central@98db2311a44c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg, mwu
bugs695843
milestone11.0a1
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 695843 part 5 - Add a FileLocation class to either store a pair (zip, path) or a file, and do some operations on these. r=bsmedberg,mwu
modules/libjar/nsZipArchive.cpp
modules/libjar/nsZipArchive.h
xpcom/build/FileLocation.cpp
xpcom/build/FileLocation.h
xpcom/build/Makefile.in
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -201,17 +201,17 @@ nsresult nsZipHandle::Init(nsILocalFile 
   nsRefPtr<nsZipHandle> handle = new nsZipHandle();
   if (!handle) {
     PR_MemUnmap(buf, (PRUint32) size);
     PR_CloseFileMap(map);
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   handle->mMap = map;
-  handle->mFile = file;
+  handle->mFile.Init(file);
   handle->mLen = (PRUint32) size;
   handle->mFileData = buf;
   *ret = handle.forget().get();
   return NS_OK;
 }
 
 nsresult nsZipHandle::Init(nsZipArchive *zip, const char *entry,
                            nsZipHandle **ret)
@@ -223,16 +223,17 @@ nsresult nsZipHandle::Init(nsZipArchive 
   handle->mBuf = new nsZipItemPtr<PRUint8>(zip, entry);
   if (!handle->mBuf)
     return NS_ERROR_OUT_OF_MEMORY;
 
   if (!handle->mBuf->Buffer())
     return NS_ERROR_UNEXPECTED;
 
   handle->mMap = nsnull;
+  handle->mFile.Init(zip, entry);
   handle->mLen = handle->mBuf->Length();
   handle->mFileData = handle->mBuf->Buffer();
   *ret = handle.forget().get();
   return NS_OK;
 }
 
 PRInt64 nsZipHandle::SizeOfMapping()
 {
@@ -274,17 +275,18 @@ nsresult nsZipArchive::OpenArchive(nsZip
     
     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;
-    aZipHandle->mFile->GetLeafName(name);
+    nsCOMPtr<nsILocalFile> file = aZipHandle->mFile.GetBaseFile();
+    file->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;
   }
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -51,16 +51,17 @@
 #endif
 #include "plarena.h"
 
 #include "zlib.h"
 #include "zipstruct.h"
 #include "nsAutoPtr.h"
 #include "nsILocalFile.h"
 #include "mozilla/FileUtils.h"
+#include "mozilla/FileLocation.h"
 
 #if defined(XP_WIN) && defined(_MSC_VER)
 #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("EXCEPTION_IN_PAGE_ERROR in " __FUNCTION__);         \
@@ -397,30 +398,31 @@ public:
     memcpy(ret, mReturnBuf, Length());
     mReturnBuf = NULL;
     return ret;
   }
 };
 
 class nsZipHandle {
 friend class nsZipArchive;
+friend class mozilla::FileLocation;
 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);
 
   PRInt64 SizeOfMapping();
 
 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 */
+  mozilla::FileLocation mFile; /* source file if any, for logging */
 
 private:
   nsZipHandle();
   ~nsZipHandle();
 
   PRFileMap *                       mMap;    /* nspr datastructure for mmap */
   nsAutoPtr<nsZipItemPtr<PRUint8> > mBuf;
   nsrefcnt                          mRefCnt; /* ref count */
new file mode 100644
--- /dev/null
+++ b/xpcom/build/FileLocation.cpp
@@ -0,0 +1,197 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mike Hommey <mh@glandium.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 ***** */
+
+#include "FileLocation.h"
+#include "nsZipArchive.h"
+#include "nsURLHelper.h"
+
+namespace mozilla {
+
+FileLocation::FileLocation(const FileLocation &file, const char *path)
+{
+  if (file.IsZip()) {
+    if (file.mBaseFile) {
+      Init(file.mBaseFile, file.mPath.get());
+    } else {
+      Init(file.mBaseZip, file.mPath.get());
+    }
+    if (path) {
+      PRInt32 i = mPath.RFindChar('/');
+      if (kNotFound == i) {
+        mPath.Truncate(0);
+      } else {
+        mPath.Truncate(i + 1);
+      }
+      mPath += path;
+    }
+  } else {
+    if (path) {
+      nsCOMPtr<nsIFile> cfile;
+      file.mBaseFile->GetParent(getter_AddRefs(cfile));
+      nsCOMPtr<nsILocalFile> clfile = do_QueryInterface(cfile);
+
+#if defined(XP_WIN) || defined(XP_OS2)
+      nsCAutoString pathStr(path);
+      char *p;
+      PRUint32 len = pathStr.GetMutableData(&p);
+      for (; len; ++p, --len) {
+        if ('/' == *p) {
+            *p = '\\';
+        }
+      }
+      clfile->AppendRelativeNativePath(pathStr);
+#else
+      clfile->AppendRelativeNativePath(nsDependentCString(path));
+#endif
+      Init(clfile);
+    } else {
+      Init(file.mBaseFile);
+    }
+  }
+}
+
+void
+FileLocation::GetURIString(nsACString &result) const
+{
+  if (mBaseFile) {
+    net_GetURLSpecFromActualFile(mBaseFile, result);
+  } else if (mBaseZip) {
+    nsRefPtr<nsZipHandle> handler = mBaseZip->GetFD();
+    handler->mFile.GetURIString(result);
+  }
+  if (IsZip()) {
+    result.Insert("jar:", 0);
+    result += "!/";
+    result += mPath;
+  }
+}
+
+already_AddRefed<nsILocalFile>
+FileLocation::GetBaseFile()
+{
+  if (IsZip() && mBaseZip) {
+    nsRefPtr<nsZipHandle> handler = mBaseZip->GetFD();
+    if (handler)
+      return handler->mFile.GetBaseFile();
+    return NULL;
+  }
+
+  nsCOMPtr<nsILocalFile> file = mBaseFile;
+  return file.forget();
+}
+
+bool
+FileLocation::Equals(const FileLocation &file) const
+{
+  if (mPath != file.mPath)
+    return false;
+
+  if (mBaseFile && file.mBaseFile) {
+    bool eq;
+    return NS_SUCCEEDED(mBaseFile->Equals(file.mBaseFile, &eq)) && eq;
+  }
+
+  const FileLocation *a = this, *b = &file;
+  if (a->mBaseZip) {
+    nsRefPtr<nsZipHandle> handler = a->mBaseZip->GetFD();
+    a = &handler->mFile;
+  }
+  if (b->mBaseZip) {
+    nsRefPtr<nsZipHandle> handler = b->mBaseZip->GetFD();
+    b = &handler->mFile;
+  }
+  return a->Equals(*b);
+}
+
+nsresult
+FileLocation::GetData(Data &data)
+{
+  if (!IsZip()) {
+    return mBaseFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &data.mFd);
+  }
+  data.mZip = mBaseZip;
+  if (!data.mZip) {
+    data.mZip = new nsZipArchive();
+    data.mZip->OpenArchive(mBaseFile);
+  }
+  data.mItem = data.mZip->GetItem(mPath.get());
+  if (data.mItem)
+    return NS_OK;
+  return NS_ERROR_FILE_UNRECOGNIZED_PATH;
+}
+
+nsresult
+FileLocation::Data::GetSize(PRUint32 *result)
+{
+  if (mFd) {
+    PRFileInfo64 fileInfo;
+    if (PR_SUCCESS != PR_GetOpenFileInfo64(mFd, &fileInfo))
+      return NS_ErrorAccordingToNSPR();
+
+    if (fileInfo.size > PRInt64(PR_UINT32_MAX))
+      return NS_ERROR_FILE_TOO_BIG;
+
+    *result = fileInfo.size;
+    return NS_OK;
+  } else if (mItem) {
+    *result = mItem->RealSize();
+    return NS_OK;
+  }
+  return NS_ERROR_NOT_INITIALIZED;
+}
+
+nsresult
+FileLocation::Data::Copy(char *buf, PRUint32 len)
+{
+  if (mFd) {
+    for (PRUint32 totalRead = 0; totalRead < len; ) {
+      PRInt32 read = PR_Read(mFd, buf + totalRead, NS_MIN(len - totalRead, PRUint32(PR_INT32_MAX)));
+      if (read < 0)
+        return NS_ErrorAccordingToNSPR();
+      totalRead += read;
+    }
+    return NS_OK;
+  } else if (mItem) {
+    nsZipCursor cursor(mItem, mZip, reinterpret_cast<PRUint8 *>(buf), len, true);
+    PRUint32 readLen;
+    cursor.Copy(&readLen);
+    return (readLen == len) ? NS_OK : NS_ERROR_FILE_CORRUPTED;
+  }
+  return NS_ERROR_NOT_INITIALIZED;
+}
+
+} /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/xpcom/build/FileLocation.h
@@ -0,0 +1,198 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mike Hommey <mh@glandium.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 mozilla_FileLocation_h
+#define mozilla_FileLocation_h
+
+#include "nsString.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsILocalFile.h"
+#include "nsIURI.h"
+#include "FileUtils.h"
+
+class nsZipArchive;
+class nsZipItem;
+
+namespace mozilla {
+
+class FileLocation
+{
+public:
+  /**
+   * FileLocation is an helper to handle different kind of file locations
+   * within Gecko:
+   * - on filesystems
+   * - in archives
+   * - in archives within archives
+   * As such, it stores a path within an archive, as well as the archive
+   * path itself, or the complete file path alone when on a filesystem.
+   * When the archive is in an archive, an nsZipArchive is stored instead
+   * of a file path.
+   */
+  FileLocation() { }
+
+  /**
+   * Constructor for plain files
+   */
+  FileLocation(nsILocalFile *file)
+  {
+    Init(file);
+  }
+
+  /**
+   * Constructors for path within an archive. The archive can be given either
+   * as nsILocalFile or nsZipArchive.
+   */
+  FileLocation(nsILocalFile *zip, const char *path)
+  {
+    Init(zip, path);
+  }
+
+  FileLocation(nsZipArchive *zip, const char *path)
+  {
+    Init(zip, path);
+  }
+
+  /**
+   * Creates a new file location relative to another one.
+   */
+  FileLocation(const FileLocation &file, const char *path = NULL);
+
+  /**
+   * Initialization functions corresponding to constructors
+   */
+  void Init(nsILocalFile *file)
+  {
+    mBaseZip = NULL;
+    mBaseFile = file;
+    mPath.Truncate();
+  }
+
+  void Init(nsILocalFile *zip, const char *path)
+  {
+    mBaseZip = NULL;
+    mBaseFile = zip;
+    mPath = path;
+  }
+
+  void Init(nsZipArchive *zip, const char *path)
+  {
+    mBaseZip = zip;
+    mBaseFile = NULL;
+    mPath = path;
+  }
+
+  /**
+   * Returns an URI string corresponding to the file location
+   */
+  void GetURIString(nsACString &result) const;
+
+  /**
+   * Returns the base file of the location, where base file is defined as:
+   * - The file itself when the location is on a filesystem
+   * - The archive file when the location is in an archive
+   * - The outer archive file when the location is in an archive in an archive
+   */
+  already_AddRefed<nsILocalFile> GetBaseFile();
+
+  /**
+   * Returns whether the "base file" (see GetBaseFile) is an archive
+   */
+  bool IsZip() const
+  {
+    return !mPath.IsEmpty();
+  }
+
+  /**
+   * Returns the path within the archive, when within an archive
+   */
+  void GetPath(nsACString &result) const
+  {
+    result = mPath;
+  }
+
+  /**
+   * Boolean value corresponding to whether the file location is initialized
+   * or not.
+   */
+  operator bool() const
+  {
+    return mBaseFile || mBaseZip;
+  }
+
+  /**
+   * Returns whether another FileLocation points to the same resource
+   */
+  bool Equals(const FileLocation &file) const;
+
+  /**
+   * Data associated with a FileLocation.
+   */
+  class Data
+  {
+  public:
+    /**
+     * Returns the data size
+     */
+    nsresult GetSize(PRUint32 *result);
+
+    /**
+     * Copies the data in the given buffer
+     */
+    nsresult Copy(char *buf, PRUint32 len);
+  protected:
+    friend class FileLocation;
+    nsZipItem *mItem;
+    nsRefPtr<nsZipArchive> mZip;
+    mozilla::AutoFDClose mFd;
+  };
+
+  /**
+   * Returns the data associated with the resource pointed at by the file
+   * location.
+   */
+  nsresult GetData(Data &data);
+private:
+  nsCOMPtr<nsILocalFile> mBaseFile;
+  nsRefPtr<nsZipArchive> mBaseZip;
+  nsCString mPath;
+}; /* class FileLocation */
+
+} /* namespace mozilla */
+
+#endif /* mozilla_FileLocation_h */
--- a/xpcom/build/Makefile.in
+++ b/xpcom/build/Makefile.in
@@ -54,24 +54,25 @@ EXPORT_LIBRARY = 1
 
 GRE_MODULE	= 1
 MOZILLA_INTERNAL_API = 1
 
 ifeq ($(OS_ARCH),Linux)
 DEFINES += -DXP_LINUX
 endif
 
-CPPSRCS		= \
-		$(XPCOM_GLUE_SRC_LCPPSRCS) \
-		$(XPCOM_GLUENS_SRC_LCPPSRCS) \
-		nsXPComInit.cpp \
-		nsXPCOMStrings.cpp \
-		Services.cpp \
-		Omnijar.cpp \
-		$(NULL)
+CPPSRCS = \
+  $(XPCOM_GLUE_SRC_LCPPSRCS) \
+  $(XPCOM_GLUENS_SRC_LCPPSRCS) \
+  nsXPComInit.cpp \
+  nsXPCOMStrings.cpp \
+  Services.cpp \
+  Omnijar.cpp \
+  FileLocation.cpp \
+  $(NULL)
 
 SHARED_LIBRARY_LIBS = \
 		$(DEPTH)/chrome/src/$(LIB_PREFIX)chrome_s.$(LIB_SUFFIX) \
 		../ds/$(LIB_PREFIX)xpcomds_s.$(LIB_SUFFIX) \
 		../io/$(LIB_PREFIX)xpcomio_s.$(LIB_SUFFIX) \
 		../components/$(LIB_PREFIX)xpcomcomponents_s.$(LIB_SUFFIX) \
 		../threads/$(LIB_PREFIX)xpcomthreads_s.$(LIB_SUFFIX) \
 		../proxy/src/$(LIB_PREFIX)xpcomproxy_s.$(LIB_SUFFIX) \
@@ -118,16 +119,17 @@ EXPORTS	= \
   nsXULAppAPI.h \
   $(NULL)
 
 EXPORTS_mozilla = \
   XPCOM.h \
   Services.h \
   ServiceList.h \
   Omnijar.h \
+  FileLocation.h \
   $(NULL)
 
 
 GARBAGE         += $(XPCOM_GLUE_SRC_LCPPSRCS) $(XPCOM_GLUENS_SRC_LCPPSRCS) $(wildcard *.$(OBJ_SUFFIX))
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk