From e2df5b7305df66efbd81232d911615af60624ae3 Mon Sep 17 00:00:00 2001 From: Ryan Harrison Date: Tue, 26 Sep 2017 15:39:10 -0400 Subject: 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, 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 Commit-Queue: Ryan Harrison --- BUILD.gn | 3 + core/fxcodec/lgif/cfx_lzwdecoder.cpp | 184 ++++++++++++++++++++++++++ core/fxcodec/lgif/cfx_lzwdecoder.h | 55 ++++++++ core/fxcodec/lgif/cfx_lzwdecoder_unittest.cpp | 147 ++++++++++++++++++++ core/fxcodec/lgif/cgifcontext.cpp | 53 +++++--- core/fxcodec/lgif/cgifcontext.h | 3 +- core/fxcodec/lgif/fx_gif.cpp | 181 ------------------------- core/fxcodec/lgif/fx_gif.h | 51 ++----- 8 files changed, 435 insertions(+), 242 deletions(-) create mode 100644 core/fxcodec/lgif/cfx_lzwdecoder.cpp create mode 100644 core/fxcodec/lgif/cfx_lzwdecoder.h create mode 100644 core/fxcodec/lgif/cfx_lzwdecoder_unittest.cpp 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 +#include +#include + +#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::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( + 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(2 << color_exp)), + code_clear_(static_cast(1 << code_exp)), + code_end_(static_cast((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(*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 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(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(-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(*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(-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(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(code); + code_first_ = static_cast(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 +#include + +#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 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(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 #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 m_GifGCE; uint8_t* next_in; std::vector> m_Images; - std::unique_ptr m_ImgDecoder; + std::unique_ptr 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(-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(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(code); - code_first = static_cast(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(*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 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(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(-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(*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_ -- cgit v1.2.3