LCOV - code coverage report
Current view: directory - netwerk/base/src - nsBufferedStreams.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 390 239 61.3 %
Date: 2012-06-02 Functions: 48 34 70.8 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       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.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "IPC/IPCMessageUtils.h"
      39                 : #include "mozilla/net/NeckoMessageUtils.h"
      40                 : 
      41                 : #include "nsAlgorithm.h"
      42                 : #include "nsBufferedStreams.h"
      43                 : #include "nsStreamUtils.h"
      44                 : #include "nsCRT.h"
      45                 : #include "nsNetCID.h"
      46                 : #include "nsIClassInfoImpl.h"
      47                 : 
      48                 : #ifdef DEBUG_brendan
      49                 : # define METERING
      50                 : #endif
      51                 : 
      52                 : #ifdef METERING
      53                 : # include <stdio.h>
      54                 : # define METER(x)       x
      55                 : # define MAX_BIG_SEEKS  20
      56                 : 
      57                 : static struct {
      58                 :     PRUint32            mSeeksWithinBuffer;
      59                 :     PRUint32            mSeeksOutsideBuffer;
      60                 :     PRUint32            mBufferReadUponSeek;
      61                 :     PRUint32            mBufferUnreadUponSeek;
      62                 :     PRUint32            mBytesReadFromBuffer;
      63                 :     PRUint32            mBigSeekIndex;
      64                 :     struct {
      65                 :         PRInt64         mOldOffset;
      66                 :         PRInt64         mNewOffset;
      67                 :     } mBigSeek[MAX_BIG_SEEKS];
      68                 : } bufstats;
      69                 : #else
      70                 : # define METER(x)       /* nothing */
      71                 : #endif
      72                 : 
      73                 : ////////////////////////////////////////////////////////////////////////////////
      74                 : // nsBufferedStream
      75                 : 
      76            3919 : nsBufferedStream::nsBufferedStream()
      77                 :     : mBuffer(nsnull),
      78                 :       mBufferStartOffset(0),
      79                 :       mCursor(0), 
      80                 :       mFillPoint(0),
      81                 :       mStream(nsnull),
      82                 :       mBufferDisabled(false),
      83                 :       mEOF(false),
      84            3919 :       mGetBufferCount(0)
      85                 : {
      86            3919 : }
      87                 : 
      88            3919 : nsBufferedStream::~nsBufferedStream()
      89                 : {
      90            3919 :     Close();
      91            7838 : }
      92                 : 
      93          137433 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsBufferedStream, nsISeekableStream)
      94                 : 
      95                 : nsresult
      96            3919 : nsBufferedStream::Init(nsISupports* stream, PRUint32 bufferSize)
      97                 : {
      98            3919 :     NS_ASSERTION(stream, "need to supply a stream");
      99            3919 :     NS_ASSERTION(mStream == nsnull, "already inited");
     100            3919 :     mStream = stream;
     101            3919 :     NS_IF_ADDREF(mStream);
     102            3919 :     mBufferSize = bufferSize;
     103            3919 :     mBufferStartOffset = 0;
     104            3919 :     mCursor = 0;
     105            7838 :     mBuffer = new char[bufferSize];
     106            3919 :     if (mBuffer == nsnull)
     107               0 :         return NS_ERROR_OUT_OF_MEMORY;
     108            3919 :     return NS_OK;
     109                 : }
     110                 : 
     111                 : nsresult
     112            7987 : nsBufferedStream::Close()
     113                 : {
     114            7987 :     NS_IF_RELEASE(mStream);
     115            7987 :     if (mBuffer) {
     116            3919 :         delete[] mBuffer;
     117            3919 :         mBuffer = nsnull;
     118            3919 :         mBufferSize = 0;
     119            3919 :         mBufferStartOffset = 0;
     120            3919 :         mCursor = 0;
     121            3919 :         mFillPoint = 0;
     122                 :     }
     123                 : #ifdef METERING
     124                 :     {
     125                 :         static FILE *tfp;
     126                 :         if (!tfp) {
     127                 :             tfp = fopen("/tmp/bufstats", "w");
     128                 :             if (tfp)
     129                 :                 setvbuf(tfp, NULL, _IOLBF, 0);
     130                 :         }
     131                 :         if (tfp) {
     132                 :             fprintf(tfp, "seeks within buffer:    %u\n",
     133                 :                     bufstats.mSeeksWithinBuffer);
     134                 :             fprintf(tfp, "seeks outside buffer:   %u\n",
     135                 :                     bufstats.mSeeksOutsideBuffer);
     136                 :             fprintf(tfp, "buffer read on seek:    %u\n",
     137                 :                     bufstats.mBufferReadUponSeek);
     138                 :             fprintf(tfp, "buffer unread on seek:  %u\n",
     139                 :                     bufstats.mBufferUnreadUponSeek);
     140                 :             fprintf(tfp, "bytes read from buffer: %u\n",
     141                 :                     bufstats.mBytesReadFromBuffer);
     142                 :             for (PRUint32 i = 0; i < bufstats.mBigSeekIndex; i++) {
     143                 :                 fprintf(tfp, "bigseek[%u] = {old: %u, new: %u}\n",
     144                 :                         i,
     145                 :                         bufstats.mBigSeek[i].mOldOffset,
     146                 :                         bufstats.mBigSeek[i].mNewOffset);
     147                 :             }
     148                 :         }
     149                 :     }
     150                 : #endif
     151            7987 :     return NS_OK;
     152                 : }
     153                 : 
     154                 : NS_IMETHODIMP
     155            5745 : nsBufferedStream::Seek(PRInt32 whence, PRInt64 offset)
     156                 : {
     157            5745 :     if (mStream == nsnull)
     158               0 :         return NS_BASE_STREAM_CLOSED;
     159                 :     
     160                 :     // If the underlying stream isn't a random access store, then fail early.
     161                 :     // We could possibly succeed for the case where the seek position denotes
     162                 :     // something that happens to be read into the buffer, but that would make
     163                 :     // the failure data-dependent.
     164                 :     nsresult rv;
     165           11490 :     nsCOMPtr<nsISeekableStream> ras = do_QueryInterface(mStream, &rv);
     166            5745 :     if (NS_FAILED(rv)) return rv;
     167                 : 
     168            5745 :     PRInt64 absPos = 0;
     169            5745 :     switch (whence) {
     170                 :       case nsISeekableStream::NS_SEEK_SET:
     171            5745 :         absPos = offset;
     172            5745 :         break;
     173                 :       case nsISeekableStream::NS_SEEK_CUR:
     174               0 :         absPos = mBufferStartOffset;
     175               0 :         absPos += mCursor;
     176               0 :         absPos += offset;
     177               0 :         break;
     178                 :       case nsISeekableStream::NS_SEEK_END:
     179               0 :         absPos = -1;
     180               0 :         break;
     181                 :       default:
     182               0 :         NS_NOTREACHED("bogus seek whence parameter");
     183               0 :         return NS_ERROR_UNEXPECTED;
     184                 :     }
     185                 : 
     186                 :     // Let mCursor point into the existing buffer if the new position is
     187                 :     // between the current cursor and the mFillPoint "fencepost" -- the
     188                 :     // client may never get around to a Read or Write after this Seek.
     189                 :     // Read and Write worry about flushing and filling in that event.
     190                 :     // But if we're at EOF, make sure to pass the seek through to the
     191                 :     // underlying stream, because it may have auto-closed itself and
     192                 :     // needs to reopen.
     193            5745 :     PRUint32 offsetInBuffer = PRUint32(absPos - mBufferStartOffset);
     194            5745 :     if (offsetInBuffer <= mFillPoint && !mEOF) {
     195                 :         METER(bufstats.mSeeksWithinBuffer++);
     196             256 :         mCursor = offsetInBuffer;
     197             256 :         return NS_OK;
     198                 :     }
     199                 : 
     200                 :     METER(bufstats.mSeeksOutsideBuffer++);
     201                 :     METER(bufstats.mBufferReadUponSeek += mCursor);
     202                 :     METER(bufstats.mBufferUnreadUponSeek += mFillPoint - mCursor);
     203            5489 :     rv = Flush();
     204            5489 :     if (NS_FAILED(rv)) return rv;
     205                 : 
     206            5489 :     rv = ras->Seek(whence, offset);
     207            5489 :     if (NS_FAILED(rv)) return rv;
     208                 : 
     209            5489 :     mEOF = false;
     210                 : 
     211                 :     // Recompute whether the offset we're seeking to is in our buffer.
     212                 :     // Note that we need to recompute because Flush() might have
     213                 :     // changed mBufferStartOffset.
     214            5489 :     offsetInBuffer = PRUint32(absPos - mBufferStartOffset);
     215            5489 :     if (offsetInBuffer <= mFillPoint) {
     216                 :         // It's safe to just set mCursor to offsetInBuffer.  In particular, we
     217                 :         // want to avoid calling Fill() here since we already have the data that
     218                 :         // was seeked to and calling Fill() might auto-close our underlying
     219                 :         // stream in some cases.
     220               2 :         mCursor = offsetInBuffer;
     221               2 :         return NS_OK;
     222                 :     }
     223                 : 
     224                 :     METER(if (bufstats.mBigSeekIndex < MAX_BIG_SEEKS)
     225                 :               bufstats.mBigSeek[bufstats.mBigSeekIndex].mOldOffset =
     226                 :                   mBufferStartOffset + PRInt64(mCursor));
     227            5487 :     const PRInt64 minus1 = -1;
     228            5487 :     if (absPos == minus1) {
     229                 :         // then we had the SEEK_END case, above
     230                 :         PRInt64 tellPos;
     231               0 :         rv = ras->Tell(&tellPos);
     232               0 :         mBufferStartOffset = tellPos;
     233               0 :         if (NS_FAILED(rv)) return rv;
     234                 :     }
     235                 :     else {
     236            5487 :         mBufferStartOffset = absPos;
     237                 :     }
     238                 :     METER(if (bufstats.mBigSeekIndex < MAX_BIG_SEEKS)
     239                 :               bufstats.mBigSeek[bufstats.mBigSeekIndex++].mNewOffset =
     240                 :                   mBufferStartOffset);
     241                 : 
     242            5487 :     mFillPoint = mCursor = 0;
     243            5487 :     return Fill();
     244                 : }
     245                 : 
     246                 : NS_IMETHODIMP
     247            6116 : nsBufferedStream::Tell(PRInt64 *result)
     248                 : {
     249            6116 :     if (mStream == nsnull)
     250               0 :         return NS_BASE_STREAM_CLOSED;
     251                 :     
     252            6116 :     PRInt64 result64 = mBufferStartOffset;
     253            6116 :     result64 += mCursor;
     254            6116 :     *result = result64;
     255            6116 :     return NS_OK;
     256                 : }
     257                 : 
     258                 : NS_IMETHODIMP
     259             939 : nsBufferedStream::SetEOF()
     260                 : {
     261             939 :     if (mStream == nsnull)
     262               0 :         return NS_BASE_STREAM_CLOSED;
     263                 :     
     264                 :     nsresult rv;
     265            1878 :     nsCOMPtr<nsISeekableStream> ras = do_QueryInterface(mStream, &rv);
     266             939 :     if (NS_FAILED(rv)) return rv;
     267                 : 
     268             939 :     rv = ras->SetEOF();
     269             939 :     if (NS_SUCCEEDED(rv))
     270             939 :         mEOF = true;
     271             939 :     return rv;
     272                 : }
     273                 : 
     274                 : ////////////////////////////////////////////////////////////////////////////////
     275                 : // nsBufferedInputStream
     276                 : 
     277           21984 : NS_IMPL_ADDREF_INHERITED(nsBufferedInputStream, nsBufferedStream)
     278           21984 : NS_IMPL_RELEASE_INHERITED(nsBufferedInputStream, nsBufferedStream)
     279                 : 
     280                 : NS_IMPL_CLASSINFO(nsBufferedInputStream, NULL, nsIClassInfo::THREADSAFE,
     281                 :                   NS_BUFFEREDINPUTSTREAM_CID)
     282                 : 
     283           30071 : NS_INTERFACE_MAP_BEGIN(nsBufferedInputStream)
     284           30071 :     NS_INTERFACE_MAP_ENTRY(nsIInputStream)
     285           21626 :     NS_INTERFACE_MAP_ENTRY(nsIBufferedInputStream)
     286           16076 :     NS_INTERFACE_MAP_ENTRY(nsIStreamBufferAccess)
     287           16062 :     NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
     288           16062 :     NS_IMPL_QUERY_CLASSINFO(nsBufferedInputStream)
     289           14230 : NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)
     290                 : 
     291             389 : NS_IMPL_CI_INTERFACE_GETTER5(nsBufferedInputStream,
     292                 :                              nsIInputStream,
     293                 :                              nsIBufferedInputStream,
     294                 :                              nsISeekableStream,
     295                 :                              nsIStreamBufferAccess,
     296             389 :                              nsIIPCSerializable)
     297                 : 
     298                 : nsresult
     299            2775 : nsBufferedInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
     300                 : {
     301            2775 :     NS_ENSURE_NO_AGGREGATION(aOuter);
     302                 : 
     303            2775 :     nsBufferedInputStream* stream = new nsBufferedInputStream();
     304            2775 :     if (stream == nsnull)
     305               0 :         return NS_ERROR_OUT_OF_MEMORY;
     306            2775 :     NS_ADDREF(stream);
     307            2775 :     nsresult rv = stream->QueryInterface(aIID, aResult);
     308            2775 :     NS_RELEASE(stream);
     309            2775 :     return rv;
     310                 : }
     311                 : 
     312                 : NS_IMETHODIMP
     313            2775 : nsBufferedInputStream::Init(nsIInputStream* stream, PRUint32 bufferSize)
     314                 : {
     315            2775 :     return nsBufferedStream::Init(stream, bufferSize);
     316                 : }
     317                 : 
     318                 : NS_IMETHODIMP
     319            1811 : nsBufferedInputStream::Close()
     320                 : {
     321            1811 :     nsresult rv1 = NS_OK, rv2;
     322            1811 :     if (mStream) {
     323            1811 :         rv1 = Source()->Close();
     324            1811 :         NS_RELEASE(mStream);
     325                 :     }
     326            1811 :     rv2 = nsBufferedStream::Close();
     327            1811 :     if (NS_FAILED(rv1)) return rv1;
     328            1811 :     return rv2;
     329                 : }
     330                 : 
     331                 : NS_IMETHODIMP
     332            4513 : nsBufferedInputStream::Available(PRUint32 *result)
     333                 : {
     334            4513 :     nsresult rv = NS_OK;
     335            4513 :     *result = 0;
     336            4513 :     if (mStream) {
     337            4512 :         rv = Source()->Available(result);
     338                 :     }
     339            4513 :     *result += (mFillPoint - mCursor);
     340            4513 :     return rv;
     341                 : }
     342                 : 
     343                 : NS_IMETHODIMP
     344              20 : nsBufferedInputStream::Read(char * buf, PRUint32 count, PRUint32 *result)
     345                 : {
     346              20 :     if (mBufferDisabled) {
     347               1 :         if (!mStream) {
     348               0 :             *result = 0;
     349               0 :             return NS_OK;
     350                 :         }
     351               1 :         nsresult rv = Source()->Read(buf, count, result);
     352               1 :         if (NS_SUCCEEDED(rv)) {
     353               1 :             mBufferStartOffset += *result;  // so nsBufferedStream::Tell works
     354               1 :             if (*result == 0) {
     355               1 :                 mEOF = true;
     356                 :             }
     357                 :         }
     358               1 :         return rv;
     359                 :     }
     360                 : 
     361              19 :     return ReadSegments(NS_CopySegmentToBuffer, buf, count, result);
     362                 : }
     363                 : 
     364                 : NS_IMETHODIMP
     365            5531 : nsBufferedInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
     366                 :                                     PRUint32 count, PRUint32 *result)
     367                 : {
     368            5531 :     *result = 0;
     369                 : 
     370            5531 :     if (!mStream)
     371               1 :         return NS_OK;
     372                 : 
     373            5530 :     nsresult rv = NS_OK;
     374           16924 :     while (count > 0) {
     375            9006 :         PRUint32 amt = NS_MIN(count, mFillPoint - mCursor);
     376            9006 :         if (amt > 0) {
     377            5305 :             PRUint32 read = 0;
     378            5305 :             rv = writer(this, closure, mBuffer + mCursor, *result, amt, &read);
     379            5305 :             if (NS_FAILED(rv)) {
     380                 :                 // errors returned from the writer end here!
     381            2373 :                 rv = NS_OK;
     382            2373 :                 break;
     383                 :             }
     384            2932 :             *result += read;
     385            2932 :             count -= read;
     386            2932 :             mCursor += read;
     387                 :         }
     388                 :         else {
     389            3701 :             rv = Fill();
     390            3701 :             if (NS_FAILED(rv) || mFillPoint == mCursor)
     391             769 :                 break;
     392                 :         }
     393                 :     }
     394            5530 :     return (*result > 0) ? NS_OK : rv;
     395                 : }
     396                 : 
     397                 : NS_IMETHODIMP
     398               0 : nsBufferedInputStream::IsNonBlocking(bool *aNonBlocking)
     399                 : {
     400               0 :     if (mStream)
     401               0 :         return Source()->IsNonBlocking(aNonBlocking);
     402               0 :     return NS_ERROR_NOT_INITIALIZED;
     403                 : }
     404                 : 
     405                 : NS_IMETHODIMP
     406            3701 : nsBufferedInputStream::Fill()
     407                 : {
     408            3701 :     if (mBufferDisabled)
     409               0 :         return NS_OK;
     410            3701 :     NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_INITIALIZED);
     411                 : 
     412                 :     nsresult rv;
     413            3701 :     PRInt32 rem = PRInt32(mFillPoint - mCursor);
     414            3701 :     if (rem > 0) {
     415                 :         // slide the remainder down to the start of the buffer
     416                 :         // |<------------->|<--rem-->|<--->|
     417                 :         // b               c         f     s
     418               0 :         memcpy(mBuffer, mBuffer + mCursor, rem);
     419                 :     }
     420            3701 :     mBufferStartOffset += mCursor;
     421            3701 :     mFillPoint = rem;
     422            3701 :     mCursor = 0;
     423                 : 
     424                 :     PRUint32 amt;
     425            3701 :     rv = Source()->Read(mBuffer + mFillPoint, mBufferSize - mFillPoint, &amt);
     426            3701 :     if (NS_FAILED(rv)) return rv;
     427                 : 
     428            3701 :     if (amt == 0)
     429             769 :         mEOF = true;
     430                 :     
     431            3701 :     mFillPoint += amt;
     432            3701 :     return NS_OK;
     433                 : }
     434                 : 
     435                 : NS_IMETHODIMP_(char*)
     436               0 : nsBufferedInputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask)
     437                 : {
     438               0 :     NS_ASSERTION(mGetBufferCount == 0, "nested GetBuffer!");
     439               0 :     if (mGetBufferCount != 0)
     440               0 :         return nsnull;
     441                 : 
     442               0 :     if (mBufferDisabled)
     443               0 :         return nsnull;
     444                 : 
     445               0 :     char* buf = mBuffer + mCursor;
     446               0 :     PRUint32 rem = mFillPoint - mCursor;
     447               0 :     if (rem == 0) {
     448               0 :         if (NS_FAILED(Fill()))
     449               0 :             return nsnull;
     450               0 :         buf = mBuffer + mCursor;
     451               0 :         rem = mFillPoint - mCursor;
     452                 :     }
     453                 : 
     454               0 :     PRUint32 mod = (NS_PTR_TO_INT32(buf) & aAlignMask);
     455               0 :     if (mod) {
     456               0 :         PRUint32 pad = aAlignMask + 1 - mod;
     457               0 :         if (pad > rem)
     458               0 :             return nsnull;
     459                 : 
     460               0 :         memset(buf, 0, pad);
     461               0 :         mCursor += pad;
     462               0 :         buf += pad;
     463               0 :         rem -= pad;
     464                 :     }
     465                 : 
     466               0 :     if (aLength > rem)
     467               0 :         return nsnull;
     468               0 :     mGetBufferCount++;
     469               0 :     return buf;
     470                 : }
     471                 : 
     472                 : NS_IMETHODIMP_(void)
     473               0 : nsBufferedInputStream::PutBuffer(char* aBuffer, PRUint32 aLength)
     474                 : {
     475               0 :     NS_ASSERTION(mGetBufferCount == 1, "stray PutBuffer!");
     476               0 :     if (--mGetBufferCount != 0)
     477               0 :         return;
     478                 : 
     479               0 :     NS_ASSERTION(mCursor + aLength <= mFillPoint, "PutBuffer botch");
     480               0 :     mCursor += aLength;
     481                 : }
     482                 : 
     483                 : NS_IMETHODIMP
     484               1 : nsBufferedInputStream::DisableBuffering()
     485                 : {
     486               1 :     NS_ASSERTION(!mBufferDisabled, "redundant call to DisableBuffering!");
     487               1 :     NS_ASSERTION(mGetBufferCount == 0,
     488                 :                  "DisableBuffer call between GetBuffer and PutBuffer!");
     489               1 :     if (mGetBufferCount != 0)
     490               0 :         return NS_ERROR_UNEXPECTED;
     491                 : 
     492                 :     // Empty the buffer so nsBufferedStream::Tell works.
     493               1 :     mBufferStartOffset += mCursor;
     494               1 :     mFillPoint = mCursor = 0;
     495               1 :     mBufferDisabled = true;
     496               1 :     return NS_OK;
     497                 : }
     498                 : 
     499                 : NS_IMETHODIMP
     500               0 : nsBufferedInputStream::EnableBuffering()
     501                 : {
     502               0 :     NS_ASSERTION(mBufferDisabled, "gratuitous call to EnableBuffering!");
     503               0 :     mBufferDisabled = false;
     504               0 :     return NS_OK;
     505                 : }
     506                 : 
     507                 : NS_IMETHODIMP
     508               0 : nsBufferedInputStream::GetUnbufferedStream(nsISupports* *aStream)
     509                 : {
     510                 :     // Empty the buffer so subsequent i/o trumps any buffered data.
     511               0 :     mBufferStartOffset += mCursor;
     512               0 :     mFillPoint = mCursor = 0;
     513                 : 
     514               0 :     *aStream = mStream;
     515               0 :     NS_IF_ADDREF(*aStream);
     516               0 :     return NS_OK;
     517                 : }
     518                 : 
     519                 : bool
     520               0 : nsBufferedInputStream::Read(const IPC::Message *aMsg, void **aIter)
     521                 : {
     522                 :     using IPC::ReadParam;
     523                 : 
     524                 :     PRUint32 bufferSize;
     525               0 :     IPC::InputStream inputStream;
     526               0 :     if (!ReadParam(aMsg, aIter, &bufferSize) ||
     527               0 :         !ReadParam(aMsg, aIter, &inputStream))
     528               0 :         return false;
     529                 : 
     530               0 :     nsCOMPtr<nsIInputStream> stream(inputStream);
     531               0 :     nsresult rv = Init(stream, bufferSize);
     532               0 :     if (NS_FAILED(rv))
     533               0 :         return false;
     534                 : 
     535               0 :     return true;
     536                 : }
     537                 : 
     538                 : void
     539               0 : nsBufferedInputStream::Write(IPC::Message *aMsg)
     540                 : {
     541                 :     using IPC::WriteParam;
     542                 : 
     543               0 :     WriteParam(aMsg, mBufferSize);
     544                 : 
     545               0 :     IPC::InputStream inputStream(Source());
     546               0 :     WriteParam(aMsg, inputStream);
     547               0 : }
     548                 : 
     549                 : ////////////////////////////////////////////////////////////////////////////////
     550                 : // nsBufferedOutputStream
     551                 : 
     552           35754 : NS_IMPL_ADDREF_INHERITED(nsBufferedOutputStream, nsBufferedStream)
     553           35754 : NS_IMPL_RELEASE_INHERITED(nsBufferedOutputStream, nsBufferedStream)
     554                 : // This QI uses NS_INTERFACE_MAP_ENTRY_CONDITIONAL to check for
     555                 : // non-nullness of mSafeStream.
     556           22820 : NS_INTERFACE_MAP_BEGIN(nsBufferedOutputStream)
     557           22820 :     NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
     558           10215 :     NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISafeOutputStream, mSafeStream)
     559           10015 :     NS_INTERFACE_MAP_ENTRY(nsIBufferedOutputStream)
     560            7727 :     NS_INTERFACE_MAP_ENTRY(nsIStreamBufferAccess)
     561            7727 : NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)
     562                 : 
     563                 : nsresult
     564            1144 : nsBufferedOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
     565                 : {
     566            1144 :     NS_ENSURE_NO_AGGREGATION(aOuter);
     567                 : 
     568            1144 :     nsBufferedOutputStream* stream = new nsBufferedOutputStream();
     569            1144 :     if (stream == nsnull)
     570               0 :         return NS_ERROR_OUT_OF_MEMORY;
     571            1144 :     NS_ADDREF(stream);
     572            1144 :     nsresult rv = stream->QueryInterface(aIID, aResult);
     573            1144 :     NS_RELEASE(stream);
     574            1144 :     return rv;
     575                 : }
     576                 : 
     577                 : NS_IMETHODIMP
     578            1144 : nsBufferedOutputStream::Init(nsIOutputStream* stream, PRUint32 bufferSize)
     579                 : {
     580                 :     // QI stream to an nsISafeOutputStream, to see if we should support it
     581            1144 :     mSafeStream = do_QueryInterface(stream);
     582                 : 
     583            1144 :     return nsBufferedStream::Init(stream, bufferSize);
     584                 : }
     585                 : 
     586                 : NS_IMETHODIMP
     587            2141 : nsBufferedOutputStream::Close()
     588                 : {
     589            2141 :     nsresult rv1, rv2 = NS_OK, rv3;
     590            2141 :     rv1 = Flush();
     591                 :     // If we fail to Flush all the data, then we close anyway and drop the
     592                 :     // remaining data in the buffer. We do this because it's what Unix does
     593                 :     // for fclose and close. However, we report the error from Flush anyway.
     594            2141 :     if (mStream) {
     595            1028 :         rv2 = Sink()->Close();
     596            1028 :         NS_RELEASE(mStream);
     597                 :     }
     598            2141 :     rv3 = nsBufferedStream::Close();
     599            2141 :     if (NS_FAILED(rv1)) return rv1;
     600            2141 :     if (NS_FAILED(rv2)) return rv2;
     601            2141 :     return rv3;
     602                 : }
     603                 : 
     604                 : NS_IMETHODIMP
     605           60909 : nsBufferedOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result)
     606                 : {
     607           60909 :     nsresult rv = NS_OK;
     608           60909 :     PRUint32 written = 0;
     609          182750 :     while (count > 0) {
     610           60932 :         PRUint32 amt = NS_MIN(count, mBufferSize - mCursor);
     611           60932 :         if (amt > 0) {
     612           60905 :             memcpy(mBuffer + mCursor, buf + written, amt);
     613           60905 :             written += amt;
     614           60905 :             count -= amt;
     615           60905 :             mCursor += amt;
     616           60905 :             if (mFillPoint < mCursor)
     617           60905 :                 mFillPoint = mCursor;
     618                 :         }
     619                 :         else {
     620              27 :             NS_ASSERTION(mFillPoint, "iloop in nsBufferedOutputStream::Write!");
     621              27 :             rv = Flush();
     622              27 :             if (NS_FAILED(rv)) break;
     623                 :         }
     624                 :     }
     625           60909 :     *result = written;
     626           60909 :     return (written > 0) ? NS_OK : rv;
     627                 : }
     628                 : 
     629                 : NS_IMETHODIMP
     630           10051 : nsBufferedOutputStream::Flush()
     631                 : {
     632                 :     nsresult rv;
     633                 :     PRUint32 amt;
     634           10051 :     if (!mStream) {
     635                 :         // Stream already cancelled/flushed; probably because of error.
     636            1113 :         return NS_OK;
     637                 :     }
     638            8938 :     rv = Sink()->Write(mBuffer, mFillPoint, &amt);
     639            8938 :     if (NS_FAILED(rv)) return rv;
     640            8938 :     mBufferStartOffset += amt;
     641            8938 :     if (amt == mFillPoint) {
     642            8938 :         mFillPoint = mCursor = 0;
     643            8938 :         return NS_OK;   // flushed everything
     644                 :     }
     645                 : 
     646                 :     // slide the remainder down to the start of the buffer
     647                 :     // |<-------------->|<---|----->|
     648                 :     // b                a    c      s
     649               0 :     PRUint32 rem = mFillPoint - amt;
     650               0 :     memcpy(mBuffer, mBuffer + amt, rem);
     651               0 :     mFillPoint = mCursor = rem;
     652               0 :     return NS_ERROR_FAILURE;        // didn't flush all
     653                 : }
     654                 : 
     655                 : // nsISafeOutputStream
     656                 : NS_IMETHODIMP
     657             116 : nsBufferedOutputStream::Finish()
     658                 : {
     659                 :     // flush the stream, to write out any buffered data...
     660             116 :     nsresult rv = nsBufferedOutputStream::Flush();
     661             116 :     if (NS_FAILED(rv))
     662               0 :         NS_WARNING("failed to flush buffered data! possible dataloss");
     663                 : 
     664                 :     // ... and finish the underlying stream...
     665             116 :     if (NS_SUCCEEDED(rv))
     666             116 :         rv = mSafeStream->Finish();
     667                 :     else
     668               0 :         Sink()->Close();
     669                 : 
     670                 :     // ... and close the buffered stream, so any further attempts to flush/close
     671                 :     // the buffered stream won't cause errors.
     672             116 :     nsBufferedStream::Close();
     673                 : 
     674             116 :     return rv;
     675                 : }
     676                 : 
     677                 : static NS_METHOD
     678           35552 : nsReadFromInputStream(nsIOutputStream* outStr,
     679                 :                       void* closure,
     680                 :                       char* toRawSegment, 
     681                 :                       PRUint32 offset,
     682                 :                       PRUint32 count,
     683                 :                       PRUint32 *readCount)
     684                 : {
     685           35552 :     nsIInputStream* fromStream = (nsIInputStream*)closure;
     686           35552 :     return fromStream->Read(toRawSegment, count, readCount);
     687                 : }
     688                 : 
     689                 : NS_IMETHODIMP
     690           33312 : nsBufferedOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
     691                 : {
     692           33312 :     return WriteSegments(nsReadFromInputStream, inStr, count, _retval);
     693                 : }
     694                 : 
     695                 : NS_IMETHODIMP
     696           33312 : nsBufferedOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
     697                 : {
     698           33312 :     *_retval = 0;
     699                 :     nsresult rv;
     700          104416 :     while (count > 0) {
     701           37792 :         PRUint32 left = NS_MIN(count, mBufferSize - mCursor);
     702           37792 :         if (left == 0) {
     703            2240 :             rv = Flush();
     704            2240 :             if (NS_FAILED(rv))
     705               0 :               return rv;
     706                 : 
     707            2240 :             continue;
     708                 :         }
     709                 : 
     710           35552 :         PRUint32 read = 0;
     711           35552 :         rv = reader(this, closure, mBuffer + mCursor, *_retval, left, &read);
     712                 : 
     713           35552 :         if (NS_FAILED(rv)) // If we have written some data, return ok
     714               0 :             return (*_retval > 0) ? NS_OK : rv;
     715           35552 :         mCursor += read;
     716           35552 :         *_retval += read;
     717           35552 :         count -= read;
     718           35552 :         mFillPoint = NS_MAX(mFillPoint, mCursor);
     719                 :     }
     720           33312 :     return NS_OK;
     721                 : }
     722                 : 
     723                 : NS_IMETHODIMP
     724               0 : nsBufferedOutputStream::IsNonBlocking(bool *aNonBlocking)
     725                 : {
     726               0 :     if (mStream)
     727               0 :         return Sink()->IsNonBlocking(aNonBlocking);
     728               0 :     return NS_ERROR_NOT_INITIALIZED;
     729                 : }
     730                 : 
     731                 : NS_IMETHODIMP_(char*)
     732               0 : nsBufferedOutputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask)
     733                 : {
     734               0 :     NS_ASSERTION(mGetBufferCount == 0, "nested GetBuffer!");
     735               0 :     if (mGetBufferCount != 0)
     736               0 :         return nsnull;
     737                 : 
     738               0 :     if (mBufferDisabled)
     739               0 :         return nsnull;
     740                 : 
     741               0 :     char* buf = mBuffer + mCursor;
     742               0 :     PRUint32 rem = mBufferSize - mCursor;
     743               0 :     if (rem == 0) {
     744               0 :         if (NS_FAILED(Flush()))
     745               0 :             return nsnull;
     746               0 :         buf = mBuffer + mCursor;
     747               0 :         rem = mBufferSize - mCursor;
     748                 :     }
     749                 : 
     750               0 :     PRUint32 mod = (NS_PTR_TO_INT32(buf) & aAlignMask);
     751               0 :     if (mod) {
     752               0 :         PRUint32 pad = aAlignMask + 1 - mod;
     753               0 :         if (pad > rem)
     754               0 :             return nsnull;
     755                 : 
     756               0 :         memset(buf, 0, pad);
     757               0 :         mCursor += pad;
     758               0 :         buf += pad;
     759               0 :         rem -= pad;
     760                 :     }
     761                 : 
     762               0 :     if (aLength > rem)
     763               0 :         return nsnull;
     764               0 :     mGetBufferCount++;
     765               0 :     return buf;
     766                 : }
     767                 : 
     768                 : NS_IMETHODIMP_(void)
     769               0 : nsBufferedOutputStream::PutBuffer(char* aBuffer, PRUint32 aLength)
     770                 : {
     771               0 :     NS_ASSERTION(mGetBufferCount == 1, "stray PutBuffer!");
     772               0 :     if (--mGetBufferCount != 0)
     773               0 :         return;
     774                 : 
     775               0 :     NS_ASSERTION(mCursor + aLength <= mBufferSize, "PutBuffer botch");
     776               0 :     mCursor += aLength;
     777               0 :     if (mFillPoint < mCursor)
     778               0 :         mFillPoint = mCursor;
     779                 : }
     780                 : 
     781                 : NS_IMETHODIMP
     782               0 : nsBufferedOutputStream::DisableBuffering()
     783                 : {
     784               0 :     NS_ASSERTION(!mBufferDisabled, "redundant call to DisableBuffering!");
     785               0 :     NS_ASSERTION(mGetBufferCount == 0,
     786                 :                  "DisableBuffer call between GetBuffer and PutBuffer!");
     787               0 :     if (mGetBufferCount != 0)
     788               0 :         return NS_ERROR_UNEXPECTED;
     789                 : 
     790                 :     // Empty the buffer so nsBufferedStream::Tell works.
     791               0 :     nsresult rv = Flush();
     792               0 :     if (NS_FAILED(rv))
     793               0 :         return rv;
     794                 : 
     795               0 :     mBufferDisabled = true;
     796               0 :     return NS_OK;
     797                 : }
     798                 : 
     799                 : NS_IMETHODIMP
     800               0 : nsBufferedOutputStream::EnableBuffering()
     801                 : {
     802               0 :     NS_ASSERTION(mBufferDisabled, "gratuitous call to EnableBuffering!");
     803               0 :     mBufferDisabled = false;
     804               0 :     return NS_OK;
     805                 : }
     806                 : 
     807                 : NS_IMETHODIMP
     808               0 : nsBufferedOutputStream::GetUnbufferedStream(nsISupports* *aStream)
     809                 : {
     810                 :     // Empty the buffer so subsequent i/o trumps any buffered data.
     811               0 :     if (mFillPoint) {
     812               0 :         nsresult rv = Flush();
     813               0 :         if (NS_FAILED(rv))
     814               0 :             return rv;
     815                 :     }
     816                 : 
     817               0 :     *aStream = mStream;
     818               0 :     NS_IF_ADDREF(*aStream);
     819               0 :     return NS_OK;
     820                 : }
     821                 : 
     822                 : ////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.7