summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Harrison <rharrison@chromium.org>2017-09-26 15:39:10 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-09-26 19:58:33 +0000
commite2df5b7305df66efbd81232d911615af60624ae3 (patch)
tree5c5aff0ae260792790cfb1ed2f3f15863c0c0d63
parent7d04f1b0ab4848f1d10983b7a7b1444ac93dec70 (diff)
downloadpdfium-e2df5b7305df66efbd81232d911615af60624ae3.tar.xz
Move LZW decoder out of fx_gif
CGifLZWDecoder has been moved out into its own file, name changed to CFX_LZWDecoder, member variable names updated, creation pattern changed, and unit tests added. Wrt the creation pattern, there is no longer a constructor and 2 initialization methods that need to be called. Instead all of the initialization is done as part of the constructor. A wrapper has been added for generating a std::unique_ptr<CFX_LZWDecoder>, so that params can be validated. BUG=pdfium:900,pdfium:901,pdfium:903,pdfium:904 Change-Id: Idcbe773f7fb18b08e64d5a89bfd87d4801332c53 Reviewed-on: https://pdfium-review.googlesource.com/14814 Reviewed-by: Tom Sepez <tsepez@chromium.org> Commit-Queue: Ryan Harrison <rharrison@chromium.org>
-rw-r--r--BUILD.gn3
-rw-r--r--core/fxcodec/lgif/cfx_lzwdecoder.cpp184
-rw-r--r--core/fxcodec/lgif/cfx_lzwdecoder.h55
-rw-r--r--core/fxcodec/lgif/cfx_lzwdecoder_unittest.cpp147
-rw-r--r--core/fxcodec/lgif/cgifcontext.cpp53
-rw-r--r--core/fxcodec/lgif/cgifcontext.h3
-rw-r--r--core/fxcodec/lgif/fx_gif.cpp181
-rw-r--r--core/fxcodec/lgif/fx_gif.h51
8 files changed, 435 insertions, 242 deletions
diff --git a/BUILD.gn b/BUILD.gn
index 33474ee818..ac244883bc 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -777,6 +777,8 @@ static_library("fxcodec") {
"core/fxcodec/codec/fx_codec_progress.cpp",
"core/fxcodec/lbmp/fx_bmp.cpp",
"core/fxcodec/lbmp/fx_bmp.h",
+ "core/fxcodec/lgif/cfx_lzwdecoder.cpp",
+ "core/fxcodec/lgif/cfx_lzwdecoder.h",
"core/fxcodec/lgif/cgifcontext.cpp",
"core/fxcodec/lgif/cgifcontext.h",
"core/fxcodec/lgif/fx_gif.cpp",
@@ -1948,6 +1950,7 @@ test("pdfium_unittests") {
include_dirs = []
if (pdf_enable_xfa) {
sources += [
+ "core/fxcodec/lgif/cfx_lzwdecoder_unittest.cpp",
"core/fxcrt/css/cfx_cssdeclaration_unittest.cpp",
"core/fxcrt/css/cfx_cssstylesheet_unittest.cpp",
"core/fxcrt/css/cfx_cssvaluelistparser_unittest.cpp",
diff --git a/core/fxcodec/lgif/cfx_lzwdecoder.cpp b/core/fxcodec/lgif/cfx_lzwdecoder.cpp
new file mode 100644
index 0000000000..9479eeafaa
--- /dev/null
+++ b/core/fxcodec/lgif/cfx_lzwdecoder.cpp
@@ -0,0 +1,184 @@
+// 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fxcodec/lgif/cfx_lzwdecoder.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "core/fxcodec/lbmp/fx_bmp.h"
+#include "third_party/base/numerics/safe_math.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+
+std::unique_ptr<CFX_LZWDecoder> CFX_LZWDecoder::Create(uint8_t color_exp,
+ uint8_t code_exp) {
+ if (code_exp > GIF_MAX_LZW_EXP || code_exp + 1 < color_exp)
+ return nullptr;
+ return std::unique_ptr<CFX_LZWDecoder>(
+ new CFX_LZWDecoder(color_exp, code_exp));
+}
+
+CFX_LZWDecoder::CFX_LZWDecoder(uint8_t color_exp, uint8_t code_exp)
+ : code_size_(code_exp),
+ code_size_cur_(0),
+ code_color_end_(static_cast<uint16_t>(2 << color_exp)),
+ code_clear_(static_cast<uint16_t>(1 << code_exp)),
+ code_end_(static_cast<uint16_t>((1 << code_exp) + 1)),
+ code_next_(0),
+ code_first_(0),
+ stack_size_(0),
+ code_old_(0),
+ next_in_(nullptr),
+ avail_in_(0),
+ bits_left_(0),
+ code_store_(0) {}
+
+CFX_LZWDecoder::~CFX_LZWDecoder() {}
+
+GifDecodeStatus CFX_LZWDecoder::Decode(uint8_t* src_buf,
+ uint32_t src_size,
+ uint8_t* des_buf,
+ uint32_t* des_size) {
+ if (!src_buf || src_size == 0 || !des_buf || !des_size)
+ return GifDecodeStatus::Error;
+
+ if (*des_size == 0)
+ return GifDecodeStatus::InsufficientDestSize;
+
+ next_in_ = src_buf;
+ avail_in_ = src_size;
+
+ ClearTable();
+
+ uint32_t i = 0;
+ if (stack_size_ != 0) {
+ if (*des_size < stack_size_) {
+ memcpy(des_buf, &stack_[GIF_MAX_LZW_CODE - stack_size_], *des_size);
+ stack_size_ -= static_cast<uint16_t>(*des_size);
+ return GifDecodeStatus::InsufficientDestSize;
+ }
+
+ memcpy(des_buf, &stack_[GIF_MAX_LZW_CODE - stack_size_], stack_size_);
+ des_buf += stack_size_;
+ i += stack_size_;
+ stack_size_ = 0;
+ }
+
+ while (i <= *des_size && (avail_in_ > 0 || bits_left_ >= code_size_cur_)) {
+ if (code_size_cur_ > GIF_MAX_LZW_EXP)
+ return GifDecodeStatus::Error;
+
+ if (avail_in_ > 0) {
+ if (bits_left_ > 31)
+ return GifDecodeStatus::Error;
+
+ pdfium::base::CheckedNumeric<uint32_t> safe_code = *next_in_++;
+ safe_code <<= bits_left_;
+ safe_code |= code_store_;
+ if (!safe_code.IsValid())
+ return GifDecodeStatus::Error;
+
+ code_store_ = safe_code.ValueOrDie();
+ --avail_in_;
+ bits_left_ += 8;
+ }
+
+ while (bits_left_ >= code_size_cur_) {
+ uint16_t code =
+ static_cast<uint16_t>(code_store_) & ((1 << code_size_cur_) - 1);
+ code_store_ >>= code_size_cur_;
+ bits_left_ -= code_size_cur_;
+ if (code == code_clear_) {
+ ClearTable();
+ continue;
+ }
+ if (code == code_end_) {
+ *des_size = i;
+ return GifDecodeStatus::Success;
+ }
+
+ if (code_old_ != static_cast<uint16_t>(-1)) {
+ if (code_next_ < GIF_MAX_LZW_CODE) {
+ if (code == code_next_) {
+ AddCode(code_old_, code_first_);
+ if (!DecodeString(code))
+ return GifDecodeStatus::Error;
+ } else if (code > code_next_) {
+ return GifDecodeStatus::Error;
+ } else {
+ if (!DecodeString(code))
+ return GifDecodeStatus::Error;
+
+ uint8_t append_char = stack_[GIF_MAX_LZW_CODE - stack_size_];
+ AddCode(code_old_, append_char);
+ }
+ }
+ } else {
+ if (!DecodeString(code))
+ return GifDecodeStatus::Error;
+ }
+
+ code_old_ = code;
+ if (i + stack_size_ > *des_size) {
+ memcpy(des_buf, &stack_[GIF_MAX_LZW_CODE - stack_size_], *des_size - i);
+ stack_size_ -= static_cast<uint16_t>(*des_size - i);
+ return GifDecodeStatus::InsufficientDestSize;
+ }
+
+ memcpy(des_buf, &stack_[GIF_MAX_LZW_CODE - stack_size_], stack_size_);
+ des_buf += stack_size_;
+ i += stack_size_;
+ stack_size_ = 0;
+ }
+ }
+
+ if (avail_in_ != 0)
+ return GifDecodeStatus::Error;
+
+ *des_size = i;
+ return GifDecodeStatus::Unfinished;
+}
+
+void CFX_LZWDecoder::ClearTable() {
+ code_size_cur_ = code_size_ + 1;
+ code_next_ = code_end_ + 1;
+ code_old_ = static_cast<uint16_t>(-1);
+ memset(code_table_, 0, sizeof(code_table_));
+ memset(stack_, 0, sizeof(stack_));
+ for (uint16_t i = 0; i < code_clear_; i++)
+ code_table_[i].suffix = static_cast<uint8_t>(i);
+}
+
+void CFX_LZWDecoder::AddCode(uint16_t prefix_code, uint8_t append_char) {
+ if (code_next_ == GIF_MAX_LZW_CODE)
+ return;
+
+ code_table_[code_next_].prefix = prefix_code;
+ code_table_[code_next_].suffix = append_char;
+ if (++code_next_ < GIF_MAX_LZW_CODE) {
+ if (code_next_ >> code_size_cur_)
+ code_size_cur_++;
+ }
+}
+
+bool CFX_LZWDecoder::DecodeString(uint16_t code) {
+ stack_size_ = 0;
+ while (code >= code_clear_ && code <= code_next_) {
+ if (code == code_table_[code].prefix || stack_size_ == GIF_MAX_LZW_CODE - 1)
+ return false;
+
+ stack_[GIF_MAX_LZW_CODE - 1 - stack_size_++] = code_table_[code].suffix;
+ code = code_table_[code].prefix;
+ }
+ if (code >= code_color_end_)
+ return false;
+
+ stack_[GIF_MAX_LZW_CODE - 1 - stack_size_++] = static_cast<uint8_t>(code);
+ code_first_ = static_cast<uint8_t>(code);
+ return true;
+}
diff --git a/core/fxcodec/lgif/cfx_lzwdecoder.h b/core/fxcodec/lgif/cfx_lzwdecoder.h
new file mode 100644
index 0000000000..913df670c6
--- /dev/null
+++ b/core/fxcodec/lgif/cfx_lzwdecoder.h
@@ -0,0 +1,55 @@
+// 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FXCODEC_LGIF_CFX_LZWDECODER_H_
+#define CORE_FXCODEC_LGIF_CFX_LZWDECODER_H_
+
+#include <memory>
+#include <vector>
+
+#include "core/fxcodec/lgif/fx_gif.h"
+
+class CFX_LZWDecoder {
+ public:
+ struct tag_Table {
+ uint16_t prefix;
+ uint8_t suffix;
+ };
+
+ // Returns nullptr on error
+ static std::unique_ptr<CFX_LZWDecoder> Create(uint8_t color_exp,
+ uint8_t code_exp);
+ ~CFX_LZWDecoder();
+
+ GifDecodeStatus Decode(uint8_t* src_buf,
+ uint32_t src_size,
+ uint8_t* des_buf,
+ uint32_t* des_size);
+
+ private:
+ CFX_LZWDecoder(uint8_t color_exp, uint8_t code_exp);
+ void ClearTable();
+ void AddCode(uint16_t prefix_code, uint8_t append_char);
+ bool DecodeString(uint16_t code);
+
+ uint8_t code_size_;
+ uint8_t code_size_cur_;
+ uint16_t code_color_end_;
+ uint16_t code_clear_;
+ uint16_t code_end_;
+ uint16_t code_next_;
+ uint8_t code_first_;
+ uint8_t stack_[GIF_MAX_LZW_CODE];
+ size_t stack_size_;
+ tag_Table code_table_[GIF_MAX_LZW_CODE];
+ uint16_t code_old_;
+ uint8_t* next_in_;
+ uint32_t avail_in_;
+ uint8_t bits_left_;
+ uint32_t code_store_;
+};
+
+#endif // CORE_FXCODEC_LGIF_CFX_LZWDECODER_H_
diff --git a/core/fxcodec/lgif/cfx_lzwdecoder_unittest.cpp b/core/fxcodec/lgif/cfx_lzwdecoder_unittest.cpp
new file mode 100644
index 0000000000..9e4b7b788e
--- /dev/null
+++ b/core/fxcodec/lgif/cfx_lzwdecoder_unittest.cpp
@@ -0,0 +1,147 @@
+// 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/lgif/cfx_lzwdecoder.h"
+
+#include "core/fxcrt/fx_memory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(CFX_LZWDecoder, CreateBadParams) {
+ EXPECT_EQ(nullptr, CFX_LZWDecoder::Create(0x10, 0x2));
+ EXPECT_EQ(nullptr, CFX_LZWDecoder::Create(0x4, 0x0F));
+}
+
+TEST(CFX_LZWDecoder, DecodeBadParams) {
+ uint8_t palette_exp = 0x0;
+ uint8_t code_exp = 0x2;
+
+ auto decoder = CFX_LZWDecoder::Create(palette_exp, code_exp);
+ ASSERT_NE(nullptr, decoder);
+
+ uint8_t image_data[10];
+ uint32_t image_size = FX_ArraySize(image_data);
+
+ uint8_t output_data[10];
+ uint32_t output_size = FX_ArraySize(output_data);
+
+ EXPECT_EQ(GifDecodeStatus::Error,
+ decoder->Decode(nullptr, image_size, output_data, &output_size));
+ EXPECT_EQ(GifDecodeStatus::Error,
+ decoder->Decode(image_data, 0, output_data, &output_size));
+ EXPECT_EQ(GifDecodeStatus::Error,
+ decoder->Decode(image_data, image_size, nullptr, &output_size));
+ EXPECT_EQ(GifDecodeStatus::Error,
+ decoder->Decode(image_data, image_size, output_data, nullptr));
+
+ output_size = 0;
+ EXPECT_EQ(GifDecodeStatus::InsufficientDestSize,
+ decoder->Decode(image_data, image_size, output_data, &output_size));
+}
+
+TEST(CFX_LZWDecoder, Decode1x1SingleColour) {
+ uint8_t palette_exp = 0x0;
+ uint8_t code_exp = 0x2;
+
+ auto decoder = CFX_LZWDecoder::Create(palette_exp, code_exp);
+ ASSERT_NE(nullptr, decoder);
+
+ uint8_t image_data[] = {0x44, 0x01};
+ uint32_t image_size = FX_ArraySize(image_data);
+
+ uint8_t output_data[1];
+ uint32_t output_size = FX_ArraySize(output_data);
+
+ EXPECT_EQ(GifDecodeStatus::Success,
+ decoder->Decode(image_data, image_size, output_data, &output_size));
+ uint8_t expected_data[] = {0x00};
+
+ EXPECT_EQ(FX_ArraySize(output_data), output_size);
+ EXPECT_TRUE(0 == memcmp(expected_data, output_data, sizeof(expected_data)));
+}
+
+TEST(CFX_LZWDecoder, Decode10x10SingleColour) {
+ uint8_t palette_exp = 0x0;
+ uint8_t code_exp = 0x2;
+
+ auto decoder = CFX_LZWDecoder::Create(palette_exp, code_exp);
+ ASSERT_NE(nullptr, decoder);
+
+ uint8_t image_data[] = {0x84, 0x8F, 0xA9, 0xCB, 0xED, 0x0F, 0x63, 0x2B};
+ uint32_t image_size = FX_ArraySize(image_data);
+
+ uint8_t output_data[100];
+ memset(output_data, 0, sizeof(output_data));
+ uint32_t output_size = FX_ArraySize(output_data);
+
+ EXPECT_EQ(GifDecodeStatus::Success,
+ decoder->Decode(image_data, image_size, output_data, &output_size));
+ uint8_t expected_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+ EXPECT_EQ(FX_ArraySize(output_data), output_size);
+ EXPECT_TRUE(0 == memcmp(expected_data, output_data, sizeof(expected_data)));
+}
+
+TEST(CFX_LZWDecoder, Decode10x10MultipleColour) {
+ uint8_t palette_exp = 0x1;
+ uint8_t code_exp = 0x2;
+
+ auto decoder = CFX_LZWDecoder::Create(palette_exp, code_exp);
+ ASSERT_NE(nullptr, decoder);
+
+ uint8_t image_data[] = {0x8C, 0x2D, 0x99, 0x87, 0x2A, 0x1C, 0xDC, 0x33,
+ 0xA0, 0x02, 0x75, 0xEC, 0x95, 0xFA, 0xA8, 0xDE,
+ 0x60, 0x8C, 0x04, 0x91, 0x4C, 0x01};
+ uint32_t image_size = FX_ArraySize(image_data);
+
+ uint8_t output_data[100];
+ memset(output_data, 0, sizeof(output_data));
+ uint32_t output_size = FX_ArraySize(output_data);
+
+ EXPECT_EQ(GifDecodeStatus::Success,
+ decoder->Decode(image_data, image_size, output_data, &output_size));
+ uint8_t expected_data[] = {
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
+ 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01,
+ 0x01, 0x01, 0x01, 0x01};
+
+ EXPECT_EQ(FX_ArraySize(output_data), output_size);
+ EXPECT_TRUE(0 == memcmp(expected_data, output_data, sizeof(expected_data)));
+}
+
+TEST(CFX_LZWDecoder, HandleColourCodeOutOfPalette) {
+ uint8_t palette_exp = 0x2; // Image uses 10 colours, so the palette exp
+ // should be 3, 2^(3+1) = 16 colours.
+ uint8_t code_exp = 0x4;
+
+ auto decoder = CFX_LZWDecoder::Create(palette_exp, code_exp);
+ ASSERT_NE(nullptr, decoder);
+
+ uint8_t image_data[] = {0x30, 0xC9, 0x49, 0x81, 0xBD, 0x78, 0xE8, 0xCD,
+ 0x89, 0xFF, 0x60, 0x20, 0x8E, 0xE4, 0x61, 0x9E,
+ 0xA8, 0xA1, 0xAE, 0x2C, 0xE2, 0xBE, 0xB0, 0x20,
+ 0xCF, 0x74, 0x61, 0xDF, 0x78, 0x04};
+ uint32_t image_size = FX_ArraySize(image_data);
+
+ uint8_t output_data[100];
+ memset(output_data, 0, sizeof(output_data));
+ uint32_t output_size = FX_ArraySize(output_data);
+
+ EXPECT_EQ(GifDecodeStatus::Error,
+ decoder->Decode(image_data, image_size, output_data, &output_size));
+}
diff --git a/core/fxcodec/lgif/cgifcontext.cpp b/core/fxcodec/lgif/cgifcontext.cpp
index 1eb1b335aa..b1de89f2b6 100644
--- a/core/fxcodec/lgif/cgifcontext.cpp
+++ b/core/fxcodec/lgif/cgifcontext.cpp
@@ -267,19 +267,14 @@ GifDecodeStatus CGifContext::LoadFrame(int32_t frame_num) {
AddError("Error Invalid Code Size");
return GifDecodeStatus::Error;
}
- if (!m_ImgDecoder.get())
- m_ImgDecoder = pdfium::MakeUnique<CGifLZWDecoder>(m_szLastError);
- m_ImgDecoder->InitTable(!gif_image_ptr->m_LocalPalettes.empty()
- ? gif_image_ptr->local_pallette_exp
- : global_pal_exp,
- gif_image_ptr->image_code_exp);
+
img_row_offset = 0;
img_row_avail_size = 0;
img_pass_num = 0;
gif_image_ptr->image_row_num = 0;
SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
}
- CGifLZWDecoder* img_decoder_ptr = m_ImgDecoder.get();
+
if (decode_status == GIF_D_STATUS_IMG_DATA) {
if (!ReadData(&data_size_ptr, 1))
return GifDecodeStatus::Unfinished;
@@ -289,13 +284,22 @@ GifDecodeStatus CGifContext::LoadFrame(int32_t frame_num) {
skip_size = skip_size_org;
return GifDecodeStatus::Unfinished;
}
- img_decoder_ptr->Input(data_ptr, *data_size_ptr);
+ if (!m_ImgDecoder.get())
+ m_ImgDecoder =
+ CFX_LZWDecoder::Create(gif_image_ptr->m_LocalPalettes.empty()
+ ? gif_image_ptr->local_pallette_exp
+ : global_pal_exp,
+ gif_image_ptr->image_code_exp);
SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
img_row_offset += img_row_avail_size;
img_row_avail_size = gif_img_row_bytes - img_row_offset;
- GifDecodeStatus ret = img_decoder_ptr->Decode(
- gif_image_ptr->m_ImageRowBuf.data() + img_row_offset,
- &img_row_avail_size);
+ GifDecodeStatus ret =
+ m_ImgDecoder.get()
+ ? m_ImgDecoder->Decode(
+ data_ptr, *data_size_ptr,
+ gif_image_ptr->m_ImageRowBuf.data() + img_row_offset,
+ &img_row_avail_size)
+ : GifDecodeStatus::Error;
if (ret == GifDecodeStatus::Error) {
DecodingFailureAtTailCleanup(gif_image_ptr);
return GifDecodeStatus::Error;
@@ -309,7 +313,6 @@ GifDecodeStatus CGifContext::LoadFrame(int32_t frame_num) {
return GifDecodeStatus::Success;
}
if (ret == GifDecodeStatus::Unfinished) {
- ASSERT(img_decoder_ptr->GetAvailInput() == 0);
skip_size_org = skip_size;
if (!ReadData(&data_size_ptr, 1))
return GifDecodeStatus::Unfinished;
@@ -319,13 +322,22 @@ GifDecodeStatus CGifContext::LoadFrame(int32_t frame_num) {
skip_size = skip_size_org;
return GifDecodeStatus::Unfinished;
}
- img_decoder_ptr->Input(data_ptr, *data_size_ptr);
+ if (!m_ImgDecoder.get())
+ m_ImgDecoder =
+ CFX_LZWDecoder::Create(!gif_image_ptr->m_LocalPalettes.empty()
+ ? gif_image_ptr->local_pallette_exp
+ : global_pal_exp,
+ gif_image_ptr->image_code_exp);
SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
img_row_offset += img_row_avail_size;
img_row_avail_size = gif_img_row_bytes - img_row_offset;
- ret = img_decoder_ptr->Decode(
- gif_image_ptr->m_ImageRowBuf.data() + img_row_offset,
- &img_row_avail_size);
+ ret =
+ m_ImgDecoder.get()
+ ? m_ImgDecoder->Decode(
+ data_ptr, *data_size_ptr,
+ gif_image_ptr->m_ImageRowBuf.data() + img_row_offset,
+ &img_row_avail_size)
+ : GifDecodeStatus::Error;
}
}
if (ret == GifDecodeStatus::InsufficientDestSize) {
@@ -349,9 +361,12 @@ GifDecodeStatus CGifContext::LoadFrame(int32_t frame_num) {
}
img_row_offset = 0;
img_row_avail_size = gif_img_row_bytes;
- ret = img_decoder_ptr->Decode(
- gif_image_ptr->m_ImageRowBuf.data() + img_row_offset,
- &img_row_avail_size);
+ ret = m_ImgDecoder.get()
+ ? m_ImgDecoder->Decode(
+ data_ptr, *data_size_ptr,
+ gif_image_ptr->m_ImageRowBuf.data() + img_row_offset,
+ &img_row_avail_size)
+ : GifDecodeStatus::Error;
}
if (ret == GifDecodeStatus::Error) {
DecodingFailureAtTailCleanup(gif_image_ptr);
diff --git a/core/fxcodec/lgif/cgifcontext.h b/core/fxcodec/lgif/cgifcontext.h
index fdff235355..87f38f0694 100644
--- a/core/fxcodec/lgif/cgifcontext.h
+++ b/core/fxcodec/lgif/cgifcontext.h
@@ -11,6 +11,7 @@
#include <vector>
#include "core/fxcodec/codec/ccodec_gifmodule.h"
+#include "core/fxcodec/lgif/cfx_lzwdecoder.h"
#include "core/fxcodec/lgif/fx_gif.h"
#include "core/fxcrt/fx_string.h"
#include "core/fxcrt/unowned_ptr.h"
@@ -56,7 +57,7 @@ class CGifContext : public CCodec_GifModule::Context {
std::unique_ptr<GifGCE> m_GifGCE;
uint8_t* next_in;
std::vector<std::unique_ptr<GifImage>> m_Images;
- std::unique_ptr<CGifLZWDecoder> m_ImgDecoder;
+ std::unique_ptr<CFX_LZWDecoder> m_ImgDecoder;
int width;
int height;
uint8_t bc_index;
diff --git a/core/fxcodec/lgif/fx_gif.cpp b/core/fxcodec/lgif/fx_gif.cpp
index 6e1c26ed12..db0744a6bb 100644
--- a/core/fxcodec/lgif/fx_gif.cpp
+++ b/core/fxcodec/lgif/fx_gif.cpp
@@ -26,184 +26,3 @@ static_assert(sizeof(GifLSD) == 7, "GifLSD should have a size of 7");
GifImage::GifImage() {}
GifImage::~GifImage() {}
-
-void CGifLZWDecoder::Input(uint8_t* src_buf, uint32_t src_size) {
- next_in = src_buf;
- avail_in = src_size;
-}
-
-uint32_t CGifLZWDecoder::GetAvailInput() {
- return avail_in;
-}
-
-CGifLZWDecoder::CGifLZWDecoder(char* error_ptr)
- : code_size(0),
- code_size_cur(0),
- code_clear(0),
- code_end(0),
- code_next(0),
- code_first(0),
- stack_size(0),
- code_old(0),
- next_in(nullptr),
- avail_in(0),
- bits_left(0),
- code_store(0),
- err_msg_ptr(error_ptr) {}
-
-CGifLZWDecoder::~CGifLZWDecoder() {}
-
-void CGifLZWDecoder::InitTable(uint8_t color_exp, uint8_t code_exp) {
- // TODO(rharrison): Refactor all of this, so that initializing the table with
- // bad values will kill the decompress.
- ASSERT(code_exp <= GIF_MAX_LZW_EXP);
- code_color_end = std::min(2 << color_exp, 1 << code_exp);
- code_size = code_exp;
- code_clear = 1 << code_exp;
- code_end = code_clear + 1;
- bits_left = 0;
- code_store = 0;
- next_in = nullptr;
- avail_in = 0;
- stack_size = 0;
- code_first = 0;
- ClearTable();
-}
-
-void CGifLZWDecoder::ClearTable() {
- code_size_cur = code_size + 1;
- code_next = code_end + 1;
- code_old = static_cast<uint16_t>(-1);
- memset(code_table, 0, sizeof(tag_Table) * GIF_MAX_LZW_CODE);
- memset(stack, 0, GIF_MAX_LZW_CODE);
- for (uint16_t i = 0; i < code_clear; i++)
- code_table[i].suffix = static_cast<uint8_t>(i);
-}
-
-bool CGifLZWDecoder::DecodeString(uint16_t code) {
- stack_size = 0;
- while (code >= code_clear && code <= code_next) {
- if (code == code_table[code].prefix || stack_size == GIF_MAX_LZW_CODE - 1)
- return false;
-
- stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = code_table[code].suffix;
- code = code_table[code].prefix;
- }
- if (code >= code_color_end)
- return false;
-
- stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = static_cast<uint8_t>(code);
- code_first = static_cast<uint8_t>(code);
- return true;
-}
-
-void CGifLZWDecoder::AddCode(uint16_t prefix_code, uint8_t append_char) {
- if (code_next == GIF_MAX_LZW_CODE)
- return;
-
- code_table[code_next].prefix = prefix_code;
- code_table[code_next].suffix = append_char;
- if (++code_next < GIF_MAX_LZW_CODE) {
- if (code_next >> code_size_cur)
- code_size_cur++;
- }
-}
-
-GifDecodeStatus CGifLZWDecoder::Decode(uint8_t* des_buf, uint32_t* des_size) {
- if (*des_size == 0)
- return GifDecodeStatus::InsufficientDestSize;
-
- uint32_t i = 0;
- if (stack_size != 0) {
- if (*des_size < stack_size) {
- memcpy(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], *des_size);
- stack_size -= static_cast<uint16_t>(*des_size);
- return GifDecodeStatus::InsufficientDestSize;
- }
- memcpy(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], stack_size);
- des_buf += stack_size;
- i += stack_size;
- stack_size = 0;
- }
- ASSERT(err_msg_ptr);
- while (i <= *des_size && (avail_in > 0 || bits_left >= code_size_cur)) {
- if (code_size_cur > GIF_MAX_LZW_EXP) {
- strncpy(err_msg_ptr, "Code Length Out Of Range", GIF_MAX_ERROR_SIZE - 1);
- return GifDecodeStatus::Error;
- }
- if (avail_in > 0) {
- if (bits_left > 31) {
- strncpy(err_msg_ptr, "Decode Error", GIF_MAX_ERROR_SIZE - 1);
- return GifDecodeStatus::Error;
- }
- pdfium::base::CheckedNumeric<uint32_t> safe_code = *next_in++;
- safe_code <<= bits_left;
- safe_code |= code_store;
- if (!safe_code.IsValid()) {
- strncpy(err_msg_ptr, "Code Store Out Of Range", GIF_MAX_ERROR_SIZE - 1);
- return GifDecodeStatus::Error;
- }
- code_store = safe_code.ValueOrDie();
- --avail_in;
- bits_left += 8;
- }
- while (bits_left >= code_size_cur) {
- uint16_t code =
- static_cast<uint16_t>(code_store) & ((1 << code_size_cur) - 1);
- code_store >>= code_size_cur;
- bits_left -= code_size_cur;
- if (code == code_clear) {
- ClearTable();
- continue;
- }
- if (code == code_end) {
- *des_size = i;
- return GifDecodeStatus::Success;
- }
- if (code_old != static_cast<uint16_t>(-1)) {
- if (code_next < GIF_MAX_LZW_CODE) {
- if (code == code_next) {
- AddCode(code_old, code_first);
- if (!DecodeString(code)) {
- strncpy(err_msg_ptr, "String Decoding Error",
- GIF_MAX_ERROR_SIZE - 1);
- return GifDecodeStatus::Error;
- }
- } else if (code > code_next) {
- strncpy(err_msg_ptr, "Decode Error, Out Of Range",
- GIF_MAX_ERROR_SIZE - 1);
- return GifDecodeStatus::Error;
- } else {
- if (!DecodeString(code)) {
- strncpy(err_msg_ptr, "String Decoding Error",
- GIF_MAX_ERROR_SIZE - 1);
- return GifDecodeStatus::Error;
- }
- uint8_t append_char = stack[GIF_MAX_LZW_CODE - stack_size];
- AddCode(code_old, append_char);
- }
- }
- } else {
- if (!DecodeString(code)) {
- strncpy(err_msg_ptr, "String Decoding Error", GIF_MAX_ERROR_SIZE - 1);
- return GifDecodeStatus::Error;
- }
- }
- code_old = code;
- if (i + stack_size > *des_size) {
- memcpy(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], *des_size - i);
- stack_size -= static_cast<uint16_t>(*des_size - i);
- return GifDecodeStatus::InsufficientDestSize;
- }
- memcpy(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], stack_size);
- des_buf += stack_size;
- i += stack_size;
- stack_size = 0;
- }
- }
- if (avail_in == 0) {
- *des_size = i;
- return GifDecodeStatus::Unfinished;
- }
- return GifDecodeStatus::Error;
-}
diff --git a/core/fxcodec/lgif/fx_gif.h b/core/fxcodec/lgif/fx_gif.h
index c3ddf36e3b..bbf847de39 100644
--- a/core/fxcodec/lgif/fx_gif.h
+++ b/core/fxcodec/lgif/fx_gif.h
@@ -35,6 +35,7 @@ class CGifContext;
#define GIF_D_STATUS_EXT_UNE 0x08
#define GIF_D_STATUS_IMG_INFO 0x09
#define GIF_D_STATUS_IMG_DATA 0x0A
+
#pragma pack(1)
typedef struct tagGifGF {
uint8_t pal_bits : 3;
@@ -42,6 +43,7 @@ typedef struct tagGifGF {
uint8_t color_resolution : 3;
uint8_t global_pal : 1;
} GifGF;
+
typedef struct tagGifLF {
uint8_t pal_bits : 3;
uint8_t reserved : 2;
@@ -49,10 +51,12 @@ typedef struct tagGifLF {
uint8_t interlace : 1;
uint8_t local_pal : 1;
} GifLF;
+
typedef struct tagGifHeader {
char signature[3];
char version[3];
} GifHeader;
+
typedef struct tagGifLSD {
uint16_t width;
uint16_t height;
@@ -60,6 +64,7 @@ typedef struct tagGifLSD {
uint8_t bc_index;
uint8_t pixel_aspect;
} GifLSD;
+
typedef struct tagGifImageInfo {
uint16_t left;
uint16_t top;
@@ -68,18 +73,21 @@ typedef struct tagGifImageInfo {
uint8_t local_flag;
} GifImageInfo;
+
typedef struct tagGifCEF {
uint8_t transparency : 1;
uint8_t user_input : 1;
uint8_t disposal_method : 3;
uint8_t reserved : 3;
} GifCEF;
+
typedef struct tagGifGCE {
uint8_t block_size;
uint8_t gce_flag;
uint16_t delay_time;
uint8_t trans_index;
} GifGCE;
+
typedef struct tagGifPTE {
uint8_t block_size;
uint16_t grid_left;
@@ -93,11 +101,13 @@ typedef struct tagGifPTE {
uint8_t fc_index;
uint8_t bc_index;
} GifPTE;
+
typedef struct tagGifAE {
uint8_t block_size;
uint8_t app_identify[8];
uint8_t app_authentication[3];
} GifAE;
+
typedef struct tagGifPalette { uint8_t r, g, b; } GifPalette;
#pragma pack()
@@ -123,45 +133,4 @@ class GifImage {
int32_t image_row_num;
};
-class CGifLZWDecoder {
- public:
- struct tag_Table {
- uint16_t prefix;
- uint8_t suffix;
- };
-
- explicit CGifLZWDecoder(char* error_ptr);
- ~CGifLZWDecoder();
-
- void InitTable(uint8_t color_exp, uint8_t code_exp);
- GifDecodeStatus Decode(uint8_t* des_buf, uint32_t* des_size);
- void Input(uint8_t* src_buf, uint32_t src_size);
- uint32_t GetAvailInput();
-
- private:
- void ClearTable();
- void AddCode(uint16_t prefix_code, uint8_t append_char);
- bool DecodeString(uint16_t code);
-
- uint8_t code_size;
- uint8_t code_size_cur;
- uint16_t code_color_end;
- uint16_t code_clear;
- uint16_t code_end;
- uint16_t code_next;
- uint8_t code_first;
- uint8_t stack[GIF_MAX_LZW_CODE];
- uint16_t stack_size;
- tag_Table code_table[GIF_MAX_LZW_CODE];
- uint16_t code_old;
-
- uint8_t* next_in;
- uint32_t avail_in;
-
- uint8_t bits_left;
- uint32_t code_store;
-
- char* err_msg_ptr;
-};
-
#endif // CORE_FXCODEC_LGIF_FX_GIF_H_