LCOV - app.info - xpcom/io/nsMultiplexInputStream.cpp

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-04-21 | 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