|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsDOMFileReader.h" |
|
7 |
|
8 #include "nsContentCID.h" |
|
9 #include "nsContentUtils.h" |
|
10 #include "nsDOMClassInfoID.h" |
|
11 #include "nsDOMFile.h" |
|
12 #include "nsError.h" |
|
13 #include "nsIConverterInputStream.h" |
|
14 #include "nsIDocument.h" |
|
15 #include "nsIFile.h" |
|
16 #include "nsIFileStreams.h" |
|
17 #include "nsIInputStream.h" |
|
18 #include "nsIMIMEService.h" |
|
19 #include "nsIUnicodeDecoder.h" |
|
20 #include "nsNetCID.h" |
|
21 #include "nsNetUtil.h" |
|
22 |
|
23 #include "nsLayoutCID.h" |
|
24 #include "nsXPIDLString.h" |
|
25 #include "nsReadableUtils.h" |
|
26 #include "nsIURI.h" |
|
27 #include "nsStreamUtils.h" |
|
28 #include "nsXPCOM.h" |
|
29 #include "nsIDOMEventListener.h" |
|
30 #include "nsJSEnvironment.h" |
|
31 #include "nsIScriptGlobalObject.h" |
|
32 #include "nsCExternalHandlerService.h" |
|
33 #include "nsIStreamConverterService.h" |
|
34 #include "nsCycleCollectionParticipant.h" |
|
35 #include "nsIScriptObjectPrincipal.h" |
|
36 #include "nsHostObjectProtocolHandler.h" |
|
37 #include "mozilla/Base64.h" |
|
38 #include "mozilla/DOMEventTargetHelper.h" |
|
39 #include "mozilla/Preferences.h" |
|
40 #include "mozilla/dom/EncodingUtils.h" |
|
41 #include "mozilla/dom/FileReaderBinding.h" |
|
42 #include "xpcpublic.h" |
|
43 #include "nsIScriptSecurityManager.h" |
|
44 #include "nsDOMJSUtils.h" |
|
45 |
|
46 #include "jsfriendapi.h" |
|
47 |
|
48 using namespace mozilla; |
|
49 using namespace mozilla::dom; |
|
50 |
|
51 #define LOAD_STR "load" |
|
52 #define LOADSTART_STR "loadstart" |
|
53 #define LOADEND_STR "loadend" |
|
54 |
|
55 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileReader) |
|
56 |
|
57 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMFileReader, |
|
58 FileIOObject) |
|
59 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFile) |
|
60 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal) |
|
61 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
|
62 |
|
63 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMFileReader, |
|
64 FileIOObject) |
|
65 tmp->mResultArrayBuffer = nullptr; |
|
66 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFile) |
|
67 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal) |
|
68 NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
|
69 |
|
70 |
|
71 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsDOMFileReader, |
|
72 DOMEventTargetHelper) |
|
73 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer) |
|
74 NS_IMPL_CYCLE_COLLECTION_TRACE_END |
|
75 |
|
76 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMFileReader) |
|
77 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
|
78 NS_INTERFACE_MAP_ENTRY(nsIDOMFileReader) |
|
79 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) |
|
80 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
|
81 NS_INTERFACE_MAP_END_INHERITING(FileIOObject) |
|
82 |
|
83 NS_IMPL_ADDREF_INHERITED(nsDOMFileReader, FileIOObject) |
|
84 NS_IMPL_RELEASE_INHERITED(nsDOMFileReader, FileIOObject) |
|
85 |
|
86 NS_IMPL_EVENT_HANDLER(nsDOMFileReader, load) |
|
87 NS_IMPL_EVENT_HANDLER(nsDOMFileReader, loadend) |
|
88 NS_IMPL_EVENT_HANDLER(nsDOMFileReader, loadstart) |
|
89 NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, abort, FileIOObject) |
|
90 NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, progress, FileIOObject) |
|
91 NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, error, FileIOObject) |
|
92 |
|
93 void |
|
94 nsDOMFileReader::RootResultArrayBuffer() |
|
95 { |
|
96 mozilla::HoldJSObjects(this); |
|
97 } |
|
98 |
|
99 //nsDOMFileReader constructors/initializers |
|
100 |
|
101 nsDOMFileReader::nsDOMFileReader() |
|
102 : mFileData(nullptr), |
|
103 mDataLen(0), mDataFormat(FILE_AS_BINARY), |
|
104 mResultArrayBuffer(nullptr) |
|
105 { |
|
106 SetDOMStringToNull(mResult); |
|
107 SetIsDOMBinding(); |
|
108 } |
|
109 |
|
110 nsDOMFileReader::~nsDOMFileReader() |
|
111 { |
|
112 FreeFileData(); |
|
113 mResultArrayBuffer = nullptr; |
|
114 mozilla::DropJSObjects(this); |
|
115 } |
|
116 |
|
117 |
|
118 /** |
|
119 * This Init method is called from the factory constructor. |
|
120 */ |
|
121 nsresult |
|
122 nsDOMFileReader::Init() |
|
123 { |
|
124 nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); |
|
125 nsCOMPtr<nsIPrincipal> principal; |
|
126 if (secMan) { |
|
127 secMan->GetSystemPrincipal(getter_AddRefs(principal)); |
|
128 } |
|
129 NS_ENSURE_STATE(principal); |
|
130 mPrincipal.swap(principal); |
|
131 |
|
132 // Instead of grabbing some random global from the context stack, |
|
133 // let's use the default one (junk scope) for now. |
|
134 // We should move away from this Init... |
|
135 nsCOMPtr<nsIGlobalObject> global = xpc::GetJunkScopeGlobal(); |
|
136 NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); |
|
137 BindToOwner(global); |
|
138 return NS_OK; |
|
139 } |
|
140 |
|
141 /* static */ already_AddRefed<nsDOMFileReader> |
|
142 nsDOMFileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) |
|
143 { |
|
144 nsRefPtr<nsDOMFileReader> fileReader = new nsDOMFileReader(); |
|
145 |
|
146 nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aGlobal.GetAsSupports()); |
|
147 if (!owner) { |
|
148 NS_WARNING("Unexpected nsIJSNativeInitializer owner"); |
|
149 aRv.Throw(NS_ERROR_FAILURE); |
|
150 return nullptr; |
|
151 } |
|
152 |
|
153 fileReader->BindToOwner(owner); |
|
154 |
|
155 // This object is bound to a |window|, |
|
156 // so reset the principal. |
|
157 nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(owner); |
|
158 if (!scriptPrincipal) { |
|
159 aRv.Throw(NS_ERROR_FAILURE); |
|
160 return nullptr; |
|
161 } |
|
162 fileReader->mPrincipal = scriptPrincipal->GetPrincipal(); |
|
163 return fileReader.forget(); |
|
164 } |
|
165 |
|
166 // nsIInterfaceRequestor |
|
167 |
|
168 NS_IMETHODIMP |
|
169 nsDOMFileReader::GetInterface(const nsIID & aIID, void **aResult) |
|
170 { |
|
171 return QueryInterface(aIID, aResult); |
|
172 } |
|
173 |
|
174 // nsIDOMFileReader |
|
175 |
|
176 NS_IMETHODIMP |
|
177 nsDOMFileReader::GetReadyState(uint16_t *aReadyState) |
|
178 { |
|
179 *aReadyState = ReadyState(); |
|
180 return NS_OK; |
|
181 } |
|
182 |
|
183 void |
|
184 nsDOMFileReader::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, |
|
185 ErrorResult& aRv) |
|
186 { |
|
187 aRv = GetResult(aCx, aResult); |
|
188 } |
|
189 |
|
190 NS_IMETHODIMP |
|
191 nsDOMFileReader::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult) |
|
192 { |
|
193 JS::Rooted<JS::Value> result(aCx); |
|
194 if (mDataFormat == FILE_AS_ARRAYBUFFER) { |
|
195 if (mReadyState == nsIDOMFileReader::DONE && mResultArrayBuffer) { |
|
196 result.setObject(*mResultArrayBuffer); |
|
197 } else { |
|
198 result.setNull(); |
|
199 } |
|
200 if (!JS_WrapValue(aCx, &result)) { |
|
201 return NS_ERROR_FAILURE; |
|
202 } |
|
203 aResult.set(result); |
|
204 return NS_OK; |
|
205 } |
|
206 |
|
207 nsString tmpResult = mResult; |
|
208 if (!xpc::StringToJsval(aCx, tmpResult, aResult)) { |
|
209 return NS_ERROR_FAILURE; |
|
210 } |
|
211 return NS_OK; |
|
212 } |
|
213 |
|
214 NS_IMETHODIMP |
|
215 nsDOMFileReader::GetError(nsISupports** aError) |
|
216 { |
|
217 NS_IF_ADDREF(*aError = GetError()); |
|
218 return NS_OK; |
|
219 } |
|
220 |
|
221 NS_IMETHODIMP |
|
222 nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aFile, JSContext* aCx) |
|
223 { |
|
224 NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER); |
|
225 ErrorResult rv; |
|
226 ReadAsArrayBuffer(aCx, aFile, rv); |
|
227 return rv.ErrorCode(); |
|
228 } |
|
229 |
|
230 NS_IMETHODIMP |
|
231 nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aFile) |
|
232 { |
|
233 NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER); |
|
234 ErrorResult rv; |
|
235 ReadAsBinaryString(aFile, rv); |
|
236 return rv.ErrorCode(); |
|
237 } |
|
238 |
|
239 NS_IMETHODIMP |
|
240 nsDOMFileReader::ReadAsText(nsIDOMBlob* aFile, |
|
241 const nsAString &aCharset) |
|
242 { |
|
243 NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER); |
|
244 ErrorResult rv; |
|
245 ReadAsText(aFile, aCharset, rv); |
|
246 return rv.ErrorCode(); |
|
247 } |
|
248 |
|
249 NS_IMETHODIMP |
|
250 nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aFile) |
|
251 { |
|
252 NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER); |
|
253 ErrorResult rv; |
|
254 ReadAsDataURL(aFile, rv); |
|
255 return rv.ErrorCode(); |
|
256 } |
|
257 |
|
258 NS_IMETHODIMP |
|
259 nsDOMFileReader::Abort() |
|
260 { |
|
261 ErrorResult rv; |
|
262 FileIOObject::Abort(rv); |
|
263 return rv.ErrorCode(); |
|
264 } |
|
265 |
|
266 /* virtual */ void |
|
267 nsDOMFileReader::DoAbort(nsAString& aEvent) |
|
268 { |
|
269 // Revert status and result attributes |
|
270 SetDOMStringToNull(mResult); |
|
271 mResultArrayBuffer = nullptr; |
|
272 |
|
273 // Non-null channel indicates a read is currently active |
|
274 if (mChannel) { |
|
275 // Cancel request requires an error status |
|
276 mChannel->Cancel(NS_ERROR_FAILURE); |
|
277 mChannel = nullptr; |
|
278 } |
|
279 mFile = nullptr; |
|
280 |
|
281 //Clean up memory buffer |
|
282 FreeFileData(); |
|
283 |
|
284 // Tell the base class which event to dispatch |
|
285 aEvent = NS_LITERAL_STRING(LOADEND_STR); |
|
286 } |
|
287 |
|
288 static |
|
289 NS_METHOD |
|
290 ReadFuncBinaryString(nsIInputStream* in, |
|
291 void* closure, |
|
292 const char* fromRawSegment, |
|
293 uint32_t toOffset, |
|
294 uint32_t count, |
|
295 uint32_t *writeCount) |
|
296 { |
|
297 char16_t* dest = static_cast<char16_t*>(closure) + toOffset; |
|
298 char16_t* end = dest + count; |
|
299 const unsigned char* source = (const unsigned char*)fromRawSegment; |
|
300 while (dest != end) { |
|
301 *dest = *source; |
|
302 ++dest; |
|
303 ++source; |
|
304 } |
|
305 *writeCount = count; |
|
306 |
|
307 return NS_OK; |
|
308 } |
|
309 |
|
310 nsresult |
|
311 nsDOMFileReader::DoOnDataAvailable(nsIRequest *aRequest, |
|
312 nsISupports *aContext, |
|
313 nsIInputStream *aInputStream, |
|
314 uint64_t aOffset, |
|
315 uint32_t aCount) |
|
316 { |
|
317 if (mDataFormat == FILE_AS_BINARY) { |
|
318 //Continuously update our binary string as data comes in |
|
319 NS_ASSERTION(mResult.Length() == aOffset, |
|
320 "unexpected mResult length"); |
|
321 uint32_t oldLen = mResult.Length(); |
|
322 if (uint64_t(oldLen) + aCount > UINT32_MAX) |
|
323 return NS_ERROR_OUT_OF_MEMORY; |
|
324 |
|
325 char16_t *buf = nullptr; |
|
326 mResult.GetMutableData(&buf, oldLen + aCount, fallible_t()); |
|
327 NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); |
|
328 |
|
329 uint32_t bytesRead = 0; |
|
330 aInputStream->ReadSegments(ReadFuncBinaryString, buf + oldLen, aCount, |
|
331 &bytesRead); |
|
332 NS_ASSERTION(bytesRead == aCount, "failed to read data"); |
|
333 } |
|
334 else if (mDataFormat == FILE_AS_ARRAYBUFFER) { |
|
335 uint32_t bytesRead = 0; |
|
336 aInputStream->Read((char*)JS_GetArrayBufferData(mResultArrayBuffer) + aOffset, |
|
337 aCount, &bytesRead); |
|
338 NS_ASSERTION(bytesRead == aCount, "failed to read data"); |
|
339 } |
|
340 else { |
|
341 //Update memory buffer to reflect the contents of the file |
|
342 if (aOffset + aCount > UINT32_MAX) { |
|
343 // PR_Realloc doesn't support over 4GB memory size even if 64-bit OS |
|
344 return NS_ERROR_OUT_OF_MEMORY; |
|
345 } |
|
346 mFileData = (char *)moz_realloc(mFileData, aOffset + aCount); |
|
347 NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY); |
|
348 |
|
349 uint32_t bytesRead = 0; |
|
350 aInputStream->Read(mFileData + aOffset, aCount, &bytesRead); |
|
351 NS_ASSERTION(bytesRead == aCount, "failed to read data"); |
|
352 |
|
353 mDataLen += aCount; |
|
354 } |
|
355 |
|
356 return NS_OK; |
|
357 } |
|
358 |
|
359 nsresult |
|
360 nsDOMFileReader::DoOnStopRequest(nsIRequest *aRequest, |
|
361 nsISupports *aContext, |
|
362 nsresult aStatus, |
|
363 nsAString& aSuccessEvent, |
|
364 nsAString& aTerminationEvent) |
|
365 { |
|
366 // Make sure we drop all the objects that could hold files open now. |
|
367 nsCOMPtr<nsIChannel> channel; |
|
368 mChannel.swap(channel); |
|
369 |
|
370 nsCOMPtr<nsIDOMBlob> file; |
|
371 mFile.swap(file); |
|
372 |
|
373 aSuccessEvent = NS_LITERAL_STRING(LOAD_STR); |
|
374 aTerminationEvent = NS_LITERAL_STRING(LOADEND_STR); |
|
375 |
|
376 // Clear out the data if necessary |
|
377 if (NS_FAILED(aStatus)) { |
|
378 FreeFileData(); |
|
379 return NS_OK; |
|
380 } |
|
381 |
|
382 nsresult rv = NS_OK; |
|
383 switch (mDataFormat) { |
|
384 case FILE_AS_ARRAYBUFFER: |
|
385 break; //Already accumulated mResultArrayBuffer |
|
386 case FILE_AS_BINARY: |
|
387 break; //Already accumulated mResult |
|
388 case FILE_AS_TEXT: |
|
389 if (!mFileData) { |
|
390 if (mDataLen) { |
|
391 rv = NS_ERROR_OUT_OF_MEMORY; |
|
392 break; |
|
393 } |
|
394 rv = GetAsText(file, mCharset, "", mDataLen, mResult); |
|
395 break; |
|
396 } |
|
397 rv = GetAsText(file, mCharset, mFileData, mDataLen, mResult); |
|
398 break; |
|
399 case FILE_AS_DATAURL: |
|
400 rv = GetAsDataURL(file, mFileData, mDataLen, mResult); |
|
401 break; |
|
402 } |
|
403 |
|
404 mResult.SetIsVoid(false); |
|
405 |
|
406 FreeFileData(); |
|
407 |
|
408 return rv; |
|
409 } |
|
410 |
|
411 // Helper methods |
|
412 |
|
413 void |
|
414 nsDOMFileReader::ReadFileContent(JSContext* aCx, |
|
415 nsIDOMBlob* aFile, |
|
416 const nsAString &aCharset, |
|
417 eDataFormat aDataFormat, |
|
418 ErrorResult& aRv) |
|
419 { |
|
420 MOZ_ASSERT(aFile); |
|
421 |
|
422 //Implicit abort to clear any other activity going on |
|
423 Abort(); |
|
424 mError = nullptr; |
|
425 SetDOMStringToNull(mResult); |
|
426 mTransferred = 0; |
|
427 mTotal = 0; |
|
428 mReadyState = nsIDOMFileReader::EMPTY; |
|
429 FreeFileData(); |
|
430 |
|
431 mFile = aFile; |
|
432 mDataFormat = aDataFormat; |
|
433 CopyUTF16toUTF8(aCharset, mCharset); |
|
434 |
|
435 //Establish a channel with our file |
|
436 { |
|
437 // Hold the internal URL alive only as long as necessary |
|
438 // After the channel is created it will own whatever is backing |
|
439 // the DOMFile. |
|
440 nsDOMFileInternalUrlHolder urlHolder(mFile, mPrincipal); |
|
441 |
|
442 nsCOMPtr<nsIURI> uri; |
|
443 aRv = NS_NewURI(getter_AddRefs(uri), urlHolder.mUrl); |
|
444 NS_ENSURE_SUCCESS_VOID(aRv.ErrorCode()); |
|
445 |
|
446 nsCOMPtr<nsILoadGroup> loadGroup; |
|
447 if (HasOrHasHadOwner()) { |
|
448 if (!GetOwner()) { |
|
449 aRv.Throw(NS_ERROR_FAILURE); |
|
450 return; |
|
451 } |
|
452 nsIDocument* doc = GetOwner()->GetExtantDoc(); |
|
453 if (doc) { |
|
454 loadGroup = doc->GetDocumentLoadGroup(); |
|
455 } |
|
456 } |
|
457 |
|
458 aRv = NS_NewChannel(getter_AddRefs(mChannel), uri, nullptr, loadGroup, |
|
459 nullptr, nsIRequest::LOAD_BACKGROUND); |
|
460 NS_ENSURE_SUCCESS_VOID(aRv.ErrorCode()); |
|
461 } |
|
462 |
|
463 //Obtain the total size of the file before reading |
|
464 mTotal = mozilla::dom::kUnknownSize; |
|
465 mFile->GetSize(&mTotal); |
|
466 |
|
467 aRv = mChannel->AsyncOpen(this, nullptr); |
|
468 NS_ENSURE_SUCCESS_VOID(aRv.ErrorCode()); |
|
469 |
|
470 //FileReader should be in loading state here |
|
471 mReadyState = nsIDOMFileReader::LOADING; |
|
472 DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR)); |
|
473 |
|
474 if (mDataFormat == FILE_AS_ARRAYBUFFER) { |
|
475 RootResultArrayBuffer(); |
|
476 mResultArrayBuffer = JS_NewArrayBuffer(aCx, mTotal); |
|
477 if (!mResultArrayBuffer) { |
|
478 NS_WARNING("Failed to create JS array buffer"); |
|
479 aRv.Throw(NS_ERROR_FAILURE); |
|
480 } |
|
481 } |
|
482 } |
|
483 |
|
484 nsresult |
|
485 nsDOMFileReader::GetAsText(nsIDOMBlob *aFile, |
|
486 const nsACString &aCharset, |
|
487 const char *aFileData, |
|
488 uint32_t aDataLen, |
|
489 nsAString& aResult) |
|
490 { |
|
491 // The BOM sniffing is baked into the "decode" part of the Encoding |
|
492 // Standard, which the File API references. |
|
493 nsAutoCString encoding; |
|
494 if (!nsContentUtils::CheckForBOM( |
|
495 reinterpret_cast<const unsigned char *>(aFileData), |
|
496 aDataLen, |
|
497 encoding)) { |
|
498 // BOM sniffing failed. Try the API argument. |
|
499 if (!EncodingUtils::FindEncodingForLabel(aCharset, |
|
500 encoding)) { |
|
501 // API argument failed. Try the type property of the blob. |
|
502 nsAutoString type16; |
|
503 aFile->GetType(type16); |
|
504 NS_ConvertUTF16toUTF8 type(type16); |
|
505 nsAutoCString specifiedCharset; |
|
506 bool haveCharset; |
|
507 int32_t charsetStart, charsetEnd; |
|
508 NS_ExtractCharsetFromContentType(type, |
|
509 specifiedCharset, |
|
510 &haveCharset, |
|
511 &charsetStart, |
|
512 &charsetEnd); |
|
513 if (!EncodingUtils::FindEncodingForLabel(specifiedCharset, encoding)) { |
|
514 // Type property failed. Use UTF-8. |
|
515 encoding.AssignLiteral("UTF-8"); |
|
516 } |
|
517 } |
|
518 } |
|
519 |
|
520 nsDependentCSubstring data(aFileData, aDataLen); |
|
521 return nsContentUtils::ConvertStringFromEncoding(encoding, data, aResult); |
|
522 } |
|
523 |
|
524 nsresult |
|
525 nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aFile, |
|
526 const char *aFileData, |
|
527 uint32_t aDataLen, |
|
528 nsAString& aResult) |
|
529 { |
|
530 aResult.AssignLiteral("data:"); |
|
531 |
|
532 nsresult rv; |
|
533 nsString contentType; |
|
534 rv = aFile->GetType(contentType); |
|
535 if (NS_SUCCEEDED(rv) && !contentType.IsEmpty()) { |
|
536 aResult.Append(contentType); |
|
537 } else { |
|
538 aResult.AppendLiteral("application/octet-stream"); |
|
539 } |
|
540 aResult.AppendLiteral(";base64,"); |
|
541 |
|
542 nsCString encodedData; |
|
543 rv = Base64Encode(Substring(aFileData, aDataLen), encodedData); |
|
544 NS_ENSURE_SUCCESS(rv, rv); |
|
545 |
|
546 if (!AppendASCIItoUTF16(encodedData, aResult, fallible_t())) { |
|
547 return NS_ERROR_OUT_OF_MEMORY; |
|
548 } |
|
549 |
|
550 return NS_OK; |
|
551 } |
|
552 |
|
553 /* virtual */ JSObject* |
|
554 nsDOMFileReader::WrapObject(JSContext* aCx) |
|
555 { |
|
556 return FileReaderBinding::Wrap(aCx, this); |
|
557 } |