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