diff options
author | Ryan Harrison <rharrison@chromium.org> | 2017-09-22 11:05:13 -0400 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2017-09-22 15:13:06 +0000 |
commit | 92827b695a69c7a3fd5940dc0aa1713fe3f3ee96 (patch) | |
tree | 1698c9f11f3709683cd4eea615b9a4d970409e3e /core | |
parent | 73bed4ef57444a2ea066d532a8a82b230fd206d9 (diff) | |
download | pdfium-92827b695a69c7a3fd5940dc0aa1713fe3f3ee96.tar.xz |
Move C-style functions into CGifContext
There are a number of functions in fx_gix.h/.cpp that take in a
pointer to a CGifContext as their first parameter. Moving these to be
methods in that class.
BUG=pdfium:902
Change-Id: I8c583ab9e42dda4241aa8a6f865408a94fa6d273
Reviewed-on: https://pdfium-review.googlesource.com/14670
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Diffstat (limited to 'core')
-rw-r--r-- | core/fxcodec/codec/ccodec_gifmodule.cpp | 12 | ||||
-rw-r--r-- | core/fxcodec/lgif/cgifcontext.cpp | 471 | ||||
-rw-r--r-- | core/fxcodec/lgif/cgifcontext.h | 13 | ||||
-rw-r--r-- | core/fxcodec/lgif/fx_gif.cpp | 484 | ||||
-rw-r--r-- | core/fxcodec/lgif/fx_gif.h | 11 |
5 files changed, 490 insertions, 501 deletions
diff --git a/core/fxcodec/codec/ccodec_gifmodule.cpp b/core/fxcodec/codec/ccodec_gifmodule.cpp index 911323c3a1..b7e55d5208 100644 --- a/core/fxcodec/codec/ccodec_gifmodule.cpp +++ b/core/fxcodec/codec/ccodec_gifmodule.cpp @@ -30,7 +30,7 @@ GifDecodeStatus CCodec_GifModule::ReadHeader(Context* pContext, int* bg_index, CFX_DIBAttribute* pAttribute) { auto* context = static_cast<CGifContext*>(pContext); - GifDecodeStatus ret = gif_read_header(context); + GifDecodeStatus ret = context->ReadHeader(); if (ret != GifDecodeStatus::Success) return ret; @@ -46,11 +46,11 @@ GifDecodeStatus CCodec_GifModule::ReadHeader(Context* pContext, GifDecodeStatus CCodec_GifModule::LoadFrameInfo(Context* pContext, int* frame_num) { auto* context = static_cast<CGifContext*>(pContext); - GifDecodeStatus ret = gif_get_frame(context); + GifDecodeStatus ret = context->GetFrame(); if (ret != GifDecodeStatus::Success) return ret; - *frame_num = gif_get_frame_num(context); + *frame_num = context->GetFrameNum(); return GifDecodeStatus::Success; } @@ -58,7 +58,7 @@ GifDecodeStatus CCodec_GifModule::LoadFrame(Context* pContext, int frame_num, CFX_DIBAttribute* pAttribute) { auto* context = static_cast<CGifContext*>(pContext); - GifDecodeStatus ret = gif_load_frame(context, frame_num); + GifDecodeStatus ret = context->LoadFrame(frame_num); if (ret != GifDecodeStatus::Success || !pAttribute) return ret; @@ -81,12 +81,12 @@ GifDecodeStatus CCodec_GifModule::LoadFrame(Context* pContext, uint32_t CCodec_GifModule::GetAvailInput(Context* pContext, uint8_t** avail_buf_ptr) { auto* context = static_cast<CGifContext*>(pContext); - return gif_get_avail_input(context, avail_buf_ptr); + return context->GetAvailInput(avail_buf_ptr); } void CCodec_GifModule::Input(Context* pContext, const uint8_t* src_buf, uint32_t src_size) { auto* context = static_cast<CGifContext*>(pContext); - gif_input_buffer(context, (uint8_t*)src_buf, src_size); + context->SetInputBuffer((uint8_t*)src_buf, src_size); } diff --git a/core/fxcodec/lgif/cgifcontext.cpp b/core/fxcodec/lgif/cgifcontext.cpp index 4dc663644c..1eb1b335aa 100644 --- a/core/fxcodec/lgif/cgifcontext.cpp +++ b/core/fxcodec/lgif/cgifcontext.cpp @@ -6,13 +6,21 @@ #include "core/fxcodec/lgif/cgifcontext.h" +#include <algorithm> #include <utility> #include "core/fxcodec/codec/ccodec_gifmodule.h" +#include "core/fxcodec/lbmp/fx_bmp.h" #include "core/fxcodec/lgif/fx_gif.h" #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" +namespace { + +const int32_t s_gif_interlace_step[4] = {8, 8, 4, 2}; + +} // namespace + CGifContext::CGifContext(CCodec_GifModule* gif_module, CCodec_GifModule::Delegate* pDelegate) : m_pModule(gif_module), @@ -64,3 +72,466 @@ bool CGifContext::GetRecordPosition(uint32_t cur_pos, cur_pos, FX_RECT(left, top, left + width, top + height), pal_num, pal_ptr, delay_time, user_input, trans_index, disposal_method, interlace); } + +GifDecodeStatus CGifContext::ReadHeader() { + uint32_t skip_size_org = skip_size; + GifHeader* gif_header_ptr = nullptr; + if (!ReadData(reinterpret_cast<uint8_t**>(&gif_header_ptr), 6)) + return GifDecodeStatus::Unfinished; + + if (strncmp(gif_header_ptr->signature, GIF_SIGNATURE, 3) != 0 || + gif_header_ptr->version[0] != '8' || gif_header_ptr->version[2] != 'a') { + AddError("Not A Gif Image"); + return GifDecodeStatus::Error; + } + GifLSD* gif_lsd_ptr = nullptr; + if (!ReadData(reinterpret_cast<uint8_t**>(&gif_lsd_ptr), 7)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + if (reinterpret_cast<GifGF*>(&gif_lsd_ptr->global_flag)->global_pal) { + global_pal_exp = + reinterpret_cast<GifGF*>(&gif_lsd_ptr->global_flag)->pal_bits; + int32_t global_pal_size = (2 << global_pal_exp) * 3; + uint8_t* global_pal_ptr = nullptr; + if (!ReadData(&global_pal_ptr, global_pal_size)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + global_sort_flag = ((GifGF*)&gif_lsd_ptr->global_flag)->sort_flag; + global_color_resolution = + ((GifGF*)&gif_lsd_ptr->global_flag)->color_resolution; + m_GlobalPalette.resize(global_pal_size / 3); + memcpy(m_GlobalPalette.data(), global_pal_ptr, global_pal_size); + } + width = + (int)GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_lsd_ptr->width)); + height = + (int)GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_lsd_ptr->height)); + bc_index = gif_lsd_ptr->bc_index; + pixel_aspect = gif_lsd_ptr->pixel_aspect; + return GifDecodeStatus::Success; +} + +GifDecodeStatus CGifContext::GetFrame() { + GifDecodeStatus ret = GifDecodeStatus::Success; + while (true) { + switch (decode_status) { + case GIF_D_STATUS_TAIL: + return GifDecodeStatus::Success; + case GIF_D_STATUS_SIG: { + uint8_t* sig_ptr = nullptr; + if (!ReadData(&sig_ptr, 1)) + return GifDecodeStatus::Unfinished; + + switch (*sig_ptr) { + case GIF_SIG_EXTENSION: + SaveDecodingStatus(GIF_D_STATUS_EXT); + continue; + case GIF_SIG_IMAGE: + SaveDecodingStatus(GIF_D_STATUS_IMG_INFO); + continue; + case GIF_SIG_TRAILER: + SaveDecodingStatus(GIF_D_STATUS_TAIL); + return GifDecodeStatus::Success; + default: + if (avail_in) { + // The Gif File has non_standard Tag! + SaveDecodingStatus(GIF_D_STATUS_SIG); + continue; + } + // The Gif File Doesn't have Trailer Tag! + return GifDecodeStatus::Success; + } + } + case GIF_D_STATUS_EXT: { + uint8_t* ext_ptr = nullptr; + if (!ReadData(&ext_ptr, 1)) + return GifDecodeStatus::Unfinished; + + switch (*ext_ptr) { + case GIF_BLOCK_CE: + SaveDecodingStatus(GIF_D_STATUS_EXT_CE); + continue; + case GIF_BLOCK_GCE: + SaveDecodingStatus(GIF_D_STATUS_EXT_GCE); + continue; + case GIF_BLOCK_PTE: + SaveDecodingStatus(GIF_D_STATUS_EXT_PTE); + continue; + default: { + int32_t status = GIF_D_STATUS_EXT_UNE; + if (*ext_ptr == GIF_BLOCK_PTE) { + status = GIF_D_STATUS_EXT_PTE; + } + SaveDecodingStatus(status); + continue; + } + } + } + case GIF_D_STATUS_IMG_INFO: { + ret = DecodeImageInfo(); + if (ret != GifDecodeStatus::Success) + return ret; + + continue; + } + case GIF_D_STATUS_IMG_DATA: { + uint8_t* data_size_ptr = nullptr; + uint8_t* data_ptr = nullptr; + uint32_t skip_size_org = skip_size; + if (!ReadData(&data_size_ptr, 1)) + return GifDecodeStatus::Unfinished; + + while (*data_size_ptr != GIF_BLOCK_TERMINAL) { + if (!ReadData(&data_ptr, *data_size_ptr)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + SaveDecodingStatus(GIF_D_STATUS_IMG_DATA); + skip_size_org = skip_size; + if (!ReadData(&data_size_ptr, 1)) + return GifDecodeStatus::Unfinished; + } + SaveDecodingStatus(GIF_D_STATUS_SIG); + continue; + } + default: { + ret = DecodeExtension(); + if (ret != GifDecodeStatus::Success) + return ret; + break; + } + } + } + return GifDecodeStatus::Success; +} + +GifDecodeStatus CGifContext::LoadFrame(int32_t frame_num) { + if (!pdfium::IndexInBounds(m_Images, frame_num)) + return GifDecodeStatus::Error; + + uint8_t* data_size_ptr = nullptr; + uint8_t* data_ptr = nullptr; + uint32_t skip_size_org = skip_size; + GifImage* gif_image_ptr = m_Images[frame_num].get(); + uint32_t gif_img_row_bytes = gif_image_ptr->m_ImageInfo.width; + if (gif_img_row_bytes == 0) { + AddError("Error Invalid Number of Row Bytes"); + return GifDecodeStatus::Error; + } + if (decode_status == GIF_D_STATUS_TAIL) { + gif_image_ptr->m_ImageRowBuf.resize(gif_img_row_bytes); + GifGCE* gif_img_gce_ptr = gif_image_ptr->m_ImageGCE.get(); + int32_t loc_pal_num = + ((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->local_pal + ? (2 << ((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->pal_bits) + : 0; + avail_in = 0; + GifPalette* pLocalPalette = gif_image_ptr->m_LocalPalettes.empty() + ? nullptr + : gif_image_ptr->m_LocalPalettes.data(); + if (!gif_img_gce_ptr) { + bool bRes = GetRecordPosition( + gif_image_ptr->image_data_pos, gif_image_ptr->m_ImageInfo.left, + gif_image_ptr->m_ImageInfo.top, gif_image_ptr->m_ImageInfo.width, + gif_image_ptr->m_ImageInfo.height, loc_pal_num, pLocalPalette, 0, 0, + -1, 0, + (bool)((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->interlace); + if (!bRes) { + gif_image_ptr->m_ImageRowBuf.clear(); + AddError("Error Read Record Position Data"); + return GifDecodeStatus::Error; + } + } else { + bool bRes = GetRecordPosition( + gif_image_ptr->image_data_pos, gif_image_ptr->m_ImageInfo.left, + gif_image_ptr->m_ImageInfo.top, gif_image_ptr->m_ImageInfo.width, + gif_image_ptr->m_ImageInfo.height, loc_pal_num, pLocalPalette, + (int32_t)gif_image_ptr->m_ImageGCE->delay_time, + (bool)((GifCEF*)&gif_image_ptr->m_ImageGCE->gce_flag)->user_input, + ((GifCEF*)&gif_image_ptr->m_ImageGCE->gce_flag)->transparency + ? (int32_t)gif_image_ptr->m_ImageGCE->trans_index + : -1, + (int32_t)((GifCEF*)&gif_image_ptr->m_ImageGCE->gce_flag) + ->disposal_method, + (bool)((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->interlace); + if (!bRes) { + gif_image_ptr->m_ImageRowBuf.clear(); + AddError("Error Read Record Position Data"); + return GifDecodeStatus::Error; + } + } + if (gif_image_ptr->image_code_exp > GIF_MAX_LZW_EXP) { + gif_image_ptr->m_ImageRowBuf.clear(); + 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; + + if (*data_size_ptr != GIF_BLOCK_TERMINAL) { + if (!ReadData(&data_ptr, *data_size_ptr)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + img_decoder_ptr->Input(data_ptr, *data_size_ptr); + 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); + if (ret == GifDecodeStatus::Error) { + DecodingFailureAtTailCleanup(gif_image_ptr); + return GifDecodeStatus::Error; + } + while (ret != GifDecodeStatus::Error) { + if (ret == GifDecodeStatus::Success) { + ReadScanline(gif_image_ptr->image_row_num, + gif_image_ptr->m_ImageRowBuf.data()); + gif_image_ptr->m_ImageRowBuf.clear(); + SaveDecodingStatus(GIF_D_STATUS_TAIL); + 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; + + if (*data_size_ptr != GIF_BLOCK_TERMINAL) { + if (!ReadData(&data_ptr, *data_size_ptr)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + img_decoder_ptr->Input(data_ptr, *data_size_ptr); + 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); + } + } + if (ret == GifDecodeStatus::InsufficientDestSize) { + if (((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->interlace) { + ReadScanline(gif_image_ptr->image_row_num, + gif_image_ptr->m_ImageRowBuf.data()); + gif_image_ptr->image_row_num += s_gif_interlace_step[img_pass_num]; + if (gif_image_ptr->image_row_num >= + (int32_t)gif_image_ptr->m_ImageInfo.height) { + img_pass_num++; + if (img_pass_num == FX_ArraySize(s_gif_interlace_step)) { + DecodingFailureAtTailCleanup(gif_image_ptr); + return GifDecodeStatus::Error; + } + gif_image_ptr->image_row_num = + s_gif_interlace_step[img_pass_num] / 2; + } + } else { + ReadScanline(gif_image_ptr->image_row_num++, + gif_image_ptr->m_ImageRowBuf.data()); + } + 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); + } + if (ret == GifDecodeStatus::Error) { + DecodingFailureAtTailCleanup(gif_image_ptr); + return GifDecodeStatus::Error; + } + } + } + SaveDecodingStatus(GIF_D_STATUS_TAIL); + } + AddError("Decode Image Data Error"); + return GifDecodeStatus::Error; +} + +void CGifContext::SetInputBuffer(uint8_t* src_buf, uint32_t src_size) { + next_in = src_buf; + avail_in = src_size; + skip_size = 0; +} + +uint32_t CGifContext::GetAvailInput(uint8_t** avail_buf_ptr) const { + if (avail_buf_ptr) { + *avail_buf_ptr = nullptr; + if (avail_in > 0) + *avail_buf_ptr = next_in; + } + return avail_in; +} + +int32_t CGifContext::GetFrameNum() const { + return pdfium::CollectionSize<int32_t>(m_Images); +} + +uint8_t* CGifContext::ReadData(uint8_t** des_buf_pp, uint32_t data_size) { + if (avail_in < skip_size + data_size) + return nullptr; + + *des_buf_pp = next_in + skip_size; + skip_size += data_size; + return *des_buf_pp; +} + +void CGifContext::SaveDecodingStatus(int32_t status) { + decode_status = status; + next_in += skip_size; + avail_in -= skip_size; + skip_size = 0; +} + +GifDecodeStatus CGifContext::DecodeExtension() { + uint8_t* data_size_ptr = nullptr; + uint8_t* data_ptr = nullptr; + uint32_t skip_size_org = skip_size; + switch (decode_status) { + case GIF_D_STATUS_EXT_CE: { + if (!ReadData(&data_size_ptr, 1)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + cmt_data.clear(); + while (*data_size_ptr != GIF_BLOCK_TERMINAL) { + uint8_t data_size = *data_size_ptr; + if (!ReadData(&data_ptr, *data_size_ptr) || + !ReadData(&data_size_ptr, 1)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + cmt_data += ByteString(data_ptr, data_size); + } + break; + } + case GIF_D_STATUS_EXT_PTE: { + GifPTE* gif_pte = nullptr; + if (!ReadData(reinterpret_cast<uint8_t**>(&gif_pte), 13)) + return GifDecodeStatus::Unfinished; + + m_GifGCE = nullptr; + if (!ReadData(&data_size_ptr, 1)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + while (*data_size_ptr != GIF_BLOCK_TERMINAL) { + if (!ReadData(&data_ptr, *data_size_ptr) || + !ReadData(&data_size_ptr, 1)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + } + break; + } + case GIF_D_STATUS_EXT_GCE: { + GifGCE* gif_gce_ptr = nullptr; + if (!ReadData(reinterpret_cast<uint8_t**>(&gif_gce_ptr), 6)) + return GifDecodeStatus::Unfinished; + + if (!m_GifGCE.get()) + m_GifGCE = pdfium::MakeUnique<GifGCE>(); + m_GifGCE->block_size = gif_gce_ptr->block_size; + m_GifGCE->gce_flag = gif_gce_ptr->gce_flag; + m_GifGCE->delay_time = GetWord_LSBFirst( + reinterpret_cast<uint8_t*>(&gif_gce_ptr->delay_time)); + m_GifGCE->trans_index = gif_gce_ptr->trans_index; + break; + } + default: { + if (decode_status == GIF_D_STATUS_EXT_PTE) + m_GifGCE = nullptr; + if (!ReadData(&data_size_ptr, 1)) + return GifDecodeStatus::Unfinished; + + while (*data_size_ptr != GIF_BLOCK_TERMINAL) { + if (!ReadData(&data_ptr, *data_size_ptr) || + !ReadData(&data_size_ptr, 1)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + } + } + } + SaveDecodingStatus(GIF_D_STATUS_SIG); + return GifDecodeStatus::Success; +} + +GifDecodeStatus CGifContext::DecodeImageInfo() { + if (width == 0 || height == 0) { + AddError("No Image Header Info"); + return GifDecodeStatus::Error; + } + uint32_t skip_size_org = skip_size; + GifImageInfo* gif_img_info_ptr = nullptr; + if (!ReadData(reinterpret_cast<uint8_t**>(&gif_img_info_ptr), 9)) + return GifDecodeStatus::Unfinished; + + auto gif_image = pdfium::MakeUnique<GifImage>(); + gif_image->m_ImageInfo.left = + GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_img_info_ptr->left)); + gif_image->m_ImageInfo.top = + GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_img_info_ptr->top)); + gif_image->m_ImageInfo.width = + GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_img_info_ptr->width)); + gif_image->m_ImageInfo.height = + GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_img_info_ptr->height)); + gif_image->m_ImageInfo.local_flag = gif_img_info_ptr->local_flag; + if (gif_image->m_ImageInfo.left + gif_image->m_ImageInfo.width > width || + gif_image->m_ImageInfo.top + gif_image->m_ImageInfo.height > height) { + AddError("Image Data Out Of LSD, The File May Be Corrupt"); + return GifDecodeStatus::Error; + } + GifLF* gif_img_info_lf_ptr = (GifLF*)&gif_img_info_ptr->local_flag; + if (gif_img_info_lf_ptr->local_pal) { + gif_image->local_pallette_exp = gif_img_info_lf_ptr->pal_bits; + int32_t loc_pal_size = (2 << gif_img_info_lf_ptr->pal_bits) * 3; + uint8_t* loc_pal_ptr = nullptr; + if (!ReadData(&loc_pal_ptr, loc_pal_size)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + gif_image->m_LocalPalettes = std::vector<GifPalette>(loc_pal_size / 3); + std::copy(loc_pal_ptr, loc_pal_ptr + loc_pal_size, + reinterpret_cast<uint8_t*>(gif_image->m_LocalPalettes.data())); + } + uint8_t* code_size_ptr = nullptr; + if (!ReadData(&code_size_ptr, 1)) { + skip_size = skip_size_org; + return GifDecodeStatus::Unfinished; + } + gif_image->image_code_exp = *code_size_ptr; + RecordCurrentPosition(&gif_image->image_data_pos); + gif_image->image_data_pos += skip_size; + gif_image->m_ImageGCE = nullptr; + if (m_GifGCE.get()) { + gif_image->m_ImageGCE = std::move(m_GifGCE); + m_GifGCE = nullptr; + } + m_Images.push_back(std::move(gif_image)); + SaveDecodingStatus(GIF_D_STATUS_IMG_DATA); + return GifDecodeStatus::Success; +} + +void CGifContext::DecodingFailureAtTailCleanup(GifImage* gif_image_ptr) { + gif_image_ptr->m_ImageRowBuf.clear(); + SaveDecodingStatus(GIF_D_STATUS_TAIL); + AddError("Decode Image Data Error"); +} diff --git a/core/fxcodec/lgif/cgifcontext.h b/core/fxcodec/lgif/cgifcontext.h index 71cf2bc75e..fdff235355 100644 --- a/core/fxcodec/lgif/cgifcontext.h +++ b/core/fxcodec/lgif/cgifcontext.h @@ -36,6 +36,12 @@ class CGifContext : public CCodec_GifModule::Context { int32_t trans_index, int32_t disposal_method, bool interlace); + GifDecodeStatus ReadHeader(); + GifDecodeStatus GetFrame(); + GifDecodeStatus LoadFrame(int32_t frame_num); + void SetInputBuffer(uint8_t* src_buf, uint32_t src_size); + uint32_t GetAvailInput(uint8_t** avail_buf_ptr) const; + int32_t GetFrameNum() const; UnownedPtr<CCodec_GifModule> m_pModule; UnownedPtr<CCodec_GifModule::Delegate> m_pDelegate; @@ -59,6 +65,13 @@ class CGifContext : public CCodec_GifModule::Context { uint8_t global_color_resolution; uint8_t img_pass_num; char m_szLastError[GIF_MAX_ERROR_SIZE]; + + private: + uint8_t* ReadData(uint8_t** des_buf_pp, uint32_t data_size); + void SaveDecodingStatus(int32_t status); + GifDecodeStatus DecodeExtension(); + GifDecodeStatus DecodeImageInfo(); + void DecodingFailureAtTailCleanup(GifImage* gif_image_ptr); }; #endif // CORE_FXCODEC_LGIF_CGIFCONTEXT_H_ diff --git a/core/fxcodec/lgif/fx_gif.cpp b/core/fxcodec/lgif/fx_gif.cpp index ea78259420..6e1c26ed12 100644 --- a/core/fxcodec/lgif/fx_gif.cpp +++ b/core/fxcodec/lgif/fx_gif.cpp @@ -23,168 +23,6 @@ static_assert(sizeof(GifGCE) == 5, "GifGCE should have a size of 5"); static_assert(sizeof(GifHeader) == 6, "GifHeader should have a size of 6"); static_assert(sizeof(GifLSD) == 7, "GifLSD should have a size of 7"); -namespace { - -uint8_t* gif_read_data(CGifContext* context, - uint8_t** des_buf_pp, - uint32_t data_size) { - if (!context || context->avail_in < context->skip_size + data_size) - return nullptr; - - *des_buf_pp = context->next_in + context->skip_size; - context->skip_size += data_size; - return *des_buf_pp; -} - -void gif_save_decoding_status(CGifContext* context, int32_t status) { - context->decode_status = status; - context->next_in += context->skip_size; - context->avail_in -= context->skip_size; - context->skip_size = 0; -} - -GifDecodeStatus gif_decode_extension(CGifContext* context) { - uint8_t* data_size_ptr = nullptr; - uint8_t* data_ptr = nullptr; - uint32_t skip_size_org = context->skip_size; - switch (context->decode_status) { - case GIF_D_STATUS_EXT_CE: { - if (!gif_read_data(context, &data_size_ptr, 1)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - context->cmt_data.clear(); - while (*data_size_ptr != GIF_BLOCK_TERMINAL) { - uint8_t data_size = *data_size_ptr; - if (!gif_read_data(context, &data_ptr, *data_size_ptr) || - !gif_read_data(context, &data_size_ptr, 1)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - context->cmt_data += ByteString(data_ptr, data_size); - } - break; - } - case GIF_D_STATUS_EXT_PTE: { - GifPTE* gif_pte = nullptr; - if (!gif_read_data(context, reinterpret_cast<uint8_t**>(&gif_pte), 13)) - return GifDecodeStatus::Unfinished; - - context->m_GifGCE = nullptr; - if (!gif_read_data(context, &data_size_ptr, 1)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - while (*data_size_ptr != GIF_BLOCK_TERMINAL) { - if (!gif_read_data(context, &data_ptr, *data_size_ptr) || - !gif_read_data(context, &data_size_ptr, 1)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - } - break; - } - case GIF_D_STATUS_EXT_GCE: { - GifGCE* gif_gce_ptr = nullptr; - if (!gif_read_data(context, reinterpret_cast<uint8_t**>(&gif_gce_ptr), 6)) - return GifDecodeStatus::Unfinished; - - if (!context->m_GifGCE.get()) - context->m_GifGCE = pdfium::MakeUnique<GifGCE>(); - context->m_GifGCE->block_size = gif_gce_ptr->block_size; - context->m_GifGCE->gce_flag = gif_gce_ptr->gce_flag; - context->m_GifGCE->delay_time = GetWord_LSBFirst( - reinterpret_cast<uint8_t*>(&gif_gce_ptr->delay_time)); - context->m_GifGCE->trans_index = gif_gce_ptr->trans_index; - break; - } - default: { - if (context->decode_status == GIF_D_STATUS_EXT_PTE) - context->m_GifGCE = nullptr; - if (!gif_read_data(context, &data_size_ptr, 1)) - return GifDecodeStatus::Unfinished; - - while (*data_size_ptr != GIF_BLOCK_TERMINAL) { - if (!gif_read_data(context, &data_ptr, *data_size_ptr) || - !gif_read_data(context, &data_size_ptr, 1)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - } - } - } - gif_save_decoding_status(context, GIF_D_STATUS_SIG); - return GifDecodeStatus::Success; -} - -GifDecodeStatus gif_decode_image_info(CGifContext* context) { - if (context->width == 0 || context->height == 0) { - context->AddError("No Image Header Info"); - return GifDecodeStatus::Error; - } - uint32_t skip_size_org = context->skip_size; - GifImageInfo* gif_img_info_ptr = nullptr; - if (!gif_read_data(context, reinterpret_cast<uint8_t**>(&gif_img_info_ptr), - 9)) - return GifDecodeStatus::Unfinished; - - auto gif_image = pdfium::MakeUnique<GifImage>(); - gif_image->m_ImageInfo.left = - GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_img_info_ptr->left)); - gif_image->m_ImageInfo.top = - GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_img_info_ptr->top)); - gif_image->m_ImageInfo.width = - GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_img_info_ptr->width)); - gif_image->m_ImageInfo.height = - GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_img_info_ptr->height)); - gif_image->m_ImageInfo.local_flag = gif_img_info_ptr->local_flag; - if (gif_image->m_ImageInfo.left + gif_image->m_ImageInfo.width > - context->width || - gif_image->m_ImageInfo.top + gif_image->m_ImageInfo.height > - context->height) { - context->AddError("Image Data Out Of LSD, The File May Be Corrupt"); - return GifDecodeStatus::Error; - } - GifLF* gif_img_info_lf_ptr = (GifLF*)&gif_img_info_ptr->local_flag; - if (gif_img_info_lf_ptr->local_pal) { - gif_image->local_pallette_exp = gif_img_info_lf_ptr->pal_bits; - int32_t loc_pal_size = (2 << gif_img_info_lf_ptr->pal_bits) * 3; - uint8_t* loc_pal_ptr = nullptr; - if (!gif_read_data(context, &loc_pal_ptr, loc_pal_size)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - gif_image->m_LocalPalettes = std::vector<GifPalette>(loc_pal_size / 3); - std::copy(loc_pal_ptr, loc_pal_ptr + loc_pal_size, - reinterpret_cast<uint8_t*>(gif_image->m_LocalPalettes.data())); - } - uint8_t* code_size_ptr = nullptr; - if (!gif_read_data(context, &code_size_ptr, 1)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - gif_image->image_code_exp = *code_size_ptr; - context->RecordCurrentPosition(&gif_image->image_data_pos); - gif_image->image_data_pos += context->skip_size; - gif_image->m_ImageGCE = nullptr; - if (context->m_GifGCE.get()) { - gif_image->m_ImageGCE = std::move(context->m_GifGCE); - context->m_GifGCE = nullptr; - } - context->m_Images.push_back(std::move(gif_image)); - gif_save_decoding_status(context, GIF_D_STATUS_IMG_DATA); - return GifDecodeStatus::Success; -} - -void gif_decoding_failure_at_tail_cleanup(CGifContext* context, - GifImage* gif_image_ptr) { - gif_image_ptr->m_ImageRowBuf.clear(); - gif_save_decoding_status(context, GIF_D_STATUS_TAIL); - context->AddError("Decode Image Data Error"); -} - -} // namespace - GifImage::GifImage() {} GifImage::~GifImage() {} @@ -369,325 +207,3 @@ GifDecodeStatus CGifLZWDecoder::Decode(uint8_t* des_buf, uint32_t* des_size) { } return GifDecodeStatus::Error; } - -GifDecodeStatus gif_read_header(CGifContext* context) { - if (!context) - return GifDecodeStatus::Error; - - uint32_t skip_size_org = context->skip_size; - GifHeader* gif_header_ptr = nullptr; - if (!gif_read_data(context, reinterpret_cast<uint8_t**>(&gif_header_ptr), 6)) - return GifDecodeStatus::Unfinished; - - if (strncmp(gif_header_ptr->signature, GIF_SIGNATURE, 3) != 0 || - gif_header_ptr->version[0] != '8' || gif_header_ptr->version[2] != 'a') { - context->AddError("Not A Gif Image"); - return GifDecodeStatus::Error; - } - GifLSD* gif_lsd_ptr = nullptr; - if (!gif_read_data(context, reinterpret_cast<uint8_t**>(&gif_lsd_ptr), 7)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - if (reinterpret_cast<GifGF*>(&gif_lsd_ptr->global_flag)->global_pal) { - context->global_pal_exp = - reinterpret_cast<GifGF*>(&gif_lsd_ptr->global_flag)->pal_bits; - int32_t global_pal_size = (2 << context->global_pal_exp) * 3; - uint8_t* global_pal_ptr = nullptr; - if (!gif_read_data(context, &global_pal_ptr, global_pal_size)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - context->global_sort_flag = ((GifGF*)&gif_lsd_ptr->global_flag)->sort_flag; - context->global_color_resolution = - ((GifGF*)&gif_lsd_ptr->global_flag)->color_resolution; - context->m_GlobalPalette.resize(global_pal_size / 3); - memcpy(context->m_GlobalPalette.data(), global_pal_ptr, global_pal_size); - } - context->width = - (int)GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_lsd_ptr->width)); - context->height = - (int)GetWord_LSBFirst(reinterpret_cast<uint8_t*>(&gif_lsd_ptr->height)); - context->bc_index = gif_lsd_ptr->bc_index; - context->pixel_aspect = gif_lsd_ptr->pixel_aspect; - return GifDecodeStatus::Success; -} - -GifDecodeStatus gif_get_frame(CGifContext* context) { - if (!context) - return GifDecodeStatus::Error; - - GifDecodeStatus ret = GifDecodeStatus::Success; - while (true) { - switch (context->decode_status) { - case GIF_D_STATUS_TAIL: - return GifDecodeStatus::Success; - case GIF_D_STATUS_SIG: { - uint8_t* sig_ptr = nullptr; - if (!gif_read_data(context, &sig_ptr, 1)) - return GifDecodeStatus::Unfinished; - - switch (*sig_ptr) { - case GIF_SIG_EXTENSION: - gif_save_decoding_status(context, GIF_D_STATUS_EXT); - continue; - case GIF_SIG_IMAGE: - gif_save_decoding_status(context, GIF_D_STATUS_IMG_INFO); - continue; - case GIF_SIG_TRAILER: - gif_save_decoding_status(context, GIF_D_STATUS_TAIL); - return GifDecodeStatus::Success; - default: - if (context->avail_in) { - // The Gif File has non_standard Tag! - gif_save_decoding_status(context, GIF_D_STATUS_SIG); - continue; - } - // The Gif File Doesn't have Trailer Tag! - return GifDecodeStatus::Success; - } - } - case GIF_D_STATUS_EXT: { - uint8_t* ext_ptr = nullptr; - if (!gif_read_data(context, &ext_ptr, 1)) - return GifDecodeStatus::Unfinished; - - switch (*ext_ptr) { - case GIF_BLOCK_CE: - gif_save_decoding_status(context, GIF_D_STATUS_EXT_CE); - continue; - case GIF_BLOCK_GCE: - gif_save_decoding_status(context, GIF_D_STATUS_EXT_GCE); - continue; - case GIF_BLOCK_PTE: - gif_save_decoding_status(context, GIF_D_STATUS_EXT_PTE); - continue; - default: { - int32_t status = GIF_D_STATUS_EXT_UNE; - if (*ext_ptr == GIF_BLOCK_PTE) { - status = GIF_D_STATUS_EXT_PTE; - } - gif_save_decoding_status(context, status); - continue; - } - } - } - case GIF_D_STATUS_IMG_INFO: { - ret = gif_decode_image_info(context); - if (ret != GifDecodeStatus::Success) - return ret; - - continue; - } - case GIF_D_STATUS_IMG_DATA: { - uint8_t* data_size_ptr = nullptr; - uint8_t* data_ptr = nullptr; - uint32_t skip_size_org = context->skip_size; - if (!gif_read_data(context, &data_size_ptr, 1)) - return GifDecodeStatus::Unfinished; - - while (*data_size_ptr != GIF_BLOCK_TERMINAL) { - if (!gif_read_data(context, &data_ptr, *data_size_ptr)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - gif_save_decoding_status(context, GIF_D_STATUS_IMG_DATA); - skip_size_org = context->skip_size; - if (!gif_read_data(context, &data_size_ptr, 1)) - return GifDecodeStatus::Unfinished; - } - gif_save_decoding_status(context, GIF_D_STATUS_SIG); - continue; - } - default: { - ret = gif_decode_extension(context); - if (ret != GifDecodeStatus::Success) - return ret; - break; - } - } - } - return GifDecodeStatus::Success; -} - -GifDecodeStatus gif_load_frame(CGifContext* context, int32_t frame_num) { - if (!context || !pdfium::IndexInBounds(context->m_Images, frame_num)) - return GifDecodeStatus::Error; - - uint8_t* data_size_ptr = nullptr; - uint8_t* data_ptr = nullptr; - uint32_t skip_size_org = context->skip_size; - GifImage* gif_image_ptr = context->m_Images[frame_num].get(); - uint32_t gif_img_row_bytes = gif_image_ptr->m_ImageInfo.width; - if (gif_img_row_bytes == 0) { - context->AddError("Error Invalid Number of Row Bytes"); - return GifDecodeStatus::Error; - } - if (context->decode_status == GIF_D_STATUS_TAIL) { - gif_image_ptr->m_ImageRowBuf.resize(gif_img_row_bytes); - GifGCE* gif_img_gce_ptr = gif_image_ptr->m_ImageGCE.get(); - int32_t loc_pal_num = - ((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->local_pal - ? (2 << ((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->pal_bits) - : 0; - context->avail_in = 0; - GifPalette* pLocalPalette = gif_image_ptr->m_LocalPalettes.empty() - ? nullptr - : gif_image_ptr->m_LocalPalettes.data(); - if (!gif_img_gce_ptr) { - bool bRes = context->GetRecordPosition( - gif_image_ptr->image_data_pos, gif_image_ptr->m_ImageInfo.left, - gif_image_ptr->m_ImageInfo.top, gif_image_ptr->m_ImageInfo.width, - gif_image_ptr->m_ImageInfo.height, loc_pal_num, pLocalPalette, 0, 0, - -1, 0, - (bool)((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->interlace); - if (!bRes) { - gif_image_ptr->m_ImageRowBuf.clear(); - context->AddError("Error Read Record Position Data"); - return GifDecodeStatus::Error; - } - } else { - bool bRes = context->GetRecordPosition( - gif_image_ptr->image_data_pos, gif_image_ptr->m_ImageInfo.left, - gif_image_ptr->m_ImageInfo.top, gif_image_ptr->m_ImageInfo.width, - gif_image_ptr->m_ImageInfo.height, loc_pal_num, pLocalPalette, - (int32_t)gif_image_ptr->m_ImageGCE->delay_time, - (bool)((GifCEF*)&gif_image_ptr->m_ImageGCE->gce_flag)->user_input, - ((GifCEF*)&gif_image_ptr->m_ImageGCE->gce_flag)->transparency - ? (int32_t)gif_image_ptr->m_ImageGCE->trans_index - : -1, - (int32_t)((GifCEF*)&gif_image_ptr->m_ImageGCE->gce_flag) - ->disposal_method, - (bool)((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->interlace); - if (!bRes) { - gif_image_ptr->m_ImageRowBuf.clear(); - context->AddError("Error Read Record Position Data"); - return GifDecodeStatus::Error; - } - } - if (gif_image_ptr->image_code_exp > GIF_MAX_LZW_EXP) { - gif_image_ptr->m_ImageRowBuf.clear(); - context->AddError("Error Invalid Code Size"); - return GifDecodeStatus::Error; - } - if (!context->m_ImgDecoder.get()) - context->m_ImgDecoder = - pdfium::MakeUnique<CGifLZWDecoder>(context->m_szLastError); - context->m_ImgDecoder->InitTable(!gif_image_ptr->m_LocalPalettes.empty() - ? gif_image_ptr->local_pallette_exp - : context->global_pal_exp, - gif_image_ptr->image_code_exp); - context->img_row_offset = 0; - context->img_row_avail_size = 0; - context->img_pass_num = 0; - gif_image_ptr->image_row_num = 0; - gif_save_decoding_status(context, GIF_D_STATUS_IMG_DATA); - } - CGifLZWDecoder* img_decoder_ptr = context->m_ImgDecoder.get(); - if (context->decode_status == GIF_D_STATUS_IMG_DATA) { - if (!gif_read_data(context, &data_size_ptr, 1)) - return GifDecodeStatus::Unfinished; - - if (*data_size_ptr != GIF_BLOCK_TERMINAL) { - if (!gif_read_data(context, &data_ptr, *data_size_ptr)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - img_decoder_ptr->Input(data_ptr, *data_size_ptr); - gif_save_decoding_status(context, GIF_D_STATUS_IMG_DATA); - context->img_row_offset += context->img_row_avail_size; - context->img_row_avail_size = gif_img_row_bytes - context->img_row_offset; - GifDecodeStatus ret = img_decoder_ptr->Decode( - gif_image_ptr->m_ImageRowBuf.data() + context->img_row_offset, - &context->img_row_avail_size); - if (ret == GifDecodeStatus::Error) { - gif_decoding_failure_at_tail_cleanup(context, gif_image_ptr); - return GifDecodeStatus::Error; - } - while (ret != GifDecodeStatus::Error) { - if (ret == GifDecodeStatus::Success) { - context->ReadScanline(gif_image_ptr->image_row_num, - gif_image_ptr->m_ImageRowBuf.data()); - gif_image_ptr->m_ImageRowBuf.clear(); - gif_save_decoding_status(context, GIF_D_STATUS_TAIL); - return GifDecodeStatus::Success; - } - if (ret == GifDecodeStatus::Unfinished) { - ASSERT(img_decoder_ptr->GetAvailInput() == 0); - skip_size_org = context->skip_size; - if (!gif_read_data(context, &data_size_ptr, 1)) - return GifDecodeStatus::Unfinished; - - if (*data_size_ptr != GIF_BLOCK_TERMINAL) { - if (!gif_read_data(context, &data_ptr, *data_size_ptr)) { - context->skip_size = skip_size_org; - return GifDecodeStatus::Unfinished; - } - img_decoder_ptr->Input(data_ptr, *data_size_ptr); - gif_save_decoding_status(context, GIF_D_STATUS_IMG_DATA); - context->img_row_offset += context->img_row_avail_size; - context->img_row_avail_size = - gif_img_row_bytes - context->img_row_offset; - ret = img_decoder_ptr->Decode( - gif_image_ptr->m_ImageRowBuf.data() + context->img_row_offset, - &context->img_row_avail_size); - } - } - if (ret == GifDecodeStatus::InsufficientDestSize) { - if (((GifLF*)&gif_image_ptr->m_ImageInfo.local_flag)->interlace) { - context->ReadScanline(gif_image_ptr->image_row_num, - gif_image_ptr->m_ImageRowBuf.data()); - gif_image_ptr->image_row_num += - s_gif_interlace_step[context->img_pass_num]; - if (gif_image_ptr->image_row_num >= - (int32_t)gif_image_ptr->m_ImageInfo.height) { - context->img_pass_num++; - if (context->img_pass_num == FX_ArraySize(s_gif_interlace_step)) { - gif_decoding_failure_at_tail_cleanup(context, gif_image_ptr); - return GifDecodeStatus::Error; - } - gif_image_ptr->image_row_num = - s_gif_interlace_step[context->img_pass_num] / 2; - } - } else { - context->ReadScanline(gif_image_ptr->image_row_num++, - gif_image_ptr->m_ImageRowBuf.data()); - } - context->img_row_offset = 0; - context->img_row_avail_size = gif_img_row_bytes; - ret = img_decoder_ptr->Decode( - gif_image_ptr->m_ImageRowBuf.data() + context->img_row_offset, - &context->img_row_avail_size); - } - if (ret == GifDecodeStatus::Error) { - gif_decoding_failure_at_tail_cleanup(context, gif_image_ptr); - return GifDecodeStatus::Error; - } - } - } - gif_save_decoding_status(context, GIF_D_STATUS_TAIL); - } - context->AddError("Decode Image Data Error"); - return GifDecodeStatus::Error; -} - -void gif_input_buffer(CGifContext* context, - uint8_t* src_buf, - uint32_t src_size) { - context->next_in = src_buf; - context->avail_in = src_size; - context->skip_size = 0; -} - -uint32_t gif_get_avail_input(CGifContext* context, uint8_t** avail_buf_ptr) { - if (avail_buf_ptr) { - *avail_buf_ptr = nullptr; - if (context->avail_in > 0) - *avail_buf_ptr = context->next_in; - } - return context->avail_in; -} - -int32_t gif_get_frame_num(CGifContext* context) { - return pdfium::CollectionSize<int32_t>(context->m_Images); -} diff --git a/core/fxcodec/lgif/fx_gif.h b/core/fxcodec/lgif/fx_gif.h index bddb22b30c..c3ddf36e3b 100644 --- a/core/fxcodec/lgif/fx_gif.h +++ b/core/fxcodec/lgif/fx_gif.h @@ -164,15 +164,4 @@ class CGifLZWDecoder { char* err_msg_ptr; }; -static const int32_t s_gif_interlace_step[4] = {8, 8, 4, 2}; - -GifDecodeStatus gif_read_header(CGifContext* gif_ptr); -GifDecodeStatus gif_get_frame(CGifContext* gif_ptr); -int32_t gif_get_frame_num(CGifContext* gif_ptr); -GifDecodeStatus gif_load_frame(CGifContext* gif_ptr, int32_t frame_num); -void gif_input_buffer(CGifContext* gif_ptr, - uint8_t* src_buf, - uint32_t src_size); -uint32_t gif_get_avail_input(CGifContext* gif_ptr, uint8_t** avail_buf_ptr); - #endif // CORE_FXCODEC_LGIF_FX_GIF_H_ |