michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ArchiveRequest.h" michael@0: michael@0: #include "mozilla/EventDispatcher.h" michael@0: #include "mozilla/dom/ArchiveRequestBinding.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsCxPusher.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: USING_FILE_NAMESPACE michael@0: michael@0: /** michael@0: * Class used to make asynchronous the ArchiveRequest. michael@0: */ michael@0: class ArchiveRequestEvent : public nsRunnable michael@0: { michael@0: public: michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: ArchiveRequestEvent(ArchiveRequest* request) michael@0: : mRequest(request) michael@0: { michael@0: MOZ_COUNT_CTOR(ArchiveRequestEvent); michael@0: } michael@0: michael@0: ~ArchiveRequestEvent() michael@0: { michael@0: MOZ_COUNT_DTOR(ArchiveRequestEvent); michael@0: } michael@0: michael@0: private: //data michael@0: nsRefPtr mRequest; michael@0: }; michael@0: michael@0: NS_IMETHODIMP michael@0: ArchiveRequestEvent::Run() michael@0: { michael@0: NS_ABORT_IF_FALSE(mRequest, "the request is not longer valid"); michael@0: mRequest->Run(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // ArchiveRequest michael@0: michael@0: ArchiveRequest::ArchiveRequest(nsPIDOMWindow* aWindow, michael@0: ArchiveReader* aReader) michael@0: : DOMRequest(aWindow), michael@0: mArchiveReader(aReader) michael@0: { michael@0: MOZ_ASSERT(aReader); michael@0: michael@0: MOZ_COUNT_CTOR(ArchiveRequest); michael@0: michael@0: /* An event to make this request asynchronous: */ michael@0: nsRefPtr event = new ArchiveRequestEvent(this); michael@0: NS_DispatchToCurrentThread(event); michael@0: } michael@0: michael@0: ArchiveRequest::~ArchiveRequest() michael@0: { michael@0: MOZ_COUNT_DTOR(ArchiveRequest); michael@0: } michael@0: michael@0: nsresult michael@0: ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor) michael@0: { michael@0: aVisitor.mCanHandle = true; michael@0: aVisitor.mParentTarget = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* virtual */ JSObject* michael@0: ArchiveRequest::WrapObject(JSContext* aCx) michael@0: { michael@0: return ArchiveRequestBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: ArchiveReader* michael@0: ArchiveRequest::Reader() const michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return mArchiveReader; michael@0: } michael@0: michael@0: // Here the request is processed: michael@0: void michael@0: ArchiveRequest::Run() michael@0: { michael@0: // Register this request to the reader. michael@0: // When the reader is ready to return data, a 'Ready()' will be called michael@0: nsresult rv = mArchiveReader->RegisterRequest(this); michael@0: if (NS_FAILED(rv)) { michael@0: FireError(rv); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ArchiveRequest::OpGetFilenames() michael@0: { michael@0: mOperation = GetFilenames; michael@0: } michael@0: michael@0: void michael@0: ArchiveRequest::OpGetFile(const nsAString& aFilename) michael@0: { michael@0: mOperation = GetFile; michael@0: mFilename = aFilename; michael@0: } michael@0: michael@0: void michael@0: ArchiveRequest::OpGetFiles() michael@0: { michael@0: mOperation = GetFiles; michael@0: } michael@0: michael@0: nsresult michael@0: ArchiveRequest::ReaderReady(nsTArray >& aFileList, michael@0: nsresult aStatus) michael@0: { michael@0: if (NS_FAILED(aStatus)) { michael@0: FireError(aStatus); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: nsIScriptContext* sc = GetContextForEventHandlers(&rv); michael@0: NS_ENSURE_STATE(sc); michael@0: michael@0: AutoPushJSContext cx(sc->GetNativeContext()); michael@0: NS_ASSERTION(cx, "Failed to get a context!"); michael@0: michael@0: JS::Rooted global(cx, sc->GetWindowProxy()); michael@0: NS_ASSERTION(global, "Failed to get global object!"); michael@0: michael@0: JSAutoCompartment ac(cx, global); michael@0: michael@0: JS::Rooted result(cx); michael@0: switch (mOperation) { michael@0: case GetFilenames: michael@0: rv = GetFilenamesResult(cx, result.address(), aFileList); michael@0: break; michael@0: michael@0: case GetFile: michael@0: rv = GetFileResult(cx, &result, aFileList); michael@0: break; michael@0: michael@0: case GetFiles: michael@0: rv = GetFilesResult(cx, &result, aFileList); michael@0: break; michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Get*Result failed!"); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: FireSuccess(result); michael@0: } michael@0: else { michael@0: FireError(rv); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: ArchiveRequest::GetFilenamesResult(JSContext* aCx, michael@0: JS::Value* aValue, michael@0: nsTArray >& aFileList) michael@0: { michael@0: JS::Rooted array(aCx, JS_NewArrayObject(aCx, aFileList.Length())); michael@0: nsresult rv; michael@0: michael@0: if (!array) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: JS::Rooted str(aCx); michael@0: for (uint32_t i = 0; i < aFileList.Length(); ++i) { michael@0: nsCOMPtr file = aFileList[i]; michael@0: michael@0: nsString filename; michael@0: rv = file->GetName(filename); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: str = JS_NewUCStringCopyZ(aCx, filename.get()); michael@0: NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: if (NS_FAILED(rv) || michael@0: !JS_DefineElement(aCx, array, i, JS::StringValue(str), nullptr, nullptr, michael@0: JSPROP_ENUMERATE)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: if (!JS_FreezeObject(aCx, array)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: *aValue = OBJECT_TO_JSVAL(array); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: ArchiveRequest::GetFileResult(JSContext* aCx, michael@0: JS::MutableHandle aValue, michael@0: nsTArray >& aFileList) michael@0: { michael@0: for (uint32_t i = 0; i < aFileList.Length(); ++i) { michael@0: nsCOMPtr file = aFileList[i]; michael@0: michael@0: nsString filename; michael@0: nsresult rv = file->GetName(filename); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (filename == mFilename) { michael@0: return nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), michael@0: aValue); michael@0: } michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsresult michael@0: ArchiveRequest::GetFilesResult(JSContext* aCx, michael@0: JS::MutableHandle aValue, michael@0: nsTArray >& aFileList) michael@0: { michael@0: JS::Rooted array(aCx, JS_NewArrayObject(aCx, aFileList.Length())); michael@0: if (!array) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < aFileList.Length(); ++i) { michael@0: nsCOMPtr file = aFileList[i]; michael@0: michael@0: JS::Rooted value(aCx); michael@0: nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), michael@0: &value); michael@0: if (NS_FAILED(rv) || michael@0: !JS_DefineElement(aCx, array, i, value, nullptr, nullptr, michael@0: JSPROP_ENUMERATE)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: aValue.setObject(*array); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: already_AddRefed michael@0: ArchiveRequest::Create(nsPIDOMWindow* aOwner, michael@0: ArchiveReader* aReader) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: nsRefPtr request = new ArchiveRequest(aOwner, aReader); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_INHERITED(ArchiveRequest, DOMRequest, michael@0: mArchiveReader) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ArchiveRequest) michael@0: NS_INTERFACE_MAP_END_INHERITING(DOMRequest) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(ArchiveRequest, DOMRequest) michael@0: NS_IMPL_RELEASE_INHERITED(ArchiveRequest, DOMRequest)