diff --git a/mozilla/xpcom/io/nsIInputStream.idl b/mozilla/xpcom/io/nsIInputStream.idl index 275d0c518eb..d90a8824f1d 100644 --- a/mozilla/xpcom/io/nsIInputStream.idl +++ b/mozilla/xpcom/io/nsIInputStream.idl @@ -55,11 +55,9 @@ interface nsIInputStream; * Implementers should return the following: * * @return NS_OK and (*aWriteCount > 0) if consumed some data - * @return NS_BASE_STREAM_WOULD_BLOCK if not interested in consuming any data - * @return on failure + * @return if not interested in consuming any data * - * Errors are passed to the caller of ReadSegments, unless aToOffset is - * greater than zero. + * Errors are never passed to the caller of ReadSegments. * * NOTE: returning NS_OK and (*aWriteCount = 0) has undefined behavior. * @@ -99,7 +97,7 @@ interface nsIInputStream : nsISupports * @param aBuf the buffer into which the data is to be read * @param aCount the maximum number of bytes to be read * - * @return number of bytes read + * @return number of bytes read (may be less than aCount). * @return 0 if reached end of file * * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from the input stream would @@ -109,15 +107,18 @@ interface nsIInputStream : nsISupports [noscript] unsigned long read(in charPtr aBuf, in unsigned long aCount); /** - * Low-level read method that has access to the stream's underlying buffer. The - * writer function may be called multiple times for segmented buffers. + * Low-level read method that has access to the stream's underlying buffer. + * The writer function may be called multiple times for segmented buffers. + * ReadSegments is expected to keep calling the writer until either there is + * nothing left to read or the writer returns an error. ReadSegments should + * not call the writer with zero bytes to consume. * * @param aWriter the "consumer" of the data to be read * @param aClosure opaque parameter passed to writer * @param aCount the maximum number of bytes to be read * - * @return number of bytes read - * @return 0 if reached end of file + * @return number of bytes read (may be less than aCount) + * @return 0 if reached end of file (or if aWriter refused to consume data) * * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from the input stream would * block the calling thread (non-blocking mode only) diff --git a/mozilla/xpcom/io/nsIOutputStream.idl b/mozilla/xpcom/io/nsIOutputStream.idl index 15843abd160..771c362311d 100644 --- a/mozilla/xpcom/io/nsIOutputStream.idl +++ b/mozilla/xpcom/io/nsIOutputStream.idl @@ -57,11 +57,9 @@ interface nsIInputStream; * * @return NS_OK and (*aReadCount > 0) if successfully provided some data * @return NS_OK and (*aReadCount = 0) or - * @return NS_BASE_STREAM_WOULD_BLOCK if not interested in providing any data - * @return on failure + * @return if not interested in providing any data * - * Errors are passed to the caller of WriteSegments, unless aFromOffset is - * greater than zero. + * Errors are never passed to the caller of WriteSegments. * * @status FROZEN */ @@ -105,7 +103,7 @@ interface nsIOutputStream : nsISupports * @param aBuf the buffer containing the data to be written * @param aCount the maximum number of bytes to be written * - * @return number of bytes written + * @return number of bytes written (may be less than aCount) * * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would * block the calling thread (non-blocking mode only) @@ -119,7 +117,7 @@ interface nsIOutputStream : nsISupports * @param aFromStream the stream containing the data to be written * @param aCount the maximum number of bytes to be written * - * @return number of bytes written + * @return number of bytes written (may be less than aCount) * * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would * block the calling thread (non-blocking mode only) @@ -135,14 +133,17 @@ interface nsIOutputStream : nsISupports in unsigned long aCount); /** - * Low-level write method that has access to the stream's underlying buffer. The - * reader function may be called multiple times for segmented buffers. + * Low-level write method that has access to the stream's underlying buffer. + * The reader function may be called multiple times for segmented buffers. + * WriteSegments is expected to keep calling the reader until either there + * is nothing left to write or the reader returns an error. WriteSegments + * should not call the reader with zero bytes to provide. * * @param aReader the "provider" of the data to be written * @param aClosure opaque parameter passed to reader * @param aCount the maximum number of bytes to be written * - * @return number of bytes written + * @return number of bytes written (may be less than aCount) * * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would * block the calling thread (non-blocking mode only) @@ -157,6 +158,9 @@ interface nsIOutputStream : nsISupports /** * @return true if stream is non-blocking + * + * NOTE: writing to a blocking output stream will block the calling thread + * until all given data can be consumed by the stream. */ boolean isNonBlocking(); }; diff --git a/mozilla/xpcom/io/nsMultiplexInputStream.cpp b/mozilla/xpcom/io/nsMultiplexInputStream.cpp index d7c0b371617..26d74fdaae1 100644 --- a/mozilla/xpcom/io/nsMultiplexInputStream.cpp +++ b/mozilla/xpcom/io/nsMultiplexInputStream.cpp @@ -187,34 +187,38 @@ nsMultiplexInputStream::Available(PRUint32 *_retval) NS_IMETHODIMP nsMultiplexInputStream::Read(char * aBuf, PRUint32 aCount, PRUint32 *_retval) { - nsresult rv; - PRUint32 len; + nsresult rv = NS_OK; + PRUint32 len, read; + + *_retval = 0; mStreams.Count(&len); - PRUint32 read = 0; - while (mCurrentStream < len && aCount > 0) { + while (mCurrentStream < len && aCount) { nsCOMPtr stream(do_QueryElementAt(&mStreams, mCurrentStream)); - rv = stream->Read(aBuf, aCount, _retval); - if (rv == NS_BASE_STREAM_WOULD_BLOCK) { - *_retval = read; - return read == 0 ? NS_BASE_STREAM_WOULD_BLOCK : NS_OK; + rv = stream->Read(aBuf, aCount, &read); + + // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF. + if (rv == NS_BASE_STREAM_CLOSED) { + rv = NS_OK; + read = 0; } - NS_ENSURE_SUCCESS(rv, rv); - if (!*_retval) { - // we're done with this stream, proceed to next + else if (NS_FAILED(rv)) + break; + + if (read == 0) { ++mCurrentStream; mStartedReadingCurrent = PR_FALSE; } else { - read += *_retval; - aBuf += *_retval; - aCount -= *_retval; + NS_ASSERTION(aCount >= read, "Read more than requested"); + *_retval += read; + aCount -= read; + aBuf += read; mStartedReadingCurrent = PR_TRUE; } } - *_retval = read; - return NS_OK; + return *_retval ? NS_OK : rv; } /* [noscript] unsigned long readSegments (in nsWriteSegmentFun writer, @@ -226,7 +230,7 @@ nsMultiplexInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, { NS_ASSERTION(aWriter, "missing aWriter"); - nsresult rv; + nsresult rv = NS_OK; ReadSegmentsState state; state.mThisStream = this; state.mOffset = 0; @@ -236,46 +240,38 @@ nsMultiplexInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, PRUint32 len; mStreams.Count(&len); - while (mCurrentStream < len) { + while (mCurrentStream < len && aCount) { nsCOMPtr stream(do_QueryElementAt(&mStreams, mCurrentStream)); PRUint32 read; rv = stream->ReadSegments(ReadSegCb, &state, aCount, &read); - // If we got an NS_BASE_STREAM_WOULD_BLOCK error since the reader - // didn't want any more data. This might not be an error for us if - // data was read from a previous stream in this run - if (state.mDone && rv == NS_BASE_STREAM_WOULD_BLOCK && - !read && state.mOffset) - break; - // If the return value is NS_BASE_STREAM_CLOSED, we are done with this - // stream. + // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF. if (rv == NS_BASE_STREAM_CLOSED) { - ++mCurrentStream; - mStartedReadingCurrent = PR_FALSE; - continue; + rv = NS_OK; + read = 0; } - NS_ENSURE_SUCCESS(rv, rv); - NS_ASSERTION(aCount >= read, "Read more than requested"); - mStartedReadingCurrent = PR_TRUE; - state.mOffset += read; - aCount -= read; - if (state.mDone || // writer doesn't want anymore data - aCount == 0) // the current stream still has data + // if |aWriter| decided to stop reading segments... + if (state.mDone || NS_FAILED(rv)) break; - - // If the writer accepted all data but we didn't read any, this stream - // is finished. Go on to the next stream. These aren't the droids - // you're looking for. + + // if stream is empty, then advance to the next stream. if (read == 0) { ++mCurrentStream; mStartedReadingCurrent = PR_FALSE; } + else { + NS_ASSERTION(aCount >= read, "Read more than requested"); + state.mOffset += read; + aCount -= read; + mStartedReadingCurrent = PR_TRUE; + } } + // if we successfully read some data, then this call succeeded. *_retval = state.mOffset; - return NS_OK; + return state.mOffset ? NS_OK : rv; } NS_METHOD @@ -292,10 +288,8 @@ nsMultiplexInputStream::ReadSegCb(nsIInputStream* aIn, void* aClosure, aToOffset + state->mOffset, aCount, aWriteCount); - if (rv == NS_BASE_STREAM_WOULD_BLOCK || - (NS_SUCCEEDED(rv) && *aWriteCount < aCount && aCount != 0)) + if (NS_FAILED(rv)) state->mDone = PR_TRUE; - return rv; } diff --git a/mozilla/xpcom/io/nsStreamUtils.cpp b/mozilla/xpcom/io/nsStreamUtils.cpp index cb20dfe5ba8..2fb7c927f1b 100644 --- a/mozilla/xpcom/io/nsStreamUtils.cpp +++ b/mozilla/xpcom/io/nsStreamUtils.cpp @@ -408,10 +408,10 @@ NS_AsyncCopy(nsIAsyncInputStream *source, // // fire off two async copies :-) // - rv = NS_AsyncCopy(source, pipeOut, segmentSize, PR_FALSE, PR_TRUE); + rv = NS_AsyncCopy(source, pipeOut, PR_FALSE, PR_TRUE, segmentSize, 1, segmentAlloc); if (NS_FAILED(rv)) return rv; - rv = NS_AsyncCopy(pipeIn, sink, segmentSize, PR_TRUE, PR_FALSE); + rv = NS_AsyncCopy(pipeIn, sink, PR_TRUE, PR_FALSE, segmentSize, 1, segmentAlloc); // maybe calling NS_AsyncCopy twice is a bad idea! NS_ASSERTION(NS_SUCCEEDED(rv), "uh-oh"); diff --git a/mozilla/xpcom/io/nsStringStream.cpp b/mozilla/xpcom/io/nsStringStream.cpp index 914093f9a1f..b40289c2a16 100644 --- a/mozilla/xpcom/io/nsStringStream.cpp +++ b/mozilla/xpcom/io/nsStringStream.cpp @@ -312,6 +312,10 @@ class ConstCharImpl PRUint32 aCount, PRUint32 *result) { nsresult rv; PRInt32 maxCount = mLength - mOffset; + if (maxCount == 0) { + *result = 0; + return NS_OK; + } if ((PRInt32)aCount > maxCount) aCount = maxCount; rv = writer(this, closure, mConstString + mOffset,