Back to index

lightning-sunbird  0.9+nobinonly
nsStringStream.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   mcmullen@netscape.com (original author)
00024  *   warren@netscape.com
00025  *   alecf@netscape.com
00026  *   scc@mozilla.org
00027  *   david.gardiner@unisa.edu.au
00028  *   fur@netscape.com
00029  *   norris@netscape.com
00030  *   pinkerton@netscape.com
00031  *   davidm@netscape.com
00032  *   sfraser@netscape.com
00033  *   darin@netscape.com
00034  *   bzbarsky@mit.edu
00035  *
00036  * Alternatively, the contents of this file may be used under the terms of
00037  * either of the GNU General Public License Version 2 or later (the "GPL"),
00038  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00039  * in which case the provisions of the GPL or the LGPL are applicable instead
00040  * of those above. If you wish to allow use of your version of this file only
00041  * under the terms of either the GPL or the LGPL, and not to allow others to
00042  * use your version of this file under the terms of the MPL, indicate your
00043  * decision by deleting the provisions above and replace them with the notice
00044  * and other provisions required by the GPL or the LGPL. If you do not delete
00045  * the provisions above, a recipient may use your version of this file under
00046  * the terms of any one of the MPL, the GPL or the LGPL.
00047  *
00048  * ***** END LICENSE BLOCK ***** */
00049 
00054 #include "nsStringStream.h"
00055 
00056 #include "prerror.h"
00057 #include "plstr.h"
00058 #include "nsReadableUtils.h"
00059 #include "nsCRT.h"
00060 #include "nsISeekableStream.h"
00061 #include "nsInt64.h"
00062 
00063 #define NS_FILE_RESULT(x) ns_file_convert_result((PRInt32)x)
00064 #define NS_FILE_FAILURE NS_FILE_RESULT(-1)
00065 
00066 static nsresult ns_file_convert_result(PRInt32 nativeErr)
00067 {
00068     return nativeErr ?
00069         NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,((nativeErr)&0xFFFF))
00070         : NS_OK;
00071 }
00072  
00073 //-----------------------------------------------------------------------------
00074 // nsIStringInputStream implementation
00075 //-----------------------------------------------------------------------------
00076 
00077 class nsStringInputStream : public nsIStringInputStream
00078                           , public nsISeekableStream
00079                             
00080 {
00081 public:
00082     nsStringInputStream()
00083         : mOffset(0)
00084         , mLastResult(NS_OK)
00085         , mEOF(PR_FALSE)
00086         , mOwned(PR_FALSE)
00087         , mConstString(nsnull)
00088         , mLength(0)
00089     {}
00090     
00091 private:
00092     ~nsStringInputStream()
00093     {
00094         if (mOwned)
00095             nsMemory::Free((char*)mConstString);
00096     }
00097 
00098 public:
00099     NS_DECL_ISUPPORTS
00100     NS_DECL_NSISTRINGINPUTSTREAM
00101     NS_DECL_NSIINPUTSTREAM
00102     NS_DECL_NSISEEKABLESTREAM
00103 
00104 protected:
00105     PRInt32 LengthRemaining() const
00106     {
00107         return mLength - mOffset;
00108     }
00109 
00110     void Clear()
00111     {
00112         NS_ASSERTION(mConstString || !mOwned,
00113                      "Can't have mOwned set and have a null string!");
00114         if (mOwned)
00115             nsMemory::Free((char*)mConstString);
00116 
00117         // We're about to get a new string; clear the members that
00118         // would no longer have valid values.
00119         mOffset = 0;
00120         mLastResult = NS_OK;
00121         mEOF = PR_FALSE;
00122     }
00123 
00124     PRUint32                       mOffset;
00125     nsresult                       mLastResult;
00126     PRPackedBool                   mEOF;
00127     PRPackedBool                   mOwned;
00128     const char*                    mConstString;
00129     PRUint32                       mLength;
00130 };
00131 
00132 NS_IMPL_THREADSAFE_ISUPPORTS3(nsStringInputStream,
00133                               nsIStringInputStream,
00134                               nsIInputStream,
00135                               nsISeekableStream)
00136 
00137 
00138 // nsIStringInputStream implementation
00140 NS_IMETHODIMP
00141 nsStringInputStream::SetData(const char *data, PRInt32 dataLen)
00142 {
00143     NS_ENSURE_ARG_POINTER(data);
00144 
00145     if (dataLen < 0)
00146         dataLen = strlen(data);
00147 
00148     return AdoptData(nsCRT::strndup(data, dataLen), dataLen);
00149 }
00150 
00151 NS_IMETHODIMP
00152 nsStringInputStream::AdoptData(char *data, PRInt32 dataLen)
00153 {
00154     NS_ENSURE_ARG_POINTER(data);
00155 
00156     if (dataLen < 0)
00157         dataLen = strlen(data);
00158 
00159     Clear();
00160     
00161     mConstString = (const char *) data;
00162     mLength = dataLen;
00163     mOwned = PR_TRUE;
00164     return NS_OK;
00165 }
00166 
00167 NS_IMETHODIMP
00168 nsStringInputStream::ShareData(const char *data, PRInt32 dataLen)
00169 {
00170     NS_ENSURE_ARG_POINTER(data);
00171 
00172     if (dataLen < 0)
00173         dataLen = strlen(data);
00174 
00175     Clear();
00176     
00177     mConstString = data;
00178     mLength = dataLen;
00179     mOwned = PR_FALSE;
00180     return NS_OK;
00181 }
00182 
00184 // nsIInputStream implementation
00186 NS_IMETHODIMP nsStringInputStream::Close()
00187 {
00188     return NS_OK;
00189 }
00190     
00191 NS_IMETHODIMP nsStringInputStream::Available(PRUint32 *aLength)
00192 {
00193     NS_PRECONDITION(aLength != nsnull, "null ptr");
00194     if (!aLength)
00195         return NS_ERROR_NULL_POINTER;
00196     *aLength = LengthRemaining();
00197     return NS_OK;
00198 }
00199 
00200 NS_IMETHODIMP nsStringInputStream::Read(char* aBuf, PRUint32 aCount,
00201                                         PRUint32 *aReadCount)
00202 {
00203     NS_PRECONDITION(aBuf != nsnull, "null ptr");
00204     if (!aBuf)
00205         return NS_ERROR_NULL_POINTER;
00206     NS_PRECONDITION(aReadCount != nsnull, "null ptr");
00207     if (!aReadCount)
00208         return NS_ERROR_NULL_POINTER;
00209     if (NS_FAILED(mLastResult))
00210         return mLastResult;
00211 
00212     PRUint32 bytesRead;
00213     PRUint32 maxCount = mLength - mOffset;
00214     if (aCount > maxCount)
00215         bytesRead = maxCount;
00216     else
00217         bytesRead = aCount;
00218   
00219     memcpy(aBuf, mConstString + mOffset, bytesRead);
00220     mOffset += bytesRead;
00221 
00222     *aReadCount = bytesRead;
00223     return NS_OK;
00224 }
00225 
00226 
00227 NS_IMETHODIMP
00228 nsStringInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure,
00229                                   PRUint32 aCount, PRUint32 * result)
00230 {
00231     nsresult rv;
00232     PRUint32 maxCount = mLength - mOffset;
00233     if (maxCount == 0) {
00234         *result = 0;
00235         return NS_OK;
00236     }
00237     if (aCount > maxCount)
00238         aCount = maxCount;
00239     rv = writer(this, closure, mConstString + mOffset, 
00240                 0, aCount, result);
00241     if (NS_SUCCEEDED(rv)) {
00242         NS_ASSERTION(*result <= aCount, "writer should not write more than we asked it to write");
00243         mOffset += *result;
00244     }
00245     // errors returned from the writer end here!
00246     return NS_OK;
00247 }
00248     
00249 NS_IMETHODIMP
00250 nsStringInputStream::IsNonBlocking(PRBool *aNonBlocking)
00251 {
00252     *aNonBlocking = PR_TRUE;
00253     return NS_OK;
00254 }
00255 
00256 
00258 // nsISeekableStream implementation
00260 NS_IMETHODIMP 
00261 nsStringInputStream::Seek(PRInt32 whence, PRInt64 offset)
00262 {
00263     mLastResult = NS_OK; // reset on a seek.
00264     const nsInt64 maxUint32 = PR_UINT32_MAX;
00265     nsInt64 offset64(offset);
00266     PRInt32 offset32;
00267     LL_L2I(offset32, offset);
00268 
00269     NS_ASSERTION(maxUint32 > offset64, "string streams only support 32 bit offsets");
00270     mEOF = PR_FALSE; // reset on a seek.
00271     PRInt32 fileSize = LengthRemaining();
00272     PRInt32 newPosition=-1;
00273     switch (whence)
00274     {
00275         case NS_SEEK_CUR: newPosition = mOffset + offset32; break;
00276         case NS_SEEK_SET: newPosition = offset32; break;
00277         case NS_SEEK_END: newPosition = fileSize + offset32; break;
00278     }
00279     if (newPosition < 0)
00280     {
00281         newPosition = 0;
00282         mLastResult = NS_FILE_RESULT(PR_FILE_SEEK_ERROR);
00283     }
00284     if (newPosition >= fileSize)
00285     {
00286         newPosition = fileSize;
00287         mEOF = PR_TRUE;
00288     }
00289     mOffset = newPosition;
00290     return NS_OK;
00291 }
00292 
00293 
00294 NS_IMETHODIMP nsStringInputStream::Tell(PRInt64* outWhere)
00295 {
00296     *outWhere = mOffset;
00297     return NS_OK;
00298 }
00299 
00300 NS_IMETHODIMP nsStringInputStream::SetEOF()
00301 {
00302     NS_NOTYETIMPLEMENTED("nsStringInputStream::SetEOF");
00303     return NS_ERROR_NOT_IMPLEMENTED;
00304 }
00305 
00306 // Factory method to get an nsInputStream from an nsAString.  Result will
00307 // implement nsIStringInputStream and nsISeekableStream
00308 extern "C" NS_COM nsresult
00309 NS_NewStringInputStream(nsIInputStream** aStreamResult,
00310                         const nsAString& aStringToRead)
00311 {
00312     NS_PRECONDITION(aStreamResult, "null out ptr");
00313 
00314     char* data = ToNewCString(aStringToRead);
00315     if (!data)
00316         return NS_ERROR_OUT_OF_MEMORY;
00317 
00318     nsStringInputStream* stream = new nsStringInputStream();
00319     if (! stream) {
00320         nsMemory::Free(data);
00321         return NS_ERROR_OUT_OF_MEMORY;
00322     }
00323 
00324     NS_ADDREF(stream);
00325 
00326     nsresult rv = stream->AdoptData(data, aStringToRead.Length());
00327     if (NS_FAILED(rv)) {
00328         nsMemory::Free(data);
00329         NS_RELEASE(stream);
00330         return rv;
00331     }
00332     
00333     *aStreamResult = stream;
00334     return NS_OK;
00335 }
00336 
00337 // Factory method to get an nsInputStream from an nsACString.  Result will
00338 // implement nsIStringInputStream and nsISeekableStream
00339 extern "C" NS_COM nsresult
00340 NS_NewCStringInputStream(nsIInputStream** aStreamResult,
00341                          const nsACString& aStringToRead)
00342 {
00343     NS_PRECONDITION(aStreamResult, "null out ptr");
00344 
00345     char* data = ToNewCString(aStringToRead);
00346     if (!data)
00347         return NS_ERROR_OUT_OF_MEMORY;
00348 
00349     nsStringInputStream* stream = new nsStringInputStream();
00350     if (! stream) {
00351         nsMemory::Free(data);
00352         return NS_ERROR_OUT_OF_MEMORY;
00353     }
00354 
00355     NS_ADDREF(stream);
00356 
00357     nsresult rv = stream->AdoptData(data, aStringToRead.Length());
00358     if (NS_FAILED(rv)) {
00359         nsMemory::Free(data);
00360         NS_RELEASE(stream);
00361         return rv;
00362     }
00363     
00364     *aStreamResult = stream;
00365     return NS_OK;
00366 }
00367 
00368 // Factory method to get an nsInputStream from a C string.  Result will
00369 // implement nsIStringInputStream and nsISeekableStream
00370 extern "C" NS_COM nsresult
00371 NS_NewCharInputStream(nsIInputStream** aStreamResult,
00372                       const char* aStringToRead)
00373 {
00374     NS_PRECONDITION(aStreamResult, "null out ptr");
00375 
00376     nsStringInputStream* stream = new nsStringInputStream();
00377     if (! stream)
00378         return NS_ERROR_OUT_OF_MEMORY;
00379 
00380     NS_ADDREF(stream);
00381 
00382     nsresult rv = stream->ShareData(aStringToRead, -1);
00383     
00384     if (NS_FAILED(rv)) {
00385         NS_RELEASE(stream);
00386         return rv;
00387     }
00388     
00389     *aStreamResult = stream;
00390     return NS_OK;
00391 }
00392 
00393 // Factory method to get an nsInputStream from a byte array.  Result will
00394 // implement nsIStringInputStream and nsISeekableStream
00395 extern "C" NS_COM nsresult
00396 NS_NewByteInputStream(nsIInputStream** aStreamResult,
00397                       const char* aStringToRead,
00398                       PRInt32 aLength)
00399 {
00400     NS_PRECONDITION(aStreamResult, "null out ptr");
00401 
00402     nsStringInputStream* stream = new nsStringInputStream();
00403     if (! stream)
00404         return NS_ERROR_OUT_OF_MEMORY;
00405 
00406     NS_ADDREF(stream);
00407 
00408     nsresult rv = stream->ShareData(aStringToRead, aLength);
00409     
00410     if (NS_FAILED(rv)) {
00411         NS_RELEASE(stream);
00412         return rv;
00413     }
00414     
00415     *aStreamResult = stream;
00416     return NS_OK;
00417 }
00418 
00419 // factory method for constructing a nsStringInputStream object
00420 NS_METHOD
00421 nsStringInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result)
00422 {
00423     *result = nsnull;
00424 
00425     if (outer)
00426         return NS_ERROR_NO_AGGREGATION;
00427 
00428     nsStringInputStream *inst;
00429     NS_NEWXPCOM(inst, nsStringInputStream);
00430     if (!inst)
00431         return NS_ERROR_OUT_OF_MEMORY;
00432 
00433     NS_ADDREF(inst);
00434     nsresult rv = inst->QueryInterface(iid, result);
00435     NS_RELEASE(inst);
00436 
00437     return rv;
00438 }