Back to index

lightning-sunbird  0.9+nobinonly
nsStreamUtils.cpp
Go to the documentation of this file.
00001 /* vim:set ts=4 sw=4 sts=4 et cin: */
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.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Darin Fisher <darin@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsStreamUtils.h"
00040 #include "nsCOMPtr.h"
00041 #include "nsIPipe.h"
00042 #include "nsIEventTarget.h"
00043 #include "nsAutoLock.h"
00044 #include "nsString.h"
00045 
00046 //-----------------------------------------------------------------------------
00047 
00048 class nsInputStreamReadyEvent : public PLEvent
00049                               , public nsIInputStreamCallback
00050 {
00051 public:
00052     NS_DECL_ISUPPORTS
00053 
00054     nsInputStreamReadyEvent(nsIInputStreamCallback *callback,
00055                             nsIEventTarget *target)
00056         : mCallback(callback)
00057         , mTarget(target)
00058     {
00059     }
00060 
00061 private:
00062     ~nsInputStreamReadyEvent()
00063     {
00064         if (mCallback) {
00065             nsresult rv;
00066             //
00067             // whoa!!  looks like we never posted this event.  take care to
00068             // release mCallback on the correct thread.  if mTarget lives on the
00069             // calling thread, then we are ok.  otherwise, we have to try to 
00070             // proxy the Release over the right thread.  if that thread is dead,
00071             // then there's nothing we can do... better to leak than crash.
00072             //
00073             PRBool val;
00074             rv = mTarget->IsOnCurrentThread(&val);
00075             if (NS_FAILED(rv) || !val) {
00076                 nsCOMPtr<nsIInputStreamCallback> event;
00077                 NS_NewInputStreamReadyEvent(getter_AddRefs(event), mCallback, mTarget);
00078                 mCallback = 0;
00079                 if (event) {
00080                     rv = event->OnInputStreamReady(nsnull);
00081                     if (NS_FAILED(rv)) {
00082                         NS_NOTREACHED("leaking stream event");
00083                         nsISupports *sup = event;
00084                         NS_ADDREF(sup);
00085                     }
00086                 }
00087             }
00088         }
00089     }
00090 
00091 public:
00092     NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *stream)
00093     {
00094         mStream = stream;
00095 
00096         // will be released when event is handled
00097         NS_ADDREF_THIS();
00098 
00099         PL_InitEvent(this, nsnull, EventHandler, EventCleanup);
00100 
00101         if (NS_FAILED(mTarget->PostEvent(this))) {
00102             NS_WARNING("PostEvent failed");
00103             NS_RELEASE_THIS();
00104             return NS_ERROR_FAILURE;
00105         }
00106 
00107         return NS_OK;
00108     }
00109 
00110 private:
00111     nsCOMPtr<nsIAsyncInputStream>    mStream;
00112     nsCOMPtr<nsIInputStreamCallback> mCallback;
00113     nsCOMPtr<nsIEventTarget>         mTarget;
00114 
00115     PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *plevent)
00116     {
00117         nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent;
00118         // bypass event delivery if this is a cleanup event...
00119         if (ev->mCallback)
00120             ev->mCallback->OnInputStreamReady(ev->mStream);
00121         ev->mCallback = 0;
00122         return NULL;
00123     }
00124 
00125     PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *plevent)
00126     {
00127         nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent;
00128         NS_RELEASE(ev);
00129     }
00130 };
00131 
00132 NS_IMPL_THREADSAFE_ISUPPORTS1(nsInputStreamReadyEvent,
00133                               nsIInputStreamCallback)
00134 
00135 //-----------------------------------------------------------------------------
00136 
00137 class nsOutputStreamReadyEvent : public PLEvent
00138                                , public nsIOutputStreamCallback
00139 {
00140 public:
00141     NS_DECL_ISUPPORTS
00142 
00143     nsOutputStreamReadyEvent(nsIOutputStreamCallback *callback,
00144                              nsIEventTarget *target)
00145         : mCallback(callback)
00146         , mTarget(target)
00147     {
00148     }
00149 
00150 private:
00151     ~nsOutputStreamReadyEvent()
00152     {
00153         if (mCallback) {
00154             nsresult rv;
00155             //
00156             // whoa!!  looks like we never posted this event.  take care to
00157             // release mCallback on the correct thread.  if mTarget lives on the
00158             // calling thread, then we are ok.  otherwise, we have to try to 
00159             // proxy the Release over the right thread.  if that thread is dead,
00160             // then there's nothing we can do... better to leak than crash.
00161             //
00162             PRBool val;
00163             rv = mTarget->IsOnCurrentThread(&val);
00164             if (NS_FAILED(rv) || !val) {
00165                 nsCOMPtr<nsIOutputStreamCallback> event;
00166                 NS_NewOutputStreamReadyEvent(getter_AddRefs(event), mCallback, mTarget);
00167                 mCallback = 0;
00168                 if (event) {
00169                     rv = event->OnOutputStreamReady(nsnull);
00170                     if (NS_FAILED(rv)) {
00171                         NS_NOTREACHED("leaking stream event");
00172                         nsISupports *sup = event;
00173                         NS_ADDREF(sup);
00174                     }
00175                 }
00176             }
00177         }
00178     }
00179 
00180 public:
00181     void Init(nsIOutputStreamCallback *callback, nsIEventTarget *target)
00182     {
00183         mCallback = callback;
00184         mTarget = target;
00185 
00186         PL_InitEvent(this, nsnull, EventHandler, EventCleanup);
00187     }
00188 
00189     NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *stream)
00190     {
00191         mStream = stream;
00192 
00193         // this will be released when the event is handled
00194         NS_ADDREF_THIS();
00195 
00196         PL_InitEvent(this, nsnull, EventHandler, EventCleanup);
00197 
00198         if (NS_FAILED(mTarget->PostEvent(this))) {
00199             NS_WARNING("PostEvent failed");
00200             NS_RELEASE_THIS();
00201             return NS_ERROR_FAILURE;
00202         }
00203 
00204         return NS_OK;
00205     }
00206 
00207 private:
00208     nsCOMPtr<nsIAsyncOutputStream>    mStream;
00209     nsCOMPtr<nsIOutputStreamCallback> mCallback;
00210     nsCOMPtr<nsIEventTarget>          mTarget;
00211 
00212     PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *plevent)
00213     {
00214         nsOutputStreamReadyEvent *ev = (nsOutputStreamReadyEvent *) plevent;
00215         if (ev->mCallback)
00216             ev->mCallback->OnOutputStreamReady(ev->mStream);
00217         ev->mCallback = 0;
00218         return NULL;
00219     }
00220 
00221     PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *ev)
00222     {
00223         nsOutputStreamReadyEvent *event = (nsOutputStreamReadyEvent *) ev;
00224         NS_RELEASE(event);
00225     }
00226 };
00227 
00228 NS_IMPL_THREADSAFE_ISUPPORTS1(nsOutputStreamReadyEvent,
00229                               nsIOutputStreamCallback)
00230 
00231 //-----------------------------------------------------------------------------
00232 
00233 NS_COM nsresult
00234 NS_NewInputStreamReadyEvent(nsIInputStreamCallback **event,
00235                             nsIInputStreamCallback *callback,
00236                             nsIEventTarget *target)
00237 {
00238     nsInputStreamReadyEvent *ev = new nsInputStreamReadyEvent(callback, target);
00239     if (!ev)
00240         return NS_ERROR_OUT_OF_MEMORY;
00241     NS_ADDREF(*event = ev);
00242     return NS_OK;
00243 }
00244 
00245 NS_COM nsresult
00246 NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **event,
00247                              nsIOutputStreamCallback *callback,
00248                              nsIEventTarget *target)
00249 {
00250     nsOutputStreamReadyEvent *ev = new nsOutputStreamReadyEvent(callback, target);
00251     if (!ev)
00252         return NS_ERROR_OUT_OF_MEMORY;
00253     NS_ADDREF(*event = ev);
00254     return NS_OK;
00255 }
00256 
00257 //-----------------------------------------------------------------------------
00258 // NS_AsyncCopy implementation
00259 
00260 // abstract stream copier...
00261 class nsAStreamCopier : public nsIInputStreamCallback
00262                       , public nsIOutputStreamCallback
00263 {
00264 public:
00265     NS_DECL_ISUPPORTS
00266 
00267     nsAStreamCopier()
00268         : mLock(nsnull)
00269         , mCallback(nsnull)
00270         , mClosure(nsnull)
00271         , mChunkSize(0)
00272         , mEventInProcess(PR_FALSE)
00273         , mEventIsPending(PR_FALSE)
00274     {
00275     }
00276 
00277     // virtual since subclasses call superclass Release()
00278     virtual ~nsAStreamCopier()
00279     {
00280         if (mLock)
00281             PR_DestroyLock(mLock);
00282     }
00283 
00284     // kick off the async copy...
00285     nsresult Start(nsIInputStream *source,
00286                    nsIOutputStream *sink,
00287                    nsIEventTarget *target,
00288                    nsAsyncCopyCallbackFun callback,
00289                    void *closure,
00290                    PRUint32 chunksize)
00291     {
00292         mSource = source;
00293         mSink = sink;
00294         mTarget = target;
00295         mCallback = callback;
00296         mClosure = closure;
00297         mChunkSize = chunksize;
00298 
00299         mLock = PR_NewLock();
00300         if (!mLock)
00301             return NS_ERROR_OUT_OF_MEMORY;
00302 
00303         mAsyncSource = do_QueryInterface(mSource);
00304         mAsyncSink = do_QueryInterface(mSink);
00305 
00306         return PostContinuationEvent();
00307     }
00308 
00309     // implemented by subclasses, returns number of bytes copied and
00310     // sets source and sink condition before returning.
00311     virtual PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition) = 0;
00312 
00313     void Process()
00314     {
00315         if (!mSource || !mSink)
00316             return;
00317 
00318         nsresult sourceCondition, sinkCondition;
00319 
00320         // ok, copy data from source to sink.
00321         for (;;) {
00322             PRUint32 n = DoCopy(&sourceCondition, &sinkCondition);
00323             if (NS_FAILED(sourceCondition) || NS_FAILED(sinkCondition) || n == 0) {
00324                 if (sourceCondition == NS_BASE_STREAM_WOULD_BLOCK && mAsyncSource) {
00325                     // need to wait for more data from source.  while waiting for
00326                     // more source data, be sure to observe failures on output end.
00327                     mAsyncSource->AsyncWait(this, 0, 0, nsnull);
00328 
00329                     if (mAsyncSink)
00330                         mAsyncSink->AsyncWait(this,
00331                                               nsIAsyncOutputStream::WAIT_CLOSURE_ONLY,
00332                                               0, nsnull);
00333                 }
00334                 else if (sinkCondition == NS_BASE_STREAM_WOULD_BLOCK && mAsyncSink) {
00335                     // need to wait for more room in the sink.  while waiting for
00336                     // more room in the sink, be sure to observer failures on the
00337                     // input end.
00338                     mAsyncSink->AsyncWait(this, 0, 0, nsnull);
00339 
00340                     if (mAsyncSource)
00341                         mAsyncSource->AsyncWait(this,
00342                                                 nsIAsyncInputStream::WAIT_CLOSURE_ONLY,
00343                                                 0, nsnull);
00344                 }
00345                 else {
00346                     // close source
00347                     if (mAsyncSource)
00348                         mAsyncSource->CloseWithStatus(sinkCondition);
00349                     else
00350                         mSource->Close();
00351                     mAsyncSource = nsnull;
00352                     mSource = nsnull;
00353 
00354                     // close sink
00355                     if (mAsyncSink)
00356                         mAsyncSink->CloseWithStatus(sourceCondition);
00357                     else
00358                         mSink->Close();
00359                     mAsyncSink = nsnull;
00360                     mSink = nsnull;
00361 
00362                     // notify state complete...
00363                     if (mCallback) {
00364                         nsresult status = sourceCondition;
00365                         if (NS_SUCCEEDED(status))
00366                             status = sinkCondition;
00367                         if (status == NS_BASE_STREAM_CLOSED)
00368                             status = NS_OK;
00369                         mCallback(mClosure, status);
00370                     }
00371                 }
00372                 break;
00373             }
00374         }
00375     }
00376 
00377     NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *source)
00378     {
00379         PostContinuationEvent();
00380         return NS_OK;
00381     }
00382 
00383     NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *sink)
00384     {
00385         PostContinuationEvent();
00386         return NS_OK;
00387     }
00388 
00389     PR_STATIC_CALLBACK(void*) HandleContinuationEvent(PLEvent *event)
00390     {
00391         nsAStreamCopier *self = (nsAStreamCopier *) event->owner;
00392         self->Process();
00393 
00394         // clear "in process" flag and post any pending continuation event
00395         nsAutoLock lock(self->mLock);
00396         self->mEventInProcess = PR_FALSE;
00397         if (self->mEventIsPending) {
00398             self->mEventIsPending = PR_FALSE;
00399             self->PostContinuationEvent_Locked();
00400         }
00401         return nsnull;
00402     }
00403 
00404     PR_STATIC_CALLBACK(void) DestroyContinuationEvent(PLEvent *event)
00405     {
00406         nsAStreamCopier *self = (nsAStreamCopier *) event->owner;
00407         NS_RELEASE(self);
00408         delete event;
00409     }
00410 
00411     nsresult PostContinuationEvent()
00412     {
00413         // we cannot post a continuation event if there is currently
00414         // an event in process.  doing so could result in Process being
00415         // run simultaneously on multiple threads, so we mark the event
00416         // as pending, and if an event is already in process then we 
00417         // just let that existing event take care of posting the real
00418         // continuation event.
00419 
00420         nsAutoLock lock(mLock);
00421         return PostContinuationEvent_Locked();
00422     }
00423 
00424     nsresult PostContinuationEvent_Locked()
00425     {
00426         nsresult rv = NS_OK;
00427         if (mEventInProcess)
00428             mEventIsPending = PR_TRUE;
00429         else {
00430             PLEvent *event = new PLEvent;
00431             if (!event)
00432                 rv = NS_ERROR_OUT_OF_MEMORY;
00433             else {
00434                 NS_ADDREF_THIS();
00435                 PL_InitEvent(event, this,
00436                              HandleContinuationEvent,
00437                              DestroyContinuationEvent);
00438 
00439                 rv = mTarget->PostEvent(event);
00440                 if (NS_SUCCEEDED(rv))
00441                     mEventInProcess = PR_TRUE;
00442                 else {
00443                     NS_ERROR("unable to post continuation event");
00444                     PL_DestroyEvent(event);
00445                 }
00446             }
00447         }
00448         return rv;
00449     }
00450 
00451 protected:
00452     nsCOMPtr<nsIInputStream>       mSource;
00453     nsCOMPtr<nsIOutputStream>      mSink;
00454     nsCOMPtr<nsIAsyncInputStream>  mAsyncSource;
00455     nsCOMPtr<nsIAsyncOutputStream> mAsyncSink;
00456     nsCOMPtr<nsIEventTarget>       mTarget;
00457     PRLock                        *mLock;
00458     nsAsyncCopyCallbackFun         mCallback;
00459     void                          *mClosure;
00460     PRUint32                       mChunkSize;
00461     PRPackedBool                   mEventInProcess;
00462     PRPackedBool                   mEventIsPending;
00463 };
00464 
00465 NS_IMPL_THREADSAFE_ISUPPORTS2(nsAStreamCopier,
00466                               nsIInputStreamCallback,
00467                               nsIOutputStreamCallback)
00468 
00469 class nsStreamCopierIB : public nsAStreamCopier
00470 {
00471 public:
00472     nsStreamCopierIB() : nsAStreamCopier() {}
00473     virtual ~nsStreamCopierIB() {}
00474 
00475     struct ReadSegmentsState {
00476         nsIOutputStream *mSink;
00477         nsresult         mSinkCondition;
00478     };
00479 
00480     static NS_METHOD ConsumeInputBuffer(nsIInputStream *inStr,
00481                                         void *closure,
00482                                         const char *buffer,
00483                                         PRUint32 offset,
00484                                         PRUint32 count,
00485                                         PRUint32 *countWritten)
00486     {
00487         ReadSegmentsState *state = (ReadSegmentsState *) closure;
00488 
00489         nsresult rv = state->mSink->Write(buffer, count, countWritten);
00490         if (NS_FAILED(rv))
00491             state->mSinkCondition = rv;
00492         else if (*countWritten == 0)
00493             state->mSinkCondition = NS_BASE_STREAM_CLOSED;
00494 
00495         return state->mSinkCondition;
00496     }
00497 
00498     PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition)
00499     {
00500         ReadSegmentsState state;
00501         state.mSink = mSink;
00502         state.mSinkCondition = NS_OK;
00503 
00504         PRUint32 n;
00505         *sourceCondition =
00506             mSource->ReadSegments(ConsumeInputBuffer, &state, mChunkSize, &n);
00507         *sinkCondition = state.mSinkCondition;
00508         return n;
00509     }
00510 };
00511 
00512 class nsStreamCopierOB : public nsAStreamCopier
00513 {
00514 public:
00515     nsStreamCopierOB() : nsAStreamCopier() {}
00516     virtual ~nsStreamCopierOB() {}
00517 
00518     struct WriteSegmentsState {
00519         nsIInputStream *mSource;
00520         nsresult        mSourceCondition;
00521     };
00522 
00523     static NS_METHOD FillOutputBuffer(nsIOutputStream *outStr,
00524                                       void *closure,
00525                                       char *buffer,
00526                                       PRUint32 offset,
00527                                       PRUint32 count,
00528                                       PRUint32 *countRead)
00529     {
00530         WriteSegmentsState *state = (WriteSegmentsState *) closure;
00531 
00532         nsresult rv = state->mSource->Read(buffer, count, countRead);
00533         if (NS_FAILED(rv))
00534             state->mSourceCondition = rv;
00535         else if (*countRead == 0)
00536             state->mSourceCondition = NS_BASE_STREAM_CLOSED;
00537 
00538         return state->mSourceCondition;
00539     }
00540 
00541     PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition)
00542     {
00543         WriteSegmentsState state;
00544         state.mSource = mSource;
00545         state.mSourceCondition = NS_OK;
00546 
00547         PRUint32 n;
00548         *sinkCondition =
00549             mSink->WriteSegments(FillOutputBuffer, &state, mChunkSize, &n);
00550         *sourceCondition = state.mSourceCondition;
00551         return n;
00552     }
00553 };
00554 
00555 //-----------------------------------------------------------------------------
00556 
00557 NS_COM nsresult
00558 NS_AsyncCopy(nsIInputStream         *source,
00559              nsIOutputStream        *sink,
00560              nsIEventTarget         *target,
00561              nsAsyncCopyMode         mode,
00562              PRUint32                chunkSize,
00563              nsAsyncCopyCallbackFun  callback,
00564              void                   *closure)
00565 {
00566     NS_ASSERTION(target, "non-null target required");
00567 
00568     nsresult rv;
00569     nsAStreamCopier *copier;
00570 
00571     if (mode == NS_ASYNCCOPY_VIA_READSEGMENTS)
00572         copier = new nsStreamCopierIB();
00573     else
00574         copier = new nsStreamCopierOB();
00575 
00576     if (!copier)
00577         return NS_ERROR_OUT_OF_MEMORY;
00578 
00579     // Start() takes an owning ref to the copier...
00580     NS_ADDREF(copier);
00581     rv = copier->Start(source, sink, target, callback, closure, chunkSize);
00582     NS_RELEASE(copier);
00583 
00584     return rv;
00585 }
00586 
00587 //-----------------------------------------------------------------------------
00588 
00589 NS_COM nsresult
00590 NS_ConsumeStream(nsIInputStream *stream, PRUint32 maxCount, nsACString &result)
00591 {
00592     nsresult rv = NS_OK;
00593     result.Truncate();
00594 
00595     while (maxCount) {
00596         PRUint32 avail;
00597         rv = stream->Available(&avail);
00598         if (NS_FAILED(rv)) {
00599             if (rv == NS_BASE_STREAM_CLOSED)
00600                 rv = NS_OK;
00601             break;
00602         }
00603         if (avail == 0)
00604             break;
00605         if (avail > maxCount)
00606             avail = maxCount;
00607 
00608         // resize result buffer
00609         PRUint32 length = result.Length();
00610         result.SetLength(length + avail);
00611         if (result.Length() != (length + avail))
00612             return NS_ERROR_OUT_OF_MEMORY;
00613         char *buf = result.BeginWriting() + length;
00614         
00615         PRUint32 n;
00616         rv = stream->Read(buf, avail, &n);
00617         if (NS_FAILED(rv))
00618             break;
00619         if (n != avail)
00620             result.SetLength(length + n);
00621         if (n == 0)
00622             break;
00623         maxCount -= n;
00624     }
00625 
00626     return rv;
00627 }
00628 
00629 //-----------------------------------------------------------------------------
00630 
00631 static NS_METHOD
00632 TestInputStream(nsIInputStream *inStr,
00633                 void *closure,
00634                 const char *buffer,
00635                 PRUint32 offset,
00636                 PRUint32 count,
00637                 PRUint32 *countWritten)
00638 {
00639     PRBool *result = NS_STATIC_CAST(PRBool *, closure);
00640     *result = PR_TRUE;
00641     return NS_ERROR_ABORT;  // don't call me anymore
00642 }
00643 
00644 NS_COM PRBool
00645 NS_InputStreamIsBuffered(nsIInputStream *stream)
00646 {
00647     PRBool result = PR_FALSE;
00648     PRUint32 n;
00649     stream->ReadSegments(TestInputStream, &result, 1, &n);
00650     return result;
00651 }
00652 
00653 static NS_METHOD
00654 TestOutputStream(nsIOutputStream *outStr,
00655                  void *closure,
00656                  char *buffer,
00657                  PRUint32 offset,
00658                  PRUint32 count,
00659                  PRUint32 *countRead)
00660 {
00661     PRBool *result = NS_STATIC_CAST(PRBool *, closure);
00662     *result = PR_TRUE;
00663     return NS_ERROR_ABORT;  // don't call me anymore
00664 }
00665 
00666 NS_COM PRBool
00667 NS_OutputStreamIsBuffered(nsIOutputStream *stream)
00668 {
00669     PRBool result = PR_FALSE;
00670     PRUint32 n;
00671     stream->WriteSegments(TestOutputStream, &result, 1, &n);
00672     return result;
00673 }
00674 
00675 //-----------------------------------------------------------------------------
00676 
00677 NS_COM NS_METHOD
00678 NS_CopySegmentToStream(nsIInputStream *inStr,
00679                        void *closure,
00680                        const char *buffer,
00681                        PRUint32 offset,
00682                        PRUint32 count,
00683                        PRUint32 *countWritten)
00684 {
00685     nsIOutputStream *outStr = NS_STATIC_CAST(nsIOutputStream *, closure);
00686     *countWritten = 0;
00687     while (count) {
00688         PRUint32 n;
00689         nsresult rv = outStr->Write(buffer, count, &n);
00690         if (NS_FAILED(rv))
00691             return rv;
00692         buffer += n;
00693         count -= n;
00694         *countWritten += n;
00695     }
00696     return NS_OK;
00697 }
00698 
00699 NS_COM NS_METHOD
00700 NS_CopySegmentToBuffer(nsIInputStream *inStr,
00701                        void *closure,
00702                        const char *buffer,
00703                        PRUint32 offset,
00704                        PRUint32 count,
00705                        PRUint32 *countWritten)
00706 {
00707     char *toBuf = NS_STATIC_CAST(char *, closure);
00708     memcpy(&toBuf[offset], buffer, count);
00709     *countWritten = count;
00710     return NS_OK;
00711 }
00712 
00713 NS_COM NS_METHOD
00714 NS_DiscardSegment(nsIInputStream *inStr,
00715                   void *closure,
00716                   const char *buffer,
00717                   PRUint32 offset,
00718                   PRUint32 count,
00719                   PRUint32 *countWritten)
00720 {
00721     *countWritten = count;
00722     return NS_OK;
00723 }
00724 
00725 //-----------------------------------------------------------------------------
00726 
00727 NS_COM NS_METHOD
00728 NS_WriteSegmentThunk(nsIInputStream *inStr,
00729                      void *closure,
00730                      const char *buffer,
00731                      PRUint32 offset,
00732                      PRUint32 count,
00733                      PRUint32 *countWritten)
00734 {
00735     nsWriteSegmentThunk *thunk = NS_STATIC_CAST(nsWriteSegmentThunk *, closure);
00736     return thunk->mFun(thunk->mStream, thunk->mClosure, buffer, offset, count,
00737                        countWritten);
00738 }