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 "codec_int.h"
13 #include "core/include/fxcrt/fx_ext.h"
14 #include "core/include/fxcrt/fx_safe_types.h"
15 #include "third_party/base/logging.h"
16
CCodec_ModuleMgr()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
ImageDataCache(int width,int height,FX_DWORD pitch)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
~ImageDataCache()38 CCodec_ScanlineDecoder::ImageDataCache::~ImageDataCache() {
39 }
40
AllocateCache()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
AppendLine(const uint8_t * line)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
GetLine(int line) const66 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
CCodec_ScanlineDecoder()74 CCodec_ScanlineDecoder::CCodec_ScanlineDecoder()
75 : m_NextLine(-1), m_pLastScanline(nullptr) {
76 }
77
~CCodec_ScanlineDecoder()78 CCodec_ScanlineDecoder::~CCodec_ScanlineDecoder() {
79 }
80
GetScanline(int line)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
SkipToScanline(int line,IFX_Pause * pPause)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
ReadNextLine()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
DownScale(int dest_width,int dest_height)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
RunLengthEncode(const uint8_t * src_buf,FX_DWORD src_size,uint8_t * & dest_buf,FX_DWORD & dest_size)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
FXstrtod(const char * nptr,char ** endptr)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
A85Encode(const uint8_t * src_buf,FX_DWORD src_size,uint8_t * & dest_buf,FX_DWORD & dest_size)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
CFX_DIBAttribute()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 }
~CFX_DIBAttribute()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
v_DownScale(int dest_width,int dest_height)300 void v_DownScale(int dest_width, int dest_height) override {}
301 FX_BOOL v_Rewind() override;
302 uint8_t* v_GetNextLine() override;
GetSrcOffset()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 };
CCodec_RLScanlineDecoder()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) {}
~CCodec_RLScanlineDecoder()326 CCodec_RLScanlineDecoder::~CCodec_RLScanlineDecoder() {
327 FX_Free(m_pScanline);
328 }
CheckDestSize()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 }
Create(const uint8_t * src_buf,FX_DWORD src_size,int width,int height,int nComps,int bpc)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 }
v_Rewind()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 }
v_GetNextLine()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 }
GetNextOperator()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 }
UpdateOperator(uint8_t used_bytes)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 }
CreateRunLengthDecoder(const uint8_t * src_buf,FX_DWORD src_size,int width,int height,int nComps,int bpc)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 }
491