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 : /**
8 : * Based on original code from nsIStringStream.cpp
9 : */
10 :
11 : #include "ipc/IPCMessageUtils.h"
12 :
13 : #include "nsStringStream.h"
14 : #include "nsStreamUtils.h"
15 : #include "nsReadableUtils.h"
16 : #include "nsICloneableInputStream.h"
17 : #include "nsISeekableStream.h"
18 : #include "nsISupportsPrimitives.h"
19 : #include "nsCRT.h"
20 : #include "prerror.h"
21 : #include "plstr.h"
22 : #include "nsIClassInfoImpl.h"
23 : #include "mozilla/Attributes.h"
24 : #include "mozilla/ipc/InputStreamUtils.h"
25 : #include "nsIIPCSerializableInputStream.h"
26 :
27 : using namespace mozilla::ipc;
28 : using mozilla::Maybe;
29 : using mozilla::Some;
30 :
31 : //-----------------------------------------------------------------------------
32 : // nsIStringInputStream implementation
33 : //-----------------------------------------------------------------------------
34 :
35 : class nsStringInputStream final
36 : : public nsIStringInputStream
37 : , public nsISeekableStream
38 : , public nsISupportsCString
39 : , public nsIIPCSerializableInputStream
40 : , public nsICloneableInputStream
41 : {
42 : public:
43 : NS_DECL_THREADSAFE_ISUPPORTS
44 : NS_DECL_NSIINPUTSTREAM
45 : NS_DECL_NSISTRINGINPUTSTREAM
46 : NS_DECL_NSISEEKABLESTREAM
47 : NS_DECL_NSISUPPORTSPRIMITIVE
48 : NS_DECL_NSISUPPORTSCSTRING
49 : NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
50 : NS_DECL_NSICLONEABLEINPUTSTREAM
51 :
52 87 : nsStringInputStream()
53 87 : {
54 87 : Clear();
55 87 : }
56 :
57 0 : explicit nsStringInputStream(const nsStringInputStream& aOther)
58 0 : : mOffset(aOther.mOffset)
59 : {
60 : // Use Assign() here because we don't want the life of the clone to be
61 : // dependent on the life of the original stream.
62 0 : mData.Assign(aOther.mData);
63 0 : }
64 :
65 : private:
66 86 : ~nsStringInputStream()
67 86 : {
68 86 : }
69 :
70 104029 : uint32_t Length() const
71 : {
72 104029 : return mData.Length();
73 : }
74 :
75 52017 : uint32_t LengthRemaining() const
76 : {
77 52017 : return Length() - mOffset;
78 : }
79 :
80 93 : void Clear()
81 : {
82 93 : mData.SetIsVoid(true);
83 93 : }
84 :
85 52017 : bool Closed()
86 : {
87 52017 : return mData.IsVoid();
88 : }
89 :
90 : nsDependentCSubstring mData;
91 : uint32_t mOffset;
92 : };
93 :
94 : // This class needs to support threadsafe refcounting since people often
95 : // allocate a string stream, and then read it from a background thread.
96 451 : NS_IMPL_ADDREF(nsStringInputStream)
97 536 : NS_IMPL_RELEASE(nsStringInputStream)
98 :
99 3 : NS_IMPL_CLASSINFO(nsStringInputStream, nullptr, nsIClassInfo::THREADSAFE,
100 : NS_STRINGINPUTSTREAM_CID)
101 358 : NS_IMPL_QUERY_INTERFACE_CI(nsStringInputStream,
102 : nsIStringInputStream,
103 : nsIInputStream,
104 : nsISupportsCString,
105 : nsISeekableStream,
106 : nsIIPCSerializableInputStream,
107 : nsICloneableInputStream)
108 0 : NS_IMPL_CI_INTERFACE_GETTER(nsStringInputStream,
109 : nsIStringInputStream,
110 : nsIInputStream,
111 : nsISupportsCString,
112 : nsISeekableStream,
113 : nsICloneableInputStream)
114 :
115 : /////////
116 : // nsISupportsCString implementation
117 : /////////
118 :
119 : NS_IMETHODIMP
120 0 : nsStringInputStream::GetType(uint16_t* aType)
121 : {
122 0 : *aType = TYPE_CSTRING;
123 0 : return NS_OK;
124 : }
125 :
126 : NS_IMETHODIMP
127 0 : nsStringInputStream::GetData(nsACString& data)
128 : {
129 : // The stream doesn't have any data when it is closed. We could fake it
130 : // and return an empty string here, but it seems better to keep this return
131 : // value consistent with the behavior of the other 'getter' methods.
132 0 : if (NS_WARN_IF(Closed())) {
133 0 : return NS_BASE_STREAM_CLOSED;
134 : }
135 :
136 0 : data.Assign(mData);
137 0 : return NS_OK;
138 : }
139 :
140 : NS_IMETHODIMP
141 6 : nsStringInputStream::SetData(const nsACString& aData)
142 : {
143 6 : mData.Assign(aData);
144 6 : mOffset = 0;
145 6 : return NS_OK;
146 : }
147 :
148 : NS_IMETHODIMP
149 0 : nsStringInputStream::ToString(char** aResult)
150 : {
151 : // NOTE: This method may result in data loss, so we do not implement it.
152 0 : return NS_ERROR_NOT_IMPLEMENTED;
153 : }
154 :
155 : /////////
156 : // nsIStringInputStream implementation
157 : /////////
158 :
159 : NS_IMETHODIMP
160 1 : nsStringInputStream::SetData(const char* aData, int32_t aDataLen)
161 : {
162 1 : if (NS_WARN_IF(!aData)) {
163 0 : return NS_ERROR_INVALID_ARG;
164 : }
165 1 : mData.Assign(aData, aDataLen);
166 1 : mOffset = 0;
167 1 : return NS_OK;
168 : }
169 :
170 : NS_IMETHODIMP
171 74 : nsStringInputStream::AdoptData(char* aData, int32_t aDataLen)
172 : {
173 74 : if (NS_WARN_IF(!aData)) {
174 0 : return NS_ERROR_INVALID_ARG;
175 : }
176 74 : mData.Adopt(aData, aDataLen);
177 74 : mOffset = 0;
178 74 : return NS_OK;
179 : }
180 :
181 : NS_IMETHODIMP
182 6 : nsStringInputStream::ShareData(const char* aData, int32_t aDataLen)
183 : {
184 6 : if (NS_WARN_IF(!aData)) {
185 0 : return NS_ERROR_INVALID_ARG;
186 : }
187 :
188 6 : if (aDataLen < 0) {
189 0 : aDataLen = strlen(aData);
190 : }
191 :
192 6 : mData.Rebind(aData, aDataLen);
193 6 : mOffset = 0;
194 6 : return NS_OK;
195 : }
196 :
197 : NS_IMETHODIMP_(size_t)
198 0 : nsStringInputStream::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
199 : {
200 0 : size_t n = aMallocSizeOf(this);
201 0 : n += mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
202 0 : return n;
203 : }
204 :
205 : /////////
206 : // nsIInputStream implementation
207 : /////////
208 :
209 : NS_IMETHODIMP
210 6 : nsStringInputStream::Close()
211 : {
212 6 : Clear();
213 6 : return NS_OK;
214 : }
215 :
216 : NS_IMETHODIMP
217 5 : nsStringInputStream::Available(uint64_t* aLength)
218 : {
219 5 : NS_ASSERTION(aLength, "null ptr");
220 :
221 5 : if (Closed()) {
222 0 : return NS_BASE_STREAM_CLOSED;
223 : }
224 :
225 5 : *aLength = LengthRemaining();
226 5 : return NS_OK;
227 : }
228 :
229 : NS_IMETHODIMP
230 39757 : nsStringInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aReadCount)
231 : {
232 39757 : NS_ASSERTION(aBuf, "null ptr");
233 39757 : return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
234 : }
235 :
236 : NS_IMETHODIMP
237 52012 : nsStringInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
238 : uint32_t aCount, uint32_t* aResult)
239 : {
240 52012 : NS_ASSERTION(aResult, "null ptr");
241 52012 : NS_ASSERTION(Length() >= mOffset, "bad stream state");
242 :
243 52012 : if (Closed()) {
244 0 : return NS_BASE_STREAM_CLOSED;
245 : }
246 :
247 : // We may be at end-of-file
248 52012 : uint32_t maxCount = LengthRemaining();
249 52012 : if (maxCount == 0) {
250 9 : *aResult = 0;
251 9 : return NS_OK;
252 : }
253 :
254 52003 : if (aCount > maxCount) {
255 4 : aCount = maxCount;
256 : }
257 52003 : nsresult rv = aWriter(this, aClosure, mData.BeginReading() + mOffset, 0,
258 52003 : aCount, aResult);
259 52003 : if (NS_SUCCEEDED(rv)) {
260 52003 : NS_ASSERTION(*aResult <= aCount,
261 : "writer should not write more than we asked it to write");
262 52003 : mOffset += *aResult;
263 : }
264 :
265 : // errors returned from the writer end here!
266 52003 : return NS_OK;
267 : }
268 :
269 : NS_IMETHODIMP
270 3 : nsStringInputStream::IsNonBlocking(bool* aNonBlocking)
271 : {
272 3 : *aNonBlocking = true;
273 3 : return NS_OK;
274 : }
275 :
276 : /////////
277 : // nsISeekableStream implementation
278 : /////////
279 :
280 : NS_IMETHODIMP
281 0 : nsStringInputStream::Seek(int32_t aWhence, int64_t aOffset)
282 : {
283 0 : if (Closed()) {
284 0 : return NS_BASE_STREAM_CLOSED;
285 : }
286 :
287 : // Compute new stream position. The given offset may be a negative value.
288 :
289 0 : int64_t newPos = aOffset;
290 0 : switch (aWhence) {
291 : case NS_SEEK_SET:
292 0 : break;
293 : case NS_SEEK_CUR:
294 0 : newPos += mOffset;
295 0 : break;
296 : case NS_SEEK_END:
297 0 : newPos += Length();
298 0 : break;
299 : default:
300 0 : NS_ERROR("invalid aWhence");
301 0 : return NS_ERROR_INVALID_ARG;
302 : }
303 :
304 0 : if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > Length())) {
305 0 : return NS_ERROR_INVALID_ARG;
306 : }
307 :
308 0 : mOffset = (uint32_t)newPos;
309 0 : return NS_OK;
310 : }
311 :
312 : NS_IMETHODIMP
313 0 : nsStringInputStream::Tell(int64_t* aOutWhere)
314 : {
315 0 : if (Closed()) {
316 0 : return NS_BASE_STREAM_CLOSED;
317 : }
318 :
319 0 : *aOutWhere = mOffset;
320 0 : return NS_OK;
321 : }
322 :
323 : NS_IMETHODIMP
324 0 : nsStringInputStream::SetEOF()
325 : {
326 0 : if (Closed()) {
327 0 : return NS_BASE_STREAM_CLOSED;
328 : }
329 :
330 0 : mOffset = Length();
331 0 : return NS_OK;
332 : }
333 :
334 : /////////
335 : // nsIIPCSerializableInputStream implementation
336 : /////////
337 :
338 : void
339 0 : nsStringInputStream::Serialize(InputStreamParams& aParams,
340 : FileDescriptorArray& /* aFDs */)
341 : {
342 0 : StringInputStreamParams params;
343 0 : params.data() = PromiseFlatCString(mData);
344 0 : aParams = params;
345 0 : }
346 :
347 : bool
348 0 : nsStringInputStream::Deserialize(const InputStreamParams& aParams,
349 : const FileDescriptorArray& /* aFDs */)
350 : {
351 0 : if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
352 0 : NS_ERROR("Received unknown parameters from the other process!");
353 0 : return false;
354 : }
355 :
356 : const StringInputStreamParams& params =
357 0 : aParams.get_StringInputStreamParams();
358 :
359 0 : if (NS_FAILED(SetData(params.data()))) {
360 0 : NS_WARNING("SetData failed!");
361 0 : return false;
362 : }
363 :
364 0 : return true;
365 : }
366 :
367 : Maybe<uint64_t>
368 0 : nsStringInputStream::ExpectedSerializedLength()
369 : {
370 0 : return Some(static_cast<uint64_t>(Length()));
371 : }
372 :
373 : /////////
374 : // nsICloneableInputStream implementation
375 : /////////
376 :
377 : NS_IMETHODIMP
378 0 : nsStringInputStream::GetCloneable(bool* aCloneableOut)
379 : {
380 0 : *aCloneableOut = true;
381 0 : return NS_OK;
382 : }
383 :
384 : NS_IMETHODIMP
385 0 : nsStringInputStream::Clone(nsIInputStream** aCloneOut)
386 : {
387 0 : RefPtr<nsIInputStream> ref = new nsStringInputStream(*this);
388 0 : ref.forget(aCloneOut);
389 0 : return NS_OK;
390 : }
391 :
392 : nsresult
393 6 : NS_NewByteInputStream(nsIInputStream** aStreamResult,
394 : const char* aStringToRead, int32_t aLength,
395 : nsAssignmentType aAssignment)
396 : {
397 6 : NS_PRECONDITION(aStreamResult, "null out ptr");
398 :
399 12 : RefPtr<nsStringInputStream> stream = new nsStringInputStream();
400 :
401 : nsresult rv;
402 6 : switch (aAssignment) {
403 : case NS_ASSIGNMENT_COPY:
404 0 : rv = stream->SetData(aStringToRead, aLength);
405 0 : break;
406 : case NS_ASSIGNMENT_DEPEND:
407 6 : rv = stream->ShareData(aStringToRead, aLength);
408 6 : break;
409 : case NS_ASSIGNMENT_ADOPT:
410 0 : rv = stream->AdoptData(const_cast<char*>(aStringToRead), aLength);
411 0 : break;
412 : default:
413 0 : NS_ERROR("invalid assignment type");
414 0 : rv = NS_ERROR_INVALID_ARG;
415 : }
416 :
417 6 : if (NS_FAILED(rv)) {
418 0 : return rv;
419 : }
420 :
421 6 : stream.forget(aStreamResult);
422 6 : return NS_OK;
423 : }
424 :
425 : nsresult
426 6 : NS_NewCStringInputStream(nsIInputStream** aStreamResult,
427 : const nsACString& aStringToRead)
428 : {
429 6 : NS_PRECONDITION(aStreamResult, "null out ptr");
430 :
431 12 : RefPtr<nsStringInputStream> stream = new nsStringInputStream();
432 :
433 6 : stream->SetData(aStringToRead);
434 :
435 6 : stream.forget(aStreamResult);
436 12 : return NS_OK;
437 : }
438 :
439 : // factory method for constructing a nsStringInputStream object
440 : nsresult
441 75 : nsStringInputStreamConstructor(nsISupports* aOuter, REFNSIID aIID,
442 : void** aResult)
443 : {
444 75 : *aResult = nullptr;
445 :
446 75 : if (NS_WARN_IF(aOuter)) {
447 0 : return NS_ERROR_NO_AGGREGATION;
448 : }
449 :
450 150 : RefPtr<nsStringInputStream> inst = new nsStringInputStream();
451 75 : return inst->QueryInterface(aIID, aResult);
452 : }
|