Bug 990957 - Seek again in Tell(), Available(), Seek() of nsMultiplexInputStream. r=mcmanus
authorBruce Sun <brsun@mozilla.com>
Mon, 05 May 2014 12:22:16 +0800
changeset 200723 d685863eb71f876767ae116ff02e5bfbb96994b8
parent 200722 e09e3bce7c0de625c4e90870e015c581f8e676e8
child 200724 290f4be587a1b53dab3849d7456123e5cd59015a
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs990957
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 990957 - Seek again in Tell(), Available(), Seek() of nsMultiplexInputStream. r=mcmanus
xpcom/io/nsMultiplexInputStream.cpp
--- a/xpcom/io/nsMultiplexInputStream.cpp
+++ b/xpcom/io/nsMultiplexInputStream.cpp
@@ -71,16 +71,53 @@ NS_IMPL_QUERY_INTERFACE_CI(nsMultiplexIn
                            nsIInputStream,
                            nsISeekableStream,
                            nsIIPCSerializableInputStream)
 NS_IMPL_CI_INTERFACE_GETTER(nsMultiplexInputStream,
                             nsIMultiplexInputStream,
                             nsIInputStream,
                             nsISeekableStream)
 
+static nsresult
+AvailableMaybeSeek(nsIInputStream *stream, uint64_t *_retval)
+{
+    nsresult rv = stream->Available(_retval);
+    if (rv == NS_BASE_STREAM_CLOSED) {
+        // Blindly seek to the current position if Available() returns
+        // NS_BASE_STREAM_CLOSED.
+        // If nsIFileInputStream is closed in Read() due to CLOSE_ON_EOF flag,
+        // Seek() could reopen the file if REOPEN_ON_REWIND flag is set.
+        nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(stream);
+        if (seekable) {
+            nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_CUR, 0);
+            if (NS_SUCCEEDED(rv)) {
+                rv = stream->Available(_retval);
+            }
+        }
+    }
+    return rv;
+}
+
+static nsresult
+TellMaybeSeek(nsISeekableStream *seekable, int64_t *_retval)
+{
+    nsresult rv = seekable->Tell(_retval);
+    if (rv == NS_BASE_STREAM_CLOSED) {
+        // Blindly seek to the current position if Tell() returns
+        // NS_BASE_STREAM_CLOSED.
+        // If nsIFileInputStream is closed in Read() due to CLOSE_ON_EOF flag,
+        // Seek() could reopen the file if REOPEN_ON_REWIND flag is set.
+        nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_CUR, 0);
+        if (NS_SUCCEEDED(rv)) {
+            rv = seekable->Tell(_retval);
+        }
+    }
+    return rv;
+}
+
 nsMultiplexInputStream::nsMultiplexInputStream()
     : mCurrentStream(0),
       mStartedReadingCurrent(false),
       mStatus(NS_OK)
 {
 }
 
 /* readonly attribute unsigned long count; */
@@ -175,17 +212,17 @@ nsMultiplexInputStream::Available(uint64
         return mStatus;
 
     nsresult rv;
     uint64_t avail = 0;
 
     uint32_t len = mStreams.Length();
     for (uint32_t i = mCurrentStream; i < len; i++) {
         uint64_t streamAvail;
-        rv = mStreams[i]->Available(&streamAvail);
+        rv = AvailableMaybeSeek(mStreams[i], &streamAvail);
         if (NS_WARN_IF(NS_FAILED(rv)))
             return rv;
         avail += streamAvail;
     }
     *_retval = avail;
     return NS_OK;
 }
 
@@ -380,17 +417,17 @@ nsMultiplexInputStream::Seek(int32_t aWh
 
             // Get position in current stream
             int64_t streamPos;
             if (i > oldCurrentStream ||
                 (i == oldCurrentStream && !oldStartedReadingCurrent)) {
                 streamPos = 0;
             }
             else {
-                rv = stream->Tell(&streamPos);
+                rv = TellMaybeSeek(stream, &streamPos);
                 if (NS_WARN_IF(NS_FAILED(rv)))
                     return rv;
             }
 
             // See if we need to seek current stream forward or backward
             if (remaining < streamPos) {
                 rv = stream->Seek(NS_SEEK_SET, remaining);
                 if (NS_WARN_IF(NS_FAILED(rv)))
@@ -404,17 +441,17 @@ nsMultiplexInputStream::Seek(int32_t aWh
             else if (remaining > streamPos) {
                 if (i < oldCurrentStream) {
                     // We're already at end so no need to seek this stream
                     remaining -= streamPos;
                     NS_ASSERTION(remaining >= 0, "Remaining invalid");
                 }
                 else {
                     uint64_t avail;
-                    rv = mStreams[i]->Available(&avail);
+                    rv = AvailableMaybeSeek(mStreams[i], &avail);
                     if (NS_WARN_IF(NS_FAILED(rv)))
                         return rv;
 
                     int64_t newPos = XPCOM_MIN(remaining, streamPos + (int64_t)avail);
 
                     rv = stream->Seek(NS_SEEK_SET, newPos);
                     if (NS_WARN_IF(NS_FAILED(rv)))
                         return rv;
@@ -437,17 +474,17 @@ nsMultiplexInputStream::Seek(int32_t aWh
 
     if (aWhence == NS_SEEK_CUR && aOffset > 0) {
         int64_t remaining = aOffset;
         for (uint32_t i = mCurrentStream; remaining && i < mStreams.Length(); ++i) {
             nsCOMPtr<nsISeekableStream> stream =
                 do_QueryInterface(mStreams[i]);
 
             uint64_t avail;
-            rv = mStreams[i]->Available(&avail);
+            rv = AvailableMaybeSeek(mStreams[i], &avail);
             if (NS_WARN_IF(NS_FAILED(rv)))
                 return rv;
 
             int64_t seek = XPCOM_MIN((int64_t)avail, remaining);
 
             rv = stream->Seek(NS_SEEK_CUR, seek);
             if (NS_WARN_IF(NS_FAILED(rv)))
                 return rv;
@@ -463,17 +500,17 @@ nsMultiplexInputStream::Seek(int32_t aWh
 
     if (aWhence == NS_SEEK_CUR && aOffset < 0) {
         int64_t remaining = -aOffset;
         for (uint32_t i = mCurrentStream; remaining && i != (uint32_t)-1; --i) {
             nsCOMPtr<nsISeekableStream> stream =
                 do_QueryInterface(mStreams[i]);
 
             int64_t pos;
-            rv = stream->Tell(&pos);
+            rv = TellMaybeSeek(stream, &pos);
             if (NS_WARN_IF(NS_FAILED(rv)))
                 return rv;
 
             int64_t seek = XPCOM_MIN(pos, remaining);
 
             rv = stream->Seek(NS_SEEK_CUR, -seek);
             if (NS_WARN_IF(NS_FAILED(rv)))
                 return rv;
@@ -515,17 +552,17 @@ nsMultiplexInputStream::Seek(int32_t aWh
             }
 
             // Get position in current stream
             int64_t streamPos;
             if (i < oldCurrentStream) {
                 streamPos = 0;
             } else {
                 uint64_t avail;
-                rv = mStreams[i]->Available(&avail);
+                rv = AvailableMaybeSeek(mStreams[i], &avail);
                 if (NS_WARN_IF(NS_FAILED(rv)))
                     return rv;
 
                 streamPos = avail;
             }
 
             // See if we have enough data in the current stream.
             if (DeprecatedAbs(remaining) < streamPos) {
@@ -539,17 +576,17 @@ nsMultiplexInputStream::Seek(int32_t aWh
                 remaining = 0;
             } else if (DeprecatedAbs(remaining) > streamPos) {
                 if (i > oldCurrentStream ||
                     (i == oldCurrentStream && !oldStartedReadingCurrent)) {
                     // We're already at start so no need to seek this stream
                     remaining += streamPos;
                 } else {
                     int64_t avail;
-                    rv = stream->Tell(&avail);
+                    rv = TellMaybeSeek(stream, &avail);
                     if (NS_WARN_IF(NS_FAILED(rv)))
                         return rv;
 
                     int64_t newPos = streamPos + XPCOM_MIN(avail, DeprecatedAbs(remaining));
 
                     rv = stream->Seek(NS_SEEK_END, -newPos);
                     if (NS_WARN_IF(NS_FAILED(rv)))
                         return rv;
@@ -585,17 +622,17 @@ nsMultiplexInputStream::Tell(int64_t *_r
     uint32_t i, last;
     last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream;
     for (i = 0; i < last; ++i) {
         nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStreams[i]);
         if (NS_WARN_IF(!stream))
             return NS_ERROR_NO_INTERFACE;
 
         int64_t pos;
-        rv = stream->Tell(&pos);
+        rv = TellMaybeSeek(stream, &pos);
         if (NS_WARN_IF(NS_FAILED(rv)))
             return rv;
         ret64 += pos;
     }
     *_retval =  ret64;
 
     return NS_OK;
 }