Allow buffered stream to work with an offset.
If the stream being buffered is buffered from somewhere other than the start, the SkFrontBufferedStream needs to take that into account when reporting its length. R=djsollen@google.com, bungeman@google.com, reed@google.com Author: scroggo@google.com Review URL: https://codereview.chromium.org/157103002 git-svn-id: http://skia.googlecode.com/svn/trunk@13388 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
ba9354b9d4
commit
74b88b70b8
@ -24,14 +24,16 @@ public:
|
||||
|
||||
virtual size_t getPosition() const SK_OVERRIDE { return fOffset; }
|
||||
|
||||
virtual bool hasLength() const SK_OVERRIDE;
|
||||
virtual bool hasLength() const SK_OVERRIDE { return fHasLength; }
|
||||
|
||||
virtual size_t getLength() const SK_OVERRIDE;
|
||||
virtual size_t getLength() const SK_OVERRIDE { return fLength; }
|
||||
|
||||
virtual SkStreamRewindable* duplicate() const SK_OVERRIDE { return NULL; }
|
||||
|
||||
private:
|
||||
SkAutoTUnref<SkStream> fStream;
|
||||
const bool fHasLength;
|
||||
const size_t fLength;
|
||||
// Current offset into the stream. Always >= 0.
|
||||
size_t fOffset;
|
||||
// Amount that has been buffered by calls to read. Will always be less than
|
||||
@ -70,6 +72,8 @@ SkStreamRewindable* SkFrontBufferedStream::Create(SkStream* stream, size_t buffe
|
||||
|
||||
FrontBufferedStream::FrontBufferedStream(SkStream* stream, size_t bufferSize)
|
||||
: fStream(SkRef(stream))
|
||||
, fHasLength(stream->hasPosition() && stream->hasLength())
|
||||
, fLength(stream->getLength() - stream->getPosition())
|
||||
, fOffset(0)
|
||||
, fBufferedSoFar(0)
|
||||
, fBufferSize(bufferSize)
|
||||
@ -94,14 +98,6 @@ bool FrontBufferedStream::rewind() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FrontBufferedStream::hasLength() const {
|
||||
return fStream->hasLength();
|
||||
}
|
||||
|
||||
size_t FrontBufferedStream::getLength() const {
|
||||
return fStream->getLength();
|
||||
}
|
||||
|
||||
size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) {
|
||||
SkASSERT(fOffset < fBufferedSoFar);
|
||||
// Some data has already been copied to fBuffer. Read up to the
|
||||
|
@ -16,7 +16,7 @@ static void test_read(skiatest::Reporter* reporter, SkStream* bufferedStream,
|
||||
// output for reading bufferedStream.
|
||||
SkAutoMalloc storage(bytesToRead);
|
||||
|
||||
size_t bytesRead = bufferedStream->read(storage.get(), bytesToRead);
|
||||
const size_t bytesRead = bufferedStream->read(storage.get(), bytesToRead);
|
||||
REPORTER_ASSERT(reporter, bytesRead == bytesToRead || bufferedStream->isAtEnd());
|
||||
REPORTER_ASSERT(reporter, memcmp(storage.get(), expectations, bytesRead) == 0);
|
||||
}
|
||||
@ -27,6 +27,20 @@ static void test_rewind(skiatest::Reporter* reporter,
|
||||
REPORTER_ASSERT(reporter, success == shouldSucceed);
|
||||
}
|
||||
|
||||
// Test that hasLength() returns the correct value, based on the stream
|
||||
// being wrapped. A length can only be known if the wrapped stream has a
|
||||
// length and it has a position (so its initial position can be taken into
|
||||
// account when computing the length).
|
||||
static void test_hasLength(skiatest::Reporter* reporter,
|
||||
const SkStream& bufferedStream,
|
||||
const SkStream& streamBeingBuffered) {
|
||||
if (streamBeingBuffered.hasLength() && streamBeingBuffered.hasPosition()) {
|
||||
REPORTER_ASSERT(reporter, bufferedStream.hasLength());
|
||||
} else {
|
||||
REPORTER_ASSERT(reporter, !bufferedStream.hasLength());
|
||||
}
|
||||
}
|
||||
|
||||
// All tests will buffer this string, and compare output to the original.
|
||||
// The string is long to ensure that all of our lengths being tested are
|
||||
// smaller than the string length.
|
||||
@ -38,6 +52,7 @@ static void test_incremental_buffering(skiatest::Reporter* reporter, size_t buff
|
||||
SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
|
||||
|
||||
SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
|
||||
test_hasLength(reporter, *bufferedStream.get(), memStream);
|
||||
|
||||
// First, test reading less than the max buffer size.
|
||||
test_read(reporter, bufferedStream, gAbcs, bufferSize / 2);
|
||||
@ -64,6 +79,7 @@ static void test_incremental_buffering(skiatest::Reporter* reporter, size_t buff
|
||||
static void test_perfectly_sized_buffer(skiatest::Reporter* reporter, size_t bufferSize) {
|
||||
SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
|
||||
SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
|
||||
test_hasLength(reporter, *bufferedStream.get(), memStream);
|
||||
|
||||
// Read exactly the amount that fits in the buffer.
|
||||
test_read(reporter, bufferedStream, gAbcs, bufferSize);
|
||||
@ -82,6 +98,7 @@ static void test_perfectly_sized_buffer(skiatest::Reporter* reporter, size_t buf
|
||||
static void test_skipping(skiatest::Reporter* reporter, size_t bufferSize) {
|
||||
SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
|
||||
SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
|
||||
test_hasLength(reporter, *bufferedStream.get(), memStream);
|
||||
|
||||
// Skip half the buffer.
|
||||
bufferedStream->skip(bufferSize / 2);
|
||||
@ -134,6 +151,7 @@ static void test_read_beyond_buffer(skiatest::Reporter* reporter, size_t bufferS
|
||||
|
||||
// Create a buffer that matches the length of the stream.
|
||||
SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
|
||||
test_hasLength(reporter, *bufferedStream.get(), memStream);
|
||||
|
||||
// Attempt to read one more than the bufferSize
|
||||
test_read(reporter, bufferedStream.get(), gAbcs, bufferSize + 1);
|
||||
@ -143,11 +161,86 @@ static void test_read_beyond_buffer(skiatest::Reporter* reporter, size_t bufferS
|
||||
test_read(reporter, bufferedStream, gAbcs, bufferSize);
|
||||
}
|
||||
|
||||
// Dummy stream that optionally has a length and/or position. Tests that FrontBufferedStream's
|
||||
// length depends on the stream it's buffering having a length and position.
|
||||
class LengthOptionalStream : public SkStream {
|
||||
public:
|
||||
LengthOptionalStream(bool hasLength, bool hasPosition)
|
||||
: fHasLength(hasLength)
|
||||
, fHasPosition(hasPosition)
|
||||
{}
|
||||
|
||||
virtual bool hasLength() const SK_OVERRIDE {
|
||||
return fHasLength;
|
||||
}
|
||||
|
||||
virtual bool hasPosition() const SK_OVERRIDE {
|
||||
return fHasPosition;
|
||||
}
|
||||
|
||||
virtual size_t read(void*, size_t) SK_OVERRIDE {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual bool isAtEnd() const SK_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const bool fHasLength;
|
||||
const bool fHasPosition;
|
||||
};
|
||||
|
||||
// Test all possible combinations of the wrapped stream having a length and a position.
|
||||
static void test_length_combos(skiatest::Reporter* reporter, size_t bufferSize) {
|
||||
for (int hasLen = 0; hasLen <= 1; hasLen++) {
|
||||
for (int hasPos = 0; hasPos <= 1; hasPos++) {
|
||||
LengthOptionalStream stream((bool) hasLen, (bool) hasPos);
|
||||
SkAutoTUnref<SkStream> buffered(SkFrontBufferedStream::Create(&stream, bufferSize));
|
||||
test_hasLength(reporter, *buffered.get(), stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test using a stream with an initial offset.
|
||||
static void test_initial_offset(skiatest::Reporter* reporter, size_t bufferSize) {
|
||||
SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
|
||||
|
||||
// Skip a few characters into the memStream, so that bufferedStream represents an offset into
|
||||
// the stream it wraps.
|
||||
const size_t arbitraryOffset = 17;
|
||||
memStream.skip(arbitraryOffset);
|
||||
SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
|
||||
|
||||
// Since SkMemoryStream has a length and a position, bufferedStream must also.
|
||||
REPORTER_ASSERT(reporter, bufferedStream->hasLength());
|
||||
|
||||
const size_t amountToRead = 10;
|
||||
const size_t bufferedLength = bufferedStream->getLength();
|
||||
size_t currentPosition = bufferedStream->getPosition();
|
||||
REPORTER_ASSERT(reporter, 0 == currentPosition);
|
||||
|
||||
// Read the stream in chunks. After each read, the position must match currentPosition,
|
||||
// which sums the amount attempted to read, unless the end of the stream has been reached.
|
||||
// Importantly, the end should not have been reached until currentPosition == bufferedLength.
|
||||
while (currentPosition < bufferedLength) {
|
||||
REPORTER_ASSERT(reporter, !bufferedStream->isAtEnd());
|
||||
test_read(reporter, bufferedStream, gAbcs + arbitraryOffset + currentPosition,
|
||||
amountToRead);
|
||||
currentPosition = SkTMin(currentPosition + amountToRead, bufferedLength);
|
||||
REPORTER_ASSERT(reporter, bufferedStream->getPosition() == currentPosition);
|
||||
}
|
||||
REPORTER_ASSERT(reporter, bufferedStream->isAtEnd());
|
||||
REPORTER_ASSERT(reporter, bufferedLength == currentPosition);
|
||||
}
|
||||
|
||||
static void test_buffers(skiatest::Reporter* reporter, size_t bufferSize) {
|
||||
test_incremental_buffering(reporter, bufferSize);
|
||||
test_perfectly_sized_buffer(reporter, bufferSize);
|
||||
test_skipping(reporter, bufferSize);
|
||||
test_read_beyond_buffer(reporter, bufferSize);
|
||||
test_length_combos(reporter, bufferSize);
|
||||
test_initial_offset(reporter, bufferSize);
|
||||
}
|
||||
|
||||
DEF_TEST(FrontBufferedStream, reporter) {
|
||||
|
Loading…
Reference in New Issue
Block a user