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 : #include "Blob.h"
8 : #include "File.h"
9 : #include "MemoryBlobImpl.h"
10 : #include "mozilla/dom/BlobBinding.h"
11 : #include "MultipartBlobImpl.h"
12 : #include "nsIInputStream.h"
13 : #include "nsPIDOMWindow.h"
14 : #include "TemporaryBlobImpl.h"
15 : #include "StreamBlobImpl.h"
16 : #include "StringBlobImpl.h"
17 :
18 : namespace mozilla {
19 : namespace dom {
20 :
21 : NS_IMPL_CYCLE_COLLECTION_CLASS(Blob)
22 :
23 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Blob)
24 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
25 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
26 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
27 :
28 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Blob)
29 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
30 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
31 :
32 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Blob)
33 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
34 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
35 :
36 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Blob)
37 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
38 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMBlob)
39 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
40 0 : NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
41 0 : NS_INTERFACE_MAP_ENTRY(nsIMutable)
42 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
43 0 : NS_INTERFACE_MAP_END
44 :
45 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(Blob)
46 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(Blob)
47 :
48 : void
49 0 : Blob::MakeValidBlobType(nsAString& aType)
50 : {
51 0 : char16_t* iter = aType.BeginWriting();
52 0 : char16_t* end = aType.EndWriting();
53 :
54 0 : for ( ; iter != end; ++iter) {
55 0 : char16_t c = *iter;
56 0 : if (c < 0x20 || c > 0x7E) {
57 : // Non-ASCII char, bail out.
58 0 : aType.Truncate();
59 0 : return;
60 : }
61 :
62 0 : if (c >= 'A' && c <= 'Z') {
63 0 : *iter = c + ('a' - 'A');
64 : }
65 : }
66 : }
67 :
68 : /* static */ Blob*
69 0 : Blob::Create(nsISupports* aParent, BlobImpl* aImpl)
70 : {
71 0 : MOZ_ASSERT(aImpl);
72 :
73 0 : return aImpl->IsFile() ? new File(aParent, aImpl)
74 0 : : new Blob(aParent, aImpl);
75 : }
76 :
77 : /* static */ already_AddRefed<Blob>
78 0 : Blob::CreateStringBlob(nsISupports* aParent, const nsACString& aData,
79 : const nsAString& aContentType)
80 : {
81 0 : RefPtr<BlobImpl> blobImpl = StringBlobImpl::Create(aData, aContentType);
82 0 : RefPtr<Blob> blob = Blob::Create(aParent, blobImpl);
83 0 : MOZ_ASSERT(!blob->mImpl->IsFile());
84 0 : return blob.forget();
85 : }
86 :
87 : /* static */ already_AddRefed<Blob>
88 0 : Blob::CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer,
89 : uint64_t aLength, const nsAString& aContentType)
90 : {
91 : RefPtr<Blob> blob = Blob::Create(aParent,
92 0 : new MemoryBlobImpl(aMemoryBuffer, aLength, aContentType));
93 0 : MOZ_ASSERT(!blob->mImpl->IsFile());
94 0 : return blob.forget();
95 : }
96 :
97 : /* static */ already_AddRefed<Blob>
98 0 : Blob::CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
99 : uint64_t aStartPos, uint64_t aLength,
100 : const nsAString& aContentType)
101 : {
102 : RefPtr<Blob> blob = Blob::Create(aParent,
103 0 : new TemporaryBlobImpl(aFD, aStartPos, aLength, aContentType));
104 0 : MOZ_ASSERT(!blob->mImpl->IsFile());
105 0 : return blob.forget();
106 : }
107 :
108 0 : Blob::Blob(nsISupports* aParent, BlobImpl* aImpl)
109 : : mImpl(aImpl)
110 0 : , mParent(aParent)
111 : {
112 0 : MOZ_ASSERT(mImpl);
113 :
114 : #ifdef DEBUG
115 : {
116 0 : nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aParent);
117 0 : if (win) {
118 0 : MOZ_ASSERT(win->IsInnerWindow());
119 : }
120 : }
121 : #endif
122 0 : }
123 :
124 0 : Blob::~Blob()
125 0 : {}
126 :
127 : bool
128 0 : Blob::IsFile() const
129 : {
130 0 : return mImpl->IsFile();
131 : }
132 :
133 : const nsTArray<RefPtr<BlobImpl>>*
134 0 : Blob::GetSubBlobImpls() const
135 : {
136 0 : return mImpl->GetSubBlobImpls();
137 : }
138 :
139 : already_AddRefed<File>
140 0 : Blob::ToFile()
141 : {
142 0 : if (!mImpl->IsFile()) {
143 0 : return nullptr;
144 : }
145 :
146 0 : RefPtr<File> file;
147 0 : if (HasFileInterface()) {
148 0 : file = static_cast<File*>(this);
149 : } else {
150 0 : file = new File(mParent, mImpl);
151 : }
152 :
153 0 : return file.forget();
154 : }
155 :
156 : already_AddRefed<File>
157 0 : Blob::ToFile(const nsAString& aName, ErrorResult& aRv) const
158 : {
159 0 : AutoTArray<RefPtr<BlobImpl>, 1> blobImpls({mImpl});
160 :
161 0 : nsAutoString contentType;
162 0 : mImpl->GetType(contentType);
163 :
164 : RefPtr<MultipartBlobImpl> impl =
165 0 : MultipartBlobImpl::Create(Move(blobImpls), aName, contentType, aRv);
166 0 : if (NS_WARN_IF(aRv.Failed())) {
167 0 : return nullptr;
168 : }
169 :
170 0 : RefPtr<File> file = new File(mParent, impl);
171 0 : return file.forget();
172 : }
173 :
174 : already_AddRefed<Blob>
175 0 : Blob::CreateSlice(uint64_t aStart, uint64_t aLength,
176 : const nsAString& aContentType,
177 : ErrorResult& aRv)
178 : {
179 0 : RefPtr<BlobImpl> impl = mImpl->CreateSlice(aStart, aLength,
180 0 : aContentType, aRv);
181 0 : if (aRv.Failed()) {
182 0 : return nullptr;
183 : }
184 :
185 0 : RefPtr<Blob> blob = Blob::Create(mParent, impl);
186 0 : return blob.forget();
187 : }
188 :
189 : uint64_t
190 0 : Blob::GetSize(ErrorResult& aRv)
191 : {
192 0 : return mImpl->GetSize(aRv);
193 : }
194 :
195 : void
196 0 : Blob::GetType(nsAString &aType)
197 : {
198 0 : mImpl->GetType(aType);
199 0 : }
200 :
201 : already_AddRefed<Blob>
202 0 : Blob::Slice(const Optional<int64_t>& aStart,
203 : const Optional<int64_t>& aEnd,
204 : const nsAString& aContentType,
205 : ErrorResult& aRv)
206 : {
207 : RefPtr<BlobImpl> impl =
208 0 : mImpl->Slice(aStart, aEnd, aContentType, aRv);
209 0 : if (aRv.Failed()) {
210 0 : return nullptr;
211 : }
212 :
213 0 : RefPtr<Blob> blob = Blob::Create(mParent, impl);
214 0 : return blob.forget();
215 : }
216 :
217 : NS_IMETHODIMP
218 0 : Blob::GetSendInfo(nsIInputStream** aBody,
219 : uint64_t* aContentLength,
220 : nsACString& aContentType,
221 : nsACString& aCharset)
222 : {
223 0 : return mImpl->GetSendInfo(aBody, aContentLength, aContentType, aCharset);
224 : }
225 :
226 : NS_IMETHODIMP
227 0 : Blob::GetMutable(bool* aMutable)
228 : {
229 0 : return mImpl->GetMutable(aMutable);
230 : }
231 :
232 : NS_IMETHODIMP
233 0 : Blob::SetMutable(bool aMutable)
234 : {
235 0 : return mImpl->SetMutable(aMutable);
236 : }
237 :
238 : JSObject*
239 0 : Blob::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
240 : {
241 0 : return BlobBinding::Wrap(aCx, this, aGivenProto);
242 : }
243 :
244 : /* static */ already_AddRefed<Blob>
245 0 : Blob::Constructor(const GlobalObject& aGlobal,
246 : const Optional<Sequence<BlobPart>>& aData,
247 : const BlobPropertyBag& aBag,
248 : ErrorResult& aRv)
249 : {
250 0 : RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl();
251 :
252 0 : if (aData.WasPassed()) {
253 0 : nsAutoString type(aBag.mType);
254 0 : MakeValidBlobType(type);
255 0 : impl->InitializeBlob(aData.Value(), type,
256 0 : aBag.mEndings == EndingTypes::Native, aRv);
257 : } else {
258 0 : impl->InitializeBlob(aRv);
259 : }
260 :
261 0 : if (NS_WARN_IF(aRv.Failed())) {
262 0 : return nullptr;
263 : }
264 :
265 0 : MOZ_ASSERT(!impl->IsFile());
266 :
267 0 : RefPtr<Blob> blob = Blob::Create(aGlobal.GetAsSupports(), impl);
268 0 : return blob.forget();
269 : }
270 :
271 : int64_t
272 0 : Blob::GetFileId()
273 : {
274 0 : return mImpl->GetFileId();
275 : }
276 :
277 : bool
278 0 : Blob::IsMemoryFile() const
279 : {
280 0 : return mImpl->IsMemoryFile();
281 : }
282 :
283 : void
284 0 : Blob::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
285 : {
286 0 : mImpl->GetInternalStream(aStream, aRv);
287 0 : }
288 :
289 : } // namespace dom
290 : } // namespace mozilla
|