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