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_CONDITIONAL(nsIDOMFile, mIsFile)
146 42 : NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
147 42 : NS_INTERFACE_MAP_ENTRY(nsIMutable)
148 42 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
149 34 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
150 34 : NS_INTERFACE_MAP_END
151 :
152 : // Threadsafe when GetMutable() == false
153 52 : NS_IMPL_THREADSAFE_ADDREF(nsDOMFileBase)
154 52 : NS_IMPL_THREADSAFE_RELEASE(nsDOMFileBase)
155 :
156 : NS_IMETHODIMP
157 6 : nsDOMFileBase::GetName(nsAString &aFileName)
158 : {
159 6 : NS_ASSERTION(mIsFile, "Should only be called on files");
160 6 : aFileName = mName;
161 6 : return NS_OK;
162 : }
163 :
164 : NS_IMETHODIMP
165 0 : nsDOMFileBase::GetMozFullPath(nsAString &aFileName)
166 : {
167 0 : NS_ASSERTION(mIsFile, "Should only be called on files");
168 :
169 : // It is unsafe to call CallerHasUniversalXPConnect on a non-main thread. If
170 : // you hit the following assertion you need to figure out some other way to
171 : // determine privileges and call GetMozFullPathInternal.
172 0 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
173 :
174 0 : if (nsContentUtils::CallerHasUniversalXPConnect()) {
175 0 : return GetMozFullPathInternal(aFileName);
176 : }
177 0 : aFileName.Truncate();
178 0 : return NS_OK;
179 : }
180 :
181 : NS_IMETHODIMP
182 0 : nsDOMFileBase::GetMozFullPathInternal(nsAString &aFileName)
183 : {
184 0 : NS_ASSERTION(mIsFile, "Should only be called on files");
185 0 : aFileName.Truncate();
186 0 : return NS_OK;
187 : }
188 :
189 : NS_IMETHODIMP
190 0 : nsDOMFileBase::GetSize(PRUint64 *aSize)
191 : {
192 0 : *aSize = mLength;
193 0 : return NS_OK;
194 : }
195 :
196 : NS_IMETHODIMP
197 0 : nsDOMFileBase::GetType(nsAString &aType)
198 : {
199 0 : aType = mContentType;
200 0 : return NS_OK;
201 : }
202 :
203 : // Makes sure that aStart and aEnd is less then or equal to aSize and greater
204 : // than 0
205 : static void
206 0 : ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd)
207 : {
208 0 : CheckedInt64 newStartOffset = aStart;
209 0 : if (aStart < -aSize) {
210 0 : newStartOffset = 0;
211 : }
212 0 : else if (aStart < 0) {
213 0 : newStartOffset += aSize;
214 : }
215 0 : else if (aStart > aSize) {
216 0 : newStartOffset = aSize;
217 : }
218 :
219 0 : CheckedInt64 newEndOffset = aEnd;
220 0 : if (aEnd < -aSize) {
221 0 : newEndOffset = 0;
222 : }
223 0 : else if (aEnd < 0) {
224 0 : newEndOffset += aSize;
225 : }
226 0 : else if (aEnd > aSize) {
227 0 : newEndOffset = aSize;
228 : }
229 :
230 0 : if (!newStartOffset.valid() || !newEndOffset.valid() ||
231 0 : newStartOffset.value() >= newEndOffset.value()) {
232 0 : aStart = aEnd = 0;
233 : }
234 : else {
235 0 : aStart = newStartOffset.value();
236 0 : aEnd = newEndOffset.value();
237 : }
238 0 : }
239 :
240 : NS_IMETHODIMP
241 0 : nsDOMFileBase::Slice(PRInt64 aStart, PRInt64 aEnd,
242 : const nsAString& aContentType, PRUint8 optional_argc,
243 : nsIDOMBlob **aBlob)
244 : {
245 0 : *aBlob = nsnull;
246 :
247 : // Truncate aStart and aEnd so that we stay within this file.
248 : PRUint64 thisLength;
249 0 : nsresult rv = GetSize(&thisLength);
250 0 : NS_ENSURE_SUCCESS(rv, rv);
251 :
252 0 : if (optional_argc < 2) {
253 0 : aEnd = (PRInt64)thisLength;
254 : }
255 :
256 0 : ParseSize((PRInt64)thisLength, aStart, aEnd);
257 :
258 : // Create the new file
259 : *aBlob = CreateSlice((PRUint64)aStart, (PRUint64)(aEnd - aStart),
260 0 : aContentType).get();
261 :
262 0 : return *aBlob ? NS_OK : NS_ERROR_UNEXPECTED;
263 : }
264 :
265 : NS_IMETHODIMP
266 0 : nsDOMFileBase::GetInternalStream(nsIInputStream **aStream)
267 : {
268 : // Must be overridden
269 0 : NS_NOTREACHED("Must override GetInternalStream");
270 :
271 0 : return NS_ERROR_NOT_IMPLEMENTED;
272 : }
273 :
274 : NS_IMETHODIMP
275 2 : nsDOMFileBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
276 : {
277 2 : NS_ENSURE_STATE(aPrincipal);
278 :
279 : nsresult rv;
280 : nsCOMPtr<nsIUUIDGenerator> uuidgen =
281 4 : do_GetService("@mozilla.org/uuid-generator;1", &rv);
282 2 : NS_ENSURE_SUCCESS(rv, rv);
283 :
284 : nsID id;
285 2 : rv = uuidgen->GenerateUUIDInPlace(&id);
286 2 : NS_ENSURE_SUCCESS(rv, rv);
287 :
288 : char chars[NSID_LENGTH];
289 2 : id.ToProvidedString(chars);
290 :
291 2 : nsCString url = NS_LITERAL_CSTRING(BLOBURI_SCHEME ":") +
292 6 : Substring(chars + 1, chars + NSID_LENGTH - 2);
293 :
294 : nsBlobProtocolHandler::AddFileDataEntry(url, this,
295 2 : aPrincipal);
296 :
297 2 : CopyASCIItoUTF16(url, aURL);
298 :
299 2 : return NS_OK;
300 : }
301 :
302 : NS_IMETHODIMP_(PRInt64)
303 0 : nsDOMFileBase::GetFileId()
304 : {
305 0 : PRInt64 id = -1;
306 :
307 0 : if (IsStoredFile() && IsWholeFile()) {
308 0 : if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
309 0 : indexedDB::IndexedDatabaseManager::FileMutex().Lock();
310 : }
311 :
312 0 : NS_ASSERTION(!mFileInfos.IsEmpty(),
313 : "A stored file must have at least one file info!");
314 :
315 0 : nsRefPtr<indexedDB::FileInfo>& fileInfo = mFileInfos.ElementAt(0);
316 0 : if (fileInfo) {
317 0 : id = fileInfo->Id();
318 : }
319 :
320 0 : if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
321 0 : indexedDB::IndexedDatabaseManager::FileMutex().Unlock();
322 : }
323 : }
324 :
325 0 : return id;
326 : }
327 :
328 : NS_IMETHODIMP_(void)
329 0 : nsDOMFileBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
330 : {
331 0 : if (indexedDB::IndexedDatabaseManager::IsClosed()) {
332 0 : NS_ERROR("Shouldn't be called after shutdown!");
333 0 : return;
334 : }
335 :
336 0 : nsRefPtr<indexedDB::FileInfo> fileInfo = aFileInfo;
337 :
338 0 : MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
339 :
340 0 : NS_ASSERTION(!mFileInfos.Contains(aFileInfo),
341 : "Adding the same file info agan?!");
342 :
343 0 : nsRefPtr<indexedDB::FileInfo>* element = mFileInfos.AppendElement();
344 0 : element->swap(fileInfo);
345 : }
346 :
347 : NS_IMETHODIMP_(indexedDB::FileInfo*)
348 0 : nsDOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
349 : {
350 0 : if (indexedDB::IndexedDatabaseManager::IsClosed()) {
351 0 : NS_ERROR("Shouldn't be called after shutdown!");
352 0 : return nsnull;
353 : }
354 :
355 : // A slice created from a stored file must keep the file info alive.
356 : // However, we don't support sharing of slices yet, so the slice must be
357 : // copied again. That's why we have to ignore the first file info.
358 0 : PRUint32 startIndex = IsStoredFile() && !IsWholeFile() ? 1 : 0;
359 :
360 0 : MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
361 :
362 0 : for (PRUint32 i = startIndex; i < mFileInfos.Length(); i++) {
363 0 : nsRefPtr<indexedDB::FileInfo>& fileInfo = mFileInfos.ElementAt(i);
364 0 : if (fileInfo->Manager() == aFileManager) {
365 0 : return fileInfo;
366 : }
367 : }
368 :
369 0 : return nsnull;
370 : }
371 :
372 : NS_IMETHODIMP
373 0 : nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
374 : nsACString& aContentType,
375 : nsACString& aCharset)
376 : {
377 : nsresult rv;
378 :
379 0 : nsCOMPtr<nsIInputStream> stream;
380 0 : rv = this->GetInternalStream(getter_AddRefs(stream));
381 0 : NS_ENSURE_SUCCESS(rv, rv);
382 :
383 0 : nsString contentType;
384 0 : rv = this->GetType(contentType);
385 0 : NS_ENSURE_SUCCESS(rv, rv);
386 :
387 0 : CopyUTF16toUTF8(contentType, aContentType);
388 :
389 0 : aCharset.Truncate();
390 :
391 0 : stream.forget(aBody);
392 0 : return NS_OK;
393 : }
394 :
395 : NS_IMETHODIMP
396 0 : nsDOMFileBase::GetMutable(bool* aMutable)
397 : {
398 0 : *aMutable = !mImmutable;
399 0 : return NS_OK;
400 : }
401 :
402 : NS_IMETHODIMP
403 0 : nsDOMFileBase::SetMutable(bool aMutable)
404 : {
405 0 : nsresult rv = NS_OK;
406 :
407 0 : NS_ENSURE_ARG(!mImmutable || !aMutable);
408 :
409 0 : if (!mImmutable && !aMutable) {
410 : // Force the content type and size to be cached
411 0 : nsString dummyString;
412 0 : rv = this->GetType(dummyString);
413 0 : NS_ENSURE_SUCCESS(rv, rv);
414 :
415 : PRUint64 dummyInt;
416 0 : rv = this->GetSize(&dummyInt);
417 0 : NS_ENSURE_SUCCESS(rv, rv);
418 : }
419 :
420 0 : mImmutable = !aMutable;
421 0 : return rv;
422 : }
423 :
424 : ////////////////////////////////////////////////////////////////////////////
425 : // nsDOMFileFile implementation
426 :
427 194 : NS_IMPL_ISUPPORTS_INHERITED1(nsDOMFileFile, nsDOMFileBase,
428 : nsIJSNativeInitializer)
429 :
430 : already_AddRefed<nsIDOMBlob>
431 0 : nsDOMFileFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
432 : const nsAString& aContentType)
433 : {
434 0 : nsCOMPtr<nsIDOMBlob> t = new nsDOMFileFile(this, aStart, aLength, aContentType);
435 0 : return t.forget();
436 : }
437 :
438 : /* static */ nsresult
439 10 : nsDOMFileFile::NewFile(nsISupports* *aNewObject)
440 : {
441 20 : nsCOMPtr<nsISupports> file = do_QueryObject(new nsDOMFileFile());
442 10 : file.forget(aNewObject);
443 10 : return NS_OK;
444 : }
445 :
446 : NS_IMETHODIMP
447 0 : nsDOMFileFile::GetMozFullPathInternal(nsAString &aFilename)
448 : {
449 0 : NS_ASSERTION(mIsFile, "Should only be called on files");
450 0 : return mFile->GetPath(aFilename);
451 : }
452 :
453 : NS_IMETHODIMP
454 2 : nsDOMFileFile::GetSize(PRUint64 *aFileSize)
455 : {
456 2 : if (IsSizeUnknown()) {
457 2 : NS_ASSERTION(mWholeFile,
458 : "Should only use lazy size when using the whole file");
459 : PRInt64 fileSize;
460 2 : nsresult rv = mFile->GetFileSize(&fileSize);
461 2 : NS_ENSURE_SUCCESS(rv, rv);
462 :
463 2 : if (fileSize < 0) {
464 0 : return NS_ERROR_FAILURE;
465 : }
466 :
467 2 : mLength = fileSize;
468 : }
469 :
470 2 : *aFileSize = mLength;
471 :
472 2 : return NS_OK;
473 : }
474 :
475 : NS_IMETHODIMP
476 2 : nsDOMFileFile::GetType(nsAString &aType)
477 : {
478 2 : if (mContentType.IsVoid()) {
479 2 : NS_ASSERTION(mWholeFile,
480 : "Should only use lazy ContentType when using the whole file");
481 : nsresult rv;
482 : nsCOMPtr<nsIMIMEService> mimeService =
483 4 : do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
484 2 : NS_ENSURE_SUCCESS(rv, rv);
485 :
486 6 : nsCAutoString mimeType;
487 2 : rv = mimeService->GetTypeFromFile(mFile, mimeType);
488 2 : if (NS_FAILED(rv)) {
489 2 : mimeType.Truncate();
490 : }
491 :
492 2 : AppendUTF8toUTF16(mimeType, mContentType);
493 2 : mContentType.SetIsVoid(false);
494 : }
495 :
496 2 : aType = mContentType;
497 :
498 2 : return NS_OK;
499 : }
500 :
501 : const PRUint32 sFileStreamFlags =
502 : nsIFileInputStream::CLOSE_ON_EOF |
503 : nsIFileInputStream::REOPEN_ON_REWIND |
504 : nsIFileInputStream::DEFER_OPEN;
505 :
506 : NS_IMETHODIMP
507 2 : nsDOMFileFile::GetInternalStream(nsIInputStream **aStream)
508 : {
509 : return mWholeFile ?
510 2 : NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
511 : NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
512 4 : -1, -1, sFileStreamFlags);
513 : }
514 :
515 : NS_IMETHODIMP
516 10 : nsDOMFileFile::Initialize(nsISupports* aOwner,
517 : JSContext* aCx,
518 : JSObject* aObj,
519 : PRUint32 aArgc,
520 : jsval* aArgv)
521 : {
522 : nsresult rv;
523 :
524 10 : NS_ASSERTION(!mImmutable, "Something went wrong ...");
525 10 : NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
526 :
527 10 : if (!nsContentUtils::IsCallerChrome()) {
528 0 : return NS_ERROR_DOM_SECURITY_ERR; // Real short trip
529 : }
530 :
531 10 : NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
532 :
533 : // We expect to get a path to represent as a File object,
534 : // or an nsIFile
535 20 : nsCOMPtr<nsIFile> file;
536 10 : if (!JSVAL_IS_STRING(aArgv[0])) {
537 : // Lets see if it's an nsIFile
538 6 : if (!JSVAL_IS_OBJECT(aArgv[0])) {
539 0 : return NS_ERROR_UNEXPECTED; // We're not interested
540 : }
541 :
542 6 : JSObject* obj = JSVAL_TO_OBJECT(aArgv[0]);
543 6 : NS_ASSERTION(obj, "This is a bit odd");
544 :
545 : // Is it an nsIFile
546 : file = do_QueryInterface(
547 6 : nsContentUtils::XPConnect()->
548 6 : GetNativeOfWrapper(aCx, obj));
549 6 : if (!file)
550 0 : return NS_ERROR_UNEXPECTED;
551 : } else {
552 : // It's a string
553 4 : JSString* str = JS_ValueToString(aCx, aArgv[0]);
554 4 : NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
555 :
556 8 : nsDependentJSString xpcomStr;
557 4 : if (!xpcomStr.init(aCx, str)) {
558 0 : return NS_ERROR_XPC_BAD_CONVERT_JS;
559 : }
560 :
561 8 : nsCOMPtr<nsILocalFile> localFile;
562 4 : rv = NS_NewLocalFile(xpcomStr, false, getter_AddRefs(localFile));
563 4 : NS_ENSURE_SUCCESS(rv, rv);
564 :
565 3 : file = do_QueryInterface(localFile);
566 3 : NS_ASSERTION(file, "This should never happen");
567 : }
568 :
569 : bool exists;
570 9 : rv = file->Exists(&exists);
571 9 : NS_ENSURE_SUCCESS(rv, rv);
572 9 : NS_ENSURE_TRUE(exists, NS_ERROR_FILE_NOT_FOUND);
573 :
574 : bool isDir;
575 9 : rv = file->IsDirectory(&isDir);
576 9 : NS_ENSURE_SUCCESS(rv, rv);
577 9 : NS_ENSURE_FALSE(isDir, NS_ERROR_FILE_IS_DIRECTORY);
578 :
579 8 : mFile = file;
580 8 : file->GetLeafName(mName);
581 :
582 8 : return NS_OK;
583 : }
584 :
585 : ////////////////////////////////////////////////////////////////////////////
586 : // nsDOMMemoryFile implementation
587 :
588 : already_AddRefed<nsIDOMBlob>
589 0 : nsDOMMemoryFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
590 : const nsAString& aContentType)
591 : {
592 : nsCOMPtr<nsIDOMBlob> t =
593 0 : new nsDOMMemoryFile(this, aStart, aLength, aContentType);
594 0 : return t.forget();
595 : }
596 :
597 : NS_IMETHODIMP
598 0 : nsDOMMemoryFile::GetInternalStream(nsIInputStream **aStream)
599 : {
600 0 : if (mLength > PR_INT32_MAX)
601 0 : return NS_ERROR_FAILURE;
602 :
603 0 : return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
604 : }
605 :
606 : ////////////////////////////////////////////////////////////////////////////
607 : // nsDOMFileList implementation
608 :
609 : DOMCI_DATA(FileList, nsDOMFileList)
610 :
611 1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileList)
612 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMFileList)
613 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
614 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
615 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMFileList)
616 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
617 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
618 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMFileList)
619 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
620 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
621 :
622 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileList)
623 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
624 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
625 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
626 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FileList)
627 0 : NS_INTERFACE_MAP_END
628 :
629 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
630 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
631 :
632 : JSObject*
633 0 : nsDOMFileList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
634 : bool *triedToWrap)
635 : {
636 0 : return mozilla::dom::binding::FileList::create(cx, scope, this, triedToWrap);
637 : }
638 :
639 : nsIDOMFile*
640 0 : nsDOMFileList::GetItemAt(PRUint32 aIndex)
641 : {
642 0 : return mFiles.SafeObjectAt(aIndex);
643 : }
644 :
645 : NS_IMETHODIMP
646 0 : nsDOMFileList::GetLength(PRUint32* aLength)
647 : {
648 0 : *aLength = mFiles.Count();
649 :
650 0 : return NS_OK;
651 : }
652 :
653 : NS_IMETHODIMP
654 0 : nsDOMFileList::Item(PRUint32 aIndex, nsIDOMFile **aFile)
655 : {
656 0 : NS_IF_ADDREF(*aFile = nsDOMFileList::GetItemAt(aIndex));
657 :
658 0 : return NS_OK;
659 : }
660 :
661 : ////////////////////////////////////////////////////////////////////////////
662 : // nsDOMFileInternalUrlHolder implementation
663 :
664 2 : nsDOMFileInternalUrlHolder::nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile,
665 : nsIPrincipal* aPrincipal
666 2 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {
667 2 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
668 2 : aFile->GetInternalUrl(aPrincipal, mUrl);
669 2 : }
670 :
671 4 : nsDOMFileInternalUrlHolder::~nsDOMFileInternalUrlHolder() {
672 2 : if (!mUrl.IsEmpty()) {
673 4 : nsCAutoString narrowUrl;
674 2 : CopyUTF16toUTF8(mUrl, narrowUrl);
675 2 : nsBlobProtocolHandler::RemoveFileDataEntry(narrowUrl);
676 : }
677 4190 : }
|