Merge to XFA: Kill FXSYS_mem{cpy,cmp,set.move}{32,8}.
[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 uint8_t* 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 uint8_t* CCodec_ScanlineDecoder::ReadNextLine()
99 {
100     uint8_t* pLine = v_GetNextLine();
101     if (pLine == NULL) {
102         return NULL;
103     }
104     if (m_pDataCache && m_NextLine == m_pDataCache->m_nCachedLines) {
105         FXSYS_memcpy(&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, uint8_t*& 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, uint8_t*& 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_memset(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     uint8_t* 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(uint8_t* data)
306 {
307     ASSERT(data);
308     return data[0] | (data[1] << 8);
309 }
310 static FX_WORD _Read2BytesB(uint8_t* data)
311 {
312     ASSERT(data);
313     return data[1] | (data[0] << 8);
314 }
315 static FX_DWORD _Read4BytesL(uint8_t* data)
316 {
317     return _Read2BytesL(data) | (_Read2BytesL(data + 2) << 16);
318 }
319 static FX_DWORD _Read4BytesB(uint8_t* data)
320 {
321     return _Read2BytesB(data + 2) | (_Read2BytesB(data) << 16);
322 }
323 typedef FX_WORD (*_Read2Bytes) (uint8_t* data);
324 typedef FX_DWORD (*_Read4Bytes) (uint8_t* data);
325 typedef void (*_Write2Bytes) (uint8_t* data, FX_WORD val);
326 typedef void (*_Write4Bytes) (uint8_t* data, FX_DWORD val);
327 uint8_t* CFX_DIBAttributeExif::ParseExifIFH(uint8_t* data, FX_DWORD len, _Read2Bytes* pReadWord, _Read4Bytes* pReadDword)
328 {
329     if (len > 8) {
330         FX_BOOL tag = FALSE;
331         if (FXSYS_memcmp(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_memcmp(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, uint8_t*>* pMap, uint8_t* 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             uint8_t* 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_memcpy(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_memcpy(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, uint8_t*>* pHead, uint8_t* data, FX_DWORD len, CFX_MapPtrTemplate<FX_DWORD, uint8_t*>* pVal)
421 {
422     if (pHead && data && pVal) {
423         if (len > 8) {
424             uint8_t* 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             uint8_t* head;
439             FX_POSITION pos = pHead->GetStartPosition();
440             while (pos) {
441                 pHead->GetNextAssoc(pos, tag, head);
442                 uint8_t* val = NULL;
443                 uint8_t* buf = NULL;
444                 uint8_t* temp = NULL;
445                 int i;
446                 if (head) {
447                     type = m_readWord(head);
448                     head += 2;
449                     dwModuleNum = m_readDword(head);
450                     head += 4;
451                     switch (type) {
452                         case FX_UnsignedByte:
453                         case FX_AscString:
454                         case FX_SignedByte:
455                         case FX_Undefined:
456                             dwSize = dwModuleNum;
457                             val = FX_Alloc(uint8_t, dwSize);
458                             if (val == NULL) {
459                                 return FALSE;
460                             }
461                             if (dwSize > 4) {
462                                 FXSYS_memcpy(val, old_data + m_readDword(head), dwSize);
463                             } else {
464                                 FXSYS_memcpy(val, head, dwSize);
465                             }
466                             break;
467                         case FX_UnsignedShort:
468                         case FX_SignedShort:
469                             dwSize = dwModuleNum << 1;
470                             val = FX_Alloc(uint8_t, dwSize);
471                             if (val == NULL) {
472                                 return FALSE;
473                             }
474                             if (dwSize > 4) {
475                                 FXSYS_memcpy(val, old_data + m_readDword(head), dwSize);
476                             } else {
477                                 FXSYS_memcpy(val, head, dwSize);
478                             }
479                             buf = val;
480                             for(i = 0; i < (int)dwModuleNum; i ++) {
481                                 *(FX_WORD*)buf = m_readWord(buf);
482                                 buf += 2;
483                             }
484                             break;
485                         case FX_UnsignedLong:
486                         case FX_SignedLong:
487                         case FX_SignedFloat:
488                             dwSize = dwModuleNum << 2;
489                             val = FX_Alloc(uint8_t, dwSize);
490                             if (val == NULL) {
491                                 return FALSE;
492                             }
493                             if (dwSize > 4) {
494                                 FXSYS_memcpy(val, old_data + m_readDword(head), dwSize);
495                             } else {
496                                 FXSYS_memcpy(val, head, dwSize);
497                             }
498                             buf = val;
499                             for(i = 0; i < (int)dwModuleNum; i ++) {
500                                 *(FX_DWORD*)buf = m_readDword(buf);
501                                 buf += 4;
502                             }
503                             break;
504                         case FX_UnsignedRation:
505                         case FX_SignedRation: {
506                                 dwSize = dwModuleNum << 3;
507                                 buf = FX_Alloc(uint8_t, dwSize);
508                                 if (buf == NULL) {
509                                     return FALSE;
510                                 }
511                                 if (dwSize > 4) {
512                                     FXSYS_memcpy(buf, old_data + m_readDword(head), dwSize);
513                                 } else {
514                                     FXSYS_memcpy(buf, head, dwSize);
515                                 }
516                                 temp = buf;
517                                 val = FX_Alloc(uint8_t, dwSize / 2);
518                                 if (val == NULL) {
519                                     FX_Free(buf);
520                                     return FALSE;
521                                 }
522                                 for(i = 0; i < (int)dwModuleNum; i ++) {
523                                     *(FX_DWORD*)temp = m_readDword(temp);
524                                     *(FX_DWORD*)(temp + 4) = m_readDword(temp + 4);
525                                     FX_DWORD* lNumerator = (FX_DWORD*)temp;
526                                     FX_DWORD* lNenominator = (FX_DWORD*)(temp + 4);
527                                     *(FX_FLOAT*)(val + i * 4) = (FX_FLOAT)(*lNumerator) / (FX_FLOAT)(*lNenominator);
528                                     temp += 8;
529                                 }
530                                 FX_Free(buf);
531                             }
532                             break;
533                         case FX_DoubleFloat:
534                             dwSize = dwModuleNum << 3;
535                             val = FX_Alloc(uint8_t, dwSize);
536                             if (val == NULL) {
537                                 return FALSE;
538                             }
539                             if (dwSize > 4) {
540                                 FXSYS_memcpy(val, old_data + m_readDword(head), dwSize);
541                             } else {
542                                 FXSYS_memcpy(val, head, dwSize);
543                             }
544                             buf = val;
545                             for(i = 0; i < (int)dwModuleNum; i ++) {
546                                 *(FX_DWORD*)buf = m_readDword(buf);
547                                 *(FX_DWORD*)(buf + 4) = m_readDword(buf + 4);
548                                 buf += 8;
549                             }
550                             break;
551                         default:
552                             return FALSE;
553                     }
554                 }
555                 pVal->SetAt(tag, val);
556             }
557             return TRUE;
558         }
559     }
560     return FALSE;
561 }
562 #define FXEXIF_INFOCONVERT(T) {T* src = (T*)ptr;        T* dst = (T*)val;       *dst = *src;}
563 FX_BOOL CFX_DIBAttributeExif::GetInfo( FX_WORD tag, void* val )
564 {
565     if (m_TagVal.GetCount() == 0) {
566         if (!ParseExif(&m_TagHead, m_pExifData, m_dwExifDataLen, &m_TagVal)) {
567             return FALSE;
568         }
569     }
570     uint8_t* ptr = NULL;
571     if (m_TagVal.Lookup(tag, ptr)) {
572         switch (tag) {
573             case EXIFTAG_USHORT_RESUNIT:
574                 FXEXIF_INFOCONVERT(FX_WORD);
575                 {
576                     FX_WORD* ptr = (FX_WORD*)val;
577                     *ptr -= 1;
578                 }
579                 break;
580             case EXIFTAG_FLOAT_DPIX:
581             case EXIFTAG_FLOAT_DPIY:
582                 FXEXIF_INFOCONVERT(FX_FLOAT);
583                 break;
584             case EXIFTAG_USHORT_ORIENTATION:
585                 FXEXIF_INFOCONVERT(FX_WORD);
586                 break;
587             default: {
588                     uint8_t** dst = (uint8_t**)val;
589                     *dst = ptr;
590                 }
591         }
592     }
593     return TRUE;
594 }
595 class CCodec_RLScanlineDecoder : public CCodec_ScanlineDecoder
596 {
597 public:
598     CCodec_RLScanlineDecoder();
599     virtual ~CCodec_RLScanlineDecoder();
600     FX_BOOL                             Create(const uint8_t* src_buf, FX_DWORD src_size, int width, int height, int nComps, int bpc);
601     virtual void                v_DownScale(int dest_width, int dest_height) {}
602     virtual FX_BOOL             v_Rewind();
603     virtual uint8_t*    v_GetNextLine();
604     virtual FX_DWORD    GetSrcOffset()
605     {
606         return m_SrcOffset;
607     }
608 protected:
609     FX_BOOL                             CheckDestSize();
610     void                                GetNextOperator();
611     void                                UpdateOperator(uint8_t used_bytes);
612
613     uint8_t*                    m_pScanline;
614     const uint8_t*                      m_pSrcBuf;
615     FX_DWORD                    m_SrcSize;
616     FX_DWORD                    m_dwLineBytes;
617     FX_DWORD                    m_SrcOffset;
618     FX_BOOL                             m_bEOD;
619     uint8_t                             m_Operator;
620 };
621 CCodec_RLScanlineDecoder::CCodec_RLScanlineDecoder()
622     : m_pScanline(NULL)
623     , m_pSrcBuf(NULL)
624     , m_SrcSize(0)
625     , m_dwLineBytes(0)
626     , m_SrcOffset(0)
627     , m_bEOD(FALSE)
628     , m_Operator(0)
629 {
630 }
631 CCodec_RLScanlineDecoder::~CCodec_RLScanlineDecoder()
632 {
633     if (m_pScanline) {
634         FX_Free(m_pScanline);
635     }
636 }
637 FX_BOOL CCodec_RLScanlineDecoder::CheckDestSize()
638 {
639     FX_DWORD i = 0;
640     FX_DWORD old_size = 0;
641     FX_DWORD dest_size = 0;
642     while (i < m_SrcSize) {
643         if (m_pSrcBuf[i] < 128) {
644             old_size = dest_size;
645             dest_size += m_pSrcBuf[i] + 1;
646             if (dest_size < old_size) {
647                 return FALSE;
648             }
649             i += m_pSrcBuf[i] + 2;
650         } else if (m_pSrcBuf[i] > 128) {
651             old_size = dest_size;
652             dest_size += 257 - m_pSrcBuf[i];
653             if (dest_size < old_size) {
654                 return FALSE;
655             }
656             i += 2;
657         } else {
658             break;
659         }
660     }
661     if (((FX_DWORD)m_OrigWidth * m_nComps * m_bpc * m_OrigHeight + 7) / 8 > dest_size) {
662         return FALSE;
663     }
664     return TRUE;
665 }
666 FX_BOOL CCodec_RLScanlineDecoder::Create(const uint8_t* src_buf, FX_DWORD src_size, int width, int height, int nComps, int bpc)
667 {
668     m_pSrcBuf = src_buf;
669     m_SrcSize = src_size;
670     m_OutputWidth = m_OrigWidth = width;
671     m_OutputHeight = m_OrigHeight = height;
672     m_nComps = nComps;
673     m_bpc = bpc;
674     m_bColorTransformed = FALSE;
675     m_DownScale = 1;
676     m_Pitch = (width * nComps * bpc + 31) / 32 * 4;
677     m_dwLineBytes = (width * nComps * bpc + 7) / 8;
678     m_pScanline = FX_Alloc(uint8_t, m_Pitch);
679     return CheckDestSize();
680 }
681 FX_BOOL CCodec_RLScanlineDecoder::v_Rewind()
682 {
683     FXSYS_memset(m_pScanline, 0, m_Pitch);
684     m_SrcOffset = 0;
685     m_bEOD = FALSE;
686     m_Operator = 0;
687     return TRUE;
688 }
689 uint8_t* CCodec_RLScanlineDecoder::v_GetNextLine()
690 {
691     if (m_SrcOffset == 0) {
692         GetNextOperator();
693     } else {
694         if (m_bEOD) {
695             return NULL;
696         }
697     }
698     FXSYS_memset(m_pScanline, 0, m_Pitch);
699     FX_DWORD col_pos = 0;
700     FX_BOOL     eol = FALSE;
701     while (m_SrcOffset < m_SrcSize && !eol) {
702         if (m_Operator < 128) {
703             FX_DWORD copy_len = m_Operator + 1;
704             if (col_pos + copy_len >= m_dwLineBytes) {
705                 copy_len = m_dwLineBytes - col_pos;
706                 eol = TRUE;
707             }
708             if (copy_len >= m_SrcSize - m_SrcOffset) {
709                 copy_len = m_SrcSize - m_SrcOffset;
710                 m_bEOD = TRUE;
711             }
712             FXSYS_memcpy(m_pScanline + col_pos, m_pSrcBuf + m_SrcOffset, copy_len);
713             col_pos += copy_len;
714             UpdateOperator((uint8_t)copy_len);
715         } else if (m_Operator > 128) {
716             int fill = 0;
717             if (m_SrcOffset - 1 < m_SrcSize - 1) {
718                 fill = m_pSrcBuf[m_SrcOffset];
719             }
720             FX_DWORD duplicate_len = 257 - m_Operator;
721             if (col_pos + duplicate_len >= m_dwLineBytes) {
722                 duplicate_len = m_dwLineBytes - col_pos;
723                 eol = TRUE;
724             }
725             FXSYS_memset(m_pScanline + col_pos, fill, duplicate_len);
726             col_pos += duplicate_len;
727             UpdateOperator((uint8_t)duplicate_len);
728         } else {
729             m_bEOD = TRUE;
730             break;
731         }
732     }
733     return m_pScanline;
734 }
735 void CCodec_RLScanlineDecoder::GetNextOperator()
736 {
737     if (m_SrcOffset >= m_SrcSize) {
738         m_Operator = 128;
739         return;
740     }
741     m_Operator = m_pSrcBuf[m_SrcOffset];
742     m_SrcOffset ++;
743 }
744 void CCodec_RLScanlineDecoder::UpdateOperator(uint8_t used_bytes)
745 {
746     if (used_bytes == 0) {
747         return;
748     }
749     if (m_Operator < 128) {
750         FXSYS_assert((FX_DWORD)m_Operator + 1 >= used_bytes);
751         if (used_bytes == m_Operator + 1) {
752             m_SrcOffset += used_bytes;
753             GetNextOperator();
754             return;
755         }
756         m_Operator -= used_bytes;
757         m_SrcOffset += used_bytes;
758         if (m_SrcOffset >= m_SrcSize) {
759             m_Operator = 128;
760         }
761         return;
762     }
763     uint8_t count = 257 - m_Operator;
764     FXSYS_assert((FX_DWORD)count >= used_bytes);
765     if (used_bytes == count) {
766         m_SrcOffset ++;
767         GetNextOperator();
768         return;
769     }
770     count -= used_bytes;
771     m_Operator = 257 - count;
772 }
773 ICodec_ScanlineDecoder* CCodec_BasicModule::CreateRunLengthDecoder(const uint8_t* src_buf, FX_DWORD src_size, int width, int height,
774         int nComps, int bpc)
775 {
776     CCodec_RLScanlineDecoder* pRLScanlineDecoder = new CCodec_RLScanlineDecoder;
777     if (!pRLScanlineDecoder->Create(src_buf, src_size, width, height, nComps, bpc)) {
778         delete pRLScanlineDecoder;
779         return NULL;
780     }
781     return pRLScanlineDecoder;
782 }