Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / xpcom / io / nsStringStream.cpp
blobb3e83a58ba253c38871afd6a4b5b385463bd08e2
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/. */
7 /**
8 * Based on original code from nsIStringStream.cpp
9 */
11 #include "ipc/IPCMessageUtils.h"
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 "nsIClassInfoImpl.h"
22 #include "mozilla/Attributes.h"
23 #include "mozilla/ipc/InputStreamUtils.h"
24 #include "mozilla/Maybe.h"
25 #include "mozilla/ReentrantMonitor.h"
26 #include "mozilla/StreamBufferSourceImpl.h"
27 #include "nsIIPCSerializableInputStream.h"
28 #include "XPCOMModule.h"
30 using namespace mozilla::ipc;
31 using mozilla::fallible;
32 using mozilla::MakeRefPtr;
33 using mozilla::MallocSizeOf;
34 using mozilla::nsBorrowedSource;
35 using mozilla::nsCStringSource;
36 using mozilla::nsTArraySource;
37 using mozilla::ReentrantMonitorAutoEnter;
38 using mozilla::Span;
39 using mozilla::StreamBufferSource;
41 //-----------------------------------------------------------------------------
42 // nsIStringInputStream implementation
43 //-----------------------------------------------------------------------------
45 class nsStringInputStream final : public nsIStringInputStream,
46 public nsISeekableStream,
47 public nsISupportsCString,
48 public nsIIPCSerializableInputStream,
49 public nsICloneableInputStream {
50 public:
51 NS_DECL_THREADSAFE_ISUPPORTS
52 NS_DECL_NSIINPUTSTREAM
53 NS_DECL_NSISTRINGINPUTSTREAM
54 NS_DECL_NSISEEKABLESTREAM
55 NS_DECL_NSITELLABLESTREAM
56 NS_DECL_NSISUPPORTSPRIMITIVE
57 NS_DECL_NSISUPPORTSCSTRING
58 NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
59 NS_DECL_NSICLONEABLEINPUTSTREAM
61 nsStringInputStream() = default;
63 nsresult Init(nsCString&& aString);
65 nsresult Init(nsTArray<uint8_t>&& aArray);
67 private:
68 ~nsStringInputStream() = default;
70 size_t Length() const MOZ_REQUIRES(mMon) {
71 return mSource ? mSource->Data().Length() : 0;
74 size_t LengthRemaining() const MOZ_REQUIRES(mMon) {
75 return Length() - mOffset;
78 void Clear() MOZ_REQUIRES(mMon) { mSource = nullptr; }
80 bool Closed() MOZ_REQUIRES(mMon) { return !mSource; }
82 RefPtr<StreamBufferSource> mSource MOZ_GUARDED_BY(mMon);
83 size_t mOffset MOZ_GUARDED_BY(mMon) = 0;
85 mutable mozilla::ReentrantMonitor mMon{"nsStringInputStream"};
88 nsresult nsStringInputStream::Init(nsCString&& aString) {
89 nsCString string;
90 if (!string.Assign(std::move(aString), fallible)) {
91 return NS_ERROR_OUT_OF_MEMORY;
93 auto source = MakeRefPtr<nsCStringSource>(std::move(string));
94 return SetDataSource(source);
97 nsresult nsStringInputStream::Init(nsTArray<uint8_t>&& aArray) {
98 auto source = MakeRefPtr<nsTArraySource>(std::move(aArray));
99 return SetDataSource(source);
102 // This class needs to support threadsafe refcounting since people often
103 // allocate a string stream, and then read it from a background thread.
104 NS_IMPL_ADDREF(nsStringInputStream)
105 NS_IMPL_RELEASE(nsStringInputStream)
107 NS_IMPL_CLASSINFO(nsStringInputStream, nullptr, nsIClassInfo::THREADSAFE,
108 NS_STRINGINPUTSTREAM_CID)
109 NS_IMPL_QUERY_INTERFACE_CI(nsStringInputStream, nsIStringInputStream,
110 nsIInputStream, nsISupportsCString,
111 nsISeekableStream, nsITellableStream,
112 nsIIPCSerializableInputStream,
113 nsICloneableInputStream)
114 NS_IMPL_CI_INTERFACE_GETTER(nsStringInputStream, nsIStringInputStream,
115 nsIInputStream, nsISupportsCString,
116 nsISeekableStream, nsITellableStream,
117 nsICloneableInputStream)
119 /////////
120 // nsISupportsCString implementation
121 /////////
123 NS_IMETHODIMP
124 nsStringInputStream::GetType(uint16_t* aType) {
125 *aType = TYPE_CSTRING;
126 return NS_OK;
129 NS_IMETHODIMP
130 nsStringInputStream::GetData(nsACString& data) {
131 ReentrantMonitorAutoEnter lock(mMon);
133 // The stream doesn't have any data when it is closed. We could fake it
134 // and return an empty string here, but it seems better to keep this return
135 // value consistent with the behavior of the other 'getter' methods.
136 if (NS_WARN_IF(Closed())) {
137 return NS_BASE_STREAM_CLOSED;
140 return mSource->GetData(data);
143 NS_IMETHODIMP
144 nsStringInputStream::SetData(const nsACString& aData) {
145 nsCString string;
146 if (!string.Assign(aData, fallible)) {
147 return NS_ERROR_OUT_OF_MEMORY;
149 auto source = MakeRefPtr<nsCStringSource>(std::move(string));
150 return SetDataSource(source);
153 NS_IMETHODIMP
154 nsStringInputStream::ToString(char** aResult) {
155 // NOTE: This method may result in data loss, so we do not implement it.
156 return NS_ERROR_NOT_IMPLEMENTED;
159 /////////
160 // nsIStringInputStream implementation
161 /////////
163 NS_IMETHODIMP
164 nsStringInputStream::SetData(const char* aData, int32_t aDataLen) {
165 if (NS_WARN_IF(!aData)) {
166 return NS_ERROR_INVALID_ARG;
169 nsCString string;
170 if (NS_WARN_IF(!string.Assign(aData, aDataLen, fallible))) {
171 return NS_ERROR_OUT_OF_MEMORY;
173 auto source = MakeRefPtr<nsCStringSource>(std::move(string));
174 return SetDataSource(source);
177 NS_IMETHODIMP
178 nsStringInputStream::SetUTF8Data(const nsACString& aData) {
179 return nsStringInputStream::SetData(aData);
182 NS_IMETHODIMP
183 nsStringInputStream::AdoptData(char* aData, int32_t aDataLen) {
184 if (NS_WARN_IF(!aData)) {
185 return NS_ERROR_INVALID_ARG;
188 nsCString string;
189 string.Adopt(aData, aDataLen);
190 auto source = MakeRefPtr<nsCStringSource>(std::move(string));
191 return SetDataSource(source);
194 NS_IMETHODIMP
195 nsStringInputStream::ShareData(const char* aData, int32_t aDataLen) {
196 if (NS_WARN_IF(!aData)) {
197 return NS_ERROR_INVALID_ARG;
200 size_t length = aDataLen < 0 ? strlen(aData) : size_t(aDataLen);
201 auto source = MakeRefPtr<nsBorrowedSource>(Span{aData, length});
202 return SetDataSource(source);
205 NS_IMETHODIMP
206 nsStringInputStream::SetDataSource(StreamBufferSource* aSource) {
207 ReentrantMonitorAutoEnter lock(mMon);
209 if (NS_WARN_IF(!aSource)) {
210 return NS_ERROR_INVALID_ARG;
213 mSource = aSource;
214 mOffset = 0;
215 return NS_OK;
218 NS_IMETHODIMP_(size_t)
219 nsStringInputStream::SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) {
220 ReentrantMonitorAutoEnter lock(mMon);
222 size_t n = aMallocSizeOf(this);
223 if (mSource) {
224 n += mSource->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
226 return n;
229 NS_IMETHODIMP_(size_t)
230 nsStringInputStream::SizeOfIncludingThisEvenIfShared(
231 MallocSizeOf aMallocSizeOf) {
232 ReentrantMonitorAutoEnter lock(mMon);
234 size_t n = aMallocSizeOf(this);
235 if (mSource) {
236 n += mSource->SizeOfIncludingThisEvenIfShared(aMallocSizeOf);
238 return n;
241 /////////
242 // nsIInputStream implementation
243 /////////
245 NS_IMETHODIMP
246 nsStringInputStream::Close() {
247 ReentrantMonitorAutoEnter lock(mMon);
249 Clear();
250 return NS_OK;
253 NS_IMETHODIMP
254 nsStringInputStream::Available(uint64_t* aLength) {
255 ReentrantMonitorAutoEnter lock(mMon);
257 NS_ASSERTION(aLength, "null ptr");
259 if (Closed()) {
260 return NS_BASE_STREAM_CLOSED;
263 *aLength = LengthRemaining();
264 return NS_OK;
267 NS_IMETHODIMP
268 nsStringInputStream::StreamStatus() {
269 ReentrantMonitorAutoEnter lock(mMon);
270 return Closed() ? NS_BASE_STREAM_CLOSED : NS_OK;
273 NS_IMETHODIMP
274 nsStringInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aReadCount) {
275 NS_ASSERTION(aBuf, "null ptr");
276 return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
279 NS_IMETHODIMP
280 nsStringInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
281 uint32_t aCount, uint32_t* aResult) {
282 ReentrantMonitorAutoEnter lock(mMon);
284 NS_ASSERTION(aResult, "null ptr");
285 NS_ASSERTION(Length() >= mOffset, "bad stream state");
287 if (Closed()) {
288 return NS_BASE_STREAM_CLOSED;
291 // We may be at end-of-file
292 size_t maxCount = LengthRemaining();
293 if (maxCount == 0) {
294 *aResult = 0;
295 return NS_OK;
298 if (aCount > maxCount) {
299 aCount = maxCount;
302 RefPtr<StreamBufferSource> source = mSource;
303 size_t offset = mOffset;
305 nsresult rv = aWriter(this, aClosure, source->Data().Elements() + offset, 0,
306 aCount, aResult);
308 if (Closed()) {
309 NS_WARNING("nsStringInputStream was closed during ReadSegments");
310 return NS_OK;
313 MOZ_RELEASE_ASSERT(mSource == source, "String was replaced!");
314 MOZ_RELEASE_ASSERT(mOffset == offset, "Nested read operation!");
316 if (NS_SUCCEEDED(rv)) {
317 NS_ASSERTION(*aResult <= aCount,
318 "writer should not write more than we asked it to write");
319 mOffset = offset + *aResult;
322 // errors returned from the writer end here!
323 return NS_OK;
326 NS_IMETHODIMP
327 nsStringInputStream::IsNonBlocking(bool* aNonBlocking) {
328 *aNonBlocking = true;
329 return NS_OK;
332 /////////
333 // nsISeekableStream implementation
334 /////////
336 NS_IMETHODIMP
337 nsStringInputStream::Seek(int32_t aWhence, int64_t aOffset) {
338 ReentrantMonitorAutoEnter lock(mMon);
340 if (Closed()) {
341 return NS_BASE_STREAM_CLOSED;
344 // Compute new stream position. The given offset may be a negative value.
346 int64_t newPos = aOffset;
347 switch (aWhence) {
348 case NS_SEEK_SET:
349 break;
350 case NS_SEEK_CUR:
351 newPos += (int64_t)mOffset;
352 break;
353 case NS_SEEK_END:
354 newPos += (int64_t)Length();
355 break;
356 default:
357 NS_ERROR("invalid aWhence");
358 return NS_ERROR_INVALID_ARG;
361 if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > (int64_t)Length())) {
362 return NS_ERROR_INVALID_ARG;
365 mOffset = (size_t)newPos;
366 return NS_OK;
369 NS_IMETHODIMP
370 nsStringInputStream::SetEOF() {
371 ReentrantMonitorAutoEnter lock(mMon);
373 if (Closed()) {
374 return NS_BASE_STREAM_CLOSED;
377 mOffset = Length();
378 return NS_OK;
381 /////////
382 // nsITellableStream implementation
383 /////////
385 NS_IMETHODIMP
386 nsStringInputStream::Tell(int64_t* aOutWhere) {
387 ReentrantMonitorAutoEnter lock(mMon);
389 if (Closed()) {
390 return NS_BASE_STREAM_CLOSED;
393 *aOutWhere = (int64_t)mOffset;
394 return NS_OK;
397 /////////
398 // nsIIPCSerializableInputStream implementation
399 /////////
401 void nsStringInputStream::SerializedComplexity(uint32_t aMaxSize,
402 uint32_t* aSizeUsed,
403 uint32_t* aPipes,
404 uint32_t* aTransferables) {
405 ReentrantMonitorAutoEnter lock(mMon);
407 if (Length() >= aMaxSize) {
408 *aPipes = 1;
409 } else {
410 *aSizeUsed = Length();
414 void nsStringInputStream::Serialize(InputStreamParams& aParams,
415 uint32_t aMaxSize, uint32_t* aSizeUsed) {
416 ReentrantMonitorAutoEnter lock(mMon);
418 MOZ_DIAGNOSTIC_ASSERT(!Closed(), "cannot send a closed stream!");
419 MOZ_ASSERT(aSizeUsed);
420 *aSizeUsed = 0;
422 if (Length() >= aMaxSize) {
423 // If the input stream is non-owning (i.e. it was initialized with
424 // `ShareData`), create a new owning source so that it doesn't go away while
425 // async copying.
426 if (!mSource->Owning()) {
427 auto source =
428 MakeRefPtr<nsCStringSource>(nsDependentCSubstring(mSource->Data()));
429 mSource = source;
432 InputStreamHelper::SerializeInputStreamAsPipe(this, aParams);
433 return;
436 *aSizeUsed = Length();
438 StringInputStreamParams params;
439 mSource->GetData(params.data());
440 aParams = params;
443 bool nsStringInputStream::Deserialize(const InputStreamParams& aParams) {
444 if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
445 NS_ERROR("Received unknown parameters from the other process!");
446 return false;
449 const StringInputStreamParams& params = aParams.get_StringInputStreamParams();
451 if (NS_FAILED(SetData(params.data()))) {
452 NS_WARNING("SetData failed!");
453 return false;
456 return true;
459 /////////
460 // nsICloneableInputStream implementation
461 /////////
463 NS_IMETHODIMP
464 nsStringInputStream::GetCloneable(bool* aCloneableOut) {
465 *aCloneableOut = true;
466 return NS_OK;
469 NS_IMETHODIMP
470 nsStringInputStream::Clone(nsIInputStream** aCloneOut) {
471 ReentrantMonitorAutoEnter lock(mMon);
473 RefPtr<nsStringInputStream> ref = new nsStringInputStream();
474 // Nothing else can access this yet, but suppress static analysis warnings
475 ReentrantMonitorAutoEnter reflock(ref->mMon);
476 if (mSource && !mSource->Owning()) {
477 auto data = mSource->Data();
478 nsresult rv = ref->SetData(data.Elements(), data.Length());
479 if (NS_WARN_IF(NS_FAILED(rv))) {
480 return rv;
482 } else {
483 ref->mSource = mSource;
486 // mOffset is overwritten by SetData().
487 ref->mOffset = mOffset;
489 ref.forget(aCloneOut);
490 return NS_OK;
493 nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
494 mozilla::Span<const char> aStringToRead,
495 nsAssignmentType aAssignment) {
496 MOZ_ASSERT(aStreamResult, "null out ptr");
498 RefPtr<nsStringInputStream> stream = new nsStringInputStream();
500 nsresult rv;
501 switch (aAssignment) {
502 case NS_ASSIGNMENT_COPY:
503 rv = stream->SetData(aStringToRead.Elements(), aStringToRead.Length());
504 break;
505 case NS_ASSIGNMENT_DEPEND:
506 rv = stream->ShareData(aStringToRead.Elements(), aStringToRead.Length());
507 break;
508 case NS_ASSIGNMENT_ADOPT:
509 rv = stream->AdoptData(const_cast<char*>(aStringToRead.Elements()),
510 aStringToRead.Length());
511 break;
512 default:
513 NS_ERROR("invalid assignment type");
514 rv = NS_ERROR_INVALID_ARG;
517 if (NS_FAILED(rv)) {
518 return rv;
521 stream.forget(aStreamResult);
522 return NS_OK;
525 nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
526 nsTArray<uint8_t>&& aArray) {
527 MOZ_ASSERT(aStreamResult, "null out ptr");
529 RefPtr<nsStringInputStream> stream = new nsStringInputStream();
531 nsresult rv = stream->Init(std::move(aArray));
532 if (NS_WARN_IF(NS_FAILED(rv))) {
533 return rv;
536 stream.forget(aStreamResult);
537 return NS_OK;
540 extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
541 mozilla::StreamBufferSource* aSource) {
542 MOZ_ASSERT(aStreamResult, "null out ptr");
544 RefPtr<nsStringInputStream> stream = new nsStringInputStream();
546 nsresult rv = stream->SetDataSource(aSource);
547 if (NS_WARN_IF(NS_FAILED(rv))) {
548 return rv;
551 stream.forget(aStreamResult);
552 return NS_OK;
555 nsresult NS_NewCStringInputStream(nsIInputStream** aStreamResult,
556 const nsACString& aStringToRead) {
557 MOZ_ASSERT(aStreamResult, "null out ptr");
559 RefPtr<nsStringInputStream> stream = new nsStringInputStream();
561 nsresult rv = stream->SetData(aStringToRead);
562 if (NS_WARN_IF(NS_FAILED(rv))) {
563 return rv;
566 stream.forget(aStreamResult);
567 return NS_OK;
570 nsresult NS_NewCStringInputStream(nsIInputStream** aStreamResult,
571 nsCString&& aStringToRead) {
572 MOZ_ASSERT(aStreamResult, "null out ptr");
574 RefPtr<nsStringInputStream> stream = new nsStringInputStream();
576 nsresult rv = stream->Init(std::move(aStringToRead));
577 if (NS_WARN_IF(NS_FAILED(rv))) {
578 return rv;
581 stream.forget(aStreamResult);
582 return NS_OK;
585 // factory method for constructing a nsStringInputStream object
586 nsresult nsStringInputStreamConstructor(REFNSIID aIID, void** aResult) {
587 *aResult = nullptr;
589 RefPtr<nsStringInputStream> inst = new nsStringInputStream();
590 return inst->QueryInterface(aIID, aResult);