mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 15:27:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
131
dom/archivereader/ArchiveEvent.cpp
Normal file
131
dom/archivereader/ArchiveEvent.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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 "nsCExternalHandlerService.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
USING_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
NS_IMPL_ISUPPORTS0(ArchiveItem)
|
||||
|
||||
ArchiveItem::ArchiveItem()
|
||||
{
|
||||
MOZ_COUNT_CTOR(ArchiveItem);
|
||||
}
|
||||
|
||||
ArchiveItem::~ArchiveItem()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ArchiveItem);
|
||||
}
|
||||
|
||||
|
||||
nsCString
|
||||
ArchiveItem::GetType()
|
||||
{
|
||||
if (mType.IsEmpty()) {
|
||||
return NS_LITERAL_CSTRING("binary/octet-stream");
|
||||
}
|
||||
|
||||
return mType;
|
||||
}
|
||||
|
||||
void
|
||||
ArchiveItem::SetType(const nsCString& aType)
|
||||
{
|
||||
mType = aType;
|
||||
}
|
||||
|
||||
ArchiveReaderEvent::ArchiveReaderEvent(ArchiveReader* aArchiveReader)
|
||||
: mArchiveReader(aArchiveReader)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ArchiveReaderEvent);
|
||||
}
|
||||
|
||||
ArchiveReaderEvent::~ArchiveReaderEvent()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_ReleaseOnMainThread(mMimeService.forget());
|
||||
}
|
||||
|
||||
MOZ_COUNT_DTOR(ArchiveReaderEvent);
|
||||
}
|
||||
|
||||
// From the filename to the mimetype:
|
||||
nsresult
|
||||
ArchiveReaderEvent::GetType(nsCString& aExt,
|
||||
nsCString& aMimeType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mMimeService.get() == nullptr) {
|
||||
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;
|
||||
|
||||
NS_DispatchToMainThread(NewRunnableMethod(this, &ArchiveReaderEvent::ShareMainThread));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ArchiveReaderEvent::ShareMainThread()
|
||||
{
|
||||
nsTArray<RefPtr<File>> fileList;
|
||||
|
||||
if (!NS_FAILED(mStatus)) {
|
||||
// This extra step must run in the main thread:
|
||||
for (uint32_t index = 0; index < mFileList.Length(); ++index) {
|
||||
RefPtr<ArchiveItem> item = mFileList[index];
|
||||
|
||||
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) {
|
||||
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(filename, type))) {
|
||||
item->SetType(type);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a File:
|
||||
RefPtr<File> file = item->GetFile(mArchiveReader);
|
||||
if (file) {
|
||||
fileList.AppendElement(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mArchiveReader->Ready(fileList, mStatus);
|
||||
}
|
||||
84
dom/archivereader/ArchiveEvent.h
Normal file
84
dom/archivereader/ArchiveEvent.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_archivereader_domarchiveevent_h__
|
||||
#define mozilla_dom_archivereader_domarchiveevent_h__
|
||||
|
||||
#include "ArchiveReader.h"
|
||||
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsIMIMEService.h"
|
||||
|
||||
#include "ArchiveReaderCommon.h"
|
||||
|
||||
BEGIN_ARCHIVEREADER_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_THREADSAFE_ISUPPORTS
|
||||
|
||||
ArchiveItem();
|
||||
|
||||
// Getter/Setter for the type
|
||||
nsCString GetType();
|
||||
void SetType(const nsCString& aType);
|
||||
|
||||
// Getter for the filename
|
||||
virtual nsresult GetFilename(nsString& aFilename) = 0;
|
||||
|
||||
// Generate a File
|
||||
virtual already_AddRefed<File> GetFile(ArchiveReader* aArchiveReader) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~ArchiveItem();
|
||||
|
||||
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 Runnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
explicit ArchiveReaderEvent(ArchiveReader* aArchiveReader);
|
||||
|
||||
protected:
|
||||
virtual ~ArchiveReaderEvent();
|
||||
|
||||
public:
|
||||
// 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<RefPtr<ArchiveItem> > mFileList; // this must be populated
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
END_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_archivereader_domarchiveevent_h__
|
||||
217
dom/archivereader/ArchiveReader.cpp
Normal file
217
dom/archivereader/ArchiveReader.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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 "nsIURI.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
#include "mozilla/dom/ArchiveReaderBinding.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
USING_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
/* static */ already_AddRefed<ArchiveReader>
|
||||
ArchiveReader::Constructor(const GlobalObject& aGlobal,
|
||||
Blob& aBlob,
|
||||
const ArchiveReaderOptions& aOptions,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString encoding;
|
||||
if (!EncodingUtils::FindEncodingForLabelNoReplacement(aOptions.mEncoding,
|
||||
encoding)) {
|
||||
aError.ThrowRangeError<MSG_ENCODING_NOT_SUPPORTED>(aOptions.mEncoding);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ArchiveReader> reader =
|
||||
new ArchiveReader(aBlob, window, encoding);
|
||||
return reader.forget();
|
||||
}
|
||||
|
||||
ArchiveReader::ArchiveReader(Blob& aBlob, nsPIDOMWindowInner* aWindow,
|
||||
const nsACString& aEncoding)
|
||||
: mBlobImpl(aBlob.Impl())
|
||||
, mWindow(aWindow)
|
||||
, mStatus(NOT_STARTED)
|
||||
, mEncoding(aEncoding)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
}
|
||||
|
||||
ArchiveReader::~ArchiveReader()
|
||||
{
|
||||
}
|
||||
|
||||
/* virtual */ JSObject*
|
||||
ArchiveReader::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return ArchiveReaderBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
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
|
||||
ErrorResult rv;
|
||||
mBlobImpl->GetInternalStream(aInputStream, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveReader::GetSize(uint64_t* aSize)
|
||||
{
|
||||
ErrorResult rv;
|
||||
*aSize = mBlobImpl->GetSize(rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
// 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:
|
||||
RefPtr<ArchiveReaderEvent> event;
|
||||
|
||||
/* FIXME: If we want to support more than 1 format we should check the content type here: */
|
||||
event = new ArchiveReaderZipEvent(this, mEncoding);
|
||||
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<RefPtr<File>>& aFileList,
|
||||
nsresult aStatus)
|
||||
{
|
||||
mStatus = READY;
|
||||
|
||||
// Let's store the values:
|
||||
mData.fileList = aFileList;
|
||||
mData.status = aStatus;
|
||||
|
||||
// Propagate the results:
|
||||
for (uint32_t index = 0; index < mRequests.Length(); ++index) {
|
||||
RefPtr<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);
|
||||
}
|
||||
|
||||
already_AddRefed<ArchiveRequest>
|
||||
ArchiveReader::GetFilenames()
|
||||
{
|
||||
RefPtr<ArchiveRequest> request = GenerateArchiveRequest();
|
||||
request->OpGetFilenames();
|
||||
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ArchiveRequest>
|
||||
ArchiveReader::GetFile(const nsAString& filename)
|
||||
{
|
||||
RefPtr<ArchiveRequest> request = GenerateArchiveRequest();
|
||||
request->OpGetFile(filename);
|
||||
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ArchiveRequest>
|
||||
ArchiveReader::GetFiles()
|
||||
{
|
||||
RefPtr<ArchiveRequest> request = GenerateArchiveRequest();
|
||||
request->OpGetFiles();
|
||||
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ArchiveRequest>
|
||||
ArchiveReader::GenerateArchiveRequest()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
return ArchiveRequest::Create(mWindow, this);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ArchiveReader,
|
||||
mBlobImpl,
|
||||
mWindow,
|
||||
mData.fileList,
|
||||
mRequests)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ArchiveReader)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ArchiveReader)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ArchiveReader)
|
||||
119
dom/archivereader/ArchiveReader.h
Normal file
119
dom/archivereader/ArchiveReader.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_archivereader_domarchivereader_h__
|
||||
#define mozilla_dom_archivereader_domarchivereader_h__
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "ArchiveReaderCommon.h"
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
struct ArchiveReaderOptions;
|
||||
class Blob;
|
||||
class BlobImpl;
|
||||
class File;
|
||||
class GlobalObject;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
class ArchiveRequest;
|
||||
|
||||
/**
|
||||
* This is the ArchiveReader object
|
||||
*/
|
||||
class ArchiveReader final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ArchiveReader)
|
||||
|
||||
static already_AddRefed<ArchiveReader>
|
||||
Constructor(const GlobalObject& aGlobal, Blob& aBlob,
|
||||
const ArchiveReaderOptions& aOptions, ErrorResult& aError);
|
||||
|
||||
ArchiveReader(Blob& aBlob, nsPIDOMWindowInner* aWindow,
|
||||
const nsACString& aEncoding);
|
||||
|
||||
nsPIDOMWindowInner* GetParentObject() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
already_AddRefed<ArchiveRequest> GetFilenames();
|
||||
already_AddRefed<ArchiveRequest> GetFile(const nsAString& filename);
|
||||
already_AddRefed<ArchiveRequest> GetFiles();
|
||||
|
||||
nsresult GetInputStream(nsIInputStream** aInputStream);
|
||||
nsresult GetSize(uint64_t* aSize);
|
||||
|
||||
public: // for the ArchiveRequest:
|
||||
nsresult RegisterRequest(ArchiveRequest* aRequest);
|
||||
|
||||
public: // For events:
|
||||
BlobImpl* GetBlobImpl() const
|
||||
{
|
||||
return mBlobImpl;
|
||||
}
|
||||
|
||||
void Ready(nsTArray<RefPtr<File>>& aFileList, nsresult aStatus);
|
||||
|
||||
private:
|
||||
~ArchiveReader();
|
||||
|
||||
already_AddRefed<ArchiveRequest> GenerateArchiveRequest();
|
||||
|
||||
nsresult OpenArchive();
|
||||
|
||||
void RequestReady(ArchiveRequest* aRequest);
|
||||
|
||||
protected:
|
||||
// The archive blob/file
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
|
||||
// The window is needed by the requests
|
||||
nsCOMPtr<nsPIDOMWindowInner> 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<RefPtr<ArchiveRequest> > mRequests;
|
||||
|
||||
// Everything related to the blobs and the status:
|
||||
struct {
|
||||
nsTArray<RefPtr<File>> fileList;
|
||||
nsresult status;
|
||||
} mData;
|
||||
|
||||
nsCString mEncoding;
|
||||
};
|
||||
|
||||
END_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_archivereader_domarchivereader_h__
|
||||
24
dom/archivereader/ArchiveReaderCommon.h
Normal file
24
dom/archivereader/ArchiveReaderCommon.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_archivereader_archivereader_h
|
||||
#define mozilla_dom_archivereader_archivereader_h
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define BEGIN_ARCHIVEREADER_NAMESPACE \
|
||||
namespace mozilla { namespace dom { namespace archivereader {
|
||||
#define END_ARCHIVEREADER_NAMESPACE \
|
||||
} /* namespace archivereader */ } /* namespace dom */ } /* namespace mozilla */
|
||||
#define USING_ARCHIVEREADER_NAMESPACE \
|
||||
using namespace mozilla::dom::archivereader;
|
||||
|
||||
#endif // mozilla_dom_archivereader_archivereadercommon_h
|
||||
277
dom/archivereader/ArchiveRequest.cpp
Normal file
277
dom/archivereader/ArchiveRequest.cpp
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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 "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/dom/ArchiveRequestBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
USING_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
/**
|
||||
* Class used to make asynchronous the ArchiveRequest.
|
||||
*/
|
||||
class ArchiveRequestEvent : public Runnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
explicit ArchiveRequestEvent(ArchiveRequest* aRequest)
|
||||
: mRequest(aRequest)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ArchiveRequestEvent);
|
||||
}
|
||||
|
||||
protected:
|
||||
~ArchiveRequestEvent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ArchiveRequestEvent);
|
||||
}
|
||||
|
||||
private: //data
|
||||
RefPtr<ArchiveRequest> mRequest;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArchiveRequestEvent::Run()
|
||||
{
|
||||
MOZ_ASSERT(mRequest, "the request is not longer valid");
|
||||
mRequest->Run();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// ArchiveRequest
|
||||
|
||||
ArchiveRequest::ArchiveRequest(nsPIDOMWindowInner* aWindow,
|
||||
ArchiveReader* aReader)
|
||||
: DOMRequest(aWindow),
|
||||
mArchiveReader(aReader)
|
||||
{
|
||||
MOZ_ASSERT(aReader);
|
||||
|
||||
MOZ_COUNT_CTOR(ArchiveRequest);
|
||||
|
||||
/* An event to make this request asynchronous: */
|
||||
RefPtr<ArchiveRequestEvent> event = new ArchiveRequestEvent(this);
|
||||
NS_DispatchToCurrentThread(event);
|
||||
}
|
||||
|
||||
ArchiveRequest::~ArchiveRequest()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ArchiveRequest);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* virtual */ JSObject*
|
||||
ArchiveRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return ArchiveRequestBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
ArchiveReader*
|
||||
ArchiveRequest::Reader() const
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
return mArchiveReader;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void
|
||||
ArchiveRequest::OpGetFiles()
|
||||
{
|
||||
mOperation = GetFiles;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::ReaderReady(nsTArray<RefPtr<File>>& aFileList,
|
||||
nsresult aStatus)
|
||||
{
|
||||
if (NS_FAILED(aStatus)) {
|
||||
FireError(aStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
switch (mOperation) {
|
||||
case GetFilenames:
|
||||
rv = GetFilenamesResult(cx, result.address(), aFileList);
|
||||
break;
|
||||
|
||||
case GetFile:
|
||||
rv = GetFileResult(cx, &result, aFileList);
|
||||
break;
|
||||
|
||||
case GetFiles:
|
||||
rv = GetFilesResult(cx, &result, aFileList);
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Get*Result failed!");
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
FireSuccess(result);
|
||||
}
|
||||
else {
|
||||
FireError(rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
||||
JS::Value* aValue,
|
||||
nsTArray<RefPtr<File>>& aFileList)
|
||||
{
|
||||
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length()));
|
||||
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
JS::Rooted<JSString*> str(aCx);
|
||||
for (uint32_t i = 0; i < aFileList.Length(); ++i) {
|
||||
RefPtr<File> file = aFileList[i];
|
||||
|
||||
nsString filename;
|
||||
file->GetName(filename);
|
||||
|
||||
str = JS_NewUCStringCopyZ(aCx, filename.get());
|
||||
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (!JS_DefineElement(aCx, array, i, str, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!JS_FreezeObject(aCx, array)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aValue->setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::GetFileResult(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
nsTArray<RefPtr<File>>& aFileList)
|
||||
{
|
||||
for (uint32_t i = 0; i < aFileList.Length(); ++i) {
|
||||
RefPtr<File> file = aFileList[i];
|
||||
|
||||
nsString filename;
|
||||
file->GetName(filename);
|
||||
|
||||
if (filename == mFilename) {
|
||||
if (!ToJSValue(aCx, file, aValue)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::GetFilesResult(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
nsTArray<RefPtr<File>>& aFileList)
|
||||
{
|
||||
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length()));
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aFileList.Length(); ++i) {
|
||||
RefPtr<File> file = aFileList[i];
|
||||
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!ToJSValue(aCx, file, &value)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!JS_DefineElement(aCx, array, i, value, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
aValue.setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<ArchiveRequest>
|
||||
ArchiveRequest::Create(nsPIDOMWindowInner* aOwner,
|
||||
ArchiveReader* aReader)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
RefPtr<ArchiveRequest> request = new ArchiveRequest(aOwner, aReader);
|
||||
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(ArchiveRequest, DOMRequest,
|
||||
mArchiveReader)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ArchiveRequest)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(ArchiveRequest, DOMRequest)
|
||||
NS_IMPL_RELEASE_INHERITED(ArchiveRequest, DOMRequest)
|
||||
88
dom/archivereader/ArchiveRequest.h
Normal file
88
dom/archivereader/ArchiveRequest.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_archivereader_domarchiverequest_h__
|
||||
#define mozilla_dom_archivereader_domarchiverequest_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "ArchiveReader.h"
|
||||
#include "DOMRequest.h"
|
||||
|
||||
#include "ArchiveReaderCommon.h"
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPreVisitor;
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
/**
|
||||
* This is the ArchiveRequest that handles any operation
|
||||
* related to ArchiveReader
|
||||
*/
|
||||
class ArchiveRequest : public mozilla::dom::DOMRequest
|
||||
{
|
||||
public:
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
ArchiveReader* Reader() const;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ArchiveRequest, DOMRequest)
|
||||
|
||||
ArchiveRequest(nsPIDOMWindowInner* aWindow,
|
||||
ArchiveReader* aReader);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
public:
|
||||
// This is called by the DOMArchiveRequestEvent
|
||||
void Run();
|
||||
|
||||
// Set the types for this request
|
||||
void OpGetFilenames();
|
||||
void OpGetFile(const nsAString& aFilename);
|
||||
void OpGetFiles();
|
||||
|
||||
nsresult ReaderReady(nsTArray<RefPtr<File>>& aFileList, nsresult aStatus);
|
||||
|
||||
public: // static
|
||||
static already_AddRefed<ArchiveRequest> Create(nsPIDOMWindowInner* aOwner,
|
||||
ArchiveReader* aReader);
|
||||
|
||||
private:
|
||||
~ArchiveRequest();
|
||||
|
||||
nsresult GetFilenamesResult(JSContext* aCx,
|
||||
JS::Value* aValue,
|
||||
nsTArray<RefPtr<File>>& aFileList);
|
||||
nsresult GetFileResult(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
nsTArray<RefPtr<File>>& aFileList);
|
||||
nsresult GetFilesResult(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
nsTArray<RefPtr<File>>& aFileList);
|
||||
|
||||
protected:
|
||||
// The reader:
|
||||
RefPtr<ArchiveReader> mArchiveReader;
|
||||
|
||||
// The operation:
|
||||
enum {
|
||||
GetFilenames,
|
||||
GetFile,
|
||||
GetFiles
|
||||
} mOperation;
|
||||
|
||||
// The filename (needed by GetFile):
|
||||
nsString mFilename;
|
||||
};
|
||||
|
||||
END_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_archivereader_domarchiverequest_h__
|
||||
216
dom/archivereader/ArchiveZipEvent.cpp
Normal file
216
dom/archivereader/ArchiveZipEvent.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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"
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
USING_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 65536 // The filename length is stored in 2 bytes
|
||||
#endif
|
||||
|
||||
ArchiveZipItem::ArchiveZipItem(const char* aFilename,
|
||||
const ZipCentral& aCentralStruct,
|
||||
const nsACString& aEncoding)
|
||||
: mFilename(aFilename),
|
||||
mCentralStruct(aCentralStruct),
|
||||
mEncoding(aEncoding)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ArchiveZipItem);
|
||||
}
|
||||
|
||||
ArchiveZipItem::~ArchiveZipItem()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ArchiveZipItem);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveZipItem::ConvertFilename()
|
||||
{
|
||||
if (mEncoding.IsEmpty()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsString filenameU;
|
||||
nsresult rv = nsContentUtils::ConvertStringFromEncoding(
|
||||
mEncoding,
|
||||
mFilename, filenameU);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (filenameU.IsEmpty()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mFilenameU = filenameU;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveZipItem::GetFilename(nsString& 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 File:
|
||||
already_AddRefed<File>
|
||||
ArchiveZipItem::GetFile(ArchiveReader* aArchiveReader)
|
||||
{
|
||||
nsString filename;
|
||||
|
||||
if (NS_FAILED(GetFilename(filename))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<dom::File> file = dom::File::Create(aArchiveReader,
|
||||
new ArchiveZipBlobImpl(filename,
|
||||
NS_ConvertUTF8toUTF16(GetType()),
|
||||
StrToInt32(mCentralStruct.orglen),
|
||||
mCentralStruct, aArchiveReader->GetBlobImpl()));
|
||||
MOZ_ASSERT(file);
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ArchiveZipItem::StrToInt32(const uint8_t* aStr)
|
||||
{
|
||||
return (uint32_t)( (aStr [0] << 0) |
|
||||
(aStr [1] << 8) |
|
||||
(aStr [2] << 16) |
|
||||
(aStr [3] << 24) );
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ArchiveZipItem::StrToInt16(const uint8_t* aStr)
|
||||
{
|
||||
return (uint16_t) ((aStr [0]) | (aStr [1] << 8));
|
||||
}
|
||||
|
||||
// ArchiveReaderZipEvent
|
||||
|
||||
ArchiveReaderZipEvent::ArchiveReaderZipEvent(ArchiveReader* aArchiveReader,
|
||||
const nsACString& aEncoding)
|
||||
: ArchiveReaderEvent(aArchiveReader),
|
||||
mEncoding(aEncoding)
|
||||
{
|
||||
}
|
||||
|
||||
// NOTE: this runs in a different thread!!
|
||||
nsresult
|
||||
ArchiveReaderZipEvent::Exec()
|
||||
{
|
||||
uint32_t centralOffset(0);
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = mArchiveReader->GetInputStream(getter_AddRefs(inputStream));
|
||||
if (NS_FAILED(rv) || !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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
uint32_t ret;
|
||||
|
||||
rv = inputStream->Read((char*)¢ralStruct, ZIPCENTRAL_SIZE, &ret);
|
||||
if (NS_FAILED(rv) || ret != ZIPCENTRAL_SIZE) {
|
||||
return RunShare(NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
uint16_t filenameLen = ArchiveZipItem::StrToInt16(centralStruct.filename_len);
|
||||
uint16_t extraLen = ArchiveZipItem::StrToInt16(centralStruct.extrafield_len);
|
||||
uint16_t 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:
|
||||
auto filename = MakeUnique<char[]>(filenameLen + 1);
|
||||
rv = inputStream->Read(filename.get(), filenameLen, &ret);
|
||||
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.get(), centralStruct,
|
||||
mEncoding));
|
||||
}
|
||||
|
||||
// Ignore the rest
|
||||
seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, extraLen + commentLen);
|
||||
}
|
||||
|
||||
return RunShare(NS_OK);
|
||||
}
|
||||
70
dom/archivereader/ArchiveZipEvent.h
Normal file
70
dom/archivereader/ArchiveZipEvent.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_archivereader_domarchivezipevent_h__
|
||||
#define mozilla_dom_archivereader_domarchivezipevent_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "ArchiveEvent.h"
|
||||
|
||||
#include "ArchiveReaderCommon.h"
|
||||
#include "zipstruct.h"
|
||||
|
||||
BEGIN_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
/**
|
||||
* ArchiveZipItem - ArchiveItem for ArchiveReaderZipEvent
|
||||
*/
|
||||
class ArchiveZipItem : public ArchiveItem
|
||||
{
|
||||
public:
|
||||
ArchiveZipItem(const char* aFilename,
|
||||
const ZipCentral& aCentralStruct,
|
||||
const nsACString& aEncoding);
|
||||
protected:
|
||||
virtual ~ArchiveZipItem();
|
||||
|
||||
public:
|
||||
nsresult GetFilename(nsString& aFilename) override;
|
||||
|
||||
// From zipItem to File:
|
||||
virtual already_AddRefed<File>
|
||||
GetFile(ArchiveReader* aArchiveReader) override;
|
||||
|
||||
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;
|
||||
|
||||
nsCString mEncoding;
|
||||
};
|
||||
|
||||
/**
|
||||
* ArchiveReaderEvent implements the ArchiveReaderEvent for the ZIP format
|
||||
*/
|
||||
class ArchiveReaderZipEvent : public ArchiveReaderEvent
|
||||
{
|
||||
public:
|
||||
ArchiveReaderZipEvent(ArchiveReader* aArchiveReader,
|
||||
const nsACString& aEncoding);
|
||||
|
||||
nsresult Exec() override;
|
||||
|
||||
private:
|
||||
nsCString mEncoding;
|
||||
};
|
||||
|
||||
END_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_archivereader_domarchivezipevent_h__
|
||||
402
dom/archivereader/ArchiveZipFile.cpp
Normal file
402
dom/archivereader/ArchiveZipFile.cpp
Normal file
|
|
@ -0,0 +1,402 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
USING_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
#define ZIP_CHUNK 16384
|
||||
|
||||
/**
|
||||
* Input stream object for zip files
|
||||
*/
|
||||
class ArchiveInputStream final : public nsIInputStream,
|
||||
public nsISeekableStream
|
||||
{
|
||||
public:
|
||||
ArchiveInputStream(uint64_t aParentSize,
|
||||
nsIInputStream* aInputStream,
|
||||
nsString& aFilename,
|
||||
uint32_t aStart,
|
||||
uint32_t aLength,
|
||||
ZipCentral& aCentral)
|
||||
: mCentral(aCentral),
|
||||
mFilename(aFilename),
|
||||
mStart(aStart),
|
||||
mLength(aLength),
|
||||
mStatus(NotStarted)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ArchiveInputStream);
|
||||
|
||||
// Reset the data:
|
||||
memset(&mData, 0, sizeof(mData));
|
||||
|
||||
mData.parentSize = aParentSize;
|
||||
mData.inputStream = aInputStream;
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
|
||||
private:
|
||||
virtual ~ArchiveInputStream()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ArchiveInputStream);
|
||||
Close();
|
||||
}
|
||||
|
||||
nsresult Init();
|
||||
|
||||
private: // data
|
||||
ZipCentral mCentral;
|
||||
nsString mFilename;
|
||||
uint32_t mStart;
|
||||
uint32_t mLength;
|
||||
|
||||
z_stream mZs;
|
||||
|
||||
enum {
|
||||
NotStarted,
|
||||
Started,
|
||||
Done
|
||||
} mStatus;
|
||||
|
||||
struct {
|
||||
uint64_t parentSize;
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
|
||||
unsigned char input[ZIP_CHUNK];
|
||||
uint32_t sizeToBeRead;
|
||||
uint32_t cursor;
|
||||
|
||||
bool compressed; // a zip file can contain stored or compressed files
|
||||
} mData;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ArchiveInputStream,
|
||||
nsIInputStream,
|
||||
nsISeekableStream)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mData.sizeToBeRead = ArchiveZipItem::StrToInt32(mCentral.size);
|
||||
|
||||
uint32_t offset = ArchiveZipItem::StrToInt32(mCentral.localhdr_offset);
|
||||
|
||||
// The file is corrupt
|
||||
if (mData.parentSize < ZIPLOCAL_SIZE ||
|
||||
offset > mData.parentSize - ZIPLOCAL_SIZE) {
|
||||
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);
|
||||
uint8_t buffer[ZIPLOCAL_SIZE];
|
||||
uint32_t ret;
|
||||
|
||||
rv = mData.inputStream->Read((char*)buffer, ZIPLOCAL_SIZE, &ret);
|
||||
if (NS_FAILED(rv) || 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 (mData.parentSize < mData.sizeToBeRead ||
|
||||
offset > mData.parentSize - mData.sizeToBeRead) {
|
||||
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) {
|
||||
rv = Seek(NS_SEEK_SET, mStart);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArchiveInputStream::Close()
|
||||
{
|
||||
if (mStatus != NotStarted) {
|
||||
inflateEnd(&mZs);
|
||||
mStatus = NotStarted;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArchiveInputStream::Available(uint64_t* _retval)
|
||||
{
|
||||
*_retval = mLength - mData.cursor - mStart;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArchiveInputStream::Read(char* aBuffer,
|
||||
uint32_t aCount,
|
||||
uint32_t* _retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aBuffer);
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// This is the first time:
|
||||
if (mStatus == NotStarted) {
|
||||
mStatus = Started;
|
||||
|
||||
rv = Init();
|
||||
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) {
|
||||
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) {
|
||||
mStatus = Done;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We have nothing ready to be processed:
|
||||
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)) {
|
||||
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) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (ret == Z_STREAM_END) {
|
||||
mStatus = Done;
|
||||
}
|
||||
|
||||
*_retval = aCount - mZs.avail_out;
|
||||
mData.cursor += *_retval;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArchiveInputStream::ReadSegments(nsWriteSegmentFun aWriter,
|
||||
void* aClosure,
|
||||
uint32_t aCount,
|
||||
uint32_t* _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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArchiveInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
{
|
||||
int64_t pos = aOffset;
|
||||
|
||||
switch (aWhence) {
|
||||
case NS_SEEK_SET:
|
||||
break;
|
||||
|
||||
case NS_SEEK_CUR:
|
||||
pos += mData.cursor;
|
||||
break;
|
||||
|
||||
case NS_SEEK_END:
|
||||
pos += mLength;
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_NOTREACHED("unexpected whence value");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (pos == int64_t(mData.cursor)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
pos -= ret;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArchiveInputStream::Tell(int64_t *aResult)
|
||||
{
|
||||
*aResult = mData.cursor;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArchiveInputStream::SetEOF()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// ArchiveZipBlobImpl
|
||||
|
||||
void
|
||||
ArchiveZipBlobImpl::GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (mLength > INT32_MAX) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t size = mBlobImpl->GetSize(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
mBlobImpl->GetInternalStream(getter_AddRefs(inputStream), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ArchiveInputStream> stream = new ArchiveInputStream(size,
|
||||
inputStream,
|
||||
mFilename,
|
||||
mStart,
|
||||
mLength,
|
||||
mCentral);
|
||||
|
||||
stream.forget(aStream);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::BlobImpl>
|
||||
ArchiveZipBlobImpl::CreateSlice(uint64_t aStart,
|
||||
uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
mozilla::ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<BlobImpl> impl =
|
||||
new ArchiveZipBlobImpl(mFilename, mContentType, aStart, mLength, mCentral,
|
||||
mBlobImpl);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(ArchiveZipBlobImpl, BlobImpl)
|
||||
81
dom/archivereader/ArchiveZipFile.h
Normal file
81
dom/archivereader/ArchiveZipFile.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_archivereader_domarchivefile_h__
|
||||
#define mozilla_dom_archivereader_domarchivefile_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
||||
#include "ArchiveReader.h"
|
||||
|
||||
#include "ArchiveReaderCommon.h"
|
||||
#include "zipstruct.h"
|
||||
|
||||
BEGIN_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
/**
|
||||
* ArchiveZipBlobImpl to BlobImpl
|
||||
*/
|
||||
class ArchiveZipBlobImpl : public BlobImplBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
ArchiveZipBlobImpl(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
ZipCentral& aCentral,
|
||||
BlobImpl* aBlobImpl)
|
||||
: BlobImplBase(aName, aContentType, aLength),
|
||||
mCentral(aCentral),
|
||||
mBlobImpl(aBlobImpl),
|
||||
mFilename(aName)
|
||||
{
|
||||
MOZ_ASSERT(mBlobImpl);
|
||||
MOZ_COUNT_CTOR(ArchiveZipBlobImpl);
|
||||
}
|
||||
|
||||
ArchiveZipBlobImpl(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aStart,
|
||||
uint64_t aLength,
|
||||
ZipCentral& aCentral,
|
||||
BlobImpl* aBlobImpl)
|
||||
: BlobImplBase(aContentType, aStart, aLength),
|
||||
mCentral(aCentral),
|
||||
mBlobImpl(aBlobImpl),
|
||||
mFilename(aName)
|
||||
{
|
||||
MOZ_ASSERT(mBlobImpl);
|
||||
MOZ_COUNT_CTOR(ArchiveZipBlobImpl);
|
||||
}
|
||||
|
||||
// Overrides:
|
||||
virtual void GetInternalStream(nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
protected:
|
||||
virtual ~ArchiveZipBlobImpl()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ArchiveZipBlobImpl);
|
||||
}
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
mozilla::ErrorResult& aRv) override;
|
||||
|
||||
private: // Data
|
||||
ZipCentral mCentral;
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
|
||||
nsString mFilename;
|
||||
};
|
||||
|
||||
END_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_archivereader_domarchivefile_h__
|
||||
30
dom/archivereader/moz.build
Normal file
30
dom/archivereader/moz.build
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXPORTS.mozilla.dom.archivereader += [
|
||||
'ArchiveEvent.h',
|
||||
'ArchiveReader.h',
|
||||
'ArchiveReaderCommon.h',
|
||||
'ArchiveRequest.h',
|
||||
'ArchiveZipEvent.h',
|
||||
'ArchiveZipFile.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ArchiveEvent.cpp',
|
||||
'ArchiveReader.cpp',
|
||||
'ArchiveRequest.cpp',
|
||||
'ArchiveZipEvent.cpp',
|
||||
'ArchiveZipFile.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../base',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
31
dom/archivereader/test/helpers.js
Normal file
31
dom/archivereader/test/helpers.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator;
|
||||
|
||||
function runTest()
|
||||
{
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [ ["dom.archivereader.enabled", true] ]}, function() {
|
||||
SpecialPowers.createFiles(filesToCreate(),
|
||||
function (files) {
|
||||
testGenerator = testSteps(files);
|
||||
return testGenerator.next();
|
||||
},
|
||||
function (msg) {
|
||||
ok(false, "File creation error: " + msg);
|
||||
finishTest();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
SpecialPowers.popPrefEnv(function() {
|
||||
testGenerator.close();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
7
dom/archivereader/test/mochitest.ini
Normal file
7
dom/archivereader/test/mochitest.ini
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
helpers.js
|
||||
|
||||
[test_basic.html]
|
||||
[test_nonUnicode.html]
|
||||
[test_zip_in_zip.html]
|
||||
227
dom/archivereader/test/test_basic.html
Normal file
227
dom/archivereader/test/test_basic.html
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
<!--
|
||||
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 filesToCreate() {
|
||||
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));
|
||||
}
|
||||
|
||||
return [ {name: "fileArchiveReader.zip", data: binaryData},
|
||||
{name: "fileArchiveReader.txt", data: "Hello World"}];
|
||||
}
|
||||
|
||||
handleFinished = 0;
|
||||
function markTestDone() {
|
||||
++handleFinished;
|
||||
if (isFinished()) {
|
||||
finishTest();
|
||||
}
|
||||
}
|
||||
function isFinished() {
|
||||
return handleFinished == 6;
|
||||
}
|
||||
|
||||
function testSteps(files)
|
||||
{
|
||||
var binaryFile = files[0];
|
||||
var textFile = files[1];
|
||||
|
||||
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");
|
||||
markTestDone();
|
||||
}
|
||||
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");
|
||||
markTestDone();
|
||||
}
|
||||
|
||||
// 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");
|
||||
markTestDone();
|
||||
}
|
||||
handle.onerror = function() {
|
||||
ok(false, "ArchiveReader.getFilenames() should not return any 'error'");
|
||||
markTestDone();
|
||||
}
|
||||
|
||||
// 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'");
|
||||
markTestDone();
|
||||
}
|
||||
handle2.onerror = function() {
|
||||
ok(true, "ArchiveReader.getFile('unknown file') should return an 'error'");
|
||||
ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
|
||||
markTestDone();
|
||||
}
|
||||
|
||||
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!");
|
||||
markTestDone();
|
||||
}
|
||||
fr.onload = function(event) {
|
||||
is(event.target.result, "hello world, 2!\n", "ArchiveReader + FileReader are working together.");
|
||||
markTestDone();
|
||||
}
|
||||
}
|
||||
|
||||
handle3.onerror = function() {
|
||||
ok(false, "ArchiveReader.getFile('test/b.txt') should not return an 'error'");
|
||||
markTestDone();
|
||||
}
|
||||
|
||||
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!");
|
||||
markTestDone();
|
||||
}
|
||||
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");
|
||||
markTestDone();
|
||||
}
|
||||
}
|
||||
handle4.onerror = function() {
|
||||
ok(false, "ArchiveReader.getFile('test/a.txt') should not return an 'error'");
|
||||
markTestDone();
|
||||
}
|
||||
|
||||
var handle5 = r.getFiles();
|
||||
isnot(handle5, null, "ArchiveReader.getFiles() cannot be null");
|
||||
handle5.onsuccess = function() {
|
||||
ok(true, "ArchiveReader.getFiles() should return a 'success'");
|
||||
ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
|
||||
|
||||
is(this.result.length, 2, "ArchiveReader.getFilenames(): the array contains 2 items");
|
||||
is(this.result[0].name, "test/a.txt", "ArchiveReader.getFilenames(): first file is 'test/a.txt'");
|
||||
is(this.result[1].name, "test/b.txt", "ArchiveReader.getFilenames(): second file is 'test/b.txt'");
|
||||
is(this.result[0].type, "text/plain", "ArchiveReader.getFile('test/a.txt') the type MUST be 'text/plain'");
|
||||
is(this.result[1].type, "text/plain", "ArchiveReader.getFile('test/a.txt') the type MUST be 'text/plain'");
|
||||
|
||||
markTestDone();
|
||||
}
|
||||
handle5.onerror = function() {
|
||||
ok(false, "ArchiveReader.getFiles() should not return an 'error'");
|
||||
markTestDone();
|
||||
}
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="runTest();">
|
||||
<p id="display">
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
77
dom/archivereader/test/test_nonUnicode.html
Normal file
77
dom/archivereader/test/test_nonUnicode.html
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<!--
|
||||
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 filesToCreate() {
|
||||
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));
|
||||
}
|
||||
return [ {name: "fileArchiveReader_nonUnicode.zip", data: binaryData} ];
|
||||
}
|
||||
|
||||
function test1(binaryFile)
|
||||
{
|
||||
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(binaryFile);
|
||||
}
|
||||
}
|
||||
|
||||
function test2(binaryFile)
|
||||
{
|
||||
try {
|
||||
new ArchiveReader(binaryFile, { encoding: "random stuff" });
|
||||
ok(false, "Should have thrown for bogus encoding label.");
|
||||
} catch (e) {
|
||||
ok(e instanceof RangeError, "Expected a RangeError");
|
||||
}
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function testSteps(files)
|
||||
{
|
||||
test1(files[0]);
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();">
|
||||
<p id="display">
|
||||
</p>
|
||||
<script type="text/javascript;version=1.7">
|
||||
var binaryString = '' +
|
||||
'504B0304140000000000255D094100000000000000000000000002000000912F504B03040A0000000000285D09416BB50A5A' +
|
||||
'010000000100000007000000912F9B2E747874D8504B01023F00140000000000255D09410000000000000000000000000200' +
|
||||
'24000000000000001000000000000000912F0A002000000000000100180062505F1A1376CD0162505F1A1376CD01FE3F8D59' +
|
||||
'1176CD01504B01023F000A0000000000285D09416BB50A5A0100000001000000070024000000000000002000000020000000' +
|
||||
'912F9B2E7478740A0020000000000001001800565EF41D1376CD0107BD73631176CD0107BD73631176CD01504B0506000000' +
|
||||
'0002000200AD000000460000000000';
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
111
dom/archivereader/test/test_zip_in_zip.html
Normal file
111
dom/archivereader/test/test_zip_in_zip.html
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Archive Reader Zip-In-Zip 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 filesToCreate() {
|
||||
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));
|
||||
}
|
||||
return [ {name: "fileArchiveReader_42.zip", data: binaryData} ];
|
||||
}
|
||||
|
||||
function testSteps(files)
|
||||
{
|
||||
var binaryFile = files[0];
|
||||
|
||||
// The input is 4 nested zip archives:
|
||||
doLoop(binaryFile, 4);
|
||||
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
function doLoop(blob, loop)
|
||||
{
|
||||
var r = new ArchiveReader(blob);
|
||||
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:\n');
|
||||
for (var i = 0; i < this.result.length; ++i)
|
||||
dump(' * ' + this.result[i] + '\n');
|
||||
|
||||
var handle = r.getFile(this.result[0]);
|
||||
handle.onerror = function() {
|
||||
ok(false, "ArchiveReader.getFile() should not return any 'error'");
|
||||
}
|
||||
handle.onsuccess = function() {
|
||||
ok(true, "ArchiveReader.getFilenames() should return a 'success'");
|
||||
ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
|
||||
|
||||
if (loop > 0)
|
||||
doLoop(this.result, loop - 1);
|
||||
else
|
||||
doLastLoop(this.result);
|
||||
}
|
||||
}
|
||||
handle.onerror = function() {
|
||||
ok(false, "ArchiveReader.getFilenames() should not return any 'error'");
|
||||
}
|
||||
}
|
||||
|
||||
function doLastLoop(blob)
|
||||
{
|
||||
ok(blob.size == 262144, "The last file size is wrong");
|
||||
ok(blob.name == 'empty.dat', "The last filename is wrong");
|
||||
finishTest();
|
||||
}
|
||||
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();">
|
||||
<p id="display">
|
||||
</p>
|
||||
<script type="text/javascript;version=1.7">
|
||||
var binaryString = '' +
|
||||
'504B03040A0000000000B0620E415F715F15970300009703000005001C00642E7A69705554090003AC262A50AC262A507578' +
|
||||
'0B000104E803000004E8030000504B03040A0000000000B0620E41CFE25F1EF7020000F702000005001C00632E7A69705554' +
|
||||
'090003AC262A50AC262A5075780B000104E803000004E8030000504B03040A0000000000B0620E4107D702A4570200005702' +
|
||||
'000005001C00622E7A69705554090003AC262A50AC262A5075780B000104E803000004E8030000504B03040A0000000000B0' +
|
||||
'620E417E45286DB7010000B701000005001C00612E7A69705554090003AC262A50AC262A5075780B000104E803000004E803' +
|
||||
'0000504B0304140000000800F7610E41784909B70F0100000000040009001C00656D7074792E646174555409000351252A50' +
|
||||
'57252A5075780B000104E803000004E8030000EDC13101000000C2A0FEA9E76D07A000000000000000000000000000000000' +
|
||||
'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +
|
||||
'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +
|
||||
'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +
|
||||
'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +
|
||||
'0000000000000000000000000000000000000000000000000000000000000000000000000000DE00504B01021E0314000000' +
|
||||
'0800F7610E41784909B70F01000000000400090018000000000001000000B48100000000656D7074792E6461745554050003' +
|
||||
'51252A5075780B000104E803000004E8030000504B050600000000010001004F000000520100000000504B01021E030A0000' +
|
||||
'000000B0620E417E45286DB7010000B7010000050018000000000000000000B48100000000612E7A69705554050003AC262A' +
|
||||
'5075780B000104E803000004E8030000504B050600000000010001004B000000F60100000000504B01021E030A0000000000' +
|
||||
'B0620E4107D702A45702000057020000050018000000000000000000B48100000000622E7A69705554050003AC262A507578' +
|
||||
'0B000104E803000004E8030000504B050600000000010001004B000000960200000000504B01021E030A0000000000B0620E' +
|
||||
'41CFE25F1EF7020000F7020000050018000000000000000000B48100000000632E7A69705554050003AC262A5075780B0001' +
|
||||
'04E803000004E8030000504B050600000000010001004B000000360300000000504B01021E030A0000000000B0620E415F71' +
|
||||
'5F159703000097030000050018000000000000000000B48100000000642E7A69705554050003AC262A5075780B000104E803' +
|
||||
'000004E8030000504B050600000000010001004B000000D60300000000';
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue