Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[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_pPngModule = FX_NEW CCodec_PngModule;\r
18     m_pGifModule = FX_NEW CCodec_GifModule;\r
19     m_pBmpModule = FX_NEW CCodec_BmpModule;\r
20     m_pTiffModule = FX_NEW CCodec_TiffModule;\r
21     m_pFlateModule = FX_NEW CCodec_FlateModule;
22 }
23 CCodec_ModuleMgr::~CCodec_ModuleMgr()
24 {
25     delete m_pBasicModule;
26     delete m_pFaxModule;
27     delete m_pJpegModule;
28     delete m_pFlateModule;
29     delete m_pJpxModule;
30     delete m_pJbig2Module;
31     delete m_pIccModule;
32 }
33 void CCodec_ModuleMgr::InitJbig2Decoder()
34 {
35 }
36 void CCodec_ModuleMgr::InitJpxDecoder()
37 {
38 }
39 void CCodec_ModuleMgr::InitIccDecoder()
40 {
41 }
42 CCodec_ScanlineDecoder::CCodec_ScanlineDecoder()
43 {
44     m_NextLine = -1;
45     m_pDataCache = NULL;
46     m_pLastScanline = NULL;
47 }
48 CCodec_ScanlineDecoder::~CCodec_ScanlineDecoder()
49 {
50     if (m_pDataCache) {
51         FX_Free(m_pDataCache);
52     }
53 }
54 FX_LPBYTE CCodec_ScanlineDecoder::GetScanline(int line)
55 {
56     if (m_pDataCache && line < m_pDataCache->m_nCachedLines) {
57         return &m_pDataCache->m_Data + line * m_Pitch;
58     }
59     if (m_NextLine == line + 1) {
60         return m_pLastScanline;
61     }
62     if (m_NextLine < 0 || m_NextLine > line) {
63         if (!v_Rewind()) {
64             return NULL;
65         }
66         m_NextLine = 0;
67     }
68     while (m_NextLine < line) {
69         ReadNextLine();
70         m_NextLine ++;
71     }
72     m_pLastScanline = ReadNextLine();
73     m_NextLine ++;
74     return m_pLastScanline;
75 }
76 FX_BOOL CCodec_ScanlineDecoder::SkipToScanline(int line, IFX_Pause* pPause)
77 {
78     if (m_pDataCache && line < m_pDataCache->m_nCachedLines) {
79         return FALSE;
80     }
81     if (m_NextLine == line || m_NextLine == line + 1) {
82         return FALSE;
83     }
84     if (m_NextLine < 0 || m_NextLine > line) {
85         v_Rewind();
86         m_NextLine = 0;
87     }
88     m_pLastScanline = NULL;
89     while (m_NextLine < line) {
90         m_pLastScanline = ReadNextLine();
91         m_NextLine ++;
92         if (pPause && pPause->NeedToPauseNow()) {
93             return TRUE;
94         }
95     }
96     return FALSE;
97 }
98 FX_LPBYTE CCodec_ScanlineDecoder::ReadNextLine()
99 {
100     FX_LPBYTE pLine = v_GetNextLine();
101     if (pLine == NULL) {
102         return NULL;
103     }
104     if (m_pDataCache && m_NextLine == m_pDataCache->m_nCachedLines) {
105         FXSYS_memcpy32(&m_pDataCache->m_Data + m_NextLine * m_Pitch, pLine, m_Pitch);
106         m_pDataCache->m_nCachedLines ++;
107     }
108     return pLine;
109 }
110 void CCodec_ScanlineDecoder::DownScale(int dest_width, int dest_height)
111 {
112     if (dest_width < 0) {
113         dest_width = -dest_width;
114     }
115     if (dest_height < 0) {
116         dest_height = -dest_height;
117     }
118     v_DownScale(dest_width, dest_height);
119     if (m_pDataCache) {
120         if (m_pDataCache->m_Height == m_OutputHeight && m_pDataCache->m_Width == m_OutputWidth) {
121             return;
122         }
123         FX_Free(m_pDataCache);
124         m_pDataCache = NULL;
125     }
126     m_pDataCache = (CCodec_ImageDataCache*)FX_AllocNL(FX_BYTE, sizeof(CCodec_ImageDataCache) + m_Pitch * m_OutputHeight);
127     if (m_pDataCache == NULL) {
128         return;
129     }
130     m_pDataCache->m_Height = m_OutputHeight;
131     m_pDataCache->m_Width = m_OutputWidth;
132     m_pDataCache->m_nCachedLines = 0;
133 }
134 FX_BOOL CCodec_BasicModule::RunLengthEncode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf,
135         FX_DWORD& dest_size)
136 {
137     return FALSE;
138 }
139 extern "C" double FXstrtod(const char* nptr, char** endptr)
140 {
141     double ret = 0.0;
142     const char* ptr = nptr;
143     const char* exp_ptr = NULL;
144     int e_number = 0,
145         e_signal = 0,
146         e_point = 0,
147         is_negative = 0;
148     int exp_ret = 0, exp_sig = 1,
149         fra_ret = 0, fra_count = 0, fra_base = 1;
150     if(nptr == NULL) {
151         return 0.0;
152     }
153     for (;; ptr++) {
154         if(!e_number && !e_point && (*ptr == '\t' || *ptr == ' ')) {
155             continue;
156         }
157         if(*ptr >= '0' && *ptr <= '9') {
158             if(!e_number) {
159                 e_number = 1;
160             }
161             if(!e_point) {
162                 ret *= 10;
163                 ret += (*ptr - '0');
164             } else {
165                 fra_count++;
166                 fra_ret *= 10;
167                 fra_ret += (*ptr - '0');
168             }
169             continue;
170         }
171         if(!e_point && *ptr == '.') {
172             e_point = 1;
173             continue;
174         }
175         if(!e_number && !e_point && !e_signal) {
176             switch(*ptr) {
177                 case '-':
178                     is_negative = 1;
179                 case '+':
180                     e_signal = 1;
181                     continue;
182             }
183         }
184         if(e_number && (*ptr == 'e' || *ptr == 'E')) {
185 #define EXPONENT_DETECT(ptr)    \
186     for(;;ptr++){               \
187         if(*ptr < '0' || *ptr > '9'){   \
188             if(endptr)  *endptr = (char*)ptr;   \
189             break;      \
190         }else{          \
191             exp_ret *= 10;      \
192             exp_ret += (*ptr - '0');    \
193             continue;           \
194         }       \
195     }
196             exp_ptr = ptr++;
197             if(*ptr == '+' || *ptr == '-') {
198                 exp_sig = (*ptr++ == '+') ? 1 : -1;
199                 if(*ptr < '0' || *ptr > '9') {
200                     if(endptr)  {
201                         *endptr = (char*)exp_ptr;
202                     }
203                     break;
204                 }
205                 EXPONENT_DETECT(ptr);
206             } else if(*ptr >= '0' && *ptr <= '9') {
207                 EXPONENT_DETECT(ptr);
208             } else {
209                 if(endptr)      {
210                     *endptr = (char*)exp_ptr;
211                 }
212                 break;
213             }
214 #undef EXPONENT_DETECT
215             break;
216         }
217         if(ptr != nptr && !e_number) {
218             if(endptr)  {
219                 *endptr = (char*)nptr;
220             }
221             break;
222         }
223         if(endptr)      {
224             *endptr = (char*)ptr;
225         }
226         break;
227     }
228     while(fra_count--) {
229         fra_base *= 10;
230     }
231     ret += (double)fra_ret / (double)fra_base;
232     if(exp_sig == 1) {
233         while(exp_ret--) {
234             ret *= 10.0;
235         }
236     } else {
237         while(exp_ret--) {
238             ret /= 10.0;
239         }
240     }
241     return is_negative ? -ret : ret;
242 }
243 FX_BOOL CCodec_BasicModule::A85Encode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf,
244                                       FX_DWORD& dest_size)
245 {
246     return FALSE;
247 }
248 CCodec_ModuleMgr* CCodec_ModuleMgr::Create()
249 {
250     return FX_NEW CCodec_ModuleMgr;
251 }
252 void CCodec_ModuleMgr::Destroy()
253 {
254     delete this;
255 }
256 CFX_DIBAttribute::CFX_DIBAttribute()\r
257 {\r
258     FXSYS_memset32(this, 0, sizeof(CFX_DIBAttribute));\r
259     m_nXDPI = -1;\r
260     m_nYDPI = -1;\r
261     m_fAspectRatio = -1.0f;\r
262     m_pExif = FX_NEW CFX_DIBAttributeExif;\r
263 }\r
264 CFX_DIBAttribute::~CFX_DIBAttribute()\r
265 {\r
266     if (m_pExif) {\r
267         delete m_pExif;\r
268     }\r
269 }\r
270 CFX_DIBAttributeExif::CFX_DIBAttributeExif()\r
271 {\r
272     m_pExifData = NULL;\r
273     m_dwExifDataLen = 0;\r
274 }\r
275 CFX_DIBAttributeExif::~CFX_DIBAttributeExif()\r
276 {\r
277     clear();\r
278 }\r
279 void CFX_DIBAttributeExif::clear()\r
280 {\r
281     if (m_pExifData) {\r
282         FX_Free(m_pExifData);\r
283     }\r
284     m_pExifData = NULL;\r
285     FX_DWORD key = 0;\r
286     FX_LPBYTE buf = NULL;\r
287     FX_POSITION pos = NULL;\r
288     pos = m_TagHead.GetStartPosition();\r
289     while (pos) {\r
290         m_TagHead.GetNextAssoc(pos, key, buf);\r
291         if (buf) {\r
292             FX_Free(buf);\r
293         }\r
294     }\r
295     m_TagHead.RemoveAll();\r
296     pos = m_TagVal.GetStartPosition();\r
297     while (pos) {\r
298         m_TagVal.GetNextAssoc(pos, key, buf);\r
299         if (buf) {\r
300             FX_Free(buf);\r
301         }\r
302     }\r
303     m_TagVal.RemoveAll();\r
304 }\r
305 static FX_WORD _Read2BytesL(FX_LPBYTE data)\r
306 {\r
307     ASSERT(data);\r
308     return data[0] | (data[1] << 8);\r
309 }\r
310 static FX_WORD _Read2BytesB(FX_LPBYTE data)\r
311 {\r
312     ASSERT(data);\r
313     return data[1] | (data[0] << 8);\r
314 }\r
315 static FX_DWORD _Read4BytesL(FX_LPBYTE data)\r
316 {\r
317     return _Read2BytesL(data) | (_Read2BytesL(data + 2) << 16);\r
318 }\r
319 static FX_DWORD _Read4BytesB(FX_LPBYTE data)\r
320 {\r
321     return _Read2BytesB(data + 2) | (_Read2BytesB(data) << 16);\r
322 }\r
323 typedef FX_WORD (*_Read2Bytes) (FX_LPBYTE data);\r
324 typedef FX_DWORD (*_Read4Bytes) (FX_LPBYTE data);\r
325 typedef void (*_Write2Bytes) (FX_LPBYTE data, FX_WORD val);\r
326 typedef void (*_Write4Bytes) (FX_LPBYTE data, FX_DWORD val);\r
327 FX_LPBYTE CFX_DIBAttributeExif::ParseExifIFH(FX_LPBYTE data, FX_DWORD len, _Read2Bytes* pReadWord, _Read4Bytes* pReadDword)\r
328 {\r
329     if (len > 8) {\r
330         FX_BOOL tag = FALSE;\r
331         if (FXSYS_memcmp32(data, "\x49\x49\x2a\x00", 4) == 0) {\r
332             if (pReadWord) {\r
333                 *pReadWord = _Read2BytesL;\r
334             }\r
335             if (pReadDword) {\r
336                 *pReadDword = _Read4BytesL;\r
337             }\r
338             tag = TRUE;\r
339         } else if (FXSYS_memcmp32(data, "\x4d\x4d\x00\x2a", 4) == 0) {\r
340             if (pReadWord) {\r
341                 *pReadWord = _Read2BytesB;\r
342             }\r
343             if (pReadDword) {\r
344                 *pReadDword = _Read4BytesB;\r
345             }\r
346             tag = TRUE;\r
347         }\r
348         if (tag) {\r
349             data += 4;\r
350             if (pReadDword) {\r
351                 data += (*pReadDword)(data) - 4;\r
352             } else {\r
353                 data += 4;\r
354             }\r
355         }\r
356     }\r
357     return data;\r
358 }\r
359 FX_BOOL CFX_DIBAttributeExif::ParseExifIFD(CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE>* pMap, FX_LPBYTE data, FX_DWORD len)\r
360 {\r
361     if (pMap && data) {\r
362         if (len > 8) {\r
363             FX_WORD wTagNum = m_readWord(data);\r
364             data += 2;\r
365             FX_DWORD wTag;\r
366             FX_LPBYTE buf;\r
367             while (wTagNum--) {\r
368                 wTag = m_readWord(data);\r
369                 data += 2;\r
370                 if (!pMap->Lookup(wTag, buf)) {\r
371                     buf = FX_Alloc(FX_BYTE, 10);\r
372                     if (buf == NULL) {\r
373                         return FALSE;\r
374                     }\r
375                     FXSYS_memcpy32(buf, data, 10);\r
376                     pMap->SetAt(wTag, buf);\r
377                 }\r
378                 data += 10;\r
379             }\r
380             FX_DWORD dwIFDOffset;\r
381             dwIFDOffset = m_readDword(data);\r
382             while (dwIFDOffset && dwIFDOffset < len) {\r
383                 data = m_pExifData + dwIFDOffset;\r
384                 wTagNum = m_readWord(data);\r
385                 data += 2;\r
386                 while (wTagNum--) {\r
387                     wTag = m_readWord(data);\r
388                     data += 2;\r
389                     if (!pMap->Lookup(wTag, buf)) {\r
390                         buf = FX_Alloc(FX_BYTE, 10);\r
391                         if (buf == NULL) {\r
392                             return FALSE;\r
393                         }\r
394                         FXSYS_memcpy32(buf, data, 10);\r
395                         pMap->SetAt(wTag, buf);\r
396                     }\r
397                     data += 10;\r
398                 }\r
399                 dwIFDOffset = m_readDword(data);\r
400             }\r
401             return TRUE;\r
402         }\r
403     }\r
404     return FALSE;\r
405 }\r
406 enum FX_ExifDataType {\r
407     FX_UnsignedByte = 1,\r
408     FX_AscString,\r
409     FX_UnsignedShort,\r
410     FX_UnsignedLong,\r
411     FX_UnsignedRation,\r
412     FX_SignedByte,\r
413     FX_Undefined,\r
414     FX_SignedShort,\r
415     FX_SignedLong,\r
416     FX_SignedRation,\r
417     FX_SignedFloat,\r
418     FX_DoubleFloat\r
419 };\r
420 FX_BOOL CFX_DIBAttributeExif::ParseExif(CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE>* pHead, FX_LPBYTE data, FX_DWORD len, CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE>* pVal)\r
421 {\r
422     if (pHead && data && pVal) {\r
423         if (len > 8) {\r
424             FX_LPBYTE old_data = data;\r
425             data = ParseExifIFH(data, len, &m_readWord, &m_readDword);\r
426             if (data == old_data) {\r
427                 return FALSE;\r
428             }\r
429             if (pHead->GetCount() == 0) {\r
430                 if (!ParseExifIFD(pHead, data, len)) {\r
431                     return FALSE;\r
432                 }\r
433             }\r
434             FX_DWORD dwModuleNum;\r
435             FX_WORD type;\r
436             FX_DWORD dwSize;\r
437             FX_DWORD tag;\r
438             FX_LPBYTE head;\r
439             FX_POSITION pos = pHead->GetStartPosition();\r
440             while (pos) {\r
441                 pHead->GetNextAssoc(pos, tag, head);\r
442                 FX_LPBYTE val = NULL, buf = NULL, temp = NULL;\r
443                 int i;\r
444                 if (head) {\r
445                     type = m_readWord(head);\r
446                     head += 2;\r
447                     dwModuleNum = m_readDword(head);\r
448                     head += 4;\r
449                     switch (type) {\r
450                         case FX_UnsignedByte:\r
451                         case FX_AscString:\r
452                         case FX_SignedByte:\r
453                         case FX_Undefined:\r
454                             dwSize = dwModuleNum;\r
455                             val = FX_Alloc(FX_BYTE, dwSize);\r
456                             if (val == NULL) {\r
457                                 return FALSE;\r
458                             }\r
459                             if (dwSize > 4) {\r
460                                 FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);\r
461                             } else {\r
462                                 FXSYS_memcpy32(val, head, dwSize);\r
463                             }\r
464                             break;\r
465                         case FX_UnsignedShort:\r
466                         case FX_SignedShort:\r
467                             dwSize = dwModuleNum << 1;\r
468                             val = FX_Alloc(FX_BYTE, dwSize);\r
469                             if (val == NULL) {\r
470                                 return FALSE;\r
471                             }\r
472                             if (dwSize > 4) {\r
473                                 FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);\r
474                             } else {\r
475                                 FXSYS_memcpy32(val, head, dwSize);\r
476                             }\r
477                             buf = val;\r
478                             for(i = 0; i < (int)dwModuleNum; i ++) {\r
479                                 *(FX_WORD*)buf = m_readWord(buf);\r
480                                 buf += 2;\r
481                             }\r
482                             break;\r
483                         case FX_UnsignedLong:\r
484                         case FX_SignedLong:\r
485                         case FX_SignedFloat:\r
486                             dwSize = dwModuleNum << 2;\r
487                             val = FX_Alloc(FX_BYTE, dwSize);\r
488                             if (val == NULL) {\r
489                                 return FALSE;\r
490                             }\r
491                             if (dwSize > 4) {\r
492                                 FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);\r
493                             } else {\r
494                                 FXSYS_memcpy32(val, head, dwSize);\r
495                             }\r
496                             buf = val;\r
497                             for(i = 0; i < (int)dwModuleNum; i ++) {\r
498                                 *(FX_DWORD*)buf = m_readDword(buf);\r
499                                 buf += 4;\r
500                             }\r
501                             break;\r
502                         case FX_UnsignedRation:\r
503                         case FX_SignedRation: {\r
504                                 dwSize = dwModuleNum << 3;\r
505                                 buf = FX_Alloc(FX_BYTE, dwSize);\r
506                                 if (buf == NULL) {\r
507                                     return FALSE;\r
508                                 }\r
509                                 if (dwSize > 4) {\r
510                                     FXSYS_memcpy32(buf, old_data + m_readDword(head), dwSize);\r
511                                 } else {\r
512                                     FXSYS_memcpy32(buf, head, dwSize);\r
513                                 }\r
514                                 temp = buf;\r
515                                 val = FX_Alloc(FX_BYTE, dwSize / 2);\r
516                                 if (val == NULL) {\r
517                                     FX_Free(buf);\r
518                                     return FALSE;\r
519                                 }\r
520                                 for(i = 0; i < (int)dwModuleNum; i ++) {\r
521                                     *(FX_DWORD*)temp = m_readDword(temp);\r
522                                     *(FX_DWORD*)(temp + 4) = m_readDword(temp + 4);\r
523                                     FX_DWORD* lNumerator = (FX_DWORD*)temp;\r
524                                     FX_DWORD* lNenominator = (FX_DWORD*)(temp + 4);\r
525                                     *(FX_FLOAT*)(val + i * 4) = (FX_FLOAT)(*lNumerator) / (FX_FLOAT)(*lNenominator);\r
526                                     temp += 8;\r
527                                 }\r
528                                 FX_Free(buf);\r
529                             }\r
530                             break;\r
531                         case FX_DoubleFloat:\r
532                             dwSize = dwModuleNum << 3;\r
533                             val = FX_Alloc(FX_BYTE, dwSize);\r
534                             if (val == NULL) {\r
535                                 return FALSE;\r
536                             }\r
537                             if (dwSize > 4) {\r
538                                 FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);\r
539                             } else {\r
540                                 FXSYS_memcpy32(val, head, dwSize);\r
541                             }\r
542                             buf = val;\r
543                             for(i = 0; i < (int)dwModuleNum; i ++) {\r
544                                 *(FX_DWORD*)buf = m_readDword(buf);\r
545                                 *(FX_DWORD*)(buf + 4) = m_readDword(buf + 4);\r
546                                 buf += 8;\r
547                             }\r
548                             break;\r
549                         default:\r
550                             return FALSE;\r
551                     }\r
552                 }\r
553                 pVal->SetAt(tag, val);\r
554             }\r
555             return TRUE;\r
556         }\r
557     }\r
558     return FALSE;\r
559 }\r
560 #define FXEXIF_INFOCONVERT(T) {T* src = (T*)ptr;        T* dst = (T*)val;       *dst = *src;}\r
561 FX_BOOL CFX_DIBAttributeExif::GetInfo( FX_WORD tag, FX_LPVOID val )\r
562 {\r
563     if (m_TagVal.GetCount() == 0) {\r
564         if (!ParseExif(&m_TagHead, m_pExifData, m_dwExifDataLen, &m_TagVal)) {\r
565             return FALSE;\r
566         }\r
567     }\r
568     FX_LPBYTE ptr = NULL;\r
569     if (m_TagVal.Lookup(tag, ptr)) {\r
570         switch (tag) {\r
571             case EXIFTAG_USHORT_RESUNIT:\r
572                 FXEXIF_INFOCONVERT(FX_WORD);\r
573                 {\r
574                     FX_WORD* ptr = (FX_WORD*)val;\r
575                     *ptr -= 1;\r
576                 }\r
577                 break;\r
578             case EXIFTAG_FLOAT_DPIX:\r
579             case EXIFTAG_FLOAT_DPIY:\r
580                 FXEXIF_INFOCONVERT(FX_FLOAT);\r
581                 break;\r
582             case EXIFTAG_USHORT_ORIENTATION:\r
583                 FXEXIF_INFOCONVERT(FX_WORD);\r
584                 break;\r
585             default: {\r
586                     FX_LPBYTE* dst = (FX_LPBYTE*)val;\r
587                     *dst = ptr;\r
588                 }\r
589         }\r
590     }\r
591     return TRUE;\r
592 }\r
593 class CCodec_RLScanlineDecoder : public CCodec_ScanlineDecoder
594 {
595 public:
596     CCodec_RLScanlineDecoder();
597     virtual ~CCodec_RLScanlineDecoder();
598     FX_BOOL                             Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, int nComps, int bpc);
599     virtual void                v_DownScale(int dest_width, int dest_height) {}
600     virtual FX_BOOL             v_Rewind();
601     virtual FX_LPBYTE   v_GetNextLine();
602     virtual FX_DWORD    GetSrcOffset()
603     {
604         return m_SrcOffset;
605     }
606 protected:
607     FX_BOOL                             CheckDestSize();
608     void                                GetNextOperator();
609     void                                UpdateOperator(FX_BYTE used_bytes);
610
611     FX_LPBYTE                   m_pScanline;
612     FX_LPCBYTE                  m_pSrcBuf;
613     FX_DWORD                    m_SrcSize;
614     FX_DWORD                    m_dwLineBytes;
615     FX_DWORD                    m_SrcOffset;
616     FX_BOOL                             m_bEOD;
617     FX_BYTE                             m_Operator;
618 };
619 CCodec_RLScanlineDecoder::CCodec_RLScanlineDecoder()
620     : m_pScanline(NULL)
621     , m_pSrcBuf(NULL)
622     , m_SrcSize(0)
623     , m_dwLineBytes(0)
624     , m_SrcOffset(0)
625     , m_bEOD(FALSE)
626     , m_Operator(0)
627 {
628 }
629 CCodec_RLScanlineDecoder::~CCodec_RLScanlineDecoder()
630 {
631     if (m_pScanline) {
632         FX_Free(m_pScanline);
633     }
634 }
635 FX_BOOL CCodec_RLScanlineDecoder::CheckDestSize()
636 {
637     FX_DWORD i = 0;
638     FX_DWORD old_size = 0;
639     FX_DWORD dest_size = 0;
640     while (i < m_SrcSize) {
641         if (m_pSrcBuf[i] < 128) {
642             old_size = dest_size;
643             dest_size += m_pSrcBuf[i] + 1;
644             if (dest_size < old_size) {
645                 return FALSE;
646             }
647             i += m_pSrcBuf[i] + 2;
648         } else if (m_pSrcBuf[i] > 128) {
649             old_size = dest_size;
650             dest_size += 257 - m_pSrcBuf[i];
651             if (dest_size < old_size) {
652                 return FALSE;
653             }
654             i += 2;
655         } else {
656             break;
657         }
658     }
659     if (((FX_DWORD)m_OrigWidth * m_nComps * m_bpc * m_OrigHeight + 7) / 8 > dest_size) {
660         return FALSE;
661     }
662     return TRUE;
663 }
664 FX_BOOL CCodec_RLScanlineDecoder::Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, int nComps, int bpc)
665 {
666     m_pSrcBuf = src_buf;
667     m_SrcSize = src_size;
668     m_OutputWidth = m_OrigWidth = width;
669     m_OutputHeight = m_OrigHeight = height;
670     m_nComps = nComps;
671     m_bpc = bpc;
672     m_bColorTransformed = FALSE;
673     m_DownScale = 1;
674     m_Pitch = (width * nComps * bpc + 31) / 32 * 4;
675     m_dwLineBytes = (width * nComps * bpc + 7) / 8;
676     m_pScanline = FX_Alloc(FX_BYTE, m_Pitch);
677     if (m_pScanline == NULL) {
678         return FALSE;
679     }
680     return CheckDestSize();
681 }
682 FX_BOOL CCodec_RLScanlineDecoder::v_Rewind()
683 {
684     FXSYS_memset32(m_pScanline, 0, m_Pitch);
685     m_SrcOffset = 0;
686     m_bEOD = FALSE;
687     m_Operator = 0;
688     return TRUE;
689 }
690 FX_LPBYTE CCodec_RLScanlineDecoder::v_GetNextLine()
691 {
692     if (m_SrcOffset == 0) {
693         GetNextOperator();
694     } else {
695         if (m_bEOD) {
696             return NULL;
697         }
698     }
699     FXSYS_memset32(m_pScanline, 0, m_Pitch);
700     FX_DWORD col_pos = 0;
701     FX_BOOL     eol = FALSE;
702     while (m_SrcOffset < m_SrcSize && !eol) {
703         if (m_Operator < 128) {
704             FX_DWORD copy_len = m_Operator + 1;
705             if (col_pos + copy_len >= m_dwLineBytes) {
706                 copy_len = m_dwLineBytes - col_pos;
707                 eol = TRUE;
708             }
709             if (copy_len >= m_SrcSize - m_SrcOffset) {
710                 copy_len = m_SrcSize - m_SrcOffset;
711                 m_bEOD = TRUE;
712             }
713             FXSYS_memcpy32(m_pScanline + col_pos, m_pSrcBuf + m_SrcOffset, copy_len);
714             col_pos += copy_len;
715             UpdateOperator((FX_BYTE)copy_len);
716         } else if (m_Operator > 128) {
717             int fill = 0;
718             if (m_SrcOffset - 1 < m_SrcSize - 1) {
719                 fill = m_pSrcBuf[m_SrcOffset];
720             }
721             FX_DWORD duplicate_len = 257 - m_Operator;
722             if (col_pos + duplicate_len >= m_dwLineBytes) {
723                 duplicate_len = m_dwLineBytes - col_pos;
724                 eol = TRUE;
725             }
726             FXSYS_memset8(m_pScanline + col_pos, fill, duplicate_len);
727             col_pos += duplicate_len;
728             UpdateOperator((FX_BYTE)duplicate_len);
729         } else {
730             m_bEOD = TRUE;
731             break;
732         }
733     }
734     return m_pScanline;
735 }
736 void CCodec_RLScanlineDecoder::GetNextOperator()
737 {
738     if (m_SrcOffset >= m_SrcSize) {
739         m_Operator = 128;
740         return;
741     }
742     m_Operator = m_pSrcBuf[m_SrcOffset];
743     m_SrcOffset ++;
744 }
745 void CCodec_RLScanlineDecoder::UpdateOperator(FX_BYTE used_bytes)
746 {
747     if (used_bytes == 0) {
748         return;
749     }
750     if (m_Operator < 128) {
751         FXSYS_assert((FX_DWORD)m_Operator + 1 >= used_bytes);
752         if (used_bytes == m_Operator + 1) {
753             m_SrcOffset += used_bytes;
754             GetNextOperator();
755             return;
756         }
757         m_Operator -= used_bytes;
758         m_SrcOffset += used_bytes;
759         if (m_SrcOffset >= m_SrcSize) {
760             m_Operator = 128;
761         }
762         return;
763     }
764     FX_BYTE count = 257 - m_Operator;
765     FXSYS_assert((FX_DWORD)count >= used_bytes);
766     if (used_bytes == count) {
767         m_SrcOffset ++;
768         GetNextOperator();
769         return;
770     }
771     count -= used_bytes;
772     m_Operator = 257 - count;
773 }
774 ICodec_ScanlineDecoder* CCodec_BasicModule::CreateRunLengthDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
775         int nComps, int bpc)
776 {
777     CCodec_RLScanlineDecoder* pRLScanlineDecoder = FX_NEW CCodec_RLScanlineDecoder;
778     if (pRLScanlineDecoder == NULL) {
779         return NULL;
780     }
781     if (!pRLScanlineDecoder->Create(src_buf, src_size, width, height, nComps, bpc)) {
782         delete pRLScanlineDecoder;
783         return NULL;
784     }
785     return pRLScanlineDecoder;
786 }