1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_FileReader_h 8 #define mozilla_dom_FileReader_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/DOMEventTargetHelper.h" 12 13 #include "nsIAsyncInputStream.h" 14 #include "nsIInterfaceRequestor.h" 15 #include "nsINamed.h" 16 #include "nsITimer.h" 17 #include "nsCOMPtr.h" 18 #include "nsString.h" 19 #include "nsWeakReference.h" 20 21 #define NS_PROGRESS_EVENT_INTERVAL 50 22 23 class nsITimer; 24 class nsIEventTarget; 25 26 namespace mozilla { 27 namespace dom { 28 29 class Blob; 30 class DOMException; 31 class OwningStringOrArrayBuffer; 32 class StrongWorkerRef; 33 class WeakWorkerRef; 34 35 extern const uint64_t kUnknownSize; 36 37 class FileReaderDecreaseBusyCounter; 38 39 // 26a79031-c94b-47e9-850a-f04fe17bc026 40 #define FILEREADER_ID \ 41 { \ 42 0x26a79031, 0xc94b, 0x47e9, { \ 43 0x85, 0x0a, 0xf0, 0x4f, 0xe1, 0x7b, 0xc0, 0x26 \ 44 } \ 45 } 46 47 class FileReader final : public DOMEventTargetHelper, 48 public nsIInterfaceRequestor, 49 public nsSupportsWeakReference, 50 public nsIInputStreamCallback, 51 public nsITimerCallback, 52 public nsINamed { 53 friend class FileReaderDecreaseBusyCounter; 54 55 public: 56 FileReader(nsIGlobalObject* aGlobal, WeakWorkerRef* aWorkerRef); 57 58 NS_DECL_ISUPPORTS_INHERITED 59 60 NS_DECL_NSITIMERCALLBACK 61 NS_DECL_NSIINPUTSTREAMCALLBACK 62 NS_DECL_NSIINTERFACEREQUESTOR 63 NS_DECL_NSINAMED 64 65 NS_DECLARE_STATIC_IID_ACCESSOR(FILEREADER_ID) 66 67 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(FileReader, 68 DOMEventTargetHelper) 69 70 virtual JSObject* WrapObject(JSContext* aCx, 71 JS::Handle<JSObject*> aGivenProto) override; 72 73 // WebIDL 74 static already_AddRefed<FileReader> Constructor(const GlobalObject& aGlobal); ReadAsArrayBuffer(JSContext * aCx,Blob & aBlob,ErrorResult & aRv)75 void ReadAsArrayBuffer(JSContext* aCx, Blob& aBlob, ErrorResult& aRv) { 76 ReadFileContent(aBlob, u""_ns, FILE_AS_ARRAYBUFFER, aRv); 77 } 78 ReadAsText(Blob & aBlob,const Optional<nsAString> & aLabel,ErrorResult & aRv)79 void ReadAsText(Blob& aBlob, const Optional<nsAString>& aLabel, 80 ErrorResult& aRv) { 81 if (aLabel.WasPassed()) { 82 ReadFileContent(aBlob, aLabel.Value(), FILE_AS_TEXT, aRv); 83 } else { 84 ReadFileContent(aBlob, u""_ns, FILE_AS_TEXT, aRv); 85 } 86 } 87 ReadAsDataURL(Blob & aBlob,ErrorResult & aRv)88 void ReadAsDataURL(Blob& aBlob, ErrorResult& aRv) { 89 ReadFileContent(aBlob, u""_ns, FILE_AS_DATAURL, aRv); 90 } 91 92 void Abort(); 93 ReadyState()94 uint16_t ReadyState() const { return static_cast<uint16_t>(mReadyState); } 95 GetError()96 DOMException* GetError() const { return mError; } 97 98 void GetResult(JSContext* aCx, Nullable<OwningStringOrArrayBuffer>& aResult); 99 100 IMPL_EVENT_HANDLER(loadstart) IMPL_EVENT_HANDLER(progress)101 IMPL_EVENT_HANDLER(progress) 102 IMPL_EVENT_HANDLER(load) 103 IMPL_EVENT_HANDLER(abort) 104 IMPL_EVENT_HANDLER(error) 105 IMPL_EVENT_HANDLER(loadend) 106 107 void ReadAsBinaryString(Blob& aBlob, ErrorResult& aRv) { 108 ReadFileContent(aBlob, u""_ns, FILE_AS_BINARY, aRv); 109 } 110 111 enum eDataFormat { 112 FILE_AS_ARRAYBUFFER, 113 FILE_AS_BINARY, 114 FILE_AS_TEXT, 115 FILE_AS_DATAURL 116 }; 117 DataFormat()118 eDataFormat DataFormat() const { return mDataFormat; } Result()119 const nsString& Result() const { return mResult; } 120 121 void InitialAsyncWait(); 122 123 private: 124 virtual ~FileReader(); 125 126 // This must be in sync with dom/webidl/FileReader.webidl 127 enum eReadyState { EMPTY = 0, LOADING = 1, DONE = 2 }; 128 129 void RootResultArrayBuffer(); 130 131 void ReadFileContent(Blob& aBlob, const nsAString& aCharset, 132 eDataFormat aDataFormat, ErrorResult& aRv); 133 nsresult GetAsText(Blob* aBlob, const nsACString& aCharset, 134 const char* aFileData, uint32_t aDataLen, 135 nsAString& aResult); 136 nsresult GetAsDataURL(Blob* aBlob, const char* aFileData, uint32_t aDataLen, 137 nsAString& aResult); 138 139 void OnLoadEnd(nsresult aStatus); 140 141 void StartProgressEventTimer(); 142 void ClearProgressEventTimer(); 143 144 void FreeDataAndDispatchSuccess(); 145 void FreeDataAndDispatchError(); 146 void FreeDataAndDispatchError(nsresult aRv); 147 nsresult DispatchProgressEvent(const nsAString& aType); 148 149 nsresult DoAsyncWait(); 150 nsresult DoReadData(uint64_t aCount); 151 152 void OnLoadEndArrayBuffer(); 153 154 void FreeFileData(); 155 156 nsresult IncreaseBusyCounter(); 157 void DecreaseBusyCounter(); 158 159 void Shutdown(); 160 161 char* mFileData; 162 RefPtr<Blob> mBlob; 163 nsCString mCharset; 164 uint32_t mDataLen; 165 166 eDataFormat mDataFormat; 167 168 nsString mResult; 169 170 JS::Heap<JSObject*> mResultArrayBuffer; 171 172 nsCOMPtr<nsITimer> mProgressNotifier; 173 bool mProgressEventWasDelayed; 174 bool mTimerIsActive; 175 176 nsCOMPtr<nsIAsyncInputStream> mAsyncStream; 177 178 RefPtr<DOMException> mError; 179 180 eReadyState mReadyState; 181 182 uint64_t mTotal; 183 uint64_t mTransferred; 184 185 nsCOMPtr<nsIEventTarget> mTarget; 186 187 uint64_t mBusyCount; 188 189 // This is set if FileReader is created on workers, but it is null if the 190 // worker is shutting down. The null value is checked in ReadFileContent() 191 // before starting any reading. 192 RefPtr<WeakWorkerRef> mWeakWorkerRef; 193 194 // This value is set when the reading starts in order to keep the worker alive 195 // during the process. 196 RefPtr<StrongWorkerRef> mStrongWorkerRef; 197 198 // Runnable to start the reading asynchronous. 199 class AsyncWaitRunnable; 200 RefPtr<AsyncWaitRunnable> mAsyncWaitRunnable; 201 }; 202 203 NS_DEFINE_STATIC_IID_ACCESSOR(FileReader, FILEREADER_ID) 204 205 } // namespace dom 206 } // namespace mozilla 207 208 #endif // mozilla_dom_FileReader_h 209