Merge to XFA: Use stdint.h types throughout PDFium.
[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 = new CCodec_BasicModule;
12     m_pFaxModule = new CCodec_FaxModule;
13     m_pJpegModule = new CCodec_JpegModule;
14     m_pJpxModule = new CCodec_JpxModule;
15     m_pJbig2Module = new CCodec_Jbig2Module;
16     m_pIccModule = new CCodec_IccModule;
17     m_pPngModule = new CCodec_PngModule;
18     m_pGifModule = new CCodec_GifModule;
19     m_pBmpModule = new CCodec_BmpModule;
20     m_pTiffModule = new CCodec_TiffModule;
21     m_pFlateModule = 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_TryAlloc(uint8_t, 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 uint8_t* 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 uint8_t* 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 new CCodec_ModuleMgr;
251 }
252 void CCodec_ModuleMgr::Destroy()
253 {
254     delete this;
255 }
256 CFX_DIBAttribute::CFX_DIBAttribute()
257 {
258     FXSYS_memset32(this, 0, sizeof(CFX_DIBAttribute));
259     m_nXDPI = -1;
260     m_nYDPI = -1;
261     m_fAspectRatio = -1.0f;
262     m_pExif = new CFX_DIBAttributeExif;
263 }
264 CFX_DIBAttribute::~CFX_DIBAttribute()
265 {
266     if (m_pExif) {
267         delete m_pExif;
268     }
269 }
270 CFX_DIBAttributeExif::CFX_DIBAttributeExif()
271 {
272     m_pExifData = NULL;
273     m_dwExifDataLen = 0;
274 }
275 CFX_DIBAttributeExif::~CFX_DIBAttributeExif()
276 {
277     clear();
278 }
279 void CFX_DIBAttributeExif::clear()
280 {
281     if (m_pExifData) {
282         FX_Free(m_pExifData);
283     }
284     m_pExifData = NULL;
285     FX_DWORD key = 0;
286     FX_LPBYTE buf = NULL;
287     FX_POSITION pos = NULL;
288     pos = m_TagHead.GetStartPosition();
289     while (pos) {
290         m_TagHead.GetNextAssoc(pos, key, buf);
291         if (buf) {
292             FX_Free(buf);
293         }
294     }
295     m_TagHead.RemoveAll();
296     pos = m_TagVal.GetStartPosition();
297     while (pos) {
298         m_TagVal.GetNextAssoc(pos, key, buf);
299         if (buf) {
300             FX_Free(buf);
301         }
302     }
303     m_TagVal.RemoveAll();
304 }
305 static FX_WORD _Read2BytesL(FX_LPBYTE data)
306 {
307     ASSERT(data);
308     return data[0] | (data[1] << 8);
309 }
310 static FX_WORD _Read2BytesB(FX_LPBYTE data)
311 {
312     ASSERT(data);
313     return data[1] | (data[0] << 8);
314 }
315 static FX_DWORD _Read4BytesL(FX_LPBYTE data)
316 {
317     return _Read2BytesL(data) | (_Read2BytesL(data + 2) << 16);
318 }
319 static FX_DWORD _Read4BytesB(FX_LPBYTE data)
320 {
321     return _Read2BytesB(data + 2) | (_Read2BytesB(data) << 16);
322 }
323 typedef FX_WORD (*_Read2Bytes) (FX_LPBYTE data);
324 typedef FX_DWORD (*_Read4Bytes) (FX_LPBYTE data);
325 typedef void (*_Write2Bytes) (FX_LPBYTE data, FX_WORD val);
326 typedef void (*_Write4Bytes) (FX_LPBYTE data, FX_DWORD val);
327 FX_LPBYTE CFX_DIBAttributeExif::ParseExifIFH(FX_LPBYTE data, FX_DWORD len, _Read2Bytes* pReadWord, _Read4Bytes* pReadDword)
328 {
329     if (len > 8) {
330         FX_BOOL tag = FALSE;
331         if (FXSYS_memcmp32(data, "\x49\x49\x2a\x00", 4) == 0) {
332             if (pReadWord) {
333                 *pReadWord = _Read2BytesL;
334             }
335             if (pReadDword) {
336                 *pReadDword = _Read4BytesL;
337             }
338             tag = TRUE;
339         } else if (FXSYS_memcmp32(data, "\x4d\x4d\x00\x2a", 4) == 0) {
340             if (pReadWord) {
341                 *pReadWord = _Read2BytesB;
342             }
343             if (pReadDword) {
344                 *pReadDword = _Read4BytesB;
345             }
346             tag = TRUE;
347         }
348         if (tag) {
349             data += 4;
350             if (pReadDword) {
351                 data += (*pReadDword)(data) - 4;
352             } else {
353                 data += 4;
354             }
355         }
356     }
357     return data;
358 }
359 FX_BOOL CFX_DIBAttributeExif::ParseExifIFD(CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE>* pMap, FX_LPBYTE data, FX_DWORD len)
360 {
361     if (pMap && data) {
362         if (len > 8) {
363             FX_WORD wTagNum = m_readWord(data);
364             data += 2;
365             FX_DWORD wTag;
366             FX_LPBYTE buf;
367             while (wTagNum--) {
368                 wTag = m_readWord(data);
369                 data += 2;
370                 if (!pMap->Lookup(wTag, buf)) {
371                     buf = FX_Alloc(uint8_t, 10);
372                     if (buf == NULL) {
373                         return FALSE;
374                     }
375                     FXSYS_memcpy32(buf, data, 10);
376                     pMap->SetAt(wTag, buf);
377                 }
378                 data += 10;
379             }
380             FX_DWORD dwIFDOffset;
381             dwIFDOffset = m_readDword(data);
382             while (dwIFDOffset && dwIFDOffset < len) {
383                 data = m_pExifData + dwIFDOffset;
384                 wTagNum = m_readWord(data);
385                 data += 2;
386                 while (wTagNum--) {
387                     wTag = m_readWord(data);
388                     data += 2;
389                     if (!pMap->Lookup(wTag, buf)) {
390                         buf = FX_Alloc(uint8_t, 10);
391                         if (buf == NULL) {
392                             return FALSE;
393                         }
394                         FXSYS_memcpy32(buf, data, 10);
395                         pMap->SetAt(wTag, buf);
396                     }
397                     data += 10;
398                 }
399                 dwIFDOffset = m_readDword(data);
400             }
401             return TRUE;
402         }
403     }
404     return FALSE;
405 }
406 enum FX_ExifDataType {
407     FX_UnsignedByte = 1,
408     FX_AscString,
409     FX_UnsignedShort,
410     FX_UnsignedLong,
411     FX_UnsignedRation,
412     FX_SignedByte,
413     FX_Undefined,
414     FX_SignedShort,
415     FX_SignedLong,
416     FX_SignedRation,
417     FX_SignedFloat,
418     FX_DoubleFloat
419 };
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)
421 {
422     if (pHead && data && pVal) {
423         if (len > 8) {
424             FX_LPBYTE old_data = data;
425             data = ParseExifIFH(data, len, &m_readWord, &m_readDword);
426             if (data == old_data) {
427                 return FALSE;
428             }
429             if (pHead->GetCount() == 0) {
430                 if (!ParseExifIFD(pHead, data, len)) {
431                     return FALSE;
432                 }
433             }
434             FX_DWORD dwModuleNum;
435             FX_WORD type;
436             FX_DWORD dwSize;
437             FX_DWORD tag;
438             FX_LPBYTE head;
439             FX_POSITION pos = pHead->GetStartPosition();
440             while (pos) {
441                 pHead->GetNextAssoc(pos, tag, head);
442                 FX_LPBYTE val = NULL, buf = NULL, temp = NULL;
443                 int i;
444                 if (head) {
445                     type = m_readWord(head);
446                     head += 2;
447                     dwModuleNum = m_readDword(head);
448                     head += 4;
449                     switch (type) {
450                         case FX_UnsignedByte:
451                         case FX_AscString:
452                         case FX_SignedByte:
453                         case FX_Undefined:
454                             dwSize = dwModuleNum;
455                             val = FX_Alloc(uint8_t, dwSize);
456                             if (val == NULL) {
457                                 return FALSE;
458                             }
459                             if (dwSize > 4) {
460                                 FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);
461                             } else {
462                                 FXSYS_memcpy32(val, head, dwSize);
463                             }
464                             break;
465                         case FX_UnsignedShort:
466                         case FX_SignedShort:
467                             dwSize = dwModuleNum << 1;
468                             val = FX_Alloc(uint8_t, dwSize);
469                             if (val == NULL) {
470                                 return FALSE;
471                             }
472                             if (dwSize > 4) {
473                                 FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);
474                             } else {
475                                 FXSYS_memcpy32(val, head, dwSize);
476                             }
477                             buf = val;
478                             for(i = 0; i < (int)dwModuleNum; i ++) {
479                                 *(FX_WORD*)buf = m_readWord(buf);
480                                 buf += 2;
481                             }
482                             break;
483                         case FX_UnsignedLong:
484                         case FX_SignedLong:
485                         case FX_SignedFloat:
486                             dwSize = dwModuleNum << 2;
487                             val = FX_Alloc(uint8_t, dwSize);
488                             if (val == NULL) {
489                                 return FALSE;
490                             }
491                             if (dwSize > 4) {
492                                 FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);
493                             } else {
494                                 FXSYS_memcpy32(val, head, dwSize);
495                             }
496                             buf = val;
497                             for(i = 0; i < (int)dwModuleNum; i ++) {
498                                 *(FX_DWORD*)buf = m_readDword(buf);
499                                 buf += 4;
500                             }
501                             break;
502                         case FX_UnsignedRation:
503                         case FX_SignedRation: {
504                                 dwSize = dwModuleNum << 3;
505                                 buf = FX_Alloc(uint8_t, dwSize);
506                                 if (buf == NULL) {
507                                     return FALSE;
508                                 }
509                                 if (dwSize > 4) {
510                                     FXSYS_memcpy32(buf, old_data + m_readDword(head), dwSize);
511                                 } else {
512                                     FXSYS_memcpy32(buf, head, dwSize);
513                                 }
514                                 temp = buf;
515                                 val = FX_Alloc(uint8_t, dwSize / 2);
516                                 if (val == NULL) {
517                                     FX_Free(buf);
518                                     return FALSE;
519                                 }
520                                 for(i = 0; i < (int)dwModuleNum; i ++) {
521                                     *(FX_DWORD*)temp = m_readDword(temp);
522                                     *(FX_DWORD*)(temp + 4) = m_readDword(temp + 4);
523                                     FX_DWORD* lNumerator = (FX_DWORD*)temp;
524                                     FX_DWORD* lNenominator = (FX_DWORD*)(temp + 4);
525                                     *(FX_FLOAT*)(val + i * 4) = (FX_FLOAT)(*lNumerator) / (FX_FLOAT)(*lNenominator);
526                                     temp += 8;
527                                 }
528                                 FX_Free(buf);
529                             }
530                             break;
531                         case FX_DoubleFloat:
532                             dwSize = dwModuleNum << 3;
533                             val = FX_Alloc(uint8_t, dwSize);
534                             if (val == NULL) {
535                                 return FALSE;
536                             }
537                             if (dwSize > 4) {
538                                 FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);
539                             } else {
540                                 FXSYS_memcpy32(val, head, dwSize);
541                             }
542                             buf = val;
543                             for(i = 0; i < (int)dwModuleNum; i ++) {
544                                 *(FX_DWORD*)buf = m_readDword(buf);
545                                 *(FX_DWORD*)(buf + 4) = m_readDword(buf + 4);
546                                 buf += 8;
547                             }
548                             break;
549                         default:
550                             return FALSE;
551                     }
552                 }
553                 pVal->SetAt(tag, val);
554             }
555             return TRUE;
556         }
557     }
558     return FALSE;
559 }
560 #define FXEXIF_INFOCONVERT(T) {T* src = (T*)ptr;        T* dst = (T*)val;       *dst = *src;}
561 FX_BOOL CFX_DIBAttributeExif::GetInfo( FX_WORD tag, FX_LPVOID val )
562 {
563     if (m_TagVal.GetCount() == 0) {
564         if (!ParseExif(&m_TagHead, m_pExifData, m_dwExifDataLen, &m_TagVal)) {
565             return FALSE;
566         }
567     }
568     FX_LPBYTE ptr = NULL;
569     if (m_TagVal.Lookup(tag, ptr)) {
570         switch (tag) {
571             case EXIFTAG_USHORT_RESUNIT:
572                 FXEXIF_INFOCONVERT(FX_WORD);
573                 {
574                     FX_WORD* ptr = (FX_WORD*)val;
575                     *ptr -= 1;
576                 }
577                 break;
578             case EXIFTAG_FLOAT_DPIX:
579             case EXIFTAG_FLOAT_DPIY:
580                 FXEXIF_INFOCONVERT(FX_FLOAT);
581                 break;
582             case EXIFTAG_USHORT_ORIENTATION:
583                 FXEXIF_INFOCONVERT(FX_WORD);
584                 break;
585             default: {
586                     FX_LPBYTE* dst = (FX_LPBYTE*)val;
587                     *dst = ptr;
588                 }
589         }
590     }
591     return TRUE;
592 }
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(uint8_t 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     uint8_t                             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(uint8_t, m_Pitch);
677     return CheckDestSize();
678 }
679 FX_BOOL CCodec_RLScanlineDecoder::v_Rewind()
680 {
681     FXSYS_memset32(m_pScanline, 0, m_Pitch);
682     m_SrcOffset = 0;
683     m_bEOD = FALSE;
684     m_Operator = 0;
685     return TRUE;
686 }
687 FX_LPBYTE CCodec_RLScanlineDecoder::v_GetNextLine()
688 {
689     if (m_SrcOffset == 0) {
690         GetNextOperator();
691     } else {
692         if (m_bEOD) {
693             return NULL;
694         }
695     }
696     FXSYS_memset32(m_pScanline, 0, m_Pitch);
697     FX_DWORD col_pos = 0;
698     FX_BOOL     eol = FALSE;
699     while (m_SrcOffset < m_SrcSize && !eol) {
700         if (m_Operator < 128) {
701             FX_DWORD copy_len = m_Operator + 1;
702             if (col_pos + copy_len >= m_dwLineBytes) {
703                 copy_len = m_dwLineBytes - col_pos;
704                 eol = TRUE;
705             }
706             if (copy_len >= m_SrcSize - m_SrcOffset) {
707                 copy_len = m_SrcSize - m_SrcOffset;
708                 m_bEOD = TRUE;
709             }
710             FXSYS_memcpy32(m_pScanline + col_pos, m_pSrcBuf + m_SrcOffset, copy_len);
711             col_pos += copy_len;
712             UpdateOperator((uint8_t)copy_len);
713         } else if (m_Operator > 128) {
714             int fill = 0;
715             if (m_SrcOffset - 1 < m_SrcSize - 1) {
716                 fill = m_pSrcBuf[m_SrcOffset];
717             }
718             FX_DWORD duplicate_len = 257 - m_Operator;
719             if (col_pos + duplicate_len >= m_dwLineBytes) {
720                 duplicate_len = m_dwLineBytes - col_pos;
721                 eol = TRUE;
722             }
723             FXSYS_memset8(m_pScanline + col_pos, fill, duplicate_len);
724             col_pos += duplicate_len;
725             UpdateOperator((uint8_t)duplicate_len);
726         } else {
727             m_bEOD = TRUE;
728             break;
729         }
730     }
731     return m_pScanline;
732 }
733 void CCodec_RLScanlineDecoder::GetNextOperator()
734 {
735     if (m_SrcOffset >= m_SrcSize) {
736         m_Operator = 128;
737         return;
738     }
739     m_Operator = m_pSrcBuf[m_SrcOffset];
740     m_SrcOffset ++;
741 }
742 void CCodec_RLScanlineDecoder::UpdateOperator(uint8_t used_bytes)
743 {
744     if (used_bytes == 0) {
745         return;
746     }
747     if (m_Operator < 128) {
748         FXSYS_assert((FX_DWORD)m_Operator + 1 >= used_bytes);
749         if (used_bytes == m_Operator + 1) {
750             m_SrcOffset += used_bytes;
751             GetNextOperator();
752             return;
753         }
754         m_Operator -= used_bytes;
755         m_SrcOffset += used_bytes;
756         if (m_SrcOffset >= m_SrcSize) {
757             m_Operator = 128;
758         }
759         return;
760     }
761     uint8_t count = 257 - m_Operator;
762     FXSYS_assert((FX_DWORD)count >= used_bytes);
763     if (used_bytes == count) {
764         m_SrcOffset ++;
765         GetNextOperator();
766         return;
767     }
768     count -= used_bytes;
769     m_Operator = 257 - count;
770 }
771 ICodec_ScanlineDecoder* CCodec_BasicModule::CreateRunLengthDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
772         int nComps, int bpc)
773 {
774     CCodec_RLScanlineDecoder* pRLScanlineDecoder = new CCodec_RLScanlineDecoder;
775     if (!pRLScanlineDecoder->Create(src_buf, src_size, width, height, nComps, bpc)) {
776         delete pRLScanlineDecoder;
777         return NULL;
778     }
779     return pRLScanlineDecoder;
780 }