aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/codec/SkGifCodec.cpp9
-rw-r--r--tests/CodecPartialTest.cpp6
-rw-r--r--tests/GifTest.cpp12
-rw-r--r--third_party/gif/SkGifImageReader.cpp8
4 files changed, 26 insertions, 9 deletions
diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp
index 7fc3c9805a..d13f97ae72 100644
--- a/src/codec/SkGifCodec.cpp
+++ b/src/codec/SkGifCodec.cpp
@@ -74,14 +74,19 @@ static SkCodec::Result gif_error(const char* msg, SkCodec::Result result = SkCod
SkCodec* SkGifCodec::NewFromStream(SkStream* stream) {
std::unique_ptr<SkGifImageReader> reader(new SkGifImageReader(stream));
if (!reader->parse(SkGifImageReader::SkGIFSizeQuery)) {
- // Not enough data to determine the size.
+ // Fatal error occurred.
return nullptr;
}
- if (0 == reader->screenWidth() || 0 == reader->screenHeight()) {
+ // If no images are in the data, or the first header is not yet defined, we cannot
+ // create a codec. In either case, the width and height are not yet known.
+ if (0 == reader->imagesCount() || !reader->frameContext(0)->isHeaderDefined()) {
return nullptr;
}
+ // isHeaderDefined() will not return true if the screen size is empty.
+ SkASSERT(reader->screenHeight() > 0 && reader->screenWidth() > 0);
+
const auto alpha = reader->firstFrameHasAlpha() ? SkEncodedInfo::kBinary_Alpha
: SkEncodedInfo::kOpaque_Alpha;
// Use kPalette since Gifs are encoded with a color table.
diff --git a/tests/CodecPartialTest.cpp b/tests/CodecPartialTest.cpp
index ba1a51f4ef..9611d0982e 100644
--- a/tests/CodecPartialTest.cpp
+++ b/tests/CodecPartialTest.cpp
@@ -90,7 +90,7 @@ private:
SkMemoryStream fStream;
};
-static void test_partial(skiatest::Reporter* r, const char* name) {
+static void test_partial(skiatest::Reporter* r, const char* name, size_t minBytes = 0) {
sk_sp<SkData> file = make_from_resource(name);
if (!file) {
SkDebugf("missing resource %s\n", name);
@@ -104,7 +104,7 @@ static void test_partial(skiatest::Reporter* r, const char* name) {
}
// Now decode part of the file
- HaltingStream* stream = new HaltingStream(file, file->size() / 2);
+ HaltingStream* stream = new HaltingStream(file, SkTMax(file->size() / 2, minBytes));
// Note that we cheat and hold on to a pointer to stream, though it is owned by
// partialCodec.
@@ -174,7 +174,7 @@ DEF_TEST(Codec_partial, r) {
test_partial(r, "baby_tux.png");
test_partial(r, "box.gif");
- test_partial(r, "randPixels.gif");
+ test_partial(r, "randPixels.gif", 215);
test_partial(r, "color_wheel.gif");
}
diff --git a/tests/GifTest.cpp b/tests/GifTest.cpp
index b06d3ead1c..17dce92186 100644
--- a/tests/GifTest.cpp
+++ b/tests/GifTest.cpp
@@ -227,3 +227,15 @@ DEF_TEST(Gif_Sampled, r) {
bm.rowBytes(), &options);
REPORTER_ASSERT(r, result == SkCodec::kSuccess);
}
+
+// If a GIF file is truncated before the header for the first image is defined,
+// we should not create an SkCodec.
+DEF_TEST(Codec_GifTruncated, r) {
+ SkString path = GetResourcePath("test640x479.gif");
+ sk_sp<SkData> data(SkData::MakeFromFileName(path.c_str()));
+
+ // This is right before the header for the first image.
+ data = SkData::MakeSubset(data.get(), 0, 446);
+ std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
+ REPORTER_ASSERT(r, !codec);
+}
diff --git a/third_party/gif/SkGifImageReader.cpp b/third_party/gif/SkGifImageReader.cpp
index 14aa1f17fa..9a14018734 100644
--- a/third_party/gif/SkGifImageReader.cpp
+++ b/third_party/gif/SkGifImageReader.cpp
@@ -781,6 +781,10 @@ bool SkGifImageReader::parse(SkGifImageReader::SkGIFParseQuery query)
}
}
+ addFrameIfNecessary();
+ SkGIFFrameContext* currentFrame = m_frames.back().get();
+ currentFrame->setHeaderDefined();
+
if (query == SkGIFSizeQuery) {
// The decoder needs to stop, so we return here, before
// flushing the buffer. Next time through, we'll be in the same
@@ -789,10 +793,6 @@ bool SkGifImageReader::parse(SkGifImageReader::SkGIFParseQuery query)
return true;
}
- addFrameIfNecessary();
- SkGIFFrameContext* currentFrame = m_frames.back().get();
-
- currentFrame->setHeaderDefined();
currentFrame->setRect(xOffset, yOffset, width, height);
currentFrame->setInterlaced(SkToBool(currentComponent[8] & 0x40));