Backed out changeset 58dbd2146e24 (bug 944961) for bustage.
[gecko.git] / content / base / src / nsDOMFile.cpp
blobffeb30039512890b72c8db8b5ff4f1abd4b18aac
1 /* -*- Mode: C++; tab-width: 2; 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/. */
7 #include "nsDOMFile.h"
9 #include "nsCExternalHandlerService.h"
10 #include "nsContentCID.h"
11 #include "nsContentUtils.h"
12 #include "nsDOMClassInfoID.h"
13 #include "nsError.h"
14 #include "nsICharsetDetector.h"
15 #include "nsIClassInfo.h"
16 #include "nsIConverterInputStream.h"
17 #include "nsIDocument.h"
18 #include "nsIFileStreams.h"
19 #include "nsIInputStream.h"
20 #include "nsIIPCSerializableInputStream.h"
21 #include "nsIMemoryReporter.h"
22 #include "nsIMIMEService.h"
23 #include "nsIPlatformCharset.h"
24 #include "nsISeekableStream.h"
25 #include "nsIUnicharInputStream.h"
26 #include "nsIUnicodeDecoder.h"
27 #include "nsNetCID.h"
28 #include "nsNetUtil.h"
29 #include "nsIUUIDGenerator.h"
30 #include "nsHostObjectProtocolHandler.h"
31 #include "nsStringStream.h"
32 #include "nsJSUtils.h"
33 #include "nsPrintfCString.h"
34 #include "mozilla/SHA1.h"
35 #include "mozilla/CheckedInt.h"
36 #include "mozilla/Preferences.h"
37 #include "mozilla/Attributes.h"
38 #include "nsThreadUtils.h"
40 #include "mozilla/dom/FileListBinding.h"
41 using namespace mozilla;
42 using namespace mozilla::dom;
44 // XXXkhuey the input stream that we pass out of a DOMFile
45 // can outlive the actual DOMFile object. Thus, we must
46 // ensure that the buffer underlying the stream we get
47 // from NS_NewByteInputStream is held alive as long as the
48 // stream is. We do that by passing back this class instead.
49 class DataOwnerAdapter MOZ_FINAL : public nsIInputStream,
50 public nsISeekableStream,
51 public nsIIPCSerializableInputStream
53 typedef nsDOMMemoryFile::DataOwner DataOwner;
54 public:
55 static nsresult Create(DataOwner* aDataOwner,
56 uint32_t aStart,
57 uint32_t aLength,
58 nsIInputStream** _retval);
60 NS_DECL_THREADSAFE_ISUPPORTS
62 // These are mandatory.
63 NS_FORWARD_NSIINPUTSTREAM(mStream->)
64 NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
66 // This is optional. We use a conditional QI to keep it from being called
67 // if the underlying stream doesn't support it.
68 NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->)
70 private:
71 DataOwnerAdapter(DataOwner* aDataOwner,
72 nsIInputStream* aStream)
73 : mDataOwner(aDataOwner), mStream(aStream),
74 mSeekableStream(do_QueryInterface(aStream)),
75 mSerializableInputStream(do_QueryInterface(aStream))
77 NS_ASSERTION(mSeekableStream, "Somebody gave us the wrong stream!");
80 nsRefPtr<DataOwner> mDataOwner;
81 nsCOMPtr<nsIInputStream> mStream;
82 nsCOMPtr<nsISeekableStream> mSeekableStream;
83 nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
86 NS_IMPL_ADDREF(DataOwnerAdapter)
87 NS_IMPL_RELEASE(DataOwnerAdapter)
89 NS_INTERFACE_MAP_BEGIN(DataOwnerAdapter)
90 NS_INTERFACE_MAP_ENTRY(nsIInputStream)
91 NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
92 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
93 mSerializableInputStream)
94 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
95 NS_INTERFACE_MAP_END
97 nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
98 uint32_t aStart,
99 uint32_t aLength,
100 nsIInputStream** _retval)
102 nsresult rv;
103 NS_ASSERTION(aDataOwner, "Uh ...");
105 nsCOMPtr<nsIInputStream> stream;
107 rv = NS_NewByteInputStream(getter_AddRefs(stream),
108 static_cast<const char*>(aDataOwner->mData) +
109 aStart,
110 (int32_t)aLength,
111 NS_ASSIGNMENT_DEPEND);
112 NS_ENSURE_SUCCESS(rv, rv);
114 NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
116 return NS_OK;
119 ////////////////////////////////////////////////////////////////////////////
120 // nsDOMFileBase implementation
122 NS_IMETHODIMP
123 nsDOMFileBase::GetName(nsAString &aFileName)
125 NS_ASSERTION(mIsFile, "Should only be called on files");
126 aFileName = mName;
127 return NS_OK;
130 NS_IMETHODIMP
131 nsDOMFileBase::GetPath(nsAString &aPath)
133 NS_ASSERTION(mIsFile, "Should only be called on files");
134 aPath = mPath;
135 return NS_OK;
138 NS_IMETHODIMP
139 nsDOMFileBase::GetLastModifiedDate(JSContext* cx, JS::Value *aLastModifiedDate)
141 JSObject* date = JS_NewDateObjectMsec(cx, JS_Now() / PR_USEC_PER_MSEC);
142 aLastModifiedDate->setObject(*date);
143 return NS_OK;
146 NS_IMETHODIMP
147 nsDOMFileBase::GetMozFullPath(nsAString &aFileName)
149 NS_ASSERTION(mIsFile, "Should only be called on files");
151 // It is unsafe to call IsCallerChrome on a non-main thread. If
152 // you hit the following assertion you need to figure out some other way to
153 // determine privileges and call GetMozFullPathInternal.
154 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
156 if (nsContentUtils::IsCallerChrome()) {
157 return GetMozFullPathInternal(aFileName);
159 aFileName.Truncate();
160 return NS_OK;
163 NS_IMETHODIMP
164 nsDOMFileBase::GetMozFullPathInternal(nsAString &aFileName)
166 if (!mIsFile) {
167 return NS_ERROR_FAILURE;
170 aFileName.Truncate();
171 return NS_OK;
174 NS_IMETHODIMP
175 nsDOMFileBase::GetSize(uint64_t *aSize)
177 *aSize = mLength;
178 return NS_OK;
181 NS_IMETHODIMP
182 nsDOMFileBase::GetType(nsAString &aType)
184 aType = mContentType;
185 return NS_OK;
188 NS_IMETHODIMP
189 nsDOMFileBase::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
191 NS_ASSERTION(mIsFile, "Should only be called on files");
192 if (IsDateUnknown()) {
193 mLastModificationDate = PR_Now();
195 *aLastModifiedDate = mLastModificationDate;
196 return NS_OK;
199 // Makes sure that aStart and aEnd is less then or equal to aSize and greater
200 // than 0
201 static void
202 ParseSize(int64_t aSize, int64_t& aStart, int64_t& aEnd)
204 CheckedInt64 newStartOffset = aStart;
205 if (aStart < -aSize) {
206 newStartOffset = 0;
208 else if (aStart < 0) {
209 newStartOffset += aSize;
211 else if (aStart > aSize) {
212 newStartOffset = aSize;
215 CheckedInt64 newEndOffset = aEnd;
216 if (aEnd < -aSize) {
217 newEndOffset = 0;
219 else if (aEnd < 0) {
220 newEndOffset += aSize;
222 else if (aEnd > aSize) {
223 newEndOffset = aSize;
226 if (!newStartOffset.isValid() || !newEndOffset.isValid() ||
227 newStartOffset.value() >= newEndOffset.value()) {
228 aStart = aEnd = 0;
230 else {
231 aStart = newStartOffset.value();
232 aEnd = newEndOffset.value();
236 NS_IMETHODIMP
237 nsDOMFileBase::Slice(int64_t aStart, int64_t aEnd,
238 const nsAString& aContentType, uint8_t optional_argc,
239 nsIDOMBlob **aBlob)
241 *aBlob = nullptr;
243 // Truncate aStart and aEnd so that we stay within this file.
244 uint64_t thisLength;
245 nsresult rv = GetSize(&thisLength);
246 NS_ENSURE_SUCCESS(rv, rv);
248 if (optional_argc < 2) {
249 aEnd = (int64_t)thisLength;
252 ParseSize((int64_t)thisLength, aStart, aEnd);
254 // Create the new file
255 *aBlob = CreateSlice((uint64_t)aStart, (uint64_t)(aEnd - aStart),
256 aContentType).get();
258 return *aBlob ? NS_OK : NS_ERROR_UNEXPECTED;
261 NS_IMETHODIMP
262 nsDOMFileBase::MozSlice(int64_t aStart, int64_t aEnd,
263 const nsAString& aContentType,
264 JSContext* aCx,
265 uint8_t optional_argc,
266 nsIDOMBlob **aBlob)
268 MOZ_ASSERT(NS_IsMainThread());
270 nsIScriptGlobalObject* sgo = nsJSUtils::GetDynamicScriptGlobal(aCx);
271 if (sgo) {
272 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
273 if (window) {
274 nsCOMPtr<nsIDocument> document = window->GetExtantDoc();
275 if (document) {
276 document->WarnOnceAbout(nsIDocument::eMozSlice);
281 return Slice(aStart, aEnd, aContentType, optional_argc, aBlob);
284 NS_IMETHODIMP
285 nsDOMFileBase::GetInternalStream(nsIInputStream **aStream)
287 // Must be overridden
288 NS_NOTREACHED("Must override GetInternalStream");
290 return NS_ERROR_NOT_IMPLEMENTED;
293 NS_IMETHODIMP
294 nsDOMFileBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
296 NS_ENSURE_STATE(aPrincipal);
298 nsCString url;
299 nsresult rv = nsBlobProtocolHandler::AddDataEntry(
300 NS_LITERAL_CSTRING(BLOBURI_SCHEME),
301 static_cast<nsIDOMBlob*>(this), aPrincipal, url);
302 if (NS_FAILED(rv)) {
303 return rv;
306 CopyASCIItoUTF16(url, aURL);
307 return NS_OK;
310 NS_IMETHODIMP_(int64_t)
311 nsDOMFileBase::GetFileId()
313 int64_t id = -1;
315 if (IsStoredFile() && IsWholeFile() && !IsSnapshot()) {
316 if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
317 indexedDB::IndexedDatabaseManager::FileMutex().Lock();
320 NS_ASSERTION(!mFileInfos.IsEmpty(),
321 "A stored file must have at least one file info!");
323 nsRefPtr<indexedDB::FileInfo>& fileInfo = mFileInfos.ElementAt(0);
324 if (fileInfo) {
325 id = fileInfo->Id();
328 if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
329 indexedDB::IndexedDatabaseManager::FileMutex().Unlock();
333 return id;
336 NS_IMETHODIMP_(void)
337 nsDOMFileBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
339 if (indexedDB::IndexedDatabaseManager::IsClosed()) {
340 NS_ERROR("Shouldn't be called after shutdown!");
341 return;
344 nsRefPtr<indexedDB::FileInfo> fileInfo = aFileInfo;
346 MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
348 NS_ASSERTION(!mFileInfos.Contains(aFileInfo),
349 "Adding the same file info agan?!");
351 nsRefPtr<indexedDB::FileInfo>* element = mFileInfos.AppendElement();
352 element->swap(fileInfo);
355 NS_IMETHODIMP_(indexedDB::FileInfo*)
356 nsDOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
358 if (indexedDB::IndexedDatabaseManager::IsClosed()) {
359 NS_ERROR("Shouldn't be called after shutdown!");
360 return nullptr;
363 // A slice created from a stored file must keep the file info alive.
364 // However, we don't support sharing of slices yet, so the slice must be
365 // copied again. That's why we have to ignore the first file info.
366 // Snapshots are handled in a similar way (they have to be copied).
367 uint32_t startIndex;
368 if (IsStoredFile() && (!IsWholeFile() || IsSnapshot())) {
369 startIndex = 1;
371 else {
372 startIndex = 0;
375 MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
377 for (uint32_t i = startIndex; i < mFileInfos.Length(); i++) {
378 nsRefPtr<indexedDB::FileInfo>& fileInfo = mFileInfos.ElementAt(i);
379 if (fileInfo->Manager() == aFileManager) {
380 return fileInfo;
384 return nullptr;
387 NS_IMETHODIMP
388 nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
389 uint64_t* aContentLength,
390 nsACString& aContentType,
391 nsACString& aCharset)
393 nsresult rv;
395 nsCOMPtr<nsIInputStream> stream;
396 rv = this->GetInternalStream(getter_AddRefs(stream));
397 NS_ENSURE_SUCCESS(rv, rv);
399 rv = this->GetSize(aContentLength);
400 NS_ENSURE_SUCCESS(rv, rv);
402 nsString contentType;
403 rv = this->GetType(contentType);
404 NS_ENSURE_SUCCESS(rv, rv);
406 CopyUTF16toUTF8(contentType, aContentType);
408 aCharset.Truncate();
410 stream.forget(aBody);
411 return NS_OK;
414 NS_IMETHODIMP
415 nsDOMFileBase::GetMutable(bool* aMutable)
417 *aMutable = !mImmutable;
418 return NS_OK;
421 NS_IMETHODIMP
422 nsDOMFileBase::SetMutable(bool aMutable)
424 nsresult rv = NS_OK;
426 NS_ENSURE_ARG(!mImmutable || !aMutable);
428 if (!mImmutable && !aMutable) {
429 // Force the content type and size to be cached
430 nsString dummyString;
431 rv = this->GetType(dummyString);
432 NS_ENSURE_SUCCESS(rv, rv);
434 uint64_t dummyInt;
435 rv = this->GetSize(&dummyInt);
436 NS_ENSURE_SUCCESS(rv, rv);
439 mImmutable = !aMutable;
440 return rv;
443 ////////////////////////////////////////////////////////////////////////////
444 // nsDOMFile implementation
446 DOMCI_DATA(File, nsDOMFile)
447 DOMCI_DATA(Blob, nsDOMFile)
449 NS_INTERFACE_MAP_BEGIN(nsDOMFile)
450 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
451 NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
452 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
453 NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
454 NS_INTERFACE_MAP_ENTRY(nsIMutable)
455 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
456 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
457 NS_INTERFACE_MAP_END
459 // Threadsafe when GetMutable() == false
460 NS_IMPL_ADDREF(nsDOMFile)
461 NS_IMPL_RELEASE(nsDOMFile)
463 ////////////////////////////////////////////////////////////////////////////
464 // nsDOMFileCC implementation
466 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileCC)
468 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsDOMFileCC)
469 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMFileCC)
470 // We don't have anything to traverse, but some of our subclasses do.
471 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
473 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileCC)
474 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
475 NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
476 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
477 NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
478 NS_INTERFACE_MAP_ENTRY(nsIMutable)
479 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
480 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
481 NS_INTERFACE_MAP_END
483 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileCC)
484 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileCC)
486 ////////////////////////////////////////////////////////////////////////////
487 // nsDOMFileFile implementation
489 already_AddRefed<nsIDOMBlob>
490 nsDOMFileFile::CreateSlice(uint64_t aStart, uint64_t aLength,
491 const nsAString& aContentType)
493 nsCOMPtr<nsIDOMBlob> t = new nsDOMFileFile(this, aStart, aLength, aContentType);
494 return t.forget();
497 NS_IMETHODIMP
498 nsDOMFileFile::GetMozFullPathInternal(nsAString &aFilename)
500 NS_ASSERTION(mIsFile, "Should only be called on files");
501 return mFile->GetPath(aFilename);
504 NS_IMETHODIMP
505 nsDOMFileFile::GetLastModifiedDate(JSContext* cx, JS::Value* aLastModifiedDate)
507 NS_ASSERTION(mIsFile, "Should only be called on files");
509 PRTime msecs;
510 if (IsDateUnknown()) {
511 nsresult rv = mFile->GetLastModifiedTime(&msecs);
512 NS_ENSURE_SUCCESS(rv, rv);
513 mLastModificationDate = msecs;
514 } else {
515 msecs = mLastModificationDate;
518 JSObject* date = JS_NewDateObjectMsec(cx, msecs);
519 if (date) {
520 aLastModifiedDate->setObject(*date);
522 else {
523 date = JS_NewDateObjectMsec(cx, JS_Now() / PR_USEC_PER_MSEC);
524 aLastModifiedDate->setObject(*date);
527 return NS_OK;
530 NS_IMETHODIMP
531 nsDOMFileFile::GetSize(uint64_t *aFileSize)
533 if (IsSizeUnknown()) {
534 NS_ASSERTION(mWholeFile,
535 "Should only use lazy size when using the whole file");
536 int64_t fileSize;
537 nsresult rv = mFile->GetFileSize(&fileSize);
538 NS_ENSURE_SUCCESS(rv, rv);
540 if (fileSize < 0) {
541 return NS_ERROR_FAILURE;
544 mLength = fileSize;
547 *aFileSize = mLength;
549 return NS_OK;
552 NS_IMETHODIMP
553 nsDOMFileFile::GetType(nsAString &aType)
555 if (mContentType.IsVoid()) {
556 NS_ASSERTION(mWholeFile,
557 "Should only use lazy ContentType when using the whole file");
558 nsresult rv;
559 nsCOMPtr<nsIMIMEService> mimeService =
560 do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
561 NS_ENSURE_SUCCESS(rv, rv);
563 nsAutoCString mimeType;
564 rv = mimeService->GetTypeFromFile(mFile, mimeType);
565 if (NS_FAILED(rv)) {
566 mimeType.Truncate();
569 AppendUTF8toUTF16(mimeType, mContentType);
570 mContentType.SetIsVoid(false);
573 aType = mContentType;
575 return NS_OK;
578 NS_IMETHODIMP
579 nsDOMFileFile::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
581 NS_ASSERTION(mIsFile, "Should only be called on files");
582 if (IsDateUnknown()) {
583 PRTime msecs;
584 nsresult rv = mFile->GetLastModifiedTime(&msecs);
585 NS_ENSURE_SUCCESS(rv, rv);
586 mLastModificationDate = msecs;
588 *aLastModifiedDate = mLastModificationDate;
589 return NS_OK;
592 const uint32_t sFileStreamFlags =
593 nsIFileInputStream::CLOSE_ON_EOF |
594 nsIFileInputStream::REOPEN_ON_REWIND |
595 nsIFileInputStream::DEFER_OPEN;
597 NS_IMETHODIMP
598 nsDOMFileFile::GetInternalStream(nsIInputStream **aStream)
600 return mWholeFile ?
601 NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
602 NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
603 -1, -1, sFileStreamFlags);
606 void
607 nsDOMFileFile::SetPath(const nsAString& aPath)
609 MOZ_ASSERT(aPath.IsEmpty() ||
610 aPath[aPath.Length() - 1] == PRUnichar('/'),
611 "Path must end with a path separator");
612 mPath = aPath;
615 ////////////////////////////////////////////////////////////////////////////
616 // nsDOMMemoryFile implementation
618 already_AddRefed<nsIDOMBlob>
619 nsDOMMemoryFile::CreateSlice(uint64_t aStart, uint64_t aLength,
620 const nsAString& aContentType)
622 nsCOMPtr<nsIDOMBlob> t =
623 new nsDOMMemoryFile(this, aStart, aLength, aContentType);
624 return t.forget();
627 NS_IMETHODIMP
628 nsDOMMemoryFile::GetInternalStream(nsIInputStream **aStream)
630 if (mLength > INT32_MAX)
631 return NS_ERROR_FAILURE;
633 return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
636 /* static */ StaticMutex
637 nsDOMMemoryFile::DataOwner::sDataOwnerMutex;
639 /* static */ StaticAutoPtr<LinkedList<nsDOMMemoryFile::DataOwner> >
640 nsDOMMemoryFile::DataOwner::sDataOwners;
642 /* static */ bool
643 nsDOMMemoryFile::DataOwner::sMemoryReporterRegistered;
645 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMMemoryFileDataOwnerMallocSizeOf)
647 class nsDOMMemoryFileDataOwnerMemoryReporter MOZ_FINAL
648 : public MemoryMultiReporter
650 public:
651 nsDOMMemoryFileDataOwnerMemoryReporter()
652 : MemoryMultiReporter("dom-memory-file-data-owner")
655 NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCallback,
656 nsISupports *aClosure)
658 typedef nsDOMMemoryFile::DataOwner DataOwner;
660 StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
662 if (!DataOwner::sDataOwners) {
663 return NS_OK;
666 const size_t LARGE_OBJECT_MIN_SIZE = 8 * 1024;
667 size_t smallObjectsTotal = 0;
669 for (DataOwner *owner = DataOwner::sDataOwners->getFirst();
670 owner; owner = owner->getNext()) {
672 size_t size = DOMMemoryFileDataOwnerMallocSizeOf(owner->mData);
674 if (size < LARGE_OBJECT_MIN_SIZE) {
675 smallObjectsTotal += size;
677 else {
678 SHA1Sum sha1;
679 sha1.update(owner->mData, owner->mLength);
680 uint8_t digest[SHA1Sum::HashSize]; // SHA1 digests are 20 bytes long.
681 sha1.finish(digest);
683 nsAutoCString digestString;
684 for (size_t i = 0; i < sizeof(digest); i++) {
685 digestString.AppendPrintf("%02x", digest[i]);
688 nsresult rv = aCallback->Callback(
689 /* process */ NS_LITERAL_CSTRING(""),
690 nsPrintfCString(
691 "explicit/dom/memory-file-data/large/file(length=%llu, sha1=%s)",
692 owner->mLength, digestString.get()),
693 nsIMemoryReporter::KIND_HEAP,
694 nsIMemoryReporter::UNITS_BYTES,
695 size,
696 nsPrintfCString(
697 "Memory used to back a memory file of length %llu bytes. The file "
698 "has a sha1 of %s.\n\n"
699 "Note that the allocator may round up a memory file's length -- "
700 "that is, an N-byte memory file may take up more than N bytes of "
701 "memory.",
702 owner->mLength, digestString.get()),
703 aClosure);
704 NS_ENSURE_SUCCESS(rv, rv);
708 if (smallObjectsTotal > 0) {
709 nsresult rv = aCallback->Callback(
710 /* process */ NS_LITERAL_CSTRING(""),
711 NS_LITERAL_CSTRING("explicit/dom/memory-file-data/small"),
712 nsIMemoryReporter::KIND_HEAP,
713 nsIMemoryReporter::UNITS_BYTES,
714 smallObjectsTotal,
715 nsPrintfCString(
716 "Memory used to back small memory files (less than %d bytes each).\n\n"
717 "Note that the allocator may round up a memory file's length -- "
718 "that is, an N-byte memory file may take up more than N bytes of "
719 "memory."),
720 aClosure);
721 NS_ENSURE_SUCCESS(rv, rv);
724 return NS_OK;
728 /* static */ void
729 nsDOMMemoryFile::DataOwner::EnsureMemoryReporterRegistered()
731 sDataOwnerMutex.AssertCurrentThreadOwns();
732 if (sMemoryReporterRegistered) {
733 return;
736 RegisterStrongMemoryReporter(new nsDOMMemoryFileDataOwnerMemoryReporter());
738 sMemoryReporterRegistered = true;
741 ////////////////////////////////////////////////////////////////////////////
742 // nsDOMFileList implementation
744 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMFileList)
746 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileList)
747 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
748 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
749 NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
750 NS_INTERFACE_MAP_END
752 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
753 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
755 JSObject*
756 nsDOMFileList::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
758 return FileListBinding::Wrap(cx, scope, this);
761 NS_IMETHODIMP
762 nsDOMFileList::GetLength(uint32_t* aLength)
764 *aLength = Length();
766 return NS_OK;
769 NS_IMETHODIMP
770 nsDOMFileList::Item(uint32_t aIndex, nsIDOMFile **aFile)
772 NS_IF_ADDREF(*aFile = Item(aIndex));
774 return NS_OK;
777 ////////////////////////////////////////////////////////////////////////////
778 // nsDOMFileInternalUrlHolder implementation
780 nsDOMFileInternalUrlHolder::nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile,
781 nsIPrincipal* aPrincipal
782 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {
783 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
784 aFile->GetInternalUrl(aPrincipal, mUrl);
787 nsDOMFileInternalUrlHolder::~nsDOMFileInternalUrlHolder() {
788 if (!mUrl.IsEmpty()) {
789 nsAutoCString narrowUrl;
790 CopyUTF16toUTF8(mUrl, narrowUrl);
791 nsBlobProtocolHandler::RemoveDataEntry(narrowUrl);
795 ////////////////////////////////////////////////////////////////////////////
796 // nsDOMTemporaryFileBlob implementation
797 already_AddRefed<nsIDOMBlob>
798 nsDOMTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
799 const nsAString& aContentType)
801 if (aStart + aLength > mLength)
802 return nullptr;
804 nsCOMPtr<nsIDOMBlob> t =
805 new nsDOMTemporaryFileBlob(this, aStart + mStartPos, aLength, aContentType);
806 return t.forget();
809 NS_IMETHODIMP
810 nsDOMTemporaryFileBlob::GetInternalStream(nsIInputStream **aStream)
812 nsCOMPtr<nsTemporaryFileInputStream> stream =
813 new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
814 stream.forget(aStream);
815 return NS_OK;