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