From 494aeeca8f17d88668338f39ca6cfea55c1ff9fc Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Wed, 18 Jul 2007 01:54:55 +0000 Subject: [PATCH] Make fastload handle short reads from its underlying buffered stream. Bug 387588, r+sr=biesi git-svn-id: svn://10.0.0.236/trunk@230163 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/io/nsBinaryStream.cpp | 69 ++++++++++++++++++++++++++--- mozilla/xpcom/io/nsFastLoadFile.cpp | 2 +- mozilla/xpcom/io/nsIInputStream.idl | 12 +++-- 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/mozilla/xpcom/io/nsBinaryStream.cpp b/mozilla/xpcom/io/nsBinaryStream.cpp index a19b6924c15..0768288123a 100644 --- a/mozilla/xpcom/io/nsBinaryStream.cpp +++ b/mozilla/xpcom/io/nsBinaryStream.cpp @@ -315,7 +315,30 @@ NS_IMETHODIMP nsBinaryInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead) { NS_ENSURE_STATE(mInputStream); - return mInputStream->Read(aBuffer, aCount, aNumRead); + + // mInputStream might give us short reads, so deal with that. + PRUint32 totalRead = 0; + + PRUint32 bytesRead; + do { + nsresult rv = mInputStream->Read(aBuffer, aCount, &bytesRead); + if (rv == NS_BASE_STREAM_WOULD_BLOCK && totalRead != 0) { + // We already read some data. Return it. + break; + } + + if (NS_FAILED(rv)) { + return rv; + } + + totalRead += bytesRead; + aBuffer += bytesRead; + aCount -= bytesRead; + } while (aCount != 0 && bytesRead != 0); + + *aNumRead = totalRead; + + return NS_OK; } @@ -328,6 +351,8 @@ struct ReadSegmentsClosure { nsIInputStream* mRealInputStream; void* mRealClosure; nsWriteSegmentFun mRealWriter; + nsresult mRealResult; + PRUint32 mBytesRead; // to properly implement aToOffset }; // the thunking function @@ -342,10 +367,17 @@ ReadSegmentForwardingThunk(nsIInputStream* aStream, ReadSegmentsClosure* thunkClosure = reinterpret_cast(aClosure); - return thunkClosure->mRealWriter(thunkClosure->mRealInputStream, - thunkClosure->mRealClosure, - aFromSegment, aToOffset, - aCount, aWriteCount); + NS_ASSERTION(NS_SUCCEEDED(thunkClosure->mRealResult), + "How did this get to be a failure status?"); + + thunkClosure->mRealResult = + thunkClosure->mRealWriter(thunkClosure->mRealInputStream, + thunkClosure->mRealClosure, + aFromSegment, + thunkClosure->mBytesRead + aToOffset, + aCount, aWriteCount); + + return thunkClosure->mRealResult; } @@ -354,9 +386,32 @@ nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUi { NS_ENSURE_STATE(mInputStream); - ReadSegmentsClosure thunkClosure = { this, closure, writer }; + ReadSegmentsClosure thunkClosure = { this, closure, writer, NS_OK, 0 }; - return mInputStream->ReadSegments(ReadSegmentForwardingThunk, &thunkClosure, count, _retval); + // mInputStream might give us short reads, so deal with that. + PRUint32 bytesRead; + do { + nsresult rv = mInputStream->ReadSegments(ReadSegmentForwardingThunk, + &thunkClosure, + count, &bytesRead); + + if (rv == NS_BASE_STREAM_WOULD_BLOCK && thunkClosure.mBytesRead != 0) { + // We already read some data. Return it. + break; + } + + if (NS_FAILED(rv)) { + return rv; + } + + thunkClosure.mBytesRead += bytesRead; + count -= bytesRead; + } while (count != 0 && bytesRead != 0 && + NS_SUCCEEDED(thunkClosure.mRealResult)); + + *_retval = thunkClosure.mBytesRead; + + return NS_OK; } NS_IMETHODIMP diff --git a/mozilla/xpcom/io/nsFastLoadFile.cpp b/mozilla/xpcom/io/nsFastLoadFile.cpp index 4861106c21e..b50881cffc7 100644 --- a/mozilla/xpcom/io/nsFastLoadFile.cpp +++ b/mozilla/xpcom/io/nsFastLoadFile.cpp @@ -579,7 +579,7 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) } } - rv = mInputStream->Read(aBuffer, aCount, aBytesRead); + rv = nsBinaryInputStream::Read(aBuffer, aCount, aBytesRead); if (NS_SUCCEEDED(rv) && entry) { NS_ASSERTION(entry->mBytesLeft >= *aBytesRead, "demux Read underflow!"); diff --git a/mozilla/xpcom/io/nsIInputStream.idl b/mozilla/xpcom/io/nsIInputStream.idl index 3be44c11eef..e494a553e32 100644 --- a/mozilla/xpcom/io/nsIInputStream.idl +++ b/mozilla/xpcom/io/nsIInputStream.idl @@ -48,10 +48,14 @@ interface nsIInputStream; * * @param aInStream stream being read * @param aClosure opaque parameter passed to ReadSegments - * @param aFromSegment pointer to memory owned by the input stream - * @param aToOffset amount already read (since ReadSegments was called) - * @param aCount length of fromSegment - * @param aWriteCount number of bytes read + * @param aFromSegment pointer to memory owned by the input stream. This is + * where the writer function should start consuming data. + * @param aToOffset amount of data already consumed by this writer during this + * ReadSegments call. This is also the sum of the aWriteCount + * returns from this writer over the previous invocations of + * the writer by this ReadSegments call. + * @param aCount Number of bytes available to be read starting at aFromSegment + * @param [out] aWriteCount number of bytes read by this writer function call * * Implementers should return the following: *