| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| 6 | |
| 7 #include "core/include/fxcodec/fx_codec.h" | |
| 8 | |
| 9 #include <cmath> | |
| 10 #include <utility> | |
| 11 | |
| 12 #include "core/include/fxcrt/fx_ext.h" | |
| 13 #include "core/include/fxcrt/fx_safe_types.h" | |
| 14 #include "core/src/fxcodec/codec/codec_int.h" | |
| 15 #include "third_party/base/logging.h" | |
| 16 | |
| 17 CCodec_ModuleMgr::CCodec_ModuleMgr() | |
| 18 : m_pBasicModule(new CCodec_BasicModule), | |
| 19 m_pFaxModule(new CCodec_FaxModule), | |
| 20 m_pJpegModule(new CCodec_JpegModule), | |
| 21 m_pJpxModule(new CCodec_JpxModule), | |
| 22 m_pJbig2Module(new CCodec_Jbig2Module), | |
| 23 m_pIccModule(new CCodec_IccModule), | |
| 24 #ifdef PDF_ENABLE_XFA | |
| 25 m_pPngModule(new CCodec_PngModule), | |
| 26 m_pGifModule(new CCodec_GifModule), | |
| 27 m_pBmpModule(new CCodec_BmpModule), | |
| 28 m_pTiffModule(new CCodec_TiffModule), | |
| 29 #endif // PDF_ENABLE_XFA | |
| 30 m_pFlateModule(new CCodec_FlateModule) { | |
| 31 } | |
| 32 | |
| 33 CCodec_ScanlineDecoder::ImageDataCache::ImageDataCache(int width, | |
| 34 int height, | |
| 35 FX_DWORD pitch) | |
| 36 : m_Width(width), m_Height(height), m_Pitch(pitch), m_nCachedLines(0) {} | |
| 37 | |
| 38 CCodec_ScanlineDecoder::ImageDataCache::~ImageDataCache() { | |
| 39 } | |
| 40 | |
| 41 bool CCodec_ScanlineDecoder::ImageDataCache::AllocateCache() { | |
| 42 if (m_Pitch == 0 || m_Height < 0) | |
| 43 return false; | |
| 44 | |
| 45 FX_SAFE_SIZE_T size = m_Pitch; | |
| 46 size *= m_Height; | |
| 47 if (!size.IsValid()) | |
| 48 return false; | |
| 49 | |
| 50 m_Data.reset(FX_TryAlloc(uint8_t, size.ValueOrDie())); | |
| 51 return IsValid(); | |
| 52 } | |
| 53 | |
| 54 void CCodec_ScanlineDecoder::ImageDataCache::AppendLine(const uint8_t* line) { | |
| 55 // If the callers adds more lines than there is room, fail. | |
| 56 if (m_Pitch == 0 || m_nCachedLines >= m_Height) { | |
| 57 NOTREACHED(); | |
| 58 return; | |
| 59 } | |
| 60 | |
| 61 size_t offset = m_Pitch; | |
| 62 FXSYS_memcpy(m_Data.get() + offset * m_nCachedLines, line, m_Pitch); | |
| 63 ++m_nCachedLines; | |
| 64 } | |
| 65 | |
| 66 const uint8_t* CCodec_ScanlineDecoder::ImageDataCache::GetLine(int line) const { | |
| 67 if (m_Pitch == 0 || line < 0 || line >= m_nCachedLines) | |
| 68 return nullptr; | |
| 69 | |
| 70 size_t offset = m_Pitch; | |
| 71 return m_Data.get() + offset * line; | |
| 72 } | |
| 73 | |
| 74 CCodec_ScanlineDecoder::CCodec_ScanlineDecoder() | |
| 75 : m_NextLine(-1), m_pLastScanline(nullptr) { | |
| 76 } | |
| 77 | |
| 78 CCodec_ScanlineDecoder::~CCodec_ScanlineDecoder() { | |
| 79 } | |
| 80 | |
| 81 const uint8_t* CCodec_ScanlineDecoder::GetScanline(int line) { | |
| 82 if (m_pDataCache && line < m_pDataCache->NumLines()) | |
| 83 return m_pDataCache->GetLine(line); | |
| 84 | |
| 85 if (m_NextLine == line + 1) | |
| 86 return m_pLastScanline; | |
| 87 | |
| 88 if (m_NextLine < 0 || m_NextLine > line) { | |
| 89 if (!v_Rewind()) | |
| 90 return nullptr; | |
| 91 m_NextLine = 0; | |
| 92 } | |
| 93 while (m_NextLine < line) { | |
| 94 ReadNextLine(); | |
| 95 m_NextLine++; | |
| 96 } | |
| 97 m_pLastScanline = ReadNextLine(); | |
| 98 m_NextLine++; | |
| 99 return m_pLastScanline; | |
| 100 } | |
| 101 | |
| 102 FX_BOOL CCodec_ScanlineDecoder::SkipToScanline(int line, IFX_Pause* pPause) { | |
| 103 if (m_pDataCache && line < m_pDataCache->NumLines()) | |
| 104 return FALSE; | |
| 105 | |
| 106 if (m_NextLine == line || m_NextLine == line + 1) | |
| 107 return FALSE; | |
| 108 | |
| 109 if (m_NextLine < 0 || m_NextLine > line) { | |
| 110 v_Rewind(); | |
| 111 m_NextLine = 0; | |
| 112 } | |
| 113 m_pLastScanline = nullptr; | |
| 114 while (m_NextLine < line) { | |
| 115 m_pLastScanline = ReadNextLine(); | |
| 116 m_NextLine++; | |
| 117 if (pPause && pPause->NeedToPauseNow()) { | |
| 118 return TRUE; | |
| 119 } | |
| 120 } | |
| 121 return FALSE; | |
| 122 } | |
| 123 | |
| 124 uint8_t* CCodec_ScanlineDecoder::ReadNextLine() { | |
| 125 uint8_t* pLine = v_GetNextLine(); | |
| 126 if (!pLine) | |
| 127 return nullptr; | |
| 128 | |
| 129 if (m_pDataCache && m_NextLine == m_pDataCache->NumLines()) | |
| 130 m_pDataCache->AppendLine(pLine); | |
| 131 return pLine; | |
| 132 } | |
| 133 | |
| 134 void CCodec_ScanlineDecoder::DownScale(int dest_width, int dest_height) { | |
| 135 dest_width = std::abs(dest_width); | |
| 136 dest_height = std::abs(dest_height); | |
| 137 v_DownScale(dest_width, dest_height); | |
| 138 | |
| 139 if (m_pDataCache && | |
| 140 m_pDataCache->IsSameDimensions(m_OutputWidth, m_OutputHeight)) { | |
| 141 return; | |
| 142 } | |
| 143 | |
| 144 std::unique_ptr<ImageDataCache> cache( | |
| 145 new ImageDataCache(m_OutputWidth, m_OutputHeight, m_Pitch)); | |
| 146 if (!cache->AllocateCache()) | |
| 147 return; | |
| 148 | |
| 149 m_pDataCache = std::move(cache); | |
| 150 } | |
| 151 | |
| 152 FX_BOOL CCodec_BasicModule::RunLengthEncode(const uint8_t* src_buf, | |
| 153 FX_DWORD src_size, | |
| 154 uint8_t*& dest_buf, | |
| 155 FX_DWORD& dest_size) { | |
| 156 return FALSE; | |
| 157 } | |
| 158 | |
| 159 #define EXPONENT_DETECT(ptr) \ | |
| 160 for (;; ptr++) { \ | |
| 161 if (!std::isdigit(*ptr)) { \ | |
| 162 if (endptr) \ | |
| 163 *endptr = (char*)ptr; \ | |
| 164 break; \ | |
| 165 } else { \ | |
| 166 exp_ret *= 10; \ | |
| 167 exp_ret += FXSYS_toDecimalDigit(*ptr); \ | |
| 168 continue; \ | |
| 169 } \ | |
| 170 } | |
| 171 | |
| 172 extern "C" double FXstrtod(const char* nptr, char** endptr) { | |
| 173 double ret = 0.0; | |
| 174 const char* ptr = nptr; | |
| 175 const char* exp_ptr = NULL; | |
| 176 int e_number = 0, e_signal = 0, e_point = 0, is_negative = 0; | |
| 177 int exp_ret = 0, exp_sig = 1, fra_ret = 0, fra_count = 0, fra_base = 1; | |
| 178 if (!nptr) { | |
| 179 return 0.0; | |
| 180 } | |
| 181 for (;; ptr++) { | |
| 182 if (!e_number && !e_point && (*ptr == '\t' || *ptr == ' ')) | |
| 183 continue; | |
| 184 | |
| 185 if (std::isdigit(*ptr)) { | |
| 186 if (!e_number) | |
| 187 e_number = 1; | |
| 188 | |
| 189 if (!e_point) { | |
| 190 ret *= 10; | |
| 191 ret += FXSYS_toDecimalDigit(*ptr); | |
| 192 } else { | |
| 193 fra_count++; | |
| 194 fra_ret *= 10; | |
| 195 fra_ret += FXSYS_toDecimalDigit(*ptr); | |
| 196 } | |
| 197 continue; | |
| 198 } | |
| 199 if (!e_point && *ptr == '.') { | |
| 200 e_point = 1; | |
| 201 continue; | |
| 202 } | |
| 203 if (!e_number && !e_point && !e_signal) { | |
| 204 switch (*ptr) { | |
| 205 case '-': | |
| 206 is_negative = 1; | |
| 207 case '+': | |
| 208 e_signal = 1; | |
| 209 continue; | |
| 210 } | |
| 211 } | |
| 212 if (e_number && (*ptr == 'e' || *ptr == 'E')) { | |
| 213 exp_ptr = ptr++; | |
| 214 if (*ptr == '+' || *ptr == '-') { | |
| 215 exp_sig = (*ptr++ == '+') ? 1 : -1; | |
| 216 if (!std::isdigit(*ptr)) { | |
| 217 if (endptr) { | |
| 218 *endptr = (char*)exp_ptr; | |
| 219 } | |
| 220 break; | |
| 221 } | |
| 222 EXPONENT_DETECT(ptr); | |
| 223 } else if (std::isdigit(*ptr)) { | |
| 224 EXPONENT_DETECT(ptr); | |
| 225 } else { | |
| 226 if (endptr) { | |
| 227 *endptr = (char*)exp_ptr; | |
| 228 } | |
| 229 break; | |
| 230 } | |
| 231 break; | |
| 232 } | |
| 233 if (ptr != nptr && !e_number) { | |
| 234 if (endptr) { | |
| 235 *endptr = (char*)nptr; | |
| 236 } | |
| 237 break; | |
| 238 } | |
| 239 if (endptr) { | |
| 240 *endptr = (char*)ptr; | |
| 241 } | |
| 242 break; | |
| 243 } | |
| 244 while (fra_count--) { | |
| 245 fra_base *= 10; | |
| 246 } | |
| 247 ret += (double)fra_ret / (double)fra_base; | |
| 248 if (exp_sig == 1) { | |
| 249 while (exp_ret--) { | |
| 250 ret *= 10.0; | |
| 251 } | |
| 252 } else { | |
| 253 while (exp_ret--) { | |
| 254 ret /= 10.0; | |
| 255 } | |
| 256 } | |
| 257 return is_negative ? -ret : ret; | |
| 258 } | |
| 259 #undef EXPONENT_DETECT | |
| 260 | |
| 261 FX_BOOL CCodec_BasicModule::A85Encode(const uint8_t* src_buf, | |
| 262 FX_DWORD src_size, | |
| 263 uint8_t*& dest_buf, | |
| 264 FX_DWORD& dest_size) { | |
| 265 return FALSE; | |
| 266 } | |
| 267 | |
| 268 #ifdef PDF_ENABLE_XFA | |
| 269 CFX_DIBAttribute::CFX_DIBAttribute() | |
| 270 : m_nXDPI(-1), | |
| 271 m_nYDPI(-1), | |
| 272 m_fAspectRatio(-1.0f), | |
| 273 m_wDPIUnit(0), | |
| 274 m_nGifLeft(0), | |
| 275 m_nGifTop(0), | |
| 276 m_pGifLocalPalette(nullptr), | |
| 277 m_nGifLocalPalNum(0), | |
| 278 m_nBmpCompressType(0) { | |
| 279 FXSYS_memset(m_strTime, 0, sizeof(m_strTime)); | |
| 280 } | |
| 281 CFX_DIBAttribute::~CFX_DIBAttribute() { | |
| 282 for (const auto& pair : m_Exif) | |
| 283 FX_Free(pair.second); | |
| 284 } | |
| 285 #endif // PDF_ENABLE_XFA | |
| 286 | |
| 287 class CCodec_RLScanlineDecoder : public CCodec_ScanlineDecoder { | |
| 288 public: | |
| 289 CCodec_RLScanlineDecoder(); | |
| 290 ~CCodec_RLScanlineDecoder() override; | |
| 291 | |
| 292 FX_BOOL Create(const uint8_t* src_buf, | |
| 293 FX_DWORD src_size, | |
| 294 int width, | |
| 295 int height, | |
| 296 int nComps, | |
| 297 int bpc); | |
| 298 | |
| 299 // CCodec_ScanlineDecoder | |
| 300 void v_DownScale(int dest_width, int dest_height) override {} | |
| 301 FX_BOOL v_Rewind() override; | |
| 302 uint8_t* v_GetNextLine() override; | |
| 303 FX_DWORD GetSrcOffset() override { return m_SrcOffset; } | |
| 304 | |
| 305 protected: | |
| 306 FX_BOOL CheckDestSize(); | |
| 307 void GetNextOperator(); | |
| 308 void UpdateOperator(uint8_t used_bytes); | |
| 309 | |
| 310 uint8_t* m_pScanline; | |
| 311 const uint8_t* m_pSrcBuf; | |
| 312 FX_DWORD m_SrcSize; | |
| 313 FX_DWORD m_dwLineBytes; | |
| 314 FX_DWORD m_SrcOffset; | |
| 315 FX_BOOL m_bEOD; | |
| 316 uint8_t m_Operator; | |
| 317 }; | |
| 318 CCodec_RLScanlineDecoder::CCodec_RLScanlineDecoder() | |
| 319 : m_pScanline(NULL), | |
| 320 m_pSrcBuf(NULL), | |
| 321 m_SrcSize(0), | |
| 322 m_dwLineBytes(0), | |
| 323 m_SrcOffset(0), | |
| 324 m_bEOD(FALSE), | |
| 325 m_Operator(0) {} | |
| 326 CCodec_RLScanlineDecoder::~CCodec_RLScanlineDecoder() { | |
| 327 FX_Free(m_pScanline); | |
| 328 } | |
| 329 FX_BOOL CCodec_RLScanlineDecoder::CheckDestSize() { | |
| 330 FX_DWORD i = 0; | |
| 331 FX_DWORD old_size = 0; | |
| 332 FX_DWORD dest_size = 0; | |
| 333 while (i < m_SrcSize) { | |
| 334 if (m_pSrcBuf[i] < 128) { | |
| 335 old_size = dest_size; | |
| 336 dest_size += m_pSrcBuf[i] + 1; | |
| 337 if (dest_size < old_size) { | |
| 338 return FALSE; | |
| 339 } | |
| 340 i += m_pSrcBuf[i] + 2; | |
| 341 } else if (m_pSrcBuf[i] > 128) { | |
| 342 old_size = dest_size; | |
| 343 dest_size += 257 - m_pSrcBuf[i]; | |
| 344 if (dest_size < old_size) { | |
| 345 return FALSE; | |
| 346 } | |
| 347 i += 2; | |
| 348 } else { | |
| 349 break; | |
| 350 } | |
| 351 } | |
| 352 if (((FX_DWORD)m_OrigWidth * m_nComps * m_bpc * m_OrigHeight + 7) / 8 > | |
| 353 dest_size) { | |
| 354 return FALSE; | |
| 355 } | |
| 356 return TRUE; | |
| 357 } | |
| 358 FX_BOOL CCodec_RLScanlineDecoder::Create(const uint8_t* src_buf, | |
| 359 FX_DWORD src_size, | |
| 360 int width, | |
| 361 int height, | |
| 362 int nComps, | |
| 363 int bpc) { | |
| 364 m_pSrcBuf = src_buf; | |
| 365 m_SrcSize = src_size; | |
| 366 m_OutputWidth = m_OrigWidth = width; | |
| 367 m_OutputHeight = m_OrigHeight = height; | |
| 368 m_nComps = nComps; | |
| 369 m_bpc = bpc; | |
| 370 m_bColorTransformed = FALSE; | |
| 371 m_DownScale = 1; | |
| 372 // Aligning the pitch to 4 bytes requires an integer overflow check. | |
| 373 FX_SAFE_DWORD pitch = width; | |
| 374 pitch *= nComps; | |
| 375 pitch *= bpc; | |
| 376 pitch += 31; | |
| 377 pitch /= 32; | |
| 378 pitch *= 4; | |
| 379 if (!pitch.IsValid()) { | |
| 380 return FALSE; | |
| 381 } | |
| 382 m_Pitch = pitch.ValueOrDie(); | |
| 383 // Overflow should already have been checked before this is called. | |
| 384 m_dwLineBytes = (static_cast<FX_DWORD>(width) * nComps * bpc + 7) / 8; | |
| 385 m_pScanline = FX_Alloc(uint8_t, m_Pitch); | |
| 386 return CheckDestSize(); | |
| 387 } | |
| 388 FX_BOOL CCodec_RLScanlineDecoder::v_Rewind() { | |
| 389 FXSYS_memset(m_pScanline, 0, m_Pitch); | |
| 390 m_SrcOffset = 0; | |
| 391 m_bEOD = FALSE; | |
| 392 m_Operator = 0; | |
| 393 return TRUE; | |
| 394 } | |
| 395 uint8_t* CCodec_RLScanlineDecoder::v_GetNextLine() { | |
| 396 if (m_SrcOffset == 0) { | |
| 397 GetNextOperator(); | |
| 398 } else { | |
| 399 if (m_bEOD) { | |
| 400 return NULL; | |
| 401 } | |
| 402 } | |
| 403 FXSYS_memset(m_pScanline, 0, m_Pitch); | |
| 404 FX_DWORD col_pos = 0; | |
| 405 FX_BOOL eol = FALSE; | |
| 406 while (m_SrcOffset < m_SrcSize && !eol) { | |
| 407 if (m_Operator < 128) { | |
| 408 FX_DWORD copy_len = m_Operator + 1; | |
| 409 if (col_pos + copy_len >= m_dwLineBytes) { | |
| 410 copy_len = m_dwLineBytes - col_pos; | |
| 411 eol = TRUE; | |
| 412 } | |
| 413 if (copy_len >= m_SrcSize - m_SrcOffset) { | |
| 414 copy_len = m_SrcSize - m_SrcOffset; | |
| 415 m_bEOD = TRUE; | |
| 416 } | |
| 417 FXSYS_memcpy(m_pScanline + col_pos, m_pSrcBuf + m_SrcOffset, copy_len); | |
| 418 col_pos += copy_len; | |
| 419 UpdateOperator((uint8_t)copy_len); | |
| 420 } else if (m_Operator > 128) { | |
| 421 int fill = 0; | |
| 422 if (m_SrcOffset - 1 < m_SrcSize - 1) { | |
| 423 fill = m_pSrcBuf[m_SrcOffset]; | |
| 424 } | |
| 425 FX_DWORD duplicate_len = 257 - m_Operator; | |
| 426 if (col_pos + duplicate_len >= m_dwLineBytes) { | |
| 427 duplicate_len = m_dwLineBytes - col_pos; | |
| 428 eol = TRUE; | |
| 429 } | |
| 430 FXSYS_memset(m_pScanline + col_pos, fill, duplicate_len); | |
| 431 col_pos += duplicate_len; | |
| 432 UpdateOperator((uint8_t)duplicate_len); | |
| 433 } else { | |
| 434 m_bEOD = TRUE; | |
| 435 break; | |
| 436 } | |
| 437 } | |
| 438 return m_pScanline; | |
| 439 } | |
| 440 void CCodec_RLScanlineDecoder::GetNextOperator() { | |
| 441 if (m_SrcOffset >= m_SrcSize) { | |
| 442 m_Operator = 128; | |
| 443 return; | |
| 444 } | |
| 445 m_Operator = m_pSrcBuf[m_SrcOffset]; | |
| 446 m_SrcOffset++; | |
| 447 } | |
| 448 void CCodec_RLScanlineDecoder::UpdateOperator(uint8_t used_bytes) { | |
| 449 if (used_bytes == 0) { | |
| 450 return; | |
| 451 } | |
| 452 if (m_Operator < 128) { | |
| 453 FXSYS_assert((FX_DWORD)m_Operator + 1 >= used_bytes); | |
| 454 if (used_bytes == m_Operator + 1) { | |
| 455 m_SrcOffset += used_bytes; | |
| 456 GetNextOperator(); | |
| 457 return; | |
| 458 } | |
| 459 m_Operator -= used_bytes; | |
| 460 m_SrcOffset += used_bytes; | |
| 461 if (m_SrcOffset >= m_SrcSize) { | |
| 462 m_Operator = 128; | |
| 463 } | |
| 464 return; | |
| 465 } | |
| 466 uint8_t count = 257 - m_Operator; | |
| 467 FXSYS_assert((FX_DWORD)count >= used_bytes); | |
| 468 if (used_bytes == count) { | |
| 469 m_SrcOffset++; | |
| 470 GetNextOperator(); | |
| 471 return; | |
| 472 } | |
| 473 count -= used_bytes; | |
| 474 m_Operator = 257 - count; | |
| 475 } | |
| 476 ICodec_ScanlineDecoder* CCodec_BasicModule::CreateRunLengthDecoder( | |
| 477 const uint8_t* src_buf, | |
| 478 FX_DWORD src_size, | |
| 479 int width, | |
| 480 int height, | |
| 481 int nComps, | |
| 482 int bpc) { | |
| 483 CCodec_RLScanlineDecoder* pRLScanlineDecoder = new CCodec_RLScanlineDecoder; | |
| 484 if (!pRLScanlineDecoder->Create(src_buf, src_size, width, height, nComps, | |
| 485 bpc)) { | |
| 486 delete pRLScanlineDecoder; | |
| 487 return NULL; | |
| 488 } | |
| 489 return pRLScanlineDecoder; | |
| 490 } | |
| OLD | NEW |