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 id23193
push userryanvm@gmail.com
push dateSat, 28 Jul 2012 21:54:39 +0000
treeherdermozilla-central@29bff59d3bbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs772434
milestone17.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 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 },