LCOV - code coverage report
Current view: directory - xpcom/io - nsMultiplexInputStream.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 193 50 25.9 %
Date: 2012-06-02 Functions: 23 10 43.5 %

       1                 : /* -*- Mode: C++; tab-width: 4; 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 frightening to behold.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Jonas Sicking.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Jonas Sicking <sicking@bigfoot.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                 : /**
      40                 :  * The multiplex stream concatenates a list of input streams into a single
      41                 :  * stream.
      42                 :  */
      43                 : 
      44                 : #include "IPC/IPCMessageUtils.h"
      45                 : #include "mozilla/net/NeckoMessageUtils.h"
      46                 : 
      47                 : #include "nsMultiplexInputStream.h"
      48                 : #include "nsIMultiplexInputStream.h"
      49                 : #include "nsISeekableStream.h"
      50                 : #include "nsCOMPtr.h"
      51                 : #include "nsCOMArray.h"
      52                 : #include "nsIIPCSerializable.h"
      53                 : #include "nsIClassInfoImpl.h"
      54                 : 
      55                 : class nsMultiplexInputStream : public nsIMultiplexInputStream,
      56                 :                                public nsISeekableStream,
      57                 :                                public nsIIPCSerializable
      58                 : {
      59                 : public:
      60                 :     nsMultiplexInputStream();
      61                 : 
      62                 :     NS_DECL_ISUPPORTS
      63                 :     NS_DECL_NSIINPUTSTREAM
      64                 :     NS_DECL_NSIMULTIPLEXINPUTSTREAM
      65                 :     NS_DECL_NSISEEKABLESTREAM
      66                 :     NS_DECL_NSIIPCSERIALIZABLE
      67                 : 
      68                 : private:
      69             387 :     ~nsMultiplexInputStream() {}
      70                 : 
      71                 :     struct ReadSegmentsState {
      72                 :         nsIInputStream* mThisStream;
      73                 :         PRUint32 mOffset;
      74                 :         nsWriteSegmentFun mWriter;
      75                 :         void* mClosure;
      76                 :         bool mDone;
      77                 :     };
      78                 : 
      79                 :     static NS_METHOD ReadSegCb(nsIInputStream* aIn, void* aClosure,
      80                 :                                const char* aFromRawSegment, PRUint32 aToOffset,
      81                 :                                PRUint32 aCount, PRUint32 *aWriteCount);
      82                 :     
      83                 :     nsCOMArray<nsIInputStream> mStreams;
      84                 :     PRUint32 mCurrentStream;
      85                 :     bool mStartedReadingCurrent;
      86                 :     nsresult mStatus;
      87                 : };
      88                 : 
      89            1551 : NS_IMPL_THREADSAFE_ADDREF(nsMultiplexInputStream)
      90            1938 : NS_IMPL_THREADSAFE_RELEASE(nsMultiplexInputStream)
      91                 : 
      92                 : NS_IMPL_CLASSINFO(nsMultiplexInputStream, NULL, nsIClassInfo::THREADSAFE,
      93                 :                   NS_MULTIPLEXINPUTSTREAM_CID)
      94                 : 
      95             784 : NS_IMPL_QUERY_INTERFACE4_CI(nsMultiplexInputStream,
      96                 :                             nsIMultiplexInputStream,
      97                 :                             nsIInputStream,
      98                 :                             nsISeekableStream,
      99               1 :                             nsIIPCSerializable)
     100               1 : NS_IMPL_CI_INTERFACE_GETTER4(nsMultiplexInputStream,
     101                 :                              nsIMultiplexInputStream,
     102                 :                              nsIInputStream,
     103                 :                              nsISeekableStream,
     104               1 :                              nsIIPCSerializable)
     105                 : 
     106             387 : nsMultiplexInputStream::nsMultiplexInputStream()
     107                 :     : mCurrentStream(0),
     108                 :       mStartedReadingCurrent(false),
     109             387 :       mStatus(NS_OK)
     110                 : {
     111             387 : }
     112                 : 
     113                 : /* readonly attribute unsigned long count; */
     114                 : NS_IMETHODIMP
     115               0 : nsMultiplexInputStream::GetCount(PRUint32 *aCount)
     116                 : {
     117               0 :     *aCount = mStreams.Count();
     118               0 :     return NS_OK;
     119                 : }
     120                 : 
     121                 : /* void appendStream (in nsIInputStream stream); */
     122                 : NS_IMETHODIMP
     123             776 : nsMultiplexInputStream::AppendStream(nsIInputStream *aStream)
     124                 : {
     125             776 :     return mStreams.AppendObject(aStream) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     126                 : }
     127                 : 
     128                 : /* void insertStream (in nsIInputStream stream, in unsigned long index); */
     129                 : NS_IMETHODIMP
     130               0 : nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, PRUint32 aIndex)
     131                 : {
     132               0 :     bool result = mStreams.InsertObjectAt(aStream, aIndex);
     133               0 :     NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
     134               0 :     if (mCurrentStream > aIndex ||
     135                 :         (mCurrentStream == aIndex && mStartedReadingCurrent))
     136               0 :         ++mCurrentStream;
     137               0 :     return NS_OK;
     138                 : }
     139                 : 
     140                 : /* void removeStream (in unsigned long index); */
     141                 : NS_IMETHODIMP
     142               0 : nsMultiplexInputStream::RemoveStream(PRUint32 aIndex)
     143                 : {
     144               0 :     bool result = mStreams.RemoveObjectAt(aIndex);
     145               0 :     NS_ENSURE_TRUE(result, NS_ERROR_NOT_AVAILABLE);
     146               0 :     if (mCurrentStream > aIndex)
     147               0 :         --mCurrentStream;
     148               0 :     else if (mCurrentStream == aIndex)
     149               0 :         mStartedReadingCurrent = false;
     150                 : 
     151               0 :     return NS_OK;
     152                 : }
     153                 : 
     154                 : /* nsIInputStream getStream (in unsigned long index); */
     155                 : NS_IMETHODIMP
     156               0 : nsMultiplexInputStream::GetStream(PRUint32 aIndex, nsIInputStream **_retval)
     157                 : {
     158               0 :     *_retval = mStreams.SafeObjectAt(aIndex);
     159               0 :     NS_ENSURE_TRUE(*_retval, NS_ERROR_NOT_AVAILABLE);
     160                 : 
     161               0 :     NS_ADDREF(*_retval);
     162               0 :     return NS_OK;
     163                 : }
     164                 : 
     165                 : /* void close (); */
     166                 : NS_IMETHODIMP
     167               0 : nsMultiplexInputStream::Close()
     168                 : {
     169               0 :     mStatus = NS_BASE_STREAM_CLOSED;
     170                 : 
     171               0 :     nsresult rv = NS_OK;
     172                 : 
     173               0 :     PRUint32 len = mStreams.Count();
     174               0 :     for (PRUint32 i = 0; i < len; ++i) {
     175               0 :         nsresult rv2 = mStreams[i]->Close();
     176                 :         // We still want to close all streams, but we should return an error
     177               0 :         if (NS_FAILED(rv2))
     178               0 :             rv = rv2;
     179                 :     }
     180               0 :     return rv;
     181                 : }
     182                 : 
     183                 : /* unsigned long available (); */
     184                 : NS_IMETHODIMP
     185             390 : nsMultiplexInputStream::Available(PRUint32 *_retval)
     186                 : {
     187             390 :     if (NS_FAILED(mStatus))
     188               0 :         return mStatus;
     189                 : 
     190                 :     nsresult rv;
     191             390 :     PRUint32 avail = 0;
     192                 : 
     193             390 :     PRUint32 len = mStreams.Count();
     194            1175 :     for (PRUint32 i = mCurrentStream; i < len; i++) {
     195                 :         PRUint32 streamAvail;
     196             785 :         rv = mStreams[i]->Available(&streamAvail);
     197             785 :         NS_ENSURE_SUCCESS(rv, rv);
     198             785 :         avail += streamAvail;
     199                 :     }
     200             390 :     *_retval = avail;
     201             390 :     return NS_OK;
     202                 : }
     203                 : 
     204                 : /* [noscript] unsigned long read (in charPtr buf, in unsigned long count); */
     205                 : NS_IMETHODIMP
     206            1161 : nsMultiplexInputStream::Read(char * aBuf, PRUint32 aCount, PRUint32 *_retval)
     207                 : {
     208                 :     // It is tempting to implement this method in terms of ReadSegments, but
     209                 :     // that would prevent this class from being used with streams that only
     210                 :     // implement Read (e.g., file streams).
     211                 :  
     212            1161 :     *_retval = 0;
     213                 : 
     214            1161 :     if (mStatus == NS_BASE_STREAM_CLOSED)
     215               0 :         return NS_OK;
     216            1161 :     if (NS_FAILED(mStatus))
     217               0 :         return mStatus;
     218                 :  
     219            1161 :     nsresult rv = NS_OK;
     220                 : 
     221            1161 :     PRUint32 len = mStreams.Count();
     222            3873 :     while (mCurrentStream < len && aCount) {
     223                 :         PRUint32 read;
     224            1551 :         rv = mStreams[mCurrentStream]->Read(aBuf, aCount, &read);
     225                 : 
     226                 :         // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
     227                 :         // (This is a bug in those stream implementations)
     228            1551 :         if (rv == NS_BASE_STREAM_CLOSED) {
     229               0 :             NS_NOTREACHED("Input stream's Read method returned NS_BASE_STREAM_CLOSED");
     230               0 :             rv = NS_OK;
     231               0 :             read = 0;
     232                 :         }
     233            1551 :         else if (NS_FAILED(rv))
     234               0 :             break;
     235                 : 
     236            1551 :         if (read == 0) {
     237             776 :             ++mCurrentStream;
     238             776 :             mStartedReadingCurrent = false;
     239                 :         }
     240                 :         else {
     241             775 :             NS_ASSERTION(aCount >= read, "Read more than requested");
     242             775 :             *_retval += read;
     243             775 :             aCount -= read;
     244             775 :             aBuf += read;
     245             775 :             mStartedReadingCurrent = true;
     246                 :         }
     247                 :     }
     248            1161 :     return *_retval ? NS_OK : rv;
     249                 : }
     250                 : 
     251                 : /* [noscript] unsigned long readSegments (in nsWriteSegmentFun writer,
     252                 :  *                                        in voidPtr closure,
     253                 :  *                                        in unsigned long count); */
     254                 : NS_IMETHODIMP
     255               0 : nsMultiplexInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
     256                 :                                      PRUint32 aCount, PRUint32 *_retval)
     257                 : {
     258               0 :     if (mStatus == NS_BASE_STREAM_CLOSED) {
     259               0 :         *_retval = 0;
     260               0 :         return NS_OK;
     261                 :     }
     262               0 :     if (NS_FAILED(mStatus))
     263               0 :         return mStatus;
     264                 : 
     265               0 :     NS_ASSERTION(aWriter, "missing aWriter");
     266                 : 
     267               0 :     nsresult rv = NS_OK;
     268                 :     ReadSegmentsState state;
     269               0 :     state.mThisStream = this;
     270               0 :     state.mOffset = 0;
     271               0 :     state.mWriter = aWriter;
     272               0 :     state.mClosure = aClosure;
     273               0 :     state.mDone = false;
     274                 :     
     275               0 :     PRUint32 len = mStreams.Count();
     276               0 :     while (mCurrentStream < len && aCount) {
     277                 :         PRUint32 read;
     278               0 :         rv = mStreams[mCurrentStream]->ReadSegments(ReadSegCb, &state, aCount, &read);
     279                 : 
     280                 :         // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
     281                 :         // (This is a bug in those stream implementations)
     282               0 :         if (rv == NS_BASE_STREAM_CLOSED) {
     283               0 :             NS_NOTREACHED("Input stream's Read method returned NS_BASE_STREAM_CLOSED");
     284               0 :             rv = NS_OK;
     285               0 :             read = 0;
     286                 :         }
     287                 : 
     288                 :         // if |aWriter| decided to stop reading segments...
     289               0 :         if (state.mDone || NS_FAILED(rv))
     290               0 :             break;
     291                 : 
     292                 :         // if stream is empty, then advance to the next stream.
     293               0 :         if (read == 0) {
     294               0 :             ++mCurrentStream;
     295               0 :             mStartedReadingCurrent = false;
     296                 :         }
     297                 :         else {
     298               0 :             NS_ASSERTION(aCount >= read, "Read more than requested");
     299               0 :             state.mOffset += read;
     300               0 :             aCount -= read;
     301               0 :             mStartedReadingCurrent = true;
     302                 :         }
     303                 :     }
     304                 : 
     305                 :     // if we successfully read some data, then this call succeeded.
     306               0 :     *_retval = state.mOffset;
     307               0 :     return state.mOffset ? NS_OK : rv;
     308                 : }
     309                 : 
     310                 : NS_METHOD
     311               0 : nsMultiplexInputStream::ReadSegCb(nsIInputStream* aIn, void* aClosure,
     312                 :                                   const char* aFromRawSegment,
     313                 :                                   PRUint32 aToOffset, PRUint32 aCount,
     314                 :                                   PRUint32 *aWriteCount)
     315                 : {
     316                 :     nsresult rv;
     317               0 :     ReadSegmentsState* state = (ReadSegmentsState*)aClosure;
     318                 :     rv = (state->mWriter)(state->mThisStream,
     319                 :                           state->mClosure,
     320                 :                           aFromRawSegment,
     321                 :                           aToOffset + state->mOffset,
     322                 :                           aCount,
     323               0 :                           aWriteCount);
     324               0 :     if (NS_FAILED(rv))
     325               0 :         state->mDone = true;
     326               0 :     return rv;
     327                 : }
     328                 : 
     329                 : /* readonly attribute boolean nonBlocking; */
     330                 : NS_IMETHODIMP
     331               0 : nsMultiplexInputStream::IsNonBlocking(bool *aNonBlocking)
     332                 : {
     333               0 :     PRUint32 len = mStreams.Count();
     334               0 :     if (len == 0) {
     335                 :         // Claim to be non-blocking, since we won't block the caller.
     336                 :         // On the other hand we'll never return NS_BASE_STREAM_WOULD_BLOCK,
     337                 :         // so maybe we should claim to be blocking?  It probably doesn't
     338                 :         // matter in practice.
     339               0 :         *aNonBlocking = true;
     340               0 :         return NS_OK;
     341                 :     }
     342               0 :     for (PRUint32 i = 0; i < len; ++i) {
     343               0 :         nsresult rv = mStreams[i]->IsNonBlocking(aNonBlocking);
     344               0 :         NS_ENSURE_SUCCESS(rv, rv);
     345                 :         // If one is non-blocking the entire stream becomes non-blocking
     346                 :         // (except that we don't implement nsIAsyncInputStream, so there's
     347                 :         //  not much for the caller to do if Read returns "would block")
     348               0 :         if (*aNonBlocking)
     349               0 :             return NS_OK;
     350                 :     }
     351               0 :     return NS_OK;
     352                 : }
     353                 : 
     354                 : /* void seek (in PRInt32 whence, in PRInt32 offset); */
     355                 : NS_IMETHODIMP
     356               0 : nsMultiplexInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset)
     357                 : {
     358               0 :     if (NS_FAILED(mStatus))
     359               0 :         return mStatus;
     360                 : 
     361                 :     nsresult rv;
     362                 : 
     363                 :     // rewinding to start is easy, and should be the most common case
     364               0 :     if (aWhence == NS_SEEK_SET && aOffset == 0)
     365                 :     {
     366                 :         PRUint32 i, last;
     367               0 :         last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream;
     368               0 :         for (i = 0; i < last; ++i) {
     369               0 :             nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStreams[i]);
     370               0 :             NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE);
     371                 : 
     372               0 :             rv = stream->Seek(NS_SEEK_SET, 0);
     373               0 :             NS_ENSURE_SUCCESS(rv, rv);
     374                 :         }
     375               0 :         mCurrentStream = 0;
     376               0 :         mStartedReadingCurrent = false;
     377               0 :         return NS_OK;
     378                 :     }
     379                 : 
     380                 :     // other Seeks not implemented yet
     381               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     382                 : }
     383                 : 
     384                 : /* PRUint32 tell (); */
     385                 : NS_IMETHODIMP
     386               0 : nsMultiplexInputStream::Tell(PRInt64 *_retval)
     387                 : {
     388               0 :     if (NS_FAILED(mStatus))
     389               0 :         return mStatus;
     390                 : 
     391                 :     nsresult rv;
     392               0 :     PRInt64 ret64 = 0;
     393                 :     PRUint32 i, last;
     394               0 :     last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream;
     395               0 :     for (i = 0; i < last; ++i) {
     396               0 :         nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStreams[i]);
     397               0 :         NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE);
     398                 : 
     399                 :         PRInt64 pos;
     400               0 :         rv = stream->Tell(&pos);
     401               0 :         NS_ENSURE_SUCCESS(rv, rv);
     402               0 :         ret64 += pos;
     403                 :     }
     404               0 :     *_retval =  ret64;
     405                 : 
     406               0 :     return NS_OK;
     407                 : }
     408                 : 
     409                 : /* void setEOF (); */
     410                 : NS_IMETHODIMP
     411               0 : nsMultiplexInputStream::SetEOF()
     412                 : {
     413               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     414                 : }
     415                 : 
     416                 : nsresult
     417             387 : nsMultiplexInputStreamConstructor(nsISupports *outer,
     418                 :                                   REFNSIID iid,
     419                 :                                   void **result)
     420                 : {
     421             387 :     *result = nsnull;
     422                 : 
     423             387 :     if (outer)
     424               0 :         return NS_ERROR_NO_AGGREGATION;
     425                 : 
     426             387 :     nsMultiplexInputStream *inst = new nsMultiplexInputStream();
     427             387 :     if (!inst)
     428               0 :         return NS_ERROR_OUT_OF_MEMORY;
     429                 : 
     430             387 :     NS_ADDREF(inst);
     431             387 :     nsresult rv = inst->QueryInterface(iid, result);
     432             387 :     NS_RELEASE(inst);
     433                 : 
     434             387 :     return rv;
     435                 : }
     436                 : 
     437                 : bool
     438               0 : nsMultiplexInputStream::Read(const IPC::Message *aMsg, void **aIter)
     439                 : {
     440                 :     using IPC::ReadParam;
     441                 : 
     442                 :     PRUint32 count;
     443               0 :     if (!ReadParam(aMsg, aIter, &count))
     444               0 :         return false;
     445                 : 
     446               0 :     for (PRUint32 i = 0; i < count; i++) {
     447               0 :         IPC::InputStream inputStream;
     448               0 :         if (!ReadParam(aMsg, aIter, &inputStream))
     449               0 :             return false;
     450                 : 
     451               0 :         nsCOMPtr<nsIInputStream> stream(inputStream);
     452               0 :         nsresult rv = AppendStream(stream);
     453               0 :         if (NS_FAILED(rv))
     454               0 :             return false;
     455                 :     }
     456                 : 
     457               0 :     if (!ReadParam(aMsg, aIter, &mCurrentStream) ||
     458               0 :         !ReadParam(aMsg, aIter, &mStartedReadingCurrent) ||
     459               0 :         !ReadParam(aMsg, aIter, &mStatus))
     460               0 :         return false;
     461                 : 
     462               0 :     return true;
     463                 : }
     464                 : 
     465                 : void
     466               0 : nsMultiplexInputStream::Write(IPC::Message *aMsg)
     467                 : {
     468                 :     using IPC::WriteParam;
     469                 : 
     470               0 :     PRUint32 count = mStreams.Count();
     471               0 :     WriteParam(aMsg, count);
     472                 : 
     473               0 :     for (PRUint32 i = 0; i < count; i++) {
     474               0 :         IPC::InputStream inputStream(mStreams.ObjectAt(i));
     475               0 :         WriteParam(aMsg, inputStream);
     476                 :     }
     477                 : 
     478               0 :     WriteParam(aMsg, mCurrentStream);
     479               0 :     WriteParam(aMsg, mStartedReadingCurrent);
     480               0 :     WriteParam(aMsg, mStatus);
     481               0 : }

Generated by: LCOV version 1.7