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/. */
8 * Based on original code from nsIStringStream.cpp
11 #include "ipc/IPCMessageUtils.h"
13 #include "nsStringStream.h"
14 #include "nsStreamUtils.h"
15 #include "nsReadableUtils.h"
16 #include "nsISeekableStream.h"
17 #include "nsISupportsPrimitives.h"
21 #include "nsIClassInfoImpl.h"
22 #include "mozilla/Attributes.h"
23 #include "mozilla/ipc/InputStreamUtils.h"
24 #include "nsIIPCSerializableInputStream.h"
26 using namespace mozilla::ipc
;
28 //-----------------------------------------------------------------------------
29 // nsIStringInputStream implementation
30 //-----------------------------------------------------------------------------
32 class nsStringInputStream MOZ_FINAL
33 : public nsIStringInputStream
34 , public nsISeekableStream
35 , public nsISupportsCString
36 , public nsIIPCSerializableInputStream
39 NS_DECL_THREADSAFE_ISUPPORTS
40 NS_DECL_NSIINPUTSTREAM
41 NS_DECL_NSISTRINGINPUTSTREAM
42 NS_DECL_NSISEEKABLESTREAM
43 NS_DECL_NSISUPPORTSPRIMITIVE
44 NS_DECL_NSISUPPORTSCSTRING
45 NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
53 ~nsStringInputStream()
57 uint32_t Length() const
59 return mData
.Length();
62 uint32_t LengthRemaining() const
64 return Length() - mOffset
;
69 mData
.SetIsVoid(true);
74 return mData
.IsVoid();
77 nsDependentCSubstring mData
;
81 // This class needs to support threadsafe refcounting since people often
82 // allocate a string stream, and then read it from a background thread.
83 NS_IMPL_ADDREF(nsStringInputStream
)
84 NS_IMPL_RELEASE(nsStringInputStream
)
86 NS_IMPL_CLASSINFO(nsStringInputStream
, nullptr, nsIClassInfo::THREADSAFE
,
87 NS_STRINGINPUTSTREAM_CID
)
88 NS_IMPL_QUERY_INTERFACE_CI(nsStringInputStream
,
93 nsIIPCSerializableInputStream
)
94 NS_IMPL_CI_INTERFACE_GETTER(nsStringInputStream
,
101 // nsISupportsCString implementation
105 nsStringInputStream::GetType(uint16_t* aType
)
107 *aType
= TYPE_CSTRING
;
112 nsStringInputStream::GetData(nsACString
& data
)
114 // The stream doesn't have any data when it is closed. We could fake it
115 // and return an empty string here, but it seems better to keep this return
116 // value consistent with the behavior of the other 'getter' methods.
117 if (NS_WARN_IF(Closed())) {
118 return NS_BASE_STREAM_CLOSED
;
126 nsStringInputStream::SetData(const nsACString
& aData
)
134 nsStringInputStream::ToString(char** aResult
)
136 // NOTE: This method may result in data loss, so we do not implement it.
137 return NS_ERROR_NOT_IMPLEMENTED
;
141 // nsIStringInputStream implementation
145 nsStringInputStream::SetData(const char* aData
, int32_t aDataLen
)
147 if (NS_WARN_IF(!aData
)) {
148 return NS_ERROR_INVALID_ARG
;
150 mData
.Assign(aData
, aDataLen
);
156 nsStringInputStream::AdoptData(char* aData
, int32_t aDataLen
)
158 if (NS_WARN_IF(!aData
)) {
159 return NS_ERROR_INVALID_ARG
;
161 mData
.Adopt(aData
, aDataLen
);
167 nsStringInputStream::ShareData(const char* aData
, int32_t aDataLen
)
169 if (NS_WARN_IF(!aData
)) {
170 return NS_ERROR_INVALID_ARG
;
174 aDataLen
= strlen(aData
);
177 mData
.Rebind(aData
, aDataLen
);
183 // nsIInputStream implementation
187 nsStringInputStream::Close()
194 nsStringInputStream::Available(uint64_t* aLength
)
196 NS_ASSERTION(aLength
, "null ptr");
199 return NS_BASE_STREAM_CLOSED
;
202 *aLength
= LengthRemaining();
207 nsStringInputStream::Read(char* aBuf
, uint32_t aCount
, uint32_t* aReadCount
)
209 NS_ASSERTION(aBuf
, "null ptr");
210 return ReadSegments(NS_CopySegmentToBuffer
, aBuf
, aCount
, aReadCount
);
214 nsStringInputStream::ReadSegments(nsWriteSegmentFun aWriter
, void* aClosure
,
215 uint32_t aCount
, uint32_t* aResult
)
217 NS_ASSERTION(aResult
, "null ptr");
218 NS_ASSERTION(Length() >= mOffset
, "bad stream state");
221 return NS_BASE_STREAM_CLOSED
;
224 // We may be at end-of-file
225 uint32_t maxCount
= LengthRemaining();
231 if (aCount
> maxCount
) {
234 nsresult rv
= aWriter(this, aClosure
, mData
.BeginReading() + mOffset
, 0,
236 if (NS_SUCCEEDED(rv
)) {
237 NS_ASSERTION(*aResult
<= aCount
,
238 "writer should not write more than we asked it to write");
242 // errors returned from the writer end here!
247 nsStringInputStream::IsNonBlocking(bool* aNonBlocking
)
249 *aNonBlocking
= true;
254 // nsISeekableStream implementation
258 nsStringInputStream::Seek(int32_t aWhence
, int64_t aOffset
)
261 return NS_BASE_STREAM_CLOSED
;
264 // Compute new stream position. The given offset may be a negative value.
266 int64_t newPos
= aOffset
;
277 NS_ERROR("invalid aWhence");
278 return NS_ERROR_INVALID_ARG
;
281 if (NS_WARN_IF(newPos
< 0) || NS_WARN_IF(newPos
> Length())) {
282 return NS_ERROR_INVALID_ARG
;
285 mOffset
= (uint32_t)newPos
;
290 nsStringInputStream::Tell(int64_t* aOutWhere
)
293 return NS_BASE_STREAM_CLOSED
;
296 *aOutWhere
= mOffset
;
301 nsStringInputStream::SetEOF()
304 return NS_BASE_STREAM_CLOSED
;
312 nsStringInputStream::Serialize(InputStreamParams
& aParams
,
313 FileDescriptorArray
& /* aFDs */)
315 StringInputStreamParams params
;
316 params
.data() = PromiseFlatCString(mData
);
321 nsStringInputStream::Deserialize(const InputStreamParams
& aParams
,
322 const FileDescriptorArray
& /* aFDs */)
324 if (aParams
.type() != InputStreamParams::TStringInputStreamParams
) {
325 NS_ERROR("Received unknown parameters from the other process!");
329 const StringInputStreamParams
& params
=
330 aParams
.get_StringInputStreamParams();
332 if (NS_FAILED(SetData(params
.data()))) {
333 NS_WARNING("SetData failed!");
341 NS_NewByteInputStream(nsIInputStream
** aStreamResult
,
342 const char* aStringToRead
, int32_t aLength
,
343 nsAssignmentType aAssignment
)
345 NS_PRECONDITION(aStreamResult
, "null out ptr");
347 nsStringInputStream
* stream
= new nsStringInputStream();
349 return NS_ERROR_OUT_OF_MEMORY
;
355 switch (aAssignment
) {
356 case NS_ASSIGNMENT_COPY
:
357 rv
= stream
->SetData(aStringToRead
, aLength
);
359 case NS_ASSIGNMENT_DEPEND
:
360 rv
= stream
->ShareData(aStringToRead
, aLength
);
362 case NS_ASSIGNMENT_ADOPT
:
363 rv
= stream
->AdoptData(const_cast<char*>(aStringToRead
), aLength
);
366 NS_ERROR("invalid assignment type");
367 rv
= NS_ERROR_INVALID_ARG
;
375 *aStreamResult
= stream
;
380 NS_NewStringInputStream(nsIInputStream
** aStreamResult
,
381 const nsAString
& aStringToRead
)
383 NS_LossyConvertUTF16toASCII
data(aStringToRead
); // truncates high-order bytes
384 return NS_NewCStringInputStream(aStreamResult
, data
);
388 NS_NewCStringInputStream(nsIInputStream
** aStreamResult
,
389 const nsACString
& aStringToRead
)
391 NS_PRECONDITION(aStreamResult
, "null out ptr");
393 nsStringInputStream
* stream
= new nsStringInputStream();
395 return NS_ERROR_OUT_OF_MEMORY
;
400 stream
->SetData(aStringToRead
);
402 *aStreamResult
= stream
;
406 // factory method for constructing a nsStringInputStream object
408 nsStringInputStreamConstructor(nsISupports
* aOuter
, REFNSIID aIID
,
413 if (NS_WARN_IF(aOuter
)) {
414 return NS_ERROR_NO_AGGREGATION
;
417 nsStringInputStream
* inst
= new nsStringInputStream();
419 return NS_ERROR_OUT_OF_MEMORY
;
423 nsresult rv
= inst
->QueryInterface(aIID
, aResult
);