Home | History | Annotate | Download | only in codec
      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 
     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 }
    491