Bumping manifests a=b2g-bump
[gecko.git] / xpcom / io / nsStringStream.cpp
blob0075cb4d52bcd9adbd38cd835844131e29ca3d5b
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 "nsISeekableStream.h"
17 #include "nsISupportsPrimitives.h"
18 #include "nsCRT.h"
19 #include "prerror.h"
20 #include "plstr.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
38 public:
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
47 nsStringInputStream()
49 Clear();
52 private:
53 ~nsStringInputStream()
57 uint32_t Length() const
59 return mData.Length();
62 uint32_t LengthRemaining() const
64 return Length() - mOffset;
67 void Clear()
69 mData.SetIsVoid(true);
72 bool Closed()
74 return mData.IsVoid();
77 nsDependentCSubstring mData;
78 uint32_t mOffset;
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,
89 nsIStringInputStream,
90 nsIInputStream,
91 nsISupportsCString,
92 nsISeekableStream,
93 nsIIPCSerializableInputStream)
94 NS_IMPL_CI_INTERFACE_GETTER(nsStringInputStream,
95 nsIStringInputStream,
96 nsIInputStream,
97 nsISupportsCString,
98 nsISeekableStream)
100 /////////
101 // nsISupportsCString implementation
102 /////////
104 NS_IMETHODIMP
105 nsStringInputStream::GetType(uint16_t* aType)
107 *aType = TYPE_CSTRING;
108 return NS_OK;
111 NS_IMETHODIMP
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;
121 data.Assign(mData);
122 return NS_OK;
125 NS_IMETHODIMP
126 nsStringInputStream::SetData(const nsACString& aData)
128 mData.Assign(aData);
129 mOffset = 0;
130 return NS_OK;
133 NS_IMETHODIMP
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;
140 /////////
141 // nsIStringInputStream implementation
142 /////////
144 NS_IMETHODIMP
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);
151 mOffset = 0;
152 return NS_OK;
155 NS_IMETHODIMP
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);
162 mOffset = 0;
163 return NS_OK;
166 NS_IMETHODIMP
167 nsStringInputStream::ShareData(const char* aData, int32_t aDataLen)
169 if (NS_WARN_IF(!aData)) {
170 return NS_ERROR_INVALID_ARG;
173 if (aDataLen < 0) {
174 aDataLen = strlen(aData);
177 mData.Rebind(aData, aDataLen);
178 mOffset = 0;
179 return NS_OK;
182 /////////
183 // nsIInputStream implementation
184 /////////
186 NS_IMETHODIMP
187 nsStringInputStream::Close()
189 Clear();
190 return NS_OK;
193 NS_IMETHODIMP
194 nsStringInputStream::Available(uint64_t* aLength)
196 NS_ASSERTION(aLength, "null ptr");
198 if (Closed()) {
199 return NS_BASE_STREAM_CLOSED;
202 *aLength = LengthRemaining();
203 return NS_OK;
206 NS_IMETHODIMP
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);
213 NS_IMETHODIMP
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");
220 if (Closed()) {
221 return NS_BASE_STREAM_CLOSED;
224 // We may be at end-of-file
225 uint32_t maxCount = LengthRemaining();
226 if (maxCount == 0) {
227 *aResult = 0;
228 return NS_OK;
231 if (aCount > maxCount) {
232 aCount = maxCount;
234 nsresult rv = aWriter(this, aClosure, mData.BeginReading() + mOffset, 0,
235 aCount, aResult);
236 if (NS_SUCCEEDED(rv)) {
237 NS_ASSERTION(*aResult <= aCount,
238 "writer should not write more than we asked it to write");
239 mOffset += *aResult;
242 // errors returned from the writer end here!
243 return NS_OK;
246 NS_IMETHODIMP
247 nsStringInputStream::IsNonBlocking(bool* aNonBlocking)
249 *aNonBlocking = true;
250 return NS_OK;
253 /////////
254 // nsISeekableStream implementation
255 /////////
257 NS_IMETHODIMP
258 nsStringInputStream::Seek(int32_t aWhence, int64_t aOffset)
260 if (Closed()) {
261 return NS_BASE_STREAM_CLOSED;
264 // Compute new stream position. The given offset may be a negative value.
266 int64_t newPos = aOffset;
267 switch (aWhence) {
268 case NS_SEEK_SET:
269 break;
270 case NS_SEEK_CUR:
271 newPos += mOffset;
272 break;
273 case NS_SEEK_END:
274 newPos += Length();
275 break;
276 default:
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;
286 return NS_OK;
289 NS_IMETHODIMP
290 nsStringInputStream::Tell(int64_t* aOutWhere)
292 if (Closed()) {
293 return NS_BASE_STREAM_CLOSED;
296 *aOutWhere = mOffset;
297 return NS_OK;
300 NS_IMETHODIMP
301 nsStringInputStream::SetEOF()
303 if (Closed()) {
304 return NS_BASE_STREAM_CLOSED;
307 mOffset = Length();
308 return NS_OK;
311 void
312 nsStringInputStream::Serialize(InputStreamParams& aParams,
313 FileDescriptorArray& /* aFDs */)
315 StringInputStreamParams params;
316 params.data() = PromiseFlatCString(mData);
317 aParams = params;
320 bool
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!");
326 return false;
329 const StringInputStreamParams& params =
330 aParams.get_StringInputStreamParams();
332 if (NS_FAILED(SetData(params.data()))) {
333 NS_WARNING("SetData failed!");
334 return false;
337 return true;
340 nsresult
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();
348 if (!stream) {
349 return NS_ERROR_OUT_OF_MEMORY;
352 NS_ADDREF(stream);
354 nsresult rv;
355 switch (aAssignment) {
356 case NS_ASSIGNMENT_COPY:
357 rv = stream->SetData(aStringToRead, aLength);
358 break;
359 case NS_ASSIGNMENT_DEPEND:
360 rv = stream->ShareData(aStringToRead, aLength);
361 break;
362 case NS_ASSIGNMENT_ADOPT:
363 rv = stream->AdoptData(const_cast<char*>(aStringToRead), aLength);
364 break;
365 default:
366 NS_ERROR("invalid assignment type");
367 rv = NS_ERROR_INVALID_ARG;
370 if (NS_FAILED(rv)) {
371 NS_RELEASE(stream);
372 return rv;
375 *aStreamResult = stream;
376 return NS_OK;
379 nsresult
380 NS_NewStringInputStream(nsIInputStream** aStreamResult,
381 const nsAString& aStringToRead)
383 NS_LossyConvertUTF16toASCII data(aStringToRead); // truncates high-order bytes
384 return NS_NewCStringInputStream(aStreamResult, data);
387 nsresult
388 NS_NewCStringInputStream(nsIInputStream** aStreamResult,
389 const nsACString& aStringToRead)
391 NS_PRECONDITION(aStreamResult, "null out ptr");
393 nsStringInputStream* stream = new nsStringInputStream();
394 if (!stream) {
395 return NS_ERROR_OUT_OF_MEMORY;
398 NS_ADDREF(stream);
400 stream->SetData(aStringToRead);
402 *aStreamResult = stream;
403 return NS_OK;
406 // factory method for constructing a nsStringInputStream object
407 nsresult
408 nsStringInputStreamConstructor(nsISupports* aOuter, REFNSIID aIID,
409 void** aResult)
411 *aResult = nullptr;
413 if (NS_WARN_IF(aOuter)) {
414 return NS_ERROR_NO_AGGREGATION;
417 nsStringInputStream* inst = new nsStringInputStream();
418 if (!inst) {
419 return NS_ERROR_OUT_OF_MEMORY;
422 NS_ADDREF(inst);
423 nsresult rv = inst->QueryInterface(aIID, aResult);
424 NS_RELEASE(inst);
426 return rv;