1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sts=4 sw=4 cin et: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * mcmullen@netscape.com (original author)
28 * david.gardiner@unisa.edu.au
31 * pinkerton@netscape.com
33 * sfraser@netscape.com
37 * Alternatively, the contents of this file may be used under the terms of
38 * either of the GNU General Public License Version 2 or later (the "GPL"),
39 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
40 * in which case the provisions of the GPL or the LGPL are applicable instead
41 * of those above. If you wish to allow use of your version of this file only
42 * under the terms of either the GPL or the LGPL, and not to allow others to
43 * use your version of this file under the terms of the MPL, indicate your
44 * decision by deleting the provisions above and replace them with the notice
45 * and other provisions required by the GPL or the LGPL. If you do not delete
46 * the provisions above, a recipient may use your version of this file under
47 * the terms of any one of the MPL, the GPL or the LGPL.
49 * ***** END LICENSE BLOCK ***** */
52 * Based on original code from nsIStringStream.cpp
55 #include "nsStringStream.h"
56 #include "nsStreamUtils.h"
57 #include "nsReadableUtils.h"
58 #include "nsISeekableStream.h"
59 #include "nsISupportsPrimitives.h"
64 #include "nsIClassInfoImpl.h"
66 //-----------------------------------------------------------------------------
67 // nsIStringInputStream implementation
68 //-----------------------------------------------------------------------------
70 class nsStringInputStream
: public nsIStringInputStream
71 , public nsISeekableStream
72 , public nsISupportsCString
76 NS_DECL_NSIINPUTSTREAM
77 NS_DECL_NSISTRINGINPUTSTREAM
78 NS_DECL_NSISEEKABLESTREAM
79 NS_DECL_NSISUPPORTSPRIMITIVE
80 NS_DECL_NSISUPPORTSCSTRING
90 ~nsStringInputStream()
96 PRInt32
LengthRemaining() const
98 return mLength
- mOffset
;
103 NS_ASSERTION(mData
|| !mOwned
, "bad state");
105 NS_Free(const_cast<char*>(mData
));
107 // We're about to get a new string; reset the offset.
117 // This class needs to support threadsafe refcounting since people often
118 // allocate a string stream, and then read it from a background thread.
119 NS_IMPL_THREADSAFE_ADDREF(nsStringInputStream
)
120 NS_IMPL_THREADSAFE_RELEASE(nsStringInputStream
)
122 NS_IMPL_QUERY_INTERFACE4_CI(nsStringInputStream
,
123 nsIStringInputStream
,
127 NS_IMPL_CI_INTERFACE_GETTER4(nsStringInputStream
,
128 nsIStringInputStream
,
134 // nsISupportsCString implementation
138 nsStringInputStream::GetType(PRUint16
*type
)
140 *type
= TYPE_CSTRING
;
145 nsStringInputStream::GetData(nsACString
&data
)
147 // The stream doesn't have any data when it is closed. We could fake it
148 // and return an empty string here, but it seems better to keep this return
149 // value consistent with the behavior of the other 'getter' methods.
150 NS_ENSURE_TRUE(mData
, NS_BASE_STREAM_CLOSED
);
152 data
.Assign(mData
, mLength
);
157 nsStringInputStream::SetData(const nsACString
&data
)
159 nsACString::const_iterator iter
;
160 data
.BeginReading(iter
);
161 return SetData(iter
.get(), iter
.size_forward());
165 nsStringInputStream::ToString(char **result
)
167 // NOTE: This method may result in data loss, so we do not implement it.
168 return NS_ERROR_NOT_IMPLEMENTED
;
172 // nsIStringInputStream implementation
176 nsStringInputStream::SetData(const char *data
, PRInt32 dataLen
)
178 NS_ENSURE_ARG_POINTER(data
);
181 dataLen
= strlen(data
);
183 // NOTE: We do not use nsCRT::strndup here because that does not handle
184 // null bytes in the middle of the given data.
186 char *copy
= static_cast<char *>(NS_Alloc(dataLen
));
188 return NS_ERROR_OUT_OF_MEMORY
;
189 memcpy(copy
, data
, dataLen
);
191 return AdoptData(copy
, dataLen
);
195 nsStringInputStream::AdoptData(char *data
, PRInt32 dataLen
)
197 NS_ENSURE_ARG_POINTER(data
);
200 dataLen
= strlen(data
);
211 nsStringInputStream::ShareData(const char *data
, PRInt32 dataLen
)
213 NS_ENSURE_ARG_POINTER(data
);
216 dataLen
= strlen(data
);
227 // nsIInputStream implementation
231 nsStringInputStream::Close()
241 nsStringInputStream::Available(PRUint32
*aLength
)
243 NS_ASSERTION(aLength
, "null ptr");
246 return NS_BASE_STREAM_CLOSED
;
248 *aLength
= LengthRemaining();
253 nsStringInputStream::Read(char* aBuf
, PRUint32 aCount
, PRUint32
*aReadCount
)
255 NS_ASSERTION(aBuf
, "null ptr");
256 return ReadSegments(NS_CopySegmentToBuffer
, aBuf
, aCount
, aReadCount
);
260 nsStringInputStream::ReadSegments(nsWriteSegmentFun writer
, void *closure
,
261 PRUint32 aCount
, PRUint32
*result
)
263 NS_ASSERTION(result
, "null ptr");
264 NS_ASSERTION(mLength
>= mOffset
, "bad stream state");
266 // We may be at end-of-file
267 PRUint32 maxCount
= LengthRemaining();
272 NS_ASSERTION(mData
, "must have data if maxCount != 0");
274 if (aCount
> maxCount
)
276 nsresult rv
= writer(this, closure
, mData
+ mOffset
, 0, aCount
, result
);
277 if (NS_SUCCEEDED(rv
)) {
278 NS_ASSERTION(*result
<= aCount
,
279 "writer should not write more than we asked it to write");
283 // errors returned from the writer end here!
288 nsStringInputStream::IsNonBlocking(PRBool
*aNonBlocking
)
290 *aNonBlocking
= PR_TRUE
;
295 // nsISeekableStream implementation
299 nsStringInputStream::Seek(PRInt32 whence
, PRInt64 offset
)
302 return NS_BASE_STREAM_CLOSED
;
304 // Compute new stream position. The given offset may be a negative value.
306 PRInt64 newPos
= offset
;
311 newPos
+= (PRInt32
) mOffset
;
314 newPos
+= (PRInt32
) mLength
;
317 NS_ERROR("invalid whence");
318 return NS_ERROR_INVALID_ARG
;
321 // mLength is never larger than PR_INT32_MAX due to the way it is assigned.
323 NS_ENSURE_ARG(newPos
>= 0);
324 NS_ENSURE_ARG(newPos
<= (PRInt32
) mLength
);
326 mOffset
= (PRInt32
) newPos
;
331 nsStringInputStream::Tell(PRInt64
* outWhere
)
334 return NS_BASE_STREAM_CLOSED
;
341 nsStringInputStream::SetEOF()
344 return NS_BASE_STREAM_CLOSED
;
351 NS_NewByteInputStream(nsIInputStream
** aStreamResult
,
352 const char* aStringToRead
, PRInt32 aLength
,
353 nsAssignmentType aAssignment
)
355 NS_PRECONDITION(aStreamResult
, "null out ptr");
357 nsStringInputStream
* stream
= new nsStringInputStream();
359 return NS_ERROR_OUT_OF_MEMORY
;
364 switch (aAssignment
) {
365 case NS_ASSIGNMENT_COPY
:
366 rv
= stream
->SetData(aStringToRead
, aLength
);
368 case NS_ASSIGNMENT_DEPEND
:
369 rv
= stream
->ShareData(aStringToRead
, aLength
);
371 case NS_ASSIGNMENT_ADOPT
:
372 rv
= stream
->AdoptData(const_cast<char*>(aStringToRead
), aLength
);
375 NS_ERROR("invalid assignment type");
376 rv
= NS_ERROR_INVALID_ARG
;
384 *aStreamResult
= stream
;
389 NS_NewStringInputStream(nsIInputStream
** aStreamResult
,
390 const nsAString
& aStringToRead
)
392 char* data
= ToNewCString(aStringToRead
); // truncates high-order bytes
394 return NS_ERROR_OUT_OF_MEMORY
;
396 nsresult rv
= NS_NewByteInputStream(aStreamResult
, data
,
397 aStringToRead
.Length(),
398 NS_ASSIGNMENT_ADOPT
);
405 NS_NewCStringInputStream(nsIInputStream
** aStreamResult
,
406 const nsACString
& aStringToRead
)
408 nsACString::const_iterator data
;
409 aStringToRead
.BeginReading(data
);
411 return NS_NewByteInputStream(aStreamResult
, data
.get(), data
.size_forward(),
415 // factory method for constructing a nsStringInputStream object
417 nsStringInputStreamConstructor(nsISupports
*outer
, REFNSIID iid
, void **result
)
421 NS_ENSURE_TRUE(!outer
, NS_ERROR_NO_AGGREGATION
);
423 nsStringInputStream
*inst
= new nsStringInputStream();
425 return NS_ERROR_OUT_OF_MEMORY
;
428 nsresult rv
= inst
->QueryInterface(iid
, result
);