summaryrefslogtreecommitdiff
path: root/core/fxcodec/gif
diff options
context:
space:
mode:
Diffstat (limited to 'core/fxcodec/gif')
-rw-r--r--core/fxcodec/gif/cfx_gif.cpp3
-rw-r--r--core/fxcodec/gif/cfx_gif.h9
-rw-r--r--core/fxcodec/gif/cfx_gifcontext.cpp98
-rw-r--r--core/fxcodec/gif/cfx_gifcontext.h6
-rw-r--r--core/fxcodec/gif/cfx_gifcontext_unittest.cpp336
5 files changed, 408 insertions, 44 deletions
diff --git a/core/fxcodec/gif/cfx_gif.cpp b/core/fxcodec/gif/cfx_gif.cpp
index c3c5c85323..985a687906 100644
--- a/core/fxcodec/gif/cfx_gif.cpp
+++ b/core/fxcodec/gif/cfx_gif.cpp
@@ -6,6 +6,9 @@
#include "core/fxcodec/gif/cfx_gif.h"
+const char* kGifSignature87 = "GIF87a";
+const char* kGifSignature89 = "GIF89a";
+
static_assert(sizeof(CFX_CFX_GifImageInfo) == 9,
"CFX_CFX_GifImageInfo should have a size of 9");
static_assert(sizeof(CFX_GifPalette) == 3,
diff --git a/core/fxcodec/gif/cfx_gif.h b/core/fxcodec/gif/cfx_gif.h
index e9eb5c4054..ab8278ecd2 100644
--- a/core/fxcodec/gif/cfx_gif.h
+++ b/core/fxcodec/gif/cfx_gif.h
@@ -12,7 +12,9 @@
class CFX_GifContext;
-#define GIF_SIGNATURE "GIF"
+extern const char* kGifSignature87;
+extern const char* kGifSignature89;
+
#define GIF_SIG_EXTENSION 0x21
#define GIF_SIG_IMAGE 0x2C
#define GIF_SIG_TRAILER 0x3B
@@ -49,10 +51,7 @@ typedef struct {
uint8_t local_pal : 1;
} CFX_GifLocalFlags;
-typedef struct {
- char signature[3];
- char version[3];
-} CFX_GifHeader;
+typedef struct { char signature[6]; } CFX_GifHeader;
typedef struct {
uint16_t width;
diff --git a/core/fxcodec/gif/cfx_gifcontext.cpp b/core/fxcodec/gif/cfx_gifcontext.cpp
index 09e8753ca0..28bcad9ceb 100644
--- a/core/fxcodec/gif/cfx_gifcontext.cpp
+++ b/core/fxcodec/gif/cfx_gifcontext.cpp
@@ -67,43 +67,10 @@ bool CFX_GifContext::GetRecordPosition(uint32_t cur_pos,
}
CFX_GifDecodeStatus CFX_GifContext::ReadHeader() {
- uint32_t skip_size_org = skip_size_;
- CFX_GifHeader* gif_header = nullptr;
- if (!ReadData(reinterpret_cast<uint8_t**>(&gif_header), 6))
- return CFX_GifDecodeStatus::Unfinished;
-
- if (strncmp(gif_header->signature, GIF_SIGNATURE, 3) != 0 ||
- gif_header->version[0] != '8' || gif_header->version[2] != 'a')
- return CFX_GifDecodeStatus::Error;
-
- CFX_GifLocalScreenDescriptor* gif_lsd = nullptr;
- if (!ReadData(reinterpret_cast<uint8_t**>(&gif_lsd), 7)) {
- skip_size_ = skip_size_org;
- return CFX_GifDecodeStatus::Unfinished;
- }
-
- if (gif_lsd->global_flags.global_pal) {
- global_pal_exp_ = gif_lsd->global_flags.pal_bits;
- uint32_t global_pal_size = unsigned(2 << global_pal_exp_) * 3u;
- uint8_t* global_pal = nullptr;
- if (!ReadData(&global_pal, global_pal_size)) {
- skip_size_ = skip_size_org;
- return CFX_GifDecodeStatus::Unfinished;
- }
-
- global_sort_flag_ = gif_lsd->global_flags.sort_flag;
- global_color_resolution_ = gif_lsd->global_flags.color_resolution;
- global_palette_.resize(global_pal_size / 3);
- memcpy(global_palette_.data(), global_pal, global_pal_size);
- }
-
- width_ = static_cast<int>(
- FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&gif_lsd->width)));
- height_ = static_cast<int>(
- FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&gif_lsd->height)));
- bc_index_ = gif_lsd->bc_index;
- pixel_aspect_ = gif_lsd->pixel_aspect;
- return CFX_GifDecodeStatus::Success;
+ CFX_GifDecodeStatus status = ReadGifSignature();
+ if (status != CFX_GifDecodeStatus::Success)
+ return status;
+ return ReadLogicalScreenDescriptor();
}
CFX_GifDecodeStatus CFX_GifContext::GetFrame() {
@@ -383,7 +350,15 @@ int32_t CFX_GifContext::GetFrameNum() const {
}
uint8_t* CFX_GifContext::ReadData(uint8_t** des_buf_pp, uint32_t data_size) {
- if (avail_in_ < skip_size_ + data_size)
+ if (!next_in_)
+ return nullptr;
+ if (avail_in_ <= skip_size_)
+ return nullptr;
+ if (!des_buf_pp)
+ return nullptr;
+ if (data_size == 0)
+ return nullptr;
+ if (avail_in_ - skip_size_ < data_size)
return nullptr;
*des_buf_pp = next_in_ + skip_size_;
@@ -391,6 +366,53 @@ uint8_t* CFX_GifContext::ReadData(uint8_t** des_buf_pp, uint32_t data_size) {
return *des_buf_pp;
}
+CFX_GifDecodeStatus CFX_GifContext::ReadGifSignature() {
+ CFX_GifHeader* header = nullptr;
+ uint32_t skip_size_org = skip_size_;
+ if (!ReadData(reinterpret_cast<uint8_t**>(&header), 6)) {
+ skip_size_ = skip_size_org;
+ return CFX_GifDecodeStatus::Unfinished;
+ }
+
+ if (strncmp(header->signature, kGifSignature87, 6) != 0 &&
+ strncmp(header->signature, kGifSignature89, 6) != 0)
+ return CFX_GifDecodeStatus::Error;
+
+ return CFX_GifDecodeStatus::Success;
+}
+
+CFX_GifDecodeStatus CFX_GifContext::ReadLogicalScreenDescriptor() {
+ CFX_GifLocalScreenDescriptor* lsd = nullptr;
+ uint32_t skip_size_org = skip_size_;
+ if (!ReadData(reinterpret_cast<uint8_t**>(&lsd), 7)) {
+ skip_size_ = skip_size_org;
+ return CFX_GifDecodeStatus::Unfinished;
+ }
+
+ if (lsd->global_flags.global_pal) {
+ uint32_t global_pal_size = unsigned(2 << lsd->global_flags.pal_bits) * 3u;
+ uint8_t* global_pal = nullptr;
+ if (!ReadData(&global_pal, global_pal_size)) {
+ skip_size_ = skip_size_org;
+ return CFX_GifDecodeStatus::Unfinished;
+ }
+
+ global_pal_exp_ = lsd->global_flags.pal_bits;
+ global_sort_flag_ = lsd->global_flags.sort_flag;
+ global_color_resolution_ = lsd->global_flags.color_resolution;
+ global_palette_.resize(global_pal_size / 3);
+ memcpy(global_palette_.data(), global_pal, global_pal_size);
+ }
+
+ width_ = static_cast<int>(
+ FXWORD_GET_MSBFIRST(reinterpret_cast<uint8_t*>(&lsd->width)));
+ height_ = static_cast<int>(
+ FXWORD_GET_MSBFIRST(reinterpret_cast<uint8_t*>(&lsd->height)));
+ bc_index_ = lsd->bc_index;
+ pixel_aspect_ = lsd->pixel_aspect;
+ return CFX_GifDecodeStatus::Success;
+}
+
void CFX_GifContext::SaveDecodingStatus(int32_t status) {
decode_status_ = status;
next_in_ += skip_size_;
diff --git a/core/fxcodec/gif/cfx_gifcontext.h b/core/fxcodec/gif/cfx_gifcontext.h
index a1cffb2746..e0c5900f93 100644
--- a/core/fxcodec/gif/cfx_gifcontext.h
+++ b/core/fxcodec/gif/cfx_gifcontext.h
@@ -65,8 +65,12 @@ class CFX_GifContext : public CCodec_GifModule::Context {
uint8_t global_color_resolution_;
uint8_t img_pass_num_;
- private:
+ protected:
uint8_t* ReadData(uint8_t** des_buf_pp, uint32_t data_size);
+ CFX_GifDecodeStatus ReadGifSignature();
+ CFX_GifDecodeStatus ReadLogicalScreenDescriptor();
+
+ private:
void SaveDecodingStatus(int32_t status);
CFX_GifDecodeStatus DecodeExtension();
CFX_GifDecodeStatus DecodeImageInfo();
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)));
+ }
+}