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