Bug 781425 - Part 1: Enconding and dictionary. r=mounir, sr=sicking
authorAndrea Marchesini <baku@mozilla.com>
Tue, 06 Nov 2012 18:23:13 -0500
changeset 112485 5bc6448929cbf262a088aaba89c268c71b94e8d9
parent 112484 6d54c207490e13b406367dc25884b5c35f56cbfb
child 112486 36a99706bcbec2f42833abd09c01c944ce734769
push id23825
push useremorley@mozilla.com
push dateWed, 07 Nov 2012 12:53:10 +0000
treeherdermozilla-central@8671bfc8e9a8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmounir, sicking
bugs781425
milestone19.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 781425 - Part 1: Enconding and dictionary. r=mounir, sr=sicking
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/nsIDOMArchiveReader.idl
dom/file/test/Makefile.in
dom/file/test/test_archivereader_nonUnicode.html
js/xpconnect/src/dictionary_helper_gen.conf
--- a/dom/file/ArchiveEvent.cpp
+++ b/dom/file/ArchiveEvent.cpp
@@ -23,17 +23,21 @@ ArchiveItem::~ArchiveItem()
 {
   MOZ_COUNT_DTOR(ArchiveItem);
 }
 
 
 nsCString
 ArchiveItem::GetType()
 {
-  return mType.IsEmpty() ? nsCString("binary/octet-stream") : mType;
+  if (mType.IsEmpty()) {
+    return NS_LITERAL_CSTRING("binary/octet-stream");
+  }
+
+  return mType;
 }
 
 void
 ArchiveItem::SetType(const nsCString& aType)
 {
   mType = aType;
 }
 
@@ -104,27 +108,36 @@ ArchiveReaderEvent::ShareMainThread()
 {
   nsTArray<nsCOMPtr<nsIDOMFile> > fileList;
 
   if (!NS_FAILED(mStatus)) {
     // This extra step must run in the main thread:
     for (uint32_t index = 0; index < mFileList.Length(); ++index) {
       nsRefPtr<ArchiveItem> item = mFileList[index];
 
-      int32_t offset = item->GetFilename().RFindChar('.');
+      nsString tmp;
+      nsresult rv = item->GetFilename(tmp);
+      nsCString filename = NS_ConvertUTF16toUTF8(tmp);
+      if (NS_FAILED(rv)) {
+        continue;
+      }
+
+      int32_t offset = filename.RFindChar('.');
       if (offset != kNotFound) {
-        nsCString ext(item->GetFilename());
-        ext.Cut(0, offset + 1);
+        filename.Cut(0, offset + 1);
 
         // Just to be sure, if something goes wrong, the mimetype is an empty string:
         nsCString type;
-        if (NS_SUCCEEDED(GetType(ext, type)))
+        if (NS_SUCCEEDED(GetType(filename, type))) {
           item->SetType(type);
+        }
       }
 
       // This is a nsDOMFile:
       nsRefPtr<nsIDOMFile> file = item->File(mArchiveReader);
-      fileList.AppendElement(file);
+      if (file) {
+        fileList.AppendElement(file);
+      }
     }
   }
 
   mArchiveReader->Ready(fileList, mStatus);
 }
--- a/dom/file/ArchiveEvent.h
+++ b/dom/file/ArchiveEvent.h
@@ -12,43 +12,47 @@
 #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.
+/**
+ * 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
 
   ArchiveItem();
   virtual ~ArchiveItem();
 
   // Getter/Setter for the type
-  virtual nsCString GetType();
-  virtual void SetType(const nsCString& aType);
+  nsCString GetType();
+  void SetType(const nsCString& aType);
 
   // Getter for the filename
-  virtual nsCString GetFilename() = 0;
+  virtual nsresult GetFilename(nsString& aFilename) = 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();
+/**
+ * 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();
--- a/dom/file/ArchiveReader.cpp
+++ b/dom/file/ArchiveReader.cpp
@@ -35,38 +35,44 @@ ArchiveReader::~ArchiveReader()
 
 NS_IMETHODIMP
 ArchiveReader::Initialize(nsISupports* aOwner,
                           JSContext* aCx,
                           JSObject* aObj,
                           uint32_t aArgc,
                           JS::Value* aArgv)
 {
-  NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
+  NS_ENSURE_TRUE(aArgc == 1 || aArgc == 2, NS_ERROR_INVALID_ARG);
 
   // We expect to get a Blob object
   if (!aArgv[0].isObject()) {
-    return NS_ERROR_UNEXPECTED; // We're not interested
+    return NS_ERROR_INVALID_ARG; // 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;
+    return NS_ERROR_INVALID_ARG;
   }
 
-  mBlob = blob;
+  // Extra param is an object
+  if (aArgc > 1) {
+    nsresult rv = mOptions.Init(aCx, &aArgv[1]);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   mWindow = do_QueryInterface(aOwner);
   if (!mWindow) {
     return NS_ERROR_UNEXPECTED;
   }
 
+  mBlob = blob;
+
   return NS_OK;
 }
 
 nsresult
 ArchiveReader::RegisterRequest(ArchiveRequest* aRequest)
 {
   switch (mStatus) {
     // Append to the list and let's start to work:
@@ -117,17 +123,17 @@ ArchiveReader::OpenArchive()
   // 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);
+  event = new ArchiveReaderZipEvent(this, mOptions);
   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;
--- a/dom/file/ArchiveReader.h
+++ b/dom/file/ArchiveReader.h
@@ -11,21 +11,25 @@
 #include "nsIJSNativeInitializer.h"
 
 #include "FileCommon.h"
 
 #include "nsCOMArray.h"
 #include "nsIChannel.h"
 #include "nsIDOMFile.h"
 #include "mozilla/Attributes.h"
+#include "DictionaryHelpers.h"
 
 BEGIN_FILE_NAMESPACE
 
 class ArchiveRequest;
 
+/**
+ * This is the ArchiveReader object
+ */
 class ArchiveReader MOZ_FINAL : public nsIDOMArchiveReader,
                                 public nsIJSNativeInitializer
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   NS_DECL_NSIDOMARCHIVEREADER
 
@@ -85,13 +89,15 @@ protected:
   // 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;
+
+  ArchiveReaderOptions mOptions;
 };
 
 END_FILE_NAMESPACE
 
 #endif // mozilla_dom_file_domarchivereader_h__
--- a/dom/file/ArchiveRequest.cpp
+++ b/dom/file/ArchiveRequest.cpp
@@ -39,17 +39,17 @@ private: //data
 NS_IMETHODIMP
 ArchiveRequestEvent::Run()
 {
   NS_ABORT_IF_FALSE(mRequest, "the request is not longer valid");
   mRequest->Run();
   return NS_OK;
 }
 
-/* ArchiveRequest */
+// ArchiveRequest
 
 ArchiveRequest::ArchiveRequest(nsIDOMWindow* aWindow,
                                ArchiveReader* aReader)
 : DOMRequest(aWindow),
   mArchiveReader(aReader)
 {
   MOZ_COUNT_CTOR(ArchiveRequest);
   nsLayoutStatics::AddRef();
@@ -85,18 +85,19 @@ ArchiveRequest::GetReader(nsIDOMArchiveR
 
 // 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))
+  if (NS_FAILED(rv)) {
     FireError(rv);
+  }
 }
 
 void
 ArchiveRequest::OpGetFilenames()
 {
   mOperation = GetFilenames;
 }
 
@@ -182,17 +183,17 @@ ArchiveRequest::GetFilenamesResult(JSCon
     if (NS_FAILED(rv) || !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)
@@ -200,18 +201,19 @@ ArchiveRequest::GetFileResult(JSContext*
   for (uint32_t 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, nullptr, true);
+      nsresult rv = nsContentUtils::WrapNative(
+                      aCx, JS_GetGlobalForScopeChain(aCx),
+                      file, &NS_GET_IID(nsIDOMFile), aValue);
       return rv;
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
 // static
--- a/dom/file/ArchiveRequest.h
+++ b/dom/file/ArchiveRequest.h
@@ -11,21 +11,25 @@
 #include "ArchiveReader.h"
 #include "DOMRequest.h"
 
 #include "FileCommon.h"
 
 
 BEGIN_FILE_NAMESPACE
 
+/**
+ * This is the ArchiveRequest that handles any operation
+ * related to ArchiveReader
+ */
 class ArchiveRequest : public mozilla::dom::DOMRequest,
                        public nsIDOMArchiveRequest
 {
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_ISUPPORTS_INHERITED
   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);
--- a/dom/file/ArchiveZipEvent.cpp
+++ b/dom/file/ArchiveZipEvent.cpp
@@ -3,57 +3,95 @@
 /* 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 "nsIPlatformCharset.h"
+#include "nsNativeCharsetUtils.h"
 #include "nsCExternalHandlerService.h"
 
+using namespace mozilla::dom;
+
 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)
+                               const ZipCentral& aCentralStruct,
+                               const ArchiveReaderOptions& aOptions)
 : mFilename(aFilename),
-  mCentralStruct(aCentralStruct)
+  mCentralStruct(aCentralStruct),
+  mOptions(aOptions)
 {
   MOZ_COUNT_CTOR(ArchiveZipItem);
 }
 
 ArchiveZipItem::~ArchiveZipItem()
 {
   MOZ_COUNT_DTOR(ArchiveZipItem);
 }
 
-// Getter/Setter for the filename
-nsCString
-ArchiveZipItem::GetFilename()
+nsresult
+ArchiveZipItem::ConvertFilename()
 {
-  return mFilename;
+  if (mOptions.encoding.IsEmpty()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsString filenameU;
+  nsresult rv = nsContentUtils::ConvertStringFromCharset(
+                  NS_ConvertUTF16toUTF8(mOptions.encoding),
+                  mFilename, filenameU);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (filenameU.IsEmpty()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mFilenameU = filenameU;
+  return NS_OK;
 }
 
-void
-ArchiveZipItem::SetFilename(const nsCString& aFilename)
+nsresult
+ArchiveZipItem::GetFilename(nsString& aFilename)
 {
-  mFilename = aFilename;
+  if (mFilenameU.IsEmpty()) {
+    // Maybe this string is UTF-8:
+    if (IsUTF8(mFilename, false)) {
+      mFilenameU = NS_ConvertUTF8toUTF16(mFilename);
+    }
+
+    // Let's use the enconding value for the dictionary
+    else {
+      nsresult rv = ConvertFilename();
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+
+  aFilename = mFilenameU;
+  return NS_OK;
 }
 
-
 // From zipItem to DOMFile:
 nsIDOMFile*
 ArchiveZipItem::File(ArchiveReader* aArchiveReader)
 {
-  return new ArchiveZipFile(NS_ConvertUTF8toUTF16(mFilename),
+  nsString filename;
+
+  if (NS_FAILED(GetFilename(filename))) {
+    return nullptr;
+  }
+
+  return new ArchiveZipFile(filename,
                             NS_ConvertUTF8toUTF16(GetType()),
                             StrToInt32(mCentralStruct.orglen),
                             mCentralStruct,
                             aArchiveReader);
 }
 
 uint32_t
 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
@@ -67,18 +105,20 @@ ArchiveZipItem::StrToInt32(const uint8_t
 uint16_t
 ArchiveZipItem::StrToInt16(const uint8_t* aStr)
 {
   return (uint16_t) ((aStr [0]) | (aStr [1] << 8));
 }
 
 // ArchiveReaderZipEvent
 
-ArchiveReaderZipEvent::ArchiveReaderZipEvent(ArchiveReader* aArchiveReader)
-: ArchiveReaderEvent(aArchiveReader)
+ArchiveReaderZipEvent::ArchiveReaderZipEvent(ArchiveReader* aArchiveReader,
+                                             const ArchiveReaderOptions& aOptions)
+: ArchiveReaderEvent(aArchiveReader),
+  mOptions(aOptions)
 {
 }
 
 // NOTE: this runs in a different thread!!
 nsresult
 ArchiveReaderZipEvent::Exec()
 {
   uint32_t centralOffset(0);
@@ -99,18 +139,17 @@ ArchiveReaderZipEvent::Exec()
 
   uint64_t size;
   rv = mArchiveReader->GetSize(&size);
   if (NS_FAILED(rv)) {
     return RunShare(NS_ERROR_UNEXPECTED);
   }
 
   // Reading backward.. looking for the ZipEnd signature
-  for (uint64_t curr = size - ZIPEND_SIZE; curr > 4; --curr)
-  {
+  for (uint64_t curr = size - ZIPEND_SIZE; curr > 4; --curr) {
     seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, curr);
 
     uint8_t buffer[ZIPEND_SIZE];
     uint32_t ret;
 
     rv = inputStream->Read((char*)buffer, sizeof(buffer), &ret);
     if (NS_FAILED(rv) || ret != sizeof(buffer)) {
       return RunShare(NS_ERROR_UNEXPECTED);
@@ -157,17 +196,17 @@ ArchiveReaderZipEvent::Exec()
     if (NS_FAILED(rv) || ret != filenameLen) {
       return RunShare(NS_ERROR_UNEXPECTED);
     }
 
     filename[filenameLen] = 0;
 
     // We ignore the directories:
     if (filename[filenameLen - 1] != '/') {
-      mFileList.AppendElement(new ArchiveZipItem(filename, centralStruct));
+      mFileList.AppendElement(new ArchiveZipItem(filename, centralStruct, mOptions));
     }
 
     PR_Free(filename);
 
     // Ignore the rest
     seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, extraLen + commentLen);
   }
 
--- a/dom/file/ArchiveZipEvent.h
+++ b/dom/file/ArchiveZipEvent.h
@@ -7,44 +7,63 @@
 #ifndef mozilla_dom_file_domarchivezipevent_h__
 #define mozilla_dom_file_domarchivezipevent_h__
 
 #include "ArchiveEvent.h"
 
 #include "FileCommon.h"
 #include "zipstruct.h"
 
+#include "DictionaryHelpers.h"
+
 BEGIN_FILE_NAMESPACE
 
+/**
+ * ArchiveZipItem - ArchiveItem for ArchiveReaderZipEvent
+ */
 class ArchiveZipItem : public ArchiveItem
 {
 public:
   ArchiveZipItem(const char* aFilename,
-                 ZipCentral& aCentralStruct);
+                 const ZipCentral& aCentralStruct,
+                 const ArchiveReaderOptions& aOptions);
   virtual ~ArchiveZipItem();
 
-  void SetFilename(const nsCString& aFilename);
-  nsCString GetFilename();
+  nsresult GetFilename(nsString& aFilename);
 
   // From zipItem to DOMFile:
   virtual nsIDOMFile* File(ArchiveReader* aArchiveReader);
 
 public: // for the event
   static uint32_t StrToInt32(const uint8_t* aStr);
   static uint16_t StrToInt16(const uint8_t* aStr);
 
+private:
+  nsresult ConvertFilename();
+
 private: // data
   nsCString mFilename;
+
+  nsString mFilenameU;
   ZipCentral mCentralStruct;
+
+  ArchiveReaderOptions mOptions;
 };
 
+/**
+ * ArchiveReaderEvent implements the ArchiveReaderEvent for the ZIP format
+ */
 class ArchiveReaderZipEvent : public ArchiveReaderEvent
 {
 public:
-  ArchiveReaderZipEvent(ArchiveReader* aArchiveReader);
+  ArchiveReaderZipEvent(ArchiveReader* aArchiveReader,
+                        const ArchiveReaderOptions& aOptions);
 
   nsresult Exec();
+
+private:
+  ArchiveReaderOptions mOptions;
 };
 
 END_FILE_NAMESPACE
 
 #endif // mozilla_dom_file_domarchivezipevent_h__
 
--- a/dom/file/ArchiveZipFile.cpp
+++ b/dom/file/ArchiveZipFile.cpp
@@ -10,18 +10,19 @@
 #include "nsIInputStream.h"
 #include "zlib.h"
 #include "mozilla/Attributes.h"
 
 USING_FILE_NAMESPACE
 
 #define ZIP_CHUNK 16384
 
-// a internat input stream object
-
+/**
+ * Input stream object for zip files
+ */
 class ArchiveInputStream MOZ_FINAL : public nsIInputStream,
                                      public nsISeekableStream
 {
 public:
   ArchiveInputStream(uint64_t aParentSize,
                      nsIInputStream* aInputStream,
                      nsString& aFilename,
                      uint32_t aStart,
@@ -87,57 +88,63 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(ArchiveInp
 
 nsresult
 ArchiveInputStream::Init()
 {
   nsresult rv;
 
   memset(&mZs, 0, sizeof(z_stream));
   int zerr = inflateInit2(&mZs, -MAX_WBITS);
-  if (zerr != Z_OK)
+  if (zerr != Z_OK) {
     return NS_ERROR_OUT_OF_MEMORY;
+  }
 
   mData.sizeToBeRead = ArchiveZipItem::StrToInt32(mCentral.size);
 
   uint32_t offset = ArchiveZipItem::StrToInt32(mCentral.localhdr_offset);
 
   // The file is corrupt
-  if (offset + ZIPLOCAL_SIZE > mData.parentSize)
+  if (offset + ZIPLOCAL_SIZE > mData.parentSize) {
     return NS_ERROR_UNEXPECTED;
+  }
 
   // From the input stream to a seekable stream
   nsCOMPtr<nsISeekableStream> seekableStream;
   seekableStream = do_QueryInterface(mData.inputStream);
-  if (!seekableStream)
+  if (!seekableStream) {
     return NS_ERROR_UNEXPECTED;
+  }
 
   // Seek + read the ZipLocal struct
   seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
   uint8_t buffer[ZIPLOCAL_SIZE];
   uint32_t ret;
 
   rv = mData.inputStream->Read((char*)buffer, ZIPLOCAL_SIZE, &ret);
-  if (NS_FAILED(rv) || ret != ZIPLOCAL_SIZE)
+  if (NS_FAILED(rv) || ret != ZIPLOCAL_SIZE) {
     return NS_ERROR_UNEXPECTED;
+  }
 
   // Signature check:
-  if (ArchiveZipItem::StrToInt32(buffer) != LOCALSIG)
+  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 > mData.parentSize)
+  if (offset + mData.sizeToBeRead > mData.parentSize) {
     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:
@@ -177,78 +184,81 @@ ArchiveInputStream::Read(char* aBuffer,
 
   nsresult rv;
 
   // This is the first time:
   if (mStatus == NotStarted) {
     mStatus = Started;
 
     rv = Init();
-    if (NS_FAILED(rv))
+    if (NS_FAILED(rv)) {
       return rv;
+    }
 
     // Let's set avail_out to -1 so we read something from the stream.
     mZs.avail_out = (uInt)-1;
   }
 
   // Nothing more can be read
   if (mStatus == Done) {
     *_retval = 0;
     return NS_OK;
   }
 
   // Stored file:
-  if (!mData.compressed)
-  {
+  if (!mData.compressed) {
     rv = mData.inputStream->Read(aBuffer,
                                  (mData.sizeToBeRead > aCount ?
                                     aCount : mData.sizeToBeRead),
                                  _retval);
     if (NS_SUCCEEDED(rv)) {
       mData.sizeToBeRead -= *_retval;
       mData.cursor += *_retval;
 
-      if (mData.sizeToBeRead == 0)
+      if (mData.sizeToBeRead == 0) {
         mStatus = Done;
+      }
     }
 
     return rv;
   }
 
   // We have nothing ready to be processed:
-  if (mZs.avail_out != 0 && mData.sizeToBeRead != 0)
-  {
+  if (mZs.avail_out != 0 && mData.sizeToBeRead != 0) {
     uint32_t ret;
     rv = mData.inputStream->Read((char*)mData.input,
                                  (mData.sizeToBeRead > sizeof(mData.input) ?
                                       sizeof(mData.input) : mData.sizeToBeRead),
                                  &ret);
-    if (NS_FAILED(rv))
+    if (NS_FAILED(rv)) {
       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;
 
   int ret = inflate(&mZs, mData.sizeToBeRead ? Z_NO_FLUSH : Z_FINISH);
-  if (ret != Z_BUF_ERROR && ret != Z_OK && ret != Z_STREAM_END)
+  if (ret != Z_BUF_ERROR && ret != Z_OK && ret != Z_STREAM_END) {
     return NS_ERROR_UNEXPECTED;
+  }
 
-  if (ret == Z_STREAM_END)
+  if (ret == Z_STREAM_END) {
     mStatus = Done;
+  }
 
   *_retval = aCount - mZs.avail_out;
   mData.cursor += *_retval;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ArchiveInputStream::ReadSegments(nsWriteSegmentFun aWriter,
@@ -286,42 +296,46 @@ ArchiveInputStream::Seek(int32_t aWhence
     pos += mLength;
     break;
 
   default:
     NS_NOTREACHED("unexpected whence value");
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (pos == int64_t(mData.cursor))
+  if (pos == int64_t(mData.cursor)) {
     return NS_OK;
+  }
 
-  if (pos < 0 || pos >= mLength)
+  if (pos < 0 || pos >= mLength) {
     return NS_ERROR_FAILURE;
+  }
 
   // We have to terminate the previous operation:
   nsresult rv;
   if (mStatus != NotStarted) {
     rv = Close();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Reset the cursor:
   mData.cursor = 0;
 
   // Note: This code is heavy but inflate does not have any seek() support:
   uint32_t ret;
   char buffer[1024];
   while (pos > 0) {
     rv = Read(buffer, pos > int64_t(sizeof(buffer)) ? sizeof(buffer) : pos, &ret);
-    if (NS_FAILED(rv))
+    if (NS_FAILED(rv)) {
       return rv;
+    }
 
-    if (ret == 0)
+    if (ret == 0) {
       return NS_ERROR_UNEXPECTED;
+    }
 
     pos -= ret;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -337,27 +351,29 @@ ArchiveInputStream::SetEOF()
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 // ArchiveZipFile
 
 NS_IMETHODIMP
 ArchiveZipFile::GetInternalStream(nsIInputStream** aStream)
 {
-  if (mLength > INT32_MAX)
+  if (mLength > INT32_MAX) {
     return NS_ERROR_FAILURE;
+  }
 
   uint64_t size;
   nsresult rv = mArchiveReader->GetSize(&size);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIInputStream> inputStream;
   rv = mArchiveReader->GetInputStream(getter_AddRefs(inputStream));
-  if (NS_FAILED(rv) || !inputStream)
+  if (NS_FAILED(rv) || !inputStream) {
     return NS_ERROR_UNEXPECTED;
+  }
 
   nsRefPtr<ArchiveInputStream> stream = new ArchiveInputStream(size,
                                                                inputStream,
                                                                mFilename,
                                                                mStart,
                                                                mLength,
                                                                mCentral);
   NS_ADDREF(stream);
--- a/dom/file/ArchiveZipFile.h
+++ b/dom/file/ArchiveZipFile.h
@@ -11,16 +11,19 @@
 
 #include "ArchiveReader.h"
 
 #include "FileCommon.h"
 #include "zipstruct.h"
 
 BEGIN_FILE_NAMESPACE
 
+/**
+ * ZipFile to DOMFileCC
+ */
 class ArchiveZipFile : public nsDOMFileCC
 {
 public:
   ArchiveZipFile(const nsAString& aName,
                  const nsAString& aContentType,
                  uint64_t aLength,
                  ZipCentral& aCentral,
                  ArchiveReader* aReader)
--- a/dom/file/nsIDOMArchiveReader.idl
+++ b/dom/file/nsIDOMArchiveReader.idl
@@ -9,15 +9,23 @@ interface nsIDOMArchiveRequest;
 
 [scriptable, builtinclass, uuid(a616ab85-fc3a-4028-9f10-f8620ee1b8e1)]
 interface nsIDOMArchiveReader : nsISupports
 {
   nsIDOMArchiveRequest getFilenames();
   nsIDOMArchiveRequest getFile(in DOMString filename);
 };
 
+/* This dictionary is the optional argument for the
+ * ArchiveReader constructor:
+ * var a = new ArchiveReader(blob, { encoding: "iso-8859-1" }); */
+dictionary ArchiveReaderOptions
+{
+  DOMString encoding = "windows-1252"; // Default fallback encoding
+};
+
 %{ 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"
 %}
--- a/dom/file/test/Makefile.in
+++ b/dom/file/test/Makefile.in
@@ -26,12 +26,13 @@ MOCHITEST_FILES = \
   test_request_readyState.html \
   test_stream_tracking.html \
   test_success_events_after_abort.html \
   test_truncate.html \
   test_write_read_data.html \
   test_workers.html \
   test_archivereader.html \
   test_archivereader_zip_in_zip.html \
+  test_archivereader_nonUnicode.html \
   test_bug_793311.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/file/test/test_archivereader_nonUnicode.html
@@ -0,0 +1,104 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Archive Reader Non-Unicode 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 createNonUnicodeData() {
+    const Cc = SpecialPowers.wrap(Components).classes;
+    const 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_nonUnicode.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);
+
+    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));
+    }
+    outStream.write(binaryData, binaryData.length);
+    outStream.close();
+
+    var fileList = document.getElementById('fileList');
+    SpecialPowers.wrap(fileList).value = testFile.path;
+
+    return fileList.files[0];
+  }
+
+  function test1()
+  {
+    var binaryFile = createNonUnicodeData();
+
+    var r = new ArchiveReader(binaryFile, { encoding: "ISO-8859-1" });
+    isnot(r, null, "ArchiveReader cannot be null");
+
+    // GetFilename
+    var 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, 1, "ArchiveReader.getFilenames(): the array contains 1 item");
+      ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
+      dump('Content: ' + this.result[0] + '\n');
+      test2();
+    }
+  }
+
+  function test2()
+  {
+    var binaryFile = createNonUnicodeData();
+
+    var r = new ArchiveReader(binaryFile, { encoding: "random stuff" });
+    isnot(r, null, "ArchiveReader cannot be null");
+
+    // GetFilename
+    var 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, 0, "ArchiveReader.getFilenames(): the array contains 0 item");
+      ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
+      finishTest();
+    }
+  }
+
+  function testSteps()
+  {
+    test1();
+    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>
+<script type="text/javascript;version=1.7">
+var binaryString = '' +
+'504B0304140000000000255D094100000000000000000000000002000000912F504B03040A0000000000285D09416BB50A5A' +
+'010000000100000007000000912F9B2E747874D8504B01023F00140000000000255D09410000000000000000000000000200' +
+'24000000000000001000000000000000912F0A002000000000000100180062505F1A1376CD0162505F1A1376CD01FE3F8D59' +
+'1176CD01504B01023F000A0000000000285D09416BB50A5A0100000001000000070024000000000000002000000020000000' +
+'912F9B2E7478740A0020000000000001001800565EF41D1376CD0107BD73631176CD0107BD73631176CD01504B0506000000' +
+'0002000200AD000000460000000000';
+</script>
+</body>
+
+</html>
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -15,17 +15,18 @@ dictionaries = [
      [ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
      [ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
      [ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ],
      [ 'CameraSize', 'nsIDOMCameraManager.idl' ],
      [ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
      [ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
      [ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
      [ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ],
-     [ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ]
+     [ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ],
+     [ 'ArchiveReaderOptions', 'nsIDOMArchiveReader.idl' ]
    ]
 
 # include file names
 special_includes = [
     'nsContentUtils.h',
     'XPCQuickStubs.h',
     'nsIDOMApplicationRegistry.h'
   ]