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