LCOV - code coverage report
Current view: directory - xpcom/io - nsStreamUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 308 264 85.7 %
Date: 2012-06-02 Functions: 51 49 96.1 %

       1                 : /* vim:set ts=4 sw=4 sts=4 et cin: */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2002
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Darin Fisher <darin@netscape.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "mozilla/Mutex.h"
      40                 : #include "nsStreamUtils.h"
      41                 : #include "nsCOMPtr.h"
      42                 : #include "nsIPipe.h"
      43                 : #include "nsIEventTarget.h"
      44                 : #include "nsIRunnable.h"
      45                 : #include "nsISafeOutputStream.h"
      46                 : #include "nsString.h"
      47                 : 
      48                 : using namespace mozilla;
      49                 : 
      50                 : //-----------------------------------------------------------------------------
      51                 : 
      52                 : class nsInputStreamReadyEvent : public nsIRunnable
      53                 :                               , public nsIInputStreamCallback
      54                 : {
      55                 : public:
      56                 :     NS_DECL_ISUPPORTS
      57                 : 
      58           19374 :     nsInputStreamReadyEvent(nsIInputStreamCallback *callback,
      59                 :                             nsIEventTarget *target)
      60                 :         : mCallback(callback)
      61           19374 :         , mTarget(target)
      62                 :     {
      63           19374 :     }
      64                 : 
      65                 : private:
      66           19374 :     ~nsInputStreamReadyEvent()
      67           38748 :     {
      68           19374 :         if (!mCallback)
      69                 :             return;
      70                 :         //
      71                 :         // whoa!!  looks like we never posted this event.  take care to
      72                 :         // release mCallback on the correct thread.  if mTarget lives on the
      73                 :         // calling thread, then we are ok.  otherwise, we have to try to 
      74                 :         // proxy the Release over the right thread.  if that thread is dead,
      75                 :         // then there's nothing we can do... better to leak than crash.
      76                 :         //
      77                 :         bool val;
      78               8 :         nsresult rv = mTarget->IsOnCurrentThread(&val);
      79               8 :         if (NS_FAILED(rv) || !val) {
      80               0 :             nsCOMPtr<nsIInputStreamCallback> event;
      81               0 :             NS_NewInputStreamReadyEvent(getter_AddRefs(event), mCallback,
      82               0 :                                         mTarget);
      83               0 :             mCallback = 0;
      84               0 :             if (event) {
      85               0 :                 rv = event->OnInputStreamReady(nsnull);
      86               0 :                 if (NS_FAILED(rv)) {
      87               0 :                     NS_NOTREACHED("leaking stream event");
      88               0 :                     nsISupports *sup = event;
      89               0 :                     NS_ADDREF(sup);
      90                 :                 }
      91                 :             }
      92                 :         }
      93           19374 :     }
      94                 : 
      95                 : public:
      96           19366 :     NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *stream)
      97                 :     {
      98           19366 :         mStream = stream;
      99                 : 
     100                 :         nsresult rv =
     101           19366 :             mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
     102           19366 :         if (NS_FAILED(rv)) {
     103               0 :             NS_WARNING("Dispatch failed");
     104               0 :             return NS_ERROR_FAILURE;
     105                 :         }
     106                 : 
     107           19366 :         return NS_OK;
     108                 :     }
     109                 : 
     110           19366 :     NS_IMETHOD Run()
     111                 :     {
     112           19366 :         if (mCallback) {
     113           19366 :             if (mStream)
     114           19366 :                 mCallback->OnInputStreamReady(mStream);
     115           19366 :             mCallback = nsnull;
     116                 :         }
     117           19366 :         return NS_OK;
     118                 :     }
     119                 : 
     120                 : private:
     121                 :     nsCOMPtr<nsIAsyncInputStream>    mStream;
     122                 :     nsCOMPtr<nsIInputStreamCallback> mCallback;
     123                 :     nsCOMPtr<nsIEventTarget>         mTarget;
     124                 : };
     125                 : 
     126          334209 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsInputStreamReadyEvent, nsIRunnable,
     127                 :                               nsIInputStreamCallback)
     128                 : 
     129                 : //-----------------------------------------------------------------------------
     130                 : 
     131                 : class nsOutputStreamReadyEvent : public nsIRunnable
     132                 :                                , public nsIOutputStreamCallback
     133                 : {
     134                 : public:
     135                 :     NS_DECL_ISUPPORTS
     136                 : 
     137           18277 :     nsOutputStreamReadyEvent(nsIOutputStreamCallback *callback,
     138                 :                              nsIEventTarget *target)
     139                 :         : mCallback(callback)
     140           18277 :         , mTarget(target)
     141                 :     {
     142           18277 :     }
     143                 : 
     144                 : private:
     145           18276 :     ~nsOutputStreamReadyEvent()
     146           36552 :     {
     147           18276 :         if (!mCallback)
     148                 :             return;
     149                 :         //
     150                 :         // whoa!!  looks like we never posted this event.  take care to
     151                 :         // release mCallback on the correct thread.  if mTarget lives on the
     152                 :         // calling thread, then we are ok.  otherwise, we have to try to 
     153                 :         // proxy the Release over the right thread.  if that thread is dead,
     154                 :         // then there's nothing we can do... better to leak than crash.
     155                 :         //
     156                 :         bool val;
     157            8369 :         nsresult rv = mTarget->IsOnCurrentThread(&val);
     158            8369 :         if (NS_FAILED(rv) || !val) {
     159               0 :             nsCOMPtr<nsIOutputStreamCallback> event;
     160               0 :             NS_NewOutputStreamReadyEvent(getter_AddRefs(event), mCallback,
     161               0 :                                          mTarget);
     162               0 :             mCallback = 0;
     163               0 :             if (event) {
     164               0 :                 rv = event->OnOutputStreamReady(nsnull);
     165               0 :                 if (NS_FAILED(rv)) {
     166               0 :                     NS_NOTREACHED("leaking stream event");
     167               0 :                     nsISupports *sup = event;
     168               0 :                     NS_ADDREF(sup);
     169                 :                 }
     170                 :             }
     171                 :         }
     172           18276 :     }
     173                 : 
     174                 : public:
     175            9907 :     NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *stream)
     176                 :     {
     177            9907 :         mStream = stream;
     178                 : 
     179                 :         nsresult rv =
     180            9907 :             mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
     181            9907 :         if (NS_FAILED(rv)) {
     182               0 :             NS_WARNING("PostEvent failed");
     183               0 :             return NS_ERROR_FAILURE;
     184                 :         }
     185                 : 
     186            9907 :         return NS_OK;
     187                 :     }
     188                 : 
     189            9907 :     NS_IMETHOD Run()
     190                 :     {
     191            9907 :         if (mCallback) {
     192            9907 :             if (mStream)
     193            9907 :                 mCallback->OnOutputStreamReady(mStream);
     194            9907 :             mCallback = nsnull;
     195                 :         }
     196            9907 :         return NS_OK;
     197                 :     }
     198                 : 
     199                 : private:
     200                 :     nsCOMPtr<nsIAsyncOutputStream>    mStream;
     201                 :     nsCOMPtr<nsIOutputStreamCallback> mCallback;
     202                 :     nsCOMPtr<nsIEventTarget>          mTarget;
     203                 : };
     204                 : 
     205          264865 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsOutputStreamReadyEvent, nsIRunnable,
     206                 :                               nsIOutputStreamCallback)
     207                 : 
     208                 : //-----------------------------------------------------------------------------
     209                 : 
     210                 : nsresult
     211           19374 : NS_NewInputStreamReadyEvent(nsIInputStreamCallback **event,
     212                 :                             nsIInputStreamCallback *callback,
     213                 :                             nsIEventTarget *target)
     214                 : {
     215           19374 :     NS_ASSERTION(callback, "null callback");
     216           19374 :     NS_ASSERTION(target, "null target");
     217           19374 :     nsInputStreamReadyEvent *ev = new nsInputStreamReadyEvent(callback, target);
     218           19374 :     if (!ev)
     219               0 :         return NS_ERROR_OUT_OF_MEMORY;
     220           19374 :     NS_ADDREF(*event = ev);
     221           19374 :     return NS_OK;
     222                 : }
     223                 : 
     224                 : nsresult
     225           18277 : NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **event,
     226                 :                              nsIOutputStreamCallback *callback,
     227                 :                              nsIEventTarget *target)
     228                 : {
     229           18277 :     NS_ASSERTION(callback, "null callback");
     230           18277 :     NS_ASSERTION(target, "null target");
     231           18277 :     nsOutputStreamReadyEvent *ev = new nsOutputStreamReadyEvent(callback, target);
     232           18277 :     if (!ev)
     233               0 :         return NS_ERROR_OUT_OF_MEMORY;
     234           18277 :     NS_ADDREF(*event = ev);
     235           18277 :     return NS_OK;
     236                 : }
     237                 : 
     238                 : //-----------------------------------------------------------------------------
     239                 : // NS_AsyncCopy implementation
     240                 : 
     241                 : // abstract stream copier...
     242                 : class nsAStreamCopier : public nsIInputStreamCallback
     243                 :                       , public nsIOutputStreamCallback
     244                 :                       , public nsIRunnable
     245                 : {
     246                 : public:
     247                 :     NS_DECL_ISUPPORTS
     248                 : 
     249            6493 :     nsAStreamCopier()
     250                 :         : mLock("nsAStreamCopier.mLock")
     251                 :         , mCallback(nsnull)
     252                 :         , mClosure(nsnull)
     253                 :         , mChunkSize(0)
     254                 :         , mEventInProcess(false)
     255                 :         , mEventIsPending(false)
     256                 :         , mCloseSource(true)
     257                 :         , mCloseSink(true)
     258                 :         , mCanceled(false)
     259            6493 :         , mCancelStatus(NS_OK)
     260                 :     {
     261            6493 :     }
     262                 : 
     263                 :     // virtual since subclasses call superclass Release()
     264            6492 :     virtual ~nsAStreamCopier()
     265            6492 :     {
     266           12984 :     }
     267                 : 
     268                 :     // kick off the async copy...
     269            6493 :     nsresult Start(nsIInputStream *source,
     270                 :                    nsIOutputStream *sink,
     271                 :                    nsIEventTarget *target,
     272                 :                    nsAsyncCopyCallbackFun callback,
     273                 :                    void *closure,
     274                 :                    PRUint32 chunksize,
     275                 :                    bool closeSource,
     276                 :                    bool closeSink)
     277                 :     {
     278            6493 :         mSource = source;
     279            6493 :         mSink = sink;
     280            6493 :         mTarget = target;
     281            6493 :         mCallback = callback;
     282            6493 :         mClosure = closure;
     283            6493 :         mChunkSize = chunksize;
     284            6493 :         mCloseSource = closeSource;
     285            6493 :         mCloseSink = closeSink;
     286                 : 
     287            6493 :         mAsyncSource = do_QueryInterface(mSource);
     288            6493 :         mAsyncSink = do_QueryInterface(mSink);
     289                 : 
     290            6493 :         return PostContinuationEvent();
     291                 :     }
     292                 : 
     293                 :     // implemented by subclasses, returns number of bytes copied and
     294                 :     // sets source and sink condition before returning.
     295                 :     virtual PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition) = 0;
     296                 : 
     297           25084 :     void Process()
     298                 :     {
     299           25084 :         if (!mSource || !mSink)
     300            5816 :             return;
     301                 : 
     302                 :         nsresult sourceCondition, sinkCondition;
     303                 :         nsresult cancelStatus;
     304                 :         bool canceled;
     305                 :         {
     306           38536 :             MutexAutoLock lock(mLock);
     307           19268 :             canceled = mCanceled;
     308           19268 :             cancelStatus = mCancelStatus;
     309                 :         }
     310                 : 
     311                 :         // Copy data from the source to the sink until we hit failure or have
     312                 :         // copied all the data.
     313            7094 :         for (;;) {
     314                 :             // Note: copyFailed will be true if the source or the sink have
     315                 :             //       reported an error, or if we failed to write any bytes
     316                 :             //       because we have consumed all of our data.
     317           26362 :             bool copyFailed = false;
     318           26362 :             if (!canceled) {
     319           26358 :                 PRUint32 n = DoCopy(&sourceCondition, &sinkCondition);
     320           26358 :                 copyFailed = NS_FAILED(sourceCondition) ||
     321           26358 :                              NS_FAILED(sinkCondition) || n == 0;
     322                 : 
     323           52716 :                 MutexAutoLock lock(mLock);
     324           26358 :                 canceled = mCanceled;
     325           26358 :                 cancelStatus = mCancelStatus;
     326                 :             }
     327           26362 :             if (copyFailed && !canceled) {
     328           19264 :                 if (sourceCondition == NS_BASE_STREAM_WOULD_BLOCK && mAsyncSource) {
     329                 :                     // need to wait for more data from source.  while waiting for
     330                 :                     // more source data, be sure to observe failures on output end.
     331           12738 :                     mAsyncSource->AsyncWait(this, 0, 0, nsnull);
     332                 : 
     333           12738 :                     if (mAsyncSink)
     334           12738 :                         mAsyncSink->AsyncWait(this,
     335                 :                                               nsIAsyncOutputStream::WAIT_CLOSURE_ONLY,
     336           12738 :                                               0, nsnull);
     337           12738 :                     break;
     338                 :                 }
     339            6526 :                 else if (sinkCondition == NS_BASE_STREAM_WOULD_BLOCK && mAsyncSink) {
     340                 :                     // need to wait for more room in the sink.  while waiting for
     341                 :                     // more room in the sink, be sure to observer failures on the
     342                 :                     // input end.
     343              41 :                     mAsyncSink->AsyncWait(this, 0, 0, nsnull);
     344                 : 
     345              41 :                     if (mAsyncSource)
     346              41 :                         mAsyncSource->AsyncWait(this,
     347                 :                                                 nsIAsyncInputStream::WAIT_CLOSURE_ONLY,
     348              41 :                                                 0, nsnull);
     349              41 :                     break;
     350                 :                 }
     351                 :             }
     352           13583 :             if (copyFailed || canceled) {
     353            6489 :                 if (mCloseSource) {
     354                 :                     // close source
     355            6483 :                     if (mAsyncSource)
     356            5818 :                         mAsyncSource->CloseWithStatus(canceled ? cancelStatus :
     357            5818 :                                                                  sinkCondition);
     358                 :                     else
     359             665 :                         mSource->Close();
     360                 :                 }
     361            6489 :                 mAsyncSource = nsnull;
     362            6489 :                 mSource = nsnull;
     363                 : 
     364            6489 :                 if (mCloseSink) {
     365                 :                     // close sink
     366            6483 :                     if (mAsyncSink)
     367            6100 :                         mAsyncSink->CloseWithStatus(canceled ? cancelStatus :
     368            6100 :                                                                sourceCondition);
     369                 :                     else {
     370                 :                         // If we have an nsISafeOutputStream, and our
     371                 :                         // sourceCondition and sinkCondition are not set to a
     372                 :                         // failure state, finish writing.
     373                 :                         nsCOMPtr<nsISafeOutputStream> sostream =
     374             766 :                             do_QueryInterface(mSink);
     375             651 :                         if (sostream && NS_SUCCEEDED(sourceCondition) &&
     376             268 :                             NS_SUCCEEDED(sinkCondition))
     377             268 :                             sostream->Finish();
     378                 :                         else
     379             115 :                             mSink->Close();
     380                 :                     }
     381                 :                 }
     382            6489 :                 mAsyncSink = nsnull;
     383            6489 :                 mSink = nsnull;
     384                 : 
     385                 :                 // notify state complete...
     386            6489 :                 if (mCallback) {
     387                 :                     nsresult status;
     388             396 :                     if (!canceled) {
     389             392 :                         status = sourceCondition;
     390             392 :                         if (NS_SUCCEEDED(status))
     391             392 :                             status = sinkCondition;
     392             392 :                         if (status == NS_BASE_STREAM_CLOSED)
     393               0 :                             status = NS_OK;
     394                 :                     } else {
     395               4 :                         status = cancelStatus; 
     396                 :                     }
     397             396 :                     mCallback(mClosure, status);
     398                 :                 }
     399            6489 :                 break;
     400                 :             }
     401                 :         }
     402                 :     }
     403                 : 
     404               7 :     nsresult Cancel(nsresult aReason)
     405                 :     {
     406              14 :         MutexAutoLock lock(mLock);
     407               7 :         if (mCanceled)
     408               0 :             return NS_ERROR_FAILURE;
     409                 : 
     410               7 :         if (NS_SUCCEEDED(aReason)) {
     411               0 :             NS_WARNING("cancel with non-failure status code");
     412               0 :             aReason = NS_BASE_STREAM_CLOSED;
     413                 :         }
     414                 : 
     415               7 :         mCanceled = true;
     416               7 :         mCancelStatus = aReason;
     417               7 :         return NS_OK;
     418                 :     }
     419                 : 
     420           12725 :     NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *source)
     421                 :     {
     422           12725 :         PostContinuationEvent();
     423           12725 :         return NS_OK;
     424                 :     }
     425                 : 
     426            5869 :     NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *sink)
     427                 :     {
     428            5869 :         PostContinuationEvent();
     429            5869 :         return NS_OK;
     430                 :     }
     431                 : 
     432                 :     // continuation event handler
     433           25084 :     NS_IMETHOD Run()
     434                 :     {
     435           25084 :         Process();
     436                 : 
     437                 :         // clear "in process" flag and post any pending continuation event
     438           50168 :         MutexAutoLock lock(mLock);
     439           25084 :         mEventInProcess = false;
     440           25084 :         if (mEventIsPending) {
     441            2950 :             mEventIsPending = false;
     442            2950 :             PostContinuationEvent_Locked();
     443                 :         }
     444                 : 
     445           25084 :         return NS_OK;
     446                 :     }
     447                 : 
     448           25087 :     nsresult PostContinuationEvent()
     449                 :     {
     450                 :         // we cannot post a continuation event if there is currently
     451                 :         // an event in process.  doing so could result in Process being
     452                 :         // run simultaneously on multiple threads, so we mark the event
     453                 :         // as pending, and if an event is already in process then we 
     454                 :         // just let that existing event take care of posting the real
     455                 :         // continuation event.
     456                 : 
     457           50174 :         MutexAutoLock lock(mLock);
     458           25087 :         return PostContinuationEvent_Locked();
     459                 :     }
     460                 : 
     461           28037 :     nsresult PostContinuationEvent_Locked()
     462                 :     {
     463           28037 :         nsresult rv = NS_OK;
     464           28037 :         if (mEventInProcess)
     465            2950 :             mEventIsPending = true;
     466                 :         else {
     467           25087 :             rv = mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
     468           25087 :             if (NS_SUCCEEDED(rv))
     469           25084 :                 mEventInProcess = true;
     470                 :             else
     471               3 :                 NS_WARNING("unable to post continuation event");
     472                 :         }
     473           28037 :         return rv;
     474                 :     }
     475                 : 
     476                 : protected:
     477                 :     nsCOMPtr<nsIInputStream>       mSource;
     478                 :     nsCOMPtr<nsIOutputStream>      mSink;
     479                 :     nsCOMPtr<nsIAsyncInputStream>  mAsyncSource;
     480                 :     nsCOMPtr<nsIAsyncOutputStream> mAsyncSink;
     481                 :     nsCOMPtr<nsIEventTarget>       mTarget;
     482                 :     Mutex                          mLock;
     483                 :     nsAsyncCopyCallbackFun         mCallback;
     484                 :     void                          *mClosure;
     485                 :     PRUint32                       mChunkSize;
     486                 :     bool                           mEventInProcess;
     487                 :     bool                           mEventIsPending;
     488                 :     bool                           mCloseSource;
     489                 :     bool                           mCloseSink;
     490                 :     bool                           mCanceled;
     491                 :     nsresult                       mCancelStatus;
     492                 : };
     493                 : 
     494          340732 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsAStreamCopier,
     495                 :                               nsIInputStreamCallback,
     496                 :                               nsIOutputStreamCallback,
     497                 :                               nsIRunnable)
     498                 : 
     499                 : class nsStreamCopierIB : public nsAStreamCopier
     500                 : {
     501                 : public:
     502            3306 :     nsStreamCopierIB() : nsAStreamCopier() {}
     503           13220 :     virtual ~nsStreamCopierIB() {}
     504                 : 
     505                 :     struct ReadSegmentsState {
     506                 :         nsIOutputStream *mSink;
     507                 :         nsresult         mSinkCondition;
     508                 :     };
     509                 : 
     510            7054 :     static NS_METHOD ConsumeInputBuffer(nsIInputStream *inStr,
     511                 :                                         void *closure,
     512                 :                                         const char *buffer,
     513                 :                                         PRUint32 offset,
     514                 :                                         PRUint32 count,
     515                 :                                         PRUint32 *countWritten)
     516                 :     {
     517            7054 :         ReadSegmentsState *state = (ReadSegmentsState *) closure;
     518                 : 
     519            7054 :         nsresult rv = state->mSink->Write(buffer, count, countWritten);
     520            7054 :         if (NS_FAILED(rv))
     521              26 :             state->mSinkCondition = rv;
     522            7028 :         else if (*countWritten == 0)
     523               0 :             state->mSinkCondition = NS_BASE_STREAM_CLOSED;
     524                 : 
     525            7054 :         return state->mSinkCondition;
     526                 :     }
     527                 : 
     528           19408 :     PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition)
     529                 :     {
     530                 :         ReadSegmentsState state;
     531           19408 :         state.mSink = mSink;
     532           19408 :         state.mSinkCondition = NS_OK;
     533                 : 
     534                 :         PRUint32 n;
     535                 :         *sourceCondition =
     536           19408 :             mSource->ReadSegments(ConsumeInputBuffer, &state, mChunkSize, &n);
     537           19408 :         *sinkCondition = state.mSinkCondition;
     538           19408 :         return n;
     539                 :     }
     540                 : };
     541                 : 
     542                 : class nsStreamCopierOB : public nsAStreamCopier
     543                 : {
     544                 : public:
     545            3187 :     nsStreamCopierOB() : nsAStreamCopier() {}
     546           12748 :     virtual ~nsStreamCopierOB() {}
     547                 : 
     548                 :     struct WriteSegmentsState {
     549                 :         nsIInputStream *mSource;
     550                 :         nsresult        mSourceCondition;
     551                 :     };
     552                 : 
     553           10513 :     static NS_METHOD FillOutputBuffer(nsIOutputStream *outStr,
     554                 :                                       void *closure,
     555                 :                                       char *buffer,
     556                 :                                       PRUint32 offset,
     557                 :                                       PRUint32 count,
     558                 :                                       PRUint32 *countRead)
     559                 :     {
     560           10513 :         WriteSegmentsState *state = (WriteSegmentsState *) closure;
     561                 : 
     562           10513 :         nsresult rv = state->mSource->Read(buffer, count, countRead);
     563           10513 :         if (NS_FAILED(rv))
     564            3480 :             state->mSourceCondition = rv;
     565            7033 :         else if (*countRead == 0)
     566            3123 :             state->mSourceCondition = NS_BASE_STREAM_CLOSED;
     567                 : 
     568           10513 :         return state->mSourceCondition;
     569                 :     }
     570                 : 
     571            6950 :     PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition)
     572                 :     {
     573                 :         WriteSegmentsState state;
     574            6950 :         state.mSource = mSource;
     575            6950 :         state.mSourceCondition = NS_OK;
     576                 : 
     577                 :         PRUint32 n;
     578                 :         *sinkCondition =
     579            6950 :             mSink->WriteSegments(FillOutputBuffer, &state, mChunkSize, &n);
     580            6950 :         *sourceCondition = state.mSourceCondition;
     581            6950 :         return n;
     582                 :     }
     583                 : };
     584                 : 
     585                 : //-----------------------------------------------------------------------------
     586                 : 
     587                 : nsresult
     588            6493 : NS_AsyncCopy(nsIInputStream         *source,
     589                 :              nsIOutputStream        *sink,
     590                 :              nsIEventTarget         *target,
     591                 :              nsAsyncCopyMode         mode,
     592                 :              PRUint32                chunkSize,
     593                 :              nsAsyncCopyCallbackFun  callback,
     594                 :              void                   *closure,
     595                 :              bool                    closeSource,
     596                 :              bool                    closeSink,
     597                 :              nsISupports           **aCopierCtx)
     598                 : {
     599            6493 :     NS_ASSERTION(target, "non-null target required");
     600                 : 
     601                 :     nsresult rv;
     602                 :     nsAStreamCopier *copier;
     603                 : 
     604            6493 :     if (mode == NS_ASYNCCOPY_VIA_READSEGMENTS)
     605            3306 :         copier = new nsStreamCopierIB();
     606                 :     else
     607            3187 :         copier = new nsStreamCopierOB();
     608                 : 
     609            6493 :     if (!copier)
     610               0 :         return NS_ERROR_OUT_OF_MEMORY;
     611                 : 
     612                 :     // Start() takes an owning ref to the copier...
     613            6493 :     NS_ADDREF(copier);
     614                 :     rv = copier->Start(source, sink, target, callback, closure, chunkSize,
     615            6493 :                        closeSource, closeSink);
     616                 : 
     617            6493 :     if (aCopierCtx) {
     618                 :         *aCopierCtx = static_cast<nsISupports*>(
     619             399 :                       static_cast<nsIRunnable*>(copier));
     620             399 :         NS_ADDREF(*aCopierCtx);
     621                 :     }
     622            6493 :     NS_RELEASE(copier);
     623                 : 
     624            6493 :     return rv;
     625                 : }
     626                 : 
     627                 : //-----------------------------------------------------------------------------
     628                 : 
     629                 : nsresult
     630               7 : NS_CancelAsyncCopy(nsISupports *aCopierCtx, nsresult aReason)
     631                 : {
     632                 :   nsAStreamCopier *copier = static_cast<nsAStreamCopier *>(
     633               7 :                             static_cast<nsIRunnable *>(aCopierCtx));
     634               7 :   return copier->Cancel(aReason);
     635                 : }
     636                 : 
     637                 : //-----------------------------------------------------------------------------
     638                 : 
     639                 : nsresult
     640             406 : NS_ConsumeStream(nsIInputStream *stream, PRUint32 maxCount, nsACString &result)
     641                 : {
     642             406 :     nsresult rv = NS_OK;
     643             406 :     result.Truncate();
     644                 : 
     645            1218 :     while (maxCount) {
     646                 :         PRUint32 avail;
     647             414 :         rv = stream->Available(&avail);
     648             414 :         if (NS_FAILED(rv)) {
     649               0 :             if (rv == NS_BASE_STREAM_CLOSED)
     650               0 :                 rv = NS_OK;
     651               0 :             break;
     652                 :         }
     653             414 :         if (avail == 0)
     654               8 :             break;
     655             406 :         if (avail > maxCount)
     656             285 :             avail = maxCount;
     657                 : 
     658                 :         // resize result buffer
     659             406 :         PRUint32 length = result.Length();
     660             406 :         result.SetLength(length + avail);
     661             406 :         if (result.Length() != (length + avail))
     662               0 :             return NS_ERROR_OUT_OF_MEMORY;
     663             406 :         char *buf = result.BeginWriting() + length;
     664                 :         
     665                 :         PRUint32 n;
     666             406 :         rv = stream->Read(buf, avail, &n);
     667             406 :         if (NS_FAILED(rv))
     668               0 :             break;
     669             406 :         if (n != avail)
     670               0 :             result.SetLength(length + n);
     671             406 :         if (n == 0)
     672               0 :             break;
     673             406 :         maxCount -= n;
     674                 :     }
     675                 : 
     676             406 :     return rv;
     677                 : }
     678                 : 
     679                 : //-----------------------------------------------------------------------------
     680                 : 
     681                 : static NS_METHOD
     682            4078 : TestInputStream(nsIInputStream *inStr,
     683                 :                 void *closure,
     684                 :                 const char *buffer,
     685                 :                 PRUint32 offset,
     686                 :                 PRUint32 count,
     687                 :                 PRUint32 *countWritten)
     688                 : {
     689            4078 :     bool *result = static_cast<bool *>(closure);
     690            4078 :     *result = true;
     691            4078 :     return NS_ERROR_ABORT;  // don't call me anymore
     692                 : }
     693                 : 
     694                 : bool
     695            4607 : NS_InputStreamIsBuffered(nsIInputStream *stream)
     696                 : {
     697            4607 :     bool result = false;
     698                 :     PRUint32 n;
     699                 :     nsresult rv = stream->ReadSegments(TestInputStream,
     700            4607 :                                        &result, 1, &n);
     701            4607 :     return result || NS_SUCCEEDED(rv);
     702                 : }
     703                 : 
     704                 : static NS_METHOD
     705               0 : TestOutputStream(nsIOutputStream *outStr,
     706                 :                  void *closure,
     707                 :                  char *buffer,
     708                 :                  PRUint32 offset,
     709                 :                  PRUint32 count,
     710                 :                  PRUint32 *countRead)
     711                 : {
     712               0 :     bool *result = static_cast<bool *>(closure);
     713               0 :     *result = true;
     714               0 :     return NS_ERROR_ABORT;  // don't call me anymore
     715                 : }
     716                 : 
     717                 : bool
     718             386 : NS_OutputStreamIsBuffered(nsIOutputStream *stream)
     719                 : {
     720             386 :     bool result = false;
     721                 :     PRUint32 n;
     722             386 :     stream->WriteSegments(TestOutputStream, &result, 1, &n);
     723             386 :     return result;
     724                 : }
     725                 : 
     726                 : //-----------------------------------------------------------------------------
     727                 : 
     728                 : NS_METHOD
     729              17 : NS_CopySegmentToStream(nsIInputStream *inStr,
     730                 :                        void *closure,
     731                 :                        const char *buffer,
     732                 :                        PRUint32 offset,
     733                 :                        PRUint32 count,
     734                 :                        PRUint32 *countWritten)
     735                 : {
     736              17 :     nsIOutputStream *outStr = static_cast<nsIOutputStream *>(closure);
     737              17 :     *countWritten = 0;
     738              51 :     while (count) {
     739                 :         PRUint32 n;
     740              17 :         nsresult rv = outStr->Write(buffer, count, &n);
     741              17 :         if (NS_FAILED(rv))
     742               0 :             return rv;
     743              17 :         buffer += n;
     744              17 :         count -= n;
     745              17 :         *countWritten += n;
     746                 :     }
     747              17 :     return NS_OK;
     748                 : }
     749                 : 
     750                 : NS_METHOD
     751         4060698 : NS_CopySegmentToBuffer(nsIInputStream *inStr,
     752                 :                        void *closure,
     753                 :                        const char *buffer,
     754                 :                        PRUint32 offset,
     755                 :                        PRUint32 count,
     756                 :                        PRUint32 *countWritten)
     757                 : {
     758         4060698 :     char *toBuf = static_cast<char *>(closure);
     759         4060698 :     memcpy(&toBuf[offset], buffer, count);
     760         4060698 :     *countWritten = count;
     761         4060698 :     return NS_OK;
     762                 : }
     763                 : 
     764                 : NS_METHOD
     765              39 : NS_DiscardSegment(nsIInputStream *inStr,
     766                 :                   void *closure,
     767                 :                   const char *buffer,
     768                 :                   PRUint32 offset,
     769                 :                   PRUint32 count,
     770                 :                   PRUint32 *countWritten)
     771                 : {
     772              39 :     *countWritten = count;
     773              39 :     return NS_OK;
     774                 : }
     775                 : 
     776                 : //-----------------------------------------------------------------------------
     777                 : 
     778                 : NS_METHOD
     779              17 : NS_WriteSegmentThunk(nsIInputStream *inStr,
     780                 :                      void *closure,
     781                 :                      const char *buffer,
     782                 :                      PRUint32 offset,
     783                 :                      PRUint32 count,
     784                 :                      PRUint32 *countWritten)
     785                 : {
     786              17 :     nsWriteSegmentThunk *thunk = static_cast<nsWriteSegmentThunk *>(closure);
     787                 :     return thunk->mFun(thunk->mStream, thunk->mClosure, buffer, offset, count,
     788              17 :                        countWritten);
     789                 : }

Generated by: LCOV version 1.7