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