1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozila.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Mozilla Foundation
19 : * Portions created by the Initial Developer are Copyright (C) 2007
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Dave Camp <dcamp@mozilla.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsDOMFile.h"
40 :
41 : #include "nsCExternalHandlerService.h"
42 : #include "nsContentCID.h"
43 : #include "nsContentUtils.h"
44 : #include "nsDOMClassInfoID.h"
45 : #include "nsDOMError.h"
46 : #include "nsICharsetDetector.h"
47 : #include "nsICharsetConverterManager.h"
48 : #include "nsIConverterInputStream.h"
49 : #include "nsIDocument.h"
50 : #include "nsIDOMDocument.h"
51 : #include "nsIFileStreams.h"
52 : #include "nsIInputStream.h"
53 : #include "nsIIPCSerializable.h"
54 : #include "nsIMIMEService.h"
55 : #include "nsIPlatformCharset.h"
56 : #include "nsISeekableStream.h"
57 : #include "nsIUnicharInputStream.h"
58 : #include "nsIUnicodeDecoder.h"
59 : #include "nsNetCID.h"
60 : #include "nsNetUtil.h"
61 : #include "nsIUUIDGenerator.h"
62 : #include "nsBlobProtocolHandler.h"
63 : #include "nsStringStream.h"
64 : #include "CheckedInt.h"
65 : #include "nsJSUtils.h"
66 : #include "mozilla/Preferences.h"
67 :
68 : #include "plbase64.h"
69 : #include "prmem.h"
70 : #include "dombindings.h"
71 :
72 : using namespace mozilla;
73 : using namespace mozilla::dom;
74 :
75 : // XXXkhuey the input stream that we pass out of a DOMFile
76 : // can outlive the actual DOMFile object. Thus, we must
77 : // ensure that the buffer underlying the stream we get
78 : // from NS_NewByteInputStream is held alive as long as the
79 : // stream is. We do that by passing back this class instead.
80 : class DataOwnerAdapter : public nsIInputStream,
81 : public nsISeekableStream
82 0 : {
83 : typedef nsDOMMemoryFile::DataOwner DataOwner;
84 : public:
85 : static nsresult Create(DataOwner* aDataOwner,
86 : PRUint32 aStart,
87 : PRUint32 aLength,
88 : nsIInputStream** _retval);
89 :
90 : NS_DECL_ISUPPORTS
91 :
92 0 : NS_FORWARD_NSIINPUTSTREAM(mStream->)
93 :
94 0 : NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
95 :
96 : private:
97 0 : DataOwnerAdapter(DataOwner* aDataOwner,
98 : nsIInputStream* aStream)
99 : : mDataOwner(aDataOwner), mStream(aStream),
100 0 : mSeekableStream(do_QueryInterface(aStream))
101 : {
102 0 : NS_ASSERTION(mSeekableStream, "Somebody gave us the wrong stream!");
103 0 : }
104 :
105 : nsRefPtr<DataOwner> mDataOwner;
106 : nsCOMPtr<nsIInputStream> mStream;
107 : nsCOMPtr<nsISeekableStream> mSeekableStream;
108 : };
109 :
110 0 : NS_IMPL_THREADSAFE_ISUPPORTS2(DataOwnerAdapter,
111 : nsIInputStream,
112 : nsISeekableStream)
113 :
114 0 : nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
115 : PRUint32 aStart,
116 : PRUint32 aLength,
117 : nsIInputStream** _retval)
118 : {
119 : nsresult rv;
120 0 : NS_ASSERTION(aDataOwner, "Uh ...");
121 :
122 0 : nsCOMPtr<nsIInputStream> stream;
123 :
124 0 : rv = NS_NewByteInputStream(getter_AddRefs(stream),
125 : static_cast<const char*>(aDataOwner->mData) +
126 : aStart,
127 : (PRInt32)aLength,
128 0 : NS_ASSIGNMENT_DEPEND);
129 0 : NS_ENSURE_SUCCESS(rv, rv);
130 :
131 0 : NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
132 :
133 0 : return NS_OK;
134 : }
135 :
136 : ////////////////////////////////////////////////////////////////////////////
137 : // nsDOMFileBase implementation
138 :
139 : DOMCI_DATA(File, nsDOMFileBase)
140 : DOMCI_DATA(Blob, nsDOMFileBase)
141 :
142 80 : NS_INTERFACE_MAP_BEGIN(nsDOMFileBase)
143 80 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
144 54 : NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
145 48 : NS_INTERFACE_MAP_ENTRY(nsIDOMBlob_GECKO_13)
146 48 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
147 42 : NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
148 42 : NS_INTERFACE_MAP_ENTRY(nsIMutable)
149 42 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
150 34 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
151 34 : NS_INTERFACE_MAP_END
152 :
153 : // Threadsafe when GetMutable() == false
154 52 : NS_IMPL_THREADSAFE_ADDREF(nsDOMFileBase)
155 52 : NS_IMPL_THREADSAFE_RELEASE(nsDOMFileBase)
156 :
157 : NS_IMETHODIMP
158 6 : nsDOMFileBase::GetName(nsAString &aFileName)
159 : {
160 6 : NS_ASSERTION(mIsFile, "Should only be called on files");
161 6 : aFileName = mName;
162 6 : return NS_OK;
163 : }
164 :
165 : NS_IMETHODIMP
166 0 : nsDOMFileBase::GetMozFullPath(nsAString &aFileName)
167 : {
168 0 : NS_ASSERTION(mIsFile, "Should only be called on files");
169 :
170 : // It is unsafe to call CallerHasUniversalXPConnect on a non-main thread. If
171 : // you hit the following assertion you need to figure out some other way to
172 : // determine privileges and call GetMozFullPathInternal.
173 0 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
174 :
175 0 : if (nsContentUtils::CallerHasUniversalXPConnect()) {
176 0 : return GetMozFullPathInternal(aFileName);
177 : }
178 0 : aFileName.Truncate();
179 0 : return NS_OK;
180 : }
181 :
182 : NS_IMETHODIMP
183 0 : nsDOMFileBase::GetMozFullPathInternal(nsAString &aFileName)
184 : {
185 0 : NS_ASSERTION(mIsFile, "Should only be called on files");
186 0 : aFileName.Truncate();
187 0 : return NS_OK;
188 : }
189 :
190 : NS_IMETHODIMP
191 0 : nsDOMFileBase::GetSize(PRUint64 *aSize)
192 : {
193 0 : *aSize = mLength;
194 0 : return NS_OK;
195 : }
196 :
197 : NS_IMETHODIMP
198 0 : nsDOMFileBase::GetType(nsAString &aType)
199 : {
200 0 : aType = mContentType;
201 0 : return NS_OK;
202 : }
203 :
204 : // Makes sure that aStart and aEnd is less then or equal to aSize and greater
205 : // than 0
206 : static void
207 0 : ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd)
208 : {
209 0 : CheckedInt64 newStartOffset = aStart;
210 0 : if (aStart < -aSize) {
211 0 : newStartOffset = 0;
212 : }
213 0 : else if (aStart < 0) {
214 0 : newStartOffset += aSize;
215 : }
216 0 : else if (aStart > aSize) {
217 0 : newStartOffset = aSize;
218 : }
219 :
220 0 : CheckedInt64 newEndOffset = aEnd;
221 0 : if (aEnd < -aSize) {
222 0 : newEndOffset = 0;
223 : }
224 0 : else if (aEnd < 0) {
225 0 : newEndOffset += aSize;
226 : }
227 0 : else if (aEnd > aSize) {
228 0 : newEndOffset = aSize;
229 : }
230 :
231 0 : if (!newStartOffset.valid() || !newEndOffset.valid() ||
232 0 : newStartOffset.value() >= newEndOffset.value()) {
233 0 : aStart = aEnd = 0;
234 : }
235 : else {
236 0 : aStart = newStartOffset.value();
237 0 : aEnd = newEndOffset.value();
238 : }
239 0 : }
240 :
241 : NS_IMETHODIMP
242 0 : nsDOMFileBase::Slice(PRInt64 aStart, PRInt64 aEnd,
243 : const nsAString& aContentType, PRUint8 optional_argc,
244 : nsIDOMBlob **aBlob)
245 : {
246 0 : *aBlob = nsnull;
247 :
248 : // Truncate aStart and aEnd so that we stay within this file.
249 : PRUint64 thisLength;
250 0 : nsresult rv = GetSize(&thisLength);
251 0 : NS_ENSURE_SUCCESS(rv, rv);
252 :
253 0 : if (optional_argc < 2) {
254 0 : aEnd = (PRInt64)thisLength;
255 : }
256 :
257 0 : ParseSize((PRInt64)thisLength, aStart, aEnd);
258 :
259 : // Create the new file
260 : *aBlob = CreateSlice((PRUint64)aStart, (PRUint64)(aEnd - aStart),
261 0 : aContentType).get();
262 :
263 0 : return *aBlob ? NS_OK : NS_ERROR_UNEXPECTED;
264 : }
265 :
266 : NS_IMETHODIMP
267 0 : nsDOMFileBase::MozSlice(PRInt64 aStart, PRInt64 aEnd,
268 : const nsAString& aContentType, PRUint8 optional_argc,
269 : nsIDOMBlob **aBlob)
270 : {
271 0 : MOZ_ASSERT(NS_IsMainThread());
272 :
273 0 : return Slice(aStart, aEnd, aContentType, optional_argc, aBlob);
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : nsDOMFileBase::GetInternalStream(nsIInputStream **aStream)
278 : {
279 : // Must be overridden
280 0 : NS_NOTREACHED("Must override GetInternalStream");
281 :
282 0 : return NS_ERROR_NOT_IMPLEMENTED;
283 : }
284 :
285 : NS_IMETHODIMP
286 2 : nsDOMFileBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
287 : {
288 2 : NS_ENSURE_STATE(aPrincipal);
289 :
290 : nsresult rv;
291 : nsCOMPtr<nsIUUIDGenerator> uuidgen =
292 4 : do_GetService("@mozilla.org/uuid-generator;1", &rv);
293 2 : NS_ENSURE_SUCCESS(rv, rv);
294 :
295 : nsID id;
296 2 : rv = uuidgen->GenerateUUIDInPlace(&id);
297 2 : NS_ENSURE_SUCCESS(rv, rv);
298 :
299 : char chars[NSID_LENGTH];
300 2 : id.ToProvidedString(chars);
301 :
302 2 : nsCString url = NS_LITERAL_CSTRING(BLOBURI_SCHEME ":") +
303 6 : Substring(chars + 1, chars + NSID_LENGTH - 2);
304 :
305 : nsBlobProtocolHandler::AddFileDataEntry(url, this,
306 2 : aPrincipal);
307 :
308 2 : CopyASCIItoUTF16(url, aURL);
309 :
310 2 : return NS_OK;
311 : }
312 :
313 : NS_IMETHODIMP_(PRInt64)
314 0 : nsDOMFileBase::GetFileId()
315 : {
316 0 : PRInt64 id = -1;
317 :
318 0 : if (IsStoredFile() && IsWholeFile()) {
319 0 : if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
320 0 : indexedDB::IndexedDatabaseManager::FileMutex().Lock();
321 : }
322 :
323 0 : NS_ASSERTION(!mFileInfos.IsEmpty(),
324 : "A stored file must have at least one file info!");
325 :
326 0 : nsRefPtr<indexedDB::FileInfo>& fileInfo = mFileInfos.ElementAt(0);
327 0 : if (fileInfo) {
328 0 : id = fileInfo->Id();
329 : }
330 :
331 0 : if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
332 0 : indexedDB::IndexedDatabaseManager::FileMutex().Unlock();
333 : }
334 : }
335 :
336 0 : return id;
337 : }
338 :
339 : NS_IMETHODIMP_(void)
340 0 : nsDOMFileBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
341 : {
342 0 : if (indexedDB::IndexedDatabaseManager::IsClosed()) {
343 0 : NS_ERROR("Shouldn't be called after shutdown!");
344 0 : return;
345 : }
346 :
347 0 : nsRefPtr<indexedDB::FileInfo> fileInfo = aFileInfo;
348 :
349 0 : MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
350 :
351 0 : NS_ASSERTION(!mFileInfos.Contains(aFileInfo),
352 : "Adding the same file info agan?!");
353 :
354 0 : nsRefPtr<indexedDB::FileInfo>* element = mFileInfos.AppendElement();
355 0 : element->swap(fileInfo);
356 : }
357 :
358 : NS_IMETHODIMP_(indexedDB::FileInfo*)
359 0 : nsDOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
360 : {
361 0 : if (indexedDB::IndexedDatabaseManager::IsClosed()) {
362 0 : NS_ERROR("Shouldn't be called after shutdown!");
363 0 : return nsnull;
364 : }
365 :
366 : // A slice created from a stored file must keep the file info alive.
367 : // However, we don't support sharing of slices yet, so the slice must be
368 : // copied again. That's why we have to ignore the first file info.
369 0 : PRUint32 startIndex = IsStoredFile() && !IsWholeFile() ? 1 : 0;
370 :
371 0 : MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
372 :
373 0 : for (PRUint32 i = startIndex; i < mFileInfos.Length(); i++) {
374 0 : nsRefPtr<indexedDB::FileInfo>& fileInfo = mFileInfos.ElementAt(i);
375 0 : if (fileInfo->Manager() == aFileManager) {
376 0 : return fileInfo;
377 : }
378 : }
379 :
380 0 : return nsnull;
381 : }
382 :
383 : NS_IMETHODIMP
384 0 : nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
385 : nsACString& aContentType,
386 : nsACString& aCharset)
387 : {
388 : nsresult rv;
389 :
390 0 : nsCOMPtr<nsIInputStream> stream;
391 0 : rv = this->GetInternalStream(getter_AddRefs(stream));
392 0 : NS_ENSURE_SUCCESS(rv, rv);
393 :
394 0 : nsString contentType;
395 0 : rv = this->GetType(contentType);
396 0 : NS_ENSURE_SUCCESS(rv, rv);
397 :
398 0 : CopyUTF16toUTF8(contentType, aContentType);
399 :
400 0 : aCharset.Truncate();
401 :
402 0 : stream.forget(aBody);
403 0 : return NS_OK;
404 : }
405 :
406 : NS_IMETHODIMP
407 0 : nsDOMFileBase::GetMutable(bool* aMutable)
408 : {
409 0 : *aMutable = !mImmutable;
410 0 : return NS_OK;
411 : }
412 :
413 : NS_IMETHODIMP
414 0 : nsDOMFileBase::SetMutable(bool aMutable)
415 : {
416 0 : nsresult rv = NS_OK;
417 :
418 0 : NS_ENSURE_ARG(!mImmutable || !aMutable);
419 :
420 0 : if (!mImmutable && !aMutable) {
421 : // Force the content type and size to be cached
422 0 : nsString dummyString;
423 0 : rv = this->GetType(dummyString);
424 0 : NS_ENSURE_SUCCESS(rv, rv);
425 :
426 : PRUint64 dummyInt;
427 0 : rv = this->GetSize(&dummyInt);
428 0 : NS_ENSURE_SUCCESS(rv, rv);
429 : }
430 :
431 0 : mImmutable = !aMutable;
432 0 : return rv;
433 : }
434 :
435 : ////////////////////////////////////////////////////////////////////////////
436 : // nsDOMFileFile implementation
437 :
438 194 : NS_IMPL_ISUPPORTS_INHERITED1(nsDOMFileFile, nsDOMFileBase,
439 : nsIJSNativeInitializer)
440 :
441 : already_AddRefed<nsIDOMBlob>
442 0 : nsDOMFileFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
443 : const nsAString& aContentType)
444 : {
445 0 : nsCOMPtr<nsIDOMBlob> t = new nsDOMFileFile(this, aStart, aLength, aContentType);
446 0 : return t.forget();
447 : }
448 :
449 : /* static */ nsresult
450 10 : nsDOMFileFile::NewFile(nsISupports* *aNewObject)
451 : {
452 20 : nsCOMPtr<nsISupports> file = do_QueryObject(new nsDOMFileFile());
453 10 : file.forget(aNewObject);
454 10 : return NS_OK;
455 : }
456 :
457 : NS_IMETHODIMP
458 0 : nsDOMFileFile::GetMozFullPathInternal(nsAString &aFilename)
459 : {
460 0 : NS_ASSERTION(mIsFile, "Should only be called on files");
461 0 : return mFile->GetPath(aFilename);
462 : }
463 :
464 : NS_IMETHODIMP
465 2 : nsDOMFileFile::GetSize(PRUint64 *aFileSize)
466 : {
467 2 : if (IsSizeUnknown()) {
468 2 : NS_ASSERTION(mWholeFile,
469 : "Should only use lazy size when using the whole file");
470 : PRInt64 fileSize;
471 2 : nsresult rv = mFile->GetFileSize(&fileSize);
472 2 : NS_ENSURE_SUCCESS(rv, rv);
473 :
474 2 : if (fileSize < 0) {
475 0 : return NS_ERROR_FAILURE;
476 : }
477 :
478 2 : mLength = fileSize;
479 : }
480 :
481 2 : *aFileSize = mLength;
482 :
483 2 : return NS_OK;
484 : }
485 :
486 : NS_IMETHODIMP
487 2 : nsDOMFileFile::GetType(nsAString &aType)
488 : {
489 2 : if (mContentType.IsVoid()) {
490 2 : NS_ASSERTION(mWholeFile,
491 : "Should only use lazy ContentType when using the whole file");
492 : nsresult rv;
493 : nsCOMPtr<nsIMIMEService> mimeService =
494 4 : do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
495 2 : NS_ENSURE_SUCCESS(rv, rv);
496 :
497 6 : nsCAutoString mimeType;
498 2 : rv = mimeService->GetTypeFromFile(mFile, mimeType);
499 2 : if (NS_FAILED(rv)) {
500 2 : mimeType.Truncate();
501 : }
502 :
503 2 : AppendUTF8toUTF16(mimeType, mContentType);
504 2 : mContentType.SetIsVoid(false);
505 : }
506 :
507 2 : aType = mContentType;
508 :
509 2 : return NS_OK;
510 : }
511 :
512 : const PRUint32 sFileStreamFlags =
513 : nsIFileInputStream::CLOSE_ON_EOF |
514 : nsIFileInputStream::REOPEN_ON_REWIND |
515 : nsIFileInputStream::DEFER_OPEN;
516 :
517 : NS_IMETHODIMP
518 2 : nsDOMFileFile::GetInternalStream(nsIInputStream **aStream)
519 : {
520 : return mWholeFile ?
521 2 : NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
522 : NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
523 4 : -1, -1, sFileStreamFlags);
524 : }
525 :
526 : NS_IMETHODIMP
527 10 : nsDOMFileFile::Initialize(nsISupports* aOwner,
528 : JSContext* aCx,
529 : JSObject* aObj,
530 : PRUint32 aArgc,
531 : jsval* aArgv)
532 : {
533 : nsresult rv;
534 :
535 10 : NS_ASSERTION(!mImmutable, "Something went wrong ...");
536 10 : NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
537 :
538 10 : if (!nsContentUtils::IsCallerChrome()) {
539 0 : return NS_ERROR_DOM_SECURITY_ERR; // Real short trip
540 : }
541 :
542 10 : NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
543 :
544 : // We expect to get a path to represent as a File object,
545 : // or an nsIFile
546 20 : nsCOMPtr<nsIFile> file;
547 10 : if (!JSVAL_IS_STRING(aArgv[0])) {
548 : // Lets see if it's an nsIFile
549 6 : if (!JSVAL_IS_OBJECT(aArgv[0])) {
550 0 : return NS_ERROR_UNEXPECTED; // We're not interested
551 : }
552 :
553 6 : JSObject* obj = JSVAL_TO_OBJECT(aArgv[0]);
554 6 : NS_ASSERTION(obj, "This is a bit odd");
555 :
556 : // Is it an nsIFile
557 : file = do_QueryInterface(
558 6 : nsContentUtils::XPConnect()->
559 6 : GetNativeOfWrapper(aCx, obj));
560 6 : if (!file)
561 0 : return NS_ERROR_UNEXPECTED;
562 : } else {
563 : // It's a string
564 4 : JSString* str = JS_ValueToString(aCx, aArgv[0]);
565 4 : NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
566 :
567 8 : nsDependentJSString xpcomStr;
568 4 : if (!xpcomStr.init(aCx, str)) {
569 0 : return NS_ERROR_XPC_BAD_CONVERT_JS;
570 : }
571 :
572 8 : nsCOMPtr<nsILocalFile> localFile;
573 4 : rv = NS_NewLocalFile(xpcomStr, false, getter_AddRefs(localFile));
574 4 : NS_ENSURE_SUCCESS(rv, rv);
575 :
576 3 : file = do_QueryInterface(localFile);
577 3 : NS_ASSERTION(file, "This should never happen");
578 : }
579 :
580 : bool exists;
581 9 : rv = file->Exists(&exists);
582 9 : NS_ENSURE_SUCCESS(rv, rv);
583 9 : NS_ENSURE_TRUE(exists, NS_ERROR_FILE_NOT_FOUND);
584 :
585 : bool isDir;
586 9 : rv = file->IsDirectory(&isDir);
587 9 : NS_ENSURE_SUCCESS(rv, rv);
588 9 : NS_ENSURE_FALSE(isDir, NS_ERROR_FILE_IS_DIRECTORY);
589 :
590 8 : mFile = file;
591 8 : file->GetLeafName(mName);
592 :
593 8 : return NS_OK;
594 : }
595 :
596 : ////////////////////////////////////////////////////////////////////////////
597 : // nsDOMMemoryFile implementation
598 :
599 : already_AddRefed<nsIDOMBlob>
600 0 : nsDOMMemoryFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
601 : const nsAString& aContentType)
602 : {
603 : nsCOMPtr<nsIDOMBlob> t =
604 0 : new nsDOMMemoryFile(this, aStart, aLength, aContentType);
605 0 : return t.forget();
606 : }
607 :
608 : NS_IMETHODIMP
609 0 : nsDOMMemoryFile::GetInternalStream(nsIInputStream **aStream)
610 : {
611 0 : if (mLength > PR_INT32_MAX)
612 0 : return NS_ERROR_FAILURE;
613 :
614 0 : return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
615 : }
616 :
617 : ////////////////////////////////////////////////////////////////////////////
618 : // nsDOMFileList implementation
619 :
620 : DOMCI_DATA(FileList, nsDOMFileList)
621 :
622 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileList)
623 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMFileList)
624 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
625 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
626 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMFileList)
627 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
628 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
629 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMFileList)
630 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
631 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
632 :
633 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileList)
634 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
635 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
636 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
637 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FileList)
638 0 : NS_INTERFACE_MAP_END
639 :
640 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
641 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
642 :
643 : JSObject*
644 0 : nsDOMFileList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
645 : bool *triedToWrap)
646 : {
647 0 : return mozilla::dom::binding::FileList::create(cx, scope, this, triedToWrap);
648 : }
649 :
650 : nsIDOMFile*
651 0 : nsDOMFileList::GetItemAt(PRUint32 aIndex)
652 : {
653 0 : return mFiles.SafeObjectAt(aIndex);
654 : }
655 :
656 : NS_IMETHODIMP
657 0 : nsDOMFileList::GetLength(PRUint32* aLength)
658 : {
659 0 : *aLength = mFiles.Count();
660 :
661 0 : return NS_OK;
662 : }
663 :
664 : NS_IMETHODIMP
665 0 : nsDOMFileList::Item(PRUint32 aIndex, nsIDOMFile **aFile)
666 : {
667 0 : NS_IF_ADDREF(*aFile = nsDOMFileList::GetItemAt(aIndex));
668 :
669 0 : return NS_OK;
670 : }
671 :
672 : ////////////////////////////////////////////////////////////////////////////
673 : // nsDOMFileInternalUrlHolder implementation
674 :
675 2 : nsDOMFileInternalUrlHolder::nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile,
676 : nsIPrincipal* aPrincipal
677 2 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {
678 2 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
679 2 : aFile->GetInternalUrl(aPrincipal, mUrl);
680 2 : }
681 :
682 4 : nsDOMFileInternalUrlHolder::~nsDOMFileInternalUrlHolder() {
683 2 : if (!mUrl.IsEmpty()) {
684 4 : nsCAutoString narrowUrl;
685 2 : CopyUTF16toUTF8(mUrl, narrowUrl);
686 2 : nsBlobProtocolHandler::RemoveFileDataEntry(narrowUrl);
687 : }
688 4394 : }
|