mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 799234 - Fix seeking within a single stream's range within a multiplexed stream. r=biesi,amarchesini
--HG-- extra : rebase_source : 73658a2351a9a0a9476f6d1f4f6e5d8a77413eb5
This commit is contained in:
parent
24a17d4186
commit
4bedd96175
@ -87,10 +87,22 @@ nsMultiplexInputStream::GetCount(uint32_t *aCount)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
SeekableStreamAtBeginning(nsIInputStream *aStream)
|
||||
{
|
||||
int64_t streamPos;
|
||||
nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(aStream);
|
||||
if (stream && NS_SUCCEEDED(stream->Tell(&streamPos)) && streamPos != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* void appendStream (in nsIInputStream stream); */
|
||||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::AppendStream(nsIInputStream *aStream)
|
||||
{
|
||||
NS_ASSERTION(SeekableStreamAtBeginning(aStream), "Appended stream not at beginning.");
|
||||
return mStreams.AppendElement(aStream) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
@ -98,6 +110,7 @@ nsMultiplexInputStream::AppendStream(nsIInputStream *aStream)
|
||||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, uint32_t aIndex)
|
||||
{
|
||||
NS_ASSERTION(SeekableStreamAtBeginning(aStream), "Inserted stream not at beginning.");
|
||||
bool result = mStreams.InsertElementAt(aIndex, aStream);
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
|
||||
if (mCurrentStream > aIndex ||
|
||||
@ -378,23 +391,27 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
remaining = 0;
|
||||
}
|
||||
else if (remaining > streamPos) {
|
||||
uint64_t avail;
|
||||
rv = mStreams[i]->Available(&avail);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int64_t newPos;
|
||||
if (remaining < (streamPos + (int64_t) avail)) {
|
||||
newPos = remaining - streamPos;
|
||||
remaining = 0;
|
||||
} else {
|
||||
newPos = streamPos + (int64_t)avail;
|
||||
remaining -= streamPos + avail;
|
||||
if (i < oldCurrentStream) {
|
||||
// We're already at end so no need to seek this stream
|
||||
remaining -= streamPos;
|
||||
NS_ASSERTION(remaining >= 0, "Remaining invalid");
|
||||
}
|
||||
rv = stream->Seek(NS_SEEK_CUR, newPos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
else {
|
||||
uint64_t avail;
|
||||
rv = mStreams[i]->Available(&avail);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentStream = i;
|
||||
mStartedReadingCurrent = true;
|
||||
int64_t newPos = NS_MIN(remaining, streamPos + (int64_t)avail);
|
||||
|
||||
rv = stream->Seek(NS_SEEK_SET, newPos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentStream = i;
|
||||
mStartedReadingCurrent = true;
|
||||
|
||||
remaining -= newPos;
|
||||
NS_ASSERTION(remaining >= 0, "Remaining invalid");
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(remaining == streamPos, "Huh?");
|
||||
|
@ -13,158 +13,157 @@ const data = "0123456789";
|
||||
const count = 10;
|
||||
|
||||
function test_multiplex_streams() {
|
||||
try {
|
||||
var MultiplexStream = CC("@mozilla.org/io/multiplex-input-stream;1",
|
||||
"nsIMultiplexInputStream");
|
||||
do_check_eq(1, 1);
|
||||
var MultiplexStream = CC("@mozilla.org/io/multiplex-input-stream;1",
|
||||
"nsIMultiplexInputStream");
|
||||
do_check_eq(1, 1);
|
||||
|
||||
var BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream");
|
||||
var BinaryOutputStream = Components.Constructor("@mozilla.org/binaryoutputstream;1",
|
||||
"nsIBinaryOutputStream",
|
||||
"setOutputStream");
|
||||
var multiplex = new MultiplexStream();
|
||||
for (var i = 0; i < count; ++i) {
|
||||
let s = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
s.setData(data, data.length);
|
||||
var BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream");
|
||||
var BinaryOutputStream = Components.Constructor("@mozilla.org/binaryoutputstream;1",
|
||||
"nsIBinaryOutputStream",
|
||||
"setOutputStream");
|
||||
var multiplex = new MultiplexStream();
|
||||
for (var i = 0; i < count; ++i) {
|
||||
let s = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
s.setData(data, data.length);
|
||||
|
||||
multiplex.appendStream(s);
|
||||
}
|
||||
var seekable = multiplex.QueryInterface(Ci.nsISeekableStream);
|
||||
var sis = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
sis.init(seekable);
|
||||
// Read some data.
|
||||
var readData = sis.read(20);
|
||||
do_check_eq(readData, data + data);
|
||||
// -- Tests for NS_SEEK_SET
|
||||
// Seek accross stream.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 35);
|
||||
do_check_eq(seekable.tell(), 35);
|
||||
do_check_eq(seekable.available(), 65);
|
||||
readData = sis.read(5);
|
||||
do_check_eq(readData, data.slice(5));
|
||||
do_check_eq(seekable.available(), 60);
|
||||
// Seek at stream boundaries.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 40);
|
||||
do_check_eq(seekable.tell(), 40);
|
||||
do_check_eq(seekable.available(), 60);
|
||||
readData = sis.read(10);
|
||||
do_check_eq(readData, data);
|
||||
do_check_eq(seekable.tell(), 50);
|
||||
do_check_eq(seekable.available(), 50);
|
||||
// Rewind and read accross streams.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 39);
|
||||
do_check_eq(seekable.tell(), 39);
|
||||
do_check_eq(seekable.available(), 61);
|
||||
readData = sis.read(11);
|
||||
do_check_eq(readData, data.slice(9) + data);
|
||||
do_check_eq(seekable.tell(), 50);
|
||||
do_check_eq(seekable.available(), 50);
|
||||
// Rewind to the beginning.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
do_check_eq(seekable.available(), 100);
|
||||
// Seek to some randome location
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 50);
|
||||
// -- Tests for NS_SEEK_CUR
|
||||
// Positive seek.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, 15);
|
||||
do_check_eq(seekable.tell(), 65);
|
||||
do_check_eq(seekable.available(), 35);
|
||||
readData = sis.read(10);
|
||||
do_check_eq(readData, data.slice(5) + data.slice(0, 5));
|
||||
do_check_eq(seekable.tell(), 75);
|
||||
do_check_eq(seekable.available(), 25);
|
||||
// Negative seek.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -15);
|
||||
do_check_eq(seekable.tell(), 60);
|
||||
do_check_eq(seekable.available(), 40);
|
||||
readData = sis.read(10);
|
||||
do_check_eq(readData, data);
|
||||
do_check_eq(seekable.tell(), 70);
|
||||
do_check_eq(seekable.available(), 30);
|
||||
|
||||
// -- Tests for NS_SEEK_END
|
||||
// Normal read.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, -5);
|
||||
do_check_eq(seekable.tell(), data.length * count - 5);
|
||||
readData = sis.read(5);
|
||||
do_check_eq(readData, data.slice(5));
|
||||
do_check_eq(seekable.tell(), data.length * count);
|
||||
// Read accros streams.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, -15);
|
||||
do_check_eq(seekable.tell(), data.length * count - 15);
|
||||
readData = sis.read(15);
|
||||
do_check_eq(readData, data.slice(5) + data);
|
||||
do_check_eq(seekable.tell(), data.length * count);
|
||||
|
||||
// -- Try to do various edge cases
|
||||
// Forward seek from the end, should throw.
|
||||
var caught = false;
|
||||
try {
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, 15);
|
||||
} catch(e) {
|
||||
caught = true;
|
||||
}
|
||||
do_check_eq(caught, true);
|
||||
do_check_eq(seekable.tell(), data.length * count);
|
||||
// Backward seek from the beginning, should be clamped.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -15);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
// Seek too far: shoul be clamped.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, 3 * data.length * count);
|
||||
do_check_eq(seekable.tell(), 100);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, data.length * count);
|
||||
do_check_eq(seekable.tell(), 100);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -2 * data.length * count);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
} catch(e) {
|
||||
dump(e + "\n");
|
||||
multiplex.appendStream(s);
|
||||
}
|
||||
var seekable = multiplex.QueryInterface(Ci.nsISeekableStream);
|
||||
var sis = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
sis.init(seekable);
|
||||
// Read some data.
|
||||
var readData = sis.read(20);
|
||||
do_check_eq(readData, data + data);
|
||||
// -- Tests for NS_SEEK_SET
|
||||
// Seek to a non-zero, non-stream-boundary offset.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 2);
|
||||
do_check_eq(seekable.tell(), 2);
|
||||
do_check_eq(seekable.available(), 98);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 9);
|
||||
do_check_eq(seekable.tell(), 9);
|
||||
do_check_eq(seekable.available(), 91);
|
||||
// Seek across stream boundary.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 35);
|
||||
do_check_eq(seekable.tell(), 35);
|
||||
do_check_eq(seekable.available(), 65);
|
||||
readData = sis.read(5);
|
||||
do_check_eq(readData, data.slice(5));
|
||||
do_check_eq(seekable.available(), 60);
|
||||
// Seek at stream boundaries.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 40);
|
||||
do_check_eq(seekable.tell(), 40);
|
||||
do_check_eq(seekable.available(), 60);
|
||||
readData = sis.read(10);
|
||||
do_check_eq(readData, data);
|
||||
do_check_eq(seekable.tell(), 50);
|
||||
do_check_eq(seekable.available(), 50);
|
||||
// Rewind and read across streams.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 39);
|
||||
do_check_eq(seekable.tell(), 39);
|
||||
do_check_eq(seekable.available(), 61);
|
||||
readData = sis.read(11);
|
||||
do_check_eq(readData, data.slice(9) + data);
|
||||
do_check_eq(seekable.tell(), 50);
|
||||
do_check_eq(seekable.available(), 50);
|
||||
// Rewind to the beginning.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
do_check_eq(seekable.available(), 100);
|
||||
// Seek to some random location
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 50);
|
||||
// -- Tests for NS_SEEK_CUR
|
||||
// Positive seek.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, 15);
|
||||
do_check_eq(seekable.tell(), 65);
|
||||
do_check_eq(seekable.available(), 35);
|
||||
readData = sis.read(10);
|
||||
do_check_eq(readData, data.slice(5) + data.slice(0, 5));
|
||||
do_check_eq(seekable.tell(), 75);
|
||||
do_check_eq(seekable.available(), 25);
|
||||
// Negative seek.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -15);
|
||||
do_check_eq(seekable.tell(), 60);
|
||||
do_check_eq(seekable.available(), 40);
|
||||
readData = sis.read(10);
|
||||
do_check_eq(readData, data);
|
||||
do_check_eq(seekable.tell(), 70);
|
||||
do_check_eq(seekable.available(), 30);
|
||||
|
||||
// -- Tests for NS_SEEK_END
|
||||
// Normal read.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, -5);
|
||||
do_check_eq(seekable.tell(), data.length * count - 5);
|
||||
readData = sis.read(5);
|
||||
do_check_eq(readData, data.slice(5));
|
||||
do_check_eq(seekable.tell(), data.length * count);
|
||||
// Read across streams.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, -15);
|
||||
do_check_eq(seekable.tell(), data.length * count - 15);
|
||||
readData = sis.read(15);
|
||||
do_check_eq(readData, data.slice(5) + data);
|
||||
do_check_eq(seekable.tell(), data.length * count);
|
||||
|
||||
// -- Try to do various edge cases
|
||||
// Forward seek from the end, should throw.
|
||||
var caught = false;
|
||||
try {
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, 15);
|
||||
} catch(e) {
|
||||
caught = true;
|
||||
}
|
||||
do_check_eq(caught, true);
|
||||
do_check_eq(seekable.tell(), data.length * count);
|
||||
// Backward seek from the beginning, should be clamped.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -15);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
// Seek too far: should be clamped.
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, 3 * data.length * count);
|
||||
do_check_eq(seekable.tell(), 100);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, data.length * count);
|
||||
do_check_eq(seekable.tell(), 100);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -2 * data.length * count);
|
||||
do_check_eq(seekable.tell(), 0);
|
||||
}
|
||||
|
||||
function test_multiplex_bug797871() {
|
||||
|
||||
var data = "1234567890123456789012345678901234567890";
|
||||
|
||||
try {
|
||||
var MultiplexStream = CC("@mozilla.org/io/multiplex-input-stream;1",
|
||||
"nsIMultiplexInputStream");
|
||||
do_check_eq(1, 1);
|
||||
var MultiplexStream = CC("@mozilla.org/io/multiplex-input-stream;1",
|
||||
"nsIMultiplexInputStream");
|
||||
do_check_eq(1, 1);
|
||||
|
||||
var BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream");
|
||||
var BinaryOutputStream = Components.Constructor("@mozilla.org/binaryoutputstream;1",
|
||||
"nsIBinaryOutputStream",
|
||||
"setOutputStream");
|
||||
var multiplex = new MultiplexStream();
|
||||
let s = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
s.setData(data, data.length);
|
||||
var BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream");
|
||||
var BinaryOutputStream = Components.Constructor("@mozilla.org/binaryoutputstream;1",
|
||||
"nsIBinaryOutputStream",
|
||||
"setOutputStream");
|
||||
var multiplex = new MultiplexStream();
|
||||
let s = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
s.setData(data, data.length);
|
||||
|
||||
multiplex.appendStream(s);
|
||||
multiplex.appendStream(s);
|
||||
|
||||
var seekable = multiplex.QueryInterface(Ci.nsISeekableStream);
|
||||
var sis = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
sis.init(seekable);
|
||||
var seekable = multiplex.QueryInterface(Ci.nsISeekableStream);
|
||||
var sis = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
sis.init(seekable);
|
||||
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 8);
|
||||
do_check_eq(seekable.tell(), 8);
|
||||
readData = sis.read(2);
|
||||
do_check_eq(seekable.tell(), 10);
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 8);
|
||||
do_check_eq(seekable.tell(), 8);
|
||||
readData = sis.read(2);
|
||||
do_check_eq(seekable.tell(), 10);
|
||||
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 20);
|
||||
do_check_eq(seekable.tell(), 20);
|
||||
} catch(e) {
|
||||
do_note_exception(e, "exception in test_multiplex_bug797871");
|
||||
}
|
||||
seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 20);
|
||||
do_check_eq(seekable.tell(), 20);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
Loading…
Reference in New Issue
Block a user