summaryrefslogtreecommitdiffstats
path: root/dom/filesystem/compat/CallbackRunnables.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/filesystem/compat/CallbackRunnables.cpp')
-rw-r--r--dom/filesystem/compat/CallbackRunnables.cpp306
1 files changed, 306 insertions, 0 deletions
diff --git a/dom/filesystem/compat/CallbackRunnables.cpp b/dom/filesystem/compat/CallbackRunnables.cpp
new file mode 100644
index 000000000..efd14b03e
--- /dev/null
+++ b/dom/filesystem/compat/CallbackRunnables.cpp
@@ -0,0 +1,306 @@
+/* -*- 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 "CallbackRunnables.h"
+#include "mozilla/dom/Directory.h"
+#include "mozilla/dom/DirectoryBinding.h"
+#include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/FileBinding.h"
+#include "mozilla/dom/FileSystemDirectoryReaderBinding.h"
+#include "mozilla/dom/FileSystemFileEntry.h"
+#include "mozilla/dom/FileSystemUtils.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/Unused.h"
+#include "nsIGlobalObject.h"
+#include "nsIFile.h"
+#include "nsPIDOMWindow.h"
+
+#include "../GetFileOrDirectoryTask.h"
+
+namespace mozilla {
+namespace dom {
+
+EntryCallbackRunnable::EntryCallbackRunnable(FileSystemEntryCallback* aCallback,
+ FileSystemEntry* aEntry)
+ : mCallback(aCallback)
+ , mEntry(aEntry)
+{
+ MOZ_ASSERT(aCallback);
+ MOZ_ASSERT(aEntry);
+}
+
+NS_IMETHODIMP
+EntryCallbackRunnable::Run()
+{
+ mCallback->HandleEvent(*mEntry);
+ return NS_OK;
+}
+
+ErrorCallbackRunnable::ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject,
+ ErrorCallback* aCallback,
+ nsresult aError)
+ : mGlobal(aGlobalObject)
+ , mCallback(aCallback)
+ , mError(aError)
+{
+ MOZ_ASSERT(aGlobalObject);
+ MOZ_ASSERT(aCallback);
+ MOZ_ASSERT(NS_FAILED(aError));
+}
+
+NS_IMETHODIMP
+ErrorCallbackRunnable::Run()
+{
+ nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
+ if (NS_WARN_IF(!window)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<DOMException> exception = DOMException::Create(mError);
+ mCallback->HandleEvent(*exception);
+ return NS_OK;
+}
+
+EmptyEntriesCallbackRunnable::EmptyEntriesCallbackRunnable(FileSystemEntriesCallback* aCallback)
+ : mCallback(aCallback)
+{
+ MOZ_ASSERT(aCallback);
+}
+
+NS_IMETHODIMP
+EmptyEntriesCallbackRunnable::Run()
+{
+ Sequence<OwningNonNull<FileSystemEntry>> sequence;
+ mCallback->HandleEvent(sequence);
+ return NS_OK;
+}
+
+GetEntryHelper::GetEntryHelper(FileSystemDirectoryEntry* aParentEntry,
+ Directory* aDirectory,
+ nsTArray<nsString>& aParts,
+ FileSystem* aFileSystem,
+ FileSystemEntryCallback* aSuccessCallback,
+ ErrorCallback* aErrorCallback,
+ FileSystemDirectoryEntry::GetInternalType aType)
+ : mParentEntry(aParentEntry)
+ , mDirectory(aDirectory)
+ , mParts(aParts)
+ , mFileSystem(aFileSystem)
+ , mSuccessCallback(aSuccessCallback)
+ , mErrorCallback(aErrorCallback)
+ , mType(aType)
+{
+ MOZ_ASSERT(aParentEntry);
+ MOZ_ASSERT(aDirectory);
+ MOZ_ASSERT(!aParts.IsEmpty());
+ MOZ_ASSERT(aFileSystem);
+ MOZ_ASSERT(aSuccessCallback || aErrorCallback);
+}
+
+GetEntryHelper::~GetEntryHelper()
+{}
+
+namespace {
+
+nsresult
+DOMPathToRealPath(Directory* aDirectory, const nsAString& aPath,
+ nsIFile** aFile)
+{
+ nsString relativePath;
+ relativePath = aPath;
+
+ // Trim white spaces.
+ static const char kWhitespace[] = "\b\t\r\n ";
+ relativePath.Trim(kWhitespace);
+
+ nsTArray<nsString> parts;
+ if (!FileSystemUtils::IsValidRelativeDOMPath(relativePath, parts)) {
+ return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
+ }
+
+ nsCOMPtr<nsIFile> file;
+ nsresult rv = aDirectory->GetInternalNsIFile()->Clone(getter_AddRefs(file));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ for (uint32_t i = 0; i < parts.Length(); ++i) {
+ rv = file->AppendRelativePath(parts[i]);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ }
+
+ file.forget(aFile);
+ return NS_OK;
+}
+
+} // anonymous
+
+void
+GetEntryHelper::Run()
+{
+ MOZ_ASSERT(!mParts.IsEmpty());
+
+ nsCOMPtr<nsIFile> realPath;
+ nsresult error = DOMPathToRealPath(mDirectory, mParts[0],
+ getter_AddRefs(realPath));
+
+ ErrorResult rv;
+ RefPtr<FileSystemBase> fs = mDirectory->GetFileSystem(rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ rv.SuppressException();
+ Error(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+
+ RefPtr<GetFileOrDirectoryTaskChild> task =
+ GetFileOrDirectoryTaskChild::Create(fs, realPath, rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ rv.SuppressException();
+ Error(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+
+ task->SetError(error);
+ task->Start();
+
+ RefPtr<Promise> promise = task->GetPromise();
+
+ mParts.RemoveElementAt(0);
+ promise->AppendNativeHandler(this);
+}
+
+void
+GetEntryHelper::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
+{
+ if(NS_WARN_IF(!aValue.isObject())) {
+ return;
+ }
+
+ JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
+
+ // This is not the last part of the path.
+ if (!mParts.IsEmpty()) {
+ ContinueRunning(obj);
+ return;
+ }
+
+ CompleteOperation(obj);
+}
+
+void
+GetEntryHelper::CompleteOperation(JSObject* aObj)
+{
+ MOZ_ASSERT(mParts.IsEmpty());
+
+ if (mType == FileSystemDirectoryEntry::eGetFile) {
+ RefPtr<File> file;
+ if (NS_FAILED(UNWRAP_OBJECT(File, aObj, file))) {
+ Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+ return;
+ }
+
+ RefPtr<FileSystemFileEntry> entry =
+ new FileSystemFileEntry(mParentEntry->GetParentObject(), file,
+ mParentEntry, mFileSystem);
+ mSuccessCallback->HandleEvent(*entry);
+ return;
+ }
+
+ MOZ_ASSERT(mType == FileSystemDirectoryEntry::eGetDirectory);
+
+ RefPtr<Directory> directory;
+ if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
+ Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+ return;
+ }
+
+ RefPtr<FileSystemDirectoryEntry> entry =
+ new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory,
+ mParentEntry, mFileSystem);
+ mSuccessCallback->HandleEvent(*entry);
+}
+
+void
+GetEntryHelper::ContinueRunning(JSObject* aObj)
+{
+ MOZ_ASSERT(!mParts.IsEmpty());
+
+ RefPtr<Directory> directory;
+ if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
+ Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+ return;
+ }
+
+ RefPtr<FileSystemDirectoryEntry> entry =
+ new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory,
+ mParentEntry, mFileSystem);
+
+ // Update the internal values.
+ mParentEntry = entry;
+ mDirectory = directory;
+
+ Run();
+}
+
+void
+GetEntryHelper::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
+{
+ Error(NS_ERROR_DOM_NOT_FOUND_ERR);
+}
+
+void
+GetEntryHelper::Error(nsresult aError)
+{
+ MOZ_ASSERT(NS_FAILED(aError));
+
+ if (mErrorCallback) {
+ RefPtr<ErrorCallbackRunnable> runnable =
+ new ErrorCallbackRunnable(mParentEntry->GetParentObject(),
+ mErrorCallback, aError);
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+ }
+}
+
+NS_IMPL_ISUPPORTS0(GetEntryHelper);
+
+/* static */ void
+FileSystemEntryCallbackHelper::Call(const Optional<OwningNonNull<FileSystemEntryCallback>>& aEntryCallback,
+ FileSystemEntry* aEntry)
+{
+ MOZ_ASSERT(aEntry);
+
+ if (aEntryCallback.WasPassed()) {
+ RefPtr<EntryCallbackRunnable> runnable =
+ new EntryCallbackRunnable(&aEntryCallback.Value(), aEntry);
+
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+ }
+}
+
+/* static */ void
+ErrorCallbackHelper::Call(nsIGlobalObject* aGlobal,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ nsresult aError)
+{
+ MOZ_ASSERT(aGlobal);
+ MOZ_ASSERT(NS_FAILED(aError));
+
+ if (aErrorCallback.WasPassed()) {
+ RefPtr<ErrorCallbackRunnable> runnable =
+ new ErrorCallbackRunnable(aGlobal, &aErrorCallback.Value(), aError);
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+ }
+}
+
+} // dom namespace
+} // mozilla namespace
+