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 "../../../include/fxge/fx_dib.h"
9#include "../../../src/fxcrt/fx_safe_types.h"
10#include "codec_int.h"
11extern "C" {
12    static void _JpegScanSOI(const FX_BYTE*& src_buf, FX_DWORD& src_size)
13    {
14        if (src_size == 0) {
15            return;
16        }
17        FX_DWORD offset = 0;
18        while (offset < src_size - 1) {
19            if (src_buf[offset] == 0xff && src_buf[offset + 1] == 0xd8) {
20                src_buf += offset;
21                src_size -= offset;
22                return;
23            }
24            offset ++;
25        }
26    }
27};
28extern "C" {
29#undef FAR
30#include "../../fx_jpeglib.h"
31}
32extern "C" {
33    static void _src_do_nothing(struct jpeg_decompress_struct* cinfo) {}
34};
35extern "C" {
36    static void _error_fatal(j_common_ptr cinfo)
37    {
38        longjmp(*(jmp_buf*)cinfo->client_data, -1);
39    }
40};
41extern "C" {
42    static void _src_skip_data(struct jpeg_decompress_struct* cinfo, long num)
43    {
44        if (num > (long)cinfo->src->bytes_in_buffer) {
45            _error_fatal((j_common_ptr)cinfo);
46        }
47        cinfo->src->next_input_byte += num;
48        cinfo->src->bytes_in_buffer -= num;
49    }
50};
51extern "C" {
52    static boolean _src_fill_buffer(j_decompress_ptr cinfo)
53    {
54        return 0;
55    }
56};
57extern "C" {
58    static boolean _src_resync(j_decompress_ptr cinfo, int desired)
59    {
60        return 0;
61    }
62};
63extern "C" {
64    static void _error_do_nothing(j_common_ptr cinfo) {}
65};
66extern "C" {
67    static void _error_do_nothing1(j_common_ptr cinfo, int) {}
68};
69extern "C" {
70    static void _error_do_nothing2(j_common_ptr cinfo, char*) {}
71};
72#define JPEG_MARKER_EXIF		(JPEG_APP0 + 1)
73#define	JPEG_MARKER_ICC			(JPEG_APP0 + 2)
74#define	JPEG_MARKER_AUTHORTIME	(JPEG_APP0 + 3)
75#define	JPEG_MARKER_MAXSIZE	0xFFFF
76#define	JPEG_OVERHEAD_LEN	14
77static	FX_BOOL _JpegEmbedIccProfile(j_compress_ptr cinfo, FX_LPCBYTE icc_buf_ptr, FX_DWORD icc_length)
78{
79    if(icc_buf_ptr == NULL || icc_length == 0) {
80        return FALSE;
81    }
82    FX_DWORD icc_segment_size = (JPEG_MARKER_MAXSIZE - 2 - JPEG_OVERHEAD_LEN);
83    FX_DWORD icc_segment_num = (icc_length / icc_segment_size) + 1;
84    if (icc_segment_num > 255)	{
85        return FALSE;
86    }
87    FX_DWORD icc_data_length = JPEG_OVERHEAD_LEN + (icc_segment_num > 1 ? icc_segment_size : icc_length);
88    FX_LPBYTE icc_data = FX_Alloc(FX_BYTE, icc_data_length);
89    FXSYS_memcpy32(icc_data, "\x49\x43\x43\x5f\x50\x52\x4f\x46\x49\x4c\x45\x00", 12);
90    icc_data[13] = (FX_BYTE)icc_segment_num;
91    for (FX_BYTE i = 0; i < (icc_segment_num - 1); i++) {
92        icc_data[12] = i + 1;
93        FXSYS_memcpy32(icc_data + JPEG_OVERHEAD_LEN, icc_buf_ptr + i * icc_segment_size, icc_segment_size);
94        jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, icc_data_length);
95    }
96    icc_data[12] = (FX_BYTE)icc_segment_num;
97    FX_DWORD icc_size = (icc_segment_num - 1) * icc_segment_size;
98    FXSYS_memcpy32(icc_data + JPEG_OVERHEAD_LEN, icc_buf_ptr + icc_size, icc_length - icc_size);
99    jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, JPEG_OVERHEAD_LEN + icc_length - icc_size);
100    FX_Free(icc_data);
101    return TRUE;
102}
103extern "C" {
104    static void _dest_do_nothing(j_compress_ptr cinfo) {}
105};
106extern "C" {
107    static boolean _dest_empty(j_compress_ptr cinfo)
108    {
109        return FALSE;
110    }
111};
112#define	JPEG_BLOCK_SIZE	1048576
113static void _JpegEncode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_STRSIZE& dest_size, int quality, FX_LPCBYTE icc_buf, FX_DWORD icc_length)
114{
115    struct jpeg_error_mgr jerr;
116    jerr.error_exit = _error_do_nothing;
117    jerr.emit_message = _error_do_nothing1;
118    jerr.output_message = _error_do_nothing;
119    jerr.format_message = _error_do_nothing2;
120    jerr.reset_error_mgr = _error_do_nothing;
121
122    struct jpeg_compress_struct cinfo;
123    memset(&cinfo, 0, sizeof(cinfo));
124    cinfo.err = &jerr;
125    jpeg_create_compress(&cinfo);
126    int Bpp = pSource->GetBPP() / 8;
127    FX_DWORD nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1;
128    FX_DWORD pitch = pSource->GetPitch();
129    FX_DWORD width = pdfium::base::checked_cast<FX_DWORD>(pSource->GetWidth());
130    FX_DWORD height = pdfium::base::checked_cast<FX_DWORD>(pSource->GetHeight());
131    FX_SAFE_DWORD safe_buf_len = width;
132    safe_buf_len *= height;
133    safe_buf_len *= nComponents;
134    safe_buf_len += 1024;
135    if (icc_length) {
136        safe_buf_len += 255 * 18;
137        safe_buf_len += icc_length;
138    }
139    FX_DWORD dest_buf_length = 0;
140    if (!safe_buf_len.IsValid()) {
141        dest_buf = nullptr;
142    } else {
143        dest_buf_length = safe_buf_len.ValueOrDie();
144        dest_buf = FX_TryAlloc(FX_BYTE, dest_buf_length);
145        const int MIN_TRY_BUF_LEN = 1024;
146        while (!dest_buf && dest_buf_length > MIN_TRY_BUF_LEN) {
147            dest_buf_length >>= 1;
148            dest_buf = FX_TryAlloc(FX_BYTE, dest_buf_length);
149        }
150    }
151    if (!dest_buf) {
152        FX_OutOfMemoryTerminate();
153    }
154    struct jpeg_destination_mgr dest;
155    dest.init_destination = _dest_do_nothing;
156    dest.term_destination = _dest_do_nothing;
157    dest.empty_output_buffer = _dest_empty;
158    dest.next_output_byte = dest_buf;
159    dest.free_in_buffer = dest_buf_length;
160    cinfo.dest = &dest;
161    cinfo.image_width = width;
162    cinfo.image_height = height;
163    cinfo.input_components = nComponents;
164    if (nComponents == 1) {
165        cinfo.in_color_space = JCS_GRAYSCALE;
166    } else if (nComponents == 3) {
167        cinfo.in_color_space = JCS_RGB;
168    } else {
169        cinfo.in_color_space = JCS_CMYK;
170    }
171    FX_LPBYTE line_buf = NULL;
172    if (nComponents > 1) {
173        line_buf = FX_Alloc2D(FX_BYTE, width, nComponents);
174    }
175    jpeg_set_defaults(&cinfo);
176    if(quality != 75) {
177        jpeg_set_quality(&cinfo, quality, TRUE);
178    }
179    jpeg_start_compress(&cinfo, TRUE);
180    _JpegEmbedIccProfile(&cinfo, icc_buf, icc_length);
181    JSAMPROW row_pointer[1];
182    JDIMENSION row;
183    while (cinfo.next_scanline < cinfo.image_height) {
184        FX_LPCBYTE src_scan = pSource->GetScanline(cinfo.next_scanline);
185        if (nComponents > 1) {
186            FX_LPBYTE dest_scan = line_buf;
187            if (nComponents == 3) {
188                for (int i = 0; i < width; i ++) {
189                    dest_scan[0] = src_scan[2];
190                    dest_scan[1] = src_scan[1];
191                    dest_scan[2] = src_scan[0];
192                    dest_scan += 3;
193                    src_scan += Bpp;
194                }
195            } else {
196                for (int i = 0; i < pitch; i ++) {
197                    *dest_scan++ = ~*src_scan++;
198                }
199            }
200            row_pointer[0] = line_buf;
201        } else {
202            row_pointer[0] = (FX_LPBYTE)src_scan;
203        }
204        row = cinfo.next_scanline;
205        jpeg_write_scanlines(&cinfo, row_pointer, 1);
206        if (cinfo.next_scanline == row) {
207            dest_buf = FX_Realloc(FX_BYTE, dest_buf, dest_buf_length + JPEG_BLOCK_SIZE);
208            dest.next_output_byte = dest_buf + dest_buf_length - dest.free_in_buffer;
209            dest_buf_length += JPEG_BLOCK_SIZE;
210            dest.free_in_buffer += JPEG_BLOCK_SIZE;
211        }
212    }
213    jpeg_finish_compress(&cinfo);
214    jpeg_destroy_compress(&cinfo);
215    if (line_buf) {
216        FX_Free(line_buf);
217    }
218    dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer;
219}
220static FX_BOOL _JpegLoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height,
221                             int& num_components, int& bits_per_components, FX_BOOL& color_transform,
222                             FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length)
223{
224    _JpegScanSOI(src_buf, src_size);
225    struct jpeg_decompress_struct cinfo;
226    struct jpeg_error_mgr jerr;
227    jerr.error_exit = _error_fatal;
228    jerr.emit_message = _error_do_nothing1;
229    jerr.output_message = _error_do_nothing;
230    jerr.format_message = _error_do_nothing2;
231    jerr.reset_error_mgr = _error_do_nothing;
232    jerr.trace_level = 0;
233    cinfo.err = &jerr;
234    jmp_buf mark;
235    cinfo.client_data = &mark;
236    if (setjmp(mark) == -1) {
237        return FALSE;
238    }
239    jpeg_create_decompress(&cinfo);
240    struct jpeg_source_mgr src;
241    src.init_source = _src_do_nothing;
242    src.term_source = _src_do_nothing;
243    src.skip_input_data = _src_skip_data;
244    src.fill_input_buffer = _src_fill_buffer;
245    src.resync_to_restart = _src_resync;
246    src.bytes_in_buffer = src_size;
247    src.next_input_byte = src_buf;
248    cinfo.src = &src;
249    if (setjmp(mark) == -1) {
250        jpeg_destroy_decompress(&cinfo);
251        return FALSE;
252    }
253    if(icc_buf_ptr && icc_length) {
254        jpeg_save_markers(&cinfo, JPEG_MARKER_ICC, JPEG_MARKER_MAXSIZE);
255    }
256    int ret = jpeg_read_header(&cinfo, TRUE);
257    if (ret != JPEG_HEADER_OK) {
258        jpeg_destroy_decompress(&cinfo);
259        return FALSE;
260    }
261    width = cinfo.image_width;
262    height = cinfo.image_height;
263    num_components = cinfo.num_components;
264    color_transform = cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK;
265    bits_per_components = cinfo.data_precision;
266    if(icc_buf_ptr != NULL) {
267        *icc_buf_ptr = NULL;
268    }
269    if(icc_length != NULL) {
270        *icc_length = 0;
271    }
272    jpeg_destroy_decompress(&cinfo);
273    return TRUE;
274}
275class CCodec_JpegDecoder : public CCodec_ScanlineDecoder
276{
277public:
278    CCodec_JpegDecoder();
279    ~CCodec_JpegDecoder();
280    FX_BOOL				Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, int nComps,
281                               FX_BOOL ColorTransform, IFX_JpegProvider* pJP);
282    virtual void		Destroy()
283    {
284        delete this;
285    }
286    virtual void		v_DownScale(int dest_width, int dest_height);
287    virtual FX_BOOL		v_Rewind();
288    virtual FX_LPBYTE	v_GetNextLine();
289    virtual FX_DWORD	GetSrcOffset();
290    jmp_buf		m_JmpBuf;
291    struct jpeg_decompress_struct cinfo;
292    struct jpeg_error_mgr jerr;
293    struct jpeg_source_mgr src;
294    FX_LPCBYTE	m_SrcBuf;
295    FX_DWORD	m_SrcSize;
296    FX_LPBYTE	m_pScanlineBuf;
297    FX_BOOL		InitDecode();
298    FX_BOOL		m_bInited, m_bStarted, m_bJpegTransform;
299protected:
300    IFX_JpegProvider*	m_pExtProvider;
301    void*				m_pExtContext;
302    FX_DWORD			m_nDefaultScaleDenom;
303};
304CCodec_JpegDecoder::CCodec_JpegDecoder()
305{
306    m_pScanlineBuf = NULL;
307    m_DownScale = 1;
308    m_bStarted = FALSE;
309    m_bInited = FALSE;
310    m_pExtProvider = NULL;
311    m_pExtContext = NULL;
312    FXSYS_memset32(&cinfo, 0, sizeof(cinfo));
313    FXSYS_memset32(&jerr, 0, sizeof(jerr));
314    FXSYS_memset32(&src, 0, sizeof(src));
315    m_nDefaultScaleDenom = 1;
316}
317CCodec_JpegDecoder::~CCodec_JpegDecoder()
318{
319    if (m_pExtProvider) {
320        m_pExtProvider->DestroyDecoder(m_pExtContext);
321        return;
322    }
323    if (m_pScanlineBuf) {
324        FX_Free(m_pScanlineBuf);
325    }
326    if (m_bInited) {
327        jpeg_destroy_decompress(&cinfo);
328    }
329}
330FX_BOOL CCodec_JpegDecoder::InitDecode()
331{
332    cinfo.err = &jerr;
333    cinfo.client_data = &m_JmpBuf;
334    if (setjmp(m_JmpBuf) == -1) {
335        return FALSE;
336    }
337    jpeg_create_decompress(&cinfo);
338    m_bInited = TRUE;
339    cinfo.src = &src;
340    src.bytes_in_buffer = m_SrcSize;
341    src.next_input_byte = m_SrcBuf;
342    if (setjmp(m_JmpBuf) == -1) {
343        jpeg_destroy_decompress(&cinfo);
344        m_bInited = FALSE;
345        return FALSE;
346    }
347    cinfo.image_width = m_OrigWidth;
348    cinfo.image_height = m_OrigHeight;
349    int ret = jpeg_read_header(&cinfo, TRUE);
350    if (ret != JPEG_HEADER_OK) {
351        return FALSE;
352    }
353    if (cinfo.saw_Adobe_marker) {
354        m_bJpegTransform = TRUE;
355    }
356    if (cinfo.num_components == 3 && !m_bJpegTransform) {
357        cinfo.out_color_space = cinfo.jpeg_color_space;
358    }
359    m_OrigWidth = cinfo.image_width;
360    m_OrigHeight = cinfo.image_height;
361    m_OutputWidth = m_OrigWidth;
362    m_OutputHeight = m_OrigHeight;
363    m_nDefaultScaleDenom = cinfo.scale_denom;
364    return TRUE;
365}
366FX_BOOL CCodec_JpegDecoder::Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
367                                   int nComps, FX_BOOL ColorTransform, IFX_JpegProvider* pJP)
368{
369    if (pJP) {
370        m_pExtProvider = pJP;
371        m_pExtContext = m_pExtProvider->CreateDecoder(src_buf, src_size, width, height, nComps, ColorTransform);
372        return m_pExtContext != NULL;
373    }
374    _JpegScanSOI(src_buf, src_size);
375    m_SrcBuf = src_buf;
376    m_SrcSize = src_size;
377    jerr.error_exit = _error_fatal;
378    jerr.emit_message = _error_do_nothing1;
379    jerr.output_message = _error_do_nothing;
380    jerr.format_message = _error_do_nothing2;
381    jerr.reset_error_mgr = _error_do_nothing;
382    src.init_source = _src_do_nothing;
383    src.term_source = _src_do_nothing;
384    src.skip_input_data = _src_skip_data;
385    src.fill_input_buffer = _src_fill_buffer;
386    src.resync_to_restart = _src_resync;
387    m_bJpegTransform = ColorTransform;
388    if(src_size > 1 && FXSYS_memcmp32(src_buf + src_size - 2, "\xFF\xD9", 2) != 0) {
389        ((FX_LPBYTE)src_buf)[src_size - 2] = 0xFF;
390        ((FX_LPBYTE)src_buf)[src_size - 1] = 0xD9;
391    }
392    m_OutputWidth = m_OrigWidth = width;
393    m_OutputHeight = m_OrigHeight = height;
394    if (!InitDecode()) {
395        return FALSE;
396    }
397    if (cinfo.num_components < nComps) {
398        return FALSE;
399    }
400    if ((int)cinfo.image_width < width) {
401        return FALSE;
402    }
403    m_Pitch = (cinfo.image_width * cinfo.num_components + 3) / 4 * 4;
404    m_pScanlineBuf = FX_Alloc(FX_BYTE, m_Pitch);
405    m_nComps = cinfo.num_components;
406    m_bpc = 8;
407    m_bColorTransformed = FALSE;
408    m_bStarted = FALSE;
409    return TRUE;
410}
411extern "C" {
412    FX_INT32 FX_GetDownsampleRatio(FX_INT32 originWidth, FX_INT32 originHeight, FX_INT32 downsampleWidth, FX_INT32 downsampleHeight)
413    {
414        int iratio_w = originWidth / downsampleWidth;
415        int iratio_h = originHeight / downsampleHeight;
416        int ratio = (iratio_w > iratio_h) ? iratio_h : iratio_w;
417        if (ratio >= 8) {
418            return 8;
419        } else if (ratio >= 4) {
420            return 4;
421        } else if (ratio >= 2) {
422            return 2;
423        }
424        return 1;
425    }
426}
427void CCodec_JpegDecoder::v_DownScale(int dest_width, int dest_height)
428{
429    if (m_pExtProvider) {
430        m_pExtProvider->DownScale(m_pExtContext, dest_width, dest_height);
431        return;
432    }
433    int old_scale = m_DownScale;
434    m_DownScale = FX_GetDownsampleRatio(m_OrigWidth, m_OrigHeight, dest_width, dest_height);
435    m_OutputWidth = (m_OrigWidth + m_DownScale - 1) / m_DownScale;
436    m_OutputHeight = (m_OrigHeight + m_DownScale - 1) / m_DownScale;
437    m_Pitch = (m_OutputWidth * m_nComps + 3) / 4 * 4;
438    if (old_scale != m_DownScale) {
439        m_NextLine = -1;
440    }
441}
442FX_BOOL CCodec_JpegDecoder::v_Rewind()
443{
444    if (m_pExtProvider) {
445        return m_pExtProvider->Rewind(m_pExtContext);
446    }
447    if (m_bStarted) {
448        jpeg_destroy_decompress(&cinfo);
449        if (!InitDecode()) {
450            return FALSE;
451        }
452    }
453    if (setjmp(m_JmpBuf) == -1) {
454        return FALSE;
455    }
456    cinfo.scale_denom = m_nDefaultScaleDenom * m_DownScale;
457    m_OutputWidth = (m_OrigWidth + m_DownScale - 1) / m_DownScale;
458    m_OutputHeight = (m_OrigHeight + m_DownScale - 1) / m_DownScale;
459    if (!jpeg_start_decompress(&cinfo)) {
460        jpeg_destroy_decompress(&cinfo);
461        return FALSE;
462    }
463    if ((int)cinfo.output_width > m_OrigWidth) {
464        FXSYS_assert(FALSE);
465        return FALSE;
466    }
467    m_bStarted = TRUE;
468    return TRUE;
469}
470FX_LPBYTE CCodec_JpegDecoder::v_GetNextLine()
471{
472    if (m_pExtProvider) {
473        return m_pExtProvider->GetNextLine(m_pExtContext);
474    }
475    int nlines = jpeg_read_scanlines(&cinfo, &m_pScanlineBuf, 1);
476    if (nlines < 1) {
477        return NULL;
478    }
479    return m_pScanlineBuf;
480}
481FX_DWORD CCodec_JpegDecoder::GetSrcOffset()
482{
483    if (m_pExtProvider) {
484        return m_pExtProvider->GetSrcOffset(m_pExtContext);
485    }
486    return (FX_DWORD)(m_SrcSize - src.bytes_in_buffer);
487}
488ICodec_ScanlineDecoder*	CCodec_JpegModule::CreateDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size,
489        int width, int height, int nComps, FX_BOOL ColorTransform)
490{
491    if (src_buf == NULL || src_size == 0) {
492        return NULL;
493    }
494    CCodec_JpegDecoder* pDecoder = new CCodec_JpegDecoder;
495    if (!pDecoder->Create(src_buf, src_size, width, height, nComps, ColorTransform, m_pExtProvider)) {
496        delete pDecoder;
497        return NULL;
498    }
499    return pDecoder;
500}
501FX_BOOL CCodec_JpegModule::LoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height,
502                                    int& num_components, int& bits_per_components, FX_BOOL& color_transform,
503                                    FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length)
504{
505    if (m_pExtProvider) {
506        return m_pExtProvider->LoadInfo(src_buf, src_size, width, height,
507                                        num_components, bits_per_components, color_transform,
508                                        icc_buf_ptr, icc_length);
509    }
510    return _JpegLoadInfo(src_buf, src_size, width, height, num_components, bits_per_components, color_transform, icc_buf_ptr, icc_length);
511}
512FX_BOOL CCodec_JpegModule::Encode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_STRSIZE& dest_size, int quality, FX_LPCBYTE icc_buf, FX_DWORD icc_length)
513{
514    if (m_pExtProvider) {
515        return m_pExtProvider->Encode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length);
516    }
517    if(pSource->GetBPP() < 8 || pSource->GetPalette() != NULL) {
518        ASSERT(pSource->GetBPP() >= 8 && pSource->GetPalette() == NULL);
519        return FALSE;
520    }
521    _JpegEncode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length);
522    return TRUE;
523}
524struct FXJPEG_Context {
525    jmp_buf			m_JumpMark;
526    jpeg_decompress_struct m_Info;
527    jpeg_error_mgr	m_ErrMgr;
528    jpeg_source_mgr	m_SrcMgr;
529    unsigned int	m_SkipSize;
530    void*		(*m_AllocFunc)(unsigned int);
531    void		(*m_FreeFunc)(void*);
532};
533extern "C" {
534    static void _error_fatal1(j_common_ptr cinfo)
535    {
536        longjmp(((FXJPEG_Context*)cinfo->client_data)->m_JumpMark, -1);
537    }
538};
539extern "C" {
540    static void _src_skip_data1(struct jpeg_decompress_struct* cinfo, long num)
541    {
542        if (cinfo->src->bytes_in_buffer < (size_t)num) {
543            ((FXJPEG_Context*)cinfo->client_data)->m_SkipSize = (unsigned int)(num - cinfo->src->bytes_in_buffer);
544            cinfo->src->bytes_in_buffer = 0;
545        } else {
546            cinfo->src->next_input_byte += num;
547            cinfo->src->bytes_in_buffer -= num;
548        }
549    }
550};
551static void* jpeg_alloc_func(unsigned int size)
552{
553    return FX_Alloc(char, size);
554}
555static void jpeg_free_func(void* p)
556{
557    FX_Free(p);
558}
559void* CCodec_JpegModule::Start()
560{
561    if (m_pExtProvider) {
562        return m_pExtProvider->Start();
563    }
564    FXJPEG_Context* p = (FXJPEG_Context*)FX_Alloc(FX_BYTE, sizeof(FXJPEG_Context));
565    p->m_AllocFunc = jpeg_alloc_func;
566    p->m_FreeFunc = jpeg_free_func;
567    p->m_ErrMgr.error_exit = _error_fatal1;
568    p->m_ErrMgr.emit_message = _error_do_nothing1;
569    p->m_ErrMgr.output_message = _error_do_nothing;
570    p->m_ErrMgr.format_message = _error_do_nothing2;
571    p->m_ErrMgr.reset_error_mgr = _error_do_nothing;
572    p->m_SrcMgr.init_source = _src_do_nothing;
573    p->m_SrcMgr.term_source = _src_do_nothing;
574    p->m_SrcMgr.skip_input_data = _src_skip_data1;
575    p->m_SrcMgr.fill_input_buffer = _src_fill_buffer;
576    p->m_SrcMgr.resync_to_restart = _src_resync;
577    p->m_Info.client_data = p;
578    p->m_Info.err = &p->m_ErrMgr;
579    if (setjmp(p->m_JumpMark) == -1) {
580        return 0;
581    }
582    jpeg_create_decompress(&p->m_Info);
583    p->m_Info.src = &p->m_SrcMgr;
584    p->m_SkipSize = 0;
585    return p;
586}
587void CCodec_JpegModule::Finish(void* pContext)
588{
589    if (m_pExtProvider) {
590        m_pExtProvider->Finish(pContext);
591        return;
592    }
593    FXJPEG_Context* p = (FXJPEG_Context*)pContext;
594    jpeg_destroy_decompress(&p->m_Info);
595    p->m_FreeFunc(p);
596}
597void CCodec_JpegModule::Input(void* pContext, const unsigned char* src_buf, FX_DWORD src_size)
598{
599    if (m_pExtProvider) {
600        m_pExtProvider->Input(pContext, src_buf, src_size);
601        return;
602    }
603    FXJPEG_Context* p = (FXJPEG_Context*)pContext;
604    if (p->m_SkipSize) {
605        if (p->m_SkipSize > src_size) {
606            p->m_SrcMgr.bytes_in_buffer = 0;
607            p->m_SkipSize -= src_size;
608            return;
609        }
610        src_size -= p->m_SkipSize;
611        src_buf += p->m_SkipSize;
612        p->m_SkipSize = 0;
613    }
614    p->m_SrcMgr.next_input_byte = src_buf;
615    p->m_SrcMgr.bytes_in_buffer = src_size;
616}
617int CCodec_JpegModule::ReadHeader(void* pContext, int* width, int* height, int* nComps)
618{
619    if (m_pExtProvider) {
620        return m_pExtProvider->ReadHeader(pContext, width, height, nComps);
621    }
622    FXJPEG_Context* p = (FXJPEG_Context*)pContext;
623    if (setjmp(p->m_JumpMark) == -1) {
624        return 1;
625    }
626    int ret = jpeg_read_header(&p->m_Info, true);
627    if (ret == JPEG_SUSPENDED) {
628        return 2;
629    }
630    if (ret != JPEG_HEADER_OK) {
631        return 1;
632    }
633    *width = p->m_Info.image_width;
634    *height = p->m_Info.image_height;
635    *nComps = p->m_Info.num_components;
636    return 0;
637}
638FX_BOOL CCodec_JpegModule::StartScanline(void* pContext, int down_scale)
639{
640    if (m_pExtProvider) {
641        return m_pExtProvider->StartScanline(pContext, down_scale);
642    }
643    FXJPEG_Context* p = (FXJPEG_Context*)pContext;
644    if (setjmp(p->m_JumpMark) == -1) {
645        return FALSE;
646    }
647    p->m_Info.scale_denom = down_scale;
648    return jpeg_start_decompress(&p->m_Info);
649}
650FX_BOOL CCodec_JpegModule::ReadScanline(void* pContext, unsigned char* dest_buf)
651{
652    if (m_pExtProvider) {
653        return m_pExtProvider->ReadScanline(pContext, dest_buf);
654    }
655    FXJPEG_Context* p = (FXJPEG_Context*)pContext;
656    if (setjmp(p->m_JumpMark) == -1) {
657        return FALSE;
658    }
659    int nlines = jpeg_read_scanlines(&p->m_Info, &dest_buf, 1);
660    return nlines == 1;
661}
662FX_DWORD CCodec_JpegModule::GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr)
663{
664    if (m_pExtProvider) {
665        return m_pExtProvider->GetAvailInput(pContext, avail_buf_ptr);
666    }
667    if(avail_buf_ptr != NULL) {
668        *avail_buf_ptr = NULL;
669        if(((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer > 0) {
670            *avail_buf_ptr = (FX_LPBYTE)((FXJPEG_Context*)pContext)->m_SrcMgr.next_input_byte;
671        }
672    }
673    return (FX_DWORD)((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer;
674}
675