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: #ifndef mozilla_dom_file_lockedfile_h__ michael@0: #define mozilla_dom_file_lockedfile_h__ michael@0: michael@0: #include "FileCommon.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/DOMEventTargetHelper.h" michael@0: #include "mozilla/dom/FileModeBinding.h" michael@0: #include "mozilla/dom/TypedArray.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsIRunnable.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: class DOMFileMetadataParameters; michael@0: class DOMRequest; michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: namespace mozilla { michael@0: class EventChainPreVisitor; michael@0: } // namespace mozilla michael@0: michael@0: BEGIN_FILE_NAMESPACE michael@0: michael@0: class FileHandle; michael@0: class FileRequest; michael@0: class MetadataHelper; michael@0: michael@0: class LockedFile : public DOMEventTargetHelper, michael@0: public nsIRunnable michael@0: { michael@0: friend class FinishHelper; michael@0: friend class FileService; michael@0: friend class FileHelper; michael@0: friend class MetadataHelper; michael@0: michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(LockedFile, DOMEventTargetHelper) michael@0: michael@0: enum RequestMode michael@0: { michael@0: NORMAL = 0, // Sequential michael@0: PARALLEL michael@0: }; michael@0: michael@0: enum ReadyState michael@0: { michael@0: INITIAL = 0, michael@0: LOADING, michael@0: FINISHING, michael@0: DONE michael@0: }; michael@0: michael@0: static already_AddRefed michael@0: Create(FileHandle* aFileHandle, michael@0: FileMode aMode, michael@0: RequestMode aRequestMode = NORMAL); michael@0: michael@0: // nsIDOMEventTarget michael@0: virtual nsresult michael@0: PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE; michael@0: michael@0: nsresult michael@0: CreateParallelStream(nsISupports** aStream); michael@0: michael@0: nsresult michael@0: GetOrCreateStream(nsISupports** aStream); michael@0: michael@0: bool michael@0: IsOpen() const; michael@0: michael@0: bool michael@0: IsAborted() const michael@0: { michael@0: return mAborted; michael@0: } michael@0: michael@0: FileHandle* michael@0: Handle() const michael@0: { michael@0: return mFileHandle; michael@0: } michael@0: michael@0: nsresult michael@0: OpenInputStream(bool aWholeFile, uint64_t aStart, uint64_t aLength, michael@0: nsIInputStream** aResult); michael@0: michael@0: // WrapperCache michael@0: virtual JSObject* michael@0: WrapObject(JSContext* aCx) MOZ_OVERRIDE; michael@0: michael@0: // WebIDL michael@0: nsPIDOMWindow* michael@0: GetParentObject() const michael@0: { michael@0: return GetOwner(); michael@0: } michael@0: michael@0: FileHandle* michael@0: GetFileHandle() const michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return Handle(); michael@0: } michael@0: michael@0: FileMode michael@0: Mode() const michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return mMode; michael@0: } michael@0: michael@0: bool michael@0: Active() const michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return IsOpen(); michael@0: } michael@0: michael@0: Nullable michael@0: GetLocation() const michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: if (mLocation == UINT64_MAX) { michael@0: return Nullable(); michael@0: } michael@0: michael@0: return Nullable(mLocation); michael@0: } michael@0: michael@0: void michael@0: SetLocation(const Nullable& aLocation) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: // Null means the end-of-file. michael@0: if (aLocation.IsNull()) { michael@0: mLocation = UINT64_MAX; michael@0: } else { michael@0: mLocation = aLocation.Value(); michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: GetMetadata(const DOMFileMetadataParameters& aParameters, ErrorResult& aRv); michael@0: michael@0: already_AddRefed michael@0: ReadAsArrayBuffer(uint64_t aSize, ErrorResult& aRv); michael@0: michael@0: already_AddRefed michael@0: ReadAsText(uint64_t aSize, const nsAString& aEncoding, ErrorResult& aRv); michael@0: michael@0: template michael@0: already_AddRefed michael@0: Write(const T& aValue, ErrorResult& aRv) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return WriteOrAppend(aValue, false, aRv); michael@0: } michael@0: michael@0: template michael@0: already_AddRefed michael@0: Append(const T& aValue, ErrorResult& aRv) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return WriteOrAppend(aValue, true, aRv); michael@0: } michael@0: michael@0: already_AddRefed michael@0: Truncate(const Optional& aSize, ErrorResult& aRv); michael@0: michael@0: already_AddRefed michael@0: Flush(ErrorResult& aRv); michael@0: michael@0: void michael@0: Abort(ErrorResult& aRv); michael@0: michael@0: IMPL_EVENT_HANDLER(complete) michael@0: IMPL_EVENT_HANDLER(abort) michael@0: IMPL_EVENT_HANDLER(error) michael@0: michael@0: private: michael@0: LockedFile(); michael@0: ~LockedFile(); michael@0: michael@0: void michael@0: OnNewRequest(); michael@0: michael@0: void michael@0: OnRequestFinished(); michael@0: michael@0: bool michael@0: CheckState(ErrorResult& aRv); michael@0: michael@0: bool michael@0: CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv); michael@0: michael@0: bool michael@0: CheckStateForWrite(ErrorResult& aRv); michael@0: michael@0: already_AddRefed michael@0: GenerateFileRequest(); michael@0: michael@0: template michael@0: already_AddRefed michael@0: WriteOrAppend(const T& aValue, bool aAppend, ErrorResult& aRv) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: // State checking for write michael@0: if (!CheckStateForWrite(aRv)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // Additional state checking for write michael@0: if (!aAppend && mLocation == UINT64_MAX) { michael@0: aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR); michael@0: return nullptr; michael@0: } michael@0: michael@0: uint64_t length; michael@0: nsCOMPtr stream = GetInputStream(aValue, &length, aRv); michael@0: if (aRv.Failed()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!length) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // Do nothing if the window is closed michael@0: if (!GetOwner()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: return WriteInternal(stream, length, aAppend, aRv); michael@0: } michael@0: michael@0: already_AddRefed michael@0: WriteInternal(nsIInputStream* aInputStream, uint64_t aInputLength, michael@0: bool aAppend, ErrorResult& aRv); michael@0: michael@0: nsresult michael@0: Finish(); michael@0: michael@0: static already_AddRefed michael@0: GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength, michael@0: ErrorResult& aRv); michael@0: michael@0: static already_AddRefed michael@0: GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength, ErrorResult& aRv); michael@0: michael@0: static already_AddRefed michael@0: GetInputStream(const nsAString& aValue, uint64_t* aInputLength, michael@0: ErrorResult& aRv); michael@0: michael@0: nsRefPtr mFileHandle; michael@0: ReadyState mReadyState; michael@0: FileMode mMode; michael@0: RequestMode mRequestMode; michael@0: uint64_t mLocation; michael@0: uint32_t mPendingRequests; michael@0: michael@0: nsTArray > mParallelStreams; michael@0: nsCOMPtr mStream; michael@0: michael@0: bool mAborted; michael@0: bool mCreating; michael@0: }; michael@0: michael@0: class FinishHelper MOZ_FINAL : public nsIRunnable michael@0: { michael@0: friend class LockedFile; michael@0: michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: private: michael@0: FinishHelper(LockedFile* aLockedFile); michael@0: ~FinishHelper() michael@0: { } michael@0: michael@0: nsRefPtr mLockedFile; michael@0: nsTArray > mParallelStreams; michael@0: nsCOMPtr mStream; michael@0: michael@0: bool mAborted; michael@0: }; michael@0: michael@0: END_FILE_NAMESPACE michael@0: michael@0: #endif // mozilla_dom_file_lockedfile_h__