From 48cd65d67eead592bce6c67084047ad6a7071267 Mon Sep 17 00:00:00 2001 From: Tom Sepez Date: Tue, 28 Aug 2018 22:37:20 +0000 Subject: Rename remaining fx_codec*.cpp to match class and .h file name Then include headers in the proper order per standards, since it will no longer trigger a presubmit warning. Change-Id: I6bb86ac90e8fd9aed30b66dac61726f0dea8222c Reviewed-on: https://pdfium-review.googlesource.com/41535 Commit-Queue: Tom Sepez Reviewed-by: Lei Zhang --- BUILD.gn | 10 +- core/fxcodec/codec/ccodec_faxmodule.cpp | 804 ++++++++++++++++++++++++++++ core/fxcodec/codec/ccodec_flatemodule.cpp | 852 ++++++++++++++++++++++++++++++ core/fxcodec/codec/ccodec_iccmodule.cpp | 146 +++++ core/fxcodec/codec/ccodec_jbig2module.cpp | 94 ++++ core/fxcodec/codec/ccodec_jpxmodule.cpp | 668 +++++++++++++++++++++++ core/fxcodec/codec/fx_codec_fax.cpp | 803 ---------------------------- core/fxcodec/codec/fx_codec_flate.cpp | 852 ------------------------------ core/fxcodec/codec/fx_codec_icc.cpp | 145 ----- core/fxcodec/codec/fx_codec_jbig.cpp | 94 ---- core/fxcodec/codec/fx_codec_jpx_opj.cpp | 667 ----------------------- 11 files changed, 2569 insertions(+), 2566 deletions(-) create mode 100644 core/fxcodec/codec/ccodec_faxmodule.cpp create mode 100644 core/fxcodec/codec/ccodec_flatemodule.cpp create mode 100644 core/fxcodec/codec/ccodec_iccmodule.cpp create mode 100644 core/fxcodec/codec/ccodec_jbig2module.cpp create mode 100644 core/fxcodec/codec/ccodec_jpxmodule.cpp delete mode 100644 core/fxcodec/codec/fx_codec_fax.cpp delete mode 100644 core/fxcodec/codec/fx_codec_flate.cpp delete mode 100644 core/fxcodec/codec/fx_codec_icc.cpp delete mode 100644 core/fxcodec/codec/fx_codec_jbig.cpp delete mode 100644 core/fxcodec/codec/fx_codec_jpx_opj.cpp diff --git a/BUILD.gn b/BUILD.gn index 8386f034d4..e3ba58cf02 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -723,23 +723,23 @@ jumbo_static_library("fxcodec") { sources = [ "core/fxcodec/JBig2_DocumentContext.h", "core/fxcodec/codec/ccodec_basicmodule.h", + "core/fxcodec/codec/ccodec_faxmodule.cpp", "core/fxcodec/codec/ccodec_faxmodule.h", + "core/fxcodec/codec/ccodec_flatemodule.cpp", "core/fxcodec/codec/ccodec_flatemodule.h", + "core/fxcodec/codec/ccodec_iccmodule.cpp", "core/fxcodec/codec/ccodec_iccmodule.h", + "core/fxcodec/codec/ccodec_jbig2module.cpp", "core/fxcodec/codec/ccodec_jbig2module.h", "core/fxcodec/codec/ccodec_jpegmodule.cpp", "core/fxcodec/codec/ccodec_jpegmodule.h", + "core/fxcodec/codec/ccodec_jpxmodule.cpp", "core/fxcodec/codec/ccodec_jpxmodule.h", "core/fxcodec/codec/ccodec_scanlinedecoder.cpp", "core/fxcodec/codec/ccodec_scanlinedecoder.h", "core/fxcodec/codec/cjpx_decoder.h", "core/fxcodec/codec/codec_int.h", "core/fxcodec/codec/fx_codec.cpp", - "core/fxcodec/codec/fx_codec_fax.cpp", - "core/fxcodec/codec/fx_codec_flate.cpp", - "core/fxcodec/codec/fx_codec_icc.cpp", - "core/fxcodec/codec/fx_codec_jbig.cpp", - "core/fxcodec/codec/fx_codec_jpx_opj.cpp", "core/fxcodec/fx_codec.h", "core/fxcodec/fx_codec_def.h", "core/fxcodec/jbig2/JBig2_ArithDecoder.cpp", diff --git a/core/fxcodec/codec/ccodec_faxmodule.cpp b/core/fxcodec/codec/ccodec_faxmodule.cpp new file mode 100644 index 0000000000..af218f7e01 --- /dev/null +++ b/core/fxcodec/codec/ccodec_faxmodule.cpp @@ -0,0 +1,804 @@ +// Copyright 2014 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/codec/ccodec_faxmodule.h" + +#include +#include +#include + +#include "core/fxcodec/codec/ccodec_scanlinedecoder.h" +#include "core/fxcodec/codec/codec_int.h" +#include "core/fxcrt/cfx_binarybuf.h" +#include "core/fxcrt/fx_memory.h" +#include "third_party/base/ptr_util.h" +#include "third_party/base/stl_util.h" + +namespace { + +const uint8_t OneLeadPos[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +// Limit of image dimension. Use the same limit as the JBIG2 codecs. +const int kMaxImageDimension = 65535; + +int FindBit(const uint8_t* data_buf, int max_pos, int start_pos, bool bit) { + ASSERT(start_pos >= 0); + if (start_pos >= max_pos) + return max_pos; + + const uint8_t bit_xor = bit ? 0x00 : 0xff; + int bit_offset = start_pos % 8; + if (bit_offset) { + const int byte_pos = start_pos / 8; + uint8_t data = (data_buf[byte_pos] ^ bit_xor) & (0xff >> bit_offset); + if (data) + return byte_pos * 8 + OneLeadPos[data]; + + start_pos += 7; + } + + const int max_byte = (max_pos + 7) / 8; + int byte_pos = start_pos / 8; + + // Try reading in bigger chunks in case there are long runs to be skipped. + static constexpr int kBulkReadSize = 8; + if (max_byte >= kBulkReadSize && byte_pos < max_byte - kBulkReadSize) { + static constexpr uint8_t skip_block_0[kBulkReadSize] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static constexpr uint8_t skip_block_1[kBulkReadSize] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const uint8_t* skip_block = bit ? skip_block_0 : skip_block_1; + while (byte_pos < max_byte - kBulkReadSize && + memcmp(data_buf + byte_pos, skip_block, kBulkReadSize) == 0) { + byte_pos += kBulkReadSize; + } + } + + while (byte_pos < max_byte) { + uint8_t data = data_buf[byte_pos] ^ bit_xor; + if (data) + return std::min(byte_pos * 8 + OneLeadPos[data], max_pos); + + ++byte_pos; + } + return max_pos; +} + +void FaxG4FindB1B2(const std::vector& ref_buf, + int columns, + int a0, + bool a0color, + int* b1, + int* b2) { + bool first_bit = a0 < 0 || (ref_buf[a0 / 8] & (1 << (7 - a0 % 8))) != 0; + *b1 = FindBit(ref_buf.data(), columns, a0 + 1, !first_bit); + if (*b1 >= columns) { + *b1 = *b2 = columns; + return; + } + if (first_bit == !a0color) { + *b1 = FindBit(ref_buf.data(), columns, *b1 + 1, first_bit); + first_bit = !first_bit; + } + if (*b1 >= columns) { + *b1 = *b2 = columns; + return; + } + *b2 = FindBit(ref_buf.data(), columns, *b1 + 1, first_bit); +} + +void FaxFillBits(uint8_t* dest_buf, int columns, int startpos, int endpos) { + startpos = std::max(startpos, 0); + endpos = pdfium::clamp(endpos, 0, columns); + if (startpos >= endpos) + return; + + int first_byte = startpos / 8; + int last_byte = (endpos - 1) / 8; + if (first_byte == last_byte) { + for (int i = startpos % 8; i <= (endpos - 1) % 8; ++i) + dest_buf[first_byte] -= 1 << (7 - i); + return; + } + + for (int i = startpos % 8; i < 8; ++i) + dest_buf[first_byte] -= 1 << (7 - i); + for (int i = 0; i <= (endpos - 1) % 8; ++i) + dest_buf[last_byte] -= 1 << (7 - i); + + if (last_byte > first_byte + 1) + memset(dest_buf + first_byte + 1, 0, last_byte - first_byte - 1); +} + +inline bool NextBit(const uint8_t* src_buf, int* bitpos) { + int pos = (*bitpos)++; + return !!(src_buf[pos / 8] & (1 << (7 - pos % 8))); +} + +const uint8_t FaxBlackRunIns[] = { + 0, 2, 0x02, 3, 0, 0x03, + 2, 0, 2, 0x02, 1, 0, + 0x03, 4, 0, 2, 0x02, 6, + 0, 0x03, 5, 0, 1, 0x03, + 7, 0, 2, 0x04, 9, 0, + 0x05, 8, 0, 3, 0x04, 10, + 0, 0x05, 11, 0, 0x07, 12, + 0, 2, 0x04, 13, 0, 0x07, + 14, 0, 1, 0x18, 15, 0, + 5, 0x08, 18, 0, 0x0f, 64, + 0, 0x17, 16, 0, 0x18, 17, + 0, 0x37, 0, 0, 10, 0x08, + 0x00, 0x07, 0x0c, 0x40, 0x07, 0x0d, + 0x80, 0x07, 0x17, 24, 0, 0x18, + 25, 0, 0x28, 23, 0, 0x37, + 22, 0, 0x67, 19, 0, 0x68, + 20, 0, 0x6c, 21, 0, 54, + 0x12, 1984 % 256, 1984 / 256, 0x13, 2048 % 256, 2048 / 256, + 0x14, 2112 % 256, 2112 / 256, 0x15, 2176 % 256, 2176 / 256, + 0x16, 2240 % 256, 2240 / 256, 0x17, 2304 % 256, 2304 / 256, + 0x1c, 2368 % 256, 2368 / 256, 0x1d, 2432 % 256, 2432 / 256, + 0x1e, 2496 % 256, 2496 / 256, 0x1f, 2560 % 256, 2560 / 256, + 0x24, 52, 0, 0x27, 55, 0, + 0x28, 56, 0, 0x2b, 59, 0, + 0x2c, 60, 0, 0x33, 320 % 256, 320 / 256, + 0x34, 384 % 256, 384 / 256, 0x35, 448 % 256, 448 / 256, + 0x37, 53, 0, 0x38, 54, 0, + 0x52, 50, 0, 0x53, 51, 0, + 0x54, 44, 0, 0x55, 45, 0, + 0x56, 46, 0, 0x57, 47, 0, + 0x58, 57, 0, 0x59, 58, 0, + 0x5a, 61, 0, 0x5b, 256 % 256, 256 / 256, + 0x64, 48, 0, 0x65, 49, 0, + 0x66, 62, 0, 0x67, 63, 0, + 0x68, 30, 0, 0x69, 31, 0, + 0x6a, 32, 0, 0x6b, 33, 0, + 0x6c, 40, 0, 0x6d, 41, 0, + 0xc8, 128, 0, 0xc9, 192, 0, + 0xca, 26, 0, 0xcb, 27, 0, + 0xcc, 28, 0, 0xcd, 29, 0, + 0xd2, 34, 0, 0xd3, 35, 0, + 0xd4, 36, 0, 0xd5, 37, 0, + 0xd6, 38, 0, 0xd7, 39, 0, + 0xda, 42, 0, 0xdb, 43, 0, + 20, 0x4a, 640 % 256, 640 / 256, 0x4b, 704 % 256, + 704 / 256, 0x4c, 768 % 256, 768 / 256, 0x4d, 832 % 256, + 832 / 256, 0x52, 1280 % 256, 1280 / 256, 0x53, 1344 % 256, + 1344 / 256, 0x54, 1408 % 256, 1408 / 256, 0x55, 1472 % 256, + 1472 / 256, 0x5a, 1536 % 256, 1536 / 256, 0x5b, 1600 % 256, + 1600 / 256, 0x64, 1664 % 256, 1664 / 256, 0x65, 1728 % 256, + 1728 / 256, 0x6c, 512 % 256, 512 / 256, 0x6d, 576 % 256, + 576 / 256, 0x72, 896 % 256, 896 / 256, 0x73, 960 % 256, + 960 / 256, 0x74, 1024 % 256, 1024 / 256, 0x75, 1088 % 256, + 1088 / 256, 0x76, 1152 % 256, 1152 / 256, 0x77, 1216 % 256, + 1216 / 256, 0xff}; + +const uint8_t FaxWhiteRunIns[] = { + 0, 0, 0, 6, 0x07, 2, + 0, 0x08, 3, 0, 0x0B, 4, + 0, 0x0C, 5, 0, 0x0E, 6, + 0, 0x0F, 7, 0, 6, 0x07, + 10, 0, 0x08, 11, 0, 0x12, + 128, 0, 0x13, 8, 0, 0x14, + 9, 0, 0x1b, 64, 0, 9, + 0x03, 13, 0, 0x07, 1, 0, + 0x08, 12, 0, 0x17, 192, 0, + 0x18, 1664 % 256, 1664 / 256, 0x2a, 16, 0, + 0x2B, 17, 0, 0x34, 14, 0, + 0x35, 15, 0, 12, 0x03, 22, + 0, 0x04, 23, 0, 0x08, 20, + 0, 0x0c, 19, 0, 0x13, 26, + 0, 0x17, 21, 0, 0x18, 28, + 0, 0x24, 27, 0, 0x27, 18, + 0, 0x28, 24, 0, 0x2B, 25, + 0, 0x37, 256 % 256, 256 / 256, 42, 0x02, + 29, 0, 0x03, 30, 0, 0x04, + 45, 0, 0x05, 46, 0, 0x0a, + 47, 0, 0x0b, 48, 0, 0x12, + 33, 0, 0x13, 34, 0, 0x14, + 35, 0, 0x15, 36, 0, 0x16, + 37, 0, 0x17, 38, 0, 0x1a, + 31, 0, 0x1b, 32, 0, 0x24, + 53, 0, 0x25, 54, 0, 0x28, + 39, 0, 0x29, 40, 0, 0x2a, + 41, 0, 0x2b, 42, 0, 0x2c, + 43, 0, 0x2d, 44, 0, 0x32, + 61, 0, 0x33, 62, 0, 0x34, + 63, 0, 0x35, 0, 0, 0x36, + 320 % 256, 320 / 256, 0x37, 384 % 256, 384 / 256, 0x4a, + 59, 0, 0x4b, 60, 0, 0x52, + 49, 0, 0x53, 50, 0, 0x54, + 51, 0, 0x55, 52, 0, 0x58, + 55, 0, 0x59, 56, 0, 0x5a, + 57, 0, 0x5b, 58, 0, 0x64, + 448 % 256, 448 / 256, 0x65, 512 % 256, 512 / 256, 0x67, + 640 % 256, 640 / 256, 0x68, 576 % 256, 576 / 256, 16, + 0x98, 1472 % 256, 1472 / 256, 0x99, 1536 % 256, 1536 / 256, + 0x9a, 1600 % 256, 1600 / 256, 0x9b, 1728 % 256, 1728 / 256, + 0xcc, 704 % 256, 704 / 256, 0xcd, 768 % 256, 768 / 256, + 0xd2, 832 % 256, 832 / 256, 0xd3, 896 % 256, 896 / 256, + 0xd4, 960 % 256, 960 / 256, 0xd5, 1024 % 256, 1024 / 256, + 0xd6, 1088 % 256, 1088 / 256, 0xd7, 1152 % 256, 1152 / 256, + 0xd8, 1216 % 256, 1216 / 256, 0xd9, 1280 % 256, 1280 / 256, + 0xda, 1344 % 256, 1344 / 256, 0xdb, 1408 % 256, 1408 / 256, + 0, 3, 0x08, 1792 % 256, 1792 / 256, 0x0c, + 1856 % 256, 1856 / 256, 0x0d, 1920 % 256, 1920 / 256, 10, + 0x12, 1984 % 256, 1984 / 256, 0x13, 2048 % 256, 2048 / 256, + 0x14, 2112 % 256, 2112 / 256, 0x15, 2176 % 256, 2176 / 256, + 0x16, 2240 % 256, 2240 / 256, 0x17, 2304 % 256, 2304 / 256, + 0x1c, 2368 % 256, 2368 / 256, 0x1d, 2432 % 256, 2432 / 256, + 0x1e, 2496 % 256, 2496 / 256, 0x1f, 2560 % 256, 2560 / 256, + 0xff, +}; + +int FaxGetRun(const uint8_t* ins_array, + const uint8_t* src_buf, + int* bitpos, + int bitsize) { + uint32_t code = 0; + int ins_off = 0; + while (1) { + uint8_t ins = ins_array[ins_off++]; + if (ins == 0xff) + return -1; + + if (*bitpos >= bitsize) + return -1; + + code <<= 1; + if (src_buf[*bitpos / 8] & (1 << (7 - *bitpos % 8))) + ++code; + + ++(*bitpos); + int next_off = ins_off + ins * 3; + for (; ins_off < next_off; ins_off += 3) { + if (ins_array[ins_off] == code) + return ins_array[ins_off + 1] + ins_array[ins_off + 2] * 256; + } + } +} + +void FaxG4GetRow(const uint8_t* src_buf, + int bitsize, + int* bitpos, + uint8_t* dest_buf, + const std::vector& ref_buf, + int columns) { + int a0 = -1; + bool a0color = true; + while (1) { + if (*bitpos >= bitsize) + return; + + int a1; + int a2; + int b1; + int b2; + FaxG4FindB1B2(ref_buf, columns, a0, a0color, &b1, &b2); + + int v_delta = 0; + if (!NextBit(src_buf, bitpos)) { + if (*bitpos >= bitsize) + return; + + bool bit1 = NextBit(src_buf, bitpos); + if (*bitpos >= bitsize) + return; + + bool bit2 = NextBit(src_buf, bitpos); + if (bit1) { + v_delta = bit2 ? 1 : -1; + } else if (bit2) { + int run_len1 = 0; + while (1) { + int run = FaxGetRun(a0color ? FaxWhiteRunIns : FaxBlackRunIns, + src_buf, bitpos, bitsize); + run_len1 += run; + if (run < 64) + break; + } + if (a0 < 0) + ++run_len1; + if (run_len1 < 0) + return; + + a1 = a0 + run_len1; + if (!a0color) + FaxFillBits(dest_buf, columns, a0, a1); + + int run_len2 = 0; + while (1) { + int run = FaxGetRun(a0color ? FaxBlackRunIns : FaxWhiteRunIns, + src_buf, bitpos, bitsize); + run_len2 += run; + if (run < 64) + break; + } + if (run_len2 < 0) + return; + a2 = a1 + run_len2; + if (a0color) + FaxFillBits(dest_buf, columns, a1, a2); + + a0 = a2; + if (a0 < columns) + continue; + + return; + } else { + if (*bitpos >= bitsize) + return; + + if (NextBit(src_buf, bitpos)) { + if (!a0color) + FaxFillBits(dest_buf, columns, a0, b2); + + if (b2 >= columns) + return; + + a0 = b2; + continue; + } + + if (*bitpos >= bitsize) + return; + + bool next_bit1 = NextBit(src_buf, bitpos); + if (*bitpos >= bitsize) + return; + + bool next_bit2 = NextBit(src_buf, bitpos); + if (next_bit1) { + v_delta = next_bit2 ? 2 : -2; + } else if (next_bit2) { + if (*bitpos >= bitsize) + return; + + v_delta = NextBit(src_buf, bitpos) ? 3 : -3; + } else { + if (*bitpos >= bitsize) + return; + + if (NextBit(src_buf, bitpos)) { + *bitpos += 3; + continue; + } + *bitpos += 5; + return; + } + } + } + a1 = b1 + v_delta; + if (!a0color) + FaxFillBits(dest_buf, columns, a0, a1); + + if (a1 >= columns) + return; + + // The position of picture element must be monotonic increasing. + if (a0 >= a1) + return; + + a0 = a1; + a0color = !a0color; + } +} + +void FaxSkipEOL(const uint8_t* src_buf, int bitsize, int* bitpos) { + int startbit = *bitpos; + while (*bitpos < bitsize) { + if (!NextBit(src_buf, bitpos)) + continue; + if (*bitpos - startbit <= 11) + *bitpos = startbit; + return; + } +} + +void FaxGet1DLine(const uint8_t* src_buf, + int bitsize, + int* bitpos, + std::vector* dest_buf, + int columns) { + bool color = true; + int startpos = 0; + while (1) { + if (*bitpos >= bitsize) + return; + + int run_len = 0; + while (1) { + int run = FaxGetRun(color ? FaxWhiteRunIns : FaxBlackRunIns, src_buf, + bitpos, bitsize); + if (run < 0) { + while (*bitpos < bitsize) { + if (NextBit(src_buf, bitpos)) + return; + } + return; + } + run_len += run; + if (run < 64) + break; + } + if (!color) + FaxFillBits(dest_buf->data(), columns, startpos, startpos + run_len); + + startpos += run_len; + if (startpos >= columns) + break; + + color = !color; + } +} + +} // namespace + +class CCodec_FaxDecoder final : public CCodec_ScanlineDecoder { + public: + CCodec_FaxDecoder(const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + uint32_t pitch, + int K, + bool EndOfLine, + bool EncodedByteAlign, + bool BlackIs1); + ~CCodec_FaxDecoder() override; + + // CCodec_ScanlineDecoder + bool v_Rewind() override; + uint8_t* v_GetNextLine() override; + uint32_t GetSrcOffset() override; + + private: + const int m_Encoding; + int m_bitpos; + bool m_bByteAlign; + const bool m_bEndOfLine; + const bool m_bBlack; + const uint32_t m_SrcSize; + const uint8_t* const m_pSrcBuf; + std::vector m_ScanlineBuf; + std::vector m_RefBuf; +}; + +CCodec_FaxDecoder::CCodec_FaxDecoder(const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + uint32_t pitch, + int K, + bool EndOfLine, + bool EncodedByteAlign, + bool BlackIs1) + : CCodec_ScanlineDecoder(width, height, width, height, 1, 1, pitch), + m_Encoding(K), + m_bitpos(0), + m_bByteAlign(EncodedByteAlign), + m_bEndOfLine(EndOfLine), + m_bBlack(BlackIs1), + m_SrcSize(src_size), + m_pSrcBuf(src_buf), + m_ScanlineBuf(pitch), + m_RefBuf(pitch) {} + +CCodec_FaxDecoder::~CCodec_FaxDecoder() {} + +bool CCodec_FaxDecoder::v_Rewind() { + memset(m_RefBuf.data(), 0xff, m_RefBuf.size()); + m_bitpos = 0; + return true; +} + +uint8_t* CCodec_FaxDecoder::v_GetNextLine() { + int bitsize = m_SrcSize * 8; + FaxSkipEOL(m_pSrcBuf, bitsize, &m_bitpos); + if (m_bitpos >= bitsize) + return nullptr; + + memset(m_ScanlineBuf.data(), 0xff, m_ScanlineBuf.size()); + if (m_Encoding < 0) { + FaxG4GetRow(m_pSrcBuf, bitsize, &m_bitpos, m_ScanlineBuf.data(), m_RefBuf, + m_OrigWidth); + m_RefBuf = m_ScanlineBuf; + } else if (m_Encoding == 0) { + FaxGet1DLine(m_pSrcBuf, bitsize, &m_bitpos, &m_ScanlineBuf, m_OrigWidth); + } else { + if (NextBit(m_pSrcBuf, &m_bitpos)) { + FaxGet1DLine(m_pSrcBuf, bitsize, &m_bitpos, &m_ScanlineBuf, m_OrigWidth); + } else { + FaxG4GetRow(m_pSrcBuf, bitsize, &m_bitpos, m_ScanlineBuf.data(), m_RefBuf, + m_OrigWidth); + } + m_RefBuf = m_ScanlineBuf; + } + if (m_bEndOfLine) + FaxSkipEOL(m_pSrcBuf, bitsize, &m_bitpos); + + if (m_bByteAlign && m_bitpos < bitsize) { + int bitpos0 = m_bitpos; + int bitpos1 = (m_bitpos + 7) / 8 * 8; + while (m_bByteAlign && bitpos0 < bitpos1) { + int bit = m_pSrcBuf[bitpos0 / 8] & (1 << (7 - bitpos0 % 8)); + if (bit != 0) + m_bByteAlign = false; + else + ++bitpos0; + } + if (m_bByteAlign) + m_bitpos = bitpos1; + } + if (m_bBlack) { + ASSERT(m_Pitch == m_ScanlineBuf.size()); + ASSERT(m_Pitch % 4 == 0); + uint32_t* data = reinterpret_cast(m_ScanlineBuf.data()); + for (size_t i = 0; i < m_ScanlineBuf.size() / 4; ++i) + data[i] = ~data[i]; + } + return m_ScanlineBuf.data(); +} + +uint32_t CCodec_FaxDecoder::GetSrcOffset() { + return std::min(static_cast((m_bitpos + 7) / 8), m_SrcSize); +} + +void FaxG4Decode(const uint8_t* src_buf, + uint32_t src_size, + int* pbitpos, + uint8_t* dest_buf, + int width, + int height, + int pitch) { + if (pitch == 0) + pitch = (width + 7) / 8; + + std::vector ref_buf(pitch, 0xff); + int bitpos = *pbitpos; + for (int iRow = 0; iRow < height; iRow++) { + uint8_t* line_buf = dest_buf + iRow * pitch; + memset(line_buf, 0xff, pitch); + FaxG4GetRow(src_buf, src_size << 3, &bitpos, line_buf, ref_buf, width); + memcpy(ref_buf.data(), line_buf, pitch); + } + *pbitpos = bitpos; +} + +std::unique_ptr CCodec_FaxModule::CreateDecoder( + const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + int K, + bool EndOfLine, + bool EncodedByteAlign, + bool BlackIs1, + int Columns, + int Rows) { + int actual_width = Columns ? Columns : width; + int actual_height = Rows ? Rows : height; + + // Reject invalid values. + if (actual_width <= 0 || actual_height <= 0) + return nullptr; + + // Reject unreasonable large input. + if (actual_width > kMaxImageDimension || actual_height > kMaxImageDimension) + return nullptr; + + uint32_t pitch = (static_cast(actual_width) + 31) / 32 * 4; + return pdfium::MakeUnique( + src_buf, src_size, actual_width, actual_height, pitch, K, EndOfLine, + EncodedByteAlign, BlackIs1); +} + +#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ +namespace { +const uint8_t BlackRunTerminator[128] = { + 0x37, 10, 0x02, 3, 0x03, 2, 0x02, 2, 0x03, 3, 0x03, 4, 0x02, 4, + 0x03, 5, 0x05, 6, 0x04, 6, 0x04, 7, 0x05, 7, 0x07, 7, 0x04, 8, + 0x07, 8, 0x18, 9, 0x17, 10, 0x18, 10, 0x08, 10, 0x67, 11, 0x68, 11, + 0x6c, 11, 0x37, 11, 0x28, 11, 0x17, 11, 0x18, 11, 0xca, 12, 0xcb, 12, + 0xcc, 12, 0xcd, 12, 0x68, 12, 0x69, 12, 0x6a, 12, 0x6b, 12, 0xd2, 12, + 0xd3, 12, 0xd4, 12, 0xd5, 12, 0xd6, 12, 0xd7, 12, 0x6c, 12, 0x6d, 12, + 0xda, 12, 0xdb, 12, 0x54, 12, 0x55, 12, 0x56, 12, 0x57, 12, 0x64, 12, + 0x65, 12, 0x52, 12, 0x53, 12, 0x24, 12, 0x37, 12, 0x38, 12, 0x27, 12, + 0x28, 12, 0x58, 12, 0x59, 12, 0x2b, 12, 0x2c, 12, 0x5a, 12, 0x66, 12, + 0x67, 12, +}; + +const uint8_t BlackRunMarkup[80] = { + 0x0f, 10, 0xc8, 12, 0xc9, 12, 0x5b, 12, 0x33, 12, 0x34, 12, 0x35, 12, + 0x6c, 13, 0x6d, 13, 0x4a, 13, 0x4b, 13, 0x4c, 13, 0x4d, 13, 0x72, 13, + 0x73, 13, 0x74, 13, 0x75, 13, 0x76, 13, 0x77, 13, 0x52, 13, 0x53, 13, + 0x54, 13, 0x55, 13, 0x5a, 13, 0x5b, 13, 0x64, 13, 0x65, 13, 0x08, 11, + 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12, + 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12, +}; + +const uint8_t WhiteRunTerminator[128] = { + 0x35, 8, 0x07, 6, 0x07, 4, 0x08, 4, 0x0B, 4, 0x0C, 4, 0x0E, 4, 0x0F, 4, + 0x13, 5, 0x14, 5, 0x07, 5, 0x08, 5, 0x08, 6, 0x03, 6, 0x34, 6, 0x35, 6, + 0x2a, 6, 0x2B, 6, 0x27, 7, 0x0c, 7, 0x08, 7, 0x17, 7, 0x03, 7, 0x04, 7, + 0x28, 7, 0x2B, 7, 0x13, 7, 0x24, 7, 0x18, 7, 0x02, 8, 0x03, 8, 0x1a, 8, + 0x1b, 8, 0x12, 8, 0x13, 8, 0x14, 8, 0x15, 8, 0x16, 8, 0x17, 8, 0x28, 8, + 0x29, 8, 0x2a, 8, 0x2b, 8, 0x2c, 8, 0x2d, 8, 0x04, 8, 0x05, 8, 0x0a, 8, + 0x0b, 8, 0x52, 8, 0x53, 8, 0x54, 8, 0x55, 8, 0x24, 8, 0x25, 8, 0x58, 8, + 0x59, 8, 0x5a, 8, 0x5b, 8, 0x4a, 8, 0x4b, 8, 0x32, 8, 0x33, 8, 0x34, 8, +}; + +const uint8_t WhiteRunMarkup[80] = { + 0x1b, 5, 0x12, 5, 0x17, 6, 0x37, 7, 0x36, 8, 0x37, 8, 0x64, 8, + 0x65, 8, 0x68, 8, 0x67, 8, 0xcc, 9, 0xcd, 9, 0xd2, 9, 0xd3, 9, + 0xd4, 9, 0xd5, 9, 0xd6, 9, 0xd7, 9, 0xd8, 9, 0xd9, 9, 0xda, 9, + 0xdb, 9, 0x98, 9, 0x99, 9, 0x9a, 9, 0x18, 6, 0x9b, 9, 0x08, 11, + 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12, + 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12, +}; + +void AddBitStream(uint8_t* dest_buf, int* dest_bitpos, int data, int bitlen) { + for (int i = bitlen - 1; i >= 0; i--) { + if (data & (1 << i)) + dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); + (*dest_bitpos)++; + } +} + +void FaxEncodeRun(uint8_t* dest_buf, int* dest_bitpos, int run, bool bWhite) { + while (run >= 2560) { + AddBitStream(dest_buf, dest_bitpos, 0x1f, 12); + run -= 2560; + } + if (run >= 64) { + int markup = run - run % 64; + const uint8_t* p = bWhite ? WhiteRunMarkup : BlackRunMarkup; + p += (markup / 64 - 1) * 2; + AddBitStream(dest_buf, dest_bitpos, *p, p[1]); + } + run %= 64; + const uint8_t* p = bWhite ? WhiteRunTerminator : BlackRunTerminator; + p += run * 2; + AddBitStream(dest_buf, dest_bitpos, *p, p[1]); +} + +void FaxEncode2DLine(uint8_t* dest_buf, + int* dest_bitpos, + const uint8_t* src_buf, + const std::vector& ref_buf, + int cols) { + int a0 = -1; + bool a0color = true; + while (1) { + int a1 = FindBit(src_buf, cols, a0 + 1, !a0color); + int b1; + int b2; + FaxG4FindB1B2(ref_buf, cols, a0, a0color, &b1, &b2); + if (b2 < a1) { + *dest_bitpos += 3; + dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); + (*dest_bitpos)++; + a0 = b2; + } else if (a1 - b1 <= 3 && b1 - a1 <= 3) { + int delta = a1 - b1; + switch (delta) { + case 0: + dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); + break; + case 1: + case 2: + case 3: + *dest_bitpos += delta == 1 ? 1 : delta + 2; + dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); + (*dest_bitpos)++; + dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); + break; + case -1: + case -2: + case -3: + *dest_bitpos += delta == -1 ? 1 : -delta + 2; + dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); + (*dest_bitpos)++; + break; + } + (*dest_bitpos)++; + a0 = a1; + a0color = !a0color; + } else { + int a2 = FindBit(src_buf, cols, a1 + 1, a0color); + (*dest_bitpos)++; + (*dest_bitpos)++; + dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); + (*dest_bitpos)++; + if (a0 < 0) + a0 = 0; + FaxEncodeRun(dest_buf, dest_bitpos, a1 - a0, a0color); + FaxEncodeRun(dest_buf, dest_bitpos, a2 - a1, !a0color); + a0 = a2; + } + if (a0 >= cols) + return; + } +} + +class CCodec_FaxEncoder { + public: + CCodec_FaxEncoder(const uint8_t* src_buf, int width, int height, int pitch); + ~CCodec_FaxEncoder(); + void Encode(std::unique_ptr* dest_buf, + uint32_t* dest_size); + + private: + CFX_BinaryBuf m_DestBuf; + std::vector m_RefLine; + uint8_t* m_pLineBuf; + const int m_Cols; + const int m_Rows; + const int m_Pitch; + const uint8_t* m_pSrcBuf; +}; + +CCodec_FaxEncoder::CCodec_FaxEncoder(const uint8_t* src_buf, + int width, + int height, + int pitch) + : m_Cols(width), m_Rows(height), m_Pitch(pitch), m_pSrcBuf(src_buf) { + m_RefLine.resize(m_Pitch); + memset(m_RefLine.data(), 0xff, m_Pitch); + m_pLineBuf = FX_Alloc2D(uint8_t, m_Pitch, 8); + m_DestBuf.SetAllocStep(10240); +} + +CCodec_FaxEncoder::~CCodec_FaxEncoder() { + FX_Free(m_pLineBuf); +} + +void CCodec_FaxEncoder::Encode( + std::unique_ptr* dest_buf, + uint32_t* dest_size) { + int dest_bitpos = 0; + uint8_t last_byte = 0; + for (int i = 0; i < m_Rows; i++) { + const uint8_t* scan_line = m_pSrcBuf + i * m_Pitch; + memset(m_pLineBuf, 0, m_Pitch * 8); + m_pLineBuf[0] = last_byte; + FaxEncode2DLine(m_pLineBuf, &dest_bitpos, scan_line, m_RefLine, m_Cols); + m_DestBuf.AppendBlock(m_pLineBuf, dest_bitpos / 8); + last_byte = m_pLineBuf[dest_bitpos / 8]; + dest_bitpos %= 8; + memcpy(m_RefLine.data(), scan_line, m_Pitch); + } + if (dest_bitpos) + m_DestBuf.AppendByte(last_byte); + *dest_size = m_DestBuf.GetSize(); + *dest_buf = m_DestBuf.DetachBuffer(); +} + +} // namespace + +void CCodec_FaxModule::FaxEncode( + const uint8_t* src_buf, + int width, + int height, + int pitch, + std::unique_ptr* dest_buf, + uint32_t* dest_size) { + CCodec_FaxEncoder encoder(src_buf, width, height, pitch); + encoder.Encode(dest_buf, dest_size); +} + +#endif // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ diff --git a/core/fxcodec/codec/ccodec_flatemodule.cpp b/core/fxcodec/codec/ccodec_flatemodule.cpp new file mode 100644 index 0000000000..9074038c96 --- /dev/null +++ b/core/fxcodec/codec/ccodec_flatemodule.cpp @@ -0,0 +1,852 @@ +// Copyright 2014 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/codec/ccodec_flatemodule.h" + +#include +#include +#include +#include +#include + +#include "core/fxcodec/codec/ccodec_scanlinedecoder.h" +#include "core/fxcodec/fx_codec.h" +#include "core/fxcrt/fx_extension.h" +#include "third_party/base/numerics/safe_conversions.h" +#include "third_party/base/ptr_util.h" +#include "third_party/base/span.h" + +#if defined(USE_SYSTEM_ZLIB) +#include +#else +#include "third_party/zlib/zlib.h" +#endif + +extern "C" { + +static void* my_alloc_func(void* opaque, + unsigned int items, + unsigned int size) { + return FX_Alloc2D(uint8_t, items, size); +} + +static void my_free_func(void* opaque, void* address) { + FX_Free(address); +} + +} // extern "C" + +namespace { + +static constexpr uint32_t kMaxTotalOutSize = 1024 * 1024 * 1024; // 1 GiB + +uint32_t FlateGetPossiblyTruncatedTotalOut(z_stream* context) { + return std::min(pdfium::base::saturated_cast(context->total_out), + kMaxTotalOutSize); +} + +uint32_t FlateGetPossiblyTruncatedTotalIn(z_stream* context) { + return pdfium::base::saturated_cast(context->total_in); +} + +bool FlateCompress(unsigned char* dest_buf, + unsigned long* dest_size, + const unsigned char* src_buf, + uint32_t src_size) { + return compress(dest_buf, dest_size, src_buf, src_size) == Z_OK; +} + +z_stream* FlateInit() { + z_stream* p = FX_Alloc(z_stream, 1); + p->zalloc = my_alloc_func; + p->zfree = my_free_func; + inflateInit(p); + return p; +} + +void FlateInput(z_stream* context, pdfium::span src_buf) { + context->next_in = const_cast(src_buf.data()); + context->avail_in = static_cast(src_buf.size()); +} + +uint32_t FlateOutput(z_stream* context, + unsigned char* dest_buf, + uint32_t dest_size) { + context->next_out = dest_buf; + context->avail_out = dest_size; + uint32_t pre_pos = FlateGetPossiblyTruncatedTotalOut(context); + int ret = inflate(static_cast(context), Z_SYNC_FLUSH); + + uint32_t post_pos = FlateGetPossiblyTruncatedTotalOut(context); + ASSERT(post_pos >= pre_pos); + + uint32_t written = post_pos - pre_pos; + if (written < dest_size) + memset(dest_buf + written, '\0', dest_size - written); + + return ret; +} + +uint32_t FlateGetAvailOut(z_stream* context) { + return context->avail_out; +} + +void FlateEnd(z_stream* context) { + inflateEnd(context); + FX_Free(context); +} + +// For use with std::unique_ptr. +struct FlateDeleter { + inline void operator()(z_stream* context) { FlateEnd(context); } +}; + +class CLZWDecoder { + public: + int Decode(uint8_t* output, + uint32_t& outlen, + const uint8_t* input, + uint32_t& size, + bool bEarlyChange); + + private: + void AddCode(uint32_t prefix_code, uint8_t append_char); + void DecodeString(uint32_t code); + + uint32_t m_InPos; + uint32_t m_OutPos; + uint8_t* m_pOutput; + const uint8_t* m_pInput; + bool m_Early; + uint32_t m_nCodes; + uint32_t m_StackLen; + int m_CodeLen; + uint32_t m_CodeArray[5021]; + uint8_t m_DecodeStack[4000]; +}; + +void CLZWDecoder::AddCode(uint32_t prefix_code, uint8_t append_char) { + if (m_nCodes + m_Early == 4094) { + return; + } + m_CodeArray[m_nCodes++] = (prefix_code << 16) | append_char; + if (m_nCodes + m_Early == 512 - 258) { + m_CodeLen = 10; + } else if (m_nCodes + m_Early == 1024 - 258) { + m_CodeLen = 11; + } else if (m_nCodes + m_Early == 2048 - 258) { + m_CodeLen = 12; + } +} + +void CLZWDecoder::DecodeString(uint32_t code) { + while (1) { + int index = code - 258; + if (index < 0 || index >= (int)m_nCodes) { + break; + } + uint32_t data = m_CodeArray[index]; + if (m_StackLen >= sizeof(m_DecodeStack)) { + return; + } + m_DecodeStack[m_StackLen++] = (uint8_t)data; + code = data >> 16; + } + if (m_StackLen >= sizeof(m_DecodeStack)) { + return; + } + m_DecodeStack[m_StackLen++] = (uint8_t)code; +} + +int CLZWDecoder::Decode(uint8_t* dest_buf, + uint32_t& dest_size, + const uint8_t* src_buf, + uint32_t& src_size, + bool bEarlyChange) { + m_CodeLen = 9; + m_InPos = 0; + m_OutPos = 0; + m_pInput = src_buf; + m_pOutput = dest_buf; + m_Early = bEarlyChange ? 1 : 0; + m_nCodes = 0; + uint32_t old_code = 0xFFFFFFFF; + uint8_t last_char = 0; + while (1) { + if (m_InPos + m_CodeLen > src_size * 8) { + break; + } + int byte_pos = m_InPos / 8; + int bit_pos = m_InPos % 8, bit_left = m_CodeLen; + uint32_t code = 0; + if (bit_pos) { + bit_left -= 8 - bit_pos; + code = (m_pInput[byte_pos++] & ((1 << (8 - bit_pos)) - 1)) << bit_left; + } + if (bit_left < 8) { + code |= m_pInput[byte_pos] >> (8 - bit_left); + } else { + bit_left -= 8; + code |= m_pInput[byte_pos++] << bit_left; + if (bit_left) { + code |= m_pInput[byte_pos] >> (8 - bit_left); + } + } + m_InPos += m_CodeLen; + if (code == 257) + break; + if (code < 256) { + if (m_OutPos == dest_size) { + return -5; + } + if (m_pOutput) { + m_pOutput[m_OutPos] = (uint8_t)code; + } + m_OutPos++; + last_char = (uint8_t)code; + if (old_code != 0xFFFFFFFF) + AddCode(old_code, last_char); + old_code = code; + } else if (code == 256) { + m_CodeLen = 9; + m_nCodes = 0; + old_code = 0xFFFFFFFF; + } else { + // Else 257 or greater. + if (old_code == 0xFFFFFFFF) + return 2; + + m_StackLen = 0; + if (code >= m_nCodes + 258) { + if (m_StackLen < sizeof(m_DecodeStack)) { + m_DecodeStack[m_StackLen++] = last_char; + } + DecodeString(old_code); + } else { + DecodeString(code); + } + if (m_OutPos + m_StackLen > dest_size) { + return -5; + } + if (m_pOutput) { + for (uint32_t i = 0; i < m_StackLen; i++) { + m_pOutput[m_OutPos + i] = m_DecodeStack[m_StackLen - i - 1]; + } + } + m_OutPos += m_StackLen; + last_char = m_DecodeStack[m_StackLen - 1]; + if (old_code < 256) { + AddCode(old_code, last_char); + } else if (old_code - 258 >= m_nCodes) { + dest_size = m_OutPos; + src_size = (m_InPos + 7) / 8; + return 0; + } else { + AddCode(old_code, last_char); + } + old_code = code; + } + } + dest_size = m_OutPos; + src_size = (m_InPos + 7) / 8; + return 0; +} + +uint8_t PathPredictor(int a, int b, int c) { + int p = a + b - c; + int pa = abs(p - a); + int pb = abs(p - b); + int pc = abs(p - c); + if (pa <= pb && pa <= pc) + return (uint8_t)a; + if (pb <= pc) + return (uint8_t)b; + return (uint8_t)c; +} + +void PNG_PredictLine(uint8_t* pDestData, + const uint8_t* pSrcData, + const uint8_t* pLastLine, + int bpc, + int nColors, + int nPixels) { + const uint32_t row_size = CalculatePitch8(bpc, nColors, nPixels).ValueOrDie(); + const uint32_t BytesPerPixel = (bpc * nColors + 7) / 8; + uint8_t tag = pSrcData[0]; + if (tag == 0) { + memmove(pDestData, pSrcData + 1, row_size); + return; + } + for (uint32_t byte = 0; byte < row_size; ++byte) { + uint8_t raw_byte = pSrcData[byte + 1]; + switch (tag) { + case 1: { + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pDestData[byte - BytesPerPixel]; + } + pDestData[byte] = raw_byte + left; + break; + } + case 2: { + uint8_t up = 0; + if (pLastLine) { + up = pLastLine[byte]; + } + pDestData[byte] = raw_byte + up; + break; + } + case 3: { + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pDestData[byte - BytesPerPixel]; + } + uint8_t up = 0; + if (pLastLine) { + up = pLastLine[byte]; + } + pDestData[byte] = raw_byte + (up + left) / 2; + break; + } + case 4: { + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pDestData[byte - BytesPerPixel]; + } + uint8_t up = 0; + if (pLastLine) { + up = pLastLine[byte]; + } + uint8_t upper_left = 0; + if (byte >= BytesPerPixel && pLastLine) { + upper_left = pLastLine[byte - BytesPerPixel]; + } + pDestData[byte] = raw_byte + PathPredictor(left, up, upper_left); + break; + } + default: + pDestData[byte] = raw_byte; + break; + } + } +} + +bool PNG_Predictor(uint8_t*& data_buf, + uint32_t& data_size, + int Colors, + int BitsPerComponent, + int Columns) { + // TODO(thestig): Look into using CalculatePitch8() here. + const int BytesPerPixel = (Colors * BitsPerComponent + 7) / 8; + const int row_size = (Colors * BitsPerComponent * Columns + 7) / 8; + if (row_size <= 0) + return false; + const int row_count = (data_size + row_size) / (row_size + 1); + if (row_count <= 0) + return false; + const int last_row_size = data_size % (row_size + 1); + uint8_t* dest_buf = FX_Alloc2D(uint8_t, row_size, row_count); + uint32_t byte_cnt = 0; + uint8_t* pSrcData = data_buf; + uint8_t* pDestData = dest_buf; + for (int row = 0; row < row_count; row++) { + uint8_t tag = pSrcData[0]; + byte_cnt++; + if (tag == 0) { + int move_size = row_size; + if ((row + 1) * (move_size + 1) > (int)data_size) { + move_size = last_row_size - 1; + } + memmove(pDestData, pSrcData + 1, move_size); + pSrcData += move_size + 1; + pDestData += move_size; + byte_cnt += move_size; + continue; + } + for (int byte = 0; byte < row_size && byte_cnt < data_size; + ++byte, ++byte_cnt) { + uint8_t raw_byte = pSrcData[byte + 1]; + switch (tag) { + case 1: { + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pDestData[byte - BytesPerPixel]; + } + pDestData[byte] = raw_byte + left; + break; + } + case 2: { + uint8_t up = 0; + if (row) { + up = pDestData[byte - row_size]; + } + pDestData[byte] = raw_byte + up; + break; + } + case 3: { + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pDestData[byte - BytesPerPixel]; + } + uint8_t up = 0; + if (row) { + up = pDestData[byte - row_size]; + } + pDestData[byte] = raw_byte + (up + left) / 2; + break; + } + case 4: { + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pDestData[byte - BytesPerPixel]; + } + uint8_t up = 0; + if (row) { + up = pDestData[byte - row_size]; + } + uint8_t upper_left = 0; + if (byte >= BytesPerPixel && row) { + upper_left = pDestData[byte - row_size - BytesPerPixel]; + } + pDestData[byte] = raw_byte + PathPredictor(left, up, upper_left); + break; + } + default: + pDestData[byte] = raw_byte; + break; + } + } + pSrcData += row_size + 1; + pDestData += row_size; + } + FX_Free(data_buf); + data_buf = dest_buf; + data_size = row_size * row_count - + (last_row_size > 0 ? (row_size + 1 - last_row_size) : 0); + return true; +} + +void TIFF_PredictLine(uint8_t* dest_buf, + uint32_t row_size, + int BitsPerComponent, + int Colors, + int Columns) { + if (BitsPerComponent == 1) { + int row_bits = std::min(BitsPerComponent * Colors * Columns, + pdfium::base::checked_cast(row_size * 8)); + int index_pre = 0; + int col_pre = 0; + for (int i = 1; i < row_bits; i++) { + int col = i % 8; + int index = i / 8; + if (((dest_buf[index] >> (7 - col)) & 1) ^ + ((dest_buf[index_pre] >> (7 - col_pre)) & 1)) { + dest_buf[index] |= 1 << (7 - col); + } else { + dest_buf[index] &= ~(1 << (7 - col)); + } + index_pre = index; + col_pre = col; + } + return; + } + int BytesPerPixel = BitsPerComponent * Colors / 8; + if (BitsPerComponent == 16) { + for (uint32_t i = BytesPerPixel; i + 1 < row_size; i += 2) { + uint16_t pixel = + (dest_buf[i - BytesPerPixel] << 8) | dest_buf[i - BytesPerPixel + 1]; + pixel += (dest_buf[i] << 8) | dest_buf[i + 1]; + dest_buf[i] = pixel >> 8; + dest_buf[i + 1] = (uint8_t)pixel; + } + } else { + for (uint32_t i = BytesPerPixel; i < row_size; i++) { + dest_buf[i] += dest_buf[i - BytesPerPixel]; + } + } +} + +bool TIFF_Predictor(uint8_t*& data_buf, + uint32_t& data_size, + int Colors, + int BitsPerComponent, + int Columns) { + int row_size = (Colors * BitsPerComponent * Columns + 7) / 8; + if (row_size == 0) + return false; + const int row_count = (data_size + row_size - 1) / row_size; + const int last_row_size = data_size % row_size; + for (int row = 0; row < row_count; row++) { + uint8_t* scan_line = data_buf + row * row_size; + if ((row + 1) * row_size > (int)data_size) { + row_size = last_row_size; + } + TIFF_PredictLine(scan_line, row_size, BitsPerComponent, Colors, Columns); + } + return true; +} + +void FlateUncompress(pdfium::span src_buf, + uint32_t orig_size, + uint8_t*& dest_buf, + uint32_t& dest_size, + uint32_t& offset) { + dest_buf = nullptr; + dest_size = 0; + + std::unique_ptr context(FlateInit()); + if (!context) + return; + + FlateInput(context.get(), src_buf); + + const uint32_t kMaxInitialAllocSize = 10000000; + uint32_t guess_size = orig_size ? orig_size : src_buf.size() * 2; + guess_size = std::min(guess_size, kMaxInitialAllocSize); + + uint32_t buf_size = guess_size; + uint32_t last_buf_size = buf_size; + std::unique_ptr guess_buf( + FX_Alloc(uint8_t, guess_size + 1)); + guess_buf.get()[guess_size] = '\0'; + + std::vector result_tmp_bufs; + uint8_t* cur_buf = guess_buf.release(); + while (1) { + uint32_t ret = FlateOutput(context.get(), cur_buf, buf_size); + uint32_t avail_buf_size = FlateGetAvailOut(context.get()); + if (ret != Z_OK || avail_buf_size != 0) { + last_buf_size = buf_size - avail_buf_size; + result_tmp_bufs.push_back(cur_buf); + break; + } + result_tmp_bufs.push_back(cur_buf); + cur_buf = FX_Alloc(uint8_t, buf_size + 1); + cur_buf[buf_size] = '\0'; + } + + // The TotalOut size returned from the library may not be big enough to + // handle the content the library returns. We can only handle items + // up to 4GB in size. + dest_size = FlateGetPossiblyTruncatedTotalOut(context.get()); + offset = FlateGetPossiblyTruncatedTotalIn(context.get()); + if (result_tmp_bufs.size() == 1) { + dest_buf = result_tmp_bufs[0]; + return; + } + + uint8_t* result_buf = FX_Alloc(uint8_t, dest_size); + uint32_t result_pos = 0; + uint32_t remaining = dest_size; + for (size_t i = 0; i < result_tmp_bufs.size(); i++) { + uint8_t* tmp_buf = result_tmp_bufs[i]; + uint32_t tmp_buf_size = buf_size; + if (i == result_tmp_bufs.size() - 1) + tmp_buf_size = last_buf_size; + + uint32_t cp_size = std::min(tmp_buf_size, remaining); + memcpy(result_buf + result_pos, tmp_buf, cp_size); + result_pos += cp_size; + remaining -= cp_size; + + FX_Free(result_tmp_bufs[i]); + } + dest_buf = result_buf; +} + +enum class PredictorType : uint8_t { kNone, kFlate, kPng }; +static PredictorType GetPredictor(int predictor) { + if (predictor >= 10) + return PredictorType::kPng; + if (predictor == 2) + return PredictorType::kFlate; + return PredictorType::kNone; +} + +class CCodec_FlateScanlineDecoder : public CCodec_ScanlineDecoder { + public: + CCodec_FlateScanlineDecoder(const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + int nComps, + int bpc); + ~CCodec_FlateScanlineDecoder() override; + + // CCodec_ScanlineDecoder: + bool v_Rewind() override; + uint8_t* v_GetNextLine() override; + uint32_t GetSrcOffset() override; + + protected: + std::unique_ptr m_pFlate; + pdfium::span const m_SrcBuf; + std::unique_ptr const m_pScanline; +}; + +CCodec_FlateScanlineDecoder::CCodec_FlateScanlineDecoder(const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + int nComps, + int bpc) + : CCodec_ScanlineDecoder(width, + height, + width, + height, + nComps, + bpc, + CalculatePitch8(bpc, nComps, width).ValueOrDie()), + m_SrcBuf(src_buf, src_size), + m_pScanline(FX_Alloc(uint8_t, m_Pitch)) {} + +CCodec_FlateScanlineDecoder::~CCodec_FlateScanlineDecoder() = default; + +bool CCodec_FlateScanlineDecoder::v_Rewind() { + m_pFlate.reset(FlateInit()); + if (!m_pFlate) + return false; + + FlateInput(m_pFlate.get(), m_SrcBuf); + return true; +} + +uint8_t* CCodec_FlateScanlineDecoder::v_GetNextLine() { + FlateOutput(m_pFlate.get(), m_pScanline.get(), m_Pitch); + return m_pScanline.get(); +} + +uint32_t CCodec_FlateScanlineDecoder::GetSrcOffset() { + return FlateGetPossiblyTruncatedTotalIn(m_pFlate.get()); +} + +class CCodec_FlatePredictorScanlineDecoder final + : public CCodec_FlateScanlineDecoder { + public: + CCodec_FlatePredictorScanlineDecoder(const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + int comps, + int bpc, + PredictorType predictor, + int Colors, + int BitsPerComponent, + int Columns); + ~CCodec_FlatePredictorScanlineDecoder() override; + + // CCodec_ScanlineDecoder: + bool v_Rewind() override; + uint8_t* v_GetNextLine() override; + + protected: + void GetNextLineWithPredictedPitch(); + void GetNextLineWithoutPredictedPitch(); + + const PredictorType m_Predictor; + int m_Colors = 0; + int m_BitsPerComponent = 0; + int m_Columns = 0; + uint32_t m_PredictPitch = 0; + size_t m_LeftOver = 0; + uint8_t* m_pLastLine = nullptr; + uint8_t* m_pPredictBuffer = nullptr; + uint8_t* m_pPredictRaw = nullptr; +}; + +CCodec_FlatePredictorScanlineDecoder::CCodec_FlatePredictorScanlineDecoder( + const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + int comps, + int bpc, + PredictorType predictor, + int Colors, + int BitsPerComponent, + int Columns) + : CCodec_FlateScanlineDecoder(src_buf, src_size, width, height, comps, bpc), + m_Predictor(predictor) { + ASSERT(m_Predictor != PredictorType::kNone); + if (BitsPerComponent * Colors * Columns == 0) { + BitsPerComponent = m_bpc; + Colors = m_nComps; + Columns = m_OrigWidth; + } + m_Colors = Colors; + m_BitsPerComponent = BitsPerComponent; + m_Columns = Columns; + m_PredictPitch = + CalculatePitch8(m_BitsPerComponent, m_Colors, m_Columns).ValueOrDie(); + m_pLastLine = FX_Alloc(uint8_t, m_PredictPitch); + m_pPredictBuffer = FX_Alloc(uint8_t, m_PredictPitch); + m_pPredictRaw = FX_Alloc(uint8_t, m_PredictPitch + 1); +} + +CCodec_FlatePredictorScanlineDecoder::~CCodec_FlatePredictorScanlineDecoder() { + FX_Free(m_pLastLine); + FX_Free(m_pPredictBuffer); + FX_Free(m_pPredictRaw); +} + +bool CCodec_FlatePredictorScanlineDecoder::v_Rewind() { + if (!CCodec_FlateScanlineDecoder::v_Rewind()) + return false; + + m_LeftOver = 0; + return true; +} + +uint8_t* CCodec_FlatePredictorScanlineDecoder::v_GetNextLine() { + if (m_Pitch == m_PredictPitch) + GetNextLineWithPredictedPitch(); + else + GetNextLineWithoutPredictedPitch(); + return m_pScanline.get(); +} + +void CCodec_FlatePredictorScanlineDecoder::GetNextLineWithPredictedPitch() { + switch (m_Predictor) { + case PredictorType::kPng: + FlateOutput(m_pFlate.get(), m_pPredictRaw, m_PredictPitch + 1); + PNG_PredictLine(m_pScanline.get(), m_pPredictRaw, m_pLastLine, + m_BitsPerComponent, m_Colors, m_Columns); + memcpy(m_pLastLine, m_pScanline.get(), m_PredictPitch); + break; + case PredictorType::kFlate: + FlateOutput(m_pFlate.get(), m_pScanline.get(), m_Pitch); + TIFF_PredictLine(m_pScanline.get(), m_PredictPitch, m_bpc, m_nComps, + m_OutputWidth); + break; + default: + NOTREACHED(); + break; + } +} + +void CCodec_FlatePredictorScanlineDecoder::GetNextLineWithoutPredictedPitch() { + size_t bytes_to_go = m_Pitch; + size_t read_leftover = m_LeftOver > bytes_to_go ? bytes_to_go : m_LeftOver; + if (read_leftover) { + memcpy(m_pScanline.get(), m_pPredictBuffer + m_PredictPitch - m_LeftOver, + read_leftover); + m_LeftOver -= read_leftover; + bytes_to_go -= read_leftover; + } + while (bytes_to_go) { + switch (m_Predictor) { + case PredictorType::kPng: + FlateOutput(m_pFlate.get(), m_pPredictRaw, m_PredictPitch + 1); + PNG_PredictLine(m_pPredictBuffer, m_pPredictRaw, m_pLastLine, + m_BitsPerComponent, m_Colors, m_Columns); + memcpy(m_pLastLine, m_pPredictBuffer, m_PredictPitch); + break; + case PredictorType::kFlate: + FlateOutput(m_pFlate.get(), m_pPredictBuffer, m_PredictPitch); + TIFF_PredictLine(m_pPredictBuffer, m_PredictPitch, m_BitsPerComponent, + m_Colors, m_Columns); + break; + default: + NOTREACHED(); + break; + } + size_t read_bytes = + m_PredictPitch > bytes_to_go ? bytes_to_go : m_PredictPitch; + memcpy(m_pScanline.get() + m_Pitch - bytes_to_go, m_pPredictBuffer, + read_bytes); + m_LeftOver += m_PredictPitch - read_bytes; + bytes_to_go -= read_bytes; + } +} + +} // namespace + +std::unique_ptr CCodec_FlateModule::CreateDecoder( + const uint8_t* src_buf, + uint32_t src_size, + int width, + int height, + int nComps, + int bpc, + int predictor, + int Colors, + int BitsPerComponent, + int Columns) { + PredictorType predictor_type = GetPredictor(predictor); + if (predictor_type == PredictorType::kNone) { + return pdfium::MakeUnique( + src_buf, src_size, width, height, nComps, bpc); + } + return pdfium::MakeUnique( + src_buf, src_size, width, height, nComps, bpc, predictor_type, Colors, + BitsPerComponent, Columns); +} + +uint32_t CCodec_FlateModule::FlateOrLZWDecode(bool bLZW, + const uint8_t* src_buf, + uint32_t src_size, + bool bEarlyChange, + int predictor, + int Colors, + int BitsPerComponent, + int Columns, + uint32_t estimated_size, + uint8_t** dest_buf, + uint32_t* dest_size) { + *dest_buf = nullptr; + uint32_t offset = 0; + PredictorType predictor_type = GetPredictor(predictor); + + if (bLZW) { + auto decoder = pdfium::MakeUnique(); + *dest_size = 0xFFFFFFFF; + offset = src_size; + int err = + decoder->Decode(nullptr, *dest_size, src_buf, offset, bEarlyChange); + if (err || *dest_size == 0 || *dest_size + 1 < *dest_size) + return FX_INVALID_OFFSET; + + decoder = pdfium::MakeUnique(); + *dest_buf = FX_Alloc(uint8_t, *dest_size + 1); + (*dest_buf)[*dest_size] = '\0'; + decoder->Decode(*dest_buf, *dest_size, src_buf, offset, bEarlyChange); + } else { + FlateUncompress(pdfium::make_span(src_buf, src_size), estimated_size, + *dest_buf, *dest_size, offset); + } + + bool ret = false; + switch (predictor_type) { + case PredictorType::kNone: + return offset; + case PredictorType::kPng: + ret = PNG_Predictor(*dest_buf, *dest_size, Colors, BitsPerComponent, + Columns); + break; + case PredictorType::kFlate: + ret = TIFF_Predictor(*dest_buf, *dest_size, Colors, BitsPerComponent, + Columns); + break; + default: + NOTREACHED(); + break; + } + return ret ? offset : FX_INVALID_OFFSET; +} + +bool CCodec_FlateModule::Encode(const uint8_t* src_buf, + uint32_t src_size, + uint8_t** dest_buf, + uint32_t* dest_size) { + *dest_size = src_size + src_size / 1000 + 12; + *dest_buf = FX_Alloc(uint8_t, *dest_size); + unsigned long temp_size = *dest_size; + if (!FlateCompress(*dest_buf, &temp_size, src_buf, src_size)) + return false; + + *dest_size = (uint32_t)temp_size; + return true; +} diff --git a/core/fxcodec/codec/ccodec_iccmodule.cpp b/core/fxcodec/codec/ccodec_iccmodule.cpp new file mode 100644 index 0000000000..74937b2807 --- /dev/null +++ b/core/fxcodec/codec/ccodec_iccmodule.cpp @@ -0,0 +1,146 @@ +// Copyright 2014 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/codec/ccodec_iccmodule.h" + +#include +#include +#include + +#include "core/fxcodec/codec/codec_int.h" + +namespace { + +// For use with std::unique_ptr. +struct CmsProfileDeleter { + inline void operator()(cmsHPROFILE p) { cmsCloseProfile(p); } +}; + +using ScopedCmsProfile = std::unique_ptr; + +bool Check3Components(cmsColorSpaceSignature cs) { + switch (cs) { + case cmsSigGrayData: + case cmsSigCmykData: + return false; + default: + return true; + } +} + +} // namespace + +CLcmsCmm::CLcmsCmm(cmsHTRANSFORM hTransform, + int srcComponents, + bool bIsLab, + bool bNormal) + : m_hTransform(hTransform), + m_nSrcComponents(srcComponents), + m_bLab(bIsLab), + m_bNormal(bNormal) {} + +CLcmsCmm::~CLcmsCmm() { + cmsDeleteTransform(m_hTransform); +} + +CCodec_IccModule::CCodec_IccModule() {} + +CCodec_IccModule::~CCodec_IccModule() {} + +std::unique_ptr CCodec_IccModule::CreateTransform_sRGB( + pdfium::span span) { + ScopedCmsProfile srcProfile(cmsOpenProfileFromMem(span.data(), span.size())); + if (!srcProfile) + return nullptr; + + ScopedCmsProfile dstProfile(cmsCreate_sRGBProfile()); + if (!dstProfile) + return nullptr; + + cmsColorSpaceSignature srcCS = cmsGetColorSpace(srcProfile.get()); + + uint32_t nSrcComponents = cmsChannelsOf(srcCS); + // According to PDF spec, number of components must be 1, 3, or 4. + if (nSrcComponents != 1 && nSrcComponents != 3 && nSrcComponents != 4) + return nullptr; + + int srcFormat; + bool bLab = false; + bool bNormal = false; + if (srcCS == cmsSigLabData) { + srcFormat = + COLORSPACE_SH(PT_Lab) | CHANNELS_SH(nSrcComponents) | BYTES_SH(0); + bLab = true; + } else { + srcFormat = + COLORSPACE_SH(PT_ANY) | CHANNELS_SH(nSrcComponents) | BYTES_SH(1); + // TODO(thestig): Check to see if lcms2 supports more colorspaces that can + // be considered normal. + bNormal = srcCS == cmsSigGrayData || srcCS == cmsSigRgbData || + srcCS == cmsSigCmykData; + } + cmsColorSpaceSignature dstCS = cmsGetColorSpace(dstProfile.get()); + if (!Check3Components(dstCS)) + return nullptr; + + cmsHTRANSFORM hTransform = nullptr; + const int intent = 0; + switch (dstCS) { + case cmsSigRgbData: + hTransform = cmsCreateTransform(srcProfile.get(), srcFormat, + dstProfile.get(), TYPE_BGR_8, intent, 0); + break; + case cmsSigGrayData: + case cmsSigCmykData: + // Check3Components() already filtered these types. + NOTREACHED(); + break; + default: + break; + } + if (!hTransform) + return nullptr; + + return pdfium::MakeUnique(hTransform, nSrcComponents, bLab, + bNormal); +} + +void CCodec_IccModule::Translate(CLcmsCmm* pTransform, + const float* pSrcValues, + float* pDestValues) { + if (!pTransform) + return; + + uint32_t nSrcComponents = m_nComponents; + uint8_t output[4]; + // TODO(npm): Currently the CmsDoTransform method is part of LCMS and it will + // apply some member of m_hTransform to the input. We need to go over all the + // places which set transform to verify that only nSrcComponents are used. + if (pTransform->IsLab()) { + std::vector inputs(std::max(nSrcComponents, 16u)); + for (uint32_t i = 0; i < nSrcComponents; ++i) + inputs[i] = pSrcValues[i]; + cmsDoTransform(pTransform->transform(), inputs.data(), output, 1); + } else { + std::vector inputs(std::max(nSrcComponents, 16u)); + for (uint32_t i = 0; i < nSrcComponents; ++i) { + inputs[i] = + pdfium::clamp(static_cast(pSrcValues[i] * 255.0f), 0, 255); + } + cmsDoTransform(pTransform->transform(), inputs.data(), output, 1); + } + pDestValues[0] = output[2] / 255.0f; + pDestValues[1] = output[1] / 255.0f; + pDestValues[2] = output[0] / 255.0f; +} + +void CCodec_IccModule::TranslateScanline(CLcmsCmm* pTransform, + unsigned char* pDest, + const unsigned char* pSrc, + int32_t pixels) { + if (pTransform) + cmsDoTransform(pTransform->transform(), pSrc, pDest, pixels); +} diff --git a/core/fxcodec/codec/ccodec_jbig2module.cpp b/core/fxcodec/codec/ccodec_jbig2module.cpp new file mode 100644 index 0000000000..36d6a0609e --- /dev/null +++ b/core/fxcodec/codec/ccodec_jbig2module.cpp @@ -0,0 +1,94 @@ +// Copyright 2014 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/codec/ccodec_jbig2module.h" + +#include +#include + +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fxcodec/JBig2_DocumentContext.h" +#include "core/fxcodec/jbig2/JBig2_Context.h" +#include "core/fxcodec/jbig2/JBig2_Image.h" +#include "core/fxcrt/fx_memory.h" +#include "third_party/base/ptr_util.h" + +JBig2_DocumentContext::JBig2_DocumentContext() {} + +JBig2_DocumentContext::~JBig2_DocumentContext() {} + +JBig2_DocumentContext* GetJBig2DocumentContext( + std::unique_ptr* pContextHolder) { + if (!pContextHolder->get()) + *pContextHolder = pdfium::MakeUnique(); + return pContextHolder->get(); +} + +CCodec_Jbig2Context::CCodec_Jbig2Context() + : m_width(0), + m_height(0), + m_pGlobalStream(nullptr), + m_pSrcStream(nullptr), + m_dest_buf(0), + m_dest_pitch(0) {} + +CCodec_Jbig2Context::~CCodec_Jbig2Context() {} + +CCodec_Jbig2Module::~CCodec_Jbig2Module() {} + +FXCODEC_STATUS CCodec_Jbig2Module::StartDecode( + CCodec_Jbig2Context* pJbig2Context, + std::unique_ptr* pContextHolder, + uint32_t width, + uint32_t height, + const RetainPtr& src_stream, + const RetainPtr& global_stream, + uint8_t* dest_buf, + uint32_t dest_pitch, + PauseIndicatorIface* pPause) { + if (!pJbig2Context) + return FXCODEC_STATUS_ERR_PARAMS; + + JBig2_DocumentContext* pJBig2DocumentContext = + GetJBig2DocumentContext(pContextHolder); + pJbig2Context->m_width = width; + pJbig2Context->m_height = height; + pJbig2Context->m_pSrcStream = src_stream; + pJbig2Context->m_pGlobalStream = global_stream; + pJbig2Context->m_dest_buf = dest_buf; + pJbig2Context->m_dest_pitch = dest_pitch; + memset(dest_buf, 0, height * dest_pitch); + pJbig2Context->m_pContext = pdfium::MakeUnique( + global_stream, src_stream, pJBig2DocumentContext->GetSymbolDictCache(), + false); + bool succeeded = pJbig2Context->m_pContext->GetFirstPage( + dest_buf, width, height, dest_pitch, pPause); + return Decode(pJbig2Context, succeeded); +} + +FXCODEC_STATUS CCodec_Jbig2Module::ContinueDecode( + CCodec_Jbig2Context* pJbig2Context, + PauseIndicatorIface* pPause) { + bool succeeded = pJbig2Context->m_pContext->Continue(pPause); + return Decode(pJbig2Context, succeeded); +} + +FXCODEC_STATUS CCodec_Jbig2Module::Decode(CCodec_Jbig2Context* pJbig2Context, + bool decode_success) { + FXCODEC_STATUS status = pJbig2Context->m_pContext->GetProcessingStatus(); + if (status != FXCODEC_STATUS_DECODE_FINISH) + return status; + + pJbig2Context->m_pContext.reset(); + if (!decode_success) + return FXCODEC_STATUS_ERROR; + + int dword_size = pJbig2Context->m_height * pJbig2Context->m_dest_pitch / 4; + uint32_t* dword_buf = reinterpret_cast(pJbig2Context->m_dest_buf); + for (int i = 0; i < dword_size; i++) + dword_buf[i] = ~dword_buf[i]; + return FXCODEC_STATUS_DECODE_FINISH; +} diff --git a/core/fxcodec/codec/ccodec_jpxmodule.cpp b/core/fxcodec/codec/ccodec_jpxmodule.cpp new file mode 100644 index 0000000000..ce6a1301fd --- /dev/null +++ b/core/fxcodec/codec/ccodec_jpxmodule.cpp @@ -0,0 +1,668 @@ +// Copyright 2014 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/codec/ccodec_jpxmodule.h" + +#include +#include +#include +#include +#include + +#include "core/fpdfapi/page/cpdf_colorspace.h" +#include "core/fxcodec/codec/cjpx_decoder.h" +#include "core/fxcrt/fx_memory.h" +#include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/ptr_util.h" +#include "third_party/libopenjpeg20/openjpeg.h" +#include "third_party/libopenjpeg20/opj_malloc.h" + +namespace { + +void fx_ignore_callback(const char* msg, void* client_data) {} + +opj_stream_t* fx_opj_stream_create_memory_stream(DecodeData* data, + OPJ_SIZE_T p_size, + OPJ_BOOL p_is_read_stream) { + if (!data || !data->src_data || data->src_size <= 0) + return nullptr; + + opj_stream_t* stream = opj_stream_create(p_size, p_is_read_stream); + if (!stream) + return nullptr; + + opj_stream_set_user_data(stream, data, nullptr); + opj_stream_set_user_data_length(stream, data->src_size); + opj_stream_set_read_function(stream, opj_read_from_memory); + opj_stream_set_skip_function(stream, opj_skip_from_memory); + opj_stream_set_seek_function(stream, opj_seek_from_memory); + return stream; +} + +bool alloc_rgb(int** out_r, int** out_g, int** out_b, size_t size) { + int* r = static_cast(opj_image_data_alloc(size)); + if (!r) + return false; + + int* g = static_cast(opj_image_data_alloc(size)); + if (!g) { + opj_image_data_free(r); + return false; + } + + int* b = static_cast(opj_image_data_alloc(size)); + if (!b) { + opj_image_data_free(r); + opj_image_data_free(g); + return false; + } + + *out_r = r; + *out_g = g; + *out_b = b; + return true; +} + +void sycc_to_rgb(int offset, + int upb, + int y, + int cb, + int cr, + int* out_r, + int* out_g, + int* out_b) { + cb -= offset; + cr -= offset; + *out_r = pdfium::clamp(y + static_cast(1.402 * cr), 0, upb); + *out_g = pdfium::clamp(y - static_cast(0.344 * cb + 0.714 * cr), 0, upb); + *out_b = pdfium::clamp(y + static_cast(1.772 * cb), 0, upb); +} + +void sycc444_to_rgb(opj_image_t* img) { + int prec = img->comps[0].prec; + // If we shift 31 we're going to go negative, then things go bad. + if (prec > 30) + return; + int offset = 1 << (prec - 1); + int upb = (1 << prec) - 1; + OPJ_UINT32 maxw = + std::min({img->comps[0].w, img->comps[1].w, img->comps[2].w}); + OPJ_UINT32 maxh = + std::min({img->comps[0].h, img->comps[1].h, img->comps[2].h}); + FX_SAFE_SIZE_T max_size = maxw; + max_size *= maxh; + max_size *= sizeof(int); + if (!max_size.IsValid()) + return; + + const int* y = img->comps[0].data; + const int* cb = img->comps[1].data; + const int* cr = img->comps[2].data; + if (!y || !cb || !cr) + return; + + int* r; + int* g; + int* b; + if (!alloc_rgb(&r, &g, &b, max_size.ValueOrDie())) + return; + + int* d0 = r; + int* d1 = g; + int* d2 = b; + max_size /= sizeof(int); + for (size_t i = 0; i < max_size.ValueOrDie(); ++i) { + sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++); + } + opj_image_data_free(img->comps[0].data); + opj_image_data_free(img->comps[1].data); + opj_image_data_free(img->comps[2].data); + img->comps[0].data = d0; + img->comps[1].data = d1; + img->comps[2].data = d2; +} + +bool sycc420_422_size_is_valid(opj_image_t* img) { + return img && img->comps[0].w != std::numeric_limits::max() && + (img->comps[0].w + 1) / 2 == img->comps[1].w && + img->comps[1].w == img->comps[2].w && + img->comps[1].h == img->comps[2].h; +} + +bool sycc420_size_is_valid(opj_image_t* img) { + return sycc420_422_size_is_valid(img) && + img->comps[0].h != std::numeric_limits::max() && + (img->comps[0].h + 1) / 2 == img->comps[1].h; +} + +bool sycc422_size_is_valid(opj_image_t* img) { + return sycc420_422_size_is_valid(img) && img->comps[0].h == img->comps[1].h; +} + +void sycc422_to_rgb(opj_image_t* img) { + if (!sycc422_size_is_valid(img)) + return; + + int prec = img->comps[0].prec; + if (prec <= 0 || prec >= 32) + return; + + int offset = 1 << (prec - 1); + int upb = (1 << prec) - 1; + OPJ_UINT32 maxw = img->comps[0].w; + OPJ_UINT32 maxh = img->comps[0].h; + FX_SAFE_SIZE_T max_size = maxw; + max_size *= maxh; + max_size *= sizeof(int); + if (!max_size.IsValid()) + return; + + const int* y = img->comps[0].data; + const int* cb = img->comps[1].data; + const int* cr = img->comps[2].data; + if (!y || !cb || !cr) + return; + + int* r; + int* g; + int* b; + if (!alloc_rgb(&r, &g, &b, max_size.ValueOrDie())) + return; + + int* d0 = r; + int* d1 = g; + int* d2 = b; + for (uint32_t i = 0; i < maxh; ++i) { + OPJ_UINT32 j; + for (j = 0; j < (maxw & ~static_cast(1)); j += 2) { + sycc_to_rgb(offset, upb, *y++, *cb, *cr, r++, g++, b++); + sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++); + } + if (j < maxw) { + sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++); + } + } + opj_image_data_free(img->comps[0].data); + opj_image_data_free(img->comps[1].data); + opj_image_data_free(img->comps[2].data); + img->comps[0].data = d0; + img->comps[1].data = d1; + img->comps[2].data = d2; + img->comps[1].w = maxw; + img->comps[1].h = maxh; + img->comps[2].w = maxw; + img->comps[2].h = maxh; + img->comps[1].dx = img->comps[0].dx; + img->comps[2].dx = img->comps[0].dx; + img->comps[1].dy = img->comps[0].dy; + img->comps[2].dy = img->comps[0].dy; +} + +bool sycc420_must_extend_cbcr(OPJ_UINT32 y, OPJ_UINT32 cbcr) { + return (y & 1) && (cbcr == y / 2); +} + +bool is_sycc420(const opj_image_t* img) { + return img->comps[0].dx == 1 && img->comps[0].dy == 1 && + img->comps[1].dx == 2 && img->comps[1].dy == 2 && + img->comps[2].dx == 2 && img->comps[2].dy == 2; +} + +bool is_sycc422(const opj_image_t* img) { + return img->comps[0].dx == 1 && img->comps[0].dy == 1 && + img->comps[1].dx == 2 && img->comps[1].dy == 1 && + img->comps[2].dx == 2 && img->comps[2].dy == 1; +} + +bool is_sycc444(const opj_image_t* img) { + return img->comps[0].dx == 1 && img->comps[0].dy == 1 && + img->comps[1].dx == 1 && img->comps[1].dy == 1 && + img->comps[2].dx == 1 && img->comps[2].dy == 1; +} + +void color_sycc_to_rgb(opj_image_t* img) { + if (img->numcomps < 3) { + img->color_space = OPJ_CLRSPC_GRAY; + return; + } + if (is_sycc420(img)) + sycc420_to_rgb(img); + else if (is_sycc422(img)) + sycc422_to_rgb(img); + else if (is_sycc444(img)) + sycc444_to_rgb(img); + else + return; + + img->color_space = OPJ_CLRSPC_SRGB; +} + +} // namespace + +OPJ_SIZE_T opj_read_from_memory(void* p_buffer, + OPJ_SIZE_T nb_bytes, + void* p_user_data) { + DecodeData* srcData = static_cast(p_user_data); + if (!srcData || !srcData->src_data || srcData->src_size == 0) + return static_cast(-1); + + // Reads at EOF return an error code. + if (srcData->offset >= srcData->src_size) + return static_cast(-1); + + OPJ_SIZE_T bufferLength = srcData->src_size - srcData->offset; + OPJ_SIZE_T readlength = nb_bytes < bufferLength ? nb_bytes : bufferLength; + memcpy(p_buffer, &srcData->src_data[srcData->offset], readlength); + srcData->offset += readlength; + return readlength; +} + +OPJ_OFF_T opj_skip_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) { + DecodeData* srcData = static_cast(p_user_data); + if (!srcData || !srcData->src_data || srcData->src_size == 0) + return static_cast(-1); + + // Offsets are signed and may indicate a negative skip. Do not support this + // because of the strange return convention where either bytes skipped or + // -1 is returned. Following that convention, a successful relative seek of + // -1 bytes would be required to to give the same result as the error case. + if (nb_bytes < 0) + return static_cast(-1); + + // FIXME: use std::make_unsigned::type once c++11 lib is OK'd. + uint64_t unsignedNbBytes = static_cast(nb_bytes); + // Additionally, the offset may take us beyond the range of a size_t (e.g. + // 32-bit platforms). If so, just clamp at EOF. + if (unsignedNbBytes > + std::numeric_limits::max() - srcData->offset) { + srcData->offset = srcData->src_size; + } else { + OPJ_SIZE_T checkedNbBytes = static_cast(unsignedNbBytes); + // Otherwise, mimic fseek() semantics to always succeed, even past EOF, + // clamping at EOF. We can get away with this since we don't actually + // provide negative relative skips from beyond EOF back to inside the + // data, which would be the only reason to need to know exactly how far + // beyond EOF we are. + srcData->offset = + std::min(srcData->offset + checkedNbBytes, srcData->src_size); + } + return nb_bytes; +} + +OPJ_BOOL opj_seek_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) { + DecodeData* srcData = static_cast(p_user_data); + if (!srcData || !srcData->src_data || srcData->src_size == 0) + return OPJ_FALSE; + + // Offsets are signed and may indicate a negative position, which would + // be before the start of the file. Do not support this. + if (nb_bytes < 0) + return OPJ_FALSE; + + // FIXME: use std::make_unsigned::type once c++11 lib is OK'd. + uint64_t unsignedNbBytes = static_cast(nb_bytes); + // Additionally, the offset may take us beyond the range of a size_t (e.g. + // 32-bit platforms). If so, just clamp at EOF. + if (unsignedNbBytes > std::numeric_limits::max()) { + srcData->offset = srcData->src_size; + } else { + OPJ_SIZE_T checkedNbBytes = static_cast(nb_bytes); + // Otherwise, mimic fseek() semantics to always succeed, even past EOF, + // again clamping at EOF. + srcData->offset = std::min(checkedNbBytes, srcData->src_size); + } + return OPJ_TRUE; +} + +void sycc420_to_rgb(opj_image_t* img) { + if (!sycc420_size_is_valid(img)) + return; + + OPJ_UINT32 prec = img->comps[0].prec; + if (!prec) + return; + + OPJ_UINT32 offset = 1 << (prec - 1); + OPJ_UINT32 upb = (1 << prec) - 1; + OPJ_UINT32 yw = img->comps[0].w; + OPJ_UINT32 yh = img->comps[0].h; + OPJ_UINT32 cbw = img->comps[1].w; + OPJ_UINT32 cbh = img->comps[1].h; + OPJ_UINT32 crw = img->comps[2].w; + bool extw = sycc420_must_extend_cbcr(yw, cbw); + bool exth = sycc420_must_extend_cbcr(yh, cbh); + FX_SAFE_UINT32 safeSize = yw; + safeSize *= yh; + safeSize *= sizeof(int); + if (!safeSize.IsValid()) + return; + + int* r; + int* g; + int* b; + if (!alloc_rgb(&r, &g, &b, safeSize.ValueOrDie())) + return; + + int* d0 = r; + int* d1 = g; + int* d2 = b; + const int* y = img->comps[0].data; + const int* cb = img->comps[1].data; + const int* cr = img->comps[2].data; + if (!y || !cb || !cr) + return; + + const int* ny = nullptr; + int* nr = nullptr; + int* ng = nullptr; + int* nb = nullptr; + OPJ_UINT32 i = 0; + OPJ_UINT32 j = 0; + for (i = 0; i < (yh & ~(OPJ_UINT32)1); i += 2) { + ny = y + yw; + nr = r + yw; + ng = g + yw; + nb = b + yw; + for (j = 0; j < (yw & ~(OPJ_UINT32)1); j += 2) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; + ++nr; + ++ng; + ++nb; + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; + ++nr; + ++ng; + ++nb; + ++cb; + ++cr; + } + if (j < yw) { + if (extw) { + --cb; + --cr; + } + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; + ++nr; + ++ng; + ++nb; + ++cb; + ++cr; + } + y += yw; + r += yw; + g += yw; + b += yw; + } + if (i < yh) { + if (exth) { + cb -= cbw; + cr -= crw; + } + for (j = 0; j < (yw & ~(OPJ_UINT32)1); j += 2) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + ++cb; + ++cr; + } + if (j < yw) { + if (extw) { + --cb; + --cr; + } + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + } + } + + opj_image_data_free(img->comps[0].data); + opj_image_data_free(img->comps[1].data); + opj_image_data_free(img->comps[2].data); + img->comps[0].data = d0; + img->comps[1].data = d1; + img->comps[2].data = d2; + img->comps[1].w = yw; + img->comps[1].h = yh; + img->comps[2].w = yw; + img->comps[2].h = yh; + img->comps[1].dx = img->comps[0].dx; + img->comps[2].dx = img->comps[0].dx; + img->comps[1].dy = img->comps[0].dy; + img->comps[2].dy = img->comps[0].dy; +} + +CJPX_Decoder::CJPX_Decoder(CPDF_ColorSpace* cs) + : m_Image(nullptr), + m_Codec(nullptr), + m_DecodeData(nullptr), + m_Stream(nullptr), + m_ColorSpace(cs) {} + +CJPX_Decoder::~CJPX_Decoder() { + if (m_Codec) + opj_destroy_codec(m_Codec.Release()); + if (m_Stream) + opj_stream_destroy(m_Stream.Release()); + if (m_Image) + opj_image_destroy(m_Image.Release()); +} + +bool CJPX_Decoder::Init(pdfium::span src_data) { + static const unsigned char szJP2Header[] = { + 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a}; + if (src_data.empty() || src_data.size() < sizeof(szJP2Header)) + return false; + + m_Image = nullptr; + m_SrcData = src_data; + m_DecodeData = + pdfium::MakeUnique(src_data.data(), src_data.size()); + m_Stream = fx_opj_stream_create_memory_stream( + m_DecodeData.get(), static_cast(OPJ_J2K_STREAM_CHUNK_SIZE), + 1); + if (!m_Stream) + return false; + + opj_set_default_decoder_parameters(&m_Parameters); + m_Parameters.decod_format = 0; + m_Parameters.cod_format = 3; + if (memcmp(m_SrcData.data(), szJP2Header, sizeof(szJP2Header)) == 0) { + m_Codec = opj_create_decompress(OPJ_CODEC_JP2); + m_Parameters.decod_format = 1; + } else { + m_Codec = opj_create_decompress(OPJ_CODEC_J2K); + } + if (!m_Codec) + return false; + + if (m_ColorSpace && m_ColorSpace->GetFamily() == PDFCS_INDEXED) + m_Parameters.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; + opj_set_info_handler(m_Codec.Get(), fx_ignore_callback, nullptr); + opj_set_warning_handler(m_Codec.Get(), fx_ignore_callback, nullptr); + opj_set_error_handler(m_Codec.Get(), fx_ignore_callback, nullptr); + if (!opj_setup_decoder(m_Codec.Get(), &m_Parameters)) + return false; + + m_Image = nullptr; + opj_image_t* pTempImage = nullptr; + if (!opj_read_header(m_Stream.Get(), m_Codec.Get(), &pTempImage)) + return false; + + m_Image = pTempImage; + m_Image->pdfium_use_colorspace = !!m_ColorSpace; + + if (!m_Parameters.nb_tile_to_decode) { + if (!opj_set_decode_area(m_Codec.Get(), m_Image.Get(), m_Parameters.DA_x0, + m_Parameters.DA_y0, m_Parameters.DA_x1, + m_Parameters.DA_y1)) { + opj_image_destroy(m_Image.Release()); + return false; + } + if (!(opj_decode(m_Codec.Get(), m_Stream.Get(), m_Image.Get()) && + opj_end_decompress(m_Codec.Get(), m_Stream.Get()))) { + opj_image_destroy(m_Image.Release()); + return false; + } + } else if (!opj_get_decoded_tile(m_Codec.Get(), m_Stream.Get(), m_Image.Get(), + m_Parameters.tile_index)) { + return false; + } + + opj_stream_destroy(m_Stream.Release()); + if (m_Image->color_space != OPJ_CLRSPC_SYCC && m_Image->numcomps == 3 && + m_Image->comps[0].dx == m_Image->comps[0].dy && + m_Image->comps[1].dx != 1) { + m_Image->color_space = OPJ_CLRSPC_SYCC; + } else if (m_Image->numcomps <= 2) { + m_Image->color_space = OPJ_CLRSPC_GRAY; + } + if (m_Image->color_space == OPJ_CLRSPC_SYCC) + color_sycc_to_rgb(m_Image.Get()); + + if (m_Image->icc_profile_buf) { + // TODO(palmer): Using |opj_free| here resolves the crash described in + // https://crbug.com/737033, but ultimately we need to harmonize the + // memory allocation strategy across OpenJPEG and its PDFium callers. + opj_free(m_Image->icc_profile_buf); + m_Image->icc_profile_buf = nullptr; + m_Image->icc_profile_len = 0; + } + + return true; +} + +void CJPX_Decoder::GetInfo(uint32_t* width, + uint32_t* height, + uint32_t* components) { + *width = m_Image->x1; + *height = m_Image->y1; + *components = m_Image->numcomps; +} + +bool CJPX_Decoder::Decode(uint8_t* dest_buf, + uint32_t pitch, + const std::vector& offsets) { + if (m_Image->comps[0].w != m_Image->x1 || m_Image->comps[0].h != m_Image->y1) + return false; + + if (pitch<(m_Image->comps[0].w * 8 * m_Image->numcomps + 31)>> 5 << 2) { + return false; + } + + memset(dest_buf, 0xff, m_Image->y1 * pitch); + std::vector channel_bufs(m_Image->numcomps); + std::vector adjust_comps(m_Image->numcomps); + for (uint32_t i = 0; i < m_Image->numcomps; i++) { + channel_bufs[i] = dest_buf + offsets[i]; + adjust_comps[i] = m_Image->comps[i].prec - 8; + if (i > 0) { + if (m_Image->comps[i].dx != m_Image->comps[i - 1].dx || + m_Image->comps[i].dy != m_Image->comps[i - 1].dy || + m_Image->comps[i].prec != m_Image->comps[i - 1].prec) { + return false; + } + } + } + uint32_t width = m_Image->comps[0].w; + uint32_t height = m_Image->comps[0].h; + for (uint32_t channel = 0; channel < m_Image->numcomps; ++channel) { + uint8_t* pChannel = channel_bufs[channel]; + if (adjust_comps[channel] < 0) { + for (uint32_t row = 0; row < height; ++row) { + uint8_t* pScanline = pChannel + row * pitch; + for (uint32_t col = 0; col < width; ++col) { + uint8_t* pPixel = pScanline + col * m_Image->numcomps; + if (!m_Image->comps[channel].data) + continue; + + int src = m_Image->comps[channel].data[row * width + col]; + src += m_Image->comps[channel].sgnd + ? 1 << (m_Image->comps[channel].prec - 1) + : 0; + if (adjust_comps[channel] > 0) { + *pPixel = 0; + } else { + *pPixel = static_cast(src << -adjust_comps[channel]); + } + } + } + } else { + for (uint32_t row = 0; row < height; ++row) { + uint8_t* pScanline = pChannel + row * pitch; + for (uint32_t col = 0; col < width; ++col) { + uint8_t* pPixel = pScanline + col * m_Image->numcomps; + if (!m_Image->comps[channel].data) + continue; + + int src = m_Image->comps[channel].data[row * width + col]; + src += m_Image->comps[channel].sgnd + ? 1 << (m_Image->comps[channel].prec - 1) + : 0; + if (adjust_comps[channel] - 1 < 0) { + *pPixel = static_cast((src >> adjust_comps[channel])); + } else { + int tmpPixel = (src >> adjust_comps[channel]) + + ((src >> (adjust_comps[channel] - 1)) % 2); + tmpPixel = pdfium::clamp(tmpPixel, 0, 255); + *pPixel = static_cast(tmpPixel); + } + } + } + } + } + return true; +} + +CCodec_JpxModule::CCodec_JpxModule() {} + +CCodec_JpxModule::~CCodec_JpxModule() {} + +std::unique_ptr CCodec_JpxModule::CreateDecoder( + const uint8_t* src_buf, + uint32_t src_size, + CPDF_ColorSpace* cs) { + auto decoder = pdfium::MakeUnique(cs); + return decoder->Init(pdfium::make_span(src_buf, src_size)) + ? std::move(decoder) + : nullptr; +} + +void CCodec_JpxModule::GetImageInfo(CJPX_Decoder* pDecoder, + uint32_t* width, + uint32_t* height, + uint32_t* components) { + pDecoder->GetInfo(width, height, components); +} + +bool CCodec_JpxModule::Decode(CJPX_Decoder* pDecoder, + uint8_t* dest_data, + uint32_t pitch, + const std::vector& offsets) { + return pDecoder->Decode(dest_data, pitch, offsets); +} diff --git a/core/fxcodec/codec/fx_codec_fax.cpp b/core/fxcodec/codec/fx_codec_fax.cpp deleted file mode 100644 index c6e71b6b60..0000000000 --- a/core/fxcodec/codec/fx_codec_fax.cpp +++ /dev/null @@ -1,803 +0,0 @@ -// Copyright 2014 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 -#include -#include - -#include "core/fxcodec/codec/ccodec_faxmodule.h" -#include "core/fxcodec/codec/ccodec_scanlinedecoder.h" -#include "core/fxcodec/codec/codec_int.h" -#include "core/fxcrt/cfx_binarybuf.h" -#include "core/fxcrt/fx_memory.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" - -namespace { - -const uint8_t OneLeadPos[256] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -// Limit of image dimension. Use the same limit as the JBIG2 codecs. -const int kMaxImageDimension = 65535; - -int FindBit(const uint8_t* data_buf, int max_pos, int start_pos, bool bit) { - ASSERT(start_pos >= 0); - if (start_pos >= max_pos) - return max_pos; - - const uint8_t bit_xor = bit ? 0x00 : 0xff; - int bit_offset = start_pos % 8; - if (bit_offset) { - const int byte_pos = start_pos / 8; - uint8_t data = (data_buf[byte_pos] ^ bit_xor) & (0xff >> bit_offset); - if (data) - return byte_pos * 8 + OneLeadPos[data]; - - start_pos += 7; - } - - const int max_byte = (max_pos + 7) / 8; - int byte_pos = start_pos / 8; - - // Try reading in bigger chunks in case there are long runs to be skipped. - static constexpr int kBulkReadSize = 8; - if (max_byte >= kBulkReadSize && byte_pos < max_byte - kBulkReadSize) { - static constexpr uint8_t skip_block_0[kBulkReadSize] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static constexpr uint8_t skip_block_1[kBulkReadSize] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - const uint8_t* skip_block = bit ? skip_block_0 : skip_block_1; - while (byte_pos < max_byte - kBulkReadSize && - memcmp(data_buf + byte_pos, skip_block, kBulkReadSize) == 0) { - byte_pos += kBulkReadSize; - } - } - - while (byte_pos < max_byte) { - uint8_t data = data_buf[byte_pos] ^ bit_xor; - if (data) - return std::min(byte_pos * 8 + OneLeadPos[data], max_pos); - - ++byte_pos; - } - return max_pos; -} - -void FaxG4FindB1B2(const std::vector& ref_buf, - int columns, - int a0, - bool a0color, - int* b1, - int* b2) { - bool first_bit = a0 < 0 || (ref_buf[a0 / 8] & (1 << (7 - a0 % 8))) != 0; - *b1 = FindBit(ref_buf.data(), columns, a0 + 1, !first_bit); - if (*b1 >= columns) { - *b1 = *b2 = columns; - return; - } - if (first_bit == !a0color) { - *b1 = FindBit(ref_buf.data(), columns, *b1 + 1, first_bit); - first_bit = !first_bit; - } - if (*b1 >= columns) { - *b1 = *b2 = columns; - return; - } - *b2 = FindBit(ref_buf.data(), columns, *b1 + 1, first_bit); -} - -void FaxFillBits(uint8_t* dest_buf, int columns, int startpos, int endpos) { - startpos = std::max(startpos, 0); - endpos = pdfium::clamp(endpos, 0, columns); - if (startpos >= endpos) - return; - - int first_byte = startpos / 8; - int last_byte = (endpos - 1) / 8; - if (first_byte == last_byte) { - for (int i = startpos % 8; i <= (endpos - 1) % 8; ++i) - dest_buf[first_byte] -= 1 << (7 - i); - return; - } - - for (int i = startpos % 8; i < 8; ++i) - dest_buf[first_byte] -= 1 << (7 - i); - for (int i = 0; i <= (endpos - 1) % 8; ++i) - dest_buf[last_byte] -= 1 << (7 - i); - - if (last_byte > first_byte + 1) - memset(dest_buf + first_byte + 1, 0, last_byte - first_byte - 1); -} - -inline bool NextBit(const uint8_t* src_buf, int* bitpos) { - int pos = (*bitpos)++; - return !!(src_buf[pos / 8] & (1 << (7 - pos % 8))); -} - -const uint8_t FaxBlackRunIns[] = { - 0, 2, 0x02, 3, 0, 0x03, - 2, 0, 2, 0x02, 1, 0, - 0x03, 4, 0, 2, 0x02, 6, - 0, 0x03, 5, 0, 1, 0x03, - 7, 0, 2, 0x04, 9, 0, - 0x05, 8, 0, 3, 0x04, 10, - 0, 0x05, 11, 0, 0x07, 12, - 0, 2, 0x04, 13, 0, 0x07, - 14, 0, 1, 0x18, 15, 0, - 5, 0x08, 18, 0, 0x0f, 64, - 0, 0x17, 16, 0, 0x18, 17, - 0, 0x37, 0, 0, 10, 0x08, - 0x00, 0x07, 0x0c, 0x40, 0x07, 0x0d, - 0x80, 0x07, 0x17, 24, 0, 0x18, - 25, 0, 0x28, 23, 0, 0x37, - 22, 0, 0x67, 19, 0, 0x68, - 20, 0, 0x6c, 21, 0, 54, - 0x12, 1984 % 256, 1984 / 256, 0x13, 2048 % 256, 2048 / 256, - 0x14, 2112 % 256, 2112 / 256, 0x15, 2176 % 256, 2176 / 256, - 0x16, 2240 % 256, 2240 / 256, 0x17, 2304 % 256, 2304 / 256, - 0x1c, 2368 % 256, 2368 / 256, 0x1d, 2432 % 256, 2432 / 256, - 0x1e, 2496 % 256, 2496 / 256, 0x1f, 2560 % 256, 2560 / 256, - 0x24, 52, 0, 0x27, 55, 0, - 0x28, 56, 0, 0x2b, 59, 0, - 0x2c, 60, 0, 0x33, 320 % 256, 320 / 256, - 0x34, 384 % 256, 384 / 256, 0x35, 448 % 256, 448 / 256, - 0x37, 53, 0, 0x38, 54, 0, - 0x52, 50, 0, 0x53, 51, 0, - 0x54, 44, 0, 0x55, 45, 0, - 0x56, 46, 0, 0x57, 47, 0, - 0x58, 57, 0, 0x59, 58, 0, - 0x5a, 61, 0, 0x5b, 256 % 256, 256 / 256, - 0x64, 48, 0, 0x65, 49, 0, - 0x66, 62, 0, 0x67, 63, 0, - 0x68, 30, 0, 0x69, 31, 0, - 0x6a, 32, 0, 0x6b, 33, 0, - 0x6c, 40, 0, 0x6d, 41, 0, - 0xc8, 128, 0, 0xc9, 192, 0, - 0xca, 26, 0, 0xcb, 27, 0, - 0xcc, 28, 0, 0xcd, 29, 0, - 0xd2, 34, 0, 0xd3, 35, 0, - 0xd4, 36, 0, 0xd5, 37, 0, - 0xd6, 38, 0, 0xd7, 39, 0, - 0xda, 42, 0, 0xdb, 43, 0, - 20, 0x4a, 640 % 256, 640 / 256, 0x4b, 704 % 256, - 704 / 256, 0x4c, 768 % 256, 768 / 256, 0x4d, 832 % 256, - 832 / 256, 0x52, 1280 % 256, 1280 / 256, 0x53, 1344 % 256, - 1344 / 256, 0x54, 1408 % 256, 1408 / 256, 0x55, 1472 % 256, - 1472 / 256, 0x5a, 1536 % 256, 1536 / 256, 0x5b, 1600 % 256, - 1600 / 256, 0x64, 1664 % 256, 1664 / 256, 0x65, 1728 % 256, - 1728 / 256, 0x6c, 512 % 256, 512 / 256, 0x6d, 576 % 256, - 576 / 256, 0x72, 896 % 256, 896 / 256, 0x73, 960 % 256, - 960 / 256, 0x74, 1024 % 256, 1024 / 256, 0x75, 1088 % 256, - 1088 / 256, 0x76, 1152 % 256, 1152 / 256, 0x77, 1216 % 256, - 1216 / 256, 0xff}; - -const uint8_t FaxWhiteRunIns[] = { - 0, 0, 0, 6, 0x07, 2, - 0, 0x08, 3, 0, 0x0B, 4, - 0, 0x0C, 5, 0, 0x0E, 6, - 0, 0x0F, 7, 0, 6, 0x07, - 10, 0, 0x08, 11, 0, 0x12, - 128, 0, 0x13, 8, 0, 0x14, - 9, 0, 0x1b, 64, 0, 9, - 0x03, 13, 0, 0x07, 1, 0, - 0x08, 12, 0, 0x17, 192, 0, - 0x18, 1664 % 256, 1664 / 256, 0x2a, 16, 0, - 0x2B, 17, 0, 0x34, 14, 0, - 0x35, 15, 0, 12, 0x03, 22, - 0, 0x04, 23, 0, 0x08, 20, - 0, 0x0c, 19, 0, 0x13, 26, - 0, 0x17, 21, 0, 0x18, 28, - 0, 0x24, 27, 0, 0x27, 18, - 0, 0x28, 24, 0, 0x2B, 25, - 0, 0x37, 256 % 256, 256 / 256, 42, 0x02, - 29, 0, 0x03, 30, 0, 0x04, - 45, 0, 0x05, 46, 0, 0x0a, - 47, 0, 0x0b, 48, 0, 0x12, - 33, 0, 0x13, 34, 0, 0x14, - 35, 0, 0x15, 36, 0, 0x16, - 37, 0, 0x17, 38, 0, 0x1a, - 31, 0, 0x1b, 32, 0, 0x24, - 53, 0, 0x25, 54, 0, 0x28, - 39, 0, 0x29, 40, 0, 0x2a, - 41, 0, 0x2b, 42, 0, 0x2c, - 43, 0, 0x2d, 44, 0, 0x32, - 61, 0, 0x33, 62, 0, 0x34, - 63, 0, 0x35, 0, 0, 0x36, - 320 % 256, 320 / 256, 0x37, 384 % 256, 384 / 256, 0x4a, - 59, 0, 0x4b, 60, 0, 0x52, - 49, 0, 0x53, 50, 0, 0x54, - 51, 0, 0x55, 52, 0, 0x58, - 55, 0, 0x59, 56, 0, 0x5a, - 57, 0, 0x5b, 58, 0, 0x64, - 448 % 256, 448 / 256, 0x65, 512 % 256, 512 / 256, 0x67, - 640 % 256, 640 / 256, 0x68, 576 % 256, 576 / 256, 16, - 0x98, 1472 % 256, 1472 / 256, 0x99, 1536 % 256, 1536 / 256, - 0x9a, 1600 % 256, 1600 / 256, 0x9b, 1728 % 256, 1728 / 256, - 0xcc, 704 % 256, 704 / 256, 0xcd, 768 % 256, 768 / 256, - 0xd2, 832 % 256, 832 / 256, 0xd3, 896 % 256, 896 / 256, - 0xd4, 960 % 256, 960 / 256, 0xd5, 1024 % 256, 1024 / 256, - 0xd6, 1088 % 256, 1088 / 256, 0xd7, 1152 % 256, 1152 / 256, - 0xd8, 1216 % 256, 1216 / 256, 0xd9, 1280 % 256, 1280 / 256, - 0xda, 1344 % 256, 1344 / 256, 0xdb, 1408 % 256, 1408 / 256, - 0, 3, 0x08, 1792 % 256, 1792 / 256, 0x0c, - 1856 % 256, 1856 / 256, 0x0d, 1920 % 256, 1920 / 256, 10, - 0x12, 1984 % 256, 1984 / 256, 0x13, 2048 % 256, 2048 / 256, - 0x14, 2112 % 256, 2112 / 256, 0x15, 2176 % 256, 2176 / 256, - 0x16, 2240 % 256, 2240 / 256, 0x17, 2304 % 256, 2304 / 256, - 0x1c, 2368 % 256, 2368 / 256, 0x1d, 2432 % 256, 2432 / 256, - 0x1e, 2496 % 256, 2496 / 256, 0x1f, 2560 % 256, 2560 / 256, - 0xff, -}; - -int FaxGetRun(const uint8_t* ins_array, - const uint8_t* src_buf, - int* bitpos, - int bitsize) { - uint32_t code = 0; - int ins_off = 0; - while (1) { - uint8_t ins = ins_array[ins_off++]; - if (ins == 0xff) - return -1; - - if (*bitpos >= bitsize) - return -1; - - code <<= 1; - if (src_buf[*bitpos / 8] & (1 << (7 - *bitpos % 8))) - ++code; - - ++(*bitpos); - int next_off = ins_off + ins * 3; - for (; ins_off < next_off; ins_off += 3) { - if (ins_array[ins_off] == code) - return ins_array[ins_off + 1] + ins_array[ins_off + 2] * 256; - } - } -} - -void FaxG4GetRow(const uint8_t* src_buf, - int bitsize, - int* bitpos, - uint8_t* dest_buf, - const std::vector& ref_buf, - int columns) { - int a0 = -1; - bool a0color = true; - while (1) { - if (*bitpos >= bitsize) - return; - - int a1; - int a2; - int b1; - int b2; - FaxG4FindB1B2(ref_buf, columns, a0, a0color, &b1, &b2); - - int v_delta = 0; - if (!NextBit(src_buf, bitpos)) { - if (*bitpos >= bitsize) - return; - - bool bit1 = NextBit(src_buf, bitpos); - if (*bitpos >= bitsize) - return; - - bool bit2 = NextBit(src_buf, bitpos); - if (bit1) { - v_delta = bit2 ? 1 : -1; - } else if (bit2) { - int run_len1 = 0; - while (1) { - int run = FaxGetRun(a0color ? FaxWhiteRunIns : FaxBlackRunIns, - src_buf, bitpos, bitsize); - run_len1 += run; - if (run < 64) - break; - } - if (a0 < 0) - ++run_len1; - if (run_len1 < 0) - return; - - a1 = a0 + run_len1; - if (!a0color) - FaxFillBits(dest_buf, columns, a0, a1); - - int run_len2 = 0; - while (1) { - int run = FaxGetRun(a0color ? FaxBlackRunIns : FaxWhiteRunIns, - src_buf, bitpos, bitsize); - run_len2 += run; - if (run < 64) - break; - } - if (run_len2 < 0) - return; - a2 = a1 + run_len2; - if (a0color) - FaxFillBits(dest_buf, columns, a1, a2); - - a0 = a2; - if (a0 < columns) - continue; - - return; - } else { - if (*bitpos >= bitsize) - return; - - if (NextBit(src_buf, bitpos)) { - if (!a0color) - FaxFillBits(dest_buf, columns, a0, b2); - - if (b2 >= columns) - return; - - a0 = b2; - continue; - } - - if (*bitpos >= bitsize) - return; - - bool next_bit1 = NextBit(src_buf, bitpos); - if (*bitpos >= bitsize) - return; - - bool next_bit2 = NextBit(src_buf, bitpos); - if (next_bit1) { - v_delta = next_bit2 ? 2 : -2; - } else if (next_bit2) { - if (*bitpos >= bitsize) - return; - - v_delta = NextBit(src_buf, bitpos) ? 3 : -3; - } else { - if (*bitpos >= bitsize) - return; - - if (NextBit(src_buf, bitpos)) { - *bitpos += 3; - continue; - } - *bitpos += 5; - return; - } - } - } - a1 = b1 + v_delta; - if (!a0color) - FaxFillBits(dest_buf, columns, a0, a1); - - if (a1 >= columns) - return; - - // The position of picture element must be monotonic increasing. - if (a0 >= a1) - return; - - a0 = a1; - a0color = !a0color; - } -} - -void FaxSkipEOL(const uint8_t* src_buf, int bitsize, int* bitpos) { - int startbit = *bitpos; - while (*bitpos < bitsize) { - if (!NextBit(src_buf, bitpos)) - continue; - if (*bitpos - startbit <= 11) - *bitpos = startbit; - return; - } -} - -void FaxGet1DLine(const uint8_t* src_buf, - int bitsize, - int* bitpos, - std::vector* dest_buf, - int columns) { - bool color = true; - int startpos = 0; - while (1) { - if (*bitpos >= bitsize) - return; - - int run_len = 0; - while (1) { - int run = FaxGetRun(color ? FaxWhiteRunIns : FaxBlackRunIns, src_buf, - bitpos, bitsize); - if (run < 0) { - while (*bitpos < bitsize) { - if (NextBit(src_buf, bitpos)) - return; - } - return; - } - run_len += run; - if (run < 64) - break; - } - if (!color) - FaxFillBits(dest_buf->data(), columns, startpos, startpos + run_len); - - startpos += run_len; - if (startpos >= columns) - break; - - color = !color; - } -} - -} // namespace - -class CCodec_FaxDecoder final : public CCodec_ScanlineDecoder { - public: - CCodec_FaxDecoder(const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - uint32_t pitch, - int K, - bool EndOfLine, - bool EncodedByteAlign, - bool BlackIs1); - ~CCodec_FaxDecoder() override; - - // CCodec_ScanlineDecoder - bool v_Rewind() override; - uint8_t* v_GetNextLine() override; - uint32_t GetSrcOffset() override; - - private: - const int m_Encoding; - int m_bitpos; - bool m_bByteAlign; - const bool m_bEndOfLine; - const bool m_bBlack; - const uint32_t m_SrcSize; - const uint8_t* const m_pSrcBuf; - std::vector m_ScanlineBuf; - std::vector m_RefBuf; -}; - -CCodec_FaxDecoder::CCodec_FaxDecoder(const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - uint32_t pitch, - int K, - bool EndOfLine, - bool EncodedByteAlign, - bool BlackIs1) - : CCodec_ScanlineDecoder(width, height, width, height, 1, 1, pitch), - m_Encoding(K), - m_bitpos(0), - m_bByteAlign(EncodedByteAlign), - m_bEndOfLine(EndOfLine), - m_bBlack(BlackIs1), - m_SrcSize(src_size), - m_pSrcBuf(src_buf), - m_ScanlineBuf(pitch), - m_RefBuf(pitch) {} - -CCodec_FaxDecoder::~CCodec_FaxDecoder() {} - -bool CCodec_FaxDecoder::v_Rewind() { - memset(m_RefBuf.data(), 0xff, m_RefBuf.size()); - m_bitpos = 0; - return true; -} - -uint8_t* CCodec_FaxDecoder::v_GetNextLine() { - int bitsize = m_SrcSize * 8; - FaxSkipEOL(m_pSrcBuf, bitsize, &m_bitpos); - if (m_bitpos >= bitsize) - return nullptr; - - memset(m_ScanlineBuf.data(), 0xff, m_ScanlineBuf.size()); - if (m_Encoding < 0) { - FaxG4GetRow(m_pSrcBuf, bitsize, &m_bitpos, m_ScanlineBuf.data(), m_RefBuf, - m_OrigWidth); - m_RefBuf = m_ScanlineBuf; - } else if (m_Encoding == 0) { - FaxGet1DLine(m_pSrcBuf, bitsize, &m_bitpos, &m_ScanlineBuf, m_OrigWidth); - } else { - if (NextBit(m_pSrcBuf, &m_bitpos)) { - FaxGet1DLine(m_pSrcBuf, bitsize, &m_bitpos, &m_ScanlineBuf, m_OrigWidth); - } else { - FaxG4GetRow(m_pSrcBuf, bitsize, &m_bitpos, m_ScanlineBuf.data(), m_RefBuf, - m_OrigWidth); - } - m_RefBuf = m_ScanlineBuf; - } - if (m_bEndOfLine) - FaxSkipEOL(m_pSrcBuf, bitsize, &m_bitpos); - - if (m_bByteAlign && m_bitpos < bitsize) { - int bitpos0 = m_bitpos; - int bitpos1 = (m_bitpos + 7) / 8 * 8; - while (m_bByteAlign && bitpos0 < bitpos1) { - int bit = m_pSrcBuf[bitpos0 / 8] & (1 << (7 - bitpos0 % 8)); - if (bit != 0) - m_bByteAlign = false; - else - ++bitpos0; - } - if (m_bByteAlign) - m_bitpos = bitpos1; - } - if (m_bBlack) { - ASSERT(m_Pitch == m_ScanlineBuf.size()); - ASSERT(m_Pitch % 4 == 0); - uint32_t* data = reinterpret_cast(m_ScanlineBuf.data()); - for (size_t i = 0; i < m_ScanlineBuf.size() / 4; ++i) - data[i] = ~data[i]; - } - return m_ScanlineBuf.data(); -} - -uint32_t CCodec_FaxDecoder::GetSrcOffset() { - return std::min(static_cast((m_bitpos + 7) / 8), m_SrcSize); -} - -void FaxG4Decode(const uint8_t* src_buf, - uint32_t src_size, - int* pbitpos, - uint8_t* dest_buf, - int width, - int height, - int pitch) { - if (pitch == 0) - pitch = (width + 7) / 8; - - std::vector ref_buf(pitch, 0xff); - int bitpos = *pbitpos; - for (int iRow = 0; iRow < height; iRow++) { - uint8_t* line_buf = dest_buf + iRow * pitch; - memset(line_buf, 0xff, pitch); - FaxG4GetRow(src_buf, src_size << 3, &bitpos, line_buf, ref_buf, width); - memcpy(ref_buf.data(), line_buf, pitch); - } - *pbitpos = bitpos; -} - -std::unique_ptr CCodec_FaxModule::CreateDecoder( - const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - int K, - bool EndOfLine, - bool EncodedByteAlign, - bool BlackIs1, - int Columns, - int Rows) { - int actual_width = Columns ? Columns : width; - int actual_height = Rows ? Rows : height; - - // Reject invalid values. - if (actual_width <= 0 || actual_height <= 0) - return nullptr; - - // Reject unreasonable large input. - if (actual_width > kMaxImageDimension || actual_height > kMaxImageDimension) - return nullptr; - - uint32_t pitch = (static_cast(actual_width) + 31) / 32 * 4; - return pdfium::MakeUnique( - src_buf, src_size, actual_width, actual_height, pitch, K, EndOfLine, - EncodedByteAlign, BlackIs1); -} - -#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ -namespace { -const uint8_t BlackRunTerminator[128] = { - 0x37, 10, 0x02, 3, 0x03, 2, 0x02, 2, 0x03, 3, 0x03, 4, 0x02, 4, - 0x03, 5, 0x05, 6, 0x04, 6, 0x04, 7, 0x05, 7, 0x07, 7, 0x04, 8, - 0x07, 8, 0x18, 9, 0x17, 10, 0x18, 10, 0x08, 10, 0x67, 11, 0x68, 11, - 0x6c, 11, 0x37, 11, 0x28, 11, 0x17, 11, 0x18, 11, 0xca, 12, 0xcb, 12, - 0xcc, 12, 0xcd, 12, 0x68, 12, 0x69, 12, 0x6a, 12, 0x6b, 12, 0xd2, 12, - 0xd3, 12, 0xd4, 12, 0xd5, 12, 0xd6, 12, 0xd7, 12, 0x6c, 12, 0x6d, 12, - 0xda, 12, 0xdb, 12, 0x54, 12, 0x55, 12, 0x56, 12, 0x57, 12, 0x64, 12, - 0x65, 12, 0x52, 12, 0x53, 12, 0x24, 12, 0x37, 12, 0x38, 12, 0x27, 12, - 0x28, 12, 0x58, 12, 0x59, 12, 0x2b, 12, 0x2c, 12, 0x5a, 12, 0x66, 12, - 0x67, 12, -}; - -const uint8_t BlackRunMarkup[80] = { - 0x0f, 10, 0xc8, 12, 0xc9, 12, 0x5b, 12, 0x33, 12, 0x34, 12, 0x35, 12, - 0x6c, 13, 0x6d, 13, 0x4a, 13, 0x4b, 13, 0x4c, 13, 0x4d, 13, 0x72, 13, - 0x73, 13, 0x74, 13, 0x75, 13, 0x76, 13, 0x77, 13, 0x52, 13, 0x53, 13, - 0x54, 13, 0x55, 13, 0x5a, 13, 0x5b, 13, 0x64, 13, 0x65, 13, 0x08, 11, - 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12, - 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12, -}; - -const uint8_t WhiteRunTerminator[128] = { - 0x35, 8, 0x07, 6, 0x07, 4, 0x08, 4, 0x0B, 4, 0x0C, 4, 0x0E, 4, 0x0F, 4, - 0x13, 5, 0x14, 5, 0x07, 5, 0x08, 5, 0x08, 6, 0x03, 6, 0x34, 6, 0x35, 6, - 0x2a, 6, 0x2B, 6, 0x27, 7, 0x0c, 7, 0x08, 7, 0x17, 7, 0x03, 7, 0x04, 7, - 0x28, 7, 0x2B, 7, 0x13, 7, 0x24, 7, 0x18, 7, 0x02, 8, 0x03, 8, 0x1a, 8, - 0x1b, 8, 0x12, 8, 0x13, 8, 0x14, 8, 0x15, 8, 0x16, 8, 0x17, 8, 0x28, 8, - 0x29, 8, 0x2a, 8, 0x2b, 8, 0x2c, 8, 0x2d, 8, 0x04, 8, 0x05, 8, 0x0a, 8, - 0x0b, 8, 0x52, 8, 0x53, 8, 0x54, 8, 0x55, 8, 0x24, 8, 0x25, 8, 0x58, 8, - 0x59, 8, 0x5a, 8, 0x5b, 8, 0x4a, 8, 0x4b, 8, 0x32, 8, 0x33, 8, 0x34, 8, -}; - -const uint8_t WhiteRunMarkup[80] = { - 0x1b, 5, 0x12, 5, 0x17, 6, 0x37, 7, 0x36, 8, 0x37, 8, 0x64, 8, - 0x65, 8, 0x68, 8, 0x67, 8, 0xcc, 9, 0xcd, 9, 0xd2, 9, 0xd3, 9, - 0xd4, 9, 0xd5, 9, 0xd6, 9, 0xd7, 9, 0xd8, 9, 0xd9, 9, 0xda, 9, - 0xdb, 9, 0x98, 9, 0x99, 9, 0x9a, 9, 0x18, 6, 0x9b, 9, 0x08, 11, - 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12, - 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12, -}; - -void AddBitStream(uint8_t* dest_buf, int* dest_bitpos, int data, int bitlen) { - for (int i = bitlen - 1; i >= 0; i--) { - if (data & (1 << i)) - dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); - (*dest_bitpos)++; - } -} - -void FaxEncodeRun(uint8_t* dest_buf, int* dest_bitpos, int run, bool bWhite) { - while (run >= 2560) { - AddBitStream(dest_buf, dest_bitpos, 0x1f, 12); - run -= 2560; - } - if (run >= 64) { - int markup = run - run % 64; - const uint8_t* p = bWhite ? WhiteRunMarkup : BlackRunMarkup; - p += (markup / 64 - 1) * 2; - AddBitStream(dest_buf, dest_bitpos, *p, p[1]); - } - run %= 64; - const uint8_t* p = bWhite ? WhiteRunTerminator : BlackRunTerminator; - p += run * 2; - AddBitStream(dest_buf, dest_bitpos, *p, p[1]); -} - -void FaxEncode2DLine(uint8_t* dest_buf, - int* dest_bitpos, - const uint8_t* src_buf, - const std::vector& ref_buf, - int cols) { - int a0 = -1; - bool a0color = true; - while (1) { - int a1 = FindBit(src_buf, cols, a0 + 1, !a0color); - int b1; - int b2; - FaxG4FindB1B2(ref_buf, cols, a0, a0color, &b1, &b2); - if (b2 < a1) { - *dest_bitpos += 3; - dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); - (*dest_bitpos)++; - a0 = b2; - } else if (a1 - b1 <= 3 && b1 - a1 <= 3) { - int delta = a1 - b1; - switch (delta) { - case 0: - dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); - break; - case 1: - case 2: - case 3: - *dest_bitpos += delta == 1 ? 1 : delta + 2; - dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); - (*dest_bitpos)++; - dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); - break; - case -1: - case -2: - case -3: - *dest_bitpos += delta == -1 ? 1 : -delta + 2; - dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); - (*dest_bitpos)++; - break; - } - (*dest_bitpos)++; - a0 = a1; - a0color = !a0color; - } else { - int a2 = FindBit(src_buf, cols, a1 + 1, a0color); - (*dest_bitpos)++; - (*dest_bitpos)++; - dest_buf[*dest_bitpos / 8] |= 1 << (7 - *dest_bitpos % 8); - (*dest_bitpos)++; - if (a0 < 0) - a0 = 0; - FaxEncodeRun(dest_buf, dest_bitpos, a1 - a0, a0color); - FaxEncodeRun(dest_buf, dest_bitpos, a2 - a1, !a0color); - a0 = a2; - } - if (a0 >= cols) - return; - } -} - -class CCodec_FaxEncoder { - public: - CCodec_FaxEncoder(const uint8_t* src_buf, int width, int height, int pitch); - ~CCodec_FaxEncoder(); - void Encode(std::unique_ptr* dest_buf, - uint32_t* dest_size); - - private: - CFX_BinaryBuf m_DestBuf; - std::vector m_RefLine; - uint8_t* m_pLineBuf; - const int m_Cols; - const int m_Rows; - const int m_Pitch; - const uint8_t* m_pSrcBuf; -}; - -CCodec_FaxEncoder::CCodec_FaxEncoder(const uint8_t* src_buf, - int width, - int height, - int pitch) - : m_Cols(width), m_Rows(height), m_Pitch(pitch), m_pSrcBuf(src_buf) { - m_RefLine.resize(m_Pitch); - memset(m_RefLine.data(), 0xff, m_Pitch); - m_pLineBuf = FX_Alloc2D(uint8_t, m_Pitch, 8); - m_DestBuf.SetAllocStep(10240); -} - -CCodec_FaxEncoder::~CCodec_FaxEncoder() { - FX_Free(m_pLineBuf); -} - -void CCodec_FaxEncoder::Encode( - std::unique_ptr* dest_buf, - uint32_t* dest_size) { - int dest_bitpos = 0; - uint8_t last_byte = 0; - for (int i = 0; i < m_Rows; i++) { - const uint8_t* scan_line = m_pSrcBuf + i * m_Pitch; - memset(m_pLineBuf, 0, m_Pitch * 8); - m_pLineBuf[0] = last_byte; - FaxEncode2DLine(m_pLineBuf, &dest_bitpos, scan_line, m_RefLine, m_Cols); - m_DestBuf.AppendBlock(m_pLineBuf, dest_bitpos / 8); - last_byte = m_pLineBuf[dest_bitpos / 8]; - dest_bitpos %= 8; - memcpy(m_RefLine.data(), scan_line, m_Pitch); - } - if (dest_bitpos) - m_DestBuf.AppendByte(last_byte); - *dest_size = m_DestBuf.GetSize(); - *dest_buf = m_DestBuf.DetachBuffer(); -} - -} // namespace - -void CCodec_FaxModule::FaxEncode( - const uint8_t* src_buf, - int width, - int height, - int pitch, - std::unique_ptr* dest_buf, - uint32_t* dest_size) { - CCodec_FaxEncoder encoder(src_buf, width, height, pitch); - encoder.Encode(dest_buf, dest_size); -} - -#endif // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ diff --git a/core/fxcodec/codec/fx_codec_flate.cpp b/core/fxcodec/codec/fx_codec_flate.cpp deleted file mode 100644 index 11bdf67c42..0000000000 --- a/core/fxcodec/codec/fx_codec_flate.cpp +++ /dev/null @@ -1,852 +0,0 @@ -// Copyright 2014 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/fx_codec.h" - -#include -#include -#include -#include -#include - -#include "core/fxcodec/codec/ccodec_flatemodule.h" -#include "core/fxcodec/codec/ccodec_scanlinedecoder.h" -#include "core/fxcrt/fx_extension.h" -#include "third_party/base/numerics/safe_conversions.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/span.h" - -#if defined(USE_SYSTEM_ZLIB) -#include -#else -#include "third_party/zlib/zlib.h" -#endif - -extern "C" { - -static void* my_alloc_func(void* opaque, - unsigned int items, - unsigned int size) { - return FX_Alloc2D(uint8_t, items, size); -} - -static void my_free_func(void* opaque, void* address) { - FX_Free(address); -} - -} // extern "C" - -namespace { - -static constexpr uint32_t kMaxTotalOutSize = 1024 * 1024 * 1024; // 1 GiB - -uint32_t FlateGetPossiblyTruncatedTotalOut(z_stream* context) { - return std::min(pdfium::base::saturated_cast(context->total_out), - kMaxTotalOutSize); -} - -uint32_t FlateGetPossiblyTruncatedTotalIn(z_stream* context) { - return pdfium::base::saturated_cast(context->total_in); -} - -bool FlateCompress(unsigned char* dest_buf, - unsigned long* dest_size, - const unsigned char* src_buf, - uint32_t src_size) { - return compress(dest_buf, dest_size, src_buf, src_size) == Z_OK; -} - -z_stream* FlateInit() { - z_stream* p = FX_Alloc(z_stream, 1); - p->zalloc = my_alloc_func; - p->zfree = my_free_func; - inflateInit(p); - return p; -} - -void FlateInput(z_stream* context, pdfium::span src_buf) { - context->next_in = const_cast(src_buf.data()); - context->avail_in = static_cast(src_buf.size()); -} - -uint32_t FlateOutput(z_stream* context, - unsigned char* dest_buf, - uint32_t dest_size) { - context->next_out = dest_buf; - context->avail_out = dest_size; - uint32_t pre_pos = FlateGetPossiblyTruncatedTotalOut(context); - int ret = inflate(static_cast(context), Z_SYNC_FLUSH); - - uint32_t post_pos = FlateGetPossiblyTruncatedTotalOut(context); - ASSERT(post_pos >= pre_pos); - - uint32_t written = post_pos - pre_pos; - if (written < dest_size) - memset(dest_buf + written, '\0', dest_size - written); - - return ret; -} - -uint32_t FlateGetAvailOut(z_stream* context) { - return context->avail_out; -} - -void FlateEnd(z_stream* context) { - inflateEnd(context); - FX_Free(context); -} - -// For use with std::unique_ptr. -struct FlateDeleter { - inline void operator()(z_stream* context) { FlateEnd(context); } -}; - -class CLZWDecoder { - public: - int Decode(uint8_t* output, - uint32_t& outlen, - const uint8_t* input, - uint32_t& size, - bool bEarlyChange); - - private: - void AddCode(uint32_t prefix_code, uint8_t append_char); - void DecodeString(uint32_t code); - - uint32_t m_InPos; - uint32_t m_OutPos; - uint8_t* m_pOutput; - const uint8_t* m_pInput; - bool m_Early; - uint32_t m_nCodes; - uint32_t m_StackLen; - int m_CodeLen; - uint32_t m_CodeArray[5021]; - uint8_t m_DecodeStack[4000]; -}; - -void CLZWDecoder::AddCode(uint32_t prefix_code, uint8_t append_char) { - if (m_nCodes + m_Early == 4094) { - return; - } - m_CodeArray[m_nCodes++] = (prefix_code << 16) | append_char; - if (m_nCodes + m_Early == 512 - 258) { - m_CodeLen = 10; - } else if (m_nCodes + m_Early == 1024 - 258) { - m_CodeLen = 11; - } else if (m_nCodes + m_Early == 2048 - 258) { - m_CodeLen = 12; - } -} - -void CLZWDecoder::DecodeString(uint32_t code) { - while (1) { - int index = code - 258; - if (index < 0 || index >= (int)m_nCodes) { - break; - } - uint32_t data = m_CodeArray[index]; - if (m_StackLen >= sizeof(m_DecodeStack)) { - return; - } - m_DecodeStack[m_StackLen++] = (uint8_t)data; - code = data >> 16; - } - if (m_StackLen >= sizeof(m_DecodeStack)) { - return; - } - m_DecodeStack[m_StackLen++] = (uint8_t)code; -} - -int CLZWDecoder::Decode(uint8_t* dest_buf, - uint32_t& dest_size, - const uint8_t* src_buf, - uint32_t& src_size, - bool bEarlyChange) { - m_CodeLen = 9; - m_InPos = 0; - m_OutPos = 0; - m_pInput = src_buf; - m_pOutput = dest_buf; - m_Early = bEarlyChange ? 1 : 0; - m_nCodes = 0; - uint32_t old_code = 0xFFFFFFFF; - uint8_t last_char = 0; - while (1) { - if (m_InPos + m_CodeLen > src_size * 8) { - break; - } - int byte_pos = m_InPos / 8; - int bit_pos = m_InPos % 8, bit_left = m_CodeLen; - uint32_t code = 0; - if (bit_pos) { - bit_left -= 8 - bit_pos; - code = (m_pInput[byte_pos++] & ((1 << (8 - bit_pos)) - 1)) << bit_left; - } - if (bit_left < 8) { - code |= m_pInput[byte_pos] >> (8 - bit_left); - } else { - bit_left -= 8; - code |= m_pInput[byte_pos++] << bit_left; - if (bit_left) { - code |= m_pInput[byte_pos] >> (8 - bit_left); - } - } - m_InPos += m_CodeLen; - if (code == 257) - break; - if (code < 256) { - if (m_OutPos == dest_size) { - return -5; - } - if (m_pOutput) { - m_pOutput[m_OutPos] = (uint8_t)code; - } - m_OutPos++; - last_char = (uint8_t)code; - if (old_code != 0xFFFFFFFF) - AddCode(old_code, last_char); - old_code = code; - } else if (code == 256) { - m_CodeLen = 9; - m_nCodes = 0; - old_code = 0xFFFFFFFF; - } else { - // Else 257 or greater. - if (old_code == 0xFFFFFFFF) - return 2; - - m_StackLen = 0; - if (code >= m_nCodes + 258) { - if (m_StackLen < sizeof(m_DecodeStack)) { - m_DecodeStack[m_StackLen++] = last_char; - } - DecodeString(old_code); - } else { - DecodeString(code); - } - if (m_OutPos + m_StackLen > dest_size) { - return -5; - } - if (m_pOutput) { - for (uint32_t i = 0; i < m_StackLen; i++) { - m_pOutput[m_OutPos + i] = m_DecodeStack[m_StackLen - i - 1]; - } - } - m_OutPos += m_StackLen; - last_char = m_DecodeStack[m_StackLen - 1]; - if (old_code < 256) { - AddCode(old_code, last_char); - } else if (old_code - 258 >= m_nCodes) { - dest_size = m_OutPos; - src_size = (m_InPos + 7) / 8; - return 0; - } else { - AddCode(old_code, last_char); - } - old_code = code; - } - } - dest_size = m_OutPos; - src_size = (m_InPos + 7) / 8; - return 0; -} - -uint8_t PathPredictor(int a, int b, int c) { - int p = a + b - c; - int pa = abs(p - a); - int pb = abs(p - b); - int pc = abs(p - c); - if (pa <= pb && pa <= pc) - return (uint8_t)a; - if (pb <= pc) - return (uint8_t)b; - return (uint8_t)c; -} - -void PNG_PredictLine(uint8_t* pDestData, - const uint8_t* pSrcData, - const uint8_t* pLastLine, - int bpc, - int nColors, - int nPixels) { - const uint32_t row_size = CalculatePitch8(bpc, nColors, nPixels).ValueOrDie(); - const uint32_t BytesPerPixel = (bpc * nColors + 7) / 8; - uint8_t tag = pSrcData[0]; - if (tag == 0) { - memmove(pDestData, pSrcData + 1, row_size); - return; - } - for (uint32_t byte = 0; byte < row_size; ++byte) { - uint8_t raw_byte = pSrcData[byte + 1]; - switch (tag) { - case 1: { - uint8_t left = 0; - if (byte >= BytesPerPixel) { - left = pDestData[byte - BytesPerPixel]; - } - pDestData[byte] = raw_byte + left; - break; - } - case 2: { - uint8_t up = 0; - if (pLastLine) { - up = pLastLine[byte]; - } - pDestData[byte] = raw_byte + up; - break; - } - case 3: { - uint8_t left = 0; - if (byte >= BytesPerPixel) { - left = pDestData[byte - BytesPerPixel]; - } - uint8_t up = 0; - if (pLastLine) { - up = pLastLine[byte]; - } - pDestData[byte] = raw_byte + (up + left) / 2; - break; - } - case 4: { - uint8_t left = 0; - if (byte >= BytesPerPixel) { - left = pDestData[byte - BytesPerPixel]; - } - uint8_t up = 0; - if (pLastLine) { - up = pLastLine[byte]; - } - uint8_t upper_left = 0; - if (byte >= BytesPerPixel && pLastLine) { - upper_left = pLastLine[byte - BytesPerPixel]; - } - pDestData[byte] = raw_byte + PathPredictor(left, up, upper_left); - break; - } - default: - pDestData[byte] = raw_byte; - break; - } - } -} - -bool PNG_Predictor(uint8_t*& data_buf, - uint32_t& data_size, - int Colors, - int BitsPerComponent, - int Columns) { - // TODO(thestig): Look into using CalculatePitch8() here. - const int BytesPerPixel = (Colors * BitsPerComponent + 7) / 8; - const int row_size = (Colors * BitsPerComponent * Columns + 7) / 8; - if (row_size <= 0) - return false; - const int row_count = (data_size + row_size) / (row_size + 1); - if (row_count <= 0) - return false; - const int last_row_size = data_size % (row_size + 1); - uint8_t* dest_buf = FX_Alloc2D(uint8_t, row_size, row_count); - uint32_t byte_cnt = 0; - uint8_t* pSrcData = data_buf; - uint8_t* pDestData = dest_buf; - for (int row = 0; row < row_count; row++) { - uint8_t tag = pSrcData[0]; - byte_cnt++; - if (tag == 0) { - int move_size = row_size; - if ((row + 1) * (move_size + 1) > (int)data_size) { - move_size = last_row_size - 1; - } - memmove(pDestData, pSrcData + 1, move_size); - pSrcData += move_size + 1; - pDestData += move_size; - byte_cnt += move_size; - continue; - } - for (int byte = 0; byte < row_size && byte_cnt < data_size; - ++byte, ++byte_cnt) { - uint8_t raw_byte = pSrcData[byte + 1]; - switch (tag) { - case 1: { - uint8_t left = 0; - if (byte >= BytesPerPixel) { - left = pDestData[byte - BytesPerPixel]; - } - pDestData[byte] = raw_byte + left; - break; - } - case 2: { - uint8_t up = 0; - if (row) { - up = pDestData[byte - row_size]; - } - pDestData[byte] = raw_byte + up; - break; - } - case 3: { - uint8_t left = 0; - if (byte >= BytesPerPixel) { - left = pDestData[byte - BytesPerPixel]; - } - uint8_t up = 0; - if (row) { - up = pDestData[byte - row_size]; - } - pDestData[byte] = raw_byte + (up + left) / 2; - break; - } - case 4: { - uint8_t left = 0; - if (byte >= BytesPerPixel) { - left = pDestData[byte - BytesPerPixel]; - } - uint8_t up = 0; - if (row) { - up = pDestData[byte - row_size]; - } - uint8_t upper_left = 0; - if (byte >= BytesPerPixel && row) { - upper_left = pDestData[byte - row_size - BytesPerPixel]; - } - pDestData[byte] = raw_byte + PathPredictor(left, up, upper_left); - break; - } - default: - pDestData[byte] = raw_byte; - break; - } - } - pSrcData += row_size + 1; - pDestData += row_size; - } - FX_Free(data_buf); - data_buf = dest_buf; - data_size = row_size * row_count - - (last_row_size > 0 ? (row_size + 1 - last_row_size) : 0); - return true; -} - -void TIFF_PredictLine(uint8_t* dest_buf, - uint32_t row_size, - int BitsPerComponent, - int Colors, - int Columns) { - if (BitsPerComponent == 1) { - int row_bits = std::min(BitsPerComponent * Colors * Columns, - pdfium::base::checked_cast(row_size * 8)); - int index_pre = 0; - int col_pre = 0; - for (int i = 1; i < row_bits; i++) { - int col = i % 8; - int index = i / 8; - if (((dest_buf[index] >> (7 - col)) & 1) ^ - ((dest_buf[index_pre] >> (7 - col_pre)) & 1)) { - dest_buf[index] |= 1 << (7 - col); - } else { - dest_buf[index] &= ~(1 << (7 - col)); - } - index_pre = index; - col_pre = col; - } - return; - } - int BytesPerPixel = BitsPerComponent * Colors / 8; - if (BitsPerComponent == 16) { - for (uint32_t i = BytesPerPixel; i + 1 < row_size; i += 2) { - uint16_t pixel = - (dest_buf[i - BytesPerPixel] << 8) | dest_buf[i - BytesPerPixel + 1]; - pixel += (dest_buf[i] << 8) | dest_buf[i + 1]; - dest_buf[i] = pixel >> 8; - dest_buf[i + 1] = (uint8_t)pixel; - } - } else { - for (uint32_t i = BytesPerPixel; i < row_size; i++) { - dest_buf[i] += dest_buf[i - BytesPerPixel]; - } - } -} - -bool TIFF_Predictor(uint8_t*& data_buf, - uint32_t& data_size, - int Colors, - int BitsPerComponent, - int Columns) { - int row_size = (Colors * BitsPerComponent * Columns + 7) / 8; - if (row_size == 0) - return false; - const int row_count = (data_size + row_size - 1) / row_size; - const int last_row_size = data_size % row_size; - for (int row = 0; row < row_count; row++) { - uint8_t* scan_line = data_buf + row * row_size; - if ((row + 1) * row_size > (int)data_size) { - row_size = last_row_size; - } - TIFF_PredictLine(scan_line, row_size, BitsPerComponent, Colors, Columns); - } - return true; -} - -void FlateUncompress(pdfium::span src_buf, - uint32_t orig_size, - uint8_t*& dest_buf, - uint32_t& dest_size, - uint32_t& offset) { - dest_buf = nullptr; - dest_size = 0; - - std::unique_ptr context(FlateInit()); - if (!context) - return; - - FlateInput(context.get(), src_buf); - - const uint32_t kMaxInitialAllocSize = 10000000; - uint32_t guess_size = orig_size ? orig_size : src_buf.size() * 2; - guess_size = std::min(guess_size, kMaxInitialAllocSize); - - uint32_t buf_size = guess_size; - uint32_t last_buf_size = buf_size; - std::unique_ptr guess_buf( - FX_Alloc(uint8_t, guess_size + 1)); - guess_buf.get()[guess_size] = '\0'; - - std::vector result_tmp_bufs; - uint8_t* cur_buf = guess_buf.release(); - while (1) { - uint32_t ret = FlateOutput(context.get(), cur_buf, buf_size); - uint32_t avail_buf_size = FlateGetAvailOut(context.get()); - if (ret != Z_OK || avail_buf_size != 0) { - last_buf_size = buf_size - avail_buf_size; - result_tmp_bufs.push_back(cur_buf); - break; - } - result_tmp_bufs.push_back(cur_buf); - cur_buf = FX_Alloc(uint8_t, buf_size + 1); - cur_buf[buf_size] = '\0'; - } - - // The TotalOut size returned from the library may not be big enough to - // handle the content the library returns. We can only handle items - // up to 4GB in size. - dest_size = FlateGetPossiblyTruncatedTotalOut(context.get()); - offset = FlateGetPossiblyTruncatedTotalIn(context.get()); - if (result_tmp_bufs.size() == 1) { - dest_buf = result_tmp_bufs[0]; - return; - } - - uint8_t* result_buf = FX_Alloc(uint8_t, dest_size); - uint32_t result_pos = 0; - uint32_t remaining = dest_size; - for (size_t i = 0; i < result_tmp_bufs.size(); i++) { - uint8_t* tmp_buf = result_tmp_bufs[i]; - uint32_t tmp_buf_size = buf_size; - if (i == result_tmp_bufs.size() - 1) - tmp_buf_size = last_buf_size; - - uint32_t cp_size = std::min(tmp_buf_size, remaining); - memcpy(result_buf + result_pos, tmp_buf, cp_size); - result_pos += cp_size; - remaining -= cp_size; - - FX_Free(result_tmp_bufs[i]); - } - dest_buf = result_buf; -} - -enum class PredictorType : uint8_t { kNone, kFlate, kPng }; -static PredictorType GetPredictor(int predictor) { - if (predictor >= 10) - return PredictorType::kPng; - if (predictor == 2) - return PredictorType::kFlate; - return PredictorType::kNone; -} - -class CCodec_FlateScanlineDecoder : public CCodec_ScanlineDecoder { - public: - CCodec_FlateScanlineDecoder(const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - int nComps, - int bpc); - ~CCodec_FlateScanlineDecoder() override; - - // CCodec_ScanlineDecoder: - bool v_Rewind() override; - uint8_t* v_GetNextLine() override; - uint32_t GetSrcOffset() override; - - protected: - std::unique_ptr m_pFlate; - pdfium::span const m_SrcBuf; - std::unique_ptr const m_pScanline; -}; - -CCodec_FlateScanlineDecoder::CCodec_FlateScanlineDecoder(const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - int nComps, - int bpc) - : CCodec_ScanlineDecoder(width, - height, - width, - height, - nComps, - bpc, - CalculatePitch8(bpc, nComps, width).ValueOrDie()), - m_SrcBuf(src_buf, src_size), - m_pScanline(FX_Alloc(uint8_t, m_Pitch)) {} - -CCodec_FlateScanlineDecoder::~CCodec_FlateScanlineDecoder() = default; - -bool CCodec_FlateScanlineDecoder::v_Rewind() { - m_pFlate.reset(FlateInit()); - if (!m_pFlate) - return false; - - FlateInput(m_pFlate.get(), m_SrcBuf); - return true; -} - -uint8_t* CCodec_FlateScanlineDecoder::v_GetNextLine() { - FlateOutput(m_pFlate.get(), m_pScanline.get(), m_Pitch); - return m_pScanline.get(); -} - -uint32_t CCodec_FlateScanlineDecoder::GetSrcOffset() { - return FlateGetPossiblyTruncatedTotalIn(m_pFlate.get()); -} - -class CCodec_FlatePredictorScanlineDecoder final - : public CCodec_FlateScanlineDecoder { - public: - CCodec_FlatePredictorScanlineDecoder(const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - int comps, - int bpc, - PredictorType predictor, - int Colors, - int BitsPerComponent, - int Columns); - ~CCodec_FlatePredictorScanlineDecoder() override; - - // CCodec_ScanlineDecoder: - bool v_Rewind() override; - uint8_t* v_GetNextLine() override; - - protected: - void GetNextLineWithPredictedPitch(); - void GetNextLineWithoutPredictedPitch(); - - const PredictorType m_Predictor; - int m_Colors = 0; - int m_BitsPerComponent = 0; - int m_Columns = 0; - uint32_t m_PredictPitch = 0; - size_t m_LeftOver = 0; - uint8_t* m_pLastLine = nullptr; - uint8_t* m_pPredictBuffer = nullptr; - uint8_t* m_pPredictRaw = nullptr; -}; - -CCodec_FlatePredictorScanlineDecoder::CCodec_FlatePredictorScanlineDecoder( - const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - int comps, - int bpc, - PredictorType predictor, - int Colors, - int BitsPerComponent, - int Columns) - : CCodec_FlateScanlineDecoder(src_buf, src_size, width, height, comps, bpc), - m_Predictor(predictor) { - ASSERT(m_Predictor != PredictorType::kNone); - if (BitsPerComponent * Colors * Columns == 0) { - BitsPerComponent = m_bpc; - Colors = m_nComps; - Columns = m_OrigWidth; - } - m_Colors = Colors; - m_BitsPerComponent = BitsPerComponent; - m_Columns = Columns; - m_PredictPitch = - CalculatePitch8(m_BitsPerComponent, m_Colors, m_Columns).ValueOrDie(); - m_pLastLine = FX_Alloc(uint8_t, m_PredictPitch); - m_pPredictBuffer = FX_Alloc(uint8_t, m_PredictPitch); - m_pPredictRaw = FX_Alloc(uint8_t, m_PredictPitch + 1); -} - -CCodec_FlatePredictorScanlineDecoder::~CCodec_FlatePredictorScanlineDecoder() { - FX_Free(m_pLastLine); - FX_Free(m_pPredictBuffer); - FX_Free(m_pPredictRaw); -} - -bool CCodec_FlatePredictorScanlineDecoder::v_Rewind() { - if (!CCodec_FlateScanlineDecoder::v_Rewind()) - return false; - - m_LeftOver = 0; - return true; -} - -uint8_t* CCodec_FlatePredictorScanlineDecoder::v_GetNextLine() { - if (m_Pitch == m_PredictPitch) - GetNextLineWithPredictedPitch(); - else - GetNextLineWithoutPredictedPitch(); - return m_pScanline.get(); -} - -void CCodec_FlatePredictorScanlineDecoder::GetNextLineWithPredictedPitch() { - switch (m_Predictor) { - case PredictorType::kPng: - FlateOutput(m_pFlate.get(), m_pPredictRaw, m_PredictPitch + 1); - PNG_PredictLine(m_pScanline.get(), m_pPredictRaw, m_pLastLine, - m_BitsPerComponent, m_Colors, m_Columns); - memcpy(m_pLastLine, m_pScanline.get(), m_PredictPitch); - break; - case PredictorType::kFlate: - FlateOutput(m_pFlate.get(), m_pScanline.get(), m_Pitch); - TIFF_PredictLine(m_pScanline.get(), m_PredictPitch, m_bpc, m_nComps, - m_OutputWidth); - break; - default: - NOTREACHED(); - break; - } -} - -void CCodec_FlatePredictorScanlineDecoder::GetNextLineWithoutPredictedPitch() { - size_t bytes_to_go = m_Pitch; - size_t read_leftover = m_LeftOver > bytes_to_go ? bytes_to_go : m_LeftOver; - if (read_leftover) { - memcpy(m_pScanline.get(), m_pPredictBuffer + m_PredictPitch - m_LeftOver, - read_leftover); - m_LeftOver -= read_leftover; - bytes_to_go -= read_leftover; - } - while (bytes_to_go) { - switch (m_Predictor) { - case PredictorType::kPng: - FlateOutput(m_pFlate.get(), m_pPredictRaw, m_PredictPitch + 1); - PNG_PredictLine(m_pPredictBuffer, m_pPredictRaw, m_pLastLine, - m_BitsPerComponent, m_Colors, m_Columns); - memcpy(m_pLastLine, m_pPredictBuffer, m_PredictPitch); - break; - case PredictorType::kFlate: - FlateOutput(m_pFlate.get(), m_pPredictBuffer, m_PredictPitch); - TIFF_PredictLine(m_pPredictBuffer, m_PredictPitch, m_BitsPerComponent, - m_Colors, m_Columns); - break; - default: - NOTREACHED(); - break; - } - size_t read_bytes = - m_PredictPitch > bytes_to_go ? bytes_to_go : m_PredictPitch; - memcpy(m_pScanline.get() + m_Pitch - bytes_to_go, m_pPredictBuffer, - read_bytes); - m_LeftOver += m_PredictPitch - read_bytes; - bytes_to_go -= read_bytes; - } -} - -} // namespace - -std::unique_ptr CCodec_FlateModule::CreateDecoder( - const uint8_t* src_buf, - uint32_t src_size, - int width, - int height, - int nComps, - int bpc, - int predictor, - int Colors, - int BitsPerComponent, - int Columns) { - PredictorType predictor_type = GetPredictor(predictor); - if (predictor_type == PredictorType::kNone) { - return pdfium::MakeUnique( - src_buf, src_size, width, height, nComps, bpc); - } - return pdfium::MakeUnique( - src_buf, src_size, width, height, nComps, bpc, predictor_type, Colors, - BitsPerComponent, Columns); -} - -uint32_t CCodec_FlateModule::FlateOrLZWDecode(bool bLZW, - const uint8_t* src_buf, - uint32_t src_size, - bool bEarlyChange, - int predictor, - int Colors, - int BitsPerComponent, - int Columns, - uint32_t estimated_size, - uint8_t** dest_buf, - uint32_t* dest_size) { - *dest_buf = nullptr; - uint32_t offset = 0; - PredictorType predictor_type = GetPredictor(predictor); - - if (bLZW) { - auto decoder = pdfium::MakeUnique(); - *dest_size = 0xFFFFFFFF; - offset = src_size; - int err = - decoder->Decode(nullptr, *dest_size, src_buf, offset, bEarlyChange); - if (err || *dest_size == 0 || *dest_size + 1 < *dest_size) - return FX_INVALID_OFFSET; - - decoder = pdfium::MakeUnique(); - *dest_buf = FX_Alloc(uint8_t, *dest_size + 1); - (*dest_buf)[*dest_size] = '\0'; - decoder->Decode(*dest_buf, *dest_size, src_buf, offset, bEarlyChange); - } else { - FlateUncompress(pdfium::make_span(src_buf, src_size), estimated_size, - *dest_buf, *dest_size, offset); - } - - bool ret = false; - switch (predictor_type) { - case PredictorType::kNone: - return offset; - case PredictorType::kPng: - ret = PNG_Predictor(*dest_buf, *dest_size, Colors, BitsPerComponent, - Columns); - break; - case PredictorType::kFlate: - ret = TIFF_Predictor(*dest_buf, *dest_size, Colors, BitsPerComponent, - Columns); - break; - default: - NOTREACHED(); - break; - } - return ret ? offset : FX_INVALID_OFFSET; -} - -bool CCodec_FlateModule::Encode(const uint8_t* src_buf, - uint32_t src_size, - uint8_t** dest_buf, - uint32_t* dest_size) { - *dest_size = src_size + src_size / 1000 + 12; - *dest_buf = FX_Alloc(uint8_t, *dest_size); - unsigned long temp_size = *dest_size; - if (!FlateCompress(*dest_buf, &temp_size, src_buf, src_size)) - return false; - - *dest_size = (uint32_t)temp_size; - return true; -} diff --git a/core/fxcodec/codec/fx_codec_icc.cpp b/core/fxcodec/codec/fx_codec_icc.cpp deleted file mode 100644 index 7ae93e59b4..0000000000 --- a/core/fxcodec/codec/fx_codec_icc.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2014 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 -#include -#include - -#include "core/fxcodec/codec/ccodec_iccmodule.h" -#include "core/fxcodec/codec/codec_int.h" - -namespace { - -// For use with std::unique_ptr. -struct CmsProfileDeleter { - inline void operator()(cmsHPROFILE p) { cmsCloseProfile(p); } -}; - -using ScopedCmsProfile = std::unique_ptr; - -bool Check3Components(cmsColorSpaceSignature cs) { - switch (cs) { - case cmsSigGrayData: - case cmsSigCmykData: - return false; - default: - return true; - } -} - -} // namespace - -CLcmsCmm::CLcmsCmm(cmsHTRANSFORM hTransform, - int srcComponents, - bool bIsLab, - bool bNormal) - : m_hTransform(hTransform), - m_nSrcComponents(srcComponents), - m_bLab(bIsLab), - m_bNormal(bNormal) {} - -CLcmsCmm::~CLcmsCmm() { - cmsDeleteTransform(m_hTransform); -} - -CCodec_IccModule::CCodec_IccModule() {} - -CCodec_IccModule::~CCodec_IccModule() {} - -std::unique_ptr CCodec_IccModule::CreateTransform_sRGB( - pdfium::span span) { - ScopedCmsProfile srcProfile(cmsOpenProfileFromMem(span.data(), span.size())); - if (!srcProfile) - return nullptr; - - ScopedCmsProfile dstProfile(cmsCreate_sRGBProfile()); - if (!dstProfile) - return nullptr; - - cmsColorSpaceSignature srcCS = cmsGetColorSpace(srcProfile.get()); - - uint32_t nSrcComponents = cmsChannelsOf(srcCS); - // According to PDF spec, number of components must be 1, 3, or 4. - if (nSrcComponents != 1 && nSrcComponents != 3 && nSrcComponents != 4) - return nullptr; - - int srcFormat; - bool bLab = false; - bool bNormal = false; - if (srcCS == cmsSigLabData) { - srcFormat = - COLORSPACE_SH(PT_Lab) | CHANNELS_SH(nSrcComponents) | BYTES_SH(0); - bLab = true; - } else { - srcFormat = - COLORSPACE_SH(PT_ANY) | CHANNELS_SH(nSrcComponents) | BYTES_SH(1); - // TODO(thestig): Check to see if lcms2 supports more colorspaces that can - // be considered normal. - bNormal = srcCS == cmsSigGrayData || srcCS == cmsSigRgbData || - srcCS == cmsSigCmykData; - } - cmsColorSpaceSignature dstCS = cmsGetColorSpace(dstProfile.get()); - if (!Check3Components(dstCS)) - return nullptr; - - cmsHTRANSFORM hTransform = nullptr; - const int intent = 0; - switch (dstCS) { - case cmsSigRgbData: - hTransform = cmsCreateTransform(srcProfile.get(), srcFormat, - dstProfile.get(), TYPE_BGR_8, intent, 0); - break; - case cmsSigGrayData: - case cmsSigCmykData: - // Check3Components() already filtered these types. - NOTREACHED(); - break; - default: - break; - } - if (!hTransform) - return nullptr; - - return pdfium::MakeUnique(hTransform, nSrcComponents, bLab, - bNormal); -} - -void CCodec_IccModule::Translate(CLcmsCmm* pTransform, - const float* pSrcValues, - float* pDestValues) { - if (!pTransform) - return; - - uint32_t nSrcComponents = m_nComponents; - uint8_t output[4]; - // TODO(npm): Currently the CmsDoTransform method is part of LCMS and it will - // apply some member of m_hTransform to the input. We need to go over all the - // places which set transform to verify that only nSrcComponents are used. - if (pTransform->IsLab()) { - std::vector inputs(std::max(nSrcComponents, 16u)); - for (uint32_t i = 0; i < nSrcComponents; ++i) - inputs[i] = pSrcValues[i]; - cmsDoTransform(pTransform->transform(), inputs.data(), output, 1); - } else { - std::vector inputs(std::max(nSrcComponents, 16u)); - for (uint32_t i = 0; i < nSrcComponents; ++i) { - inputs[i] = - pdfium::clamp(static_cast(pSrcValues[i] * 255.0f), 0, 255); - } - cmsDoTransform(pTransform->transform(), inputs.data(), output, 1); - } - pDestValues[0] = output[2] / 255.0f; - pDestValues[1] = output[1] / 255.0f; - pDestValues[2] = output[0] / 255.0f; -} - -void CCodec_IccModule::TranslateScanline(CLcmsCmm* pTransform, - unsigned char* pDest, - const unsigned char* pSrc, - int32_t pixels) { - if (pTransform) - cmsDoTransform(pTransform->transform(), pSrc, pDest, pixels); -} diff --git a/core/fxcodec/codec/fx_codec_jbig.cpp b/core/fxcodec/codec/fx_codec_jbig.cpp deleted file mode 100644 index 36d6a0609e..0000000000 --- a/core/fxcodec/codec/fx_codec_jbig.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2014 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/codec/ccodec_jbig2module.h" - -#include -#include - -#include "core/fpdfapi/parser/cpdf_stream_acc.h" -#include "core/fxcodec/JBig2_DocumentContext.h" -#include "core/fxcodec/jbig2/JBig2_Context.h" -#include "core/fxcodec/jbig2/JBig2_Image.h" -#include "core/fxcrt/fx_memory.h" -#include "third_party/base/ptr_util.h" - -JBig2_DocumentContext::JBig2_DocumentContext() {} - -JBig2_DocumentContext::~JBig2_DocumentContext() {} - -JBig2_DocumentContext* GetJBig2DocumentContext( - std::unique_ptr* pContextHolder) { - if (!pContextHolder->get()) - *pContextHolder = pdfium::MakeUnique(); - return pContextHolder->get(); -} - -CCodec_Jbig2Context::CCodec_Jbig2Context() - : m_width(0), - m_height(0), - m_pGlobalStream(nullptr), - m_pSrcStream(nullptr), - m_dest_buf(0), - m_dest_pitch(0) {} - -CCodec_Jbig2Context::~CCodec_Jbig2Context() {} - -CCodec_Jbig2Module::~CCodec_Jbig2Module() {} - -FXCODEC_STATUS CCodec_Jbig2Module::StartDecode( - CCodec_Jbig2Context* pJbig2Context, - std::unique_ptr* pContextHolder, - uint32_t width, - uint32_t height, - const RetainPtr& src_stream, - const RetainPtr& global_stream, - uint8_t* dest_buf, - uint32_t dest_pitch, - PauseIndicatorIface* pPause) { - if (!pJbig2Context) - return FXCODEC_STATUS_ERR_PARAMS; - - JBig2_DocumentContext* pJBig2DocumentContext = - GetJBig2DocumentContext(pContextHolder); - pJbig2Context->m_width = width; - pJbig2Context->m_height = height; - pJbig2Context->m_pSrcStream = src_stream; - pJbig2Context->m_pGlobalStream = global_stream; - pJbig2Context->m_dest_buf = dest_buf; - pJbig2Context->m_dest_pitch = dest_pitch; - memset(dest_buf, 0, height * dest_pitch); - pJbig2Context->m_pContext = pdfium::MakeUnique( - global_stream, src_stream, pJBig2DocumentContext->GetSymbolDictCache(), - false); - bool succeeded = pJbig2Context->m_pContext->GetFirstPage( - dest_buf, width, height, dest_pitch, pPause); - return Decode(pJbig2Context, succeeded); -} - -FXCODEC_STATUS CCodec_Jbig2Module::ContinueDecode( - CCodec_Jbig2Context* pJbig2Context, - PauseIndicatorIface* pPause) { - bool succeeded = pJbig2Context->m_pContext->Continue(pPause); - return Decode(pJbig2Context, succeeded); -} - -FXCODEC_STATUS CCodec_Jbig2Module::Decode(CCodec_Jbig2Context* pJbig2Context, - bool decode_success) { - FXCODEC_STATUS status = pJbig2Context->m_pContext->GetProcessingStatus(); - if (status != FXCODEC_STATUS_DECODE_FINISH) - return status; - - pJbig2Context->m_pContext.reset(); - if (!decode_success) - return FXCODEC_STATUS_ERROR; - - int dword_size = pJbig2Context->m_height * pJbig2Context->m_dest_pitch / 4; - uint32_t* dword_buf = reinterpret_cast(pJbig2Context->m_dest_buf); - for (int i = 0; i < dword_size; i++) - dword_buf[i] = ~dword_buf[i]; - return FXCODEC_STATUS_DECODE_FINISH; -} diff --git a/core/fxcodec/codec/fx_codec_jpx_opj.cpp b/core/fxcodec/codec/fx_codec_jpx_opj.cpp deleted file mode 100644 index 3e44b19a9d..0000000000 --- a/core/fxcodec/codec/fx_codec_jpx_opj.cpp +++ /dev/null @@ -1,667 +0,0 @@ -// Copyright 2014 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 -#include -#include -#include -#include - -#include "core/fpdfapi/page/cpdf_colorspace.h" -#include "core/fxcodec/codec/ccodec_jpxmodule.h" -#include "core/fxcodec/codec/cjpx_decoder.h" -#include "core/fxcrt/fx_memory.h" -#include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/ptr_util.h" -#include "third_party/libopenjpeg20/openjpeg.h" -#include "third_party/libopenjpeg20/opj_malloc.h" - -namespace { - -void fx_ignore_callback(const char* msg, void* client_data) {} - -opj_stream_t* fx_opj_stream_create_memory_stream(DecodeData* data, - OPJ_SIZE_T p_size, - OPJ_BOOL p_is_read_stream) { - if (!data || !data->src_data || data->src_size <= 0) - return nullptr; - - opj_stream_t* stream = opj_stream_create(p_size, p_is_read_stream); - if (!stream) - return nullptr; - - opj_stream_set_user_data(stream, data, nullptr); - opj_stream_set_user_data_length(stream, data->src_size); - opj_stream_set_read_function(stream, opj_read_from_memory); - opj_stream_set_skip_function(stream, opj_skip_from_memory); - opj_stream_set_seek_function(stream, opj_seek_from_memory); - return stream; -} - -bool alloc_rgb(int** out_r, int** out_g, int** out_b, size_t size) { - int* r = static_cast(opj_image_data_alloc(size)); - if (!r) - return false; - - int* g = static_cast(opj_image_data_alloc(size)); - if (!g) { - opj_image_data_free(r); - return false; - } - - int* b = static_cast(opj_image_data_alloc(size)); - if (!b) { - opj_image_data_free(r); - opj_image_data_free(g); - return false; - } - - *out_r = r; - *out_g = g; - *out_b = b; - return true; -} - -void sycc_to_rgb(int offset, - int upb, - int y, - int cb, - int cr, - int* out_r, - int* out_g, - int* out_b) { - cb -= offset; - cr -= offset; - *out_r = pdfium::clamp(y + static_cast(1.402 * cr), 0, upb); - *out_g = pdfium::clamp(y - static_cast(0.344 * cb + 0.714 * cr), 0, upb); - *out_b = pdfium::clamp(y + static_cast(1.772 * cb), 0, upb); -} - -void sycc444_to_rgb(opj_image_t* img) { - int prec = img->comps[0].prec; - // If we shift 31 we're going to go negative, then things go bad. - if (prec > 30) - return; - int offset = 1 << (prec - 1); - int upb = (1 << prec) - 1; - OPJ_UINT32 maxw = - std::min({img->comps[0].w, img->comps[1].w, img->comps[2].w}); - OPJ_UINT32 maxh = - std::min({img->comps[0].h, img->comps[1].h, img->comps[2].h}); - FX_SAFE_SIZE_T max_size = maxw; - max_size *= maxh; - max_size *= sizeof(int); - if (!max_size.IsValid()) - return; - - const int* y = img->comps[0].data; - const int* cb = img->comps[1].data; - const int* cr = img->comps[2].data; - if (!y || !cb || !cr) - return; - - int* r; - int* g; - int* b; - if (!alloc_rgb(&r, &g, &b, max_size.ValueOrDie())) - return; - - int* d0 = r; - int* d1 = g; - int* d2 = b; - max_size /= sizeof(int); - for (size_t i = 0; i < max_size.ValueOrDie(); ++i) { - sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++); - } - opj_image_data_free(img->comps[0].data); - opj_image_data_free(img->comps[1].data); - opj_image_data_free(img->comps[2].data); - img->comps[0].data = d0; - img->comps[1].data = d1; - img->comps[2].data = d2; -} - -bool sycc420_422_size_is_valid(opj_image_t* img) { - return img && img->comps[0].w != std::numeric_limits::max() && - (img->comps[0].w + 1) / 2 == img->comps[1].w && - img->comps[1].w == img->comps[2].w && - img->comps[1].h == img->comps[2].h; -} - -bool sycc420_size_is_valid(opj_image_t* img) { - return sycc420_422_size_is_valid(img) && - img->comps[0].h != std::numeric_limits::max() && - (img->comps[0].h + 1) / 2 == img->comps[1].h; -} - -bool sycc422_size_is_valid(opj_image_t* img) { - return sycc420_422_size_is_valid(img) && img->comps[0].h == img->comps[1].h; -} - -void sycc422_to_rgb(opj_image_t* img) { - if (!sycc422_size_is_valid(img)) - return; - - int prec = img->comps[0].prec; - if (prec <= 0 || prec >= 32) - return; - - int offset = 1 << (prec - 1); - int upb = (1 << prec) - 1; - OPJ_UINT32 maxw = img->comps[0].w; - OPJ_UINT32 maxh = img->comps[0].h; - FX_SAFE_SIZE_T max_size = maxw; - max_size *= maxh; - max_size *= sizeof(int); - if (!max_size.IsValid()) - return; - - const int* y = img->comps[0].data; - const int* cb = img->comps[1].data; - const int* cr = img->comps[2].data; - if (!y || !cb || !cr) - return; - - int* r; - int* g; - int* b; - if (!alloc_rgb(&r, &g, &b, max_size.ValueOrDie())) - return; - - int* d0 = r; - int* d1 = g; - int* d2 = b; - for (uint32_t i = 0; i < maxh; ++i) { - OPJ_UINT32 j; - for (j = 0; j < (maxw & ~static_cast(1)); j += 2) { - sycc_to_rgb(offset, upb, *y++, *cb, *cr, r++, g++, b++); - sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++); - } - if (j < maxw) { - sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++); - } - } - opj_image_data_free(img->comps[0].data); - opj_image_data_free(img->comps[1].data); - opj_image_data_free(img->comps[2].data); - img->comps[0].data = d0; - img->comps[1].data = d1; - img->comps[2].data = d2; - img->comps[1].w = maxw; - img->comps[1].h = maxh; - img->comps[2].w = maxw; - img->comps[2].h = maxh; - img->comps[1].dx = img->comps[0].dx; - img->comps[2].dx = img->comps[0].dx; - img->comps[1].dy = img->comps[0].dy; - img->comps[2].dy = img->comps[0].dy; -} - -bool sycc420_must_extend_cbcr(OPJ_UINT32 y, OPJ_UINT32 cbcr) { - return (y & 1) && (cbcr == y / 2); -} - -bool is_sycc420(const opj_image_t* img) { - return img->comps[0].dx == 1 && img->comps[0].dy == 1 && - img->comps[1].dx == 2 && img->comps[1].dy == 2 && - img->comps[2].dx == 2 && img->comps[2].dy == 2; -} - -bool is_sycc422(const opj_image_t* img) { - return img->comps[0].dx == 1 && img->comps[0].dy == 1 && - img->comps[1].dx == 2 && img->comps[1].dy == 1 && - img->comps[2].dx == 2 && img->comps[2].dy == 1; -} - -bool is_sycc444(const opj_image_t* img) { - return img->comps[0].dx == 1 && img->comps[0].dy == 1 && - img->comps[1].dx == 1 && img->comps[1].dy == 1 && - img->comps[2].dx == 1 && img->comps[2].dy == 1; -} - -void color_sycc_to_rgb(opj_image_t* img) { - if (img->numcomps < 3) { - img->color_space = OPJ_CLRSPC_GRAY; - return; - } - if (is_sycc420(img)) - sycc420_to_rgb(img); - else if (is_sycc422(img)) - sycc422_to_rgb(img); - else if (is_sycc444(img)) - sycc444_to_rgb(img); - else - return; - - img->color_space = OPJ_CLRSPC_SRGB; -} - -} // namespace - -OPJ_SIZE_T opj_read_from_memory(void* p_buffer, - OPJ_SIZE_T nb_bytes, - void* p_user_data) { - DecodeData* srcData = static_cast(p_user_data); - if (!srcData || !srcData->src_data || srcData->src_size == 0) - return static_cast(-1); - - // Reads at EOF return an error code. - if (srcData->offset >= srcData->src_size) - return static_cast(-1); - - OPJ_SIZE_T bufferLength = srcData->src_size - srcData->offset; - OPJ_SIZE_T readlength = nb_bytes < bufferLength ? nb_bytes : bufferLength; - memcpy(p_buffer, &srcData->src_data[srcData->offset], readlength); - srcData->offset += readlength; - return readlength; -} - -OPJ_OFF_T opj_skip_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) { - DecodeData* srcData = static_cast(p_user_data); - if (!srcData || !srcData->src_data || srcData->src_size == 0) - return static_cast(-1); - - // Offsets are signed and may indicate a negative skip. Do not support this - // because of the strange return convention where either bytes skipped or - // -1 is returned. Following that convention, a successful relative seek of - // -1 bytes would be required to to give the same result as the error case. - if (nb_bytes < 0) - return static_cast(-1); - - // FIXME: use std::make_unsigned::type once c++11 lib is OK'd. - uint64_t unsignedNbBytes = static_cast(nb_bytes); - // Additionally, the offset may take us beyond the range of a size_t (e.g. - // 32-bit platforms). If so, just clamp at EOF. - if (unsignedNbBytes > - std::numeric_limits::max() - srcData->offset) { - srcData->offset = srcData->src_size; - } else { - OPJ_SIZE_T checkedNbBytes = static_cast(unsignedNbBytes); - // Otherwise, mimic fseek() semantics to always succeed, even past EOF, - // clamping at EOF. We can get away with this since we don't actually - // provide negative relative skips from beyond EOF back to inside the - // data, which would be the only reason to need to know exactly how far - // beyond EOF we are. - srcData->offset = - std::min(srcData->offset + checkedNbBytes, srcData->src_size); - } - return nb_bytes; -} - -OPJ_BOOL opj_seek_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) { - DecodeData* srcData = static_cast(p_user_data); - if (!srcData || !srcData->src_data || srcData->src_size == 0) - return OPJ_FALSE; - - // Offsets are signed and may indicate a negative position, which would - // be before the start of the file. Do not support this. - if (nb_bytes < 0) - return OPJ_FALSE; - - // FIXME: use std::make_unsigned::type once c++11 lib is OK'd. - uint64_t unsignedNbBytes = static_cast(nb_bytes); - // Additionally, the offset may take us beyond the range of a size_t (e.g. - // 32-bit platforms). If so, just clamp at EOF. - if (unsignedNbBytes > std::numeric_limits::max()) { - srcData->offset = srcData->src_size; - } else { - OPJ_SIZE_T checkedNbBytes = static_cast(nb_bytes); - // Otherwise, mimic fseek() semantics to always succeed, even past EOF, - // again clamping at EOF. - srcData->offset = std::min(checkedNbBytes, srcData->src_size); - } - return OPJ_TRUE; -} - -void sycc420_to_rgb(opj_image_t* img) { - if (!sycc420_size_is_valid(img)) - return; - - OPJ_UINT32 prec = img->comps[0].prec; - if (!prec) - return; - - OPJ_UINT32 offset = 1 << (prec - 1); - OPJ_UINT32 upb = (1 << prec) - 1; - OPJ_UINT32 yw = img->comps[0].w; - OPJ_UINT32 yh = img->comps[0].h; - OPJ_UINT32 cbw = img->comps[1].w; - OPJ_UINT32 cbh = img->comps[1].h; - OPJ_UINT32 crw = img->comps[2].w; - bool extw = sycc420_must_extend_cbcr(yw, cbw); - bool exth = sycc420_must_extend_cbcr(yh, cbh); - FX_SAFE_UINT32 safeSize = yw; - safeSize *= yh; - safeSize *= sizeof(int); - if (!safeSize.IsValid()) - return; - - int* r; - int* g; - int* b; - if (!alloc_rgb(&r, &g, &b, safeSize.ValueOrDie())) - return; - - int* d0 = r; - int* d1 = g; - int* d2 = b; - const int* y = img->comps[0].data; - const int* cb = img->comps[1].data; - const int* cr = img->comps[2].data; - if (!y || !cb || !cr) - return; - - const int* ny = nullptr; - int* nr = nullptr; - int* ng = nullptr; - int* nb = nullptr; - OPJ_UINT32 i = 0; - OPJ_UINT32 j = 0; - for (i = 0; i < (yh & ~(OPJ_UINT32)1); i += 2) { - ny = y + yw; - nr = r + yw; - ng = g + yw; - nb = b + yw; - for (j = 0; j < (yw & ~(OPJ_UINT32)1); j += 2) { - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - ++y; - ++r; - ++g; - ++b; - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - ++y; - ++r; - ++g; - ++b; - sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); - ++ny; - ++nr; - ++ng; - ++nb; - sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); - ++ny; - ++nr; - ++ng; - ++nb; - ++cb; - ++cr; - } - if (j < yw) { - if (extw) { - --cb; - --cr; - } - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - ++y; - ++r; - ++g; - ++b; - sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); - ++ny; - ++nr; - ++ng; - ++nb; - ++cb; - ++cr; - } - y += yw; - r += yw; - g += yw; - b += yw; - } - if (i < yh) { - if (exth) { - cb -= cbw; - cr -= crw; - } - for (j = 0; j < (yw & ~(OPJ_UINT32)1); j += 2) { - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - ++y; - ++r; - ++g; - ++b; - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - ++y; - ++r; - ++g; - ++b; - ++cb; - ++cr; - } - if (j < yw) { - if (extw) { - --cb; - --cr; - } - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - } - } - - opj_image_data_free(img->comps[0].data); - opj_image_data_free(img->comps[1].data); - opj_image_data_free(img->comps[2].data); - img->comps[0].data = d0; - img->comps[1].data = d1; - img->comps[2].data = d2; - img->comps[1].w = yw; - img->comps[1].h = yh; - img->comps[2].w = yw; - img->comps[2].h = yh; - img->comps[1].dx = img->comps[0].dx; - img->comps[2].dx = img->comps[0].dx; - img->comps[1].dy = img->comps[0].dy; - img->comps[2].dy = img->comps[0].dy; -} - -CJPX_Decoder::CJPX_Decoder(CPDF_ColorSpace* cs) - : m_Image(nullptr), - m_Codec(nullptr), - m_DecodeData(nullptr), - m_Stream(nullptr), - m_ColorSpace(cs) {} - -CJPX_Decoder::~CJPX_Decoder() { - if (m_Codec) - opj_destroy_codec(m_Codec.Release()); - if (m_Stream) - opj_stream_destroy(m_Stream.Release()); - if (m_Image) - opj_image_destroy(m_Image.Release()); -} - -bool CJPX_Decoder::Init(pdfium::span src_data) { - static const unsigned char szJP2Header[] = { - 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a}; - if (src_data.empty() || src_data.size() < sizeof(szJP2Header)) - return false; - - m_Image = nullptr; - m_SrcData = src_data; - m_DecodeData = - pdfium::MakeUnique(src_data.data(), src_data.size()); - m_Stream = fx_opj_stream_create_memory_stream( - m_DecodeData.get(), static_cast(OPJ_J2K_STREAM_CHUNK_SIZE), - 1); - if (!m_Stream) - return false; - - opj_set_default_decoder_parameters(&m_Parameters); - m_Parameters.decod_format = 0; - m_Parameters.cod_format = 3; - if (memcmp(m_SrcData.data(), szJP2Header, sizeof(szJP2Header)) == 0) { - m_Codec = opj_create_decompress(OPJ_CODEC_JP2); - m_Parameters.decod_format = 1; - } else { - m_Codec = opj_create_decompress(OPJ_CODEC_J2K); - } - if (!m_Codec) - return false; - - if (m_ColorSpace && m_ColorSpace->GetFamily() == PDFCS_INDEXED) - m_Parameters.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; - opj_set_info_handler(m_Codec.Get(), fx_ignore_callback, nullptr); - opj_set_warning_handler(m_Codec.Get(), fx_ignore_callback, nullptr); - opj_set_error_handler(m_Codec.Get(), fx_ignore_callback, nullptr); - if (!opj_setup_decoder(m_Codec.Get(), &m_Parameters)) - return false; - - m_Image = nullptr; - opj_image_t* pTempImage = nullptr; - if (!opj_read_header(m_Stream.Get(), m_Codec.Get(), &pTempImage)) - return false; - - m_Image = pTempImage; - m_Image->pdfium_use_colorspace = !!m_ColorSpace; - - if (!m_Parameters.nb_tile_to_decode) { - if (!opj_set_decode_area(m_Codec.Get(), m_Image.Get(), m_Parameters.DA_x0, - m_Parameters.DA_y0, m_Parameters.DA_x1, - m_Parameters.DA_y1)) { - opj_image_destroy(m_Image.Release()); - return false; - } - if (!(opj_decode(m_Codec.Get(), m_Stream.Get(), m_Image.Get()) && - opj_end_decompress(m_Codec.Get(), m_Stream.Get()))) { - opj_image_destroy(m_Image.Release()); - return false; - } - } else if (!opj_get_decoded_tile(m_Codec.Get(), m_Stream.Get(), m_Image.Get(), - m_Parameters.tile_index)) { - return false; - } - - opj_stream_destroy(m_Stream.Release()); - if (m_Image->color_space != OPJ_CLRSPC_SYCC && m_Image->numcomps == 3 && - m_Image->comps[0].dx == m_Image->comps[0].dy && - m_Image->comps[1].dx != 1) { - m_Image->color_space = OPJ_CLRSPC_SYCC; - } else if (m_Image->numcomps <= 2) { - m_Image->color_space = OPJ_CLRSPC_GRAY; - } - if (m_Image->color_space == OPJ_CLRSPC_SYCC) - color_sycc_to_rgb(m_Image.Get()); - - if (m_Image->icc_profile_buf) { - // TODO(palmer): Using |opj_free| here resolves the crash described in - // https://crbug.com/737033, but ultimately we need to harmonize the - // memory allocation strategy across OpenJPEG and its PDFium callers. - opj_free(m_Image->icc_profile_buf); - m_Image->icc_profile_buf = nullptr; - m_Image->icc_profile_len = 0; - } - - return true; -} - -void CJPX_Decoder::GetInfo(uint32_t* width, - uint32_t* height, - uint32_t* components) { - *width = m_Image->x1; - *height = m_Image->y1; - *components = m_Image->numcomps; -} - -bool CJPX_Decoder::Decode(uint8_t* dest_buf, - uint32_t pitch, - const std::vector& offsets) { - if (m_Image->comps[0].w != m_Image->x1 || m_Image->comps[0].h != m_Image->y1) - return false; - - if (pitch<(m_Image->comps[0].w * 8 * m_Image->numcomps + 31)>> 5 << 2) { - return false; - } - - memset(dest_buf, 0xff, m_Image->y1 * pitch); - std::vector channel_bufs(m_Image->numcomps); - std::vector adjust_comps(m_Image->numcomps); - for (uint32_t i = 0; i < m_Image->numcomps; i++) { - channel_bufs[i] = dest_buf + offsets[i]; - adjust_comps[i] = m_Image->comps[i].prec - 8; - if (i > 0) { - if (m_Image->comps[i].dx != m_Image->comps[i - 1].dx || - m_Image->comps[i].dy != m_Image->comps[i - 1].dy || - m_Image->comps[i].prec != m_Image->comps[i - 1].prec) { - return false; - } - } - } - uint32_t width = m_Image->comps[0].w; - uint32_t height = m_Image->comps[0].h; - for (uint32_t channel = 0; channel < m_Image->numcomps; ++channel) { - uint8_t* pChannel = channel_bufs[channel]; - if (adjust_comps[channel] < 0) { - for (uint32_t row = 0; row < height; ++row) { - uint8_t* pScanline = pChannel + row * pitch; - for (uint32_t col = 0; col < width; ++col) { - uint8_t* pPixel = pScanline + col * m_Image->numcomps; - if (!m_Image->comps[channel].data) - continue; - - int src = m_Image->comps[channel].data[row * width + col]; - src += m_Image->comps[channel].sgnd - ? 1 << (m_Image->comps[channel].prec - 1) - : 0; - if (adjust_comps[channel] > 0) { - *pPixel = 0; - } else { - *pPixel = static_cast(src << -adjust_comps[channel]); - } - } - } - } else { - for (uint32_t row = 0; row < height; ++row) { - uint8_t* pScanline = pChannel + row * pitch; - for (uint32_t col = 0; col < width; ++col) { - uint8_t* pPixel = pScanline + col * m_Image->numcomps; - if (!m_Image->comps[channel].data) - continue; - - int src = m_Image->comps[channel].data[row * width + col]; - src += m_Image->comps[channel].sgnd - ? 1 << (m_Image->comps[channel].prec - 1) - : 0; - if (adjust_comps[channel] - 1 < 0) { - *pPixel = static_cast((src >> adjust_comps[channel])); - } else { - int tmpPixel = (src >> adjust_comps[channel]) + - ((src >> (adjust_comps[channel] - 1)) % 2); - tmpPixel = pdfium::clamp(tmpPixel, 0, 255); - *pPixel = static_cast(tmpPixel); - } - } - } - } - } - return true; -} - -CCodec_JpxModule::CCodec_JpxModule() {} - -CCodec_JpxModule::~CCodec_JpxModule() {} - -std::unique_ptr CCodec_JpxModule::CreateDecoder( - const uint8_t* src_buf, - uint32_t src_size, - CPDF_ColorSpace* cs) { - auto decoder = pdfium::MakeUnique(cs); - return decoder->Init(pdfium::make_span(src_buf, src_size)) - ? std::move(decoder) - : nullptr; -} - -void CCodec_JpxModule::GetImageInfo(CJPX_Decoder* pDecoder, - uint32_t* width, - uint32_t* height, - uint32_t* components) { - pDecoder->GetInfo(width, height, components); -} - -bool CCodec_JpxModule::Decode(CJPX_Decoder* pDecoder, - uint8_t* dest_data, - uint32_t pitch, - const std::vector& offsets) { - return pDecoder->Decode(dest_data, pitch, offsets); -} -- cgit v1.2.3