Bug 772434 - Blob support for Zip file contents, r=jst
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 27 Jul 2012 17:21:34 -0700
changeset 100792 5bff8785ab1b17476f6cb37c03522f460b94cb6b
parent 100791 6ec566153ef80a9910a295df3159674a321bceaf
child 100793 e0e33c1c7c17aeff411248076b5280011a138d26
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjst
bugs772434
milestone17.0a1
Bug 772434 - Blob support for Zip file contents, r=jst
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/file/ArchiveEvent.cpp
dom/file/ArchiveEvent.h
dom/file/ArchiveReader.cpp
dom/file/ArchiveReader.h
dom/file/ArchiveRequest.cpp
dom/file/ArchiveRequest.h
dom/file/ArchiveZipEvent.cpp
dom/file/ArchiveZipEvent.h
dom/file/ArchiveZipFile.cpp
dom/file/ArchiveZipFile.h
dom/file/Makefile.in
dom/file/nsIDOMArchiveReader.idl
dom/file/nsIDOMArchiveRequest.idl
dom/file/test/Makefile.in
dom/file/test/test_archivereader.html
dom/tests/mochitest/general/test_interfaces.html
layout/build/Makefile.in
layout/build/nsLayoutModule.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -435,16 +435,18 @@
 #endif
 
 // Workers
 #include "mozilla/dom/workers/Workers.h"
 
 #include "nsDOMFile.h"
 #include "nsDOMFileReader.h"
 #include "nsIDOMFormData.h"
+#include "ArchiveReader.h"
+#include "ArchiveRequest.h"
 
 #include "nsIDOMDOMStringMap.h"
 
 #include "nsIDOMDesktopNotification.h"
 #include "nsIDOMNavigatorDesktopNotification.h"
 #include "nsIDOMNavigatorDeviceStorage.h"
 #include "nsIDOMNavigatorGeolocation.h"
 #include "Navigator.h"
@@ -1399,16 +1401,20 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(FileList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(Blob, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(File, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(FileReader, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(ArchiveReader, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(ArchiveRequest, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozURLProperty, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozBlobBuilder, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DOMStringMap, nsDOMStringMapSH,
                            DOMSTRINGMAP_SCRIPTABLE_FLAGS)
 
@@ -1689,16 +1695,17 @@ struct nsContractIDMapData
 
 #define NS_DEFINE_CONSTRUCTOR_DATA(_class, _contract_id)                      \
   { eDOMClassInfo_##_class##_id, _contract_id },
 
 static const nsContractIDMapData kConstructorMap[] =
 {
   NS_DEFINE_CONSTRUCTOR_DATA(DOMParser, NS_DOMPARSER_CONTRACTID)
   NS_DEFINE_CONSTRUCTOR_DATA(FileReader, NS_FILEREADER_CONTRACTID)
+  NS_DEFINE_CONSTRUCTOR_DATA(ArchiveReader, NS_ARCHIVEREADER_CONTRACTID)
   NS_DEFINE_CONSTRUCTOR_DATA(FormData, NS_FORMDATA_CONTRACTID)
   NS_DEFINE_CONSTRUCTOR_DATA(XMLSerializer, NS_XMLSERIALIZER_CONTRACTID)
   NS_DEFINE_CONSTRUCTOR_DATA(WebSocket, NS_WEBSOCKET_CONTRACTID)
   NS_DEFINE_CONSTRUCTOR_DATA(XPathEvaluator, NS_XPATH_EVALUATOR_CONTRACTID)
   NS_DEFINE_CONSTRUCTOR_DATA(XSLTProcessor,
                              "@mozilla.org/document-transformer;1?type=xslt")
   NS_DEFINE_CONSTRUCTOR_DATA(EventSource, NS_EVENTSOURCE_CONTRACTID)
   NS_DEFINE_CONSTRUCTOR_DATA(MutationObserver, NS_DOMMUTATIONOBSERVER_CONTRACTID)
@@ -3981,16 +3988,25 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMFile)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(FileReader, nsIDOMFileReader)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileReader)
     DOM_CLASSINFO_MAP_ENTRY(nsIInterfaceRequestor)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(ArchiveReader, nsIDOMArchiveReader)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMArchiveReader)
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(ArchiveRequest, nsIDOMArchiveRequest)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMArchiveRequest)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(MozURLProperty, nsIDOMMozURLProperty)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozURLProperty)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozBlobBuilder, nsIDOMMozBlobBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozBlobBuilder)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -362,16 +362,18 @@ DOMCI_CLASS(SVGForeignObjectElement)
 DOMCI_CLASS(XULCommandEvent)
 DOMCI_CLASS(CommandEvent)
 DOMCI_CLASS(OfflineResourceList)
 
 DOMCI_CLASS(FileList)
 DOMCI_CLASS(Blob)
 DOMCI_CLASS(File)
 DOMCI_CLASS(FileReader)
+DOMCI_CLASS(ArchiveReader)
+DOMCI_CLASS(ArchiveRequest)
 DOMCI_CLASS(MozURLProperty)
 DOMCI_CLASS(MozBlobBuilder)
 
 DOMCI_CLASS(DOMStringMap)
 
 // DOM modal content window class, almost identical to Window
 DOMCI_CLASS(ModalContentWindow)
 
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveEvent.cpp
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ArchiveEvent.h"
+
+#include "nsContentUtils.h"
+#include "nsCExternalHandlerService.h"
+
+USING_FILE_NAMESPACE
+
+NS_IMPL_THREADSAFE_ISUPPORTS0(ArchiveItem)
+
+ArchiveItem::~ArchiveItem()
+{
+}
+
+
+nsCString
+ArchiveItem::GetType()
+{
+  return mType.IsEmpty() ? nsCString("binary/octet-stream") : mType;
+}
+
+void
+ArchiveItem::SetType(const nsCString& aType)
+{
+  mType = aType;
+}
+
+ArchiveReaderEvent::ArchiveReaderEvent(ArchiveReader* aArchiveReader)
+: mArchiveReader(aArchiveReader)
+{
+  MOZ_COUNT_CTOR(ArchiveReaderEvent);
+}
+
+ArchiveReaderEvent::~ArchiveReaderEvent()
+{
+  MOZ_COUNT_DTOR(ArchiveReaderEvent);
+}
+
+// From the filename to the mimetype:
+nsresult
+ArchiveReaderEvent::GetType(nsCString& aExt,
+                            nsCString& aMimeType)
+{
+  nsresult rv;
+  
+  if (mMimeService.get() == nsnull) {
+    mMimeService = do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = mMimeService->GetTypeFromExtension(aExt, aMimeType);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ArchiveReaderEvent::Run()
+{
+  return Exec();
+}
+
+nsresult
+ArchiveReaderEvent::RunShare(nsresult aStatus)
+{
+  mStatus = aStatus;
+
+  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &ArchiveReaderEvent::ShareMainThread);
+  NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
+
+  return NS_OK;
+}
+
+void
+ArchiveReaderEvent::ShareMainThread()
+{
+  nsTArray<nsCOMPtr<nsIDOMFile> > fileList;
+
+  if (!NS_FAILED(mStatus)) {
+    // This extra step must run in the main thread:
+    for (PRUint32 index = 0; index < mFileList.Length(); ++index) {
+      nsRefPtr<ArchiveItem> item = mFileList[index];
+
+      PRInt32 offset = item->GetFilename().RFindChar('.');
+      if (offset != kNotFound) {
+        nsCString ext(item->GetFilename());
+        ext.Cut(0, offset + 1);
+
+        // Just to be sure, if something goes wrong, the mimetype is an empty string:
+        nsCString type;
+        if (GetType(ext, type) == NS_OK)
+          item->SetType(type);
+      }
+
+      // This is a nsDOMFile:
+      nsRefPtr<nsIDOMFile> file = item->File(mArchiveReader);
+      fileList.AppendElement(file);
+    }
+  }
+
+  mArchiveReader->Ready(fileList, mStatus);
+}
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveEvent.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_file_domarchiveevent_h__
+#define mozilla_dom_file_domarchiveevent_h__
+
+#include "ArchiveReader.h"
+
+#include "nsISeekableStream.h"
+#include "nsIMIMEService.h"
+#include "nsDOMFile.h"
+
+#include "FileCommon.h"
+
+BEGIN_FILE_NAMESPACE
+
+// This class contains all the info needed for a single item
+// It must contain the implementation of the File() method.
+class ArchiveItem : public nsISupports
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  virtual ~ArchiveItem();
+
+  // Getter/Setter for the type
+  virtual nsCString GetType();
+  virtual void SetType(const nsCString& aType);
+
+  // Getter for the filename
+  virtual nsCString GetFilename() = 0;
+
+  // Generate a DOMFile
+  virtual nsIDOMFile* File(ArchiveReader* aArchiveReader) = 0;
+
+protected:
+  nsCString mType;
+};
+
+// This class must be extended by any archive format supported by ArchiveReader API
+// This class runs in a different thread and it calls the 'exec()' method.
+// The exec() must populate mFileList and mStatus then it must call RunShare();
+class ArchiveReaderEvent : public nsRunnable
+{
+public:
+  NS_DECL_NSIRUNNABLE
+
+  ArchiveReaderEvent(ArchiveReader* aArchiveReader);
+
+  virtual ~ArchiveReaderEvent();
+
+  // This must be implemented
+  virtual nsresult Exec() = 0;
+
+protected:
+  nsresult GetType(nsCString& aExt,
+                   nsCString& aMimeType);
+
+  nsresult RunShare(nsresult aStatus);
+  void ShareMainThread();
+
+protected: // data
+  ArchiveReader* mArchiveReader;
+
+  nsCOMPtr<nsIMIMEService> mMimeService;
+
+  nsTArray<nsRefPtr<ArchiveItem> > mFileList; // this must be populated
+  nsresult mStatus;
+};
+
+END_FILE_NAMESPACE
+
+#endif // mozilla_dom_file_domarchiveevent_h__
+
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveReader.cpp
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ArchiveReader.h"
+#include "ArchiveRequest.h"
+#include "ArchiveEvent.h"
+#include "ArchiveZipEvent.h"
+
+#include "nsContentUtils.h"
+#include "nsLayoutStatics.h"
+#include "nsDOMClassInfoID.h"
+
+#include "nsIURI.h"
+#include "nsNetUtil.h"
+
+USING_FILE_NAMESPACE
+
+ArchiveReader::ArchiveReader()
+: mBlob(nsnull),
+  mWindow(nsnull),
+  mStatus(NOT_STARTED)
+{
+  nsLayoutStatics::AddRef();
+}
+
+ArchiveReader::~ArchiveReader()
+{
+  nsLayoutStatics::Release();
+}
+
+NS_IMETHODIMP
+ArchiveReader::Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          JS::Value* aArgv)
+{
+  NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
+
+  // We expect to get a Blob object
+  if (!aArgv[0].isObject()) {
+    return NS_ERROR_UNEXPECTED; // We're not interested
+  }
+
+  JSObject* obj = &aArgv[0].toObject();
+
+  nsCOMPtr<nsIDOMBlob> blob;
+  blob = do_QueryInterface(nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj));
+  if (!blob) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  mBlob = blob;
+
+  mWindow = do_QueryInterface(aOwner);
+  if (!mWindow) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+ArchiveReader::RegisterRequest(ArchiveRequest* aRequest)
+{
+  switch (mStatus) {
+    // Append to the list and let's start to work:
+    case NOT_STARTED:
+      mRequests.AppendElement(aRequest);
+      return OpenArchive();
+
+    // Just append to the list:
+    case WORKING:
+      mRequests.AppendElement(aRequest);
+      return NS_OK;
+
+    // Return data!
+    case READY:
+      RequestReady(aRequest);
+      return NS_OK;
+  }
+
+  NS_ASSERTION(false, "unexpected mStatus value");
+  return NS_OK;
+}
+
+// This returns the input stream
+nsresult
+ArchiveReader::GetInputStream(nsIInputStream** aInputStream)
+{
+  // Getting the input stream
+  mBlob->GetInternalStream(aInputStream);
+  NS_ENSURE_TRUE(*aInputStream, NS_ERROR_UNEXPECTED);
+  return NS_OK;
+}
+
+nsresult
+ArchiveReader::GetSize(PRUint64* aSize)
+{
+  nsresult rv = mBlob->GetSize(aSize);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
+}
+
+// Here we open the archive:
+nsresult
+ArchiveReader::OpenArchive()
+{
+  mStatus = WORKING;
+  nsresult rv;
+
+  // Target:
+  nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+  NS_ASSERTION(target, "Must have stream transport service");
+
+  // Here a Event to make everything async:
+  nsRefPtr<ArchiveReaderEvent> event;
+
+  /* FIXME: If we want to support more than 1 format we should check the content type here: */
+  event = new ArchiveReaderZipEvent(this);
+  rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // In order to be sure that this object exists when the event finishes its task,
+  // we increase the refcount here:
+  AddRef();
+
+  return NS_OK;
+}
+
+// Data received from the dispatched event:
+void
+ArchiveReader::Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+                     nsresult aStatus)
+{
+  mStatus = READY;
+ 
+  // Let's store the values:
+  mData.fileList = aFileList;
+  mData.status = aStatus;
+
+  // Propagate the results:
+  for (PRUint32 index = 0; index < mRequests.Length(); ++index) {
+    nsRefPtr<ArchiveRequest> request = mRequests[index];
+    RequestReady(request);
+  }
+
+  mRequests.Clear();
+
+  // The async operation is concluded, we can decrease the reference:
+  Release();
+}
+
+void
+ArchiveReader::RequestReady(ArchiveRequest* aRequest)
+{
+  // The request will do the rest:
+  aRequest->ReaderReady(mData.fileList, mData.status);
+}
+
+/* nsIDOMArchiveRequest getFilenames (); */
+NS_IMETHODIMP
+ArchiveReader::GetFilenames(nsIDOMArchiveRequest** _retval)
+{
+  nsRefPtr<ArchiveRequest> request = GenerateArchiveRequest();
+  request->OpGetFilenames();
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+/* nsIDOMArchiveRequest getFile (in DOMString filename); */
+NS_IMETHODIMP
+ArchiveReader::GetFile(const nsAString& filename,
+                       nsIDOMArchiveRequest** _retval)
+{
+  nsRefPtr<ArchiveRequest> request = GenerateArchiveRequest();
+  request->OpGetFile(filename);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+already_AddRefed<ArchiveRequest>
+ArchiveReader::GenerateArchiveRequest()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  return ArchiveRequest::Create(mWindow, this);
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(ArchiveReader)
+
+// C++ traverse
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ArchiveReader)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBlob)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mData.fileList)
+
+  for (PRUint32 i = 0; i < tmp->mRequests.Length(); i++) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRequests[i]");
+    cb.NoteXPCOMChild(static_cast<nsIDOMArchiveRequest*>(tmp->mRequests[i].get()));
+  }
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+// Unlink
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ArchiveReader)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBlob)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mData.fileList)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mRequests)
+  tmp->mRequests.Clear();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ArchiveReader)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMArchiveReader)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMArchiveReader)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ArchiveReader)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(ArchiveReader)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(ArchiveReader)
+
+DOMCI_DATA(ArchiveReader, ArchiveReader)
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveReader.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_file_domarchivereader_h__
+#define mozilla_dom_file_domarchivereader_h__
+
+#include "nsIDOMArchiveReader.h"
+#include "nsIJSNativeInitializer.h"
+
+#include "FileCommon.h"
+
+#include "nsCOMArray.h"
+#include "nsIChannel.h"
+#include "nsIDOMFile.h"
+
+
+BEGIN_FILE_NAMESPACE
+
+class ArchiveRequest;
+
+class ArchiveReader : public nsIDOMArchiveReader,
+                      public nsIJSNativeInitializer
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+
+  NS_DECL_NSIDOMARCHIVEREADER
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ArchiveReader,
+                                           nsIDOMArchiveReader)
+
+  ArchiveReader();
+
+  // nsIJSNativeInitializer
+  NS_IMETHOD Initialize(nsISupports* aOwner,
+                        JSContext* aCx,
+                        JSObject* aObj,
+                        PRUint32 aArgc,
+                        jsval* aArgv);
+
+  nsresult GetInputStream(nsIInputStream** aInputStream);
+  nsresult GetSize(PRUint64* aSize);
+
+public: // for the ArchiveRequest:
+  nsresult RegisterRequest(ArchiveRequest* aRequest);
+
+public: // For events:
+  void Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+             nsresult aStatus);
+
+private:
+  ~ArchiveReader();
+
+  already_AddRefed<ArchiveRequest> GenerateArchiveRequest();
+
+  nsresult OpenArchive();
+
+  void RequestReady(ArchiveRequest* aRequest);
+
+protected:
+  // The archive blob/file
+  nsCOMPtr<nsIDOMBlob> mBlob;
+
+  // The window is needed by the requests
+  nsCOMPtr<nsIDOMWindow> mWindow;
+
+  // Are we ready to return data?
+  enum {
+    NOT_STARTED = 0,
+    WORKING,
+    READY
+  } mStatus;
+
+  // State of the read:
+  enum {
+    Header, // We are collecting the header: 30bytes
+    Name,   // The name length is contained in the header
+    Data,   // The length of the data segment COULD be written in the header
+    Search  // ... if the data length is unknown (== 0) we wait until we read a new header 
+  } mReadStatus;
+
+  // List of requests to be processed
+  nsTArray<nsRefPtr<ArchiveRequest> > mRequests;
+
+  // Everything related to the blobs and the status:
+  struct {
+    nsTArray<nsCOMPtr<nsIDOMFile> > fileList;
+    nsresult status;
+  } mData;
+};
+
+END_FILE_NAMESPACE
+
+#endif // mozilla_dom_file_domarchivereader_h__
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveRequest.cpp
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ArchiveRequest.h"
+
+#include "nsContentUtils.h"
+#include "nsLayoutStatics.h"
+#include "nsEventDispatcher.h"
+#include "nsDOMClassInfoID.h"
+
+USING_FILE_NAMESPACE
+
+/**
+ * Class used to make asynchronous the ArchiveRequest.
+ */
+class ArchiveRequestEvent : public nsRunnable
+{
+public:
+  NS_DECL_NSIRUNNABLE
+
+  ArchiveRequestEvent(ArchiveRequest* request)
+  : mRequest(request)
+  {
+    MOZ_COUNT_CTOR(ArchiveRequestEvent);
+  }
+
+  ~ArchiveRequestEvent()
+  {
+    MOZ_COUNT_DTOR(ArchiveRequestEvent);
+  }
+
+private: //data
+  nsRefPtr<ArchiveRequest> mRequest;
+};
+
+NS_IMETHODIMP
+ArchiveRequestEvent::Run()
+{
+  NS_ABORT_IF_FALSE(mRequest, "the request is not longer valid");
+  mRequest->Run();
+  return NS_OK;
+}
+
+/* ArchiveRequest */
+
+ArchiveRequest::ArchiveRequest(nsIDOMWindow* aWindow,
+                               ArchiveReader* aReader)
+: DOMRequest(aWindow),
+  mArchiveReader(aReader)
+{
+  nsLayoutStatics::AddRef();
+
+  /* An event to make this request asynchronous: */
+  nsRefPtr<ArchiveRequestEvent> event = new ArchiveRequestEvent(this);
+  NS_DispatchToCurrentThread(event);
+}
+
+ArchiveRequest::~ArchiveRequest()
+{
+  nsLayoutStatics::Release();
+}
+
+nsresult
+ArchiveRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+{
+  aVisitor.mCanHandle = true;
+  aVisitor.mParentTarget = nsnull;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ArchiveRequest::GetReader(nsIDOMArchiveReader** aArchiveReader)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  nsCOMPtr<nsIDOMArchiveReader> archiveReader(mArchiveReader);
+  archiveReader.forget(aArchiveReader);
+  return NS_OK;
+}
+
+// Here the request is processed:
+void
+ArchiveRequest::Run()
+{
+  // Register this request to the reader.
+  // When the reader is ready to return data, a 'Ready()' will be called
+  nsresult rv = mArchiveReader->RegisterRequest(this);
+  if (NS_FAILED(rv))
+    FireError(rv);
+}
+
+void
+ArchiveRequest::OpGetFilenames()
+{
+  mOperation = GetFilenames;
+}
+
+void
+ArchiveRequest::OpGetFile(const nsAString& aFilename)
+{
+  mOperation = GetFile;
+  mFilename = aFilename;
+}
+
+nsresult
+ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+                            nsresult aStatus)
+{
+  if (aStatus != NS_OK) {
+    FireError(aStatus);
+    return NS_OK;
+  }
+
+  jsval result;
+  nsresult rv;
+
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+  NS_ENSURE_STATE(sc);
+
+  JSContext* cx = sc->GetNativeContext();
+  NS_ASSERTION(cx, "Failed to get a context!");
+
+  JSObject* global = sc->GetNativeGlobal();
+  NS_ASSERTION(global, "Failed to get global object!");
+
+  JSAutoRequest ar(cx);
+  JSAutoEnterCompartment ac;
+  if (ac.enter(cx, global)) {
+    switch (mOperation) {
+      case GetFilenames:
+        rv = GetFilenamesResult(cx, &result, aFileList);
+        break;
+
+      case GetFile:
+        rv = GetFileResult(cx, &result, aFileList);
+        break;
+    }
+
+    if (NS_FAILED(rv)) {
+      NS_WARNING("Get*Result failed!");
+    }
+  } else {
+    NS_WARNING("Failed to enter correct compartment!");
+    rv = NS_ERROR_FAILURE;
+  }
+
+  if (NS_SUCCEEDED(rv)) {
+    FireSuccess(result);
+  }
+  else {
+    FireError(rv);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+ArchiveRequest::GetFilenamesResult(JSContext* aCx,
+                                   jsval* aValue,
+                                   nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
+{
+  JSObject* array = JS_NewArrayObject(aCx, aFileList.Length(), nsnull);
+  nsresult rv;
+
+  if (!array) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  for (PRUint32 i = 0; i < aFileList.Length(); ++i) {
+    nsCOMPtr<nsIDOMFile> file = aFileList[i];
+
+    nsString filename;
+    rv = file->GetName(filename);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    JSString* str = JS_NewUCStringCopyZ(aCx, filename.get());
+    NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
+
+    jsval item = STRING_TO_JSVAL(str);
+
+    if (rv != NS_OK || !JS_SetElement(aCx, array, i, &item)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  if (!JS_FreezeObject(aCx, array)) {
+    return NS_ERROR_FAILURE;
+  }
+  
+  *aValue = OBJECT_TO_JSVAL(array);
+  return NS_OK;
+}
+
+nsresult
+ArchiveRequest::GetFileResult(JSContext* aCx,
+                              jsval* aValue,
+                              nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
+{
+  for (PRUint32 i = 0; i < aFileList.Length(); ++i) {
+    nsCOMPtr<nsIDOMFile> file = aFileList[i];
+
+    nsString filename;
+    nsresult rv = file->GetName(filename);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (filename == mFilename) {
+      JSObject* scope = JS_GetGlobalForScopeChain(aCx);
+      nsresult rv = nsContentUtils::WrapNative(aCx, scope, file, aValue, nsnull, true);
+      return rv;
+    }
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
+// static
+already_AddRefed<ArchiveRequest>
+ArchiveRequest::Create(nsIDOMWindow* aOwner,
+                       ArchiveReader* aReader)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<ArchiveRequest> request = new ArchiveRequest(aOwner, aReader);
+
+  return request.forget();
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(ArchiveRequest)
+
+// C++ traverse
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ArchiveRequest,
+                                                  DOMRequest)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mArchiveReader, nsIDOMArchiveReader)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+// Unlink
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ArchiveRequest,
+                                                DOMRequest)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArchiveReader)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ArchiveRequest)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMArchiveRequest)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ArchiveRequest)
+NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
+
+NS_IMPL_ADDREF_INHERITED(ArchiveRequest, DOMRequest)
+NS_IMPL_RELEASE_INHERITED(ArchiveRequest, DOMRequest)
+
+DOMCI_DATA(ArchiveRequest, ArchiveRequest)
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveRequest.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_file_domarchiverequest_h__
+#define mozilla_dom_file_domarchiverequest_h__
+
+#include "nsIDOMArchiveRequest.h"
+#include "ArchiveReader.h"
+#include "DOMRequest.h"
+
+#include "FileCommon.h"
+
+
+BEGIN_FILE_NAMESPACE
+
+class ArchiveRequest : public mozilla::dom::DOMRequest,
+                       public nsIDOMArchiveRequest
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMARCHIVEREQUEST
+
+  NS_FORWARD_NSIDOMDOMREQUEST(DOMRequest::)
+  NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(DOMRequest::)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ArchiveRequest, DOMRequest)
+
+  ArchiveRequest(nsIDOMWindow* aWindow,
+                 ArchiveReader* aReader);
+
+  // nsIDOMEventTarget
+  virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
+
+public:
+  // This is called by the DOMArchiveRequestEvent
+  void Run();
+
+  // Set the types for this request
+  void OpGetFilenames();
+  void OpGetFile(const nsAString& aFilename);
+
+  nsresult ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+                       nsresult aStatus);
+
+public: // static
+  static already_AddRefed<ArchiveRequest> Create(nsIDOMWindow* aOwner,
+                                                 ArchiveReader* aReader);
+
+private:
+  ~ArchiveRequest();
+
+  nsresult GetFilenamesResult(JSContext* aCx,
+                              jsval* aValue,
+                              nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
+  nsresult GetFileResult(JSContext* aCx,
+                         jsval* aValue,
+                         nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
+
+protected:
+  // The reader:
+  nsRefPtr<ArchiveReader> mArchiveReader;
+
+  // The operation:
+  enum {
+    GetFilenames,
+    GetFile
+  } mOperation;
+
+  // The filename (needed by GetFile):
+  nsString mFilename;
+};
+
+END_FILE_NAMESPACE
+
+#endif // mozilla_dom_file_domarchiverequest_h__
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveZipEvent.cpp
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ArchiveZipEvent.h"
+#include "ArchiveZipFile.h"
+
+#include "nsContentUtils.h"
+#include "nsCExternalHandlerService.h"
+
+USING_FILE_NAMESPACE
+
+#ifndef PATH_MAX
+#  define PATH_MAX 65536 // The filename length is stored in 2 bytes
+#endif
+
+// ArchiveZipItem
+ArchiveZipItem::ArchiveZipItem(const char* aFilename,
+                               ZipCentral& aCentralStruct)
+: mFilename(aFilename),
+  mCentralStruct(aCentralStruct)
+{
+}
+
+// Getter/Setter for the filename
+nsCString
+ArchiveZipItem::GetFilename()
+{
+  return mFilename;
+}
+
+void
+ArchiveZipItem::SetFilename(const nsCString& aFilename)
+{
+  mFilename = aFilename;
+}
+
+
+// From zipItem to DOMFile:
+nsIDOMFile*
+ArchiveZipItem::File(ArchiveReader* aArchiveReader)
+{
+  return new ArchiveZipFile(NS_ConvertUTF8toUTF16(mFilename),
+                            NS_ConvertUTF8toUTF16(GetType()),
+                            StrToInt32(mCentralStruct.orglen),
+                            mCentralStruct,
+                            aArchiveReader);
+}
+
+PRUint32
+ArchiveZipItem::StrToInt32(const PRUint8* aStr)
+{
+  return (PRUint32)( (aStr [0] <<  0) |
+                     (aStr [1] <<  8) |
+                     (aStr [2] << 16) |
+                     (aStr [3] << 24) );
+}
+
+PRUint16
+ArchiveZipItem::StrToInt16(const PRUint8* aStr)
+{
+  return (PRUint16) ((aStr [0]) | (aStr [1] << 8));
+}
+
+// ArchiveReaderZipEvent
+
+ArchiveReaderZipEvent::ArchiveReaderZipEvent(ArchiveReader* aArchiveReader)
+: ArchiveReaderEvent(aArchiveReader)
+{
+}
+
+// NOTE: this runs in a different thread!!
+nsresult
+ArchiveReaderZipEvent::Exec()
+{
+  PRUint32 centralOffset(0);
+  nsresult rv;
+
+  nsCOMPtr<nsIInputStream> inputStream;
+  rv = mArchiveReader->GetInputStream(getter_AddRefs(inputStream));
+  if (rv != NS_OK || !inputStream) {
+    return RunShare(NS_ERROR_UNEXPECTED);
+  }
+
+  // From the input stream to a seekable stream
+  nsCOMPtr<nsISeekableStream> seekableStream;
+  seekableStream = do_QueryInterface(inputStream);
+  if (!seekableStream) {
+    return RunShare(NS_ERROR_UNEXPECTED);
+  }
+
+  PRUint64 size;
+  rv = mArchiveReader->GetSize(&size);
+  if (rv != NS_OK) {
+    return RunShare(NS_ERROR_UNEXPECTED);
+  }
+
+  // Reading backward.. looking for the ZipEnd signature
+  for (PRUint64 curr = size - ZIPEND_SIZE; curr > 4; --curr)
+  {
+    seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, curr);
+
+    PRUint8 buffer[ZIPEND_SIZE];
+    PRUint32 ret;
+
+    rv = inputStream->Read((char*)buffer, sizeof(buffer), &ret);
+    if (rv != NS_OK || ret != sizeof(buffer)) {
+      return RunShare(NS_ERROR_UNEXPECTED);
+    }
+
+    // Here we are:
+    if (ArchiveZipItem::StrToInt32(buffer) == ENDSIG) {
+      centralOffset = ArchiveZipItem::StrToInt32(((ZipEnd*)buffer)->offset_central_dir);
+      break;
+    }
+  }
+
+  // No central Offset
+  if (!centralOffset || centralOffset >= size - ZIPEND_SIZE) {
+    return RunShare(NS_ERROR_FAILURE);
+  }
+
+  // Seek to the first central directory:
+  seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, centralOffset);
+
+  // For each central directory:
+  while (centralOffset <= size - ZIPCENTRAL_SIZE) {
+    ZipCentral centralStruct;
+    PRUint32 ret;
+    
+    rv = inputStream->Read((char*)&centralStruct, ZIPCENTRAL_SIZE, &ret);
+    if (rv != NS_OK || ret != ZIPCENTRAL_SIZE) {
+      return RunShare(NS_ERROR_UNEXPECTED);
+    }
+
+    PRUint16 filenameLen = ArchiveZipItem::StrToInt16(centralStruct.filename_len);
+    PRUint16 extraLen = ArchiveZipItem::StrToInt16(centralStruct.extrafield_len);
+    PRUint16 commentLen = ArchiveZipItem::StrToInt16(centralStruct.commentfield_len);
+
+    // Point to the next item at the top of loop
+    centralOffset += ZIPCENTRAL_SIZE + filenameLen + extraLen + commentLen;
+    if (filenameLen == 0 || filenameLen >= PATH_MAX || centralOffset >= size) {
+      return RunShare(NS_ERROR_FILE_CORRUPTED);
+    }
+
+    // Read the name:
+    char* filename = (char*)PR_Malloc(filenameLen + 1);
+    rv = inputStream->Read(filename, filenameLen, &ret);
+    if (rv != NS_OK || ret != filenameLen) {
+      return RunShare(NS_ERROR_UNEXPECTED);
+    }
+
+    filename[filenameLen] = 0;
+
+    // We ignore the directories:
+    if (filename[filenameLen - 1] != '/') {
+      mFileList.AppendElement(new ArchiveZipItem(filename, centralStruct));
+    }
+
+    PR_Free(filename);
+
+    // Ignore the rest
+    seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, extraLen + commentLen);
+  }
+
+  return RunShare(NS_OK);
+}
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveZipEvent.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_file_domarchivezipevent_h__
+#define mozilla_dom_file_domarchivezipevent_h__
+
+#include "ArchiveEvent.h"
+
+#include "FileCommon.h"
+#include "zipstruct.h"
+
+BEGIN_FILE_NAMESPACE
+
+class ArchiveZipItem : public ArchiveItem
+{
+public:
+  ArchiveZipItem(const char* aFilename,
+                 ZipCentral& aCentralStruct);
+
+  void SetFilename(const nsCString& aFilename);
+  nsCString GetFilename();
+
+  // From zipItem to DOMFile:
+  virtual nsIDOMFile* File(ArchiveReader* aArchiveReader);
+
+public: // for the event
+  static PRUint32 StrToInt32(const PRUint8* aStr);
+  static PRUint16 StrToInt16(const PRUint8* aStr);
+
+private: // data
+  nsCString mFilename;
+  ZipCentral mCentralStruct;
+};
+
+class ArchiveReaderZipEvent : public ArchiveReaderEvent
+{
+public:
+  ArchiveReaderZipEvent(ArchiveReader* aArchiveReader);
+
+  nsresult Exec();
+};
+
+END_FILE_NAMESPACE
+
+#endif // mozilla_dom_file_domarchivezipevent_h__
+
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveZipFile.cpp
@@ -0,0 +1,314 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ArchiveZipFile.h"
+#include "ArchiveZipEvent.h"
+
+#include "nsIInputStream.h"
+#include "zlib.h"
+
+USING_FILE_NAMESPACE
+
+#define ZIP_CHUNK 16384
+
+// a internat input stream object
+
+class ArchiveInputStream : public nsIInputStream
+{
+public:
+  ArchiveInputStream(ArchiveReader* aReader,
+                     nsString& aFilename,
+                     PRUint32 aStart,
+                     PRUint32 aLength,
+                     ZipCentral& aCentral)
+  : mArchiveReader(aReader),
+    mCentral(aCentral),
+    mFilename(aFilename),
+    mStart(aStart),
+    mLength(aLength),
+    mRunning(false)
+  {}
+
+  ~ArchiveInputStream()
+  {
+    Close();
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIINPUTSTREAM
+
+private:
+  nsresult Init();
+
+private: // data
+  nsRefPtr<ArchiveReader> mArchiveReader;
+  ZipCentral mCentral;
+  nsString mFilename;
+  PRUint32 mStart;
+  PRUint32 mLength;
+
+  z_stream mZs;
+
+  bool mRunning;
+
+  struct {
+    nsCOMPtr<nsIInputStream> inputStream;
+    unsigned char input[ZIP_CHUNK];
+    PRUint32 sizeToBeRead;
+    bool compressed; // a zip file can contain stored or compressed files
+  } mData;
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(ArchiveInputStream, nsIInputStream)
+
+nsresult
+ArchiveInputStream::Init()
+{
+  nsresult rv;
+
+  memset(&mZs, 0, sizeof(z_stream));
+  int zerr = inflateInit2(&mZs, -MAX_WBITS);
+  if (zerr != Z_OK)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  // Reset the data:
+  memset(&mData, 0, sizeof(mData));
+  mData.sizeToBeRead = ArchiveZipItem::StrToInt32(mCentral.size);
+
+  PRUint32 offset = ArchiveZipItem::StrToInt32(mCentral.localhdr_offset);
+  PRUint64 size;
+  rv = mArchiveReader->GetSize(&size);
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  // The file is corrupt
+  if (offset + ZIPLOCAL_SIZE > size)
+    return NS_ERROR_UNEXPECTED;
+
+  mArchiveReader->GetInputStream(getter_AddRefs(mData.inputStream));
+  if (rv != NS_OK || !mData.inputStream)
+    return NS_ERROR_UNEXPECTED;
+
+  // From the input stream to a seekable stream
+  nsCOMPtr<nsISeekableStream> seekableStream;
+  seekableStream = do_QueryInterface(mData.inputStream);
+  if (!seekableStream)
+    return NS_ERROR_UNEXPECTED;
+
+  // Seek + read the ZipLocal struct
+  seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
+  PRUint8 buffer[ZIPLOCAL_SIZE];
+  PRUint32 ret;
+
+  rv = mData.inputStream->Read((char*)buffer, ZIPLOCAL_SIZE, &ret);
+  if (rv != NS_OK || ret != ZIPLOCAL_SIZE)
+    return NS_ERROR_UNEXPECTED;
+
+  // Signature check:
+  if (ArchiveZipItem::StrToInt32(buffer) != LOCALSIG)
+    return NS_ERROR_UNEXPECTED;
+
+  ZipLocal local;
+  memcpy(&local, buffer, ZIPLOCAL_SIZE);
+
+  // Seek to the real data:
+  offset += ZIPLOCAL_SIZE +
+            ArchiveZipItem::StrToInt16(local.filename_len) +
+            ArchiveZipItem::StrToInt16(local.extrafield_len);
+
+  // The file is corrupt if there is not enough data
+  if (offset + mData.sizeToBeRead > size)
+    return NS_ERROR_UNEXPECTED;
+
+  // Data starts here:
+  seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
+
+  // The file is compressed or not?
+  mData.compressed = (ArchiveZipItem::StrToInt16(mCentral.method) != 0);
+
+  // We have to skip the first mStart bytes:
+  if (mStart != 0) {
+    PRUint32 done(mStart);
+    PRUint32 ret;
+    char buffer[1024];
+
+    while (done > 0) {
+      rv = Read(buffer, done > sizeof(buffer) ? sizeof(buffer) : done, &ret);
+      if (rv != NS_OK)
+        return rv;
+
+      if (ret == 0)
+        return NS_ERROR_UNEXPECTED;
+
+      done -= ret;
+    }
+  }
+
+  mRunning = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ArchiveInputStream::Close()
+{
+  if (mRunning) {
+    inflateEnd(&mZs);
+    mRunning = false;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ArchiveInputStream::Available(PRUint32* _retval)
+{
+  *_retval = mLength - mZs.total_out - mStart;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ArchiveInputStream::Read(char* aBuffer,
+                         PRUint32 aCount,
+                         PRUint32* _retval)
+{
+  NS_ENSURE_ARG_POINTER(aBuffer);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  PRUint32 ret;
+  nsresult rv;
+
+  // This is the first time:
+  if (!mRunning) {
+    rv = Init();
+    if (rv != NS_OK)
+      return rv;
+  }
+
+  // Nothing more can be read
+  if (mData.sizeToBeRead == 0) {
+    *_retval = 0;
+    return NS_OK;
+  }
+
+  // Stored file:
+  if (!mData.compressed)
+  {
+    rv = mData.inputStream->Read(aBuffer,
+                                 (mData.sizeToBeRead > aCount ?
+                                      aCount : mData.sizeToBeRead),
+                                 _retval);
+    if (rv == NS_OK)
+      mData.sizeToBeRead -= *_retval;
+
+    return rv;
+  }
+
+  // We have nothing ready to be processed:
+  if (mZs.avail_out == 0)
+  {
+    rv = mData.inputStream->Read((char*)mData.input,
+                                 (mData.sizeToBeRead > sizeof(mData.input) ?
+                                      sizeof(mData.input) : mData.sizeToBeRead),
+                                 &ret);
+    if (rv != NS_OK)
+      return rv;
+
+    // Terminator:
+    if (ret == 0) {
+      *_retval = 0;
+      return NS_OK;
+    }
+
+    mData.sizeToBeRead -= ret;
+    mZs.avail_in = ret;
+    mZs.next_in = mData.input;
+  }
+
+  mZs.avail_out = aCount;
+  mZs.next_out = (unsigned char*)aBuffer;
+
+  ret = inflate(&mZs, mData.sizeToBeRead ? Z_NO_FLUSH : Z_FINISH);
+  if (ret != Z_OK && ret != Z_STREAM_END)
+    return NS_ERROR_UNEXPECTED;
+
+  *_retval = aCount - mZs.avail_out;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ArchiveInputStream::ReadSegments(nsWriteSegmentFun aWriter,
+                                 void* aClosure,
+                                 PRUint32 aCount,
+                                 PRUint32* _retval)
+{
+  // don't have a buffer to read from, so this better not be called!
+  NS_NOTREACHED("Consumers should be using Read()!");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ArchiveInputStream::IsNonBlocking(bool* _retval)
+{
+  // We are blocking
+  *_retval = false;
+  return NS_OK;
+}
+
+
+// ArchiveZipFile
+
+NS_IMETHODIMP
+ArchiveZipFile::GetInternalStream(nsIInputStream** aStream)
+{
+  if (mLength > PR_INT32_MAX)
+    return NS_ERROR_FAILURE;
+
+  nsRefPtr<ArchiveInputStream> stream = new ArchiveInputStream(mArchiveReader,
+                                                               mFilename,
+                                                               mStart,
+                                                               mLength,
+                                                               mCentral);
+  NS_ADDREF(stream);
+
+  *aStream = stream;
+  return NS_OK;
+}
+
+already_AddRefed<nsIDOMBlob>
+ArchiveZipFile::CreateSlice(PRUint64 aStart,
+                            PRUint64 aLength,
+                            const nsAString& aContentType)
+{
+  nsCOMPtr<nsIDOMBlob> t = new ArchiveZipFile(mFilename,
+                                              mContentType,
+                                              aStart,
+                                              mLength,
+                                              mCentral,
+                                              mArchiveReader);
+  return t.forget();
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(ArchiveZipFile)
+
+// C++ traverse
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ArchiveZipFile)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mArchiveReader, nsIDOMArchiveReader)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+// Unlink
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ArchiveZipFile)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArchiveReader)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ArchiveZipFile)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
+  NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
+  NS_INTERFACE_MAP_ENTRY(nsIMutable)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMFileCC)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(ArchiveZipFile)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(ArchiveZipFile)
new file mode 100644
--- /dev/null
+++ b/dom/file/ArchiveZipFile.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_file_domarchivefile_h__
+#define mozilla_dom_file_domarchivefile_h__
+
+#include "nsDOMFile.h"
+
+#include "ArchiveReader.h"
+
+#include "FileCommon.h"
+#include "zipstruct.h"
+
+BEGIN_FILE_NAMESPACE
+
+class ArchiveZipFile : public nsDOMFileCC
+{
+public:
+  ArchiveZipFile(const nsAString& aName,
+                 const nsAString& aContentType,
+                 PRUint64 aLength,
+                 ZipCentral& aCentral,
+                 ArchiveReader* aReader)
+  : nsDOMFileCC(aName, aContentType, aLength),
+    mCentral(aCentral),
+    mArchiveReader(aReader),
+    mFilename(aName)
+  {
+    NS_ASSERTION(mArchiveReader, "must have a reader");
+  }
+
+  ArchiveZipFile(const nsAString& aName,
+                 const nsAString& aContentType,
+                 PRUint64 aStart,
+                 PRUint64 aLength,
+                 ZipCentral& aCentral,
+                 ArchiveReader* aReader)
+  : nsDOMFileCC(aContentType, aStart, aLength),
+    mCentral(aCentral),
+    mArchiveReader(aReader),
+    mFilename(aName)
+  {
+    NS_ASSERTION(mArchiveReader, "must have a reader");
+  }
+
+  // Overrides:
+  NS_IMETHOD GetInternalStream(nsIInputStream**);
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ArchiveZipFile, nsIDOMFile)
+
+protected:
+  virtual already_AddRefed<nsIDOMBlob> CreateSlice(PRUint64 aStart,
+                                                   PRUint64 aLength,
+                                                   const nsAString& aContentType);
+
+private: // Data
+  ZipCentral mCentral;
+  nsRefPtr<ArchiveReader> mArchiveReader;
+
+  nsString mFilename;
+};
+
+END_FILE_NAMESPACE
+
+#endif // mozilla_dom_file_domarchivefile_h__
--- a/dom/file/Makefile.in
+++ b/dom/file/Makefile.in
@@ -26,33 +26,45 @@ CPPSRCS = \
   FileHandle.cpp \
   FileHelper.cpp \
   FileRequest.cpp \
   FileService.cpp \
   FileStreamWrappers.cpp \
   LockedFile.cpp \
   MemoryStreams.cpp \
   MetadataHelper.cpp \
+  ArchiveEvent.cpp \
+  ArchiveZipEvent.cpp \
+  ArchiveZipFile.cpp \
+  ArchiveReader.cpp \
+  ArchiveRequest.cpp \
   $(NULL)
 
 EXPORTS = \
   nsIFileStorage.h \
   $(NULL)
 
 EXPORTS_mozilla/dom/file = \
   DOMFileHandle.h \
   File.h \
   FileCommon.h \
   FileHandle.h \
   FileHelper.h \
   FileService.h \
   LockedFile.h \
+  ArchiveEvent.h \
+  ArchiveZipEvent.h \
+  ArchiveZipFile.h \
+  ArchiveReader.h \
+  ArchiveRequest.h \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMFileHandle.idl \
   nsIDOMFileRequest.idl \
   nsIDOMLockedFile.idl \
+  nsIDOMArchiveReader.idl \
+  nsIDOMArchiveRequest.idl \
   $(NULL)
 
 TEST_DIRS += test
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/file/nsIDOMArchiveReader.idl
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIDOMArchiveRequest;
+
+[scriptable, builtinclass, uuid(a616ab85-fc3a-4028-9f10-f8620ee1b8e1)]
+interface nsIDOMArchiveReader : nsISupports
+{
+  nsIDOMArchiveRequest getFilenames();
+  nsIDOMArchiveRequest getFile(in DOMString filename);
+};
+
+%{ C++
+#define NS_ARCHIVEREADER_CID                         \
+{0xb6b8c817, 0x4e9a, 0x46f8,                         \
+{0x9e, 0x3e, 0x3d, 0x96, 0x79, 0x01, 0xa2, 0x80}}
+#define NS_ARCHIVEREADER_CONTRACTID \
+"@mozilla.org/files/archivereader;1"
+%}
new file mode 100644
--- /dev/null
+++ b/dom/file/nsIDOMArchiveRequest.idl
@@ -0,0 +1,15 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMDOMRequest.idl"
+
+interface nsIDOMArchiveReader;
+
+[scriptable, builtinclass, uuid(6e59f1be-24bc-43ee-810a-8abb21599f29)]
+interface nsIDOMArchiveRequest : nsIDOMDOMRequest
+{
+  readonly attribute nsIDOMArchiveReader reader;
+};
--- a/dom/file/test/Makefile.in
+++ b/dom/file/test/Makefile.in
@@ -22,11 +22,12 @@ MOCHITEST_FILES = \
   test_overlapping_lockedfiles.html \
   test_progress_events.html \
   test_readonly_lockedfiles.html \
   test_request_readyState.html \
   test_stream_tracking.html \
   test_success_events_after_abort.html \
   test_truncate.html \
   test_write_read_data.html \
+  test_archivereader.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/file/test/test_archivereader.html
@@ -0,0 +1,221 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Archive Reader Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7">
+  function createZipFileWithData(fileData) {
+    var Cc = SpecialPowers.wrap(Components).classes;
+    var Ci = SpecialPowers.wrap(Components).interfaces;
+
+    var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+    var testFile = dirSvc.get("ProfD", Ci.nsIFile);
+    testFile.append("fileArchiveReader.zip");
+    var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+    outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
+                   0666, 0);
+    outStream.write(fileData, fileData.length);
+    outStream.close();
+
+    var fileList = document.getElementById('fileList');
+    SpecialPowers.wrap(fileList).value = testFile.path;
+
+    return fileList.files[0];
+  }
+
+  function createTextFileWithData(fileData) {
+    var Cc = SpecialPowers.wrap(Components).classes;
+    var Ci = SpecialPowers.wrap(Components).interfaces;
+
+    var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+    var testFile = dirSvc.get("ProfD", Ci.nsIFile);
+    testFile.append("fileArchiveReader.txt");
+    var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+    outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
+                   0666, 0);
+    outStream.write(fileData, fileData.length);
+    outStream.close();
+
+    var fileList = document.getElementById('fileList');
+    SpecialPowers.wrap(fileList).value = testFile.path;
+
+    return fileList.files[0];
+  }
+
+  function testSteps()
+  {
+    var binaryString = '504B03040A00000000002E6BF14000000000000000000000000005001C00746573742F555409000337CA055039CA055075780B' +
+                       '000104E803000004E8030000504B03041400000008002D6BF1401780E15015000000580200000A001C00746573742F612E7478' +
+                       '74555409000336CA05503ACA055075780B000104E803000004E8030000CB48CDC9C95728CF2FCA49E1CA18658FB2A9C4060050' +
+                       '4B03040A00000000002F88EC40662E847010000000100000000A001C00746573742F622E74787455540900035A65FF4F42C505' +
+                       '5075780B000104E803000004E803000068656C6C6F20776F726C642C2032210A504B01021E030A00000000002E6BF140000000' +
+                       '000000000000000000050018000000000000001000FD4100000000746573742F555405000337CA055075780B000104E8030000' +
+                       '04E8030000504B01021E031400000008002D6BF1401780E15015000000580200000A0018000000000001000000B4813F000000' +
+                       '746573742F612E747874555405000336CA055075780B000104E803000004E8030000504B01021E030A00000000002F88EC4066' +
+                       '2E847010000000100000000A0018000000000001000000B48198000000746573742F622E74787455540500035A65FF4F75780B' +
+                       '000104E803000004E8030000504B05060000000003000300EB000000EC0000000000';
+
+    var binaryData = "";
+    for (var i = 0, len = binaryString.length / 2; i < len; ++i) {
+      var hex = binaryString[i * 2] + binaryString[i * 2 + 1];
+      binaryData += String.fromCharCode(parseInt(hex,16));
+    }
+
+    var binaryFile = createZipFileWithData(binaryData);
+    var textFile = createTextFileWithData("Hello World");
+
+    var status;
+
+    // Create - wrong 1
+    try {
+      var r = new ArchiveReader();
+      status = false;
+    }
+    catch(e) {
+      status = true;
+    }
+    ok(status, "ArchiveReader() without args MUST fail");
+
+    // Create - wrong 2
+    try {
+      var r = new ArchiveReader(true);
+      status = false;
+    }
+    catch(e) {
+      status = true;
+    }
+    ok(status, "ArchiveReader() without a blob arg MUST fail");
+
+    // Create - wrong 3
+    try {
+      var r = new ArchiveReader("hello world");
+      status = false;
+    }
+    catch(e) {
+      status = true;
+    }
+    ok(status, "ArchiveReader() without a blob arg MUST fail");
+
+    // Create - good! (but with a text file)
+    var rt = new ArchiveReader(textFile);
+    isnot(rt, null, "ArchiveReader cannot be null");
+
+    // GetFilename
+    var handle = rt.getFilenames();
+    isnot(handle, null, "ArchiveReader.getFilenames() cannot be null");
+    handle.onsuccess = function() {
+      ok(false, "ArchiveReader.getFilenames() should return a 'failure' if the input file is not a zip");
+    }
+    handle.onerror = function() {
+      ok(true, "ArchiveReader.getFilenames() should return a 'error' if the input file is a zip file");
+      is(this.reader, rt, "ArchiveRequest.reader == ArchiveReader");
+    }
+
+    // Create - good!
+    var r = new ArchiveReader(binaryFile);
+    isnot(r, null, "ArchiveReader cannot be null");
+
+    // GetFilename
+    handle = r.getFilenames();
+    isnot(handle, null, "ArchiveReader.getFilenames() cannot be null");
+    handle.onsuccess = function() {
+      ok(true, "ArchiveReader.getFilenames() should return a 'success'");
+      is(this.result instanceof Array, true, "ArchiveReader.getFilenames() should return an array");
+      is(this.result.length, 2, "ArchiveReader.getFilenames(): the array contains 2 items");
+      is(this.result[0], "test/a.txt", "ArchiveReader.getFilenames(): first file is 'test/a.txt'");
+      is(this.result[1], "test/b.txt", "ArchiveReader.getFilenames(): second file is 'test/b.txt'");
+      ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
+    }
+    handle.onerror = function() {
+      ok(false, "ArchiveReader.getFilenames() should not return any 'error'");
+    }
+
+    // GetFile - wrong (no args)
+    try {
+      r.getFile();
+      status = false;
+    }
+    catch(e) {
+      status = true;
+    }
+    ok(status, "ArchiveReader.getFile() without args fail");
+
+    var handle2 = r.getFile("hello world");
+    isnot(handle2, null, "ArchiveReader.getFile() cannot be null");
+    handle2.onsuccess = function() {
+      ok(false, "ArchiveReader.getFile('unknown file') should not return a 'success'");
+    }
+    handle2.onerror = function() {
+      ok(true, "ArchiveReader.getFile('unknown file') should return an 'error'");
+      ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
+    }
+
+    var handle3 = r.getFile("test/b.txt");
+    isnot(handle3, null, "ArchiveReader.getFile() cannot be null");
+    handle3.onsuccess = function() {
+      ok(true, "ArchiveReader.getFile('test/b.txt') should return a 'success'");
+      ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
+      is(this.result.name, "test/b.txt", "ArchiveReader.getFile('test/b.txt') the name MUST be 'test/b.txt'");
+      is(this.result.type, "text/plain", "ArchiveReader.getFile('test/b.txt') the type MUST be 'text/plain'");
+
+      var fr = new FileReader();
+      fr.readAsText(this.result);
+      fr.onerror = function() {
+        ok(false, "ArchiveReader + FileReader should work!");
+      }
+      fr.onload = function(event) {
+        is(event.target.result, "hello world, 2!\n", "ArchiveReader + FileReader are working together.");
+      }
+    }
+
+    handle3.onerror = function() {
+      ok(false, "ArchiveReader.getFile('test/b.txt') should not return an 'error'");
+    }
+
+    var handle4 = r.getFile("test/a.txt");
+    isnot(handle4, null, "ArchiveReader.getFile() cannot be null");
+    handle4.onsuccess = function() {
+      ok(true, "ArchiveReader.getFile('test/a.txt') should return a 'success'");
+      ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
+      is(this.result.name, "test/a.txt", "ArchiveReader.getFile('test/a.txt') the name MUST be 'test/a.txt'");
+      is(this.result.type, "text/plain", "ArchiveReader.getFile('test/a.txt') the type MUST be 'text/plain'");
+
+      var fr = new FileReader();
+      fr.readAsText(this.result);
+      fr.onerror = function() {
+        ok(false, "ArchiveReader + FileReader should work!");
+      }
+      fr.onload = function(event) {
+        is(event.target.result.length, 600, "ArchiveReader + FileReader are working with a compress data");
+        var p = event.target.result.trim().split('\n');
+        is(p.length, 50, "ArchiveReader + FileReader are working with a compress data");
+
+        for (var i = 0; i < p.length; ++i)
+          is(p[i], "hello world", "ArchiveReader + FileReader are working with a compress data");
+      }
+    }
+    handle4.onerror = function() {
+      ok(false, "ArchiveReader.getFile('test/a.txt') should not return an 'error'");
+    }
+
+    finishTest();
+    yield;
+  }
+  </script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+
+</head>
+
+<body onload="runTest();">
+<p id="display">
+  <input id="fileList" type="file"></input>
+</p>
+</body>
+
+</html>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -204,16 +204,18 @@ var interfaceNamesInGlobalScope =
     "SVGFEMorphologyElement",
     "SVGFETurbulenceElement",
     "XULTextBoxElement",
     "SVGDocument",
     "CSSStyleDeclaration",
     "SVGAltGlyphElement",
     "Screen",
     "FileReader",
+    "ArchiveReader",
+    "ArchiveRequest",
     "SVGSwitchElement",
     "SVGPolylineElement",
     "SVGPathSegLinetoAbs",
     "NavigatorDeviceStorage",
     "HTMLOptionsCollection",
     "IDBKeyRange",
     "Parser",
     "HTMLDivElement",
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -237,16 +237,17 @@ LOCAL_INCLUDES	+= -I$(srcdir)/../base \
 		   -I$(topsrcdir)/content/xslt/src/xslt \
 		   -I$(topsrcdir)/content/xul/content/src \
 		   -I$(topsrcdir)/content/xul/document/src \
 		   -I$(topsrcdir)/content/xul/templates/src \
 		   -I$(topsrcdir)/content/events/src \
 		   -I$(topsrcdir)/content/xbl/src \
 		   -I$(topsrcdir)/view/src \
 		   -I$(topsrcdir)/dom/base \
+		   -I$(topsrcdir)/dom/file \
 		   -I$(topsrcdir)/dom/src/json \
 		   -I$(topsrcdir)/dom/src/jsurl \
 		   -I$(topsrcdir)/dom/src/storage \
 		   -I$(topsrcdir)/dom/src/offline \
 		   -I$(topsrcdir)/dom/src/geolocation \
 		   -I$(topsrcdir)/dom/contacts \
 		   -I$(topsrcdir)/dom/settings \
 		   -I$(topsrcdir)/dom/telephony \
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -72,16 +72,21 @@
 // view stuff
 #include "nsViewsCID.h"
 #include "nsViewManager.h"
 #include "nsContentCreatorFunctions.h"
 
 // DOM includes
 #include "nsDOMException.h"
 #include "nsDOMFileReader.h"
+
+#include "ArchiveReader.h"
+
+using namespace mozilla::dom::file;
+
 #include "nsFormData.h"
 #include "nsBlobProtocolHandler.h"
 #include "nsGlobalWindowCommands.h"
 #include "nsIControllerCommandTable.h"
 #include "nsJSProtocolHandler.h"
 #include "nsScriptNameSpaceManager.h"
 #include "nsIControllerContext.h"
 #include "nsDOMScriptObjectFactory.h"
@@ -247,16 +252,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(txMozilla
 NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(nsXPathEvaluator, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(txNodeSetAdaptor, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMSerializer)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsXMLHttpRequest, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsEventSource)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebSocket)
 NS_GENERIC_FACTORY_CONSTRUCTOR(Activity)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDOMFileReader, Init)
+NS_GENERIC_FACTORY_CONSTRUCTOR(ArchiveReader)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFormData)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBlobProtocolHandler)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMParser)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDOMStorageManager,
                                          nsDOMStorageManager::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsChannelPolicy)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(IndexedDatabaseManager,
                                          IndexedDatabaseManager::FactoryCreate)
@@ -726,16 +732,17 @@ NS_DEFINE_NAMED_CID(NS_PLUGINDOCUMENT_CI
 NS_DEFINE_NAMED_CID(NS_VIDEODOCUMENT_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_STYLESHEETSERVICE_CID);
 NS_DEFINE_NAMED_CID(TRANSFORMIIX_XSLT_PROCESSOR_CID);
 NS_DEFINE_NAMED_CID(TRANSFORMIIX_XPATH_EVALUATOR_CID);
 NS_DEFINE_NAMED_CID(TRANSFORMIIX_NODESET_CID);
 NS_DEFINE_NAMED_CID(NS_XMLSERIALIZER_CID);
 NS_DEFINE_NAMED_CID(NS_FILEREADER_CID);
+NS_DEFINE_NAMED_CID(NS_ARCHIVEREADER_CID);
 NS_DEFINE_NAMED_CID(NS_FORMDATA_CID);
 NS_DEFINE_NAMED_CID(NS_BLOBPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_XMLHTTPREQUEST_CID);
 NS_DEFINE_NAMED_CID(NS_EVENTSOURCE_CID);
 NS_DEFINE_NAMED_CID(NS_WEBSOCKET_CID);
 NS_DEFINE_NAMED_CID(NS_DOMACTIVITY_CID);
 NS_DEFINE_NAMED_CID(NS_DOMPARSER_CID);
 NS_DEFINE_NAMED_CID(NS_DOMSTORAGE2_CID);
@@ -998,16 +1005,17 @@ static const mozilla::Module::CIDEntry k
   { &kNS_VIDEODOCUMENT_CID, false, NULL, CreateVideoDocument },
 #endif
   { &kNS_STYLESHEETSERVICE_CID, false, NULL, nsStyleSheetServiceConstructor },
   { &kTRANSFORMIIX_XSLT_PROCESSOR_CID, false, NULL, txMozillaXSLTProcessorConstructor },
   { &kTRANSFORMIIX_XPATH_EVALUATOR_CID, false, NULL, nsXPathEvaluatorConstructor },
   { &kTRANSFORMIIX_NODESET_CID, false, NULL, txNodeSetAdaptorConstructor },
   { &kNS_XMLSERIALIZER_CID, false, NULL, nsDOMSerializerConstructor },
   { &kNS_FILEREADER_CID, false, NULL, nsDOMFileReaderConstructor },
+  { &kNS_ARCHIVEREADER_CID, false, NULL, ArchiveReaderConstructor },
   { &kNS_FORMDATA_CID, false, NULL, nsFormDataConstructor },
   { &kNS_BLOBPROTOCOLHANDLER_CID, false, NULL, nsBlobProtocolHandlerConstructor },
   { &kNS_XMLHTTPREQUEST_CID, false, NULL, nsXMLHttpRequestConstructor },
   { &kNS_EVENTSOURCE_CID, false, NULL, nsEventSourceConstructor },
   { &kNS_WEBSOCKET_CID, false, NULL, nsWebSocketConstructor },
   { &kNS_DOMACTIVITY_CID, false, NULL, ActivityConstructor },
   { &kNS_DOMPARSER_CID, false, NULL, nsDOMParserConstructor },
   { &kNS_DOMSTORAGE2_CID, false, NULL, NS_NewDOMStorage2 },
@@ -1135,16 +1143,17 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/view-manager;1", &kNS_VIEW_MANAGER_CID },
   { PLUGIN_DLF_CONTRACTID, &kNS_PLUGINDOCLOADERFACTORY_CID },
   { NS_STYLESHEETSERVICE_CONTRACTID, &kNS_STYLESHEETSERVICE_CID },
   { TRANSFORMIIX_XSLT_PROCESSOR_CONTRACTID, &kTRANSFORMIIX_XSLT_PROCESSOR_CID },
   { NS_XPATH_EVALUATOR_CONTRACTID, &kTRANSFORMIIX_XPATH_EVALUATOR_CID },
   { TRANSFORMIIX_NODESET_CONTRACTID, &kTRANSFORMIIX_NODESET_CID },
   { NS_XMLSERIALIZER_CONTRACTID, &kNS_XMLSERIALIZER_CID },
   { NS_FILEREADER_CONTRACTID, &kNS_FILEREADER_CID },
+  { NS_ARCHIVEREADER_CONTRACTID, &kNS_ARCHIVEREADER_CID },
   { NS_FORMDATA_CONTRACTID, &kNS_FORMDATA_CID },
   { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX BLOBURI_SCHEME, &kNS_BLOBPROTOCOLHANDLER_CID },
   { NS_XMLHTTPREQUEST_CONTRACTID, &kNS_XMLHTTPREQUEST_CID },
   { NS_EVENTSOURCE_CONTRACTID, &kNS_EVENTSOURCE_CID },
   { NS_WEBSOCKET_CONTRACTID, &kNS_WEBSOCKET_CID },
   { NS_DOMACTIVITY_CONTRACTID, &kNS_DOMACTIVITY_CID },
   { NS_DOMPARSER_CONTRACTID, &kNS_DOMPARSER_CID },
   { "@mozilla.org/dom/storage;2", &kNS_DOMSTORAGE2_CID },