summaryrefslogtreecommitdiff
path: root/core/fxcodec/gif/cfx_gifcontext_unittest.cpp
diff options
context:
space:
mode:
authorRyan Harrison <rharrison@chromium.org>2017-10-03 09:32:14 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-10-03 13:53:21 +0000
commit0feba6f9ef721e4927e37da68ac27572ffae1453 (patch)
tree9e5cfef2691bcd8e439bca9175c8197fbd946e33 /core/fxcodec/gif/cfx_gifcontext_unittest.cpp
parentc2ae41abd16aef062fee878160aa18457d2118a7 (diff)
downloadpdfium-0feba6f9ef721e4927e37da68ac27572ffae1453.tar.xz
Rewrite how GIF headers are read
Break up reading the signature and local screen descriptors into seperate functions. Fix a bug in how matching in the signature validation works. Move LSD value assignment to after sufficient data has been confirmed. Convert LSB to MSB methods where they were just wrong. Add unit tests for ReadData, SetInputBuffer, ReadSignature, ReadLocalScreenDescriptor, and ReadHeader. BUG=pdfium:913,chromium:770470 Change-Id: I1683b8aefc11300625b9be8087c6988549308a8f Reviewed-on: https://pdfium-review.googlesource.com/15250 Commit-Queue: dsinclair <dsinclair@chromium.org> Reviewed-by: dsinclair <dsinclair@chromium.org>
Diffstat (limited to 'core/fxcodec/gif/cfx_gifcontext_unittest.cpp')
-rw-r--r--core/fxcodec/gif/cfx_gifcontext_unittest.cpp336
1 files changed, 336 insertions, 0 deletions
diff --git a/core/fxcodec/gif/cfx_gifcontext_unittest.cpp b/core/fxcodec/gif/cfx_gifcontext_unittest.cpp
new file mode 100644
index 0000000000..98b8ec5cd0
--- /dev/null
+++ b/core/fxcodec/gif/cfx_gifcontext_unittest.cpp
@@ -0,0 +1,336 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fxcodec/gif/cfx_gifcontext.h"
+
+#include "core/fxcrt/unowned_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class CFX_GifContextForTest : public CFX_GifContext {
+ public:
+ CFX_GifContextForTest(CCodec_GifModule* gif_module,
+ CCodec_GifModule::Delegate* delegate)
+ : CFX_GifContext(gif_module, delegate) {}
+ ~CFX_GifContextForTest() override {}
+
+ using CFX_GifContext::ReadData;
+ using CFX_GifContext::ReadGifSignature;
+ using CFX_GifContext::ReadLogicalScreenDescriptor;
+};
+
+TEST(CFX_GifContext, SetInputBuffer) {
+ CFX_GifContextForTest context(nullptr, nullptr);
+
+ context.SetInputBuffer(nullptr, 0);
+ EXPECT_EQ(nullptr, context.next_in_);
+ EXPECT_EQ(0u, context.avail_in_);
+ EXPECT_EQ(0u, context.skip_size_);
+
+ context.SetInputBuffer(nullptr, 100);
+ EXPECT_EQ(nullptr, context.next_in_);
+ EXPECT_EQ(100u, context.avail_in_);
+ EXPECT_EQ(0u, context.skip_size_);
+
+ uint8_t buffer[] = {0x00, 0x01, 0x02};
+ context.SetInputBuffer(buffer, 0);
+ EXPECT_EQ(buffer, context.next_in_);
+ EXPECT_EQ(0u, context.avail_in_);
+ EXPECT_EQ(0u, context.skip_size_);
+
+ context.SetInputBuffer(buffer, 3);
+ EXPECT_EQ(buffer, context.next_in_);
+ EXPECT_EQ(3u, context.avail_in_);
+ EXPECT_EQ(0u, context.skip_size_);
+
+ context.SetInputBuffer(buffer, 100);
+ EXPECT_EQ(buffer, context.next_in_);
+ EXPECT_EQ(100u, context.avail_in_);
+ EXPECT_EQ(0u, context.skip_size_);
+}
+
+TEST(CFX_GifContext, ReadData) {
+ CFX_GifContextForTest context(nullptr, nullptr);
+
+ context.SetInputBuffer(nullptr, 0);
+ EXPECT_EQ(nullptr, context.ReadData(nullptr, 0));
+ EXPECT_EQ(nullptr, context.ReadData(nullptr, 10));
+
+ uint8_t* dest_buffer = nullptr;
+ EXPECT_EQ(nullptr,
+ context.ReadData(reinterpret_cast<uint8_t**>(&dest_buffer), 0));
+ EXPECT_EQ(nullptr,
+ context.ReadData(reinterpret_cast<uint8_t**>(&dest_buffer), 10));
+
+ uint8_t src_buffer[] = {0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09};
+ context.SetInputBuffer(src_buffer, 0);
+ EXPECT_EQ(nullptr,
+ context.ReadData(reinterpret_cast<uint8_t**>(&dest_buffer), 10));
+ EXPECT_EQ(reinterpret_cast<uint8_t*>(src_buffer), context.next_in_);
+ EXPECT_EQ(0u, context.avail_in_);
+ EXPECT_EQ(0u, context.skip_size_);
+
+ dest_buffer = nullptr;
+ context.SetInputBuffer(src_buffer, 10);
+ EXPECT_EQ(src_buffer,
+ context.ReadData(reinterpret_cast<uint8_t**>(&dest_buffer), 10));
+ EXPECT_EQ(reinterpret_cast<uint8_t*>(src_buffer), dest_buffer);
+ EXPECT_EQ(src_buffer, context.next_in_);
+ EXPECT_EQ(10u, context.avail_in_);
+ EXPECT_EQ(10u, context.skip_size_);
+
+ dest_buffer = nullptr;
+ context.SetInputBuffer(src_buffer, 10);
+ EXPECT_EQ(src_buffer,
+ context.ReadData(reinterpret_cast<uint8_t**>(&dest_buffer), 5));
+ EXPECT_EQ(reinterpret_cast<uint8_t*>(src_buffer), dest_buffer);
+ EXPECT_EQ(src_buffer, context.next_in_);
+ EXPECT_EQ(10u, context.avail_in_);
+ EXPECT_EQ(5u, context.skip_size_);
+
+ dest_buffer = nullptr;
+ EXPECT_EQ(src_buffer + 5,
+ context.ReadData(reinterpret_cast<uint8_t**>(&dest_buffer), 5));
+ EXPECT_EQ(reinterpret_cast<uint8_t*>(src_buffer + 5), dest_buffer);
+ EXPECT_EQ(src_buffer, context.next_in_);
+ EXPECT_EQ(10u, context.avail_in_);
+ EXPECT_EQ(10u, context.skip_size_);
+
+ dest_buffer = nullptr;
+ EXPECT_EQ(nullptr,
+ context.ReadData(reinterpret_cast<uint8_t**>(&dest_buffer), 5));
+ EXPECT_EQ(nullptr, dest_buffer);
+ EXPECT_EQ(src_buffer, context.next_in_);
+ EXPECT_EQ(10u, context.avail_in_);
+ EXPECT_EQ(10u, context.skip_size_);
+}
+
+TEST(CFX_GifContext, ReadGifSignature) {
+ CFX_GifContextForTest context(nullptr, nullptr);
+
+ {
+ uint8_t data[1];
+ context.SetInputBuffer(data, 0);
+ EXPECT_EQ(CFX_GifDecodeStatus::Unfinished, context.ReadGifSignature());
+ EXPECT_EQ(0u, context.skip_size_);
+ }
+ // Make sure testing the entire signature
+ {
+ uint8_t data[] = {'G', 'I', 'F'};
+ context.SetInputBuffer(data, sizeof(data));
+ EXPECT_EQ(CFX_GifDecodeStatus::Unfinished, context.ReadGifSignature());
+ EXPECT_EQ(0u, context.skip_size_);
+ }
+ {
+ uint8_t data[] = {'N', 'O', 'T', 'G', 'I', 'F'};
+ context.SetInputBuffer(data, sizeof(data));
+ EXPECT_EQ(CFX_GifDecodeStatus::Error, context.ReadGifSignature());
+ EXPECT_EQ(6u, context.skip_size_);
+ }
+ // Make sure not matching GIF8*a
+ {
+ uint8_t data[] = {'G', 'I', 'F', '8', '0', 'a'};
+ context.SetInputBuffer(data, sizeof(data));
+ EXPECT_EQ(CFX_GifDecodeStatus::Error, context.ReadGifSignature());
+ EXPECT_EQ(6u, context.skip_size_);
+ }
+ // Make sure not matching GIF**a
+ {
+ uint8_t data[] = {'G', 'I', 'F', '9', '2', 'a'};
+ context.SetInputBuffer(data, sizeof(data));
+ EXPECT_EQ(CFX_GifDecodeStatus::Error, context.ReadGifSignature());
+ EXPECT_EQ(6u, context.skip_size_);
+ }
+ // One valid signature
+ {
+ uint8_t data[] = {'G', 'I', 'F', '8', '7', 'a'};
+ context.SetInputBuffer(data, sizeof(data));
+ EXPECT_EQ(CFX_GifDecodeStatus::Success, context.ReadGifSignature());
+ EXPECT_EQ(6u, context.skip_size_);
+ }
+ // The other valid signature
+ {
+ uint8_t data[] = {'G', 'I', 'F', '8', '9', 'a'};
+ context.SetInputBuffer(data, sizeof(data));
+ EXPECT_EQ(CFX_GifDecodeStatus::Success, context.ReadGifSignature());
+ EXPECT_EQ(6u, context.skip_size_);
+ }
+}
+
+TEST(CFX_GifContext, ReadLocalScreenDescriptor) {
+ CFX_GifContextForTest context(nullptr, nullptr);
+ {
+ uint8_t data[1];
+ context.SetInputBuffer(data, 0);
+ EXPECT_EQ(CFX_GifDecodeStatus::Unfinished,
+ context.ReadLogicalScreenDescriptor());
+ }
+ // LSD with all the values zero'd
+ {
+ CFX_GifLocalScreenDescriptor lsd;
+ memset(&lsd, 0, sizeof(CFX_GifLocalScreenDescriptor));
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&lsd),
+ sizeof(CFX_GifLocalScreenDescriptor));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Success,
+ context.ReadLogicalScreenDescriptor());
+
+ EXPECT_EQ(sizeof(CFX_GifLocalScreenDescriptor), context.skip_size_);
+ EXPECT_EQ(0, context.width_);
+ EXPECT_EQ(0, context.height_);
+ EXPECT_EQ(0u, context.bc_index_);
+ EXPECT_EQ(0u, context.pixel_aspect_);
+ }
+ // LSD with no global palette
+ {
+ CFX_GifLocalScreenDescriptor lsd{0x0A00, 0x000F, {0, 0, 0, 0}, 1, 2};
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&lsd),
+ sizeof(CFX_GifLocalScreenDescriptor));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Success,
+ context.ReadLogicalScreenDescriptor());
+
+ EXPECT_EQ(sizeof(CFX_GifLocalScreenDescriptor), context.skip_size_);
+ EXPECT_EQ(0x000A, context.width_);
+ EXPECT_EQ(0x0F00, context.height_);
+ EXPECT_EQ(1u, context.bc_index_);
+ EXPECT_EQ(2u, context.pixel_aspect_);
+ }
+ // LSD with global palette bit set, but no global palette
+ {
+ CFX_GifLocalScreenDescriptor lsd{0x0A00, 0x000F, {0, 0, 0, 1}, 1, 2};
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&lsd),
+ sizeof(CFX_GifLocalScreenDescriptor));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Unfinished,
+ context.ReadLogicalScreenDescriptor());
+
+ EXPECT_EQ(0u, context.skip_size_);
+ }
+ // LSD with global palette
+ {
+ CFX_GifLocalScreenDescriptor lsd = {0x0A00, 0x000F, {1, 1, 2, 1}, 1, 2};
+ CFX_GifPalette palette[4] = {{0, 0, 0}, {1, 1, 1}, {1, 0, 0}, {0, 0, 1}};
+ struct {
+ CFX_GifLocalScreenDescriptor lsd;
+ CFX_GifPalette palette[4];
+ } data;
+ memcpy(&data.lsd, &lsd, sizeof(data.lsd));
+ memcpy(&data.palette, &palette, sizeof(data.lsd));
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&data), sizeof(data));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Success,
+ context.ReadLogicalScreenDescriptor());
+
+ EXPECT_EQ(sizeof(data), context.skip_size_);
+ EXPECT_EQ(0x000A, context.width_);
+ EXPECT_EQ(0x0F00, context.height_);
+ EXPECT_EQ(1u, context.bc_index_);
+ EXPECT_EQ(2u, context.pixel_aspect_);
+ EXPECT_EQ(1u, context.global_pal_exp_);
+ EXPECT_EQ(1, context.global_sort_flag_);
+ EXPECT_EQ(2, context.global_color_resolution_);
+ EXPECT_TRUE(0 == memcmp(data.palette, context.global_palette_.data(),
+ sizeof(data.palette)));
+ }
+}
+
+TEST(CFX_GifContext, ReadHeader) {
+ CFX_GifContextForTest context(nullptr, nullptr);
+ // Bad signature
+ {
+ uint8_t signature[] = {'N', 'O', 'T', 'G', 'I', 'F'};
+ CFX_GifLocalScreenDescriptor lsd{0x0A00, 0x000F, {0, 0, 0, 0}, 1, 2};
+ struct {
+ uint8_t signature[6];
+ CFX_GifLocalScreenDescriptor lsd;
+ } data;
+ memcpy(&data.signature, signature, sizeof(data.signature));
+ memcpy(&data.lsd, &lsd, sizeof(data.lsd));
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&data), sizeof(data));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Error, context.ReadHeader());
+
+ EXPECT_EQ(sizeof(signature), context.skip_size_);
+ }
+ // Short after signature
+ {
+ uint8_t signature[] = {'G', 'I', 'F', '8', '7', 'a'};
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&signature),
+ sizeof(signature));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Unfinished, context.ReadHeader());
+
+ EXPECT_EQ(sizeof(signature), context.skip_size_);
+ }
+ // Success without global palette
+ {
+ uint8_t signature[] = {'G', 'I', 'F', '8', '7', 'a'};
+ CFX_GifLocalScreenDescriptor lsd{0x0A00, 0x000F, {0, 0, 0, 0}, 1, 2};
+ struct {
+ uint8_t signature[6];
+ CFX_GifLocalScreenDescriptor lsd;
+ } data;
+ memcpy(&data.signature, signature, sizeof(data.signature));
+ memcpy(&data.lsd, &lsd, sizeof(data.lsd));
+
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&data), sizeof(data));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Success, context.ReadHeader());
+
+ EXPECT_EQ(sizeof(data), context.skip_size_);
+ EXPECT_EQ(0x000A, context.width_);
+ EXPECT_EQ(0x0F00, context.height_);
+ EXPECT_EQ(1u, context.bc_index_);
+ EXPECT_EQ(2u, context.pixel_aspect_);
+ }
+ // Missing Global Palette
+ {
+ uint8_t signature[] = {'G', 'I', 'F', '8', '7', 'a'};
+ CFX_GifLocalScreenDescriptor lsd{0x0A00, 0x000F, {0, 0, 0, 1}, 1, 2};
+
+ struct {
+ uint8_t signature[6];
+ CFX_GifLocalScreenDescriptor lsd;
+ } data;
+ memcpy(&data.signature, signature, sizeof(data.signature));
+ memcpy(&data.lsd, &lsd, sizeof(data.lsd));
+
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&data), sizeof(data));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Unfinished, context.ReadHeader());
+
+ EXPECT_EQ(sizeof(signature), context.skip_size_);
+ }
+ // Success with global palette
+ {
+ uint8_t signature[] = {'G', 'I', 'F', '8', '7', 'a'};
+ CFX_GifLocalScreenDescriptor lsd = {0x0A00, 0x000F, {1, 1, 2, 1}, 1, 2};
+ CFX_GifPalette palette[4] = {{0, 0, 0}, {1, 1, 1}, {1, 0, 0}, {0, 0, 1}};
+
+ struct {
+ uint8_t signature[6];
+ CFX_GifLocalScreenDescriptor lsd;
+ CFX_GifPalette palette[4];
+ } data;
+ memcpy(&data.signature, signature, sizeof(data.signature));
+ memcpy(&data.lsd, &lsd, sizeof(data.lsd));
+ memcpy(&data.palette, &palette, sizeof(data.lsd));
+
+ context.SetInputBuffer(reinterpret_cast<uint8_t*>(&data), sizeof(data));
+
+ EXPECT_EQ(CFX_GifDecodeStatus::Success, context.ReadHeader());
+
+ EXPECT_EQ(sizeof(data), context.skip_size_);
+ EXPECT_EQ(0x000A, context.width_);
+ EXPECT_EQ(0x0F00, context.height_);
+ EXPECT_EQ(1u, context.bc_index_);
+ EXPECT_EQ(2u, context.pixel_aspect_);
+ EXPECT_EQ(1u, context.global_pal_exp_);
+ EXPECT_EQ(1, context.global_sort_flag_);
+ EXPECT_EQ(2, context.global_color_resolution_);
+ EXPECT_TRUE(0 == memcmp(data.palette, context.global_palette_.data(),
+ sizeof(data.palette)));
+ }
+}