c6b3ccee43c50ab94efd459a13c7aca0189914de
[pdfium.git] / core / src / fxcodec / codec / fx_codec.cpp
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 "../../../include/fxcodec/fx_codec.h"
8 #include "codec_int.h"
9 CCodec_ModuleMgr::CCodec_ModuleMgr()
10 {
11     m_pBasicModule = FX_NEW CCodec_BasicModule;
12     m_pFaxModule = FX_NEW CCodec_FaxModule;
13     m_pJpegModule = FX_NEW CCodec_JpegModule;
14     m_pJpxModule = FX_NEW CCodec_JpxModule;
15     m_pJbig2Module = FX_NEW CCodec_Jbig2Module;
16     m_pIccModule = FX_NEW CCodec_IccModule;
17     m_pFlateModule = FX_NEW CCodec_FlateModule;
18 }
19 CCodec_ModuleMgr::~CCodec_ModuleMgr()
20 {
21     delete m_pBasicModule;
22     delete m_pFaxModule;
23     delete m_pJpegModule;
24     delete m_pFlateModule;
25     delete m_pJpxModule;
26     delete m_pJbig2Module;
27     delete m_pIccModule;
28 }
29 void CCodec_ModuleMgr::InitJbig2Decoder()
30 {
31 }
32 void CCodec_ModuleMgr::InitJpxDecoder()
33 {
34 }
35 void CCodec_ModuleMgr::InitIccDecoder()
36 {
37 }
38 CCodec_ScanlineDecoder::CCodec_ScanlineDecoder()
39 {
40     m_NextLine = -1;
41     m_pDataCache = NULL;
42     m_pLastScanline = NULL;
43 }
44 CCodec_ScanlineDecoder::~CCodec_ScanlineDecoder()
45 {
46     if (m_pDataCache) {
47         FX_Free(m_pDataCache);
48     }
49 }
50 FX_LPBYTE CCodec_ScanlineDecoder::GetScanline(int line)
51 {
52     if (m_pDataCache && line < m_pDataCache->m_nCachedLines) {
53         return &m_pDataCache->m_Data + line * m_Pitch;
54     }
55     if (m_NextLine == line + 1) {
56         return m_pLastScanline;
57     }
58     if (m_NextLine < 0 || m_NextLine > line) {
59         if (!v_Rewind()) {
60             return NULL;
61         }
62         m_NextLine = 0;
63     }
64     while (m_NextLine < line) {
65         ReadNextLine();
66         m_NextLine ++;
67     }
68     m_pLastScanline = ReadNextLine();
69     m_NextLine ++;
70     return m_pLastScanline;
71 }
72 FX_BOOL CCodec_ScanlineDecoder::SkipToScanline(int line, IFX_Pause* pPause)
73 {
74     if (m_pDataCache && line < m_pDataCache->m_nCachedLines) {
75         return FALSE;
76     }
77     if (m_NextLine == line || m_NextLine == line + 1) {
78         return FALSE;
79     }
80     if (m_NextLine < 0 || m_NextLine > line) {
81         v_Rewind();
82         m_NextLine = 0;
83     }
84     m_pLastScanline = NULL;
85     while (m_NextLine < line) {
86         m_pLastScanline = ReadNextLine();
87         m_NextLine ++;
88         if (pPause && pPause->NeedToPauseNow()) {
89             return TRUE;
90         }
91     }
92     return FALSE;
93 }
94 FX_LPBYTE CCodec_ScanlineDecoder::ReadNextLine()
95 {
96     FX_LPBYTE pLine = v_GetNextLine();
97     if (pLine == NULL) {
98         return NULL;
99     }
100     if (m_pDataCache && m_NextLine == m_pDataCache->m_nCachedLines) {
101         FXSYS_memcpy32(&m_pDataCache->m_Data + m_NextLine * m_Pitch, pLine, m_Pitch);
102         m_pDataCache->m_nCachedLines ++;
103     }
104     return pLine;
105 }
106 void CCodec_ScanlineDecoder::DownScale(int dest_width, int dest_height)
107 {
108     if (dest_width < 0) {
109         dest_width = -dest_width;
110     }
111     if (dest_height < 0) {
112         dest_height = -dest_height;
113     }
114     v_DownScale(dest_width, dest_height);
115     if (m_pDataCache) {
116         if (m_pDataCache->m_Height == m_OutputHeight && m_pDataCache->m_Width == m_OutputWidth) {
117             return;
118         }
119         FX_Free(m_pDataCache);
120         m_pDataCache = NULL;
121     }
122     m_pDataCache = (CCodec_ImageDataCache*)FXMEM_DefaultAlloc(
123                        sizeof(CCodec_ImageDataCache) + m_Pitch * m_OutputHeight, FXMEM_NONLEAVE);
124     if (m_pDataCache == NULL) {
125         return;
126     }
127     m_pDataCache->m_Height = m_OutputHeight;
128     m_pDataCache->m_Width = m_OutputWidth;
129     m_pDataCache->m_nCachedLines = 0;
130 }
131 FX_BOOL CCodec_BasicModule::RunLengthEncode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf,
132         FX_DWORD& dest_size)
133 {
134     return FALSE;
135 }
136 extern "C" double FXstrtod(const char* nptr, char** endptr)
137 {
138     double ret = 0.0;
139     const char* ptr = nptr;
140     const char* exp_ptr = NULL;
141     int e_number = 0,
142         e_signal = 0,
143         e_point = 0,
144         is_negative = 0;
145     int exp_ret = 0, exp_sig = 1,
146         fra_ret = 0, fra_count = 0, fra_base = 1;
147     if(nptr == NULL) {
148         return 0.0;
149     }
150     for (;; ptr++) {
151         if(!e_number && !e_point && (*ptr == '\t' || *ptr == ' ')) {
152             continue;
153         }
154         if(*ptr >= '0' && *ptr <= '9') {
155             if(!e_number) {
156                 e_number = 1;
157             }
158             if(!e_point) {
159                 ret *= 10;
160                 ret += (*ptr - '0');
161             } else {
162                 fra_count++;
163                 fra_ret *= 10;
164                 fra_ret += (*ptr - '0');
165             }
166             continue;
167         }
168         if(!e_point && *ptr == '.') {
169             e_point = 1;
170             continue;
171         }
172         if(!e_number && !e_point && !e_signal) {
173             switch(*ptr) {
174                 case '-':
175                     is_negative = 1;
176                 case '+':
177                     e_signal = 1;
178                     continue;
179             }
180         }
181         if(e_number && (*ptr == 'e' || *ptr == 'E')) {
182 #define EXPONENT_DETECT(ptr)    \
183     for(;;ptr++){               \
184         if(*ptr < '0' || *ptr > '9'){   \
185             if(endptr)  *endptr = (char*)ptr;   \
186             break;      \
187         }else{          \
188             exp_ret *= 10;      \
189             exp_ret += (*ptr - '0');    \
190             continue;           \
191         }       \
192     }
193             exp_ptr = ptr++;
194             if(*ptr == '+' || *ptr == '-') {
195                 exp_sig = (*ptr++ == '+') ? 1 : -1;
196                 if(*ptr < '0' || *ptr > '9') {
197                     if(endptr)  {
198                         *endptr = (char*)exp_ptr;
199                     }
200                     break;
201                 }
202                 EXPONENT_DETECT(ptr);
203             } else if(*ptr >= '0' && *ptr <= '9') {
204                 EXPONENT_DETECT(ptr);
205             } else {
206                 if(endptr)      {
207                     *endptr = (char*)exp_ptr;
208                 }
209                 break;
210             }
211 #undef EXPONENT_DETECT
212             break;
213         }
214         if(ptr != nptr && !e_number) {
215             if(endptr)  {
216                 *endptr = (char*)nptr;
217             }
218             break;
219         }
220         if(endptr)      {
221             *endptr = (char*)ptr;
222         }
223         break;
224     }
225     while(fra_count--) {
226         fra_base *= 10;
227     }
228     ret += (double)fra_ret / (double)fra_base;
229     if(exp_sig == 1) {
230         while(exp_ret--) {
231             ret *= 10.0;
232         }
233     } else {
234         while(exp_ret--) {
235             ret /= 10.0;
236         }
237     }
238     return is_negative ? -ret : ret;
239 }
240 FX_BOOL CCodec_BasicModule::A85Encode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf,
241                                       FX_DWORD& dest_size)
242 {
243     return FALSE;
244 }
245 CCodec_ModuleMgr* CCodec_ModuleMgr::Create()
246 {
247     return FX_NEW CCodec_ModuleMgr;
248 }
249 void CCodec_ModuleMgr::Destroy()
250 {
251     delete this;
252 }
253 class CCodec_RLScanlineDecoder : public CCodec_ScanlineDecoder
254 {
255 public:
256     CCodec_RLScanlineDecoder();
257     virtual ~CCodec_RLScanlineDecoder();
258     FX_BOOL                             Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, int nComps, int bpc);
259     virtual void                v_DownScale(int dest_width, int dest_height) {}
260     virtual FX_BOOL             v_Rewind();
261     virtual FX_LPBYTE   v_GetNextLine();
262     virtual FX_DWORD    GetSrcOffset()
263     {
264         return m_SrcOffset;
265     }
266 protected:
267     FX_BOOL                             CheckDestSize();
268     void                                GetNextOperator();
269     void                                UpdateOperator(FX_BYTE used_bytes);
270
271     FX_LPBYTE                   m_pScanline;
272     FX_LPCBYTE                  m_pSrcBuf;
273     FX_DWORD                    m_SrcSize;
274     FX_DWORD                    m_dwLineBytes;
275     FX_DWORD                    m_SrcOffset;
276     FX_BOOL                             m_bEOD;
277     FX_BYTE                             m_Operator;
278 };
279 CCodec_RLScanlineDecoder::CCodec_RLScanlineDecoder()
280     : m_pScanline(NULL)
281     , m_pSrcBuf(NULL)
282     , m_SrcSize(0)
283     , m_dwLineBytes(0)
284     , m_SrcOffset(0)
285     , m_bEOD(FALSE)
286     , m_Operator(0)
287 {
288 }
289 CCodec_RLScanlineDecoder::~CCodec_RLScanlineDecoder()
290 {
291     if (m_pScanline) {
292         FX_Free(m_pScanline);
293     }
294 }
295 FX_BOOL CCodec_RLScanlineDecoder::CheckDestSize()
296 {
297     FX_DWORD i = 0;
298     FX_DWORD old_size = 0;
299     FX_DWORD dest_size = 0;
300     while (i < m_SrcSize) {
301         if (m_pSrcBuf[i] < 128) {
302             old_size = dest_size;
303             dest_size += m_pSrcBuf[i] + 1;
304             if (dest_size < old_size) {
305                 return FALSE;
306             }
307             i += m_pSrcBuf[i] + 2;
308         } else if (m_pSrcBuf[i] > 128) {
309             old_size = dest_size;
310             dest_size += 257 - m_pSrcBuf[i];
311             if (dest_size < old_size) {
312                 return FALSE;
313             }
314             i += 2;
315         } else {
316             break;
317         }
318     }
319     if (((FX_DWORD)m_OrigWidth * m_nComps * m_bpc * m_OrigHeight + 7) / 8 > dest_size) {
320         return FALSE;
321     }
322     return TRUE;
323 }
324 FX_BOOL CCodec_RLScanlineDecoder::Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, int nComps, int bpc)
325 {
326     m_pSrcBuf = src_buf;
327     m_SrcSize = src_size;
328     m_OutputWidth = m_OrigWidth = width;
329     m_OutputHeight = m_OrigHeight = height;
330     m_nComps = nComps;
331     m_bpc = bpc;
332     m_bColorTransformed = FALSE;
333     m_DownScale = 1;
334     m_Pitch = (width * nComps * bpc + 31) / 32 * 4;
335     m_dwLineBytes = (width * nComps * bpc + 7) / 8;
336     m_pScanline = FX_Alloc(FX_BYTE, m_Pitch);
337     if (m_pScanline == NULL) {
338         return FALSE;
339     }
340     FXSYS_memset32(m_pScanline, 0, m_Pitch);
341     return CheckDestSize();
342 }
343 FX_BOOL CCodec_RLScanlineDecoder::v_Rewind()
344 {
345     FXSYS_memset32(m_pScanline, 0, m_Pitch);
346     m_SrcOffset = 0;
347     m_bEOD = FALSE;
348     m_Operator = 0;
349     return TRUE;
350 }
351 FX_LPBYTE CCodec_RLScanlineDecoder::v_GetNextLine()
352 {
353     if (m_SrcOffset == 0) {
354         GetNextOperator();
355     } else {
356         if (m_bEOD) {
357             return NULL;
358         }
359     }
360     FXSYS_memset32(m_pScanline, 0, m_Pitch);
361     FX_DWORD col_pos = 0;
362     FX_BOOL     eol = FALSE;
363     while (m_SrcOffset < m_SrcSize && !eol) {
364         if (m_Operator < 128) {
365             FX_DWORD copy_len = m_Operator + 1;
366             if (col_pos + copy_len >= m_dwLineBytes) {
367                 copy_len = m_dwLineBytes - col_pos;
368                 eol = TRUE;
369             }
370             if (copy_len >= m_SrcSize - m_SrcOffset) {
371                 copy_len = m_SrcSize - m_SrcOffset;
372                 m_bEOD = TRUE;
373             }
374             FXSYS_memcpy32(m_pScanline + col_pos, m_pSrcBuf + m_SrcOffset, copy_len);
375             col_pos += copy_len;
376             UpdateOperator((FX_BYTE)copy_len);
377         } else if (m_Operator > 128) {
378             int fill = 0;
379             if (m_SrcOffset - 1 < m_SrcSize - 1) {
380                 fill = m_pSrcBuf[m_SrcOffset];
381             }
382             FX_DWORD duplicate_len = 257 - m_Operator;
383             if (col_pos + duplicate_len >= m_dwLineBytes) {
384                 duplicate_len = m_dwLineBytes - col_pos;
385                 eol = TRUE;
386             }
387             FXSYS_memset8(m_pScanline + col_pos, fill, duplicate_len);
388             col_pos += duplicate_len;
389             UpdateOperator((FX_BYTE)duplicate_len);
390         } else {
391             m_bEOD = TRUE;
392             break;
393         }
394     }
395     return m_pScanline;
396 }
397 void CCodec_RLScanlineDecoder::GetNextOperator()
398 {
399     if (m_SrcOffset >= m_SrcSize) {
400         m_Operator = 128;
401         return;
402     }
403     m_Operator = m_pSrcBuf[m_SrcOffset];
404     m_SrcOffset ++;
405 }
406 void CCodec_RLScanlineDecoder::UpdateOperator(FX_BYTE used_bytes)
407 {
408     if (used_bytes == 0) {
409         return;
410     }
411     if (m_Operator < 128) {
412         FXSYS_assert((FX_DWORD)m_Operator + 1 >= used_bytes);
413         if (used_bytes == m_Operator + 1) {
414             m_SrcOffset += used_bytes;
415             GetNextOperator();
416             return;
417         }
418         m_Operator -= used_bytes;
419         m_SrcOffset += used_bytes;
420         if (m_SrcOffset >= m_SrcSize) {
421             m_Operator = 128;
422         }
423         return;
424     }
425     FX_BYTE count = 257 - m_Operator;
426     FXSYS_assert((FX_DWORD)count >= used_bytes);
427     if (used_bytes == count) {
428         m_SrcOffset ++;
429         GetNextOperator();
430         return;
431     }
432     count -= used_bytes;
433     m_Operator = 257 - count;
434 }
435 ICodec_ScanlineDecoder* CCodec_BasicModule::CreateRunLengthDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
436         int nComps, int bpc)
437 {
438     CCodec_RLScanlineDecoder* pRLScanlineDecoder = FX_NEW CCodec_RLScanlineDecoder;
439     if (pRLScanlineDecoder == NULL) {
440         return NULL;
441     }
442     if (!pRLScanlineDecoder->Create(src_buf, src_size, width, height, nComps, bpc)) {
443         delete pRLScanlineDecoder;
444         return NULL;
445     }
446     return pRLScanlineDecoder;
447 }