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_MemoryBlobImpl_h 8 #define mozilla_dom_MemoryBlobImpl_h 9 10 #include "mozilla/dom/BaseBlobImpl.h" 11 #include "mozilla/LinkedList.h" 12 #include "mozilla/StaticMutex.h" 13 #include "mozilla/StaticPtr.h" 14 #include "nsICloneableInputStream.h" 15 #include "nsIInputStream.h" 16 #include "nsIIPCSerializableInputStream.h" 17 #include "nsIMemoryReporter.h" 18 #include "nsISeekableStream.h" 19 20 namespace mozilla { 21 namespace dom { 22 23 class MemoryBlobImpl final : public BaseBlobImpl { 24 public: NS_INLINE_DECL_REFCOUNTING_INHERITED(MemoryBlobImpl,BaseBlobImpl)25 NS_INLINE_DECL_REFCOUNTING_INHERITED(MemoryBlobImpl, BaseBlobImpl) 26 27 MemoryBlobImpl(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName, 28 const nsAString& aContentType, int64_t aLastModifiedDate) 29 : BaseBlobImpl(aName, aContentType, aLength, aLastModifiedDate), 30 mDataOwner(new DataOwner(aMemoryBuffer, aLength)) { 31 MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data"); 32 } 33 MemoryBlobImpl(void * aMemoryBuffer,uint64_t aLength,const nsAString & aContentType)34 MemoryBlobImpl(void* aMemoryBuffer, uint64_t aLength, 35 const nsAString& aContentType) 36 : BaseBlobImpl(aContentType, aLength), 37 mDataOwner(new DataOwner(aMemoryBuffer, aLength)) { 38 MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data"); 39 } 40 41 virtual void CreateInputStream(nsIInputStream** aStream, 42 ErrorResult& aRv) override; 43 44 virtual already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, 45 uint64_t aLength, 46 const nsAString& aContentType, 47 ErrorResult& aRv) override; 48 IsMemoryFile()49 virtual bool IsMemoryFile() const override { return true; } 50 GetAllocationSize()51 size_t GetAllocationSize() const override { return mLength; } 52 53 class DataOwner final : public mozilla::LinkedListElement<DataOwner> { 54 public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOwner)55 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOwner) 56 DataOwner(void* aMemoryBuffer, uint64_t aLength) 57 : mData(aMemoryBuffer), mLength(aLength) { 58 mozilla::StaticMutexAutoLock lock(sDataOwnerMutex); 59 60 if (!sDataOwners) { 61 sDataOwners = new mozilla::LinkedList<DataOwner>(); 62 EnsureMemoryReporterRegistered(); 63 } 64 sDataOwners->insertBack(this); 65 } 66 67 private: 68 // Private destructor, to discourage deletion outside of Release(): ~DataOwner()69 ~DataOwner() { 70 mozilla::StaticMutexAutoLock lock(sDataOwnerMutex); 71 72 remove(); 73 if (sDataOwners->isEmpty()) { 74 // Free the linked list if it's empty. 75 sDataOwners = nullptr; 76 } 77 78 free(mData); 79 } 80 81 public: 82 static void EnsureMemoryReporterRegistered(); 83 84 // sDataOwners and sMemoryReporterRegistered may only be accessed while 85 // holding sDataOwnerMutex! You also must hold the mutex while touching 86 // elements of the linked list that DataOwner inherits from. 87 static mozilla::StaticMutex sDataOwnerMutex; 88 static mozilla::StaticAutoPtr<mozilla::LinkedList<DataOwner> > sDataOwners; 89 static bool sMemoryReporterRegistered; 90 91 void* mData; 92 uint64_t mLength; 93 }; 94 95 class DataOwnerAdapter final : public nsIInputStream, 96 public nsISeekableStream, 97 public nsIIPCSerializableInputStream, 98 public nsICloneableInputStream { 99 typedef MemoryBlobImpl::DataOwner DataOwner; 100 101 public: 102 static nsresult Create(DataOwner* aDataOwner, uint32_t aStart, 103 uint32_t aLength, nsIInputStream** _retval); 104 105 NS_DECL_THREADSAFE_ISUPPORTS 106 107 // These are mandatory. 108 NS_FORWARD_NSIINPUTSTREAM(mStream->) 109 NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->) 110 NS_FORWARD_NSICLONEABLEINPUTSTREAM(mCloneableInputStream->) 111 112 // This is optional. We use a conditional QI to keep it from being called 113 // if the underlying stream doesn't support it. 114 NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->) 115 116 private: ~DataOwnerAdapter()117 ~DataOwnerAdapter() {} 118 DataOwnerAdapter(DataOwner * aDataOwner,nsIInputStream * aStream)119 DataOwnerAdapter(DataOwner* aDataOwner, nsIInputStream* aStream) 120 : mDataOwner(aDataOwner), 121 mStream(aStream), 122 mSeekableStream(do_QueryInterface(aStream)), 123 mSerializableInputStream(do_QueryInterface(aStream)), 124 mCloneableInputStream(do_QueryInterface(aStream)) { 125 MOZ_ASSERT(mSeekableStream, "Somebody gave us the wrong stream!"); 126 } 127 128 RefPtr<DataOwner> mDataOwner; 129 nsCOMPtr<nsIInputStream> mStream; 130 nsCOMPtr<nsISeekableStream> mSeekableStream; 131 nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream; 132 nsCOMPtr<nsICloneableInputStream> mCloneableInputStream; 133 }; 134 135 private: 136 // Create slice MemoryBlobImpl(const MemoryBlobImpl * aOther,uint64_t aStart,uint64_t aLength,const nsAString & aContentType)137 MemoryBlobImpl(const MemoryBlobImpl* aOther, uint64_t aStart, 138 uint64_t aLength, const nsAString& aContentType) 139 : BaseBlobImpl(aContentType, aOther->mStart + aStart, aLength), 140 mDataOwner(aOther->mDataOwner) { 141 MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data"); 142 mImmutable = aOther->mImmutable; 143 } 144 ~MemoryBlobImpl()145 ~MemoryBlobImpl() {} 146 147 // Used when backed by a memory store 148 RefPtr<DataOwner> mDataOwner; 149 }; 150 151 } // namespace dom 152 } // namespace mozilla 153 154 #endif // mozilla_dom_MemoryBlobImpl_h 155