Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
diff --git a/core/include/fpdfdoc/fpdf_doc.h b/core/include/fpdfdoc/fpdf_doc.h
index e4cf777..960e943 100644
--- a/core/include/fpdfdoc/fpdf_doc.h
+++ b/core/include/fpdfdoc/fpdf_doc.h
@@ -1230,8 +1230,9 @@
 
     FX_BOOL					ClearSelectedOptions(FX_BOOL bNotify = FALSE);
 
+    FX_BOOL					ClearOptions(FX_BOOL bNotify = FALSE);

 
-
+    int						InsertOption(CFX_WideString csOptLabel, int index = -1, FX_BOOL bNotify = FALSE);

 
     FX_FLOAT				GetFontSize()
     {
diff --git a/core/include/fxcodec/fx_codec.h b/core/include/fxcodec/fx_codec.h
index da8b309..b0eecc3 100644
--- a/core/include/fxcodec/fx_codec.h
+++ b/core/include/fxcodec/fx_codec.h
@@ -13,6 +13,7 @@
 #include "fx_codec_provider.h"
 class CFX_DIBSource;
 class ICodec_ScanlineDecoder;
+class ICodec_ProgressiveDecoder;

 class ICodec_BasicModule;
 class ICodec_FaxModule;
 class ICodec_JpegModule;
@@ -21,6 +22,11 @@
 class ICodec_IccModule;
 class ICodec_FlateModule;
 class ICodec_Jbig2Encoder;
+class ICodec_PngModule;

+class ICodec_GifModule;

+class ICodec_BmpModule;

+class ICodec_TiffModule;

+class CFX_DIBAttribute;

 class ICodec_ScanlineDecoder;
 class CCodec_ModuleMgr : public CFX_Object
 {
@@ -37,6 +43,9 @@
 
     void				InitIccDecoder();
 
+

+    ICodec_ProgressiveDecoder*	CreateProgressiveDecoder();

+

     ICodec_Jbig2Encoder*		CreateJbig2Encoder();
 protected:
     CCodec_ModuleMgr();
@@ -70,6 +79,22 @@
     {
         return m_pFlateModule;
     }
+    ICodec_PngModule*	GetPngModule()

+    {

+        return m_pPngModule;

+    }

+    ICodec_GifModule*	GetGifModule()

+    {

+        return m_pGifModule;

+    }

+    ICodec_BmpModule*	GetBmpModule()

+    {

+        return m_pBmpModule;

+    }

+    ICodec_TiffModule*	GetTiffModule()

+    {

+        return m_pTiffModule;

+    }

 protected:
     ICodec_BasicModule*	m_pBasicModule;
     ICodec_FaxModule*	m_pFaxModule;
@@ -78,6 +103,10 @@
     ICodec_Jbig2Module*	m_pJbig2Module;
     ICodec_IccModule*	m_pIccModule;
     ICodec_FlateModule*	m_pFlateModule;
+    ICodec_PngModule*	m_pPngModule;

+    ICodec_GifModule*	m_pGifModule;

+    ICodec_BmpModule*	m_pBmpModule;

+    ICodec_TiffModule*	m_pTiffModule;

 
 };
 class ICodec_BasicModule : public CFX_Object
@@ -170,7 +199,7 @@
 
     virtual void		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size) = 0;
 
-    virtual int			ReadHeader(void* pContext, int* width, int* height, int* nComps) = 0;
+    virtual int			ReadHeader(void* pContext, int* width, int* height, int* nComps, CFX_DIBAttribute* pAttribute = NULL) = 0;

 
 
     virtual int			StartScanline(void* pContext, int down_scale) = 0;
@@ -197,6 +226,97 @@
 
     virtual void		DestroyDecoder(FX_LPVOID ctx) = 0;
 };
+class ICodec_PngModule : public CFX_Object

+{

+public:

+

+    virtual ~ICodec_PngModule() {}

+

+    virtual void*		Start(void* pModule) = 0;

+

+    virtual void		Finish(void* pContext) = 0;

+

+    virtual FX_BOOL		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_DIBAttribute* pAttribute = NULL) = 0;

+

+    FX_BOOL				(*ReadHeaderCallback)(void* pModule, int width, int height, int bpc, int pass, int* color_type, double* gamma);

+

+    FX_BOOL				(*AskScanlineBufCallback)(void* pModule, int line, FX_LPBYTE& src_buf);

+

+    void				(*FillScanlineBufCompletedCallback)(void* pModule, int pass, int line);

+};

+class ICodec_GifModule : public CFX_Object

+{

+public:

+

+    virtual ~ICodec_GifModule() {}

+

+    virtual void*		Start(void* pModule) = 0;

+

+    virtual void		Finish(void* pContext) = 0;

+

+    virtual FX_DWORD	GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr = NULL) = 0;

+

+    virtual void		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size) = 0;

+

+    virtual FX_INT32	ReadHeader(void* pContext, int* width, int* height,

+                                   int* pal_num, void** pal_pp, int* bg_index, CFX_DIBAttribute* pAttribute = NULL) = 0;

+

+    virtual FX_INT32	LoadFrameInfo(void* pContext, int* frame_num) = 0;

+

+    void				(*RecordCurrentPositionCallback)(void* pModule, FX_DWORD& cur_pos);

+

+    FX_LPBYTE			(*AskLocalPaletteBufCallback)(void* pModule, FX_INT32 frame_num, FX_INT32 pal_size);

+

+    virtual FX_INT32	LoadFrame(void* pContext, int frame_num, CFX_DIBAttribute* pAttribute = NULL) = 0;

+

+    FX_BOOL				(*InputRecordPositionBufCallback)(void* pModule, FX_DWORD rcd_pos, const FX_RECT& img_rc,

+            FX_INT32 pal_num, void* pal_ptr,

+            FX_INT32 delay_time, FX_BOOL user_input,

+            FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace);

+

+    void				(*ReadScanlineCallback)(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf);

+};

+class ICodec_BmpModule : public CFX_Object

+{

+public:

+

+    virtual ~ICodec_BmpModule() {}

+

+    virtual void*		Start(void* pModule) = 0;

+

+    virtual void		Finish(void* pContext) = 0;

+

+    virtual FX_DWORD	GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr = NULL) = 0;

+

+    virtual void		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size) = 0;

+

+    virtual FX_INT32	ReadHeader(void* pContext, FX_INT32* width, FX_INT32* height, FX_BOOL* tb_flag, FX_INT32* components,

+                                   int* pal_num, FX_DWORD** pal_pp, CFX_DIBAttribute* pAttribute = NULL) = 0;

+

+    virtual FX_INT32	LoadImage(void* pContext) = 0;

+

+    FX_BOOL				(*InputImagePositionBufCallback)(void* pModule, FX_DWORD rcd_pos);

+

+    void				(*ReadScanlineCallback)(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf);

+};

+class ICodec_TiffModule : public CFX_Object

+{

+public:

+

+    virtual ~ICodec_TiffModule() {}

+

+    virtual FX_LPVOID 	CreateDecoder(IFX_FileRead* file_ptr) = 0;

+

+

+    virtual void		GetFrames(FX_LPVOID ctx, FX_INT32& frames) = 0;

+

+    virtual FX_BOOL		LoadFrameInfo(FX_LPVOID ctx, FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute = NULL) = 0;

+

+

+    virtual FX_BOOL		Decode(FX_LPVOID ctx, class CFX_DIBitmap* pDIBitmap) = 0;

+

+    virtual void		DestroyDecoder(FX_LPVOID ctx) = 0;

+};

 class ICodec_Jbig2Module : public CFX_Object
 {
 public:
@@ -218,6 +338,34 @@
     virtual FXCODEC_STATUS		ContinueDecode(void* pJbig2Content, IFX_Pause* pPause) = 0;
     virtual void				DestroyJbig2Context(void* pJbig2Content) = 0;
 };
+class ICodec_ProgressiveDecoder : public CFX_Object

+{

+public:

+

+    virtual ~ICodec_ProgressiveDecoder() {}

+

+    virtual FXCODEC_STATUS		LoadImageInfo(IFX_FileRead* pFile, FXCODEC_IMAGE_TYPE imageType = FXCODEC_IMAGE_UNKNOWN, CFX_DIBAttribute* pAttribute = NULL) = 0;

+

+    virtual FXCODEC_IMAGE_TYPE	GetType() = 0;

+

+    virtual FX_INT32			GetWidth() = 0;

+

+    virtual FX_INT32			GetHeight() = 0;

+

+    virtual FX_INT32			GetNumComponents() = 0;

+

+    virtual FX_INT32			GetBPC() = 0;

+

+    virtual void				SetClipBox(FX_RECT* clip) = 0;

+

+    virtual FXCODEC_STATUS		GetFrames(FX_INT32& frames, IFX_Pause* pPause = NULL) = 0;

+

+    virtual FXCODEC_STATUS		StartDecode(class CFX_DIBitmap* pDIBitmap,

+                                            FX_INT32 start_x, FX_INT32 start_y, FX_INT32 size_x, FX_INT32 size_y,

+                                            FX_INT32 frames = 0, FX_BOOL bInterpol = TRUE) = 0;

+

+    virtual FXCODEC_STATUS		ContinueDecode(IFX_Pause* pPause = NULL) = 0;

+};

 class ICodec_Jbig2Encoder : public CFX_Object
 {
 public:
@@ -286,4 +434,38 @@
 void AdobeCMYK_to_sRGB(FX_FLOAT c, FX_FLOAT m, FX_FLOAT y, FX_FLOAT k, FX_FLOAT& R, FX_FLOAT& G, FX_FLOAT& B);
 void AdobeCMYK_to_sRGB1(FX_BYTE c, FX_BYTE m, FX_BYTE y, FX_BYTE k, FX_BYTE& R, FX_BYTE& G, FX_BYTE& B);
 FX_BOOL MD5ComputeID(FX_LPCVOID buf, FX_DWORD dwSize, FX_BYTE ID[16]);
+class CFX_DIBAttribute : public CFX_Object

+{

+public:

+    CFX_DIBAttribute();

+    ~CFX_DIBAttribute();

+

+    FX_INT32		m_nXDPI;

+

+    FX_INT32		m_nYDPI;

+

+    FX_FLOAT		m_fAspectRatio;

+

+    FX_WORD			m_wDPIUnit;

+

+    CFX_ByteString	m_strAuthor;

+

+    FX_BYTE			m_strTime[20];

+

+    FX_INT32		m_nGifLeft;

+    FX_INT32		m_nGifTop;

+

+    FX_DWORD*		m_pGifLocalPalette;

+

+    FX_DWORD		m_nGifLocalPalNum;

+

+    FX_INT32		m_nBmpCompressType;

+    class IFX_DIBAttributeExif* m_pExif;

+};

+class IFX_DIBAttributeExif : public CFX_Object

+{

+public:

+    virtual ~IFX_DIBAttributeExif() {};

+    virtual FX_BOOL		GetInfo(FX_WORD tag, FX_LPVOID val) = 0;

+};

 #endif
diff --git a/core/include/fxcodec/fx_codec_def.h b/core/include/fxcodec/fx_codec_def.h
index 0d08da6..7a18f5b 100644
--- a/core/include/fxcodec/fx_codec_def.h
+++ b/core/include/fxcodec/fx_codec_def.h
@@ -6,6 +6,15 @@
 
 #ifndef _FX_CODEC_DEF_H_
 #define _FX_CODEC_DEF_H_
+enum FXCODEC_IMAGE_TYPE {
+    FXCODEC_IMAGE_UNKNOWN = 0,
+    FXCODEC_IMAGE_BMP,
+    FXCODEC_IMAGE_JPG,
+    FXCODEC_IMAGE_PNG,
+    FXCODEC_IMAGE_GIF,
+    FXCODEC_IMAGE_TIF,
+    FXCODEC_IMAGE_MAX
+};
 enum FXCODEC_STATUS {
     FXCODEC_STATUS_ERROR = -1,
     FXCODEC_STATUS_FRAME_READY,
@@ -58,6 +67,12 @@
 #define Icc_PARAMTYPE_NONE					0
 #define Icc_PARAMTYPE_BUFFER				1
 #define Icc_PARAMTYPE_PARAM					2
+enum FXCODEC_RESUNIT {
+    FXCODEC_RESUNIT_NONE = 0,
+    FXCODEC_RESUNIT_INCH,
+    FXCODEC_RESUNIT_CENTIMETER,
+    FXCODEC_RESUNIT_METER
+};
 #define EXIFTAG_USHORT_RESUNIT				296
 #define EXIFTAG_FLOAT_DPIX					282
 #define EXIFTAG_FLOAT_DPIY					283
diff --git a/core/include/fxcodec/fx_codec_provider.h b/core/include/fxcodec/fx_codec_provider.h
index a3ef396..f26194a 100644
--- a/core/include/fxcodec/fx_codec_provider.h
+++ b/core/include/fxcodec/fx_codec_provider.h
@@ -6,6 +6,7 @@
 
 #ifndef _FX_CODEC_PROVIDER_H_
 #define _FX_CODEC_PROVIDER_H_
+class CFX_DIBAttribute;
 class IFX_JpegProvider
 {
 public:
@@ -39,8 +40,7 @@
 
     virtual void		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size) = 0;
 
-    virtual int			ReadHeader(void* pContext, int* width, int* height, int* nComps) = 0;
-
+    virtual int			ReadHeader(void* pContext, int* width, int* height, int* nComps, CFX_DIBAttribute* pAttribute = NULL) = 0;
 
     virtual int			StartScanline(void* pContext, int down_scale) = 0;
 
diff --git a/core/include/fxcrt/fx_arb.h b/core/include/fxcrt/fx_arb.h
index 4950f81..ed0370f 100644
--- a/core/include/fxcrt/fx_arb.h
+++ b/core/include/fxcrt/fx_arb.h
@@ -6,6 +6,54 @@
 
 #ifndef _FX_ARABIC_
 #define _FX_ARABIC_
+class IFX_ArabicChar;
+class IFX_BidiChar;
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+typedef struct _FX_ARBFORMTABLE {
+    FX_WCHAR	wIsolated;
+    FX_WCHAR	wFinal;
+    FX_WCHAR	wInitial;
+    FX_WCHAR	wMedial;
+} FX_ARBFORMTABLE, * FX_LPARBFORMTABLE;
+typedef FX_ARBFORMTABLE const * FX_LPCARBFORMTABLE;
+typedef struct _FX_ARAALEF {
+    FX_WCHAR	wAlef;
+    FX_WCHAR	wIsolated;
+} FX_ARAALEF, * FX_LPARAALEF;
+typedef FX_ARAALEF const * FX_LPCARAALEF;
+typedef struct _FX_ARASHADDA {
+    FX_WCHAR	wShadda;
+    FX_WCHAR	wIsolated;
+} FX_ARASHADDA, * FX_LPARASHADDA;
+typedef FX_ARASHADDA const * FX_LPCARASHADDA;
+FX_LPCARBFORMTABLE FX_GetArabicFormTable(FX_WCHAR unicode);
+FX_WCHAR FX_GetArabicFromAlefTable(FX_WCHAR alef);
+FX_WCHAR FX_GetArabicFromShaddaTable(FX_WCHAR shadda);
+#ifdef __cplusplus
+};
+#endif
+enum FX_ARBPOSITION {
+    FX_ARBPOSITION_Isolated = 0,
+    FX_ARBPOSITION_Final,
+    FX_ARBPOSITION_Initial,
+    FX_ARBPOSITION_Medial,
+};
+class IFX_ArabicChar
+{
+public:
+    static IFX_ArabicChar*		Create();
+    virtual void				Release() = 0;
+    virtual FX_BOOL				IsArabicChar(FX_WCHAR wch) const = 0;
+    virtual FX_BOOL				IsArabicFormChar(FX_WCHAR wch) const = 0;
+    virtual FX_WCHAR			GetFormChar(FX_WCHAR wch, FX_WCHAR prev = 0, FX_WCHAR next = 0) const = 0;
+    virtual FX_WCHAR			GetFormChar(const CFX_Char *cur, const CFX_Char *prev, const CFX_Char *next) const = 0;
+};
+void FX_BidiLine(CFX_WideString &wsText, FX_INT32 iBaseLevel = 0);
+void FX_BidiLine(CFX_TxtCharArray &chars, FX_INT32 iCount, FX_INT32 iBaseLevel = 0);
+void FX_BidiLine(CFX_RTFCharArray &chars, FX_INT32 iCount, FX_INT32 iBaseLevel = 0);
 class IFX_BidiChar
 {
 public:
diff --git a/core/include/fxcrt/fx_basic.h b/core/include/fxcrt/fx_basic.h
index 22ba611..0c84f54 100644
--- a/core/include/fxcrt/fx_basic.h
+++ b/core/include/fxcrt/fx_basic.h
@@ -1578,6 +1578,13 @@
 } FX_ProgressiveStatus;
 #define ProgressiveStatus	FX_ProgressiveStatus
 #define FX_NAMESPACE_DECLARE(namespace, type)       namespace::type
+class IFX_Unknown
+{
+public:
+    virtual FX_DWORD	Release() = 0;
+    virtual FX_DWORD	AddRef() = 0;
+};
+#define FX_IsOdd(a)	((a) & 1)
 
 class CFX_Vector_3by1 : public CFX_Object
 {
diff --git a/core/include/fxcrt/fx_ext.h b/core/include/fxcrt/fx_ext.h
index 03ec488..ceba015 100644
--- a/core/include/fxcrt/fx_ext.h
+++ b/core/include/fxcrt/fx_ext.h
@@ -76,6 +76,24 @@
 #ifdef __cplusplus
 }
 #endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct FX_GUID {
+    FX_DWORD	data1;
+    FX_WORD		data2;
+    FX_WORD		data3;
+    FX_BYTE		data4[8];
+} FX_GUID, * FX_LPGUID;
+typedef FX_GUID const * FX_LPCGUID;
+
+void	FX_GUID_CreateV4(FX_LPGUID pGUID);
+
+void	FX_GUID_ToString(FX_LPCGUID pGUID, CFX_ByteString &bsStr, FX_BOOL bSeparator = TRUE);
+#ifdef __cplusplus
+}
+#endif
 template<class baseType>
 class CFX_SSortTemplate
 {
diff --git a/core/include/fxcrt/fx_stream.h b/core/include/fxcrt/fx_stream.h
index 8e298f7..0a3d1c4 100644
--- a/core/include/fxcrt/fx_stream.h
+++ b/core/include/fxcrt/fx_stream.h
@@ -162,6 +162,15 @@
 };
 IFX_FileStream*		FX_CreateFileStream(FX_LPCSTR filename, FX_DWORD dwModes);
 IFX_FileStream*		FX_CreateFileStream(FX_LPCWSTR filename, FX_DWORD dwModes);
+class IFX_FileAccess
+{
+public:
+	virtual void				Release() = 0;	
+	virtual IFX_FileAccess*		Retain() = 0;
+	virtual void				GetPath(CFX_WideString& wsPath) = 0;
+	virtual IFX_FileStream*		CreateFileStream(FX_DWORD dwModes) = 0;
+};
+IFX_FileAccess* FX_CreateDefaultFileAccess(FX_WSTR wsPath);
 class IFX_MemoryStream : public IFX_FileStream
 {
 public:
diff --git a/core/include/fxcrt/fx_ucd.h b/core/include/fxcrt/fx_ucd.h
index 9e1862a..c87e459 100644
--- a/core/include/fxcrt/fx_ucd.h
+++ b/core/include/fxcrt/fx_ucd.h
@@ -88,6 +88,20 @@
     FX_CHARTYPE_ArabicForm			= (11 << FX_CHARTYPEBITS),
     FX_CHARTYPE_Arabic				= (12 << FX_CHARTYPEBITS),
 };
+typedef struct _FX_CHARPROPERTIES {

+    union FX_CHARPROPERTIES_UNION{

+        struct FX_CHARPROPERTIES_BIT{

+            FX_DWORD	dwBreakType		: 6;

+            FX_DWORD	dwBidiClass		: 5;

+            FX_DWORD	dwCharType		: 4;

+            FX_DWORD	dwRotation		: 1;

+            FX_DWORD	dwCJKSpecial	: 1;

+            FX_DWORD	dwVertIndex		: 6;

+            FX_DWORD	dwBidiIndex		: 9;

+        };

+        FX_DWORD	dwCharProps;

+    };

+} FX_CHARPROPERTIES;

 FX_DWORD FX_GetUnicodeProperties(FX_WCHAR wch);
 FX_BOOL	FX_IsCtrlCode(FX_WCHAR ch);
 FX_BOOL	FX_IsRotationCode(FX_WCHAR ch);
@@ -95,4 +109,89 @@
 FX_BOOL	FX_IsBidiChar(FX_WCHAR wch);
 FX_WCHAR FX_GetMirrorChar(FX_WCHAR wch, FX_BOOL bRTL, FX_BOOL bVertical);
 FX_WCHAR FX_GetMirrorChar(FX_WCHAR wch, FX_DWORD dwProps, FX_BOOL bRTL, FX_BOOL bVertical);
+class CFX_Char : public CFX_Object

+{

+public:

+    CFX_Char() : m_wCharCode(0)

+        , m_nBreakType(0)

+        , m_nRotation(0)

+        , m_dwCharProps(0)

+        , m_dwCharStyles(0)

+        , m_iCharWidth(0)

+        , m_iHorizontalScale(100)

+        , m_iVertialScale(100)

+    {

+    }

+    CFX_Char(FX_WORD wCharCode, FX_DWORD dwCharProps)

+        : m_wCharCode(wCharCode)

+        , m_nBreakType(0)

+        , m_nRotation(0)

+        , m_dwCharProps(dwCharProps)

+        , m_dwCharStyles(0)

+        , m_iCharWidth(0)

+        , m_iHorizontalScale(100)

+        , m_iVertialScale(100)

+    {

+    }

+    FX_DWORD	GetCharType() const

+    {

+        return m_dwCharProps & FX_CHARTYPEBITSMASK;

+    }

+    FX_WORD		m_wCharCode;

+    FX_BYTE		m_nBreakType;

+    FX_INT8		m_nRotation;

+    FX_DWORD	m_dwCharProps;

+    FX_DWORD	m_dwCharStyles;

+    FX_INT32	m_iCharWidth;

+    FX_INT32	m_iHorizontalScale;

+    FX_INT32	m_iVertialScale;

+};

+typedef CFX_ArrayTemplate<CFX_Char>	CFX_CharArray;

+class CFX_TxtChar : public CFX_Char

+{

+public:

+    CFX_TxtChar() : CFX_Char()

+        , m_dwStatus(0)

+        , m_iBidiClass(0)

+        , m_iBidiLevel(0)

+        , m_iBidiPos(0)

+        , m_iBidiOrder(0)

+        , m_pUserData(NULL)

+    {

+    }

+    FX_DWORD			m_dwStatus;

+    FX_INT16			m_iBidiClass;

+    FX_INT16			m_iBidiLevel;

+    FX_INT16			m_iBidiPos;

+    FX_INT16			m_iBidiOrder;

+    FX_LPVOID			m_pUserData;

+};

+typedef CFX_ArrayTemplate<CFX_TxtChar>	CFX_TxtCharArray;

+class CFX_RTFChar : public CFX_Char

+{

+public:

+    CFX_RTFChar() : CFX_Char()

+        , m_dwStatus(0)

+        , m_iFontSize(0)

+        , m_iFontHeight(0)

+        , m_iBidiClass(0)

+        , m_iBidiLevel(0)

+        , m_iBidiPos(0)

+        , m_dwLayoutStyles(0)

+        , m_dwIdentity(0)

+        , m_pUserData(NULL)

+    {

+    }

+    FX_DWORD			m_dwStatus;

+    FX_INT32			m_iFontSize;

+    FX_INT32			m_iFontHeight;

+    FX_INT16			m_iBidiClass;

+    FX_INT16			m_iBidiLevel;

+    FX_INT16			m_iBidiPos;

+    FX_INT16			m_iBidiOrder;

+    FX_DWORD			m_dwLayoutStyles;

+    FX_DWORD			m_dwIdentity;

+    IFX_Unknown			*m_pUserData;

+};

+typedef CFX_ArrayTemplate<CFX_RTFChar>	CFX_RTFCharArray;

 #endif
diff --git a/core/include/fxge/fx_font.h b/core/include/fxge/fx_font.h
index 52f8f30..8744919 100644
--- a/core/include/fxge/fx_font.h
+++ b/core/include/fxge/fx_font.h
@@ -29,6 +29,7 @@
 #define FXFONT_ITALIC			0x40
 #define FXFONT_BOLD				0x40000
 #define FXFONT_USEEXTERNATTR	0x80000
+#define FXFONT_EXACTMATCH		0x80000000

 #define FXFONT_CIDFONT			0x100000
 #define FXFONT_ANSI_CHARSET		0
 #define FXFONT_DEFAULT_CHARSET	1
@@ -61,7 +62,10 @@
 
     FX_BOOL					LoadEmbedded(FX_LPCBYTE data, FX_DWORD size);
 
-    FX_BOOL					LoadFile(IFX_FileRead* pFile);
+	FX_BOOL					LoadFile(IFX_FileRead* pFile, int nFaceIndex = 0, int* pFaceCount = NULL);

+

+    FX_BOOL                 LoadClone(const CFX_Font* pFont);

+

 
     FXFT_Face				GetFace() const
     {
@@ -141,6 +145,7 @@
 
     FX_BOOL					m_bEmbedded;
     FX_BOOL					m_bVertical;
+    FX_BOOL                 m_bLogic;

     void*					m_pOwnedStream;
 };
 #define ENCODING_INTERNAL		0
@@ -157,6 +162,32 @@
     virtual FX_DWORD		CharCodeFromUnicode(FX_WCHAR Unicode) const = 0;
 };
 IFX_FontEncoding* FXGE_CreateUnicodeEncoding(CFX_Font* pFont);
+#define FXFM_ENC_TAG(a, b, c, d) (((FX_DWORD)(a) << 24) | ((FX_DWORD)(b) << 16) | ((FX_DWORD)(c) << 8) | (FX_DWORD)(d))

+#define FXFM_ENCODING_NONE				FXFM_ENC_TAG(0, 0, 0, 0)

+#define FXFM_ENCODING_MS_SYMBOL			FXFM_ENC_TAG('s', 'y', 'm', 'b')

+#define FXFM_ENCODING_UNICODE			FXFM_ENC_TAG('u', 'n', 'i', 'c')

+#define FXFM_ENCODING_MS_SJIS			FXFM_ENC_TAG('s', 'j', 'i', 's')

+#define FXFM_ENCODING_MS_GB2312			FXFM_ENC_TAG('g', 'b', ' ', ' ')

+#define FXFM_ENCODING_MS_BIG5			FXFM_ENC_TAG('b', 'i', 'g', '5')

+#define FXFM_ENCODING_MS_WANSUNG		FXFM_ENC_TAG('w', 'a', 'n', 's')

+#define FXFM_ENCODING_MS_JOHAB			FXFM_ENC_TAG('j', 'o', 'h', 'a')

+#define FXFM_ENCODING_ADOBE_STANDARD	FXFM_ENC_TAG('A', 'D', 'O', 'B')

+#define FXFM_ENCODING_ADOBE_EXPERT		FXFM_ENC_TAG('A', 'D', 'B', 'E')

+#define FXFM_ENCODING_ADOBE_CUSTOM		FXFM_ENC_TAG('A', 'D', 'B', 'C')

+#define FXFM_ENCODING_ADOBE_LATIN_1		FXFM_ENC_TAG('l', 'a', 't', '1')

+#define FXFM_ENCODING_OLD_LATIN_2		FXFM_ENC_TAG('l', 'a', 't', '2')

+#define FXFM_ENCODING_APPLE_ROMAN		FXFM_ENC_TAG('a', 'r', 'm', 'n')

+class IFX_FontEncodingEx : public IFX_FontEncoding

+{

+public:

+

+    virtual FX_DWORD		GlyphIndexFromName(FX_LPCSTR pStrName) = 0;

+

+    virtual CFX_ByteString	NameFromGlyphIndex(FX_DWORD dwGlyphIndex) = 0;

+

+    virtual FX_DWORD		CharCodeFromGlyphIndex(FX_DWORD dwGlyphIndex) = 0;

+};

+IFX_FontEncodingEx*	FX_CreateFontEncodingEx(CFX_Font* pFont, FX_DWORD nEncodingID = FXFM_ENCODING_NONE);

 #define FXFONT_SUBST_MM				0x01
 #define FXFONT_SUBST_GLYPHPATH		0x04
 #define FXFONT_SUBST_CLEARTYPE		0x08
@@ -277,6 +308,7 @@
     }
     virtual FXFT_Face	FindSubstFont(const CFX_ByteString& face_name, FX_BOOL bTrueType, FX_DWORD flags,
                                       int weight, int italic_angle, int CharsetCP, CFX_SubstFont* pSubstFont);
+    FXFT_Face	FindSubstFontByUnicode(FX_DWORD dwUnicode, FX_DWORD flags, int weight, int italic_angle);

 private:
     CFX_ByteString		GetPSNameFromTT(void* hFont);
     CFX_ByteString		MatchInstalledFonts(const CFX_ByteString& norm_name);
@@ -298,6 +330,10 @@
     virtual void		Release() = 0;
     virtual	FX_BOOL		EnumFontList(CFX_FontMapper* pMapper) = 0;
     virtual void*		MapFont(int weight, FX_BOOL bItalic, int charset, int pitch_family, FX_LPCSTR face, FX_BOOL& bExact) = 0;
+    virtual void*		MapFontByUnicode(FX_DWORD dwUnicode, int weight, FX_BOOL bItalic, int pitch_family)

+    {

+        return NULL;

+    }

     virtual void*		GetFont(FX_LPCSTR face) = 0;
     virtual FX_DWORD	GetFontData(void* hFont, FX_DWORD table, FX_LPBYTE buffer, FX_DWORD size) = 0;
     virtual FX_BOOL		GetFaceName(void* hFont, CFX_ByteString& name) = 0;
@@ -321,6 +357,7 @@
     virtual void		Release();
     virtual	FX_BOOL		EnumFontList(CFX_FontMapper* pMapper);
     virtual void*		MapFont(int weight, FX_BOOL bItalic, int charset, int pitch_family, FX_LPCSTR face, FX_BOOL& bExact);
+    virtual void*		MapFontByUnicode(FX_DWORD dwUnicode, int weight, FX_BOOL bItalic, int pitch_family);

     virtual void*		GetFont(FX_LPCSTR face);
     virtual FX_DWORD	GetFontData(void* hFont, FX_DWORD table, FX_LPBYTE buffer, FX_DWORD size);
     virtual void		DeleteFont(void* hFont);
diff --git a/core/src/fpdfdoc/doc_formfield.cpp b/core/src/fpdfdoc/doc_formfield.cpp
index a2f0fbd..64e9c28 100644
--- a/core/src/fpdfdoc/doc_formfield.cpp
+++ b/core/src/fpdfdoc/doc_formfield.cpp
@@ -797,6 +797,77 @@
     }
     return -1;
 }
+int CPDF_FormField::InsertOption(CFX_WideString csOptLabel, int index, FX_BOOL bNotify)

+{

+    if (csOptLabel.IsEmpty()) return -1;

+

+    if (bNotify && m_pForm->m_pFormNotify != NULL)

+    {

+        int iRet = 0;

+        if (GetType() == ListBox) iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csOptLabel);

+        if (GetType() == ComboBox) iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csOptLabel);

+        if (iRet < 0) return -1;

+    }

+

+    CFX_ByteString csStr = PDF_EncodeText(csOptLabel, csOptLabel.GetLength());

+    CPDF_Array* pOpt = NULL;

+    CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");

+    if (pValue == NULL || pValue->GetType() != PDFOBJ_ARRAY)

+    {

+        pOpt = CPDF_Array::Create();

+        if (pOpt == NULL) return -1;

+        m_pDict->SetAt("Opt", pOpt);

+    }

+    else

+        pOpt = (CPDF_Array*)pValue;

+    int iCount = (int)pOpt->GetCount();

+    if (index < 0 || index >= iCount)

+    {

+        pOpt->AddString(csStr);

+        index = iCount;

+    }

+    else {

+        CPDF_String* pString = CPDF_String::Create(csStr);

+        if (pString == NULL) return -1;

+        pOpt->InsertAt(index, pString);

+    }

+

+    if (bNotify && m_pForm->m_pFormNotify != NULL)

+    {

+        if (GetType() == ListBox) m_pForm->m_pFormNotify->AfterSelectionChange(this);

+        if (GetType() == ComboBox) m_pForm->m_pFormNotify->AfterValueChange(this);

+    }

+    m_pForm->m_bUpdated = TRUE;

+    return index;

+}
+FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify)

+{

+    if (bNotify && m_pForm->m_pFormNotify != NULL)

+    {

+        int iRet = 0;

+        CFX_WideString csValue;

+        int iIndex = GetSelectedIndex(0);

+        if (iIndex >= 0) csValue = GetOptionLabel(iIndex);

+        if (GetType() == ListBox) iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);

+        if (GetType() == ComboBox) iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);

+        if (iRet < 0) return FALSE;

+    }

+

+    m_pDict->RemoveAt("Opt");

+    m_pDict->RemoveAt("V");

+    m_pDict->RemoveAt("DV");

+    m_pDict->RemoveAt("I");

+    m_pDict->RemoveAt("TI");

+

+    if (bNotify && m_pForm->m_pFormNotify != NULL)

+    {

+        if (GetType() == ListBox) m_pForm->m_pFormNotify->AfterSelectionChange(this);

+        if (GetType() == ComboBox) m_pForm->m_pFormNotify->AfterValueChange(this);

+    }

+

+    m_pForm->m_bUpdated = TRUE;

+    return TRUE;

+}
 FX_BOOL CPDF_FormField::CheckControl(int iControlIndex, FX_BOOL bChecked, FX_BOOL bNotify)
 {
     ASSERT(GetType() == CheckBox || GetType() == RadioButton);
diff --git a/core/src/fxcodec/codec/codec_int.h b/core/src/fxcodec/codec/codec_int.h
index 78672e6..3cbdce9 100644
--- a/core/src/fxcodec/codec/codec_int.h
+++ b/core/src/fxcodec/codec/codec_int.h
@@ -142,13 +142,67 @@
     virtual void*		Start();
     virtual void		Finish(void* pContext);
     virtual void		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size);
-    virtual int			ReadHeader(void* pContext, int* width, int* height, int* nComps);
+    virtual int			ReadHeader(void* pContext, int* width, int* height, int* nComps, CFX_DIBAttribute* pAttribute = NULL);

     virtual FX_BOOL		StartScanline(void* pContext, int down_scale);
     virtual FX_BOOL		ReadScanline(void* pContext, FX_LPBYTE dest_buf);
     virtual FX_DWORD	GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr);
 protected:
     IFX_JpegProvider* m_pExtProvider;
 };
+#define PNG_ERROR_SIZE 256

+class CCodec_PngModule : public ICodec_PngModule

+{

+public:

+    CCodec_PngModule()

+    {

+        FXSYS_memset8(m_szLastError, '\0', PNG_ERROR_SIZE);

+    }

+

+    virtual void*		Start(void* pModule);

+    virtual void		Finish(void* pContext);

+    virtual FX_BOOL		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_DIBAttribute* pAttribute);

+protected:

+    FX_CHAR				m_szLastError[PNG_ERROR_SIZE];

+};

+class CCodec_GifModule : public ICodec_GifModule

+{

+public:

+    CCodec_GifModule()

+    {

+        FXSYS_memset8(m_szLastError, '\0', 256);

+    }

+    virtual void*		Start(void* pModule);

+    virtual void		Finish(void* pContext);

+    virtual FX_DWORD	GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr);

+    virtual void		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size);

+

+    virtual FX_INT32	ReadHeader(void* pContext, int* width, int* height,

+                                   int* pal_num, void** pal_pp, int* bg_index, CFX_DIBAttribute* pAttribute);

+

+    virtual FX_INT32	LoadFrameInfo(void* pContext, int* frame_num);

+

+    virtual FX_INT32	LoadFrame(void* pContext, int frame_num, CFX_DIBAttribute* pAttribute);

+

+protected:

+    FX_CHAR				m_szLastError[256];

+};

+class CCodec_BmpModule : public ICodec_BmpModule

+{

+public:

+    CCodec_BmpModule()

+    {

+        FXSYS_memset8(m_szLastError, '\0', 256);

+    }

+    virtual void*		Start(void* pModule);

+    virtual void		Finish(void* pContext);

+    virtual FX_DWORD	GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr);

+    virtual void		Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size);

+    virtual FX_INT32	ReadHeader(void* pContext, FX_INT32* width, FX_INT32* height, FX_BOOL* tb_flag, FX_INT32* components, FX_INT32* pal_num, FX_DWORD** pal_pp, CFX_DIBAttribute* pAttribute);

+    virtual FX_INT32	LoadImage(void* pContext);

+

+protected:

+    FX_CHAR				m_szLastError[256];

+};

 class CCodec_IccModule : public ICodec_IccModule
 {
 public:
@@ -196,6 +250,15 @@
     FX_BOOL		Decode(void* ctx, FX_LPBYTE dest_data, int pitch, FX_BOOL bTranslateColor, FX_LPBYTE offsets);
     void		DestroyDecoder(void* ctx);
 };
+class CCodec_TiffModule : public ICodec_TiffModule

+{

+public:

+    virtual FX_LPVOID 	CreateDecoder(IFX_FileRead* file_ptr);

+    virtual void		GetFrames(FX_LPVOID ctx, FX_INT32& frames);

+    virtual FX_BOOL		LoadFrameInfo(FX_LPVOID ctx, FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute = NULL);

+    virtual FX_BOOL		Decode(FX_LPVOID ctx, class CFX_DIBitmap* pDIBitmap);

+    virtual void		DestroyDecoder(FX_LPVOID ctx);

+};

 #include "../jbig2/JBig2_Context.h"
 class CPDF_Jbig2Interface : public CFX_Object, public CJBig2_Module
 {
@@ -270,3 +333,27 @@
     CPDF_Jbig2Interface	m_Module;
 private:
 };
+class CFX_DIBAttributeExif : public IFX_DIBAttributeExif

+{

+public:

+    CFX_DIBAttributeExif();

+    ~CFX_DIBAttributeExif();

+    virtual FX_BOOL		GetInfo(FX_WORD tag, FX_LPVOID val);

+

+    FX_BOOL ParseExif(CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE>* pHead, FX_LPBYTE data, FX_DWORD len, CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE>* pVal);

+

+    typedef FX_WORD (*_Read2Bytes)(FX_LPBYTE data);

+    typedef FX_DWORD (*_Read4Bytes)(FX_LPBYTE data);

+    FX_LPBYTE ParseExifIFH(FX_LPBYTE data, FX_DWORD len, _Read2Bytes* pReadWord, _Read4Bytes* pReadDword);

+    FX_BOOL ParseExifIFD(CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE>* pMap, FX_LPBYTE data, FX_DWORD len);

+

+    FX_LPBYTE			m_pExifData;

+

+    FX_DWORD			m_dwExifDataLen;

+

+    void				clear();

+    _Read2Bytes m_readWord;

+    _Read4Bytes m_readDword;

+    CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE> m_TagHead;

+    CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE> m_TagVal;

+};

diff --git a/core/src/fxcodec/codec/fx_codec.cpp b/core/src/fxcodec/codec/fx_codec.cpp
index 456ec40..b2f70c7 100644
--- a/core/src/fxcodec/codec/fx_codec.cpp
+++ b/core/src/fxcodec/codec/fx_codec.cpp
@@ -14,6 +14,10 @@
     m_pJpxModule = FX_NEW CCodec_JpxModule;
     m_pJbig2Module = FX_NEW CCodec_Jbig2Module;
     m_pIccModule = FX_NEW CCodec_IccModule;
+    m_pPngModule = FX_NEW CCodec_PngModule;

+    m_pGifModule = FX_NEW CCodec_GifModule;

+    m_pBmpModule = FX_NEW CCodec_BmpModule;

+    m_pTiffModule = FX_NEW CCodec_TiffModule;

     m_pFlateModule = FX_NEW CCodec_FlateModule;
 }
 CCodec_ModuleMgr::~CCodec_ModuleMgr()
@@ -249,6 +253,343 @@
 {
     delete this;
 }
+CFX_DIBAttribute::CFX_DIBAttribute()

+{

+    FXSYS_memset32(this, 0, sizeof(CFX_DIBAttribute));

+    m_nXDPI = -1;

+    m_nYDPI = -1;

+    m_fAspectRatio = -1.0f;

+    m_pExif = FX_NEW CFX_DIBAttributeExif;

+}

+CFX_DIBAttribute::~CFX_DIBAttribute()

+{

+    if (m_pExif) {

+        delete m_pExif;

+    }

+}

+CFX_DIBAttributeExif::CFX_DIBAttributeExif()

+{

+    m_pExifData = NULL;

+    m_dwExifDataLen = 0;

+}

+CFX_DIBAttributeExif::~CFX_DIBAttributeExif()

+{

+    clear();

+}

+void CFX_DIBAttributeExif::clear()

+{

+    if (m_pExifData) {

+        FX_Free(m_pExifData);

+    }

+    m_pExifData = NULL;

+    FX_DWORD key = 0;

+    FX_LPBYTE buf = NULL;

+    FX_POSITION pos = NULL;

+    pos = m_TagHead.GetStartPosition();

+    while (pos) {

+        m_TagHead.GetNextAssoc(pos, key, buf);

+        if (buf) {

+            FX_Free(buf);

+        }

+    }

+    m_TagHead.RemoveAll();

+    pos = m_TagVal.GetStartPosition();

+    while (pos) {

+        m_TagVal.GetNextAssoc(pos, key, buf);

+        if (buf) {

+            FX_Free(buf);

+        }

+    }

+    m_TagVal.RemoveAll();

+}

+static FX_WORD _Read2BytesL(FX_LPBYTE data)

+{

+    ASSERT(data);

+    return data[0] | (data[1] << 8);

+}

+static FX_WORD _Read2BytesB(FX_LPBYTE data)

+{

+    ASSERT(data);

+    return data[1] | (data[0] << 8);

+}

+static FX_DWORD _Read4BytesL(FX_LPBYTE data)

+{

+    return _Read2BytesL(data) | (_Read2BytesL(data + 2) << 16);

+}

+static FX_DWORD _Read4BytesB(FX_LPBYTE data)

+{

+    return _Read2BytesB(data + 2) | (_Read2BytesB(data) << 16);

+}

+typedef FX_WORD (*_Read2Bytes) (FX_LPBYTE data);

+typedef FX_DWORD (*_Read4Bytes) (FX_LPBYTE data);

+typedef void (*_Write2Bytes) (FX_LPBYTE data, FX_WORD val);

+typedef void (*_Write4Bytes) (FX_LPBYTE data, FX_DWORD val);

+FX_LPBYTE CFX_DIBAttributeExif::ParseExifIFH(FX_LPBYTE data, FX_DWORD len, _Read2Bytes* pReadWord, _Read4Bytes* pReadDword)

+{

+    if (len > 8) {

+        FX_BOOL tag = FALSE;

+        if (FXSYS_memcmp32(data, "\x49\x49\x2a\x00", 4) == 0) {

+            if (pReadWord) {

+                *pReadWord = _Read2BytesL;

+            }

+            if (pReadDword) {

+                *pReadDword = _Read4BytesL;

+            }

+            tag = TRUE;

+        } else if (FXSYS_memcmp32(data, "\x4d\x4d\x00\x2a", 4) == 0) {

+            if (pReadWord) {

+                *pReadWord = _Read2BytesB;

+            }

+            if (pReadDword) {

+                *pReadDword = _Read4BytesB;

+            }

+            tag = TRUE;

+        }

+        if (tag) {

+            data += 4;

+            if (pReadDword) {

+                data += (*pReadDword)(data) - 4;

+            } else {

+                data += 4;

+            }

+        }

+    }

+    return data;

+}

+FX_BOOL CFX_DIBAttributeExif::ParseExifIFD(CFX_MapPtrTemplate<FX_DWORD, FX_LPBYTE>* pMap, FX_LPBYTE data, FX_DWORD len)

+{

+    if (pMap && data) {

+        if (len > 8) {

+            FX_WORD wTagNum = m_readWord(data);

+            data += 2;

+            FX_DWORD wTag;

+            FX_LPBYTE buf;

+            while (wTagNum--) {

+                wTag = m_readWord(data);

+                data += 2;

+                if (!pMap->Lookup(wTag, buf)) {

+                    buf = FX_Alloc(FX_BYTE, 10);

+                    if (buf == NULL) {

+                        return FALSE;

+                    }

+                    FXSYS_memcpy32(buf, data, 10);

+                    pMap->SetAt(wTag, buf);

+                }

+                data += 10;

+            }

+            FX_DWORD dwIFDOffset;

+            dwIFDOffset = m_readDword(data);

+            while (dwIFDOffset && dwIFDOffset < len) {

+                data = m_pExifData + dwIFDOffset;

+                wTagNum = m_readWord(data);

+                data += 2;

+                while (wTagNum--) {

+                    wTag = m_readWord(data);

+                    data += 2;

+                    if (!pMap->Lookup(wTag, buf)) {

+                        buf = FX_Alloc(FX_BYTE, 10);

+                        if (buf == NULL) {

+                            return FALSE;

+                        }

+                        FXSYS_memcpy32(buf, data, 10);

+                        pMap->SetAt(wTag, buf);

+                    }

+                    data += 10;

+                }

+                dwIFDOffset = m_readDword(data);

+            }

+            return TRUE;

+        }

+    }

+    return FALSE;

+}

+enum FX_ExifDataType {

+    FX_UnsignedByte = 1,

+    FX_AscString,

+    FX_UnsignedShort,

+    FX_UnsignedLong,

+    FX_UnsignedRation,

+    FX_SignedByte,

+    FX_Undefined,

+    FX_SignedShort,

+    FX_SignedLong,

+    FX_SignedRation,

+    FX_SignedFloat,

+    FX_DoubleFloat

+};

+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)

+{

+    if (pHead && data && pVal) {

+        if (len > 8) {

+            FX_LPBYTE old_data = data;

+            data = ParseExifIFH(data, len, &m_readWord, &m_readDword);

+            if (data == old_data) {

+                return FALSE;

+            }

+            if (pHead->GetCount() == 0) {

+                if (!ParseExifIFD(pHead, data, len)) {

+                    return FALSE;

+                }

+            }

+            FX_DWORD dwModuleNum;

+            FX_WORD type;

+            FX_DWORD dwSize;

+            FX_DWORD tag;

+            FX_LPBYTE head;

+            FX_POSITION pos = pHead->GetStartPosition();

+            while (pos) {

+                pHead->GetNextAssoc(pos, tag, head);

+                FX_LPBYTE val = NULL, buf = NULL, temp = NULL;

+                int i;

+                if (head) {

+                    type = m_readWord(head);

+                    head += 2;

+                    dwModuleNum = m_readDword(head);

+                    head += 4;

+                    switch (type) {

+                        case FX_UnsignedByte:

+                        case FX_AscString:

+                        case FX_SignedByte:

+                        case FX_Undefined:

+                            dwSize = dwModuleNum;

+                            val = FX_Alloc(FX_BYTE, dwSize);

+                            if (val == NULL) {

+                                return FALSE;

+                            }

+                            if (dwSize > 4) {

+                                FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);

+                            } else {

+                                FXSYS_memcpy32(val, head, dwSize);

+                            }

+                            break;

+                        case FX_UnsignedShort:

+                        case FX_SignedShort:

+                            dwSize = dwModuleNum << 1;

+                            val = FX_Alloc(FX_BYTE, dwSize);

+                            if (val == NULL) {

+                                return FALSE;

+                            }

+                            if (dwSize > 4) {

+                                FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);

+                            } else {

+                                FXSYS_memcpy32(val, head, dwSize);

+                            }

+                            buf = val;

+                            for(i = 0; i < (int)dwModuleNum; i ++) {

+                                *(FX_WORD*)buf = m_readWord(buf);

+                                buf += 2;

+                            }

+                            break;

+                        case FX_UnsignedLong:

+                        case FX_SignedLong:

+                        case FX_SignedFloat:

+                            dwSize = dwModuleNum << 2;

+                            val = FX_Alloc(FX_BYTE, dwSize);

+                            if (val == NULL) {

+                                return FALSE;

+                            }

+                            if (dwSize > 4) {

+                                FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);

+                            } else {

+                                FXSYS_memcpy32(val, head, dwSize);

+                            }

+                            buf = val;

+                            for(i = 0; i < (int)dwModuleNum; i ++) {

+                                *(FX_DWORD*)buf = m_readDword(buf);

+                                buf += 4;

+                            }

+                            break;

+                        case FX_UnsignedRation:

+                        case FX_SignedRation: {

+                                dwSize = dwModuleNum << 3;

+                                buf = FX_Alloc(FX_BYTE, dwSize);

+                                if (buf == NULL) {

+                                    return FALSE;

+                                }

+                                if (dwSize > 4) {

+                                    FXSYS_memcpy32(buf, old_data + m_readDword(head), dwSize);

+                                } else {

+                                    FXSYS_memcpy32(buf, head, dwSize);

+                                }

+                                temp = buf;

+                                val = FX_Alloc(FX_BYTE, dwSize / 2);

+                                if (val == NULL) {

+                                    FX_Free(buf);

+                                    return FALSE;

+                                }

+                                for(i = 0; i < (int)dwModuleNum; i ++) {

+                                    *(FX_DWORD*)temp = m_readDword(temp);

+                                    *(FX_DWORD*)(temp + 4) = m_readDword(temp + 4);

+                                    FX_DWORD* lNumerator = (FX_DWORD*)temp;

+                                    FX_DWORD* lNenominator = (FX_DWORD*)(temp + 4);

+                                    *(FX_FLOAT*)(val + i * 4) = (FX_FLOAT)(*lNumerator) / (FX_FLOAT)(*lNenominator);

+                                    temp += 8;

+                                }

+                                FX_Free(buf);

+                            }

+                            break;

+                        case FX_DoubleFloat:

+                            dwSize = dwModuleNum << 3;

+                            val = FX_Alloc(FX_BYTE, dwSize);

+                            if (val == NULL) {

+                                return FALSE;

+                            }

+                            if (dwSize > 4) {

+                                FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize);

+                            } else {

+                                FXSYS_memcpy32(val, head, dwSize);

+                            }

+                            buf = val;

+                            for(i = 0; i < (int)dwModuleNum; i ++) {

+                                *(FX_DWORD*)buf = m_readDword(buf);

+                                *(FX_DWORD*)(buf + 4) = m_readDword(buf + 4);

+                                buf += 8;

+                            }

+                            break;

+                        default:

+                            return FALSE;

+                    }

+                }

+                pVal->SetAt(tag, val);

+            }

+            return TRUE;

+        }

+    }

+    return FALSE;

+}

+#define FXEXIF_INFOCONVERT(T) {T* src = (T*)ptr;	T* dst = (T*)val;	*dst = *src;}

+FX_BOOL CFX_DIBAttributeExif::GetInfo( FX_WORD tag, FX_LPVOID val )

+{

+    if (m_TagVal.GetCount() == 0) {

+        if (!ParseExif(&m_TagHead, m_pExifData, m_dwExifDataLen, &m_TagVal)) {

+            return FALSE;

+        }

+    }

+    FX_LPBYTE ptr = NULL;

+    if (m_TagVal.Lookup(tag, ptr)) {

+        switch (tag) {

+            case EXIFTAG_USHORT_RESUNIT:

+                FXEXIF_INFOCONVERT(FX_WORD);

+                {

+                    FX_WORD* ptr = (FX_WORD*)val;

+                    *ptr -= 1;

+                }

+                break;

+            case EXIFTAG_FLOAT_DPIX:

+            case EXIFTAG_FLOAT_DPIY:

+                FXEXIF_INFOCONVERT(FX_FLOAT);

+                break;

+            case EXIFTAG_USHORT_ORIENTATION:

+                FXEXIF_INFOCONVERT(FX_WORD);

+                break;

+            default: {

+                    FX_LPBYTE* dst = (FX_LPBYTE*)val;

+                    *dst = ptr;

+                }

+        }

+    }

+    return TRUE;

+}

 class CCodec_RLScanlineDecoder : public CCodec_ScanlineDecoder
 {
 public:
diff --git a/core/src/fxcodec/codec/fx_codec_bmp.cpp b/core/src/fxcodec/codec/fx_codec_bmp.cpp
new file mode 100644
index 0000000..4e974e2
--- /dev/null
+++ b/core/src/fxcodec/codec/fx_codec_bmp.cpp
@@ -0,0 +1,124 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../../../include/fxcodec/fx_codec.h"

+#include "../../../include/fxge/fx_dib.h"

+#include "codec_int.h"

+#include "../lbmp/fx_bmp.h"

+struct FXBMP_Context {

+    bmp_decompress_struct_p bmp_ptr;

+    void*		parent_ptr;

+    void*		child_ptr;

+

+    void*		(*m_AllocFunc)(unsigned int);

+    void		(*m_FreeFunc)(void*);

+};

+extern "C" {

+    static void* _bmp_alloc_func(unsigned int size)

+    {

+        return FX_Alloc(char, size);

+    }

+    static void  _bmp_free_func(void* p)

+    {

+        if(p != NULL) {

+            FX_Free(p);

+        }

+    }

+};

+static void _bmp_error_data(bmp_decompress_struct_p bmp_ptr, FX_LPCSTR err_msg)

+{

+    FXSYS_strncpy((char*)bmp_ptr->err_ptr, err_msg, BMP_MAX_ERROR_SIZE - 1);

+    longjmp(bmp_ptr->jmpbuf, 1);

+}

+static void _bmp_read_scanline(bmp_decompress_struct_p bmp_ptr, FX_INT32 row_num, FX_LPBYTE row_buf)

+{

+    FXBMP_Context* p = (FXBMP_Context*)bmp_ptr->context_ptr;

+    CCodec_BmpModule* pModule = (CCodec_BmpModule*)p->parent_ptr;

+    pModule->ReadScanlineCallback(p->child_ptr, row_num, row_buf);

+}

+static FX_BOOL _bmp_get_data_position(bmp_decompress_struct_p bmp_ptr, FX_DWORD rcd_pos)

+{

+    FXBMP_Context* p = (FXBMP_Context*)bmp_ptr->context_ptr;

+    CCodec_BmpModule* pModule = (CCodec_BmpModule*)p->parent_ptr;

+    return pModule->InputImagePositionBufCallback(p->child_ptr, rcd_pos);

+}

+void* CCodec_BmpModule::Start(void* pModule)

+{

+    FXBMP_Context* p = (FXBMP_Context*)FX_Alloc(FX_BYTE, sizeof(FXBMP_Context));

+    if (p == NULL) {

+        return NULL;

+    }

+    FXSYS_memset32(p, 0, sizeof(FXBMP_Context));

+    if(p == NULL) {

+        return NULL;

+    }

+    p->m_AllocFunc = _bmp_alloc_func;

+    p->m_FreeFunc = _bmp_free_func;

+    p->bmp_ptr = NULL;

+    p->parent_ptr = (void*)this;

+    p->child_ptr = pModule;

+    p->bmp_ptr = _bmp_create_decompress();

+    if (p->bmp_ptr == NULL) {

+        FX_Free(p);

+        return NULL;

+    }

+    p->bmp_ptr->context_ptr = (void*)p;

+    p->bmp_ptr->err_ptr = m_szLastError;

+    p->bmp_ptr->_bmp_error_fn = _bmp_error_data;

+    p->bmp_ptr->_bmp_get_row_fn = _bmp_read_scanline;

+    p->bmp_ptr->_bmp_get_data_position_fn = _bmp_get_data_position;

+    return p;

+}

+void CCodec_BmpModule::Finish(void* pContext)

+{

+    FXBMP_Context* p = (FXBMP_Context*)pContext;

+    if(p != NULL) {

+        _bmp_destroy_decompress(&p->bmp_ptr);

+        p->m_FreeFunc(p);

+    }

+}

+FX_INT32 CCodec_BmpModule::ReadHeader(void* pContext, FX_INT32* width, FX_INT32* height, FX_BOOL* tb_flag, FX_INT32* components, FX_INT32* pal_num, FX_DWORD** pal_pp, CFX_DIBAttribute* pAttribute)

+{

+    FXBMP_Context* p = (FXBMP_Context*)pContext;

+    if(setjmp(p->bmp_ptr->jmpbuf)) {

+        return 0;

+    }

+    FX_INT32 ret = _bmp_read_header(p->bmp_ptr);

+    if (ret != 1) {

+        return ret;

+    }

+    *width = p->bmp_ptr->width;

+    *height = p->bmp_ptr->height;

+    *tb_flag = p->bmp_ptr->imgTB_flag;

+    *components = p->bmp_ptr->components;

+    *pal_num = p->bmp_ptr->pal_num;

+    *pal_pp = p->bmp_ptr->pal_ptr;

+    if (pAttribute) {

+        pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_METER;

+        pAttribute->m_nXDPI = p->bmp_ptr->dpi_x;

+        pAttribute->m_nYDPI = p->bmp_ptr->dpi_y;

+        pAttribute->m_nBmpCompressType = p->bmp_ptr->compress_flag;

+    }

+    return 1;

+}

+FX_INT32 CCodec_BmpModule::LoadImage(void* pContext)

+{

+    FXBMP_Context* p = (FXBMP_Context*)pContext;

+    if(setjmp(p->bmp_ptr->jmpbuf)) {

+        return 0;

+    }

+    return _bmp_decode_image(p->bmp_ptr);

+}

+FX_DWORD CCodec_BmpModule::GetAvailInput(void* pContext, FX_LPBYTE* avial_buf_ptr)

+{

+    FXBMP_Context* p = (FXBMP_Context*)pContext;

+    return _bmp_get_avail_input(p->bmp_ptr, avial_buf_ptr);

+}

+void CCodec_BmpModule::Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size)

+{

+    FXBMP_Context* p = (FXBMP_Context*)pContext;

+    _bmp_input_buffer(p->bmp_ptr, (FX_LPBYTE)src_buf, src_size);

+}

diff --git a/core/src/fxcodec/codec/fx_codec_gif.cpp b/core/src/fxcodec/codec/fx_codec_gif.cpp
new file mode 100644
index 0000000..1fc708d
--- /dev/null
+++ b/core/src/fxcodec/codec/fx_codec_gif.cpp
@@ -0,0 +1,176 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../../../include/fxcodec/fx_codec.h"

+#include "../../../include/fxge/fx_dib.h"

+#include "codec_int.h"

+#include "../lgif/fx_gif.h"

+struct FXGIF_Context {

+    gif_decompress_struct_p gif_ptr;

+    void*		parent_ptr;

+    void*		child_ptr;

+

+    void*		(*m_AllocFunc)(unsigned int);

+    void		(*m_FreeFunc)(void*);

+};

+extern "C" {

+    static void* _gif_alloc_func(unsigned int size)

+    {

+        return FX_Alloc(char, size);

+    }

+    static void  _gif_free_func(void* p)

+    {

+        if(p != NULL) {

+            FX_Free(p);

+        }

+    }

+};

+static void _gif_error_data(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg)

+{

+    FXSYS_strncpy((char*)gif_ptr->err_ptr, err_msg, GIF_MAX_ERROR_SIZE - 1);

+    longjmp(gif_ptr->jmpbuf, 1);

+}

+static FX_LPBYTE _gif_ask_buf_for_pal(gif_decompress_struct_p gif_ptr, FX_INT32 pal_size)

+{

+    FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;

+    CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;

+    return pModule->AskLocalPaletteBufCallback(p->child_ptr,

+            _gif_get_frame_num(gif_ptr),

+            pal_size);

+}

+static void _gif_record_current_position(gif_decompress_struct_p gif_ptr, FX_DWORD* cur_pos_ptr)

+{

+    FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;

+    CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;

+    pModule->RecordCurrentPositionCallback(p->child_ptr, *cur_pos_ptr);

+}

+static void _gif_read_scanline(gif_decompress_struct_p gif_ptr, FX_INT32 row_num, FX_LPBYTE row_buf)

+{

+    FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;

+    CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;

+    pModule->ReadScanlineCallback(p->child_ptr, row_num, row_buf);

+}

+static FX_BOOL _gif_get_record_position(gif_decompress_struct_p gif_ptr, FX_DWORD cur_pos,

+                                        FX_INT32 left, FX_INT32 top, FX_INT32 width, FX_INT32 height,

+                                        FX_INT32 pal_num, void* pal_ptr,

+                                        FX_INT32 delay_time, FX_BOOL user_input,

+                                        FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace)

+{

+    FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;

+    CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;

+    return pModule->InputRecordPositionBufCallback(p->child_ptr, cur_pos, FX_RECT(left, top, left + width, top + height),

+            pal_num, pal_ptr, delay_time, user_input, trans_index, disposal_method, interlace);

+}

+void* CCodec_GifModule::Start(void* pModule)

+{

+    FXGIF_Context* p = (FXGIF_Context*)FX_Alloc(FX_BYTE, sizeof(FXGIF_Context));

+    if (p == NULL) {

+        return NULL;

+    }

+    FXSYS_memset32(p, 0, sizeof(FXGIF_Context));

+    p->m_AllocFunc = _gif_alloc_func;

+    p->m_FreeFunc = _gif_free_func;

+    p->gif_ptr = NULL;

+    p->parent_ptr = (void*)this;

+    p->child_ptr = pModule;

+    p->gif_ptr = _gif_create_decompress();

+    if (p->gif_ptr == NULL) {

+        FX_Free(p);

+        return NULL;

+    }

+    p->gif_ptr->context_ptr = (void*)p;

+    p->gif_ptr->err_ptr = m_szLastError;

+    p->gif_ptr->_gif_error_fn = _gif_error_data;

+    p->gif_ptr->_gif_ask_buf_for_pal_fn = _gif_ask_buf_for_pal;

+    p->gif_ptr->_gif_record_current_position_fn = _gif_record_current_position;

+    p->gif_ptr->_gif_get_row_fn = _gif_read_scanline;

+    p->gif_ptr->_gif_get_record_position_fn = _gif_get_record_position;

+    return p;

+}

+void CCodec_GifModule::Finish(void* pContext)

+{

+    FXGIF_Context* p = (FXGIF_Context*)pContext;

+    if(p != NULL) {

+        _gif_destroy_decompress(&p->gif_ptr);

+        p->m_FreeFunc(p);

+    }

+}

+FX_INT32 CCodec_GifModule::ReadHeader(void* pContext, int* width, int* height,

+                                      int* pal_num, void** pal_pp, int* bg_index, CFX_DIBAttribute* pAttribute)

+{

+    FXGIF_Context* p = (FXGIF_Context*)pContext;

+    if(setjmp(p->gif_ptr->jmpbuf)) {

+        return 0;

+    }

+    FX_INT32 ret = _gif_read_header(p->gif_ptr);

+    if (ret != 1) {

+        return ret;

+    }

+    if (pAttribute) {

+    }

+    *width = p->gif_ptr->width;

+    *height = p->gif_ptr->height;

+    *pal_num = p->gif_ptr->global_pal_num;

+    *pal_pp = p->gif_ptr->global_pal_ptr;

+    *bg_index = p->gif_ptr->bc_index;

+    return 1;

+}

+FX_INT32 CCodec_GifModule::LoadFrameInfo(void* pContext, int* frame_num)

+{

+    FXGIF_Context* p = (FXGIF_Context*)pContext;

+    if(setjmp(p->gif_ptr->jmpbuf)) {

+        return 0;

+    }

+    FX_INT32 ret = _gif_get_frame(p->gif_ptr);

+    if (ret != 1) {

+        return ret;

+    }

+    *frame_num = _gif_get_frame_num(p->gif_ptr);

+    return 1;

+}

+FX_INT32 CCodec_GifModule::LoadFrame(void* pContext, int frame_num, CFX_DIBAttribute* pAttribute)

+{

+    FXGIF_Context* p = (FXGIF_Context*)pContext;

+    if(setjmp(p->gif_ptr->jmpbuf)) {

+        return 0;

+    }

+    FX_INT32 ret = _gif_load_frame(p->gif_ptr, frame_num);

+    if (ret == 1) {

+        if (pAttribute) {

+            pAttribute->m_nGifLeft = p->gif_ptr->img_ptr_arr_ptr->GetAt(frame_num)->image_info_ptr->left;

+            pAttribute->m_nGifTop = p->gif_ptr->img_ptr_arr_ptr->GetAt(frame_num)->image_info_ptr->top;

+            pAttribute->m_fAspectRatio = p->gif_ptr->pixel_aspect;

+            if (p->gif_ptr->cmt_data_ptr) {

+                FX_LPCBYTE buf = (FX_LPCBYTE)p->gif_ptr->cmt_data_ptr->GetBuffer(0);

+                FX_DWORD len = p->gif_ptr->cmt_data_ptr->GetLength();

+                if (len > 21) {

+                    FX_BYTE size = *buf++;

+                    if (size) {

+                        pAttribute->m_strAuthor = CFX_ByteString(buf, size);

+                    } else {

+                        pAttribute->m_strAuthor.Empty();

+                    }

+                    buf += size;

+                    size = *buf++;

+                    if (size == 20) {

+                        FXSYS_memcpy32(pAttribute->m_strTime, buf, size);

+                    }

+                }

+            }

+        }

+    }

+    return ret;

+}

+FX_DWORD CCodec_GifModule::GetAvailInput(void* pContext, FX_LPBYTE* avial_buf_ptr)

+{

+    FXGIF_Context* p = (FXGIF_Context*)pContext;

+    return _gif_get_avail_input(p->gif_ptr, avial_buf_ptr);

+}

+void CCodec_GifModule::Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size)

+{

+    FXGIF_Context* p = (FXGIF_Context*)pContext;

+    _gif_input_buffer(p->gif_ptr, (FX_LPBYTE)src_buf, src_size);

+}

diff --git a/core/src/fxcodec/codec/fx_codec_jpeg.cpp b/core/src/fxcodec/codec/fx_codec_jpeg.cpp
index 489f099..95770ea 100644
--- a/core/src/fxcodec/codec/fx_codec_jpeg.cpp
+++ b/core/src/fxcodec/codec/fx_codec_jpeg.cpp
@@ -73,6 +73,68 @@
 #define	JPEG_MARKER_AUTHORTIME	(JPEG_APP0 + 3)
 #define	JPEG_MARKER_MAXSIZE	0xFFFF
 #define	JPEG_OVERHEAD_LEN	14
+static FX_BOOL _JpegIsIccMarker(jpeg_saved_marker_ptr marker)
+{
+    if (marker->marker == JPEG_MARKER_ICC &&
+            marker->data_length >= JPEG_OVERHEAD_LEN &&
+            (FXSYS_memcmp32(marker->data, "\x49\x43\x43\x5f\x50\x52\x4f\x46\x49\x4c\x45\x00", 12) == 0)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+static	FX_BOOL _JpegLoadIccProfile(j_decompress_ptr cinfo, FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length)
+{
+    if(icc_buf_ptr == NULL || icc_length == NULL) {
+        return FALSE;
+    }
+    *icc_buf_ptr = NULL;
+    *icc_length = 0;
+    FX_LPBYTE icc_data_ptr = NULL;
+    FX_DWORD icc_data_len = 0;
+    FX_BYTE count_icc_marker = 0;
+    FX_BYTE num_icc_marker = 0;
+    jpeg_saved_marker_ptr marker_list[256] = {NULL};
+    for (jpeg_saved_marker_ptr cur_marker = cinfo->marker_list;
+            cur_marker != NULL;
+            cur_marker = cur_marker->next) {
+        if(_JpegIsIccMarker(cur_marker)) {
+            if(count_icc_marker == 0) {
+                num_icc_marker = cur_marker->data[13];
+            } else if(num_icc_marker != cur_marker->data[13]) {
+                return FALSE;
+            }
+            int sn = cur_marker->data[12] - 1;
+            if(sn < 0 || sn >= num_icc_marker) {
+                return FALSE;
+            }
+            if(marker_list[sn] == NULL) {
+                marker_list[sn] = cur_marker;
+            } else {
+                return FALSE;
+            }
+            count_icc_marker ++;
+            icc_data_len +=	(cur_marker->data_length - JPEG_OVERHEAD_LEN);
+        }
+    }
+    if(count_icc_marker != num_icc_marker) {
+        return FALSE;
+    }
+    if(num_icc_marker == 0) {
+        return TRUE;
+    }
+    icc_data_ptr = FX_Alloc(FX_BYTE, icc_data_len);
+    if(icc_buf_ptr == NULL)	{
+        return FALSE;
+    }
+    *icc_buf_ptr = icc_data_ptr;
+    *icc_length = icc_data_len;
+    for (int idx = 0; idx < num_icc_marker; idx++) {
+        icc_data_len = marker_list[idx]->data_length - JPEG_OVERHEAD_LEN;
+        FXSYS_memcpy32(icc_data_ptr, marker_list[idx]->data + JPEG_OVERHEAD_LEN, icc_data_len);
+        icc_data_ptr += icc_data_len;
+    }
+    return TRUE;
+}
 static	FX_BOOL _JpegEmbedIccProfile(j_compress_ptr cinfo, FX_LPCBYTE icc_buf_ptr, FX_DWORD icc_length)
 {
     if(icc_buf_ptr == NULL || icc_length == 0) {
@@ -207,6 +269,17 @@
     }
     dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer;
 }
+static void _JpegLoadAttribute(struct jpeg_decompress_struct* pInfo, CFX_DIBAttribute* pAttribute)
+{
+    if (pInfo == NULL || pAttribute == NULL) {
+        return;
+    }
+    if (pAttribute) {
+        pAttribute->m_nXDPI = pInfo->X_density;
+        pAttribute->m_nYDPI = pInfo->Y_density;
+        pAttribute->m_wDPIUnit = pInfo->density_unit;
+    }
+}
 static FX_BOOL _JpegLoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height,
                              int& num_components, int& bits_per_components, FX_BOOL& color_transform,
                              FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length)
@@ -613,10 +686,10 @@
     p->m_SrcMgr.next_input_byte = src_buf;
     p->m_SrcMgr.bytes_in_buffer = src_size;
 }
-int CCodec_JpegModule::ReadHeader(void* pContext, int* width, int* height, int* nComps)
+int CCodec_JpegModule::ReadHeader(void* pContext, int* width, int* height, int* nComps, CFX_DIBAttribute* pAttribute)
 {
     if (m_pExtProvider) {
-        return m_pExtProvider->ReadHeader(pContext, width, height, nComps);
+        return m_pExtProvider->ReadHeader(pContext, width, height, nComps, pAttribute);
     }
     FXJPEG_Context* p = (FXJPEG_Context*)pContext;
     if (setjmp(p->m_JumpMark) == -1) {
@@ -632,6 +705,7 @@
     *width = p->m_Info.image_width;
     *height = p->m_Info.image_height;
     *nComps = p->m_Info.num_components;
+    _JpegLoadAttribute(&p->m_Info, pAttribute);
     return 0;
 }
 FX_BOOL CCodec_JpegModule::StartScanline(void* pContext, int down_scale)
diff --git a/core/src/fxcodec/codec/fx_codec_png.cpp b/core/src/fxcodec/codec/fx_codec_png.cpp
new file mode 100644
index 0000000..0ddae7a
--- /dev/null
+++ b/core/src/fxcodec/codec/fx_codec_png.cpp
@@ -0,0 +1,245 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../../../include/fxcodec/fx_codec.h"

+#include "../../../include/fxge/fx_dib.h"

+#include "codec_int.h"

+extern "C" {

+#undef FAR

+#include "../fx_lpng/include/fx_png.h"

+}

+static void _png_error_data(png_structp png_ptr, png_const_charp error_msg)

+{

+    if(png_get_error_ptr(png_ptr)) {

+        FXSYS_strncpy((char*)png_get_error_ptr(png_ptr), error_msg, PNG_ERROR_SIZE - 1);

+    }

+    longjmp(png_jmpbuf(png_ptr), 1);

+}

+static void _png_warning_data(png_structp png_ptr, png_const_charp error_msg)

+{

+}

+static void _png_load_bmp_attribute(png_structp png_ptr, png_infop info_ptr, CFX_DIBAttribute* pAttribute)

+{

+    if (pAttribute) {

+#if defined(PNG_pHYs_SUPPORTED)

+        pAttribute->m_nXDPI = png_get_x_pixels_per_meter(png_ptr, info_ptr);

+        pAttribute->m_nYDPI = png_get_y_pixels_per_meter(png_ptr, info_ptr);

+        png_uint_32 res_x, res_y;

+        int unit_type;

+        png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);

+        switch (unit_type) {

+            case PNG_RESOLUTION_METER:

+                pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_METER;

+                break;

+            default:

+                pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_NONE;

+        }

+#endif

+#if defined(PNG_iCCP_SUPPORTED)

+        png_charp icc_name;

+        png_bytep icc_profile;

+        png_uint_32 icc_proflen;

+        int compress_type;

+        png_get_iCCP(png_ptr, info_ptr, &icc_name, &compress_type, &icc_profile, &icc_proflen);

+#endif

+        int bTime = 0;

+#if defined(PNG_tIME_SUPPORTED)

+        png_timep t = NULL;

+        png_get_tIME(png_ptr, info_ptr, &t);

+        if (t) {

+            FXSYS_memset32(pAttribute->m_strTime, 0, 20);

+            FXSYS_sprintf((FX_LPSTR)pAttribute->m_strTime, "%4d:%2d:%2d %2d:%2d:%2d", t->year, t->month, t->day, t->hour, t->minute, t->second);

+            bTime = 1;

+        }

+#endif

+#if defined(PNG_TEXT_SUPPORTED)

+        int i;

+        FX_DWORD len;

+        FX_LPCSTR buf;

+        int num_text;

+        png_textp text = NULL;

+        png_get_text(png_ptr, info_ptr, &text, &num_text);

+        for (i = 0; i < num_text; i++) {

+            len = (FX_DWORD)FXSYS_strlen(text[i].key);

+            buf = "Time";

+            if (!FXSYS_memcmp32(buf, text[i].key, FX_MIN(len, FXSYS_strlen(buf)))) {

+                if (!bTime) {

+                    FXSYS_memset32(pAttribute->m_strTime, 0, 20);

+                    FXSYS_memcpy32(pAttribute->m_strTime, text[i].text, text[i].text_length);

+                }

+            } else {

+                buf = "Author";

+                if (!FXSYS_memcmp32(buf, text[i].key, FX_MIN(len, FXSYS_strlen(buf)))) {

+                    pAttribute->m_strAuthor.Empty();

+                    pAttribute->m_strAuthor.Load((FX_LPBYTE)text[i].text, (FX_STRSIZE)text[i].text_length);

+                }

+            }

+        }

+#endif

+    }

+}

+struct FXPNG_Context {

+    png_structp png_ptr;

+    png_infop	info_ptr;

+    void*		parent_ptr;

+    void*		child_ptr;

+

+    void*		(*m_AllocFunc)(unsigned int);

+    void		(*m_FreeFunc)(void*);

+};

+extern "C" {

+    static void* _png_alloc_func(unsigned int size)

+    {

+        return FX_Alloc(char, size);

+    }

+    static void  _png_free_func(void* p)

+    {

+        if(p != NULL) {

+            FX_Free(p);

+        }

+    }

+};

+static void _png_get_header_func(png_structp png_ptr, png_infop info_ptr)

+{

+    FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);

+    if(p == NULL) {

+        return;

+    }

+    CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;

+    if(pModule == NULL) {

+        return;

+    }

+    png_uint_32 width = 0, height = 0;

+    int bpc = 0, color_type = 0 , color_type1 = 0, pass = 0;

+    double gamma = 1.0;

+    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, NULL, NULL, NULL);

+    color_type1 = color_type;

+    if(bpc > 8) {

+        png_set_strip_16(png_ptr);

+    } else if(bpc < 8) {

+        png_set_expand_gray_1_2_4_to_8(png_ptr);

+    }

+    bpc = 8;

+    if(color_type == PNG_COLOR_TYPE_PALETTE) {

+        png_set_palette_to_rgb(png_ptr);

+    }

+    pass = png_set_interlace_handling(png_ptr);

+    if(!pModule->ReadHeaderCallback(p->child_ptr, width, height, bpc, pass, &color_type, &gamma)) {

+        png_error(p->png_ptr, "Read Header Callback Error");

+    }

+    int intent;

+    if (png_get_sRGB(png_ptr, info_ptr, &intent)) {

+        png_set_gamma(png_ptr, gamma, 0.45455);

+    } else {

+        double image_gamma;

+        if(png_get_gAMA(png_ptr, info_ptr, &image_gamma)) {

+            png_set_gamma(png_ptr, gamma, image_gamma);

+        } else {

+            png_set_gamma(png_ptr, gamma, 0.45455);

+        }

+    }

+    switch(color_type) {

+        case PNG_COLOR_TYPE_GRAY:

+        case PNG_COLOR_TYPE_GRAY_ALPHA: {

+                if(color_type1 & PNG_COLOR_MASK_COLOR) {

+                    png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587);

+                }

+            }

+            break;

+        case PNG_COLOR_TYPE_PALETTE:

+            if(color_type1 != PNG_COLOR_TYPE_PALETTE) {

+                png_error(p->png_ptr, "Not Support Output Palette Now");

+            }

+        case PNG_COLOR_TYPE_RGB:

+        case PNG_COLOR_TYPE_RGB_ALPHA:

+            if(!(color_type1 & PNG_COLOR_MASK_COLOR)) {

+                png_set_gray_to_rgb(png_ptr);

+            }

+            png_set_bgr(png_ptr);

+            break;

+    }

+    if(!(color_type & PNG_COLOR_MASK_ALPHA)) {

+        png_set_strip_alpha(png_ptr);

+    }

+    if(color_type & PNG_COLOR_MASK_ALPHA && !(color_type1 & PNG_COLOR_MASK_ALPHA)) {

+        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);

+    }

+    png_read_update_info(png_ptr, info_ptr);

+}

+static void _png_get_end_func(png_structp png_ptr, png_infop info_ptr) {}

+static void _png_get_row_func(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass)

+{

+    FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);

+    if(p == NULL) {

+        return;

+    }

+    CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;

+    FX_LPBYTE src_buf = NULL;

+    if(!pModule->AskScanlineBufCallback(p->child_ptr, row_num, src_buf)) {

+        png_error(png_ptr, "Ask Scanline buffer Callback Error");

+    }

+    if(src_buf != NULL) {

+        png_progressive_combine_row(png_ptr, src_buf, new_row);

+    }

+    pModule->FillScanlineBufCompletedCallback(p->child_ptr, pass, row_num);

+}

+void* CCodec_PngModule::Start(void* pModule)

+{

+    FXPNG_Context* p = (FXPNG_Context*)FX_Alloc(FX_BYTE, sizeof(FXPNG_Context));

+    if(p == NULL) {

+        return NULL;

+    }

+    p->m_AllocFunc = _png_alloc_func;

+    p->m_FreeFunc = _png_free_func;

+    p->png_ptr = NULL;

+    p->info_ptr = NULL;

+    p->parent_ptr = (void*)this;

+    p->child_ptr = pModule;

+    p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

+    if (p->png_ptr == NULL) {

+        FX_Free(p);

+        return NULL;

+    }

+    p->info_ptr = png_create_info_struct(p->png_ptr);

+    if (p->info_ptr == NULL) {

+        png_destroy_read_struct(&(p->png_ptr), (png_infopp)NULL, (png_infopp)NULL);

+        FX_Free(p);

+        return NULL;

+    }

+    if (setjmp(png_jmpbuf(p->png_ptr))) {

+        if(p != NULL) {

+            png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), (png_infopp)NULL);

+            FX_Free(p);

+        }

+        return NULL;

+    }

+    png_set_progressive_read_fn(p->png_ptr, p,

+                                _png_get_header_func,

+                                _png_get_row_func,

+                                _png_get_end_func);

+    png_set_error_fn(p->png_ptr, m_szLastError, (png_error_ptr)_png_error_data, (png_error_ptr)_png_warning_data);

+    return p;

+}

+void CCodec_PngModule::Finish(void* pContext)

+{

+    FXPNG_Context* p = (FXPNG_Context*)pContext;

+    if(p != NULL) {

+        png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), (png_infopp)NULL);

+        p->m_FreeFunc(p);

+    }

+}

+FX_BOOL CCodec_PngModule::Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_DIBAttribute* pAttribute)

+{

+    FXPNG_Context* p = (FXPNG_Context*)pContext;

+    if(setjmp(png_jmpbuf(p->png_ptr))) {

+        if (pAttribute && 0 == FXSYS_strcmp(m_szLastError, "Read Header Callback Error")) {

+            _png_load_bmp_attribute(p->png_ptr, p->info_ptr, pAttribute);

+        }

+        return FALSE;

+    }

+    png_process_data(p->png_ptr, p->info_ptr, (FX_LPBYTE)src_buf, src_size);

+    return TRUE;

+}

diff --git a/core/src/fxcodec/codec/fx_codec_progress.cpp b/core/src/fxcodec/codec/fx_codec_progress.cpp
new file mode 100644
index 0000000..542ac68
--- /dev/null
+++ b/core/src/fxcodec/codec/fx_codec_progress.cpp
@@ -0,0 +1,2263 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../../../include/fxge/fx_dib.h"

+#include "../../../include/fxcodec/fx_codec.h"

+#include "fx_codec_progress.h"

+void CFXCODEC_WeightTable::Calc(int dest_len, int dest_min, int dest_max, int src_len, int src_min, int src_max, FX_BOOL bInterpol)

+{

+    if (m_pWeightTables) {

+        FX_Free(m_pWeightTables);

+    }

+    double scale, base;

+    scale = FXSYS_Div((FX_FLOAT)(src_len), (FX_FLOAT)(dest_len));

+    if (dest_len < 0) {

+        base = (FX_FLOAT)(src_len);

+    } else {

+        base = 0.0f;

+    }

+    m_ItemSize = (int)(sizeof(int) * 2 + sizeof(int) * (FXSYS_ceil(FXSYS_fabs((FX_FLOAT)scale)) + 1));

+    m_DestMin = dest_min;

+    m_pWeightTables = FX_Alloc(FX_BYTE, (dest_max - dest_min) * m_ItemSize + 4);

+    if(m_pWeightTables == NULL) {

+        return;

+    }

+    if (FXSYS_fabs((FX_FLOAT)scale) < 1.0f) {

+        for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel ++) {

+            PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);

+            double src_pos = dest_pixel * scale + scale / 2 + base;

+            if (bInterpol) {

+                pixel_weights.m_SrcStart = (int)FXSYS_floor((FX_FLOAT)src_pos - 1.0f / 2);

+                pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos + 1.0f / 2);

+                if (pixel_weights.m_SrcStart < src_min) {

+                    pixel_weights.m_SrcStart = src_min;

+                }

+                if (pixel_weights.m_SrcEnd >= src_max) {

+                    pixel_weights.m_SrcEnd = src_max - 1;

+                }

+                if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {

+                    pixel_weights.m_Weights[0] = 65536;

+                } else {

+                    pixel_weights.m_Weights[1] = FXSYS_round((FX_FLOAT)(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * 65536);

+                    pixel_weights.m_Weights[0] = 65536 - pixel_weights.m_Weights[1];

+                }

+            } else {

+                pixel_weights.m_SrcStart = pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos);

+                pixel_weights.m_Weights[0] = 65536;

+            }

+        }

+        return;

+    }

+    for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel ++) {

+        PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);

+        double src_start = dest_pixel * scale + base;

+        double src_end = src_start + scale;

+        int start_i, end_i;

+        if (src_start < src_end) {

+            start_i = (int)FXSYS_floor((FX_FLOAT)src_start);

+            end_i = (int)FXSYS_ceil((FX_FLOAT)src_end);

+        } else {

+            start_i = (int)FXSYS_floor((FX_FLOAT)src_end);

+            end_i = (int)FXSYS_ceil((FX_FLOAT)src_start);

+        }

+        if (start_i < src_min) {

+            start_i = src_min;

+        }

+        if (end_i >= src_max) {

+            end_i = src_max - 1;

+        }

+        if (start_i > end_i) {

+            pixel_weights.m_SrcStart = start_i;

+            pixel_weights.m_SrcEnd = start_i;

+            continue;

+        }

+        pixel_weights.m_SrcStart = start_i;

+        pixel_weights.m_SrcEnd = end_i;

+        for (int j = start_i; j <= end_i; j ++) {

+            double dest_start = FXSYS_Div((FX_FLOAT)(j) - base, scale);

+            double dest_end = FXSYS_Div((FX_FLOAT)(j + 1) - base, scale);

+            if (dest_start > dest_end) {

+                double temp = dest_start;

+                dest_start = dest_end;

+                dest_end = temp;

+            }

+            double area_start = dest_start > (FX_FLOAT)(dest_pixel) ? dest_start : (FX_FLOAT)(dest_pixel);

+            double area_end = dest_end > (FX_FLOAT)(dest_pixel + 1) ? (FX_FLOAT)(dest_pixel + 1) : dest_end;

+            double weight = area_start >= area_end ? 0.0f : area_end - area_start;

+            if (weight == 0 && j == end_i) {

+                pixel_weights.m_SrcEnd --;

+                break;

+            }

+            pixel_weights.m_Weights[j - start_i] = FXSYS_round((FX_FLOAT)(weight * 65536));

+        }

+    }

+}

+void CFXCODEC_HorzTable::Calc(int dest_len, int src_len, FX_BOOL bInterpol)

+{

+    if (m_pWeightTables) {

+        FX_Free(m_pWeightTables);

+    }

+    double scale = (double)dest_len / (double)src_len;

+    m_ItemSize = sizeof(int) * 4;

+    int size = dest_len * m_ItemSize + 4;

+    m_pWeightTables = FX_Alloc(FX_BYTE, size);

+    if(m_pWeightTables == NULL)	{

+        return;

+    }

+    FXSYS_memset32(m_pWeightTables, 0, size);

+    if(scale > 1) {

+        int pre_des_col = 0;

+        for (int src_col = 0; src_col < src_len; src_col++) {

+            double des_col_f = src_col * scale;

+            int des_col = FXSYS_round((FX_FLOAT)des_col_f);

+            PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_col * m_ItemSize);

+            pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col;

+            pWeight->m_Weights[0] = 65536;

+            pWeight->m_Weights[1] = 0;

+            if(src_col == src_len - 1 && des_col < dest_len - 1) {

+                for (int des_col_index = pre_des_col + 1; des_col_index < dest_len; des_col_index++) {

+                    pWeight = (PixelWeight*)(m_pWeightTables + des_col_index * m_ItemSize);

+                    pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col;

+                    pWeight->m_Weights[0] = 65536;

+                    pWeight->m_Weights[1] = 0;

+                }

+                return;

+            }

+            int des_col_len = des_col - pre_des_col;

+            for (int des_col_index = pre_des_col + 1; des_col_index < des_col; des_col_index++) {

+                pWeight = (PixelWeight*)(m_pWeightTables + des_col_index * m_ItemSize);

+                pWeight->m_SrcStart = src_col - 1;

+                pWeight->m_SrcEnd = src_col;

+                pWeight->m_Weights[0] = bInterpol ? FXSYS_round((FX_FLOAT)

+                                        (

+                                            ((FX_FLOAT)des_col - (FX_FLOAT)des_col_index)

+                                            / (FX_FLOAT)des_col_len * 65536

+                                        )

+                                                               ) : 65536;

+                pWeight->m_Weights[1] = 65536 - pWeight->m_Weights[0];

+            }

+            pre_des_col = des_col;

+        }

+        return;

+    }

+    for (int des_col = 0; des_col < dest_len; des_col++) {

+        double src_col_f = des_col / scale;

+        int src_col = FXSYS_round((FX_FLOAT)src_col_f);

+        PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_col * m_ItemSize);

+        pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col;

+        pWeight->m_Weights[0] = 65536;

+        pWeight->m_Weights[1] = 0;

+    }

+}

+void CFXCODEC_VertTable::Calc(int dest_len, int src_len)

+{

+    if (m_pWeightTables) {

+        FX_Free(m_pWeightTables);

+    }

+    double scale = (double)dest_len / (double)src_len;

+    m_ItemSize = sizeof(int) * 4;

+    int size = dest_len * m_ItemSize + 4;

+    m_pWeightTables = FX_Alloc(FX_BYTE, size);

+    if(m_pWeightTables == NULL) {

+        return;

+    }

+    FXSYS_memset32(m_pWeightTables, 0, size);

+    if(scale > 1) {

+        double step = 0.0;

+        int src_row = 0;

+        while ( step < (double)dest_len ) {

+            int start_step = (int)step;

+            step = scale * (++src_row);

+            int end_step = (int)step;

+            if(end_step >= dest_len) {

+                end_step = dest_len;

+                for (int des_row = start_step; des_row < end_step; des_row++) {

+                    PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_row * m_ItemSize);

+                    pWeight->m_SrcStart = start_step;

+                    pWeight->m_SrcEnd = start_step;

+                    pWeight->m_Weights[0] = 65536;

+                    pWeight->m_Weights[1] = 0;

+                }

+                return;

+            }

+            int length = end_step - start_step;

+            {

+                PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + start_step * m_ItemSize);

+                pWeight->m_SrcStart = start_step;

+                pWeight->m_SrcEnd = start_step;

+                pWeight->m_Weights[0] = 65536;

+                pWeight->m_Weights[1] = 0;

+            }

+            for (int des_row = start_step + 1; des_row < end_step; des_row++) {

+                PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_row * m_ItemSize);

+                pWeight->m_SrcStart = start_step;

+                pWeight->m_SrcEnd = end_step;

+                pWeight->m_Weights[0] = FXSYS_round((FX_FLOAT)(end_step - des_row) / (FX_FLOAT)length * 65536);

+                pWeight->m_Weights[1] = 65536 - pWeight->m_Weights[0];

+            }

+        }

+    } else {

+        for (int des_row = 0; des_row < dest_len; des_row++) {

+            PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_row * m_ItemSize);

+            pWeight->m_SrcStart = des_row;

+            pWeight->m_SrcEnd = des_row;

+            pWeight->m_Weights[0] = 65536;

+            pWeight->m_Weights[1] = 0;

+        }

+    }

+}

+CCodec_ProgressiveDecoder::CCodec_ProgressiveDecoder(CCodec_ModuleMgr* pCodecMgr)

+{

+    m_pFile = NULL;

+    m_pJpegContext = NULL;

+    m_pPngContext = NULL;

+    m_pGifContext = NULL;

+    m_pBmpContext = NULL;

+    m_pTiffContext = NULL;

+    m_pCodecMgr = NULL;

+    m_pSrcBuf = NULL;

+    m_pDecodeBuf = NULL;

+    m_pDeviceBitmap = NULL;

+    m_pSrcPalette = NULL;

+    m_pCodecMgr = pCodecMgr;

+    m_offSet = 0;

+    m_SrcSize = 0;

+    m_ScanlineSize = 0;

+    m_SrcWidth = m_SrcHeight = 0;

+    m_SrcComponents = 0;

+    m_SrcBPC = 0;

+    m_SrcPassNumber = 0;

+    m_clipBox = FX_RECT(0, 0, 0, 0);

+    m_imagType = FXCODEC_IMAGE_UNKNOWN;

+    m_status = FXCODEC_STATUS_DECODE_FINISH;

+    m_TransMethod = -1;

+    m_SrcRow = 0;

+    m_SrcFormat = FXCodec_Invalid;

+    m_bInterpol = TRUE;

+    m_FrameNumber = 0;

+    m_FrameCur = 0;

+    m_SrcPaletteNumber = 0;

+    m_GifPltNumber = 0;

+    m_GifBgIndex = 0;

+    m_pGifPalette = NULL;

+    m_GifTransIndex = -1;

+    m_GifFrameRect = FX_RECT(0, 0, 0, 0);

+    m_BmpIsTopBottom = FALSE;

+}

+CCodec_ProgressiveDecoder::~CCodec_ProgressiveDecoder()

+{

+    m_pFile = NULL;

+    if(m_pJpegContext != NULL) {

+        m_pCodecMgr->GetJpegModule()->Finish(m_pJpegContext);

+    }

+    if(m_pPngContext != NULL) {

+        m_pCodecMgr->GetPngModule()->Finish(m_pPngContext);

+    }

+    if(m_pGifContext != NULL) {

+        m_pCodecMgr->GetGifModule()->Finish(m_pGifContext);

+    }

+    if(m_pBmpContext != NULL) {

+        m_pCodecMgr->GetBmpModule()->Finish(m_pBmpContext);

+    }

+    if(m_pTiffContext != NULL) {

+        m_pCodecMgr->GetTiffModule()->DestroyDecoder(m_pTiffContext);

+    }

+    if(m_pSrcBuf != NULL) {

+        FX_Free(m_pSrcBuf);

+    }

+    if(m_pDecodeBuf != NULL) {

+        FX_Free(m_pDecodeBuf);

+    }

+    if(m_pSrcPalette != NULL) {

+        FX_Free(m_pSrcPalette);

+    }

+}

+FX_BOOL CCodec_ProgressiveDecoder::JpegReadMoreData(ICodec_JpegModule* pJpegModule, FXCODEC_STATUS& err_status)

+{

+    FX_DWORD dwSize = (FX_DWORD)m_pFile->GetSize();

+    if (dwSize <= m_offSet) {

+        return FALSE;

+    }

+    dwSize = dwSize - m_offSet;

+    FX_DWORD dwAvail = pJpegModule->GetAvailInput(m_pJpegContext, NULL);

+    if (dwAvail == m_SrcSize) {

+        if (dwSize > FXCODEC_BLOCK_SIZE) {

+            dwSize = FXCODEC_BLOCK_SIZE;

+        }

+        m_SrcSize = (dwSize + dwAvail + FXCODEC_BLOCK_SIZE - 1) / FXCODEC_BLOCK_SIZE * FXCODEC_BLOCK_SIZE;

+        m_pSrcBuf = FX_Realloc(FX_BYTE, m_pSrcBuf, m_SrcSize);

+        if (!m_pSrcBuf) {

+            err_status = FXCODEC_STATUS_ERR_MEMORY;

+            return FALSE;

+        }

+    } else {

+        FX_DWORD dwConsume = m_SrcSize - dwAvail;

+        if (dwAvail) {

+            FXSYS_memcpy32(m_pSrcBuf, m_pSrcBuf + dwConsume, dwAvail);

+        }

+        if (dwSize > dwConsume) {

+            dwSize = dwConsume;

+        }

+    }

+    if (!m_pFile->ReadBlock(m_pSrcBuf + dwAvail, m_offSet, dwSize)) {

+        err_status = FXCODEC_STATUS_ERR_READ;

+        return FALSE;

+    }

+    m_offSet += dwSize;

+    pJpegModule->Input(m_pJpegContext, m_pSrcBuf, dwSize + dwAvail);

+    return TRUE;

+}

+FX_BOOL CCodec_ProgressiveDecoder::PngReadHeaderFunc(void* pModule, int width, int height, int bpc, int pass, int* color_type, double* gamma)

+{

+    CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;

+    if(pCodec->m_pDeviceBitmap == NULL) {

+        pCodec->m_SrcWidth = width;

+        pCodec->m_SrcHeight = height;

+        pCodec->m_SrcBPC = bpc;

+        pCodec->m_SrcPassNumber = pass;

+        pCodec->m_SrcComponents = *color_type == 0 ? 1 :

+                                  *color_type == 2 ? 3 :

+                                  *color_type == 3 ? 4 :

+                                  *color_type == 4 ? 2 :

+                                  *color_type == 6 ? 4 : 0;

+        pCodec->m_clipBox = FX_RECT(0, 0, width, height);

+        return FALSE;

+    }

+    FXDIB_Format format = pCodec->m_pDeviceBitmap->GetFormat();

+    switch(format) {

+        case FXDIB_1bppMask:

+        case FXDIB_1bppRgb:

+            ASSERT(FALSE);

+            return FALSE;

+        case FXDIB_8bppMask:

+        case FXDIB_8bppRgb:

+            *color_type = 0;

+            break;

+        case FXDIB_Rgb:

+            *color_type = 2;

+            break;

+        case FXDIB_Rgb32:

+        case FXDIB_Argb:

+            *color_type = 6;

+            break;

+        default:

+            ASSERT(FALSE);

+            return FALSE;

+    }

+    *gamma = FXCODEC_PNG_GAMMA;

+    return TRUE;

+}

+FX_BOOL CCodec_ProgressiveDecoder::PngAskScanlineBufFunc(void* pModule, int line, FX_LPBYTE& src_buf)

+{

+    CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;

+    CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap;

+    ASSERT(pDIBitmap != NULL);

+    if(pDIBitmap == NULL) {

+        return FALSE;

+    }

+    if(line >= pCodec->m_clipBox.top && line < pCodec->m_clipBox.bottom) {

+        double scale_y = (double)pCodec->m_sizeY / (double)pCodec->m_clipBox.Height();

+        FX_INT32 row = (FX_INT32)((line - pCodec->m_clipBox.top) * scale_y) + pCodec->m_startY;

+        FX_LPBYTE src_scan = (FX_LPBYTE)pDIBitmap->GetScanline(row);

+        FX_LPBYTE des_scan = pCodec->m_pDecodeBuf;

+        src_buf = pCodec->m_pDecodeBuf;

+        FX_INT32 src_Bpp = pDIBitmap->GetBPP() >> 3;

+        FX_INT32 des_Bpp = (pCodec->m_SrcFormat & 0xff) >> 3;

+        FX_INT32 src_left = pCodec->m_startX;

+        FX_INT32 des_left = pCodec->m_clipBox.left;

+        src_scan += src_left * src_Bpp;

+        des_scan += des_left * des_Bpp;

+        for (FX_INT32 src_col = 0; src_col < pCodec->m_sizeX; src_col++) {

+            PixelWeight* pPixelWeights = pCodec->m_WeightHorzOO.GetPixelWeight(src_col);

+            if(pPixelWeights->m_SrcStart != pPixelWeights->m_SrcEnd) {

+                continue;

+            }

+            switch(pDIBitmap->GetFormat()) {

+                case FXDIB_1bppMask:

+                case FXDIB_1bppRgb:

+                    ASSERT(FALSE);

+                    return FALSE;

+                case FXDIB_8bppMask:

+                case FXDIB_8bppRgb: {

+                        if(pDIBitmap->GetPalette() != NULL) {

+                            return FALSE;

+                        }

+                        FX_DWORD des_g = 0;

+                        des_g += pPixelWeights->m_Weights[0] * src_scan[src_col];

+                        des_scan[pPixelWeights->m_SrcStart] = (FX_BYTE)(des_g >> 16);

+                    }

+                    break;

+                case FXDIB_Rgb:

+                case FXDIB_Rgb32: {

+                        FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                        FX_LPCBYTE p = src_scan + src_col * src_Bpp;

+                        des_b += pPixelWeights->m_Weights[0] * (*p++);

+                        des_g += pPixelWeights->m_Weights[0] * (*p++);

+                        des_r += pPixelWeights->m_Weights[0] * (*p);

+                        FX_LPBYTE pDes = &des_scan[pPixelWeights->m_SrcStart * des_Bpp];

+                        *pDes++ = (FX_BYTE)((des_b) >> 16);

+                        *pDes++ = (FX_BYTE)((des_g) >> 16);

+                        *pDes	= (FX_BYTE)((des_r) >> 16);

+                    }

+                    break;

+                case FXDIB_Argb: {

+                        FX_DWORD des_r = 0, des_g = 0, des_b = 0;

+                        FX_LPCBYTE p = src_scan + src_col * src_Bpp;

+                        des_b += pPixelWeights->m_Weights[0] * (*p++);

+                        des_g += pPixelWeights->m_Weights[0] * (*p++);

+                        des_r += pPixelWeights->m_Weights[0] * (*p++);

+                        FX_LPBYTE pDes = &des_scan[pPixelWeights->m_SrcStart * des_Bpp];

+                        *pDes++ = (FX_BYTE)((des_b) >> 16);

+                        *pDes++ = (FX_BYTE)((des_g) >> 16);

+                        *pDes++	= (FX_BYTE)((des_r) >> 16);

+                        *pDes	= *p;

+                    }

+                    break;

+                default:

+                    return FALSE;

+            }

+        }

+    }

+    return TRUE;

+}

+void CCodec_ProgressiveDecoder::PngOneOneMapResampleHorz(CFX_DIBitmap* pDeviceBitmap, FX_INT32 des_line, FX_LPBYTE src_scan, FXCodec_Format src_format)

+{

+    FX_LPBYTE des_scan = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_line);

+    FX_INT32 src_Bpp = (m_SrcFormat & 0xff) >> 3;

+    FX_INT32 des_Bpp = pDeviceBitmap->GetBPP() >> 3;

+    FX_INT32 src_left = m_clipBox.left;

+    FX_INT32 des_left = m_startX;

+    src_scan += src_left * src_Bpp;

+    des_scan += des_left * des_Bpp;

+    for (FX_INT32 des_col = 0; des_col < m_sizeX; des_col++) {

+        PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(des_col);

+        switch(pDeviceBitmap->GetFormat()) {

+            case FXDIB_1bppMask:

+            case FXDIB_1bppRgb:

+                ASSERT(FALSE);

+                return;

+            case FXDIB_8bppMask:

+            case FXDIB_8bppRgb: {

+                    if(pDeviceBitmap->GetPalette() != NULL) {

+                        return;

+                    }

+                    FX_DWORD des_g = 0;

+                    des_g += pPixelWeights->m_Weights[0] * src_scan[pPixelWeights->m_SrcStart];

+                    des_g += pPixelWeights->m_Weights[1] * src_scan[pPixelWeights->m_SrcEnd];

+                    *des_scan++ = (FX_BYTE)(des_g >> 16);

+                }

+                break;

+            case FXDIB_Rgb:

+            case FXDIB_Rgb32: {

+                    FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                    FX_LPCBYTE p = src_scan;

+                    p = src_scan + pPixelWeights->m_SrcStart * src_Bpp;

+                    des_b += pPixelWeights->m_Weights[0] * (*p++);

+                    des_g += pPixelWeights->m_Weights[0] * (*p++);

+                    des_r += pPixelWeights->m_Weights[0] * (*p);

+                    p = src_scan + pPixelWeights->m_SrcEnd * src_Bpp;

+                    des_b += pPixelWeights->m_Weights[1] * (*p++);

+                    des_g += pPixelWeights->m_Weights[1] * (*p++);

+                    des_r += pPixelWeights->m_Weights[1] * (*p);

+                    *des_scan++ = (FX_BYTE)((des_b) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_g) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_r) >> 16);

+                    des_scan += des_Bpp - 3;

+                }

+                break;

+            case FXDIB_Argb: {

+                    FX_DWORD des_a = 0, des_b = 0, des_g = 0, des_r = 0;

+                    FX_LPCBYTE p = src_scan;

+                    p = src_scan + pPixelWeights->m_SrcStart * src_Bpp;

+                    des_b += pPixelWeights->m_Weights[0] * (*p++);

+                    des_g += pPixelWeights->m_Weights[0] * (*p++);

+                    des_r += pPixelWeights->m_Weights[0] * (*p++);

+                    des_a += pPixelWeights->m_Weights[0] * (*p);

+                    p = src_scan + pPixelWeights->m_SrcEnd * src_Bpp;

+                    des_b += pPixelWeights->m_Weights[1] * (*p++);

+                    des_g += pPixelWeights->m_Weights[1] * (*p++);

+                    des_r += pPixelWeights->m_Weights[1] * (*p++);

+                    des_a += pPixelWeights->m_Weights[1] * (*p);

+                    *des_scan++ = (FX_BYTE)((des_b) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_g) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_r) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_a) >> 16);

+                }

+                break;

+            default:

+                return;

+        }

+    }

+}

+void CCodec_ProgressiveDecoder::PngFillScanlineBufCompletedFunc(void* pModule, int pass, int line)

+{

+    CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;

+    CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap;

+    ASSERT(pDIBitmap != NULL);

+    int src_top = pCodec->m_clipBox.top;

+    int src_bottom = pCodec->m_clipBox.bottom;

+    int des_top = pCodec->m_startY;

+    int src_hei = pCodec->m_clipBox.Height();

+    int des_hei = pCodec->m_sizeY;

+    if(line >= src_top && line < src_bottom) {

+        double scale_y = (double)des_hei / (double)src_hei;

+        int src_row = line - src_top;

+        int des_row = (int)(src_row * scale_y)  + des_top;

+        if(des_row >= des_top + des_hei)	{

+            return;

+        }

+        pCodec->PngOneOneMapResampleHorz(pDIBitmap, des_row, pCodec->m_pDecodeBuf, pCodec->m_SrcFormat);

+        if(pCodec->m_SrcPassNumber == 1 && scale_y > 1.0) {

+            pCodec->ResampleVert(pDIBitmap, scale_y, des_row);

+            return;

+        }

+        if(pass == 6 && scale_y > 1.0) {

+            pCodec->ResampleVert(pDIBitmap, scale_y, des_row);

+        }

+    }

+}

+FX_BOOL CCodec_ProgressiveDecoder::GifReadMoreData(ICodec_GifModule* pGifModule, FXCODEC_STATUS& err_status)

+{

+    FX_DWORD dwSize = (FX_DWORD)m_pFile->GetSize();

+    if (dwSize <= m_offSet) {

+        return FALSE;

+    }

+    dwSize = dwSize - m_offSet;

+    FX_DWORD dwAvail = pGifModule->GetAvailInput(m_pGifContext, NULL);

+    if (dwAvail == m_SrcSize) {

+        if (dwSize > FXCODEC_BLOCK_SIZE) {

+            dwSize = FXCODEC_BLOCK_SIZE;

+        }

+        m_SrcSize = (dwSize + dwAvail + FXCODEC_BLOCK_SIZE - 1) / FXCODEC_BLOCK_SIZE * FXCODEC_BLOCK_SIZE;

+        m_pSrcBuf = FX_Realloc(FX_BYTE, m_pSrcBuf, m_SrcSize);

+        if (!m_pSrcBuf) {

+            err_status = FXCODEC_STATUS_ERR_MEMORY;

+            return FALSE;

+        }

+    } else {

+        FX_DWORD dwConsume = m_SrcSize - dwAvail;

+        if (dwAvail) {

+            FXSYS_memcpy32(m_pSrcBuf, m_pSrcBuf + dwConsume, dwAvail);

+        }

+        if (dwSize > dwConsume) {

+            dwSize = dwConsume;

+        }

+    }

+    if (!m_pFile->ReadBlock(m_pSrcBuf + dwAvail, m_offSet, dwSize)) {

+        err_status = FXCODEC_STATUS_ERR_READ;

+        return FALSE;

+    }

+    m_offSet += dwSize;

+    pGifModule->Input(m_pGifContext, m_pSrcBuf, dwSize + dwAvail);

+    return TRUE;

+}

+void CCodec_ProgressiveDecoder::GifRecordCurrentPositionCallback(void* pModule, FX_DWORD& cur_pos)

+{

+    CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;

+    FX_DWORD remain_size = pCodec->m_pCodecMgr->GetGifModule()->GetAvailInput(pCodec->m_pGifContext);

+    cur_pos = pCodec->m_offSet - remain_size;

+}

+FX_LPBYTE CCodec_ProgressiveDecoder::GifAskLocalPaletteBufCallback(void* pModule, FX_INT32 frame_num, FX_INT32 pal_size)

+{

+    return FX_Alloc(FX_BYTE, pal_size);

+}

+FX_BOOL CCodec_ProgressiveDecoder::GifInputRecordPositionBufCallback(void* pModule, FX_DWORD rcd_pos, const FX_RECT& img_rc,

+        FX_INT32 pal_num, void* pal_ptr,

+        FX_INT32 delay_time, FX_BOOL user_input,

+        FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace)

+{

+    CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;

+    pCodec->m_offSet = rcd_pos;

+    FXCODEC_STATUS error_status = FXCODEC_STATUS_ERROR;

+    if(!pCodec->GifReadMoreData(pCodec->m_pCodecMgr->GetGifModule(), error_status)) {

+        return FALSE;

+    }

+    FX_LPBYTE pPalette = NULL;

+    if(pal_num != 0 && pal_ptr) {

+        pPalette = (FX_LPBYTE)pal_ptr;

+    } else {

+        pal_num = pCodec->m_GifPltNumber;

+        pPalette = pCodec->m_pGifPalette;

+    }

+    if(pCodec->m_pSrcPalette == NULL) {

+        pCodec->m_pSrcPalette = FX_Alloc(FX_ARGB, pal_num);

+    } else if(pal_num > pCodec->m_SrcPaletteNumber) {

+        pCodec->m_pSrcPalette = FX_Realloc(FX_ARGB, pCodec->m_pSrcPalette, pal_num);

+    }

+    if(pCodec->m_pSrcPalette == NULL) {

+        return FALSE;

+    }

+    pCodec->m_SrcPaletteNumber = pal_num;

+    for (int i = 0; i < pal_num; i++) {

+        register FX_DWORD j = i * 3;

+        pCodec->m_pSrcPalette[i] =

+            ArgbEncode(0xff, pPalette[j], pPalette[j + 1], pPalette[j + 2]);

+    }

+    pCodec->m_GifTransIndex = trans_index;

+    pCodec->m_GifFrameRect = img_rc;

+    pCodec->m_SrcPassNumber = interlace ? 4 : 1;

+    FX_INT32 pal_index = pCodec->m_GifBgIndex;

+    CFX_DIBitmap* pDevice = pCodec->m_pDeviceBitmap;

+    if (trans_index >= pal_num) {

+        trans_index = -1;

+    }

+    if (trans_index != -1) {

+        pCodec->m_pSrcPalette[trans_index] &= 0x00ffffff;

+        if (pDevice->HasAlpha()) {

+            pal_index = trans_index;

+        }

+    }

+    int startX = pCodec->m_startX;

+    int startY = pCodec->m_startY;

+    int sizeX = pCodec->m_sizeX;

+    int sizeY = pCodec->m_sizeY;

+    int Bpp = pDevice->GetBPP() / 8;

+    FX_ARGB argb = pCodec->m_pSrcPalette[pal_index];

+    for (int row = 0; row < sizeY; row ++) {

+        FX_LPBYTE pScanline = (FX_LPBYTE)pDevice->GetScanline(row + startY) + startX * Bpp;

+        switch(pCodec->m_TransMethod) {

+            case 3:	{

+                    FX_BYTE gray = FXRGB2GRAY(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb));

+                    FXSYS_memset8(pScanline, gray, sizeX);

+                    break;

+                }

+            case 8:	{

+                    for (int col = 0; col < sizeX; col ++) {

+                        *pScanline++ = FXARGB_B(argb);

+                        *pScanline++ = FXARGB_G(argb);

+                        *pScanline++ = FXARGB_R(argb);

+                        pScanline += Bpp - 3;

+                    }

+                    break;

+                }

+            case 12: {

+                    for (int col = 0; col < sizeX; col ++) {

+                        FXARGB_SETDIB(pScanline, argb);

+                        pScanline += 4;

+                    }

+                    break;

+                }

+        }

+    }

+    return TRUE;

+}

+void CCodec_ProgressiveDecoder::GifReadScanlineCallback(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf)

+{

+    CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;

+    CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap;

+    ASSERT(pDIBitmap != NULL);

+    FX_INT32 img_width = pCodec->m_GifFrameRect.Width();

+    if (!pDIBitmap->HasAlpha()) {

+        FX_LPBYTE byte_ptr = row_buf;

+        for (int i = 0; i < img_width; i++ ) {

+            if(*byte_ptr == pCodec->m_GifTransIndex) {

+                *byte_ptr = pCodec->m_GifBgIndex;

+            }

+            byte_ptr++;

+        }

+    }

+    FX_INT32 pal_index = pCodec->m_GifBgIndex;

+    if (pCodec->m_GifTransIndex != -1 && pCodec->m_pDeviceBitmap->HasAlpha()) {

+        pal_index = pCodec->m_GifTransIndex;

+    }

+    FXSYS_memset8(pCodec->m_pDecodeBuf, pal_index, pCodec->m_SrcWidth);

+    FX_BOOL bLastPass = ((row_num % 2) == 1) ? TRUE : FALSE;

+    FX_INT32 line = row_num + pCodec->m_GifFrameRect.top;

+    FX_INT32 left = pCodec->m_GifFrameRect.left;

+    FXSYS_memcpy32(pCodec->m_pDecodeBuf + left, row_buf, img_width);

+    int src_top = pCodec->m_clipBox.top;

+    int src_bottom = pCodec->m_clipBox.bottom;

+    int des_top = pCodec->m_startY;

+    int src_hei = pCodec->m_clipBox.Height();

+    int des_hei = pCodec->m_sizeY;

+    if(line >= src_top && line < src_bottom) {

+        double scale_y = (double)des_hei / (double)src_hei;

+        int src_row = line - src_top;

+        int des_row = (int)(src_row * scale_y)  + des_top;

+        if(des_row >= des_top + des_hei)	{

+            return;

+        }

+        pCodec->ReSampleScanline(pDIBitmap, des_row, pCodec->m_pDecodeBuf, pCodec->m_SrcFormat);

+        if(scale_y > 1.0 && (!pCodec->m_bInterpol || pCodec->m_SrcPassNumber == 1)) {

+            pCodec->ResampleVert(pDIBitmap, scale_y, des_row);

+            return;

+        }

+        if(scale_y > 1.0) {

+            int des_bottom = des_top + pCodec->m_sizeY;

+            int des_Bpp = pDIBitmap->GetBPP() >> 3;

+            FX_DWORD des_ScanOffet = pCodec->m_startX * des_Bpp;

+            if(des_row + (int)scale_y >= des_bottom - 1) {

+                FX_LPBYTE scan_src = (FX_LPBYTE)pDIBitmap->GetScanline(des_row) + des_ScanOffet;

+                int cur_row = des_row;

+                while (++cur_row < des_bottom) {

+                    FX_LPBYTE scan_des = (FX_LPBYTE)pDIBitmap->GetScanline(cur_row) + des_ScanOffet;

+                    FX_DWORD size = pCodec->m_sizeX * des_Bpp;

+                    FXSYS_memcpy32(scan_des, scan_src, size);

+                }

+            }

+            if(bLastPass) {

+                pCodec->GifDoubleLineResampleVert(pDIBitmap, scale_y, des_row);

+            }

+        }

+    }

+}

+void CCodec_ProgressiveDecoder::GifDoubleLineResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row)

+{

+    int des_Bpp = pDeviceBitmap->GetBPP() >> 3;

+    FX_DWORD des_ScanOffet = m_startX * des_Bpp;

+    int des_top = m_startY;

+    int des_row_1 = des_row - int(2 * scale_y);

+    if(des_row_1 < des_top) {

+        des_row_1 = des_top;

+    }

+    for (; des_row_1 < des_row; des_row_1++) {

+        FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row_1) + des_ScanOffet;

+        PixelWeight* pWeight = m_WeightVert.GetPixelWeight(des_row_1 - des_top);

+        FX_LPCBYTE scan_src1 = pDeviceBitmap->GetScanline(pWeight->m_SrcStart + des_top) + des_ScanOffet;

+        FX_LPCBYTE scan_src2 = pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + des_top) + des_ScanOffet;

+        for (int des_col = 0; des_col < m_sizeX; des_col++) {

+            switch(pDeviceBitmap->GetFormat()) {

+                case FXDIB_Invalid:

+                case FXDIB_1bppMask:

+                case FXDIB_1bppRgb:

+                    return;

+                case FXDIB_8bppMask:

+                case FXDIB_8bppRgb: {

+                        if(pDeviceBitmap->GetPalette() != NULL) {

+                            return;

+                        }

+                        int des_g = 0;

+                        des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                        *scan_des++ = (FX_BYTE)(des_g >> 16);

+                    }

+                    break;

+                case FXDIB_Rgb:

+                case FXDIB_Rgb32: {

+                        FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                        des_b += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_r += pWeight->m_Weights[0] * (*scan_src1++);

+                        scan_src1 += des_Bpp - 3;

+                        des_b += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_r += pWeight->m_Weights[1] * (*scan_src2++);

+                        scan_src2 += des_Bpp - 3;

+                        *scan_des++ = (FX_BYTE)((des_b) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_g) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_r) >> 16);

+                        scan_des += des_Bpp - 3;

+                    }

+                    break;

+                case FXDIB_Argb: {

+                        FX_DWORD des_a = 0, des_b = 0, des_g = 0, des_r = 0;

+                        des_b += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_r += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_a += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_b += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_r += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_a += pWeight->m_Weights[1] * (*scan_src2++);

+                        *scan_des++ = (FX_BYTE)((des_b) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_g) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_r) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_a) >> 16);

+                    }

+                    break;

+                default:

+                    return;

+            }

+        }

+    }

+    int des_bottom = des_top + m_sizeY - 1;

+    if(des_row + (int)(2 * scale_y) >= des_bottom && des_row + (int)scale_y < des_bottom) {

+        GifDoubleLineResampleVert(pDeviceBitmap, scale_y, des_row + (int)scale_y);

+    }

+}

+FX_BOOL CCodec_ProgressiveDecoder::BmpReadMoreData(ICodec_BmpModule* pBmpModule, FXCODEC_STATUS& err_status)

+{

+    FX_DWORD dwSize = (FX_DWORD)m_pFile->GetSize();

+    if (dwSize <= m_offSet) {

+        return FALSE;

+    }

+    dwSize = dwSize - m_offSet;

+    FX_DWORD dwAvail = pBmpModule->GetAvailInput(m_pBmpContext, NULL);

+    if (dwAvail == m_SrcSize) {

+        if (dwSize > FXCODEC_BLOCK_SIZE) {

+            dwSize = FXCODEC_BLOCK_SIZE;

+        }

+        m_SrcSize = (dwSize + dwAvail + FXCODEC_BLOCK_SIZE - 1) / FXCODEC_BLOCK_SIZE * FXCODEC_BLOCK_SIZE;

+        m_pSrcBuf = FX_Realloc(FX_BYTE, m_pSrcBuf, m_SrcSize);

+        if (!m_pSrcBuf) {

+            err_status = FXCODEC_STATUS_ERR_MEMORY;

+            return FALSE;

+        }

+    } else {

+        FX_DWORD dwConsume = m_SrcSize - dwAvail;

+        if (dwAvail) {

+            FXSYS_memcpy32(m_pSrcBuf, m_pSrcBuf + dwConsume, dwAvail);

+        }

+        if (dwSize > dwConsume) {

+            dwSize = dwConsume;

+        }

+    }

+    if (!m_pFile->ReadBlock(m_pSrcBuf + dwAvail, m_offSet, dwSize)) {

+        err_status = FXCODEC_STATUS_ERR_READ;

+        return FALSE;

+    }

+    m_offSet += dwSize;

+    pBmpModule->Input(m_pBmpContext, m_pSrcBuf, dwSize + dwAvail);

+    return TRUE;

+}

+FX_BOOL CCodec_ProgressiveDecoder::BmpInputImagePositionBufCallback(void* pModule, FX_DWORD rcd_pos)

+{

+    CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;

+    pCodec->m_offSet = rcd_pos;

+    FXCODEC_STATUS error_status = FXCODEC_STATUS_ERROR;

+    if(!pCodec->BmpReadMoreData(pCodec->m_pCodecMgr->GetBmpModule(), error_status)) {

+        return FALSE;

+    }

+    return TRUE;

+}

+void CCodec_ProgressiveDecoder::BmpReadScanlineCallback(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf)

+{

+    CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule;

+    CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap;

+    ASSERT(pDIBitmap != NULL);

+    FXSYS_memcpy32(pCodec->m_pDecodeBuf, row_buf, pCodec->m_ScanlineSize);

+    int src_top = pCodec->m_clipBox.top;

+    int src_bottom = pCodec->m_clipBox.bottom;

+    int des_top = pCodec->m_startY;

+    int src_hei = pCodec->m_clipBox.Height();

+    int des_hei = pCodec->m_sizeY;

+    if(row_num >= src_top && row_num < src_bottom) {

+        double scale_y = (double)des_hei / (double)src_hei;

+        int src_row = row_num - src_top;

+        int des_row = (int)(src_row * scale_y)  + des_top;

+        if(des_row >= des_top + des_hei)	{

+            return;

+        }

+        pCodec->ReSampleScanline(pDIBitmap, des_row, pCodec->m_pDecodeBuf, pCodec->m_SrcFormat);

+        if(scale_y > 1.0) {

+            if(pCodec->m_BmpIsTopBottom || !pCodec->m_bInterpol) {

+                pCodec->ResampleVert(pDIBitmap, scale_y, des_row);

+                return;

+            } else {

+                pCodec->ResampleVertBT(pDIBitmap, scale_y, des_row);

+            }

+        }

+    }

+}

+void CCodec_ProgressiveDecoder::ResampleVertBT(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row)

+{

+    int des_Bpp = pDeviceBitmap->GetBPP() >> 3;

+    FX_DWORD des_ScanOffet = m_startX * des_Bpp;

+    int des_top = m_startY;

+    int des_bottom = m_startY + m_sizeY;

+    int des_row_1 = des_row + int(scale_y);

+    if(des_row_1 >= des_bottom - 1) {

+        FX_LPBYTE scan_src = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet;

+        while (++des_row < des_bottom) {

+            FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet;

+            FX_DWORD size = m_sizeX * des_Bpp;

+            FXSYS_memcpy32(scan_des, scan_src, size);

+        }

+        return;

+    }

+    for (; des_row_1 > des_row; des_row_1--) {

+        FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row_1) + des_ScanOffet;

+        PixelWeight* pWeight = m_WeightVert.GetPixelWeight(des_row_1 - des_top);

+        FX_LPCBYTE scan_src1 = pDeviceBitmap->GetScanline(pWeight->m_SrcStart + des_top) + des_ScanOffet;

+        FX_LPCBYTE scan_src2 = pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + des_top) + des_ScanOffet;

+        for (int des_col = 0; des_col < m_sizeX; des_col++) {

+            switch(pDeviceBitmap->GetFormat()) {

+                case FXDIB_Invalid:

+                case FXDIB_1bppMask:

+                case FXDIB_1bppRgb:

+                    return;

+                case FXDIB_8bppMask:

+                case FXDIB_8bppRgb: {

+                        if(pDeviceBitmap->GetPalette() != NULL) {

+                            return;

+                        }

+                        int des_g = 0;

+                        des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                        *scan_des++ = (FX_BYTE)(des_g >> 16);

+                    }

+                    break;

+                case FXDIB_Rgb:

+                case FXDIB_Rgb32: {

+                        FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                        des_b += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_r += pWeight->m_Weights[0] * (*scan_src1++);

+                        scan_src1 += des_Bpp - 3;

+                        des_b += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_r += pWeight->m_Weights[1] * (*scan_src2++);

+                        scan_src2 += des_Bpp - 3;

+                        *scan_des++ = (FX_BYTE)((des_b) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_g) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_r) >> 16);

+                        scan_des += des_Bpp - 3;

+                    }

+                    break;

+                case FXDIB_Argb: {

+                        FX_DWORD des_a = 0, des_b = 0, des_g = 0, des_r = 0;

+                        des_b += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_r += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_a += pWeight->m_Weights[0] * (*scan_src1++);

+                        des_b += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_r += pWeight->m_Weights[1] * (*scan_src2++);

+                        des_a += pWeight->m_Weights[1] * (*scan_src2++);

+                        *scan_des++ = (FX_BYTE)((des_b) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_g) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_r) >> 16);

+                        *scan_des++ = (FX_BYTE)((des_a) >> 16);

+                    }

+                    break;

+                default:

+                    return;

+            }

+        }

+    }

+}

+FX_BOOL CCodec_ProgressiveDecoder::DetectImageType(FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute* pAttribute)

+{

+    m_offSet = 0;

+    FX_DWORD size = (FX_DWORD)m_pFile->GetSize();

+    if(size > FXCODEC_BLOCK_SIZE) {

+        size = FXCODEC_BLOCK_SIZE;

+    }

+    if(m_pSrcBuf != NULL) {

+        FX_Free(m_pSrcBuf);

+        m_pSrcBuf = NULL;

+    }

+    m_pSrcBuf = FX_Alloc(FX_BYTE, size);

+    if(m_pSrcBuf == NULL) {

+        m_status = FXCODEC_STATUS_ERR_MEMORY;

+        return FALSE;

+    }

+    FXSYS_memset32(m_pSrcBuf, 0, size);

+    m_SrcSize = size;

+    switch(imageType) {

+        case FXCODEC_IMAGE_BMP: {

+                ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();

+                if(pBmpModule == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    return FALSE;

+                }

+                pBmpModule->InputImagePositionBufCallback = BmpInputImagePositionBufCallback;

+                pBmpModule->ReadScanlineCallback = BmpReadScanlineCallback;

+                m_pBmpContext = pBmpModule->Start((void*)this);

+                if(m_pBmpContext == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    return FALSE;

+                }

+                FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, 0, size);

+                if(!bResult) {

+                    m_status = FXCODEC_STATUS_ERR_READ;

+                    return FALSE;

+                }

+                m_offSet += size;

+                pBmpModule->Input(m_pBmpContext, m_pSrcBuf, size);

+                FX_DWORD* pPalette = NULL;

+                FX_INT32 readResult = pBmpModule->ReadHeader(m_pBmpContext, &m_SrcWidth, &m_SrcHeight, &m_BmpIsTopBottom,

+                                      &m_SrcComponents, &m_SrcPaletteNumber, &pPalette, pAttribute);

+                while(readResult == 2) {

+                    FXCODEC_STATUS error_status = FXCODEC_STATUS_ERR_FORMAT;

+                    if(!BmpReadMoreData(pBmpModule, error_status)) {

+                        m_status = error_status;

+                        return FALSE;

+                    }

+                    readResult = pBmpModule->ReadHeader(m_pBmpContext, &m_SrcWidth, &m_SrcHeight, &m_BmpIsTopBottom,

+                                                        &m_SrcComponents, &m_SrcPaletteNumber, &pPalette, pAttribute);

+                }

+                if(readResult == 1) {

+                    m_SrcBPC = 8;

+                    m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);

+                    if(m_pSrcPalette != NULL) {

+                        FX_Free(m_pSrcPalette);

+                        m_pSrcPalette = NULL;

+                    }

+                    if (m_SrcPaletteNumber) {

+                        m_pSrcPalette = FX_Alloc(FX_ARGB, m_SrcPaletteNumber);

+                        if(m_pSrcPalette == NULL) {

+                            m_status = FXCODEC_STATUS_ERR_MEMORY;

+                            return FALSE;

+                        }

+                        FXSYS_memcpy32(m_pSrcPalette, pPalette, m_SrcPaletteNumber * sizeof(FX_DWORD));

+                    }

+                    return TRUE;

+                }

+                if(m_pBmpContext != NULL) {

+                    pBmpModule->Finish(m_pBmpContext);

+                    m_pBmpContext = NULL;

+                }

+                m_status = FXCODEC_STATUS_ERR_FORMAT;

+                return FALSE;

+            }

+            break;

+        case FXCODEC_IMAGE_JPG: {

+                ICodec_JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule();

+                if(pJpegModule == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    return FALSE;

+                }

+                m_pJpegContext = pJpegModule->Start();

+                if(m_pJpegContext == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    return FALSE;

+                }

+                FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, 0, size);

+                if(!bResult) {

+                    m_status = FXCODEC_STATUS_ERR_READ;

+                    return FALSE;

+                }

+                m_offSet += size;

+                pJpegModule->Input(m_pJpegContext, m_pSrcBuf, size);

+                FX_INT32 readResult = pJpegModule->ReadHeader(m_pJpegContext, &m_SrcWidth, &m_SrcHeight, &m_SrcComponents, pAttribute);

+                while(readResult == 2) {

+                    FXCODEC_STATUS error_status = FXCODEC_STATUS_ERR_FORMAT;

+                    if(!JpegReadMoreData(pJpegModule, error_status)) {

+                        m_status = error_status;

+                        return FALSE;

+                    }

+                    readResult = pJpegModule->ReadHeader(m_pJpegContext, &m_SrcWidth, &m_SrcHeight, &m_SrcComponents, pAttribute);

+                }

+                if(!readResult) {

+                    m_SrcBPC = 8;

+                    m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);

+                    return TRUE;

+                }

+                if(m_pJpegContext != NULL) {

+                    pJpegModule->Finish(m_pJpegContext);

+                    m_pJpegContext = NULL;

+                }

+                m_status = FXCODEC_STATUS_ERR_FORMAT;

+                return FALSE;

+            }

+            break;

+        case FXCODEC_IMAGE_PNG: {

+                ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();

+                if(pPngModule == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    return FALSE;

+                }

+                pPngModule->ReadHeaderCallback = CCodec_ProgressiveDecoder::PngReadHeaderFunc;

+                pPngModule->AskScanlineBufCallback = CCodec_ProgressiveDecoder::PngAskScanlineBufFunc;

+                pPngModule->FillScanlineBufCompletedCallback = CCodec_ProgressiveDecoder::PngFillScanlineBufCompletedFunc;

+                m_pPngContext = pPngModule->Start((void*)this);

+                if(m_pPngContext == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    return FALSE;

+                }

+                FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, 0, size);

+                if(!bResult) {

+                    m_status = FXCODEC_STATUS_ERR_READ;

+                    return FALSE;

+                }

+                m_offSet += size;

+                bResult = pPngModule->Input(m_pPngContext, m_pSrcBuf, size, pAttribute);

+                while(bResult) {

+                    FX_DWORD remain_size = (FX_DWORD)m_pFile->GetSize() - m_offSet;

+                    FX_DWORD input_size = remain_size > FXCODEC_BLOCK_SIZE ? FXCODEC_BLOCK_SIZE : remain_size;

+                    if(input_size == 0) {

+                        if(m_pPngContext != NULL) {

+                            pPngModule->Finish(m_pPngContext);

+                        }

+                        m_pPngContext = NULL;

+                        m_status = FXCODEC_STATUS_ERR_FORMAT;

+                        return FALSE;

+                    }

+                    if(m_pSrcBuf != NULL && input_size > m_SrcSize) {

+                        FX_Free(m_pSrcBuf);

+                        m_pSrcBuf = FX_Alloc(FX_BYTE, input_size);

+                        if(m_pSrcBuf == NULL) {

+                            m_status = FXCODEC_STATUS_ERR_MEMORY;

+                            return FALSE;

+                        }

+                        FXSYS_memset32(m_pSrcBuf, 0, input_size);

+                        m_SrcSize = input_size;

+                    }

+                    bResult = m_pFile->ReadBlock(m_pSrcBuf, m_offSet, input_size);

+                    if(!bResult) {

+                        m_status = FXCODEC_STATUS_ERR_READ;

+                        return FALSE;

+                    }

+                    m_offSet += input_size;

+                    bResult = pPngModule->Input(m_pPngContext, m_pSrcBuf, input_size, pAttribute);

+                }

+                ASSERT(!bResult);

+                if(m_pPngContext != NULL) {

+                    pPngModule->Finish(m_pPngContext);

+                    m_pPngContext = NULL;

+                }

+                if(m_SrcPassNumber == 0) {

+                    m_status = FXCODEC_STATUS_ERR_FORMAT;

+                    return FALSE;

+                }

+            }

+            break;

+        case FXCODEC_IMAGE_GIF: {

+                ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();

+                if(pGifModule == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    return FALSE;

+                }

+                pGifModule->RecordCurrentPositionCallback = CCodec_ProgressiveDecoder::GifRecordCurrentPositionCallback;

+                pGifModule->AskLocalPaletteBufCallback = CCodec_ProgressiveDecoder::GifAskLocalPaletteBufCallback;

+                pGifModule->InputRecordPositionBufCallback = CCodec_ProgressiveDecoder::GifInputRecordPositionBufCallback;

+                pGifModule->ReadScanlineCallback = CCodec_ProgressiveDecoder::GifReadScanlineCallback;

+                m_pGifContext = pGifModule->Start((void*)this);

+                if(m_pGifContext == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    return FALSE;

+                }

+                FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, 0, size);

+                if(!bResult) {

+                    m_status = FXCODEC_STATUS_ERR_READ;

+                    return FALSE;

+                }

+                m_offSet += size;

+                pGifModule->Input(m_pGifContext, m_pSrcBuf, size);

+                m_SrcComponents = 1;

+                FX_INT32 readResult = pGifModule->ReadHeader(m_pGifContext, &m_SrcWidth, &m_SrcHeight,

+                                      &m_GifPltNumber, (void**)&m_pGifPalette, &m_GifBgIndex);

+                while(readResult == 2) {

+                    FXCODEC_STATUS error_status = FXCODEC_STATUS_ERR_FORMAT;

+                    if(!GifReadMoreData(pGifModule, error_status)) {

+                        m_status = error_status;

+                        return FALSE;

+                    }

+                    readResult = pGifModule->ReadHeader(m_pGifContext, &m_SrcWidth, &m_SrcHeight,

+                                                        &m_GifPltNumber, (void**)&m_pGifPalette, &m_GifBgIndex);

+                }

+                if(readResult == 1) {

+                    m_SrcBPC = 8;

+                    m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);

+                    return TRUE;

+                }

+                if(m_pGifContext != NULL) {

+                    pGifModule->Finish(m_pGifContext);

+                    m_pGifContext = NULL;

+                }

+                m_status = FXCODEC_STATUS_ERR_FORMAT;

+                return FALSE;

+            }

+            break;

+        case FXCODEC_IMAGE_TIF: {

+                ICodec_TiffModule* pTiffModule = m_pCodecMgr->GetTiffModule();

+                if(pTiffModule == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_FORMAT;

+                    return FALSE;

+                }

+                m_pTiffContext = pTiffModule->CreateDecoder(m_pFile);

+                if(m_pTiffContext == NULL) {

+                    m_status = FXCODEC_STATUS_ERR_FORMAT;

+                    return FALSE;

+                }

+                FX_INT32 frames = 0;

+                pTiffModule->GetFrames(m_pTiffContext, frames);

+                FX_DWORD bpc;

+                FX_BOOL ret = pTiffModule->LoadFrameInfo(m_pTiffContext, 0, (FX_DWORD&)m_SrcWidth, (FX_DWORD&)m_SrcHeight, (FX_DWORD&)m_SrcComponents, bpc, pAttribute);

+                m_SrcComponents = 4;

+                m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);

+                if(!ret) {

+                    pTiffModule->DestroyDecoder(m_pTiffContext);

+                    (m_pTiffContext = NULL);

+                    (m_status = FXCODEC_STATUS_ERR_FORMAT);

+                    return FALSE;

+                }

+            }

+            break;

+        default:

+            m_status = FXCODEC_STATUS_ERR_FORMAT;

+            return FALSE;

+    }

+    return TRUE;

+}

+FXCODEC_STATUS CCodec_ProgressiveDecoder::LoadImageInfo(IFX_FileRead* pFile, FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute* pAttribute)

+{

+    switch(m_status) {

+        case FXCODEC_STATUS_FRAME_READY:

+        case FXCODEC_STATUS_FRAME_TOBECONTINUE:

+        case FXCODEC_STATUS_DECODE_READY:

+        case FXCODEC_STATUS_DECODE_TOBECONTINUE:

+            return FXCODEC_STATUS_ERROR;

+        default:

+            ;

+    }

+    if(pFile == NULL) {

+        m_status = FXCODEC_STATUS_ERR_PARAMS;

+        m_pFile = NULL;

+        return m_status;

+    }

+    m_pFile = pFile;

+    m_offSet = 0;

+    m_SrcWidth = m_SrcHeight = 0;

+    m_SrcComponents = m_SrcBPC = 0;

+    m_clipBox = FX_RECT(0, 0, 0, 0);

+    m_startX = m_startY = 0;

+    m_sizeX = m_sizeY = 0;

+    m_SrcPassNumber = 0;

+    if(imageType != FXCODEC_IMAGE_UNKNOWN &&

+            DetectImageType(imageType, pAttribute)) {

+        m_imagType = imageType;

+        m_status = FXCODEC_STATUS_FRAME_READY;

+        return m_status;

+    }

+    for (int type = FXCODEC_IMAGE_BMP; type < FXCODEC_IMAGE_MAX; type++) {

+        if(DetectImageType((FXCODEC_IMAGE_TYPE)type, pAttribute)) {

+            m_imagType = (FXCODEC_IMAGE_TYPE)type;

+            m_status = FXCODEC_STATUS_FRAME_READY;

+            return m_status;

+        }

+    }

+    m_status = FXCODEC_STATUS_ERR_FORMAT;

+    m_pFile = NULL;

+    return m_status;

+}

+void CCodec_ProgressiveDecoder::SetClipBox(FX_RECT* clip)

+{

+    if(m_status != FXCODEC_STATUS_FRAME_READY) {

+        return;

+    }

+    if(clip->IsEmpty()) {

+        m_clipBox = FX_RECT(0, 0, 0, 0);

+        return;

+    }

+    if(clip->left < 0) {

+        clip->left = 0;

+    }

+    if(clip->right > m_SrcWidth) {

+        clip->right = m_SrcWidth;

+    }

+    if(clip->top < 0) {

+        clip->top = 0;

+    }

+    if(clip->bottom > m_SrcHeight) {

+        clip->bottom = m_SrcHeight;

+    }

+    if(clip->IsEmpty()) {

+        m_clipBox = FX_RECT(0, 0, 0, 0);

+        return;

+    }

+    m_clipBox = *clip;

+}

+void CCodec_ProgressiveDecoder::GetDownScale(int& down_scale)

+{

+    down_scale = 1;

+    int ratio_w = m_clipBox.Width() / m_sizeX;

+    int ratio_h = m_clipBox.Height() / m_sizeY;

+    int ratio = (ratio_w > ratio_h) ? ratio_h : ratio_w;

+    if (ratio >= 8) {

+        down_scale = 8;

+    } else if (ratio >= 4)	{

+        down_scale = 4;

+    } else if (ratio >= 2)	{

+        down_scale = 2;

+    }

+    m_clipBox.left /= down_scale;

+    m_clipBox.right /= down_scale;

+    m_clipBox.top /= down_scale;

+    m_clipBox.bottom /= down_scale;

+    if(m_clipBox.right == m_clipBox.left) {

+        m_clipBox.right = m_clipBox.left + 1;

+    }

+    if(m_clipBox.bottom == m_clipBox.top) {

+        m_clipBox.bottom = m_clipBox.top + 1;

+    }

+}

+void CCodec_ProgressiveDecoder::GetTransMethod(FXDIB_Format des_format, FXCodec_Format src_format)

+{

+    switch(des_format) {

+        case FXDIB_1bppMask:

+        case FXDIB_1bppRgb: {

+                switch(src_format) {

+                    case FXCodec_1bppGray:

+                        m_TransMethod = 0;

+                        break;

+                    default:

+                        m_TransMethod = -1;

+                }

+            }

+            break;

+        case FXDIB_8bppMask:

+        case FXDIB_8bppRgb: {

+                switch(src_format) {

+                    case FXCodec_1bppGray:

+                        m_TransMethod = 1;

+                        break;

+                    case FXCodec_8bppGray:

+                        m_TransMethod = 2;

+                        break;

+                    case FXCodec_1bppRgb:

+                    case FXCodec_8bppRgb:

+                        m_TransMethod = 3;

+                        break;

+                    case FXCodec_Rgb:

+                    case FXCodec_Rgb32:

+                    case FXCodec_Argb:

+                        m_TransMethod = 4;

+                        break;

+                    case FXCodec_Cmyk:

+                        m_TransMethod = 5;

+                        break;

+                    default:

+                        m_TransMethod = -1;

+                }

+            }

+            break;

+        case FXDIB_Rgb: {

+                switch(src_format) {

+                    case FXCodec_1bppGray:

+                        m_TransMethod = 6;

+                        break;

+                    case FXCodec_8bppGray:

+                        m_TransMethod = 7;

+                        break;

+                    case FXCodec_1bppRgb:

+                    case FXCodec_8bppRgb:

+                        m_TransMethod = 8;

+                        break;

+                    case FXCodec_Rgb:

+                    case FXCodec_Rgb32:

+                    case FXCodec_Argb:

+                        m_TransMethod = 9;

+                        break;

+                    case FXCodec_Cmyk:

+                        m_TransMethod = 10;

+                        break;

+                    default:

+                        m_TransMethod = -1;

+                }

+            }

+            break;

+        case FXDIB_Rgb32:

+        case FXDIB_Argb: {

+                switch(src_format) {

+                    case FXCodec_1bppGray:

+                        m_TransMethod = 6;

+                        break;

+                    case FXCodec_8bppGray:

+                        m_TransMethod = 7;

+                        break;

+                    case FXCodec_1bppRgb:

+                    case FXCodec_8bppRgb:

+                        if(des_format == FXDIB_Argb) {

+                            m_TransMethod = 12;

+                        } else {

+                            m_TransMethod = 8;

+                        }

+                        break;

+                    case FXCodec_Rgb:

+                    case FXCodec_Rgb32:

+                        m_TransMethod = 9;

+                        break;

+                    case FXCodec_Cmyk:

+                        m_TransMethod = 10;

+                        break;

+                    case FXCodec_Argb:

+                        m_TransMethod = 11;

+                        break;

+                    default:

+                        m_TransMethod = -1;

+                }

+            }

+            break;

+        default:

+            m_TransMethod = -1;

+    }

+}

+void _RGB2BGR(FX_LPBYTE buffer, int width = 1)

+{

+    if (buffer && width > 0) {

+        FX_BYTE temp;

+        int i = 0;

+        int j = 0;

+        for (; i < width; i++, j += 3) {

+            temp = buffer[j];

+            buffer[j] = buffer[j + 2];

+            buffer[j + 2] = temp;

+        }

+    }

+}

+void CCodec_ProgressiveDecoder::ReSampleScanline(CFX_DIBitmap* pDeviceBitmap, int des_line, FX_LPBYTE src_scan, FXCodec_Format src_format)

+{

+    int src_left = m_clipBox.left;

+    int des_left = m_startX;

+    FX_LPBYTE des_scan = pDeviceBitmap->GetBuffer() + des_line * pDeviceBitmap->GetPitch();

+    int src_bpp = src_format & 0xff;

+    int des_bpp = pDeviceBitmap->GetBPP();

+    int src_Bpp = src_bpp >> 3;

+    int des_Bpp = des_bpp >> 3;

+    src_scan += src_left * src_Bpp;

+    des_scan += des_left * des_Bpp;

+    for (int des_col = 0; des_col < m_sizeX; des_col++) {

+        PixelWeight* pPixelWeights = m_WeightHorz.GetPixelWeight(des_col);

+        switch(m_TransMethod) {

+            case -1:

+                return;

+            case 0:

+                return;

+            case 1:

+                return;

+            case 2: {

+                    FX_DWORD des_g = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        des_g += pixel_weight * src_scan[j];

+                    }

+                    *des_scan++ = (FX_BYTE)(des_g >> 16);

+                }

+                break;

+            case 3: {

+                    int des_r = 0, des_g = 0, des_b = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        unsigned long argb = m_pSrcPalette[src_scan[j]];

+                        des_r += pixel_weight * (FX_BYTE)(argb >> 16);

+                        des_g += pixel_weight * (FX_BYTE)(argb >> 8);

+                        des_b += pixel_weight * (FX_BYTE)argb;

+                    }

+                    *des_scan++ = (FX_BYTE)FXRGB2GRAY((des_r >> 16), (des_g >> 16), (des_b >> 16));

+                }

+                break;

+            case 4: {

+                    FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        FX_LPCBYTE src_pixel = src_scan + j * src_Bpp;

+                        des_b += pixel_weight * (*src_pixel++);

+                        des_g += pixel_weight * (*src_pixel++);

+                        des_r += pixel_weight * (*src_pixel);

+                    }

+                    *des_scan++ = (FX_BYTE)FXRGB2GRAY((des_r >> 16), (des_g >> 16), (des_b >> 16));

+                }

+                break;

+            case 5: {

+                    FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        FX_LPCBYTE src_pixel = src_scan + j * src_Bpp;

+                        FX_BYTE src_b = 0, src_g = 0, src_r = 0;

+                        AdobeCMYK_to_sRGB1(255 - src_pixel[0], 255 - src_pixel[1], 255 - src_pixel[2], 255 - src_pixel[3],

+                                           src_r, src_g, src_b);

+                        des_b += pixel_weight * src_b;

+                        des_g += pixel_weight * src_g;

+                        des_r += pixel_weight * src_r;

+                    }

+                    *des_scan++ = (FX_BYTE)FXRGB2GRAY((des_r >> 16), (des_g >> 16), (des_b >> 16));

+                }

+                break;

+            case 6:

+                return;

+            case 7: {

+                    FX_DWORD des_g = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        des_g += pixel_weight * src_scan[j];

+                    }

+                    FXSYS_memset8(des_scan, (FX_BYTE)(des_g >> 16), 3);

+                    des_scan += des_Bpp;

+                }

+                break;

+            case 8: {

+                    int des_r = 0, des_g = 0, des_b = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        unsigned long argb = m_pSrcPalette[src_scan[j]];

+                        des_r += pixel_weight * (FX_BYTE)(argb >> 16);

+                        des_g += pixel_weight * (FX_BYTE)(argb >> 8);

+                        des_b += pixel_weight * (FX_BYTE)argb;

+                    }

+                    *des_scan++ = (FX_BYTE)((des_b) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_g) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_r) >> 16);

+                    des_scan += des_Bpp - 3;

+                }

+                break;

+            case 12: {

+                    if (m_pBmpContext) {

+                        int des_r = 0, des_g = 0, des_b = 0;

+                        for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {

+                            int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                            unsigned long argb = m_pSrcPalette[src_scan[j]];

+                            des_r += pixel_weight * (FX_BYTE)(argb >> 16);

+                            des_g += pixel_weight * (FX_BYTE)(argb >> 8);

+                            des_b += pixel_weight * (FX_BYTE)argb;

+                        }

+                        *des_scan++ = (FX_BYTE)((des_b) >> 16);

+                        *des_scan++ = (FX_BYTE)((des_g) >> 16);

+                        *des_scan++ = (FX_BYTE)((des_r) >> 16);

+                        *des_scan++ = 0xFF;

+                    } else {

+                        int des_a = 0, des_r = 0, des_g = 0, des_b = 0;

+                        for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {

+                            int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                            unsigned long argb = m_pSrcPalette[src_scan[j]];

+                            des_a += pixel_weight * (FX_BYTE)(argb >> 24);

+                            des_r += pixel_weight * (FX_BYTE)(argb >> 16);

+                            des_g += pixel_weight * (FX_BYTE)(argb >> 8);

+                            des_b += pixel_weight * (FX_BYTE)argb;

+                        }

+                        *des_scan++ = (FX_BYTE)((des_b) >> 16);

+                        *des_scan++ = (FX_BYTE)((des_g) >> 16);

+                        *des_scan++ = (FX_BYTE)((des_r) >> 16);

+                        *des_scan++ = (FX_BYTE)((des_a) >> 16);

+                    }

+                }

+                break;

+            case 9: {

+                    FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        FX_LPCBYTE src_pixel = src_scan + j * src_Bpp;

+                        des_b += pixel_weight * (*src_pixel++);

+                        des_g += pixel_weight * (*src_pixel++);

+                        des_r += pixel_weight * (*src_pixel);

+                    }

+                    *des_scan++ = (FX_BYTE)((des_b) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_g) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_r) >> 16);

+                    des_scan += des_Bpp - 3;

+                }

+                break;

+            case 10: {

+                    FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        FX_LPCBYTE src_pixel = src_scan + j * src_Bpp;

+                        FX_BYTE src_b = 0, src_g = 0, src_r = 0;

+                        AdobeCMYK_to_sRGB1(255 - src_pixel[0], 255 - src_pixel[1], 255 - src_pixel[2], 255 - src_pixel[3],

+                                           src_r, src_g, src_b);

+                        des_b += pixel_weight * src_b;

+                        des_g += pixel_weight * src_g;

+                        des_r += pixel_weight * src_r;

+                    }

+                    *des_scan++ = (FX_BYTE)((des_b) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_g) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_r) >> 16);

+                    des_scan += des_Bpp - 3;

+                }

+                break;

+            case 11: {

+                    FX_DWORD des_alpha = 0, des_r = 0, des_g = 0, des_b = 0;

+                    for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {

+                        int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];

+                        FX_LPCBYTE src_pixel = src_scan + j * src_Bpp;

+                        pixel_weight = pixel_weight * src_pixel[3] / 255;

+                        des_b += pixel_weight * (*src_pixel++);

+                        des_g += pixel_weight * (*src_pixel++);

+                        des_r += pixel_weight * (*src_pixel);

+                        des_alpha += pixel_weight;

+                    }

+                    *des_scan++ = (FX_BYTE)((des_b) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_g) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_r) >> 16);

+                    *des_scan++ = (FX_BYTE)((des_alpha * 255) >> 16);

+                }

+                break;

+            default:

+                return;

+        }

+    }

+}

+void CCodec_ProgressiveDecoder::ResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row)

+{

+    int des_Bpp = pDeviceBitmap->GetBPP() >> 3;

+    FX_DWORD des_ScanOffet = m_startX * des_Bpp;

+    if(m_bInterpol) {

+        int des_top = m_startY;

+        int des_row_1 = des_row - int(scale_y);

+        if(des_row_1 < des_top) {

+            int des_bottom = des_top + m_sizeY;

+            if(des_row + (int)scale_y >= des_bottom - 1) {

+                FX_LPBYTE scan_src = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet;

+                while (++des_row < des_bottom) {

+                    FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet;

+                    FX_DWORD size = m_sizeX * des_Bpp;

+                    FXSYS_memcpy32(scan_des, scan_src, size);

+                }

+            }

+            return;

+        }

+        for (; des_row_1 < des_row; des_row_1++) {

+            FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row_1) + des_ScanOffet;

+            PixelWeight* pWeight = m_WeightVert.GetPixelWeight(des_row_1 - des_top);

+            FX_LPCBYTE scan_src1 = pDeviceBitmap->GetScanline(pWeight->m_SrcStart + des_top) + des_ScanOffet;

+            FX_LPCBYTE scan_src2 = pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + des_top) + des_ScanOffet;

+            for (int des_col = 0; des_col < m_sizeX; des_col++) {

+                switch(pDeviceBitmap->GetFormat()) {

+                    case FXDIB_Invalid:

+                    case FXDIB_1bppMask:

+                    case FXDIB_1bppRgb:

+                        return;

+                    case FXDIB_8bppMask:

+                    case FXDIB_8bppRgb: {

+                            if(pDeviceBitmap->GetPalette() != NULL) {

+                                return;

+                            }

+                            int des_g = 0;

+                            des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                            des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                            *scan_des++ = (FX_BYTE)(des_g >> 16);

+                        }

+                        break;

+                    case FXDIB_Rgb:

+                    case FXDIB_Rgb32: {

+                            FX_DWORD des_b = 0, des_g = 0, des_r = 0;

+                            des_b += pWeight->m_Weights[0] * (*scan_src1++);

+                            des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                            des_r += pWeight->m_Weights[0] * (*scan_src1++);

+                            scan_src1 += des_Bpp - 3;

+                            des_b += pWeight->m_Weights[1] * (*scan_src2++);

+                            des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                            des_r += pWeight->m_Weights[1] * (*scan_src2++);

+                            scan_src2 += des_Bpp - 3;

+                            *scan_des++ = (FX_BYTE)((des_b) >> 16);

+                            *scan_des++ = (FX_BYTE)((des_g) >> 16);

+                            *scan_des++ = (FX_BYTE)((des_r) >> 16);

+                            scan_des += des_Bpp - 3;

+                        }

+                        break;

+                    case FXDIB_Argb: {

+                            FX_DWORD des_a = 0, des_b = 0, des_g = 0, des_r = 0;

+                            des_b += pWeight->m_Weights[0] * (*scan_src1++);

+                            des_g += pWeight->m_Weights[0] * (*scan_src1++);

+                            des_r += pWeight->m_Weights[0] * (*scan_src1++);

+                            des_a += pWeight->m_Weights[0] * (*scan_src1++);

+                            des_b += pWeight->m_Weights[1] * (*scan_src2++);

+                            des_g += pWeight->m_Weights[1] * (*scan_src2++);

+                            des_r += pWeight->m_Weights[1] * (*scan_src2++);

+                            des_a += pWeight->m_Weights[1] * (*scan_src2++);

+                            *scan_des++ = (FX_BYTE)((des_b) >> 16);

+                            *scan_des++ = (FX_BYTE)((des_g) >> 16);

+                            *scan_des++ = (FX_BYTE)((des_r) >> 16);

+                            *scan_des++ = (FX_BYTE)((des_a) >> 16);

+                        }

+                        break;

+                    default:

+                        return;

+                }

+            }

+        }

+        int des_bottom = des_top + m_sizeY;

+        if(des_row + (int)scale_y >= des_bottom - 1) {

+            FX_LPBYTE scan_src = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet;

+            while (++des_row < des_bottom) {

+                FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet;

+                FX_DWORD size = m_sizeX * des_Bpp;

+                FXSYS_memcpy32(scan_des, scan_src, size);

+            }

+        }

+        return;

+    }

+    int multiple = (int)FXSYS_ceil((FX_FLOAT)scale_y - 1);

+    if(multiple > 0) {

+        FX_LPBYTE scan_src = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet;

+        for (int i = 1; i <= multiple; i++) {

+            if(des_row + i >= m_startY + m_sizeY) {

+                return;

+            }

+            FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row + i) + des_ScanOffet;

+            FX_DWORD size = m_sizeX * des_Bpp;

+            FXSYS_memcpy32(scan_des, scan_src, size);

+        }

+    }

+}

+void CCodec_ProgressiveDecoder::Resample(CFX_DIBitmap* pDeviceBitmap, FX_INT32 src_line, FX_LPBYTE src_scan, FXCodec_Format src_format)

+{

+    int src_top = m_clipBox.top;

+    int des_top = m_startY;

+    int src_hei = m_clipBox.Height();

+    int des_hei = m_sizeY;

+    if(src_line >= src_top) {

+        double scale_y = (double)des_hei / (double)src_hei;

+        int src_row = src_line - src_top;

+        int des_row = (int)(src_row * scale_y)  + des_top;

+        if(des_row >= des_top + des_hei)	{

+            return;

+        }

+        ReSampleScanline(pDeviceBitmap, des_row, m_pDecodeBuf, src_format);

+        if(scale_y > 1.0) {

+            ResampleVert(pDeviceBitmap, scale_y, des_row);

+        }

+    }

+}

+FXCODEC_STATUS CCodec_ProgressiveDecoder::GetFrames(FX_INT32& frames, IFX_Pause* pPause)

+{

+    if(!(m_status == FXCODEC_STATUS_FRAME_READY || m_status == FXCODEC_STATUS_FRAME_TOBECONTINUE)) {

+        return FXCODEC_STATUS_ERROR;

+    }

+    switch(m_imagType) {

+        case FXCODEC_IMAGE_BMP:

+        case FXCODEC_IMAGE_JPG:

+        case FXCODEC_IMAGE_PNG:

+        case FXCODEC_IMAGE_TIF:

+            frames = m_FrameNumber = 1;

+            return m_status = FXCODEC_STATUS_DECODE_READY;

+        case FXCODEC_IMAGE_GIF: {

+                ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();

+                while (TRUE) {

+                    FX_INT32 readResult = pGifModule->LoadFrameInfo(m_pGifContext, &m_FrameNumber);

+                    while(readResult == 2) {

+                        FXCODEC_STATUS error_status = FXCODEC_STATUS_ERR_READ;

+                        if(!GifReadMoreData(pGifModule, error_status)) {

+                            return error_status;

+                        }

+                        if(pPause && pPause->NeedToPauseNow()) {

+                            return m_status = FXCODEC_STATUS_FRAME_TOBECONTINUE;

+                        }

+                        readResult = pGifModule->LoadFrameInfo(m_pGifContext, &m_FrameNumber);

+                    }

+                    if(readResult == 1) {

+                        frames = m_FrameNumber;

+                        return m_status = FXCODEC_STATUS_DECODE_READY;

+                    }

+                    if(m_pGifContext != NULL) {

+                        pGifModule->Finish(m_pGifContext);

+                        m_pGifContext = NULL;

+                    }

+                    return m_status = FXCODEC_STATUS_ERROR;

+                }

+            }

+            break;

+        default:

+            ;

+    }

+    return FXCODEC_STATUS_ERROR;

+}

+FXCODEC_STATUS CCodec_ProgressiveDecoder::StartDecode(CFX_DIBitmap* pDIBitmap,

+        int start_x, int start_y, int size_x, int size_y,

+        FX_INT32 frames, FX_BOOL bInterpol)

+{

+    if(m_status != FXCODEC_STATUS_DECODE_READY) {

+        return FXCODEC_STATUS_ERROR;

+    }

+    if(pDIBitmap == NULL || pDIBitmap->GetBPP() < 8 ||

+            frames < 0 || frames >= m_FrameNumber) {

+        return FXCODEC_STATUS_ERR_PARAMS;

+    }

+    m_pDeviceBitmap = pDIBitmap;

+    if(m_clipBox.IsEmpty()) {

+        return FXCODEC_STATUS_ERR_PARAMS;

+    }

+    if(size_x <= 0 || size_x > 65535 || size_y <= 0 || size_y > 65535) {

+        return FXCODEC_STATUS_ERR_PARAMS;

+    }

+    FX_RECT device_rc = FX_RECT(start_x, start_y, start_x + size_x, start_y + size_y);

+    FX_INT32 out_range_x = device_rc.right - pDIBitmap->GetWidth();

+    FX_INT32 out_range_y = device_rc.bottom - pDIBitmap->GetHeight();

+    device_rc.Intersect(FX_RECT(0, 0, pDIBitmap->GetWidth(), pDIBitmap->GetHeight()));

+    if(device_rc.IsEmpty()) {

+        return FXCODEC_STATUS_ERR_PARAMS;

+    }

+    m_startX = device_rc.left;

+    m_startY = device_rc.top;

+    m_sizeX  = device_rc.Width();

+    m_sizeY  = device_rc.Height();

+    m_bInterpol = bInterpol;

+    m_FrameCur = 0;

+    if(start_x < 0 || out_range_x > 0) {

+        FX_FLOAT scaleX = (FX_FLOAT)m_clipBox.Width() / (FX_FLOAT)size_x;

+        if(start_x < 0)	{

+            m_clipBox.left -= (FX_INT32)FXSYS_ceil((FX_FLOAT)start_x * scaleX);

+        }

+        if(out_range_x > 0)	{

+            m_clipBox.right -= (FX_INT32)FXSYS_floor((FX_FLOAT)out_range_x * scaleX);

+        }

+    }

+    if(start_y < 0 || out_range_y > 0) {

+        FX_FLOAT scaleY = (FX_FLOAT)m_clipBox.Height() / (FX_FLOAT)size_y;

+        if(start_y < 0) {

+            m_clipBox.top  -= (FX_INT32)FXSYS_ceil((FX_FLOAT)start_y * scaleY);

+        }

+        if(out_range_y > 0) {

+            m_clipBox.bottom  -= (FX_INT32)FXSYS_floor((FX_FLOAT)out_range_y * scaleY);

+        }

+    }

+    if(m_clipBox.IsEmpty()) {

+        return FXCODEC_STATUS_ERR_PARAMS;

+    }

+    switch(m_imagType) {

+        case FXCODEC_IMAGE_JPG: {

+                ICodec_JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule();

+                int down_scale = 1;

+                GetDownScale(down_scale);

+                FX_BOOL bStart = pJpegModule->StartScanline(m_pJpegContext, down_scale);

+                while(!bStart) {

+                    FXCODEC_STATUS error_status = FXCODEC_STATUS_ERROR;

+                    if(!JpegReadMoreData(pJpegModule, error_status)) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = error_status;

+                    }

+                    bStart = pJpegModule->StartScanline(m_pJpegContext, down_scale);

+                }

+                int scanline_size = ( m_SrcWidth + down_scale - 1) / down_scale;

+                scanline_size = (scanline_size * m_SrcComponents + 3) / 4 * 4;

+                if(m_pDecodeBuf != NULL) {

+                    FX_Free(m_pDecodeBuf);

+                    m_pDecodeBuf = NULL;

+                }

+                m_pDecodeBuf = FX_Alloc(FX_BYTE, scanline_size);

+                if(m_pDecodeBuf == NULL) {

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                }

+                FXSYS_memset32(m_pDecodeBuf, 0, scanline_size);

+                m_WeightHorz.Calc(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0, m_clipBox.Width(), m_bInterpol);

+                m_WeightVert.Calc(m_sizeY, m_clipBox.Height());

+                switch(m_SrcComponents) {

+                    case 1:

+                        m_SrcFormat = FXCodec_8bppGray;

+                        break;

+                    case 3:

+                        m_SrcFormat = FXCodec_Rgb;

+                        break;

+                    case 4:

+                        m_SrcFormat = FXCodec_Cmyk;

+                        break;

+                }

+                GetTransMethod(pDIBitmap->GetFormat(), m_SrcFormat);

+                return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+            }

+            break;

+        case FXCODEC_IMAGE_PNG: {

+                ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();

+                if(pPngModule == NULL) {

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                }

+                if(m_pPngContext != NULL) {

+                    pPngModule->Finish(m_pPngContext);

+                    m_pPngContext = NULL;

+                }

+                m_pPngContext = pPngModule->Start((void*)this);

+                if(m_pPngContext == NULL) {

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                }

+                m_offSet = 0;

+                switch(m_pDeviceBitmap->GetFormat()) {

+                    case FXDIB_8bppMask:

+                    case FXDIB_8bppRgb:

+                        m_SrcComponents = 1;

+                        m_SrcFormat = FXCodec_8bppGray;

+                        break;

+                    case FXDIB_Rgb:

+                        m_SrcComponents = 3;

+                        m_SrcFormat = FXCodec_Rgb;

+                        break;

+                    case FXDIB_Rgb32:

+                    case FXDIB_Argb:

+                        m_SrcComponents = 4;

+                        m_SrcFormat = FXCodec_Argb;

+                        break;

+                    default: {

+                            m_pDeviceBitmap = NULL;

+                            m_pFile = NULL;

+                            return m_status = FXCODEC_STATUS_ERR_PARAMS;

+                        }

+                }

+                GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat);

+                int scanline_size = (m_SrcWidth * m_SrcComponents + 3) / 4 * 4;

+                if(m_pDecodeBuf != NULL) {

+                    FX_Free(m_pDecodeBuf);

+                    m_pDecodeBuf = NULL;

+                }

+                m_pDecodeBuf = FX_Alloc(FX_BYTE, scanline_size);

+                if(m_pDecodeBuf == NULL) {

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                }

+                FXSYS_memset32(m_pDecodeBuf, 0, scanline_size);

+                m_WeightHorzOO.Calc(m_sizeX, m_clipBox.Width(), m_bInterpol);

+                m_WeightVert.Calc(m_sizeY, m_clipBox.Height());

+                return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+            }

+            break;

+        case FXCODEC_IMAGE_GIF: {

+                ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();

+                if(pGifModule == NULL) {

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                }

+                m_SrcFormat = FXCodec_8bppRgb;

+                GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat);

+                int scanline_size = (m_SrcWidth + 3) / 4 * 4;

+                if(m_pDecodeBuf != NULL) {

+                    FX_Free(m_pDecodeBuf);

+                    m_pDecodeBuf = NULL;

+                }

+                m_pDecodeBuf = FX_Alloc(FX_BYTE, scanline_size);

+                if(m_pDecodeBuf == NULL) {

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                }

+                FXSYS_memset32(m_pDecodeBuf, 0, scanline_size);

+                m_WeightHorz.Calc(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0, m_clipBox.Width(), m_bInterpol);

+                m_WeightVert.Calc(m_sizeY, m_clipBox.Height());

+                m_FrameCur = frames;

+                return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+            }

+            break;

+        case FXCODEC_IMAGE_BMP: {

+                ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();

+                if(pBmpModule == NULL) {

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                }

+                switch(m_SrcComponents) {

+                    case 1:

+                        m_SrcFormat = FXCodec_8bppRgb;

+                        break;

+                    case 3:

+                        m_SrcFormat = FXCodec_Rgb;

+                        break;

+                    case 4:

+                        m_SrcFormat = FXCodec_Rgb32;

+                        break;

+                }

+                GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat);

+                m_ScanlineSize = (m_SrcWidth * m_SrcComponents + 3) / 4 * 4;

+                if(m_pDecodeBuf != NULL) {

+                    FX_Free(m_pDecodeBuf);

+                    m_pDecodeBuf = NULL;

+                }

+                m_pDecodeBuf = FX_Alloc(FX_BYTE, m_ScanlineSize);

+                if(m_pDecodeBuf == NULL) {

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                }

+                FXSYS_memset32(m_pDecodeBuf, 0, m_ScanlineSize);

+                m_WeightHorz.Calc(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0, m_clipBox.Width(), m_bInterpol);

+                m_WeightVert.Calc(m_sizeY, m_clipBox.Height());

+                return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+            }

+            break;

+        case FXCODEC_IMAGE_TIF:

+            return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+        default:

+            break;

+    }

+    return FXCODEC_STATUS_ERROR;

+}

+FXCODEC_STATUS CCodec_ProgressiveDecoder::ContinueDecode(IFX_Pause* pPause)

+{

+    if(m_status != FXCODEC_STATUS_DECODE_TOBECONTINUE) {

+        return FXCODEC_STATUS_ERROR;

+    }

+    switch(m_imagType) {

+        case FXCODEC_IMAGE_JPG: {

+                ICodec_JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule();

+                while(TRUE) {

+                    FX_BOOL readRes = pJpegModule->ReadScanline(m_pJpegContext, m_pDecodeBuf);

+                    while(!readRes) {

+                        FXCODEC_STATUS error_status = FXCODEC_STATUS_DECODE_FINISH;

+                        if(!JpegReadMoreData(pJpegModule, error_status)) {

+                            m_pDeviceBitmap = NULL;

+                            m_pFile = NULL;

+                            return m_status = error_status;

+                        }

+                        readRes = pJpegModule->ReadScanline(m_pJpegContext, m_pDecodeBuf);

+                    }

+                    if(m_SrcFormat == FXCodec_Rgb) {

+                        int src_Bpp = (m_SrcFormat & 0xff) >> 3;

+                        _RGB2BGR(m_pDecodeBuf + m_clipBox.left * src_Bpp, m_clipBox.Width());

+                    }

+                    if(m_SrcRow >= m_clipBox.bottom) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_DECODE_FINISH;

+                    }

+                    Resample(m_pDeviceBitmap, m_SrcRow, m_pDecodeBuf, m_SrcFormat);

+                    m_SrcRow++;

+                    if(pPause && pPause->NeedToPauseNow()) {

+                        return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+                    }

+                }

+            }

+            break;

+        case FXCODEC_IMAGE_PNG: {

+                ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule();

+                while (TRUE) {

+                    FX_DWORD remain_size = (FX_DWORD)m_pFile->GetSize() - m_offSet;

+                    FX_DWORD input_size = remain_size > FXCODEC_BLOCK_SIZE ? FXCODEC_BLOCK_SIZE : remain_size;

+                    if(input_size == 0) {

+                        if(m_pPngContext != NULL) {

+                            pPngModule->Finish(m_pPngContext);

+                        }

+                        m_pPngContext = NULL;

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_DECODE_FINISH;

+                    }

+                    if(m_pSrcBuf != NULL && input_size > m_SrcSize) {

+                        FX_Free(m_pSrcBuf);

+                        m_pSrcBuf = FX_Alloc(FX_BYTE, input_size);

+                        if(m_pSrcBuf == NULL) {

+                            m_pDeviceBitmap = NULL;

+                            m_pFile = NULL;

+                            return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                        }

+                        FXSYS_memset32(m_pSrcBuf, 0, input_size);

+                        m_SrcSize = input_size;

+                    }

+                    FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, m_offSet, input_size);

+                    if(!bResult) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_ERR_READ;

+                    }

+                    m_offSet += input_size;

+                    bResult = pPngModule->Input(m_pPngContext, m_pSrcBuf, input_size);

+                    if(!bResult) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_ERROR;

+                    }

+                    if(pPause && pPause->NeedToPauseNow()) {

+                        return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+                    }

+                }

+            }

+            break;

+        case FXCODEC_IMAGE_GIF: {

+                ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule();

+                while(TRUE) {

+                    FX_INT32 readRes = pGifModule->LoadFrame(m_pGifContext, m_FrameCur);

+                    while(readRes == 2) {

+                        FXCODEC_STATUS error_status = FXCODEC_STATUS_DECODE_FINISH;

+                        if(!GifReadMoreData(pGifModule, error_status)) {

+                            m_pDeviceBitmap = NULL;

+                            m_pFile = NULL;

+                            return m_status = error_status;

+                        }

+                        if(pPause && pPause->NeedToPauseNow()) {

+                            return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+                        }

+                        readRes = pGifModule->LoadFrame(m_pGifContext, m_FrameCur);

+                    }

+                    if(readRes == 1) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_DECODE_FINISH;

+                    }

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERROR;

+                }

+            }

+            break;

+        case FXCODEC_IMAGE_BMP: {

+                ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule();

+                while(TRUE) {

+                    FX_INT32 readRes = pBmpModule->LoadImage(m_pBmpContext);

+                    while(readRes == 2) {

+                        FXCODEC_STATUS error_status = FXCODEC_STATUS_DECODE_FINISH;

+                        if(!BmpReadMoreData(pBmpModule, error_status)) {

+                            m_pDeviceBitmap = NULL;

+                            m_pFile = NULL;

+                            return m_status = error_status;

+                        }

+                        if(pPause && pPause->NeedToPauseNow()) {

+                            return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE;

+                        }

+                        readRes = pBmpModule->LoadImage(m_pBmpContext);

+                    }

+                    if(readRes == 1) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_DECODE_FINISH;

+                    }

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_ERROR;

+                }

+            }

+            break;

+        case FXCODEC_IMAGE_TIF: {

+                ICodec_TiffModule* pTiffModule = m_pCodecMgr->GetTiffModule();

+                FX_BOOL ret = FALSE;

+                if(m_pDeviceBitmap->GetBPP() == 32 &&

+                        m_pDeviceBitmap->GetWidth() == m_SrcWidth && m_SrcWidth == m_sizeX &&

+                        m_pDeviceBitmap->GetHeight() == m_SrcHeight && m_SrcHeight == m_sizeY &&

+                        m_startX == 0 && m_startY == 0 && m_clipBox.left == 0 && m_clipBox.top == 0

+                        && m_clipBox.right == m_SrcWidth && m_clipBox.bottom == m_SrcHeight) {

+                    ret = pTiffModule->Decode(m_pTiffContext, m_pDeviceBitmap);

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    if(!ret)	{

+                        return m_status = FXCODEC_STATUS_ERROR;

+                    }

+                    return m_status = FXCODEC_STATUS_DECODE_FINISH;

+                } else {

+                    CFX_DIBitmap* pDIBitmap = FX_NEW CFX_DIBitmap;

+                    if(pDIBitmap == NULL) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    }

+                    pDIBitmap->Create(m_SrcWidth, m_SrcHeight, FXDIB_Argb);

+                    if(pDIBitmap->GetBuffer() == NULL) {

+                        delete pDIBitmap;

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    }

+                    ret = pTiffModule->Decode(m_pTiffContext, pDIBitmap);

+                    if(!ret) {

+                        delete pDIBitmap;

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_ERROR;

+                    }

+                    CFX_DIBitmap* pClipBitmap =

+                        (m_clipBox.left  == 0 &&

+                         m_clipBox.top == 0 &&

+                         m_clipBox.right == m_SrcWidth &&

+                         m_clipBox.bottom == m_SrcHeight) ? pDIBitmap : pDIBitmap->Clone(&m_clipBox);

+                    if(pDIBitmap != pClipBitmap) {

+                        delete pDIBitmap;

+                    }

+                    if(pClipBitmap == NULL) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    }

+                    CFX_DIBitmap* pFormatBitmap = NULL;

+                    switch(m_pDeviceBitmap->GetFormat()) {

+                        case FXDIB_8bppRgb:

+                            pFormatBitmap = FX_NEW CFX_DIBitmap;

+                            if(pFormatBitmap == NULL) {

+                                m_pDeviceBitmap = NULL;

+                                m_pFile = NULL;

+                                return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                            }

+                            pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(), FXDIB_8bppRgb);

+                            break;

+                        case FXDIB_8bppMask:

+                            pFormatBitmap = FX_NEW CFX_DIBitmap;

+                            if(pFormatBitmap == NULL) {

+                                m_pDeviceBitmap = NULL;

+                                m_pFile = NULL;

+                                return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                            }

+                            pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(), FXDIB_8bppMask);

+                            break;

+                        case FXDIB_Rgb:

+                            pFormatBitmap = FX_NEW CFX_DIBitmap;

+                            if(pFormatBitmap == NULL) {

+                                m_pDeviceBitmap = NULL;

+                                m_pFile = NULL;

+                                return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                            }

+                            pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(), FXDIB_Rgb);

+                            break;

+                        case FXDIB_Rgb32:

+                            pFormatBitmap = FX_NEW CFX_DIBitmap;

+                            if(pFormatBitmap == NULL) {

+                                m_pDeviceBitmap = NULL;

+                                m_pFile = NULL;

+                                return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                            }

+                            pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(), FXDIB_Rgb32);

+                            break;

+                        case FXDIB_Argb:

+                            pFormatBitmap = pClipBitmap;

+                            break;

+                        default:

+                            ;

+                    }

+                    switch(m_pDeviceBitmap->GetFormat()) {

+                        case FXDIB_8bppRgb:

+                        case FXDIB_8bppMask: {

+                                for (FX_INT32 row = 0; row < pClipBitmap->GetHeight(); row++) {

+                                    FX_LPBYTE src_line = (FX_LPBYTE)pClipBitmap->GetScanline(row);

+                                    FX_LPBYTE des_line = (FX_LPBYTE)pFormatBitmap->GetScanline(row);

+                                    for (FX_INT32 col = 0; col < pClipBitmap->GetWidth(); col++) {

+                                        FX_BYTE _a = 255 - src_line[3];

+                                        FX_BYTE b = (src_line[0] * src_line[3] + 0xFF * _a) / 255;

+                                        FX_BYTE g = (src_line[1] * src_line[3] + 0xFF * _a) / 255;

+                                        FX_BYTE r = (src_line[2] * src_line[3] + 0xFF * _a) / 255;

+                                        *des_line++ = FXRGB2GRAY(r, g, b);

+                                        src_line += 4;

+                                    }

+                                }

+                            }

+                            break;

+                        case FXDIB_Rgb:

+                        case FXDIB_Rgb32: {

+                                FX_INT32 desBpp = (m_pDeviceBitmap->GetFormat() == FXDIB_Rgb) ? 3 : 4;

+                                for (FX_INT32 row = 0; row < pClipBitmap->GetHeight(); row++) {

+                                    FX_LPBYTE src_line = (FX_LPBYTE)pClipBitmap->GetScanline(row);

+                                    FX_LPBYTE des_line = (FX_LPBYTE)pFormatBitmap->GetScanline(row);

+                                    for (FX_INT32 col = 0; col < pClipBitmap->GetWidth(); col++) {

+                                        FX_BYTE _a = 255 - src_line[3];

+                                        FX_BYTE b = (src_line[0] * src_line[3] + 0xFF * _a) / 255;

+                                        FX_BYTE g = (src_line[1] * src_line[3] + 0xFF * _a) / 255;

+                                        FX_BYTE r = (src_line[2] * src_line[3] + 0xFF * _a) / 255;

+                                        *des_line++ = b;

+                                        *des_line++ = g;

+                                        *des_line++ = r;

+                                        des_line += desBpp - 3;

+                                        src_line += 4;

+                                    }

+                                }

+                            }

+                            break;

+                        default:

+                            ;

+                    }

+                    if(pClipBitmap != pFormatBitmap) {

+                        delete pClipBitmap;

+                    }

+                    if(pFormatBitmap == NULL) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    }

+                    CFX_DIBitmap* pStrechBitmap = pFormatBitmap->StretchTo(m_sizeX, m_sizeY, m_bInterpol ? FXDIB_INTERPOL : FXDIB_DOWNSAMPLE);

+                    delete pFormatBitmap;

+                    pFormatBitmap = NULL;

+                    if(pStrechBitmap == NULL) {

+                        m_pDeviceBitmap = NULL;

+                        m_pFile = NULL;

+                        return m_status = FXCODEC_STATUS_ERR_MEMORY;

+                    }

+                    m_pDeviceBitmap->TransferBitmap(m_startX, m_startY, m_sizeX, m_sizeY, pStrechBitmap, 0, 0);

+                    delete pStrechBitmap;

+                    pStrechBitmap = NULL;

+                    m_pDeviceBitmap = NULL;

+                    m_pFile = NULL;

+                    return m_status = FXCODEC_STATUS_DECODE_FINISH;

+                }

+            }

+            break;

+        default:

+            break;

+    }

+    return FXCODEC_STATUS_ERROR;

+}

+ICodec_ProgressiveDecoder* CCodec_ModuleMgr::CreateProgressiveDecoder()

+{

+    return FX_NEW CCodec_ProgressiveDecoder(this);

+}

diff --git a/core/src/fxcodec/codec/fx_codec_progress.h b/core/src/fxcodec/codec/fx_codec_progress.h
new file mode 100644
index 0000000..6a618e2
--- /dev/null
+++ b/core/src/fxcodec/codec/fx_codec_progress.h
@@ -0,0 +1,206 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#ifndef _FX_CODEC_PROGRESS_H_

+#define _FX_CODEC_PROGRESS_H_

+#define FXCODEC_BLOCK_SIZE 4096

+#define FXCODEC_PNG_GAMMA	2.2

+#if _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_

+#	undef FXCODEC_PNG_GAMMA

+#	define FXCODEC_PNG_GAMMA	1.7

+#endif

+struct PixelWeight {

+    int		m_SrcStart;

+    int		m_SrcEnd;

+    int		m_Weights[1];

+};

+class CFXCODEC_WeightTable : public CFX_Object

+{

+public:

+    CFXCODEC_WeightTable()

+    {

+        m_pWeightTables = NULL;

+    }

+    ~CFXCODEC_WeightTable()

+    {

+        if(m_pWeightTables != NULL) {

+            FX_Free(m_pWeightTables);

+        }

+    }

+

+    void			Calc(int dest_len, int dest_min, int dest_max, int src_len, int src_min, int src_max, FX_BOOL bInterpol);

+    PixelWeight*	GetPixelWeight(int pixel)

+    {

+        return (PixelWeight*)(m_pWeightTables + (pixel - m_DestMin) * m_ItemSize);

+    }

+

+    int				m_DestMin, m_ItemSize;

+    FX_LPBYTE		m_pWeightTables;

+};

+class CFXCODEC_HorzTable : public CFX_Object

+{

+public:

+    CFXCODEC_HorzTable()

+    {

+        m_pWeightTables = NULL;

+    }

+    ~CFXCODEC_HorzTable()

+    {

+        if(m_pWeightTables != NULL) {

+            FX_Free(m_pWeightTables);

+        }

+    }

+

+    void			Calc(int dest_len, int src_len, FX_BOOL bInterpol);

+    PixelWeight*	GetPixelWeight(int pixel)

+    {

+        return (PixelWeight*)(m_pWeightTables + pixel * m_ItemSize);

+    }

+

+    int				m_ItemSize;

+    FX_LPBYTE		m_pWeightTables;

+};

+class CFXCODEC_VertTable : public CFX_Object

+{

+public:

+    CFXCODEC_VertTable()

+    {

+        m_pWeightTables = NULL;

+    }

+    ~CFXCODEC_VertTable()

+    {

+        if(m_pWeightTables != NULL) {

+            FX_Free(m_pWeightTables);

+        }

+    }

+    void			Calc(int dest_len, int src_len);

+    PixelWeight*	GetPixelWeight(int pixel)

+    {

+        return (PixelWeight*)(m_pWeightTables + pixel * m_ItemSize);

+    }

+    int				m_ItemSize;

+    FX_LPBYTE		m_pWeightTables;

+};

+enum FXCodec_Format {

+    FXCodec_Invalid = 0,

+    FXCodec_1bppGray = 0x101,

+    FXCodec_1bppRgb = 0x001,

+    FXCodec_8bppGray = 0x108,

+    FXCodec_8bppRgb = 0x008,

+    FXCodec_Rgb = 0x018,

+    FXCodec_Rgb32 = 0x020,

+    FXCodec_Argb = 0x220,

+    FXCodec_Cmyk = 0x120

+};

+class CCodec_ProgressiveDecoder : public ICodec_ProgressiveDecoder

+{

+public:

+    CCodec_ProgressiveDecoder(CCodec_ModuleMgr* pCodecMgr);

+    virtual ~CCodec_ProgressiveDecoder();

+

+public:

+    virtual FXCODEC_STATUS		LoadImageInfo(IFX_FileRead* pFile, FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute* pAttribute);

+

+    virtual FXCODEC_IMAGE_TYPE	GetType()

+    {

+        return m_imagType;

+    }

+    virtual FX_INT32			GetWidth()

+    {

+        return m_SrcWidth;

+    }

+    virtual FX_INT32			GetHeight()

+    {

+        return m_SrcHeight;

+    }

+    virtual FX_INT32			GetNumComponents()

+    {

+        return m_SrcComponents;

+    }

+    virtual FX_INT32			GetBPC()

+    {

+        return m_SrcBPC;

+    }

+    virtual void				SetClipBox(FX_RECT* clip);

+    virtual FXCODEC_STATUS		GetFrames(FX_INT32& frames, IFX_Pause* pPause);

+

+    virtual FXCODEC_STATUS		StartDecode(CFX_DIBitmap* pDIBitmap,

+                                            int start_x, int start_y, int size_x, int size_y,

+                                            FX_INT32 frames, FX_BOOL bInterpol);

+

+    virtual FXCODEC_STATUS		ContinueDecode(IFX_Pause* pPause);

+

+protected:

+    FX_BOOL						DetectImageType(FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute* pAttribute = NULL);

+    void						GetDownScale(int& down_scale);

+    void						GetTransMethod(FXDIB_Format des_format, FXCodec_Format src_format);

+    void						ReSampleScanline(CFX_DIBitmap* pDeviceBitmap, FX_INT32 des_line, FX_LPBYTE src_scan, FXCodec_Format src_format);

+    void						Resample(CFX_DIBitmap* pDeviceBitmap, FX_INT32 src_line, FX_LPBYTE src_scan, FXCodec_Format src_format);

+    void						ResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row);

+    FX_BOOL						JpegReadMoreData(ICodec_JpegModule* pJpegModule, FXCODEC_STATUS& err_status);

+    static FX_BOOL				PngReadHeaderFunc(void* pModule, int width, int height, int bpc, int pass, int* color_type, double* gamma);

+    static FX_BOOL				PngAskScanlineBufFunc(void* pModule, int line, FX_LPBYTE& src_buf);

+    static void					PngFillScanlineBufCompletedFunc(void* pModule, int pass, int line);

+    void						PngOneOneMapResampleHorz(CFX_DIBitmap* pDeviceBitmap, FX_INT32 des_line, FX_LPBYTE src_scan, FXCodec_Format src_format);

+

+    FX_BOOL						GifReadMoreData(ICodec_GifModule* pGifModule, FXCODEC_STATUS& err_status);

+    static void					GifRecordCurrentPositionCallback(void* pModule, FX_DWORD& cur_pos);

+    static FX_LPBYTE			GifAskLocalPaletteBufCallback(void* pModule, FX_INT32 frame_num, FX_INT32 pal_size);

+    static FX_BOOL				GifInputRecordPositionBufCallback(void* pModule, FX_DWORD rcd_pos, const FX_RECT& img_rc,

+            FX_INT32 pal_num, void* pal_ptr,

+            FX_INT32 delay_time, FX_BOOL user_input,

+            FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace);

+    static void					GifReadScanlineCallback(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf);

+    void						GifDoubleLineResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row);

+    FX_BOOL						BmpReadMoreData(ICodec_BmpModule* pBmpModule, FXCODEC_STATUS& err_status);

+    static FX_BOOL				BmpInputImagePositionBufCallback(void* pModule, FX_DWORD rcd_pos);

+    static void					BmpReadScanlineCallback(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf);

+    void						ResampleVertBT(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row);

+public:

+    IFX_FileRead*				m_pFile;

+    CCodec_ModuleMgr*			m_pCodecMgr;

+    FX_LPVOID					m_pJpegContext;

+    FX_LPVOID					m_pPngContext;

+    FX_LPVOID					m_pGifContext;

+    FX_LPVOID					m_pBmpContext;

+    FX_LPVOID					m_pTiffContext;

+    FXCODEC_IMAGE_TYPE			m_imagType;

+    FX_DWORD					m_offSet;

+    FX_LPBYTE					m_pSrcBuf;

+    FX_DWORD					m_SrcSize;

+    FX_LPBYTE					m_pDecodeBuf;

+    int							m_ScanlineSize;

+    CFX_DIBitmap*				m_pDeviceBitmap;

+    FX_BOOL						m_bInterpol;

+    CFXCODEC_WeightTable		m_WeightHorz;

+    CFXCODEC_VertTable			m_WeightVert;

+    CFXCODEC_HorzTable			m_WeightHorzOO;

+    int			m_SrcWidth;

+    int			m_SrcHeight;

+    int			m_SrcComponents;

+    int			m_SrcBPC;

+    FX_RECT		m_clipBox;

+    int			m_startX;

+    int			m_startY;

+    int			m_sizeX;

+    int			m_sizeY;

+    int			m_TransMethod;

+    FX_ARGB*	m_pSrcPalette;

+    int			m_SrcPaletteNumber;

+    int			m_SrcRow;

+    FXCodec_Format m_SrcFormat;

+    int			m_SrcPassNumber;

+    int			m_FrameNumber;

+    int			m_FrameCur;

+    int				m_GifBgIndex;

+    FX_LPBYTE		m_pGifPalette;

+    FX_INT32		m_GifPltNumber;

+    int				m_GifTransIndex;

+    FX_RECT			m_GifFrameRect;

+    FX_BOOL			m_BmpIsTopBottom;

+    FXCODEC_STATUS m_status;

+};

+#endif

diff --git a/core/src/fxcodec/codec/fx_codec_tiff.cpp b/core/src/fxcodec/codec/fx_codec_tiff.cpp
new file mode 100644
index 0000000..c90de7a
--- /dev/null
+++ b/core/src/fxcodec/codec/fx_codec_tiff.cpp
@@ -0,0 +1,532 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../../../include/fxcodec/fx_codec.h"

+#include "../../../include/fxge/fx_dib.h"

+#include "codec_int.h"

+extern "C" {

+#include "../fx_tiff/include/fx_tiffiop.h"

+}

+#if !defined(_FPDFAPI_MINI_)

+void* IccLib_CreateTransform_sRGB(const unsigned char* pProfileData, unsigned int dwProfileSize, int nComponents, int intent, FX_DWORD dwSrcFormat = Icc_FORMAT_DEFAULT);

+void IccLib_TranslateImage(void* pTransform, unsigned char* pDest, const unsigned char* pSrc, int pixels);

+void IccLib_DestroyTransform(void* pTransform);

+#endif

+class CCodec_TiffContext : public CFX_Object

+{

+public:

+    CCodec_TiffContext();

+    ~CCodec_TiffContext();

+

+    FX_BOOL	InitDecoder(IFX_FileRead* file_ptr);

+    void	GetFrames(FX_INT32& frames);

+    FX_BOOL	LoadFrameInfo(FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute);

+    FX_BOOL	Decode(CFX_DIBitmap* pDIBitmap);

+

+    union {

+        IFX_FileRead*	in;

+        IFX_FileStream* out;

+    } io;

+

+    FX_DWORD		offset;

+

+    TIFF*			tif_ctx;

+    void*			icc_ctx;

+    FX_INT32		frame_num;

+    FX_INT32		frame_cur;

+    FX_BOOL			isDecoder;

+private:

+    FX_BOOL	isSupport(CFX_DIBitmap* pDIBitmap);

+    void	SetPalette(CFX_DIBitmap* pDIBitmap, FX_UINT16 bps);

+    FX_BOOL	Decode1bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp);

+    FX_BOOL	Decode8bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp);

+    FX_BOOL	Decode24bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp);

+};

+CCodec_TiffContext::CCodec_TiffContext()

+{

+    offset = 0;

+    frame_num = 0;

+    frame_cur = 0;

+    io.in = NULL;

+    tif_ctx = NULL;

+    icc_ctx = NULL;

+    isDecoder = TRUE;

+}

+CCodec_TiffContext::~CCodec_TiffContext()

+{

+#if !defined(_FPDFAPI_MINI_)

+    if(icc_ctx) {

+        IccLib_DestroyTransform(icc_ctx);

+        icc_ctx = NULL;

+    }

+#endif

+    if(tif_ctx)	{

+        TIFFClose(tif_ctx);

+    }

+}

+static tsize_t _tiff_read(thandle_t context, tdata_t buf, tsize_t length)

+{

+    CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context;

+    FX_BOOL ret = FALSE;

+    if(pTiffContext->isDecoder) {

+        ret = pTiffContext->io.in->ReadBlock(buf, pTiffContext->offset, length);

+    } else {

+        ret = pTiffContext->io.out->ReadBlock(buf, pTiffContext->offset, length);

+    }

+    if(!ret) {

+        return 0;

+    }

+    pTiffContext->offset += (FX_DWORD)length;

+    return length;

+}

+static tsize_t _tiff_write(thandle_t context, tdata_t buf, tsize_t length)

+{

+    CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context;

+    ASSERT(!pTiffContext->isDecoder);

+    if(!pTiffContext->io.out->WriteBlock(buf, pTiffContext->offset, length)) {

+        return 0;

+    }

+    pTiffContext->offset += (FX_DWORD)length;

+    return length;

+}

+static toff_t _tiff_seek(thandle_t context, toff_t offset, int whence)

+{

+    CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context;

+    switch(whence) {

+        case 0:

+            pTiffContext->offset = (FX_DWORD)offset;

+            break;

+        case 1:

+            pTiffContext->offset += (FX_DWORD)offset;

+            break;

+        case 2:

+            if(pTiffContext->isDecoder) {

+                if(pTiffContext->io.in->GetSize() < (FX_FILESIZE)offset) {

+                    return -1;

+                }

+                pTiffContext->offset = (FX_DWORD)(pTiffContext->io.in->GetSize() - offset);

+            } else {

+                if(pTiffContext->io.out->GetSize() < (FX_FILESIZE)offset) {

+                    return -1;

+                }

+                pTiffContext->offset = (FX_DWORD)(pTiffContext->io.out->GetSize() - offset);

+            }

+            break;

+        default:

+            return -1;

+    }

+    ASSERT(pTiffContext->isDecoder ?

+           (pTiffContext->offset <= (FX_DWORD)pTiffContext->io.in->GetSize()) :

+           TRUE);

+    return pTiffContext->offset;

+}

+static int _tiff_close(thandle_t context)

+{

+    return 0;

+}

+static toff_t _tiff_get_size(thandle_t context)

+{

+    CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context;

+    return pTiffContext->isDecoder ?

+           (toff_t)pTiffContext->io.in->GetSize() :

+           (toff_t)pTiffContext->io.out->GetSize();

+}

+static int _tiff_map(thandle_t context, tdata_t*, toff_t*)

+{

+    return 0;

+}

+static void _tiff_unmap(thandle_t context, tdata_t, toff_t) {}

+TIFF* _tiff_open(void* context, const char* mode)

+{

+    TIFF* tif = TIFFClientOpen("Tiff Image", mode,

+                               (thandle_t)context,

+                               _tiff_read, _tiff_write, _tiff_seek, _tiff_close,

+                               _tiff_get_size, _tiff_map, _tiff_unmap);

+    if(tif)	{

+        tif->tif_fd = (int)(FX_INTPTR)context;

+    }

+    return tif;

+}

+void* _TIFFmalloc(tmsize_t size)

+{

+    return FXMEM_DefaultAlloc(size, 0);

+}

+void _TIFFfree(void* ptr)

+{

+    FXMEM_DefaultFree(ptr, 0);

+}

+void* _TIFFrealloc(void* ptr, tmsize_t size)

+{

+    return FXMEM_DefaultRealloc(ptr, size, 0);

+}

+void _TIFFmemset(void* ptr, int val, tmsize_t size)

+{

+    FXSYS_memset8(ptr, val, (size_t)size);

+}

+void _TIFFmemcpy(void* des, const void* src, tmsize_t size)

+{

+    FXSYS_memcpy32(des, src, (size_t)size);

+}

+int _TIFFmemcmp(const void* ptr1, const void* ptr2, tmsize_t size)

+{

+    return FXSYS_memcmp32(ptr1, ptr2, (size_t)size);

+}

+static void _tiff_warning_ext(thandle_t context, const char* module, const char* fmt, va_list ap)

+{

+    if(module != NULL) {

+    }

+}

+TIFFErrorHandlerExt _TIFFwarningHandlerExt = _tiff_warning_ext;

+static void _tiff_error_ext(thandle_t context, const char* module, const char* fmt, va_list ap)

+{

+    if(module != NULL) {

+    }

+}

+TIFFErrorHandlerExt _TIFFerrorHandlerExt = _tiff_error_ext;

+int TIFFCmyk2Rgb(thandle_t context, uint8 c, uint8 m, uint8 y, uint8 k, uint8* r, uint8* g, uint8* b)

+{

+    if(context == NULL) {

+        return 0;

+    }

+    CCodec_TiffContext* p = (CCodec_TiffContext*)context;

+#if !defined(_FPDFAPI_MINI_)

+    if(p->icc_ctx) {

+        unsigned char cmyk[4], bgr[3];

+        cmyk[0] = c, cmyk[1] = m, cmyk[2] = y, cmyk[3] = k;

+        IccLib_TranslateImage(p->icc_ctx, bgr, cmyk, 1);

+        *r = bgr[2], *g = bgr[1], *b = bgr[0];

+    } else {

+#endif

+        AdobeCMYK_to_sRGB1(c, m, y, k, *r, *g, *b);

+#if !defined(_FPDFAPI_MINI_)

+    }

+#endif

+    return 1;

+}

+FX_BOOL CCodec_TiffContext::InitDecoder(IFX_FileRead* file_ptr)

+{

+    io.in = file_ptr;

+    tif_ctx = _tiff_open(this, "r");

+    if(tif_ctx == NULL) {

+        return FALSE;

+    }

+    return TRUE;

+}

+void CCodec_TiffContext::GetFrames(FX_INT32& frames)

+{

+    frames = frame_num = TIFFNumberOfDirectories(tif_ctx);

+}

+#define TIFF_EXIF_GETINFO(key, T, tag) {\

+        T val = (T)0;\

+        TIFFGetField(tif_ctx,tag,&val);\

+        if (val) {\

+            (key) = FX_Alloc(FX_BYTE,sizeof(T));\

+            if ((key)) {\

+                T* ptr = (T*)(key);\

+                *ptr = val;\

+                pExif->m_TagVal.SetAt(tag,(key));}}}\

+    (key) = NULL;

+#define TIFF_EXIF_GETSTRINGINFO(key, tag) {\

+        FX_DWORD size = 0;\

+        FX_LPBYTE buf = NULL;\

+        TIFFGetField(tif_ctx,tag,&size, &buf);\

+        if (size && buf) {\

+            (key) = FX_Alloc(FX_BYTE,size);\

+            if ((key)) {\

+                FXSYS_memcpy32((key),buf,size);\

+                pExif->m_TagVal.SetAt(tag,(key));}}}\

+    (key) = NULL;

+template <class T>

+static FX_BOOL Tiff_Exif_GetInfo(TIFF* tif_ctx, ttag_t tag, CFX_DIBAttributeExif* pExif)

+{

+    FX_LPBYTE key = NULL;

+    T val = (T)0;

+    TIFFGetField(tif_ctx, tag, &val);

+    if (val) {

+        (key) = FX_Alloc(FX_BYTE, sizeof(T));

+        if ((key) == NULL) {

+            return FALSE;

+        }

+        T* ptr = (T*)(key);

+        *ptr = val;

+        pExif->m_TagVal.SetAt(tag, (key));

+        return TRUE;

+    }

+    return FALSE;

+}

+static void Tiff_Exif_GetStringInfo(TIFF* tif_ctx, ttag_t tag, CFX_DIBAttributeExif* pExif)

+{

+    FX_LPSTR buf = NULL;

+    FX_LPBYTE key = NULL;

+    TIFFGetField(tif_ctx, tag, &buf);

+    if (buf) {

+        FX_INT32 size = (FX_INT32)FXSYS_strlen(buf);

+        (key) = FX_Alloc(FX_BYTE, size + 1);

+        if ((key) == NULL) {

+            return;

+        }

+        FXSYS_memcpy32((key), buf, size);

+        key[size] = 0;

+        pExif->m_TagVal.SetAt(tag, (key));

+    }

+}

+FX_BOOL CCodec_TiffContext::LoadFrameInfo(FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute)

+{

+    if (!TIFFSetDirectory(tif_ctx, (uint16)frame))	{

+        return FALSE;

+    }

+    FX_WORD tif_cs;

+    FX_DWORD tif_icc_size = 0;

+    FX_LPBYTE tif_icc_buf = NULL;

+    FX_WORD tif_bpc = 0;

+    FX_WORD tif_cps;

+    FX_DWORD tif_rps;

+    width = height = comps = 0;

+    TIFFGetField(tif_ctx, TIFFTAG_IMAGEWIDTH, &width);

+    TIFFGetField(tif_ctx, TIFFTAG_IMAGELENGTH, &height);

+    TIFFGetField(tif_ctx, TIFFTAG_SAMPLESPERPIXEL, &comps);

+    TIFFGetField(tif_ctx, TIFFTAG_BITSPERSAMPLE, &tif_bpc);

+    TIFFGetField(tif_ctx, TIFFTAG_PHOTOMETRIC, &tif_cs);

+    TIFFGetField(tif_ctx, TIFFTAG_COMPRESSION, &tif_cps);

+    TIFFGetField(tif_ctx, TIFFTAG_ROWSPERSTRIP, &tif_rps);

+    TIFFGetField(tif_ctx, TIFFTAG_ICCPROFILE, &tif_icc_size, &tif_icc_buf);

+    if (pAttribute) {

+        pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_INCH;

+        if (TIFFGetField(tif_ctx, TIFFTAG_RESOLUTIONUNIT, &pAttribute->m_wDPIUnit)) {

+            pAttribute->m_wDPIUnit -= 1;

+        }

+        CFX_DIBAttributeExif* pExif = (CFX_DIBAttributeExif*)pAttribute->m_pExif;

+        pExif->clear();

+        Tiff_Exif_GetInfo<FX_WORD>(tif_ctx, TIFFTAG_ORIENTATION, pExif);

+        if (Tiff_Exif_GetInfo<FX_FLOAT>(tif_ctx, TIFFTAG_XRESOLUTION, pExif)) {

+            FX_FLOAT fDpi = 0;

+            pExif->GetInfo(TIFFTAG_XRESOLUTION, &fDpi);

+            pAttribute->m_nXDPI = (FX_INT32)(fDpi + 0.5f);

+        }

+        if (Tiff_Exif_GetInfo<FX_FLOAT>(tif_ctx, TIFFTAG_YRESOLUTION, pExif)) {

+            FX_FLOAT fDpi = 0;

+            pExif->GetInfo(TIFFTAG_YRESOLUTION, &fDpi);

+            pAttribute->m_nYDPI = (FX_INT32)(fDpi + 0.5f);

+        }

+        Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_IMAGEDESCRIPTION, pExif);

+        Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_MAKE, pExif);

+        Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_MODEL, pExif);

+    }

+    bpc = tif_bpc;

+    if(tif_rps > height) {

+        TIFFSetField(tif_ctx, TIFFTAG_ROWSPERSTRIP, tif_rps = height);

+    }

+    return TRUE;

+}

+void _TiffBGRA2RGBA(FX_LPBYTE pBuf, FX_INT32 pixel, FX_INT32 spp)

+{

+    register FX_BYTE tmp;

+    for (FX_INT32 n = 0; n < pixel; n++) {

+        tmp = pBuf[0];

+        pBuf[0] = pBuf[2];

+        pBuf[2] = tmp;

+        pBuf += spp;

+    }

+}

+FX_BOOL CCodec_TiffContext::isSupport(CFX_DIBitmap* pDIBitmap)

+{

+    if (TIFFIsTiled(tif_ctx)) {

+        return FALSE;

+    }

+    FX_UINT16 photometric;

+    if (!TIFFGetField(tif_ctx, TIFFTAG_PHOTOMETRIC, &photometric)) {

+        return FALSE;

+    }

+    switch (pDIBitmap->GetBPP()) {

+        case 1:

+        case 8:

+            if (photometric != PHOTOMETRIC_PALETTE) {

+                return FALSE;

+            }

+            break;

+        case 24:

+            if (photometric != PHOTOMETRIC_RGB) {

+                return FALSE;

+            }

+            break;

+        default:

+            return FALSE;

+    }

+    FX_UINT16 planarconfig;

+    if (!TIFFGetFieldDefaulted(tif_ctx, TIFFTAG_PLANARCONFIG, &planarconfig)) {

+        return FALSE;

+    }

+    if (planarconfig == PLANARCONFIG_SEPARATE) {

+        return FALSE;

+    }

+    return TRUE;

+}

+void CCodec_TiffContext::SetPalette(CFX_DIBitmap* pDIBitmap, FX_UINT16 bps)

+{

+    FX_UINT16 *red_orig, *green_orig, *blue_orig;

+    TIFFGetField(tif_ctx, TIFFTAG_COLORMAP, &red_orig, &green_orig, &blue_orig);

+    for (FX_INT32 i = (1L << bps) - 1; i >= 0; i--) {

+#define	CVT(x)		((FX_UINT16)((x)>>8))

+        red_orig[i] = CVT(red_orig[i]);

+        green_orig[i] = CVT(green_orig[i]);

+        blue_orig[i] = CVT(blue_orig[i]);

+#undef	CVT

+    }

+    FX_INT32 len = 1 << bps;

+    for(FX_INT32 index = 0; index < len; index++) {

+        FX_DWORD r = red_orig[index] & 0xFF;

+        FX_DWORD g = green_orig[index] & 0xFF;

+        FX_DWORD b = blue_orig[index] & 0xFF;

+        FX_DWORD color = (FX_UINT32)b | ((FX_UINT32)g << 8) | ((FX_UINT32)r << 16) | (((uint32)0xffL) << 24);

+        pDIBitmap->SetPaletteEntry(index, color);

+    }

+}

+FX_BOOL CCodec_TiffContext::Decode1bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp)

+{

+    if (pDIBitmap->GetBPP() != 1 || spp != 1 || bps != 1 || !isSupport(pDIBitmap)) {

+        return FALSE;

+    }

+    SetPalette(pDIBitmap, bps);

+    FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx);

+    FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size);

+    if (buf == NULL) {

+        TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer");

+        return FALSE;

+    }

+    FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer();

+    FX_DWORD pitch = pDIBitmap->GetPitch();

+    for(FX_INT32 row = 0; row < height; row++) {

+        TIFFReadScanline(tif_ctx, buf, row, 0);

+        for(FX_INT32 j = 0; j < size; j++) {

+            bitMapbuffer[row * pitch + j] = buf[j];

+        }

+    }

+    _TIFFfree(buf);

+    return TRUE;

+}

+FX_BOOL CCodec_TiffContext::Decode8bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp)

+{

+    if (pDIBitmap->GetBPP() != 8 || spp != 1 || (bps != 4 && bps != 8) || !isSupport(pDIBitmap)) {

+        return FALSE;

+    }

+    SetPalette(pDIBitmap, bps);

+    FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx);

+    FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size);

+    if (buf == NULL) {

+        TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer");

+        return FALSE;

+    }

+    FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer();

+    FX_DWORD pitch = pDIBitmap->GetPitch();

+    for(FX_INT32 row = 0; row < height; row++) {

+        TIFFReadScanline(tif_ctx, buf, row, 0);

+        for(FX_INT32 j = 0; j < size; j++) {

+            switch(bps) {

+                case 4:

+                    bitMapbuffer[row * pitch + 2 * j + 0] = (buf[j] & 0xF0) >> 4;

+                    bitMapbuffer[row * pitch + 2 * j + 1] = (buf[j] & 0x0F) >> 0;

+                    break;

+                case 8:

+                    bitMapbuffer[row * pitch + j] = buf[j];

+                    break;

+            }

+        }

+    }

+    _TIFFfree(buf);

+    return TRUE;

+}

+FX_BOOL CCodec_TiffContext::Decode24bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp)

+{

+    if (pDIBitmap->GetBPP() != 24 || !isSupport(pDIBitmap)) {

+        return FALSE;

+    }

+    FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx);

+    FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size);

+    if (buf == NULL) {

+        TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer");

+        return FALSE;

+    }

+    FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer();

+    FX_DWORD pitch = pDIBitmap->GetPitch();

+    for(FX_INT32 row = 0; row < height; row++) {

+        TIFFReadScanline(tif_ctx, buf, row, 0);

+        for(FX_INT32 j = 0; j < size - 2; j += 3) {

+            bitMapbuffer[row * pitch + j + 0] = buf[j + 2];

+            bitMapbuffer[row * pitch + j + 1] = buf[j + 1];

+            bitMapbuffer[row * pitch + j + 2] = buf[j + 0];

+        }

+    }

+    _TIFFfree(buf);

+    return TRUE;

+}

+FX_BOOL CCodec_TiffContext::Decode(CFX_DIBitmap* pDIBitmap)

+{

+    FX_DWORD img_wid = pDIBitmap->GetWidth();

+    FX_DWORD img_hei = pDIBitmap->GetHeight();

+    FX_DWORD width = 0;

+    FX_DWORD height = 0;

+    TIFFGetField(tif_ctx, TIFFTAG_IMAGEWIDTH, &width);

+    TIFFGetField(tif_ctx, TIFFTAG_IMAGELENGTH, &height);

+    if (img_wid != width || img_hei != height) {

+        return FALSE;

+    }

+    if (pDIBitmap->GetBPP() == 32) {

+        FX_WORD rotation = ORIENTATION_TOPLEFT;

+        TIFFGetField(tif_ctx, TIFFTAG_ORIENTATION, &rotation);

+        if(TIFFReadRGBAImageOriented(tif_ctx, img_wid, img_hei,

+                                     (uint32*)pDIBitmap->GetBuffer(), rotation, 1)) {

+            for (FX_DWORD row = 0; row < img_hei; row++) {

+                FX_LPBYTE row_buf = (FX_LPBYTE)pDIBitmap->GetScanline(row);

+                _TiffBGRA2RGBA(row_buf, img_wid, 4);

+            }

+            return TRUE;

+        }

+    }

+    FX_UINT16 spp, bps;

+    TIFFGetField(tif_ctx, TIFFTAG_SAMPLESPERPIXEL, &spp);

+    TIFFGetField(tif_ctx, TIFFTAG_BITSPERSAMPLE, &bps);

+    FX_DWORD bpp = bps * spp;

+    if (bpp == 1) {

+        return Decode1bppRGB(pDIBitmap, height, width, bps, spp);

+    } else if (bpp <= 8) {

+        return Decode8bppRGB(pDIBitmap, height, width, bps, spp);

+    } else if (bpp <= 24) {

+        return Decode24bppRGB(pDIBitmap, height, width, bps, spp);

+    }

+    return FALSE;

+}

+FX_LPVOID CCodec_TiffModule::CreateDecoder(IFX_FileRead* file_ptr)

+{

+    CCodec_TiffContext* pDecoder = FX_NEW CCodec_TiffContext;

+    if (pDecoder == NULL) {

+        return NULL;

+    }

+    if (!pDecoder->InitDecoder(file_ptr)) {

+        delete pDecoder;

+        return NULL;

+    }

+    return pDecoder;

+}

+void CCodec_TiffModule::GetFrames(FX_LPVOID ctx, FX_INT32& frames)

+{

+    CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx;

+    pDecoder->GetFrames(frames);

+}

+FX_BOOL CCodec_TiffModule::LoadFrameInfo(FX_LPVOID ctx, FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute)

+{

+    CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx;

+    return pDecoder->LoadFrameInfo(frame, width, height, comps, bpc, pAttribute);

+}

+FX_BOOL CCodec_TiffModule::Decode(void* ctx, class CFX_DIBitmap* pDIBitmap)

+{

+    CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx;

+    return pDecoder->Decode(pDIBitmap);

+}

+void CCodec_TiffModule::DestroyDecoder(void* ctx)

+{

+    CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx;

+    delete pDecoder;

+}

diff --git a/core/src/fxcodec/fx_lpng/include/fx_png.h b/core/src/fxcodec/fx_lpng/include/fx_png.h
new file mode 100644
index 0000000..4ef53d0
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/include/fx_png.h
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/png.h"

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_png.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_png.c
new file mode 100644
index 0000000..5329a64
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_png.c
@@ -0,0 +1,4299 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* png.c - location for general purpose libpng functions

+ *

+ * Last changed in libpng 1.6.2 [April 25, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+

+#include "pngpriv.h"

+

+/* Generate a compiler error if there is an old png.h in the search path. */

+typedef png_libpng_version_1_6_3 Your_png_h_is_not_version_1_6_3;

+

+/* Tells libpng that we have already handled the first "num_bytes" bytes

+ * of the PNG file signature.  If the PNG data is embedded into another

+ * stream we can set num_bytes = 8 so that libpng will not attempt to read

+ * or write any of the magic bytes before it starts on the IHDR.

+ */

+

+#ifdef PNG_READ_SUPPORTED

+void PNGAPI

+png_set_sig_bytes(png_structrp png_ptr, int num_bytes)

+{

+   png_debug(1, "in png_set_sig_bytes");

+

+   if (png_ptr == NULL)

+      return;

+

+   if (num_bytes > 8)

+      png_error(png_ptr, "Too many bytes for PNG signature");

+

+   png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);

+}

+

+/* Checks whether the supplied bytes match the PNG signature.  We allow

+ * checking less than the full 8-byte signature so that those apps that

+ * already read the first few bytes of a file to determine the file type

+ * can simply check the remaining bytes for extra assurance.  Returns

+ * an integer less than, equal to, or greater than zero if sig is found,

+ * respectively, to be less than, to match, or be greater than the correct

+ * PNG signature (this is the same behavior as strcmp, memcmp, etc).

+ */

+int PNGAPI

+png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check)

+{

+   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};

+

+   if (num_to_check > 8)

+      num_to_check = 8;

+

+   else if (num_to_check < 1)

+      return (-1);

+

+   if (start > 7)

+      return (-1);

+

+   if (start + num_to_check > 8)

+      num_to_check = 8 - start;

+

+   return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check)));

+}

+

+#endif /* PNG_READ_SUPPORTED */

+

+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

+/* Function to allocate memory for zlib */

+PNG_FUNCTION(voidpf /* PRIVATE */,

+png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)

+{

+   png_alloc_size_t num_bytes = size;

+

+   if (png_ptr == NULL)

+      return NULL;

+

+   if (items >= (~(png_alloc_size_t)0)/size)

+   {

+      png_warning (png_voidcast(png_structrp, png_ptr),

+         "Potential overflow in png_zalloc()");

+      return NULL;

+   }

+

+   num_bytes *= items;

+   return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes);

+}

+

+/* Function to free memory for zlib */

+void /* PRIVATE */

+png_zfree(voidpf png_ptr, voidpf ptr)

+{

+   png_free(png_voidcast(png_const_structrp,png_ptr), ptr);

+}

+

+/* Reset the CRC variable to 32 bits of 1's.  Care must be taken

+ * in case CRC is > 32 bits to leave the top bits 0.

+ */

+void /* PRIVATE */

+png_reset_crc(png_structrp png_ptr)

+{

+   /* The cast is safe because the crc is a 32 bit value. */

+   png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0);

+}

+

+/* Calculate the CRC over a section of data.  We can only pass as

+ * much data to this routine as the largest single buffer size.  We

+ * also check that this data will actually be used before going to the

+ * trouble of calculating it.

+ */

+void /* PRIVATE */

+png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length)

+{

+   int need_crc = 1;

+

+   if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))

+   {

+      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==

+          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))

+         need_crc = 0;

+   }

+

+   else /* critical */

+   {

+      if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)

+         need_crc = 0;

+   }

+

+   /* 'uLong' is defined in zlib.h as unsigned long; this means that on some

+    * systems it is a 64 bit value.  crc32, however, returns 32 bits so the

+    * following cast is safe.  'uInt' may be no more than 16 bits, so it is

+    * necessary to perform a loop here.

+    */

+   if (need_crc && length > 0)

+   {

+      uLong crc = png_ptr->crc; /* Should never issue a warning */

+

+      do

+      {

+         uInt safe_length = (uInt)length;

+         if (safe_length == 0)

+            safe_length = (uInt)-1; /* evil, but safe */

+

+         crc = crc32(crc, ptr, safe_length);

+

+         /* The following should never issue compiler warnings; if they do the

+          * target system has characteristics that will probably violate other

+          * assumptions within the libpng code.

+          */

+         ptr += safe_length;

+         length -= safe_length;

+      }

+      while (length > 0);

+

+      /* And the following is always safe because the crc is only 32 bits. */

+      png_ptr->crc = (png_uint_32)crc;

+   }

+}

+

+/* Check a user supplied version number, called from both read and write

+ * functions that create a png_struct.

+ */

+int

+png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)

+{

+   if (user_png_ver)

+   {

+      int i = 0;

+

+      do

+      {

+         if (user_png_ver[i] != png_libpng_ver[i])

+            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;

+      } while (png_libpng_ver[i++]);

+   }

+

+   else

+      png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;

+

+   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)

+   {

+     /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so

+      * we must recompile any applications that use any older library version.

+      * For versions after libpng 1.0, we will be compatible, so we need

+      * only check the first and third digits (note that when we reach version

+      * 1.10 we will need to check the fourth symbol, namely user_png_ver[3]).

+      */

+      if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||

+          (user_png_ver[0] == '1' && (user_png_ver[2] != png_libpng_ver[2] ||

+          user_png_ver[3] != png_libpng_ver[3])) ||

+          (user_png_ver[0] == '0' && user_png_ver[2] < '9'))

+      {

+#ifdef PNG_WARNINGS_SUPPORTED

+         size_t pos = 0;

+         char m[128];

+

+         pos = png_safecat(m, (sizeof m), pos,

+             "Application built with libpng-");

+         pos = png_safecat(m, (sizeof m), pos, user_png_ver);

+         pos = png_safecat(m, (sizeof m), pos, " but running with ");

+         pos = png_safecat(m, (sizeof m), pos, png_libpng_ver);

+

+         png_warning(png_ptr, m);

+#endif

+

+#ifdef PNG_ERROR_NUMBERS_SUPPORTED

+         png_ptr->flags = 0;

+#endif

+

+         return 0;

+      }

+   }

+

+   /* Success return. */

+   return 1;

+}

+

+/* Generic function to create a png_struct for either read or write - this

+ * contains the common initialization.

+ */

+PNG_FUNCTION(png_structp /* PRIVATE */,

+png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,

+    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,

+    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)

+{

+   png_struct create_struct;

+#  ifdef PNG_SETJMP_SUPPORTED

+      jmp_buf create_jmp_buf;

+#  endif

+

+   /* This temporary stack-allocated structure is used to provide a place to

+    * build enough context to allow the user provided memory allocator (if any)

+    * to be called.

+    */

+   memset(&create_struct, 0, (sizeof create_struct));

+

+   /* Added at libpng-1.2.6 */

+#  ifdef PNG_USER_LIMITS_SUPPORTED

+      create_struct.user_width_max = PNG_USER_WIDTH_MAX;

+      create_struct.user_height_max = PNG_USER_HEIGHT_MAX;

+

+#     ifdef PNG_USER_CHUNK_CACHE_MAX

+         /* Added at libpng-1.2.43 and 1.4.0 */

+         create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;

+#     endif

+

+#     ifdef PNG_USER_CHUNK_MALLOC_MAX

+         /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists

+          * in png_struct regardless.

+          */

+         create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;

+#     endif

+#  endif

+

+   /* The following two API calls simply set fields in png_struct, so it is safe

+    * to do them now even though error handling is not yet set up.

+    */

+#  ifdef PNG_USER_MEM_SUPPORTED

+      png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn);

+#  endif

+

+   /* (*error_fn) can return control to the caller after the error_ptr is set,

+    * this will result in a memory leak unless the error_fn does something

+    * extremely sophisticated.  The design lacks merit but is implicit in the

+    * API.

+    */

+   png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn);

+

+#  ifdef PNG_SETJMP_SUPPORTED

+      if (!setjmp(create_jmp_buf))

+      {

+         /* Temporarily fake out the longjmp information until we have

+          * successfully completed this function.  This only works if we have

+          * setjmp() support compiled in, but it is safe - this stuff should

+          * never happen.

+          */

+         create_struct.jmp_buf_ptr = &create_jmp_buf;

+         create_struct.jmp_buf_size = 0; /*stack allocation*/

+         create_struct.longjmp_fn = longjmp;

+#  else

+      {

+#  endif

+         /* Call the general version checker (shared with read and write code):

+          */

+         if (png_user_version_check(&create_struct, user_png_ver))

+         {

+            png_structrp png_ptr = png_voidcast(png_structrp,

+               png_malloc_warn(&create_struct, (sizeof *png_ptr)));

+

+            if (png_ptr != NULL)

+            {

+               /* png_ptr->zstream holds a back-pointer to the png_struct, so

+                * this can only be done now:

+                */

+               create_struct.zstream.zalloc = png_zalloc;

+               create_struct.zstream.zfree = png_zfree;

+               create_struct.zstream.opaque = png_ptr;

+

+#              ifdef PNG_SETJMP_SUPPORTED

+                  /* Eliminate the local error handling: */

+                  create_struct.jmp_buf_ptr = NULL;

+                  create_struct.jmp_buf_size = 0;

+                  create_struct.longjmp_fn = 0;

+#              endif

+

+               *png_ptr = create_struct;

+

+               /* This is the successful return point */

+               return png_ptr;

+            }

+         }

+      }

+

+   /* A longjmp because of a bug in the application storage allocator or a

+    * simple failure to allocate the png_struct.

+    */

+   return NULL;

+}

+

+/* Allocate the memory for an info_struct for the application. */

+PNG_FUNCTION(png_infop,PNGAPI

+png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED)

+{

+   png_inforp info_ptr;

+

+   png_debug(1, "in png_create_info_struct");

+

+   if (png_ptr == NULL)

+      return NULL;

+

+   /* Use the internal API that does not (or at least should not) error out, so

+    * that this call always returns ok.  The application typically sets up the

+    * error handling *after* creating the info_struct because this is the way it

+    * has always been done in 'example.c'.

+    */

+   info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr,

+      (sizeof *info_ptr)));

+

+   if (info_ptr != NULL)

+      memset(info_ptr, 0, (sizeof *info_ptr));

+

+   return info_ptr;

+}

+

+/* This function frees the memory associated with a single info struct.

+ * Normally, one would use either png_destroy_read_struct() or

+ * png_destroy_write_struct() to free an info struct, but this may be

+ * useful for some applications.  From libpng 1.6.0 this function is also used

+ * internally to implement the png_info release part of the 'struct' destroy

+ * APIs.  This ensures that all possible approaches free the same data (all of

+ * it).

+ */

+void PNGAPI

+png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr)

+{

+   png_inforp info_ptr = NULL;

+

+   png_debug(1, "in png_destroy_info_struct");

+

+   if (png_ptr == NULL)

+      return;

+

+   if (info_ptr_ptr != NULL)

+      info_ptr = *info_ptr_ptr;

+

+   if (info_ptr != NULL)

+   {

+      /* Do this first in case of an error below; if the app implements its own

+       * memory management this can lead to png_free calling png_error, which

+       * will abort this routine and return control to the app error handler.

+       * An infinite loop may result if it then tries to free the same info

+       * ptr.

+       */

+      *info_ptr_ptr = NULL;

+

+      png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);

+      memset(info_ptr, 0, (sizeof *info_ptr));

+      png_free(png_ptr, info_ptr);

+   }

+}

+

+/* Initialize the info structure.  This is now an internal function (0.89)

+ * and applications using it are urged to use png_create_info_struct()

+ * instead.  Use deprecated in 1.6.0, internal use removed (used internally it

+ * is just a memset).

+ *

+ * NOTE: it is almost inconceivable that this API is used because it bypasses

+ * the user-memory mechanism and the user error handling/warning mechanisms in

+ * those cases where it does anything other than a memset.

+ */

+PNG_FUNCTION(void,PNGAPI

+png_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size),

+   PNG_DEPRECATED)

+{

+   png_inforp info_ptr = *ptr_ptr;

+

+   png_debug(1, "in png_info_init_3");

+

+   if (info_ptr == NULL)

+      return;

+

+   if ((sizeof (png_info)) > png_info_struct_size)

+   {

+      *ptr_ptr = NULL;

+      /* The following line is why this API should not be used: */

+      free(info_ptr);

+      info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL,

+         (sizeof *info_ptr)));

+      *ptr_ptr = info_ptr;

+   }

+

+   /* Set everything to 0 */

+   memset(info_ptr, 0, (sizeof *info_ptr));

+}

+

+/* The following API is not called internally */

+void PNGAPI

+png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr,

+   int freer, png_uint_32 mask)

+{

+   png_debug(1, "in png_data_freer");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   if (freer == PNG_DESTROY_WILL_FREE_DATA)

+      info_ptr->free_me |= mask;

+

+   else if (freer == PNG_USER_WILL_FREE_DATA)

+      info_ptr->free_me &= ~mask;

+

+   else

+      png_error(png_ptr, "Unknown freer parameter in png_data_freer");

+}

+

+void PNGAPI

+png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask,

+   int num)

+{

+   png_debug(1, "in png_free_data");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+#ifdef PNG_TEXT_SUPPORTED

+   /* Free text item num or (if num == -1) all text items */

+   if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)

+   {

+      if (num != -1)

+      {

+         if (info_ptr->text && info_ptr->text[num].key)

+         {

+            png_free(png_ptr, info_ptr->text[num].key);

+            info_ptr->text[num].key = NULL;

+         }

+      }

+

+      else

+      {

+         int i;

+         for (i = 0; i < info_ptr->num_text; i++)

+             png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);

+         png_free(png_ptr, info_ptr->text);

+         info_ptr->text = NULL;

+         info_ptr->num_text=0;

+      }

+   }

+#endif

+

+#ifdef PNG_tRNS_SUPPORTED

+   /* Free any tRNS entry */

+   if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)

+   {

+      png_free(png_ptr, info_ptr->trans_alpha);

+      info_ptr->trans_alpha = NULL;

+      info_ptr->valid &= ~PNG_INFO_tRNS;

+   }

+#endif

+

+#ifdef PNG_sCAL_SUPPORTED

+   /* Free any sCAL entry */

+   if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)

+   {

+      png_free(png_ptr, info_ptr->scal_s_width);

+      png_free(png_ptr, info_ptr->scal_s_height);

+      info_ptr->scal_s_width = NULL;

+      info_ptr->scal_s_height = NULL;

+      info_ptr->valid &= ~PNG_INFO_sCAL;

+   }

+#endif

+

+#ifdef PNG_pCAL_SUPPORTED

+   /* Free any pCAL entry */

+   if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)

+   {

+      png_free(png_ptr, info_ptr->pcal_purpose);

+      png_free(png_ptr, info_ptr->pcal_units);

+      info_ptr->pcal_purpose = NULL;

+      info_ptr->pcal_units = NULL;

+      if (info_ptr->pcal_params != NULL)

+         {

+            unsigned int i;

+            for (i = 0; i < info_ptr->pcal_nparams; i++)

+            {

+               png_free(png_ptr, info_ptr->pcal_params[i]);

+               info_ptr->pcal_params[i] = NULL;

+            }

+            png_free(png_ptr, info_ptr->pcal_params);

+            info_ptr->pcal_params = NULL;

+         }

+      info_ptr->valid &= ~PNG_INFO_pCAL;

+   }

+#endif

+

+#ifdef PNG_iCCP_SUPPORTED

+   /* Free any profile entry */

+   if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)

+   {

+      png_free(png_ptr, info_ptr->iccp_name);

+      png_free(png_ptr, info_ptr->iccp_profile);

+      info_ptr->iccp_name = NULL;

+      info_ptr->iccp_profile = NULL;

+      info_ptr->valid &= ~PNG_INFO_iCCP;

+   }

+#endif

+

+#ifdef PNG_sPLT_SUPPORTED

+   /* Free a given sPLT entry, or (if num == -1) all sPLT entries */

+   if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)

+   {

+      if (num != -1)

+      {

+         if (info_ptr->splt_palettes)

+         {

+            png_free(png_ptr, info_ptr->splt_palettes[num].name);

+            png_free(png_ptr, info_ptr->splt_palettes[num].entries);

+            info_ptr->splt_palettes[num].name = NULL;

+            info_ptr->splt_palettes[num].entries = NULL;

+         }

+      }

+

+      else

+      {

+         if (info_ptr->splt_palettes_num)

+         {

+            int i;

+            for (i = 0; i < info_ptr->splt_palettes_num; i++)

+               png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, (int)i);

+

+            png_free(png_ptr, info_ptr->splt_palettes);

+            info_ptr->splt_palettes = NULL;

+            info_ptr->splt_palettes_num = 0;

+         }

+         info_ptr->valid &= ~PNG_INFO_sPLT;

+      }

+   }

+#endif

+

+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED

+   if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)

+   {

+      if (num != -1)

+      {

+          if (info_ptr->unknown_chunks)

+          {

+             png_free(png_ptr, info_ptr->unknown_chunks[num].data);

+             info_ptr->unknown_chunks[num].data = NULL;

+          }

+      }

+

+      else

+      {

+         int i;

+

+         if (info_ptr->unknown_chunks_num)

+         {

+            for (i = 0; i < info_ptr->unknown_chunks_num; i++)

+               png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, (int)i);

+

+            png_free(png_ptr, info_ptr->unknown_chunks);

+            info_ptr->unknown_chunks = NULL;

+            info_ptr->unknown_chunks_num = 0;

+         }

+      }

+   }

+#endif

+

+#ifdef PNG_hIST_SUPPORTED

+   /* Free any hIST entry */

+   if ((mask & PNG_FREE_HIST)  & info_ptr->free_me)

+   {

+      png_free(png_ptr, info_ptr->hist);

+      info_ptr->hist = NULL;

+      info_ptr->valid &= ~PNG_INFO_hIST;

+   }

+#endif

+

+   /* Free any PLTE entry that was internally allocated */

+   if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)

+   {

+      png_free(png_ptr, info_ptr->palette);

+      info_ptr->palette = NULL;

+      info_ptr->valid &= ~PNG_INFO_PLTE;

+      info_ptr->num_palette = 0;

+   }

+

+#ifdef PNG_INFO_IMAGE_SUPPORTED

+   /* Free any image bits attached to the info structure */

+   if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)

+   {

+      if (info_ptr->row_pointers)

+      {

+         png_uint_32 row;

+         for (row = 0; row < info_ptr->height; row++)

+         {

+            png_free(png_ptr, info_ptr->row_pointers[row]);

+            info_ptr->row_pointers[row] = NULL;

+         }

+         png_free(png_ptr, info_ptr->row_pointers);

+         info_ptr->row_pointers = NULL;

+      }

+      info_ptr->valid &= ~PNG_INFO_IDAT;

+   }

+#endif

+

+   if (num != -1)

+      mask &= ~PNG_FREE_MUL;

+

+   info_ptr->free_me &= ~mask;

+}

+#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */

+

+/* This function returns a pointer to the io_ptr associated with the user

+ * functions.  The application should free any memory associated with this

+ * pointer before png_write_destroy() or png_read_destroy() are called.

+ */

+png_voidp PNGAPI

+png_get_io_ptr(png_const_structrp png_ptr)

+{

+   if (png_ptr == NULL)

+      return (NULL);

+

+   return (png_ptr->io_ptr);

+}

+

+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

+#  ifdef PNG_STDIO_SUPPORTED

+/* Initialize the default input/output functions for the PNG file.  If you

+ * use your own read or write routines, you can call either png_set_read_fn()

+ * or png_set_write_fn() instead of png_init_io().  If you have defined

+ * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a

+ * function of your own because "FILE *" isn't necessarily available.

+ */

+void PNGAPI

+png_init_io(png_structrp png_ptr, png_FILE_p fp)

+{

+   png_debug(1, "in png_init_io");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->io_ptr = (png_voidp)fp;

+}

+#  endif

+

+#ifdef PNG_SAVE_INT_32_SUPPORTED

+/* The png_save_int_32 function assumes integers are stored in two's

+ * complement format.  If this isn't the case, then this routine needs to

+ * be modified to write data in two's complement format.  Note that,

+ * the following works correctly even if png_int_32 has more than 32 bits

+ * (compare the more complex code required on read for sign extension.)

+ */

+void PNGAPI

+png_save_int_32(png_bytep buf, png_int_32 i)

+{

+   buf[0] = (png_byte)((i >> 24) & 0xff);

+   buf[1] = (png_byte)((i >> 16) & 0xff);

+   buf[2] = (png_byte)((i >> 8) & 0xff);

+   buf[3] = (png_byte)(i & 0xff);

+}

+#endif

+

+#  ifdef PNG_TIME_RFC1123_SUPPORTED

+/* Convert the supplied time into an RFC 1123 string suitable for use in

+ * a "Creation Time" or other text-based time string.

+ */

+int PNGAPI

+png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime)

+{

+   static PNG_CONST char short_months[12][4] =

+        {"Jan", "Feb", "Mar", "Apr", "May", "Jun",

+         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

+

+   if (out == NULL)

+      return 0;

+

+   if (ptime->year > 9999 /* RFC1123 limitation */ ||

+       ptime->month == 0    ||  ptime->month > 12  ||

+       ptime->day   == 0    ||  ptime->day   > 31  ||

+       ptime->hour  > 23    ||  ptime->minute > 59 ||

+       ptime->second > 60)

+      return 0;

+

+   {

+      size_t pos = 0;

+      char number_buf[5]; /* enough for a four-digit year */

+

+#     define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string))

+#     define APPEND_NUMBER(format, value)\

+         APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value)))

+#     define APPEND(ch) if (pos < 28) out[pos++] = (ch)

+

+      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day);

+      APPEND(' ');

+      APPEND_STRING(short_months[(ptime->month - 1)]);

+      APPEND(' ');

+      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year);

+      APPEND(' ');

+      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour);

+      APPEND(':');

+      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute);

+      APPEND(':');

+      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second);

+      APPEND_STRING(" +0000"); /* This reliably terminates the buffer */

+

+#     undef APPEND

+#     undef APPEND_NUMBER

+#     undef APPEND_STRING

+   }

+

+   return 1;

+}

+

+#     if PNG_LIBPNG_VER < 10700

+/* To do: remove the following from libpng-1.7 */

+/* Original API that uses a private buffer in png_struct.

+ * Deprecated because it causes png_struct to carry a spurious temporary

+ * buffer (png_struct::time_buffer), better to have the caller pass this in.

+ */

+png_const_charp PNGAPI

+png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime)

+{

+   if (png_ptr != NULL)

+   {

+      /* The only failure above if png_ptr != NULL is from an invalid ptime */

+      if (!png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime))

+         png_warning(png_ptr, "Ignoring invalid time value");

+

+      else

+         return png_ptr->time_buffer;

+   }

+

+   return NULL;

+}

+#     endif

+#  endif /* PNG_TIME_RFC1123_SUPPORTED */

+

+#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */

+

+png_const_charp PNGAPI

+png_get_copyright(png_const_structrp png_ptr)

+{

+   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */

+#ifdef PNG_STRING_COPYRIGHT

+   return PNG_STRING_COPYRIGHT

+#else

+#  ifdef __STDC__

+   return PNG_STRING_NEWLINE \

+     "libpng version 1.6.3 - July 18, 2013" PNG_STRING_NEWLINE \

+     "Copyright (c) 1998-2013 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \

+     "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \

+     "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \

+     PNG_STRING_NEWLINE;

+#  else

+      return "libpng version 1.6.3 - July 18, 2013\

+      Copyright (c) 1998-2013 Glenn Randers-Pehrson\

+      Copyright (c) 1996-1997 Andreas Dilger\

+      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";

+#  endif

+#endif

+}

+

+/* The following return the library version as a short string in the

+ * format 1.0.0 through 99.99.99zz.  To get the version of *.h files

+ * used with your application, print out PNG_LIBPNG_VER_STRING, which

+ * is defined in png.h.

+ * Note: now there is no difference between png_get_libpng_ver() and

+ * png_get_header_ver().  Due to the version_nn_nn_nn typedef guard,

+ * it is guaranteed that png.c uses the correct version of png.h.

+ */

+png_const_charp PNGAPI

+png_get_libpng_ver(png_const_structrp png_ptr)

+{

+   /* Version of *.c files used when building libpng */

+   return png_get_header_ver(png_ptr);

+}

+

+png_const_charp PNGAPI

+png_get_header_ver(png_const_structrp png_ptr)

+{

+   /* Version of *.h files used when building libpng */

+   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */

+   return PNG_LIBPNG_VER_STRING;

+}

+

+png_const_charp PNGAPI

+png_get_header_version(png_const_structrp png_ptr)

+{

+   /* Returns longer string containing both version and date */

+   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */

+#ifdef __STDC__

+   return PNG_HEADER_VERSION_STRING

+#  ifndef PNG_READ_SUPPORTED

+   "     (NO READ SUPPORT)"

+#  endif

+   PNG_STRING_NEWLINE;

+#else

+   return PNG_HEADER_VERSION_STRING;

+#endif

+}

+

+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+int PNGAPI

+png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name)

+{

+   /* Check chunk_name and return "keep" value if it's on the list, else 0 */

+   png_const_bytep p, p_end;

+

+   if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0)

+      return PNG_HANDLE_CHUNK_AS_DEFAULT;

+

+   p_end = png_ptr->chunk_list;

+   p = p_end + png_ptr->num_chunk_list*5; /* beyond end */

+

+   /* The code is the fifth byte after each four byte string.  Historically this

+    * code was always searched from the end of the list, this is no longer

+    * necessary because the 'set' routine handles duplicate entries correcty.

+    */

+   do /* num_chunk_list > 0, so at least one */

+   {

+      p -= 5;

+

+      if (!memcmp(chunk_name, p, 4))

+         return p[4];

+   }

+   while (p > p_end);

+

+   /* This means that known chunks should be processed and unknown chunks should

+    * be handled according to the value of png_ptr->unknown_default; this can be

+    * confusing because, as a result, there are two levels of defaulting for

+    * unknown chunks.

+    */

+   return PNG_HANDLE_CHUNK_AS_DEFAULT;

+}

+

+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED

+int /* PRIVATE */

+png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name)

+{

+   png_byte chunk_string[5];

+

+   PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name);

+   return png_handle_as_unknown(png_ptr, chunk_string);

+}

+#endif /* READ_UNKNOWN_CHUNKS */

+#endif /* SET_UNKNOWN_CHUNKS */

+

+#ifdef PNG_READ_SUPPORTED

+/* This function, added to libpng-1.0.6g, is untested. */

+int PNGAPI

+png_reset_zstream(png_structrp png_ptr)

+{

+   if (png_ptr == NULL)

+      return Z_STREAM_ERROR;

+

+   /* WARNING: this resets the window bits to the maximum! */

+   return (inflateReset(&png_ptr->zstream));

+}

+#endif /* PNG_READ_SUPPORTED */

+

+/* This function was added to libpng-1.0.7 */

+png_uint_32 PNGAPI

+png_access_version_number(void)

+{

+   /* Version of *.c files used when building libpng */

+   return((png_uint_32)PNG_LIBPNG_VER);

+}

+

+

+

+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

+/* Ensure that png_ptr->zstream.msg holds some appropriate error message string.

+ * If it doesn't 'ret' is used to set it to something appropriate, even in cases

+ * like Z_OK or Z_STREAM_END where the error code is apparently a success code.

+ */

+void /* PRIVATE */

+png_zstream_error(png_structrp png_ptr, int ret)

+{

+   /* Translate 'ret' into an appropriate error string, priority is given to the

+    * one in zstream if set.  This always returns a string, even in cases like

+    * Z_OK or Z_STREAM_END where the error code is a success code.

+    */

+   if (png_ptr->zstream.msg == NULL) switch (ret)

+   {

+      default:

+      case Z_OK:

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code");

+         break;

+

+      case Z_STREAM_END:

+         /* Normal exit */

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream");

+         break;

+

+      case Z_NEED_DICT:

+         /* This means the deflate stream did not have a dictionary; this

+          * indicates a bogus PNG.

+          */

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary");

+         break;

+

+      case Z_ERRNO:

+         /* gz APIs only: should not happen */

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error");

+         break;

+

+      case Z_STREAM_ERROR:

+         /* internal libpng error */

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib");

+         break;

+

+      case Z_DATA_ERROR:

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream");

+         break;

+

+      case Z_MEM_ERROR:

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory");

+         break;

+

+      case Z_BUF_ERROR:

+         /* End of input or output; not a problem if the caller is doing

+          * incremental read or write.

+          */

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated");

+         break;

+

+      case Z_VERSION_ERROR:

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version");

+         break;

+

+      case PNG_UNEXPECTED_ZLIB_RETURN:

+         /* Compile errors here mean that zlib now uses the value co-opted in

+          * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above

+          * and change pngpriv.h.  Note that this message is "... return",

+          * whereas the default/Z_OK one is "... return code".

+          */

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return");

+         break;

+   }

+}

+

+/* png_convert_size: a PNGAPI but no longer in png.h, so deleted

+ * at libpng 1.5.5!

+ */

+

+/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */

+#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */

+static int

+png_colorspace_check_gamma(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, png_fixed_point gAMA, int from)

+   /* This is called to check a new gamma value against an existing one.  The

+    * routine returns false if the new gamma value should not be written.

+    *

+    * 'from' says where the new gamma value comes from:

+    *

+    *    0: the new gamma value is the libpng estimate for an ICC profile

+    *    1: the new gamma value comes from a gAMA chunk

+    *    2: the new gamma value comes from an sRGB chunk

+    */

+{

+   png_fixed_point gtest;

+

+   if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&

+      (!png_muldiv(&gtest, colorspace->gamma, PNG_FP_1, gAMA) ||

+      png_gamma_significant(gtest)))

+   {

+      /* Either this is an sRGB image, in which case the calculated gamma

+       * approximation should match, or this is an image with a profile and the

+       * value libpng calculates for the gamma of the profile does not match the

+       * value recorded in the file.  The former, sRGB, case is an error, the

+       * latter is just a warning.

+       */

+      if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2)

+      {

+         png_chunk_report(png_ptr, "gamma value does not match sRGB",

+            PNG_CHUNK_ERROR);

+         /* Do not overwrite an sRGB value */

+         return from == 2;

+      }

+

+      else /* sRGB tag not involved */

+      {

+         png_chunk_report(png_ptr, "gamma value does not match libpng estimate",

+            PNG_CHUNK_WARNING);

+         return from == 1;

+      }

+   }

+

+   return 1;

+}

+

+void /* PRIVATE */

+png_colorspace_set_gamma(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, png_fixed_point gAMA)

+{

+   /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't

+    * occur.  Since the fixed point representation is assymetrical it is

+    * possible for 1/gamma to overflow the limit of 21474 and this means the

+    * gamma value must be at least 5/100000 and hence at most 20000.0.  For

+    * safety the limits here are a little narrower.  The values are 0.00016 to

+    * 6250.0, which are truly ridiculous gamma values (and will produce

+    * displays that are all black or all white.)

+    *

+    * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk

+    * handling code, which only required the value to be >0.

+    */

+   png_const_charp errmsg;

+

+   if (gAMA < 16 || gAMA > 625000000)

+      errmsg = "gamma value out of range";

+

+#  ifdef PNG_READ_gAMA_SUPPORTED

+      /* Allow the application to set the gamma value more than once */

+      else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&

+         (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)

+         errmsg = "duplicate";

+#  endif

+

+   /* Do nothing if the colorspace is already invalid */

+   else if (colorspace->flags & PNG_COLORSPACE_INVALID)

+      return;

+

+   else

+   {

+      if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, 1/*from gAMA*/))

+      {

+         /* Store this gamma value. */

+         colorspace->gamma = gAMA;

+         colorspace->flags |=

+            (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);

+      }

+

+      /* At present if the check_gamma test fails the gamma of the colorspace is

+       * not updated however the colorspace is not invalidated.  This

+       * corresponds to the case where the existing gamma comes from an sRGB

+       * chunk or profile.  An error message has already been output.

+       */

+      return;

+   }

+

+   /* Error exit - errmsg has been set. */

+   colorspace->flags |= PNG_COLORSPACE_INVALID;

+   png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);

+}

+

+void /* PRIVATE */

+png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr)

+{

+   if (info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)

+   {

+      /* Everything is invalid */

+      info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB|

+         PNG_INFO_iCCP);

+

+#     ifdef PNG_COLORSPACE_SUPPORTED

+         /* Clean up the iCCP profile now if it won't be used. */

+         png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/);

+#     else

+         PNG_UNUSED(png_ptr)

+#     endif

+   }

+

+   else

+   {

+#     ifdef PNG_COLORSPACE_SUPPORTED

+         /* Leave the INFO_iCCP flag set if the pngset.c code has already set

+          * it; this allows a PNG to contain a profile which matches sRGB and

+          * yet still have that profile retrievable by the application.

+          */

+         if (info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB)

+            info_ptr->valid |= PNG_INFO_sRGB;

+

+         else

+            info_ptr->valid &= ~PNG_INFO_sRGB;

+

+         if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)

+            info_ptr->valid |= PNG_INFO_cHRM;

+

+         else

+            info_ptr->valid &= ~PNG_INFO_cHRM;

+#     endif

+

+      if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA)

+         info_ptr->valid |= PNG_INFO_gAMA;

+

+      else

+         info_ptr->valid &= ~PNG_INFO_gAMA;

+   }

+}

+

+#ifdef PNG_READ_SUPPORTED

+void /* PRIVATE */

+png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)

+{

+   if (info_ptr == NULL) /* reduce code size; check here not in the caller */

+      return;

+

+   info_ptr->colorspace = png_ptr->colorspace;

+   png_colorspace_sync_info(png_ptr, info_ptr);

+}

+#endif

+#endif

+

+#ifdef PNG_COLORSPACE_SUPPORTED

+/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for

+ * cHRM, as opposed to using chromaticities.  These internal APIs return

+ * non-zero on a parameter error.  The X, Y and Z values are required to be

+ * positive and less than 1.0.

+ */

+static int

+png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)

+{

+   png_int_32 d, dwhite, whiteX, whiteY;

+

+   d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z;

+   if (!png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d)) return 1;

+   if (!png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d)) return 1;

+   dwhite = d;

+   whiteX = XYZ->red_X;

+   whiteY = XYZ->red_Y;

+

+   d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z;

+   if (!png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d)) return 1;

+   if (!png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d)) return 1;

+   dwhite += d;

+   whiteX += XYZ->green_X;

+   whiteY += XYZ->green_Y;

+

+   d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z;

+   if (!png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d)) return 1;

+   if (!png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d)) return 1;

+   dwhite += d;

+   whiteX += XYZ->blue_X;

+   whiteY += XYZ->blue_Y;

+

+   /* The reference white is simply the sum of the end-point (X,Y,Z) vectors,

+    * thus:

+    */

+   if (!png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite)) return 1;

+   if (!png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite)) return 1;

+

+   return 0;

+}

+

+static int

+png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)

+{

+   png_fixed_point red_inverse, green_inverse, blue_scale;

+   png_fixed_point left, right, denominator;

+

+   /* Check xy and, implicitly, z.  Note that wide gamut color spaces typically

+    * have end points with 0 tristimulus values (these are impossible end

+    * points, but they are used to cover the possible colors.)

+    */

+   if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1;

+   if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1;

+   if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1;

+   if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1;

+   if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1;

+   if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1;

+   if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1;

+   if (xy->whitey < 0 || xy->whitey > PNG_FP_1-xy->whitex) return 1;

+

+   /* The reverse calculation is more difficult because the original tristimulus

+    * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8

+    * derived values were recorded in the cHRM chunk;

+    * (red,green,blue,white)x(x,y).  This loses one degree of freedom and

+    * therefore an arbitrary ninth value has to be introduced to undo the

+    * original transformations.

+    *

+    * Think of the original end-points as points in (X,Y,Z) space.  The

+    * chromaticity values (c) have the property:

+    *

+    *           C

+    *   c = ---------

+    *       X + Y + Z

+    *

+    * For each c (x,y,z) from the corresponding original C (X,Y,Z).  Thus the

+    * three chromaticity values (x,y,z) for each end-point obey the

+    * relationship:

+    *

+    *   x + y + z = 1

+    *

+    * This describes the plane in (X,Y,Z) space that intersects each axis at the

+    * value 1.0; call this the chromaticity plane.  Thus the chromaticity

+    * calculation has scaled each end-point so that it is on the x+y+z=1 plane

+    * and chromaticity is the intersection of the vector from the origin to the

+    * (X,Y,Z) value with the chromaticity plane.

+    *

+    * To fully invert the chromaticity calculation we would need the three

+    * end-point scale factors, (red-scale, green-scale, blue-scale), but these

+    * were not recorded.  Instead we calculated the reference white (X,Y,Z) and

+    * recorded the chromaticity of this.  The reference white (X,Y,Z) would have

+    * given all three of the scale factors since:

+    *

+    *    color-C = color-c * color-scale

+    *    white-C = red-C + green-C + blue-C

+    *            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale

+    *

+    * But cHRM records only white-x and white-y, so we have lost the white scale

+    * factor:

+    *

+    *    white-C = white-c*white-scale

+    *

+    * To handle this the inverse transformation makes an arbitrary assumption

+    * about white-scale:

+    *

+    *    Assume: white-Y = 1.0

+    *    Hence:  white-scale = 1/white-y

+    *    Or:     red-Y + green-Y + blue-Y = 1.0

+    *

+    * Notice the last statement of the assumption gives an equation in three of

+    * the nine values we want to calculate.  8 more equations come from the

+    * above routine as summarised at the top above (the chromaticity

+    * calculation):

+    *

+    *    Given: color-x = color-X / (color-X + color-Y + color-Z)

+    *    Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0

+    *

+    * This is 9 simultaneous equations in the 9 variables "color-C" and can be

+    * solved by Cramer's rule.  Cramer's rule requires calculating 10 9x9 matrix

+    * determinants, however this is not as bad as it seems because only 28 of

+    * the total of 90 terms in the various matrices are non-zero.  Nevertheless

+    * Cramer's rule is notoriously numerically unstable because the determinant

+    * calculation involves the difference of large, but similar, numbers.  It is

+    * difficult to be sure that the calculation is stable for real world values

+    * and it is certain that it becomes unstable where the end points are close

+    * together.

+    *

+    * So this code uses the perhaps slightly less optimal but more

+    * understandable and totally obvious approach of calculating color-scale.

+    *

+    * This algorithm depends on the precision in white-scale and that is

+    * (1/white-y), so we can immediately see that as white-y approaches 0 the

+    * accuracy inherent in the cHRM chunk drops off substantially.

+    *

+    * libpng arithmetic: a simple invertion of the above equations

+    * ------------------------------------------------------------

+    *

+    *    white_scale = 1/white-y

+    *    white-X = white-x * white-scale

+    *    white-Y = 1.0

+    *    white-Z = (1 - white-x - white-y) * white_scale

+    *

+    *    white-C = red-C + green-C + blue-C

+    *            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale

+    *

+    * This gives us three equations in (red-scale,green-scale,blue-scale) where

+    * all the coefficients are now known:

+    *

+    *    red-x*red-scale + green-x*green-scale + blue-x*blue-scale

+    *       = white-x/white-y

+    *    red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1

+    *    red-z*red-scale + green-z*green-scale + blue-z*blue-scale

+    *       = (1 - white-x - white-y)/white-y

+    *

+    * In the last equation color-z is (1 - color-x - color-y) so we can add all

+    * three equations together to get an alternative third:

+    *

+    *    red-scale + green-scale + blue-scale = 1/white-y = white-scale

+    *

+    * So now we have a Cramer's rule solution where the determinants are just

+    * 3x3 - far more tractible.  Unfortunately 3x3 determinants still involve

+    * multiplication of three coefficients so we can't guarantee to avoid

+    * overflow in the libpng fixed point representation.  Using Cramer's rule in

+    * floating point is probably a good choice here, but it's not an option for

+    * fixed point.  Instead proceed to simplify the first two equations by

+    * eliminating what is likely to be the largest value, blue-scale:

+    *

+    *    blue-scale = white-scale - red-scale - green-scale

+    *

+    * Hence:

+    *

+    *    (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale =

+    *                (white-x - blue-x)*white-scale

+    *

+    *    (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale =

+    *                1 - blue-y*white-scale

+    *

+    * And now we can trivially solve for (red-scale,green-scale):

+    *

+    *    green-scale =

+    *                (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale

+    *                -----------------------------------------------------------

+    *                                  green-x - blue-x

+    *

+    *    red-scale =

+    *                1 - blue-y*white-scale - (green-y - blue-y) * green-scale

+    *                ---------------------------------------------------------

+    *                                  red-y - blue-y

+    *

+    * Hence:

+    *

+    *    red-scale =

+    *          ( (green-x - blue-x) * (white-y - blue-y) -

+    *            (green-y - blue-y) * (white-x - blue-x) ) / white-y

+    * -------------------------------------------------------------------------

+    *  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)

+    *

+    *    green-scale =

+    *          ( (red-y - blue-y) * (white-x - blue-x) -

+    *            (red-x - blue-x) * (white-y - blue-y) ) / white-y

+    * -------------------------------------------------------------------------

+    *  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)

+    *

+    * Accuracy:

+    * The input values have 5 decimal digits of accuracy.  The values are all in

+    * the range 0 < value < 1, so simple products are in the same range but may

+    * need up to 10 decimal digits to preserve the original precision and avoid

+    * underflow.  Because we are using a 32-bit signed representation we cannot

+    * match this; the best is a little over 9 decimal digits, less than 10.

+    *

+    * The approach used here is to preserve the maximum precision within the

+    * signed representation.  Because the red-scale calculation above uses the

+    * difference between two products of values that must be in the range -1..+1

+    * it is sufficient to divide the product by 7; ceil(100,000/32767*2).  The

+    * factor is irrelevant in the calculation because it is applied to both

+    * numerator and denominator.

+    *

+    * Note that the values of the differences of the products of the

+    * chromaticities in the above equations tend to be small, for example for

+    * the sRGB chromaticities they are:

+    *

+    * red numerator:    -0.04751

+    * green numerator:  -0.08788

+    * denominator:      -0.2241 (without white-y multiplication)

+    *

+    *  The resultant Y coefficients from the chromaticities of some widely used

+    *  color space definitions are (to 15 decimal places):

+    *

+    *  sRGB

+    *    0.212639005871510 0.715168678767756 0.072192315360734

+    *  Kodak ProPhoto

+    *    0.288071128229293 0.711843217810102 0.000085653960605

+    *  Adobe RGB

+    *    0.297344975250536 0.627363566255466 0.075291458493998

+    *  Adobe Wide Gamut RGB

+    *    0.258728243040113 0.724682314948566 0.016589442011321

+    */

+   /* By the argument, above overflow should be impossible here. The return

+    * value of 2 indicates an internal error to the caller.

+    */

+   if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7))

+      return 2;

+   if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7))

+      return 2;

+   denominator = left - right;

+

+   /* Now find the red numerator. */

+   if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7))

+      return 2;

+   if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7))

+      return 2;

+

+   /* Overflow is possible here and it indicates an extreme set of PNG cHRM

+    * chunk values.  This calculation actually returns the reciprocal of the

+    * scale value because this allows us to delay the multiplication of white-y

+    * into the denominator, which tends to produce a small number.

+    */

+   if (!png_muldiv(&red_inverse, xy->whitey, denominator, left-right) ||

+       red_inverse <= xy->whitey /* r+g+b scales = white scale */)

+      return 1;

+

+   /* Similarly for green_inverse: */

+   if (!png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7))

+      return 2;

+   if (!png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7))

+      return 2;

+   if (!png_muldiv(&green_inverse, xy->whitey, denominator, left-right) ||

+       green_inverse <= xy->whitey)

+      return 1;

+

+   /* And the blue scale, the checks above guarantee this can't overflow but it

+    * can still produce 0 for extreme cHRM values.

+    */

+   blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) -

+      png_reciprocal(green_inverse);

+   if (blue_scale <= 0) return 1;

+

+

+   /* And fill in the png_XYZ: */

+   if (!png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse)) return 1;

+   if (!png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse)) return 1;

+   if (!png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1,

+      red_inverse))

+      return 1;

+

+   if (!png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse))

+      return 1;

+   if (!png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse))

+      return 1;

+   if (!png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1,

+      green_inverse))

+      return 1;

+

+   if (!png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1)) return 1;

+   if (!png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1)) return 1;

+   if (!png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale,

+      PNG_FP_1))

+      return 1;

+

+   return 0; /*success*/

+}

+

+static int

+png_XYZ_normalize(png_XYZ *XYZ)

+{

+   png_int_32 Y;

+

+   if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 ||

+      XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 ||

+      XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0)

+      return 1;

+

+   /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1.

+    * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore

+    * relying on addition of two positive values producing a negative one is not

+    * safe.

+    */

+   Y = XYZ->red_Y;

+   if (0x7fffffff - Y < XYZ->green_X) return 1;

+   Y += XYZ->green_Y;

+   if (0x7fffffff - Y < XYZ->blue_X) return 1;

+   Y += XYZ->blue_Y;

+

+   if (Y != PNG_FP_1)

+   {

+      if (!png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y)) return 1;

+      if (!png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y)) return 1;

+      if (!png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y)) return 1;

+

+      if (!png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y)) return 1;

+      if (!png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y)) return 1;

+      if (!png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y)) return 1;

+

+      if (!png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y)) return 1;

+      if (!png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y)) return 1;

+      if (!png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y)) return 1;

+   }

+

+   return 0;

+}

+

+static int

+png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta)

+{

+   /* Allow an error of +/-0.01 (absolute value) on each chromaticity */

+   return !(PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) ||

+      PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) ||

+      PNG_OUT_OF_RANGE(xy1->redx,   xy2->redx,  delta) ||

+      PNG_OUT_OF_RANGE(xy1->redy,   xy2->redy,  delta) ||

+      PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) ||

+      PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) ||

+      PNG_OUT_OF_RANGE(xy1->bluex,  xy2->bluex, delta) ||

+      PNG_OUT_OF_RANGE(xy1->bluey,  xy2->bluey, delta));

+}

+

+/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM

+ * chunk chromaticities.  Earlier checks used to simply look for the overflow

+ * condition (where the determinant of the matrix to solve for XYZ ends up zero

+ * because the chromaticity values are not all distinct.)  Despite this it is

+ * theoretically possible to produce chromaticities that are apparently valid

+ * but that rapidly degrade to invalid, potentially crashing, sets because of

+ * arithmetic inaccuracies when calculations are performed on them.  The new

+ * check is to round-trip xy -> XYZ -> xy and then check that the result is

+ * within a small percentage of the original.

+ */

+static int

+png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy)

+{

+   int result;

+   png_xy xy_test;

+

+   /* As a side-effect this routine also returns the XYZ endpoints. */

+   result = png_XYZ_from_xy(XYZ, xy);

+   if (result) return result;

+

+   result = png_xy_from_XYZ(&xy_test, XYZ);

+   if (result) return result;

+

+   if (png_colorspace_endpoints_match(xy, &xy_test,

+      5/*actually, the math is pretty accurate*/))

+      return 0;

+

+   /* Too much slip */

+   return 1;

+}

+

+/* This is the check going the other way.  The XYZ is modified to normalize it

+ * (another side-effect) and the xy chromaticities are returned.

+ */

+static int

+png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ)

+{

+   int result;

+   png_XYZ XYZtemp;

+

+   result = png_XYZ_normalize(XYZ);

+   if (result) return result;

+

+   result = png_xy_from_XYZ(xy, XYZ);

+   if (result) return result;

+

+   XYZtemp = *XYZ;

+   return png_colorspace_check_xy(&XYZtemp, xy);

+}

+

+/* Used to check for an endpoint match against sRGB */

+static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */

+{

+   /* color      x       y */

+   /* red   */ 64000, 33000,

+   /* green */ 30000, 60000,

+   /* blue  */ 15000,  6000,

+   /* white */ 31270, 32900

+};

+

+static int

+png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ,

+   int preferred)

+{

+   if (colorspace->flags & PNG_COLORSPACE_INVALID)

+      return 0;

+

+   /* The consistency check is performed on the chromaticities; this factors out

+    * variations because of the normalization (or not) of the end point Y

+    * values.

+    */

+   if (preferred < 2 && (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS))

+   {

+      /* The end points must be reasonably close to any we already have.  The

+       * following allows an error of up to +/-.001

+       */

+      if (!png_colorspace_endpoints_match(xy, &colorspace->end_points_xy, 100))

+      {

+         colorspace->flags |= PNG_COLORSPACE_INVALID;

+         png_benign_error(png_ptr, "inconsistent chromaticities");

+         return 0; /* failed */

+      }

+

+      /* Only overwrite with preferred values */

+      if (!preferred)

+         return 1; /* ok, but no change */

+   }

+

+   colorspace->end_points_xy = *xy;

+   colorspace->end_points_XYZ = *XYZ;

+   colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS;

+

+   /* The end points are normally quoted to two decimal digits, so allow +/-0.01

+    * on this test.

+    */

+   if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000))

+      colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB;

+

+   else

+      colorspace->flags &= PNG_COLORSPACE_CANCEL(

+         PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);

+

+   return 2; /* ok and changed */

+}

+

+int /* PRIVATE */

+png_colorspace_set_chromaticities(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, const png_xy *xy, int preferred)

+{

+   /* We must check the end points to ensure they are reasonable - in the past

+    * color management systems have crashed as a result of getting bogus

+    * colorant values, while this isn't the fault of libpng it is the

+    * responsibility of libpng because PNG carries the bomb and libpng is in a

+    * position to protect against it.

+    */

+   png_XYZ XYZ;

+

+   switch (png_colorspace_check_xy(&XYZ, xy))

+   {

+      case 0: /* success */

+         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ,

+            preferred);

+

+      case 1:

+         /* We can't invert the chromaticities so we can't produce value XYZ

+          * values.  Likely as not a color management system will fail too.

+          */

+         colorspace->flags |= PNG_COLORSPACE_INVALID;

+         png_benign_error(png_ptr, "invalid chromaticities");

+         break;

+

+      default:

+         /* libpng is broken; this should be a warning but if it happens we

+          * want error reports so for the moment it is an error.

+          */

+         colorspace->flags |= PNG_COLORSPACE_INVALID;

+         png_error(png_ptr, "internal error checking chromaticities");

+         break;

+   }

+

+   return 0; /* failed */

+}

+

+int /* PRIVATE */

+png_colorspace_set_endpoints(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred)

+{

+   png_XYZ XYZ = *XYZ_in;

+   png_xy xy;

+

+   switch (png_colorspace_check_XYZ(&xy, &XYZ))

+   {

+      case 0:

+         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ,

+            preferred);

+

+      case 1:

+         /* End points are invalid. */

+         colorspace->flags |= PNG_COLORSPACE_INVALID;

+         png_benign_error(png_ptr, "invalid end points");

+         break;

+

+      default:

+         colorspace->flags |= PNG_COLORSPACE_INVALID;

+         png_error(png_ptr, "internal error checking chromaticities");

+         break;

+   }

+

+   return 0; /* failed */

+}

+

+#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED)

+/* Error message generation */

+static char

+png_icc_tag_char(png_uint_32 byte)

+{

+   byte &= 0xff;

+   if (byte >= 32 && byte <= 126)

+      return (char)byte;

+   else

+      return '?';

+}

+

+static void

+png_icc_tag_name(char *name, png_uint_32 tag)

+{

+   name[0] = '\'';

+   name[1] = png_icc_tag_char(tag >> 24);

+   name[2] = png_icc_tag_char(tag >> 16);

+   name[3] = png_icc_tag_char(tag >>  8);

+   name[4] = png_icc_tag_char(tag      );

+   name[5] = '\'';

+}

+

+static int

+is_ICC_signature_char(png_alloc_size_t it)

+{

+   return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) ||

+      (it >= 97 && it <= 122);

+}

+

+static int is_ICC_signature(png_alloc_size_t it)

+{

+   return is_ICC_signature_char(it >> 24) /* checks all the top bits */ &&

+      is_ICC_signature_char((it >> 16) & 0xff) &&

+      is_ICC_signature_char((it >> 8) & 0xff) &&

+      is_ICC_signature_char(it & 0xff);

+}

+

+static int

+png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,

+   png_const_charp name, png_alloc_size_t value, png_const_charp reason)

+{

+   size_t pos;

+   char message[196]; /* see below for calculation */

+

+   if (colorspace != NULL)

+      colorspace->flags |= PNG_COLORSPACE_INVALID;

+

+   pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */

+   pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */

+   pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */

+   if (is_ICC_signature(value))

+   {

+      /* So 'value' is at most 4 bytes and the following cast is safe */

+      png_icc_tag_name(message+pos, (png_uint_32)value);

+      pos += 6; /* total +8; less than the else clause */

+      message[pos++] = ':';

+      message[pos++] = ' ';

+   }

+#  ifdef PNG_WARNINGS_SUPPORTED

+   else

+      {

+         char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/

+

+         pos = png_safecat(message, (sizeof message), pos,

+            png_format_number(number, number+(sizeof number),

+               PNG_NUMBER_FORMAT_x, value));

+         pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/

+      }

+#  endif

+   /* The 'reason' is an arbitrary message, allow +79 maximum 195 */

+   pos = png_safecat(message, (sizeof message), pos, reason);

+

+   /* This is recoverable, but make it unconditionally an app_error on write to

+    * avoid writing invalid ICC profiles into PNG files.  (I.e.  we handle them

+    * on read, with a warning, but on write unless the app turns off

+    * application errors the PNG won't be written.)

+    */

+   png_chunk_report(png_ptr, message,

+      (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);

+

+   return 0;

+}

+#endif /* sRGB || iCCP */

+

+#ifdef PNG_sRGB_SUPPORTED

+int /* PRIVATE */

+png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,

+   int intent)

+{

+   /* sRGB sets known gamma, end points and (from the chunk) intent. */

+   /* IMPORTANT: these are not necessarily the values found in an ICC profile

+    * because ICC profiles store values adapted to a D50 environment; it is

+    * expected that the ICC profile mediaWhitePointTag will be D50, see the

+    * checks and code elsewhere to understand this better.

+    *

+    * These XYZ values, which are accurate to 5dp, produce rgb to gray

+    * coefficients of (6968,23435,2366), which are reduced (because they add up

+    * to 32769 not 32768) to (6968,23434,2366).  These are the values that

+    * libpng has traditionally used (and are the best values given the 15bit

+    * algorithm used by the rgb to gray code.)

+    */

+   static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */

+   {

+      /* color      X      Y      Z */

+      /* red   */ 41239, 21264,  1933,

+      /* green */ 35758, 71517, 11919,

+      /* blue  */ 18048,  7219, 95053

+   };

+

+   /* Do nothing if the colorspace is already invalidated. */

+   if (colorspace->flags & PNG_COLORSPACE_INVALID)

+      return 0;

+

+   /* Check the intent, then check for existing settings.  It is valid for the

+    * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must

+    * be consistent with the correct values.  If, however, this function is

+    * called below because an iCCP chunk matches sRGB then it is quite

+    * conceivable that an older app recorded incorrect gAMA and cHRM because of

+    * an incorrect calculation based on the values in the profile - this does

+    * *not* invalidate the profile (though it still produces an error, which can

+    * be ignored.)

+    */

+   if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST)

+      return png_icc_profile_error(png_ptr, colorspace, "sRGB",

+         (unsigned)intent, "invalid sRGB rendering intent");

+

+   if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 &&

+      colorspace->rendering_intent != intent)

+      return png_icc_profile_error(png_ptr, colorspace, "sRGB",

+         (unsigned)intent, "inconsistent rendering intents");

+

+   if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0)

+   {

+      png_benign_error(png_ptr, "duplicate sRGB information ignored");

+      return 0;

+   }

+

+   /* If the standard sRGB cHRM chunk does not match the one from the PNG file

+    * warn but overwrite the value with the correct one.

+    */

+   if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 &&

+      !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy,

+         100))

+      png_chunk_report(png_ptr, "cHRM chunk does not match sRGB",

+         PNG_CHUNK_ERROR);

+

+   /* This check is just done for the error reporting - the routine always

+    * returns true when the 'from' argument corresponds to sRGB (2).

+    */

+   (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE,

+      2/*from sRGB*/);

+

+   /* intent: bugs in GCC force 'int' to be used as the parameter type. */

+   colorspace->rendering_intent = (png_uint_16)intent;

+   colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT;

+

+   /* endpoints */

+   colorspace->end_points_xy = sRGB_xy;

+   colorspace->end_points_XYZ = sRGB_XYZ;

+   colorspace->flags |=

+      (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);

+

+   /* gamma */

+   colorspace->gamma = PNG_GAMMA_sRGB_INVERSE;

+   colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;

+

+   /* Finally record that we have an sRGB profile */

+   colorspace->flags |=

+      (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB);

+

+   return 1; /* set */

+}

+#endif /* sRGB */

+

+#ifdef PNG_iCCP_SUPPORTED

+/* Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value

+ * is XYZ(0.9642,1.0,0.8249), which scales to:

+ *

+ *    (63189.8112, 65536, 54060.6464)

+ */

+static const png_byte D50_nCIEXYZ[12] =

+   { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d };

+

+int /* PRIVATE */

+png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,

+   png_const_charp name, png_uint_32 profile_length)

+{

+   if (profile_length < 132)

+      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,

+         "too short");

+

+   if (profile_length & 3)

+      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,

+         "invalid length");

+

+   return 1;

+}

+

+int /* PRIVATE */

+png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,

+   png_const_charp name, png_uint_32 profile_length,

+   png_const_bytep profile/* first 132 bytes only */, int color_type)

+{

+   png_uint_32 temp;

+

+   /* Length check; this cannot be ignored in this code because profile_length

+    * is used later to check the tag table, so even if the profile seems over

+    * long profile_length from the caller must be correct.  The caller can fix

+    * this up on read or write by just passing in the profile header length.

+    */

+   temp = png_get_uint_32(profile);

+   if (temp != profile_length)

+      return png_icc_profile_error(png_ptr, colorspace, name, temp,

+         "length does not match profile");

+

+   temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */

+   if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */

+      profile_length < 132+12*temp) /* truncated tag table */

+      return png_icc_profile_error(png_ptr, colorspace, name, temp,

+         "tag count too large");

+

+   /* The 'intent' must be valid or we can't store it, ICC limits the intent to

+    * 16 bits.

+    */

+   temp = png_get_uint_32(profile+64);

+   if (temp >= 0xffff) /* The ICC limit */

+      return png_icc_profile_error(png_ptr, colorspace, name, temp,

+         "invalid rendering intent");

+

+   /* This is just a warning because the profile may be valid in future

+    * versions.

+    */

+   if (temp >= PNG_sRGB_INTENT_LAST)

+      (void)png_icc_profile_error(png_ptr, NULL, name, temp,

+         "intent outside defined range");

+

+   /* At this point the tag table can't be checked because it hasn't necessarily

+    * been loaded; however, various header fields can be checked.  These checks

+    * are for values permitted by the PNG spec in an ICC profile; the PNG spec

+    * restricts the profiles that can be passed in an iCCP chunk (they must be

+    * appropriate to processing PNG data!)

+    */

+

+   /* Data checks (could be skipped).  These checks must be independent of the

+    * version number; however, the version number doesn't accomodate changes in

+    * the header fields (just the known tags and the interpretation of the

+    * data.)

+    */

+   temp = png_get_uint_32(profile+36); /* signature 'ascp' */

+   if (temp != 0x61637370)

+      return png_icc_profile_error(png_ptr, colorspace, name, temp,

+         "invalid signature");

+

+   /* Currently the PCS illuminant/adopted white point (the computational

+    * white point) are required to be D50,

+    * however the profile contains a record of the illuminant so perhaps ICC

+    * expects to be able to change this in the future (despite the rationale in

+    * the introduction for using a fixed PCS adopted white.)  Consequently the

+    * following is just a warning.

+    */

+   if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0)

+      (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/,

+         "PCS illuminant is not D50");

+

+   /* The PNG spec requires this:

+    * "If the iCCP chunk is present, the image samples conform to the colour

+    * space represented by the embedded ICC profile as defined by the

+    * International Color Consortium [ICC]. The colour space of the ICC profile

+    * shall be an RGB colour space for colour images (PNG colour types 2, 3, and

+    * 6), or a greyscale colour space for greyscale images (PNG colour types 0

+    * and 4)."

+    *

+    * This checking code ensures the embedded profile (on either read or write)

+    * conforms to the specification requirements.  Notice that an ICC 'gray'

+    * color-space profile contains the information to transform the monochrome

+    * data to XYZ or L*a*b (according to which PCS the profile uses) and this

+    * should be used in preference to the standard libpng K channel replication

+    * into R, G and B channels.

+    *

+    * Previously it was suggested that an RGB profile on grayscale data could be

+    * handled.  However it it is clear that using an RGB profile in this context

+    * must be an error - there is no specification of what it means.  Thus it is

+    * almost certainly more correct to ignore the profile.

+    */

+   temp = png_get_uint_32(profile+16); /* data colour space field */

+   switch (temp)

+   {

+      case 0x52474220: /* 'RGB ' */

+         if (!(color_type & PNG_COLOR_MASK_COLOR))

+            return png_icc_profile_error(png_ptr, colorspace, name, temp,

+               "RGB color space not permitted on grayscale PNG");

+         break;

+

+      case 0x47524159: /* 'GRAY' */

+         if (color_type & PNG_COLOR_MASK_COLOR)

+            return png_icc_profile_error(png_ptr, colorspace, name, temp,

+               "Gray color space not permitted on RGB PNG");

+         break;

+

+      default:

+         return png_icc_profile_error(png_ptr, colorspace, name, temp,

+            "invalid ICC profile color space");

+   }

+

+   /* It is up to the application to check that the profile class matches the

+    * application requirements; the spec provides no guidance, but it's pretty

+    * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer

+    * ('prtr') or 'spac' (for generic color spaces).  Issue a warning in these

+    * cases.  Issue an error for device link or abstract profiles - these don't

+    * contain the records necessary to transform the color-space to anything

+    * other than the target device (and not even that for an abstract profile).

+    * Profiles of these classes may not be embedded in images.

+    */

+   temp = png_get_uint_32(profile+12); /* profile/device class */

+   switch (temp)

+   {

+      case 0x73636E72: /* 'scnr' */

+      case 0x6D6E7472: /* 'mntr' */

+      case 0x70727472: /* 'prtr' */

+      case 0x73706163: /* 'spac' */

+         /* All supported */

+         break;

+

+      case 0x61627374: /* 'abst' */

+         /* May not be embedded in an image */

+         return png_icc_profile_error(png_ptr, colorspace, name, temp,

+            "invalid embedded Abstract ICC profile");

+

+      case 0x6C696E6B: /* 'link' */

+         /* DeviceLink profiles cannnot be interpreted in a non-device specific

+          * fashion, if an app uses the AToB0Tag in the profile the results are

+          * undefined unless the result is sent to the intended device,

+          * therefore a DeviceLink profile should not be found embedded in a

+          * PNG.

+          */

+         return png_icc_profile_error(png_ptr, colorspace, name, temp,

+            "unexpected DeviceLink ICC profile class");

+

+      case 0x6E6D636C: /* 'nmcl' */

+         /* A NamedColor profile is also device specific, however it doesn't

+          * contain an AToB0 tag that is open to misintrepretation.  Almost

+          * certainly it will fail the tests below.

+          */

+         (void)png_icc_profile_error(png_ptr, NULL, name, temp,

+            "unexpected NamedColor ICC profile class");

+         break;

+

+      default:

+         /* To allow for future enhancements to the profile accept unrecognized

+          * profile classes with a warning, these then hit the test below on the

+          * tag content to ensure they are backward compatible with one of the

+          * understood profiles.

+          */

+         (void)png_icc_profile_error(png_ptr, NULL, name, temp,

+            "unrecognized ICC profile class");

+         break;

+   }

+

+   /* For any profile other than a device link one the PCS must be encoded

+    * either in XYZ or Lab.

+    */

+   temp = png_get_uint_32(profile+20);

+   switch (temp)

+   {

+      case 0x58595A20: /* 'XYZ ' */

+      case 0x4C616220: /* 'Lab ' */

+         break;

+

+      default:

+         return png_icc_profile_error(png_ptr, colorspace, name, temp,

+            "unexpected ICC PCS encoding");

+   }

+

+   return 1;

+}

+

+int /* PRIVATE */

+png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,

+   png_const_charp name, png_uint_32 profile_length,

+   png_const_bytep profile /* header plus whole tag table */)

+{

+   png_uint_32 tag_count = png_get_uint_32(profile+128);

+   png_uint_32 itag;

+   png_const_bytep tag = profile+132; /* The first tag */

+

+   /* First scan all the tags in the table and add bits to the icc_info value

+    * (temporarily in 'tags').

+    */

+   for (itag=0; itag < tag_count; ++itag, tag += 12)

+   {

+      png_uint_32 tag_id = png_get_uint_32(tag+0);

+      png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */

+      png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */

+

+      /* The ICC specification does not exclude zero length tags, therefore the

+       * start might actually be anywhere if there is no data, but this would be

+       * a clear abuse of the intent of the standard so the start is checked for

+       * being in range.  All defined tag types have an 8 byte header - a 4 byte

+       * type signature then 0.

+       */

+      if ((tag_start & 3) != 0)

+      {

+         /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is

+          * only a warning here because libpng does not care about the

+          * alignment.

+          */

+         (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,

+            "ICC profile tag start not a multiple of 4");

+      }

+

+      /* This is a hard error; potentially it can cause read outside the

+       * profile.

+       */

+      if (tag_start > profile_length || tag_length > profile_length - tag_start)

+         return png_icc_profile_error(png_ptr, colorspace, name, tag_id,

+            "ICC profile tag outside profile");

+   }

+

+   return 1; /* success, maybe with warnings */

+}

+

+#ifdef PNG_sRGB_SUPPORTED

+/* Information about the known ICC sRGB profiles */

+static const struct

+{

+   png_uint_32 adler, crc, length;

+   png_uint_32 md5[4];

+   png_byte    have_md5;

+   png_byte    is_broken;

+   png_uint_16 intent;

+

+#  define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0)

+#  define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\

+      { adler, crc, length, md5, broke, intent },

+

+} png_sRGB_checks[] =

+{

+   /* This data comes from contrib/tools/checksum-icc run on downloads of

+    * all four ICC sRGB profiles from www.color.org.

+    */

+   /* adler32, crc32, MD5[4], intent, date, length, file-name */

+   PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9,

+      PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0,

+      "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc")

+

+   /* ICC sRGB v2 perceptual no black-compensation: */

+   PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21,

+      PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0,

+      "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc")

+

+   PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae,

+      PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0,

+      "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc")

+

+   /* ICC sRGB v4 perceptual */

+   PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812,

+      PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0,

+      "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc")

+

+   /* The following profiles have no known MD5 checksum. If there is a match

+    * on the (empty) MD5 the other fields are used to attempt a match and

+    * a warning is produced.  The first two of these profiles have a 'cprt' tag

+    * which suggests that they were also made by Hewlett Packard.

+    */

+   PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce,

+      PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0,

+      "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc")

+

+   /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not

+    * match the D50 PCS illuminant in the header (it is in fact the D65 values,

+    * so the white point is recorded as the un-adapted value.)  The profiles

+    * below only differ in one byte - the intent - and are basically the same as

+    * the previous profile except for the mediaWhitePointTag error and a missing

+    * chromaticAdaptationTag.

+    */

+   PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552,

+      PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/,

+      "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual")

+

+   PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d,

+      PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/,

+      "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative")

+};

+

+static int

+png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,

+   png_const_bytep profile, uLong adler)

+{

+   /* The quick check is to verify just the MD5 signature and trust the

+    * rest of the data.  Because the profile has already been verified for

+    * correctness this is safe.  png_colorspace_set_sRGB will check the 'intent'

+    * field too, so if the profile has been edited with an intent not defined

+    * by sRGB (but maybe defined by a later ICC specification) the read of

+    * the profile will fail at that point.

+    */

+   png_uint_32 length = 0;

+   png_uint_32 intent = 0x10000; /* invalid */

+#if PNG_sRGB_PROFILE_CHECKS > 1

+   uLong crc = 0; /* the value for 0 length data */

+#endif

+   unsigned int i;

+

+   for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i)

+   {

+      if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&

+         png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&

+         png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&

+         png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])

+      {

+         /* This may be one of the old HP profiles without an MD5, in that

+          * case we can only use the length and Adler32 (note that these

+          * are not used by default if there is an MD5!)

+          */

+#        if PNG_sRGB_PROFILE_CHECKS == 0

+            if (png_sRGB_checks[i].have_md5)

+               return 1+png_sRGB_checks[i].is_broken;

+#        endif

+

+         /* Profile is unsigned or more checks have been configured in. */

+         if (length == 0)

+         {

+            length = png_get_uint_32(profile);

+            intent = png_get_uint_32(profile+64);

+         }

+

+         /* Length *and* intent must match */

+         if (length == png_sRGB_checks[i].length &&

+            intent == png_sRGB_checks[i].intent)

+         {

+            /* Now calculate the adler32 if not done already. */

+            if (adler == 0)

+            {

+               adler = adler32(0, NULL, 0);

+               adler = adler32(adler, profile, length);

+            }

+

+            if (adler == png_sRGB_checks[i].adler)

+            {

+               /* These basic checks suggest that the data has not been

+                * modified, but if the check level is more than 1 perform

+                * our own crc32 checksum on the data.

+                */

+#              if PNG_sRGB_PROFILE_CHECKS > 1

+                  if (crc == 0)

+                  {

+                     crc = crc32(0, NULL, 0);

+                     crc = crc32(crc, profile, length);

+                  }

+

+                  /* So this check must pass for the 'return' below to happen.

+                   */

+                  if (crc == png_sRGB_checks[i].crc)

+#              endif

+               {

+                  if (png_sRGB_checks[i].is_broken)

+                  {

+                     /* These profiles are known to have bad data that may cause

+                      * problems if they are used, therefore attempt to

+                      * discourage their use, skip the 'have_md5' warning below,

+                      * which is made irrelevant by this error.

+                      */

+                     png_chunk_report(png_ptr, "known incorrect sRGB profile",

+                        PNG_CHUNK_ERROR);

+                  }

+

+                  /* Warn that this being done; this isn't even an error since

+                   * the profile is perfectly valid, but it would be nice if

+                   * people used the up-to-date ones.

+                   */

+                  else if (!png_sRGB_checks[i].have_md5)

+                  {

+                     png_chunk_report(png_ptr,

+                        "out-of-date sRGB profile with no signature",

+                        PNG_CHUNK_WARNING);

+                  }

+

+                  return 1+png_sRGB_checks[i].is_broken;

+               }

+            }

+         }

+

+#        if PNG_sRGB_PROFILE_CHECKS > 0

+            /* The signature matched, but the profile had been changed in some

+             * way.  This is an apparent violation of the ICC terms of use and,

+             * anyway, probably indicates a data error or uninformed hacking.

+             */

+            if (png_sRGB_checks[i].have_md5)

+               png_benign_error(png_ptr,

+                  "copyright violation: edited ICC profile ignored");

+#        endif

+      }

+   }

+

+   return 0; /* no match */

+}

+#endif

+

+#ifdef PNG_sRGB_SUPPORTED

+void /* PRIVATE */

+png_icc_set_sRGB(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, png_const_bytep profile, uLong adler)

+{

+   /* Is this profile one of the known ICC sRGB profiles?  If it is, just set

+    * the sRGB information.

+    */

+   if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler))

+      (void)png_colorspace_set_sRGB(png_ptr, colorspace,

+         (int)/*already checked*/png_get_uint_32(profile+64));

+}

+#endif /* PNG_READ_sRGB_SUPPORTED */

+

+int /* PRIVATE */

+png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace,

+   png_const_charp name, png_uint_32 profile_length, png_const_bytep profile,

+   int color_type)

+{

+   if (colorspace->flags & PNG_COLORSPACE_INVALID)

+      return 0;

+

+   if (png_icc_check_length(png_ptr, colorspace, name, profile_length) &&

+      png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,

+         color_type) &&

+      png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,

+         profile))

+   {

+#     ifdef PNG_sRGB_SUPPORTED

+         /* If no sRGB support, don't try storing sRGB information */

+         png_icc_set_sRGB(png_ptr, colorspace, profile, 0);

+#     endif

+      return 1;

+   }

+

+   /* Failure case */

+   return 0;

+}

+#endif /* iCCP */

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+void /* PRIVATE */

+png_colorspace_set_rgb_coefficients(png_structrp png_ptr)

+{

+   /* Set the rgb_to_gray coefficients from the colorspace. */

+   if (!png_ptr->rgb_to_gray_coefficients_set &&

+      (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)

+   {

+      /* png_set_background has not been called, get the coefficients from the Y

+       * values of the colorspace colorants.

+       */

+      png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y;

+      png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y;

+      png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y;

+      png_fixed_point total = r+g+b;

+

+      if (total > 0 &&

+         r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&

+         g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&

+         b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&

+         r+g+b <= 32769)

+      {

+         /* We allow 0 coefficients here.  r+g+b may be 32769 if two or

+          * all of the coefficients were rounded up.  Handle this by

+          * reducing the *largest* coefficient by 1; this matches the

+          * approach used for the default coefficients in pngrtran.c

+          */

+         int add = 0;

+

+         if (r+g+b > 32768)

+            add = -1;

+         else if (r+g+b < 32768)

+            add = 1;

+

+         if (add != 0)

+         {

+            if (g >= r && g >= b)

+               g += add;

+            else if (r >= g && r >= b)

+               r += add;

+            else

+               b += add;

+         }

+

+         /* Check for an internal error. */

+         if (r+g+b != 32768)

+            png_error(png_ptr,

+               "internal error handling cHRM coefficients");

+

+         else

+         {

+            png_ptr->rgb_to_gray_red_coeff   = (png_uint_16)r;

+            png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;

+         }

+      }

+

+      /* This is a png_error at present even though it could be ignored -

+       * it should never happen, but it is important that if it does, the

+       * bug is fixed.

+       */

+      else

+         png_error(png_ptr, "internal error handling cHRM->XYZ");

+   }

+}

+#endif

+

+#endif /* COLORSPACE */

+

+void /* PRIVATE */

+png_check_IHDR(png_const_structrp png_ptr,

+   png_uint_32 width, png_uint_32 height, int bit_depth,

+   int color_type, int interlace_type, int compression_type,

+   int filter_type)

+{

+   int error = 0;

+

+   /* Check for width and height valid values */

+   if (width == 0)

+   {

+      png_warning(png_ptr, "Image width is zero in IHDR");

+      error = 1;

+   }

+

+   if (height == 0)

+   {

+      png_warning(png_ptr, "Image height is zero in IHDR");

+      error = 1;

+   }

+

+#  ifdef PNG_SET_USER_LIMITS_SUPPORTED

+   if (width > png_ptr->user_width_max)

+

+#  else

+   if (width > PNG_USER_WIDTH_MAX)

+#  endif

+   {

+      png_warning(png_ptr, "Image width exceeds user limit in IHDR");

+      error = 1;

+   }

+

+#  ifdef PNG_SET_USER_LIMITS_SUPPORTED

+   if (height > png_ptr->user_height_max)

+#  else

+   if (height > PNG_USER_HEIGHT_MAX)

+#  endif

+   {

+      png_warning(png_ptr, "Image height exceeds user limit in IHDR");

+      error = 1;

+   }

+

+   if (width > PNG_UINT_31_MAX)

+   {

+      png_warning(png_ptr, "Invalid image width in IHDR");

+      error = 1;

+   }

+

+   if (height > PNG_UINT_31_MAX)

+   {

+      png_warning(png_ptr, "Invalid image height in IHDR");

+      error = 1;

+   }

+

+   if (width > (PNG_UINT_32_MAX

+                 >> 3)      /* 8-byte RGBA pixels */

+                 - 48       /* bigrowbuf hack */

+                 - 1        /* filter byte */

+                 - 7*8      /* rounding of width to multiple of 8 pixels */

+                 - 8)       /* extra max_pixel_depth pad */

+      png_warning(png_ptr, "Width is too large for libpng to process pixels");

+

+   /* Check other values */

+   if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&

+       bit_depth != 8 && bit_depth != 16)

+   {

+      png_warning(png_ptr, "Invalid bit depth in IHDR");

+      error = 1;

+   }

+

+   if (color_type < 0 || color_type == 1 ||

+       color_type == 5 || color_type > 6)

+   {

+      png_warning(png_ptr, "Invalid color type in IHDR");

+      error = 1;

+   }

+

+   if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||

+       ((color_type == PNG_COLOR_TYPE_RGB ||

+         color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||

+         color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))

+   {

+      png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR");

+      error = 1;

+   }

+

+   if (interlace_type >= PNG_INTERLACE_LAST)

+   {

+      png_warning(png_ptr, "Unknown interlace method in IHDR");

+      error = 1;

+   }

+

+   if (compression_type != PNG_COMPRESSION_TYPE_BASE)

+   {

+      png_warning(png_ptr, "Unknown compression method in IHDR");

+      error = 1;

+   }

+

+#  ifdef PNG_MNG_FEATURES_SUPPORTED

+   /* Accept filter_method 64 (intrapixel differencing) only if

+    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and

+    * 2. Libpng did not read a PNG signature (this filter_method is only

+    *    used in PNG datastreams that are embedded in MNG datastreams) and

+    * 3. The application called png_permit_mng_features with a mask that

+    *    included PNG_FLAG_MNG_FILTER_64 and

+    * 4. The filter_method is 64 and

+    * 5. The color_type is RGB or RGBA

+    */

+   if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) &&

+       png_ptr->mng_features_permitted)

+      png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");

+

+   if (filter_type != PNG_FILTER_TYPE_BASE)

+   {

+      if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&

+          (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&

+          ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&

+          (color_type == PNG_COLOR_TYPE_RGB ||

+          color_type == PNG_COLOR_TYPE_RGB_ALPHA)))

+      {

+         png_warning(png_ptr, "Unknown filter method in IHDR");

+         error = 1;

+      }

+

+      if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE)

+      {

+         png_warning(png_ptr, "Invalid filter method in IHDR");

+         error = 1;

+      }

+   }

+

+#  else

+   if (filter_type != PNG_FILTER_TYPE_BASE)

+   {

+      png_warning(png_ptr, "Unknown filter method in IHDR");

+      error = 1;

+   }

+#  endif

+

+   if (error == 1)

+      png_error(png_ptr, "Invalid IHDR data");

+}

+

+#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)

+/* ASCII to fp functions */

+/* Check an ASCII formated floating point value, see the more detailed

+ * comments in pngpriv.h

+ */

+/* The following is used internally to preserve the sticky flags */

+#define png_fp_add(state, flags) ((state) |= (flags))

+#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY))

+

+int /* PRIVATE */

+png_check_fp_number(png_const_charp string, png_size_t size, int *statep,

+   png_size_tp whereami)

+{

+   int state = *statep;

+   png_size_t i = *whereami;

+

+   while (i < size)

+   {

+      int type;

+      /* First find the type of the next character */

+      switch (string[i])

+      {

+      case 43:  type = PNG_FP_SAW_SIGN;                   break;

+      case 45:  type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break;

+      case 46:  type = PNG_FP_SAW_DOT;                    break;

+      case 48:  type = PNG_FP_SAW_DIGIT;                  break;

+      case 49: case 50: case 51: case 52:

+      case 53: case 54: case 55: case 56:

+      case 57:  type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break;

+      case 69:

+      case 101: type = PNG_FP_SAW_E;                      break;

+      default:  goto PNG_FP_End;

+      }

+

+      /* Now deal with this type according to the current

+       * state, the type is arranged to not overlap the

+       * bits of the PNG_FP_STATE.

+       */

+      switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY))

+      {

+      case PNG_FP_INTEGER + PNG_FP_SAW_SIGN:

+         if (state & PNG_FP_SAW_ANY)

+            goto PNG_FP_End; /* not a part of the number */

+

+         png_fp_add(state, type);

+         break;

+

+      case PNG_FP_INTEGER + PNG_FP_SAW_DOT:

+         /* Ok as trailer, ok as lead of fraction. */

+         if (state & PNG_FP_SAW_DOT) /* two dots */

+            goto PNG_FP_End;

+

+         else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */

+            png_fp_add(state, type);

+

+         else

+            png_fp_set(state, PNG_FP_FRACTION | type);

+

+         break;

+

+      case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT:

+         if (state & PNG_FP_SAW_DOT) /* delayed fraction */

+            png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);

+

+         png_fp_add(state, type | PNG_FP_WAS_VALID);

+

+         break;

+

+      case PNG_FP_INTEGER + PNG_FP_SAW_E:

+         if ((state & PNG_FP_SAW_DIGIT) == 0)

+            goto PNG_FP_End;

+

+         png_fp_set(state, PNG_FP_EXPONENT);

+

+         break;

+

+   /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN:

+         goto PNG_FP_End; ** no sign in fraction */

+

+   /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT:

+         goto PNG_FP_End; ** Because SAW_DOT is always set */

+

+      case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT:

+         png_fp_add(state, type | PNG_FP_WAS_VALID);

+         break;

+

+      case PNG_FP_FRACTION + PNG_FP_SAW_E:

+         /* This is correct because the trailing '.' on an

+          * integer is handled above - so we can only get here

+          * with the sequence ".E" (with no preceding digits).

+          */

+         if ((state & PNG_FP_SAW_DIGIT) == 0)

+            goto PNG_FP_End;

+

+         png_fp_set(state, PNG_FP_EXPONENT);

+

+         break;

+

+      case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN:

+         if (state & PNG_FP_SAW_ANY)

+            goto PNG_FP_End; /* not a part of the number */

+

+         png_fp_add(state, PNG_FP_SAW_SIGN);

+

+         break;

+

+   /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT:

+         goto PNG_FP_End; */

+

+      case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT:

+         png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID);

+

+         break;

+

+   /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E:

+         goto PNG_FP_End; */

+

+      default: goto PNG_FP_End; /* I.e. break 2 */

+      }

+

+      /* The character seems ok, continue. */

+      ++i;

+   }

+

+PNG_FP_End:

+   /* Here at the end, update the state and return the correct

+    * return code.

+    */

+   *statep = state;

+   *whereami = i;

+

+   return (state & PNG_FP_SAW_DIGIT) != 0;

+}

+

+

+/* The same but for a complete string. */

+int

+png_check_fp_string(png_const_charp string, png_size_t size)

+{

+   int        state=0;

+   png_size_t char_index=0;

+

+   if (png_check_fp_number(string, size, &state, &char_index) &&

+      (char_index == size || string[char_index] == 0))

+      return state /* must be non-zero - see above */;

+

+   return 0; /* i.e. fail */

+}

+#endif /* pCAL or sCAL */

+

+#ifdef PNG_sCAL_SUPPORTED

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+/* Utility used below - a simple accurate power of ten from an integral

+ * exponent.

+ */

+static double

+png_pow10(int power)

+{

+   int recip = 0;

+   double d = 1;

+

+   /* Handle negative exponent with a reciprocal at the end because

+    * 10 is exact whereas .1 is inexact in base 2

+    */

+   if (power < 0)

+   {

+      if (power < DBL_MIN_10_EXP) return 0;

+      recip = 1, power = -power;

+   }

+

+   if (power > 0)

+   {

+      /* Decompose power bitwise. */

+      double mult = 10;

+      do

+      {

+         if (power & 1) d *= mult;

+         mult *= mult;

+         power >>= 1;

+      }

+      while (power > 0);

+

+      if (recip) d = 1/d;

+   }

+   /* else power is 0 and d is 1 */

+

+   return d;

+}

+

+/* Function to format a floating point value in ASCII with a given

+ * precision.

+ */

+void /* PRIVATE */

+png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size,

+    double fp, unsigned int precision)

+{

+   /* We use standard functions from math.h, but not printf because

+    * that would require stdio.  The caller must supply a buffer of

+    * sufficient size or we will png_error.  The tests on size and

+    * the space in ascii[] consumed are indicated below.

+    */

+   if (precision < 1)

+      precision = DBL_DIG;

+

+   /* Enforce the limit of the implementation precision too. */

+   if (precision > DBL_DIG+1)

+      precision = DBL_DIG+1;

+

+   /* Basic sanity checks */

+   if (size >= precision+5) /* See the requirements below. */

+   {

+      if (fp < 0)

+      {

+         fp = -fp;

+         *ascii++ = 45; /* '-'  PLUS 1 TOTAL 1 */

+         --size;

+      }

+

+      if (fp >= DBL_MIN && fp <= DBL_MAX)

+      {

+         int exp_b10;       /* A base 10 exponent */

+         double base;   /* 10^exp_b10 */

+

+         /* First extract a base 10 exponent of the number,

+          * the calculation below rounds down when converting

+          * from base 2 to base 10 (multiply by log10(2) -

+          * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to

+          * be increased.  Note that the arithmetic shift

+          * performs a floor() unlike C arithmetic - using a

+          * C multiply would break the following for negative

+          * exponents.

+          */

+         (void)frexp(fp, &exp_b10); /* exponent to base 2 */

+

+         exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */

+

+         /* Avoid underflow here. */

+         base = png_pow10(exp_b10); /* May underflow */

+

+         while (base < DBL_MIN || base < fp)

+         {

+            /* And this may overflow. */

+            double test = png_pow10(exp_b10+1);

+

+            if (test <= DBL_MAX)

+               ++exp_b10, base = test;

+

+            else

+               break;

+         }

+

+         /* Normalize fp and correct exp_b10, after this fp is in the

+          * range [.1,1) and exp_b10 is both the exponent and the digit

+          * *before* which the decimal point should be inserted

+          * (starting with 0 for the first digit).  Note that this

+          * works even if 10^exp_b10 is out of range because of the

+          * test on DBL_MAX above.

+          */

+         fp /= base;

+         while (fp >= 1) fp /= 10, ++exp_b10;

+

+         /* Because of the code above fp may, at this point, be

+          * less than .1, this is ok because the code below can

+          * handle the leading zeros this generates, so no attempt

+          * is made to correct that here.

+          */

+

+         {

+            int czero, clead, cdigits;

+            char exponent[10];

+

+            /* Allow up to two leading zeros - this will not lengthen

+             * the number compared to using E-n.

+             */

+            if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */

+            {

+               czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */

+               exp_b10 = 0;      /* Dot added below before first output. */

+            }

+            else

+               czero = 0;    /* No zeros to add */

+

+            /* Generate the digit list, stripping trailing zeros and

+             * inserting a '.' before a digit if the exponent is 0.

+             */

+            clead = czero; /* Count of leading zeros */

+            cdigits = 0;   /* Count of digits in list. */

+

+            do

+            {

+               double d;

+

+               fp *= 10;

+               /* Use modf here, not floor and subtract, so that

+                * the separation is done in one step.  At the end

+                * of the loop don't break the number into parts so

+                * that the final digit is rounded.

+                */

+               if (cdigits+czero-clead+1 < (int)precision)

+                  fp = modf(fp, &d);

+

+               else

+               {

+                  d = floor(fp + .5);

+

+                  if (d > 9)

+                  {

+                     /* Rounding up to 10, handle that here. */

+                     if (czero > 0)

+                     {

+                        --czero, d = 1;

+                        if (cdigits == 0) --clead;

+                     }

+                     else

+                     {

+                        while (cdigits > 0 && d > 9)

+                        {

+                           int ch = *--ascii;

+

+                           if (exp_b10 != (-1))

+                              ++exp_b10;

+

+                           else if (ch == 46)

+                           {

+                              ch = *--ascii, ++size;

+                              /* Advance exp_b10 to '1', so that the

+                               * decimal point happens after the

+                               * previous digit.

+                               */

+                              exp_b10 = 1;

+                           }

+

+                           --cdigits;

+                           d = ch - 47;  /* I.e. 1+(ch-48) */

+                        }

+

+                        /* Did we reach the beginning? If so adjust the

+                         * exponent but take into account the leading

+                         * decimal point.

+                         */

+                        if (d > 9)  /* cdigits == 0 */

+                        {

+                           if (exp_b10 == (-1))

+                           {

+                              /* Leading decimal point (plus zeros?), if

+                               * we lose the decimal point here it must

+                               * be reentered below.

+                               */

+                              int ch = *--ascii;

+

+                              if (ch == 46)

+                                 ++size, exp_b10 = 1;

+

+                              /* Else lost a leading zero, so 'exp_b10' is

+                               * still ok at (-1)

+                               */

+                           }

+                           else

+                              ++exp_b10;

+

+                           /* In all cases we output a '1' */

+                           d = 1;

+                        }

+                     }

+                  }

+                  fp = 0; /* Guarantees termination below. */

+               }

+

+               if (d == 0)

+               {

+                  ++czero;

+                  if (cdigits == 0) ++clead;

+               }

+               else

+               {

+                  /* Included embedded zeros in the digit count. */

+                  cdigits += czero - clead;

+                  clead = 0;

+

+                  while (czero > 0)

+                  {

+                     /* exp_b10 == (-1) means we just output the decimal

+                      * place - after the DP don't adjust 'exp_b10' any

+                      * more!

+                      */

+                     if (exp_b10 != (-1))

+                     {

+                        if (exp_b10 == 0) *ascii++ = 46, --size;

+                        /* PLUS 1: TOTAL 4 */

+                        --exp_b10;

+                     }

+                     *ascii++ = 48, --czero;

+                  }

+

+                  if (exp_b10 != (-1))

+                  {

+                     if (exp_b10 == 0) *ascii++ = 46, --size; /* counted

+                                                                 above */

+                     --exp_b10;

+                  }

+                  *ascii++ = (char)(48 + (int)d), ++cdigits;

+               }

+            }

+            while (cdigits+czero-clead < (int)precision && fp > DBL_MIN);

+

+            /* The total output count (max) is now 4+precision */

+

+            /* Check for an exponent, if we don't need one we are

+             * done and just need to terminate the string.  At

+             * this point exp_b10==(-1) is effectively if flag - it got

+             * to '-1' because of the decrement after outputing

+             * the decimal point above (the exponent required is

+             * *not* -1!)

+             */

+            if (exp_b10 >= (-1) && exp_b10 <= 2)

+            {

+               /* The following only happens if we didn't output the

+                * leading zeros above for negative exponent, so this

+                * doest add to the digit requirement.  Note that the

+                * two zeros here can only be output if the two leading

+                * zeros were *not* output, so this doesn't increase

+                * the output count.

+                */

+               while (--exp_b10 >= 0) *ascii++ = 48;

+

+               *ascii = 0;

+

+               /* Total buffer requirement (including the '\0') is

+                * 5+precision - see check at the start.

+                */

+               return;

+            }

+

+            /* Here if an exponent is required, adjust size for

+             * the digits we output but did not count.  The total

+             * digit output here so far is at most 1+precision - no

+             * decimal point and no leading or trailing zeros have

+             * been output.

+             */

+            size -= cdigits;

+

+            *ascii++ = 69, --size;    /* 'E': PLUS 1 TOTAL 2+precision */

+

+            /* The following use of an unsigned temporary avoids ambiguities in

+             * the signed arithmetic on exp_b10 and permits GCC at least to do

+             * better optimization.

+             */

+            {

+               unsigned int uexp_b10;

+

+               if (exp_b10 < 0)

+               {

+                  *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */

+                  uexp_b10 = -exp_b10;

+               }

+

+               else

+                  uexp_b10 = exp_b10;

+

+               cdigits = 0;

+

+               while (uexp_b10 > 0)

+               {

+                  exponent[cdigits++] = (char)(48 + uexp_b10 % 10);

+                  uexp_b10 /= 10;

+               }

+            }

+

+            /* Need another size check here for the exponent digits, so

+             * this need not be considered above.

+             */

+            if ((int)size > cdigits)

+            {

+               while (cdigits > 0) *ascii++ = exponent[--cdigits];

+

+               *ascii = 0;

+

+               return;

+            }

+         }

+      }

+      else if (!(fp >= DBL_MIN))

+      {

+         *ascii++ = 48; /* '0' */

+         *ascii = 0;

+         return;

+      }

+      else

+      {

+         *ascii++ = 105; /* 'i' */

+         *ascii++ = 110; /* 'n' */

+         *ascii++ = 102; /* 'f' */

+         *ascii = 0;

+         return;

+      }

+   }

+

+   /* Here on buffer too small. */

+   png_error(png_ptr, "ASCII conversion buffer too small");

+}

+

+#  endif /* FLOATING_POINT */

+

+#  ifdef PNG_FIXED_POINT_SUPPORTED

+/* Function to format a fixed point value in ASCII.

+ */

+void /* PRIVATE */

+png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii,

+    png_size_t size, png_fixed_point fp)

+{

+   /* Require space for 10 decimal digits, a decimal point, a minus sign and a

+    * trailing \0, 13 characters:

+    */

+   if (size > 12)

+   {

+      png_uint_32 num;

+

+      /* Avoid overflow here on the minimum integer. */

+      if (fp < 0)

+         *ascii++ = 45, --size, num = -fp;

+      else

+         num = fp;

+

+      if (num <= 0x80000000) /* else overflowed */

+      {

+         unsigned int ndigits = 0, first = 16 /* flag value */;

+         char digits[10];

+

+         while (num)

+         {

+            /* Split the low digit off num: */

+            unsigned int tmp = num/10;

+            num -= tmp*10;

+            digits[ndigits++] = (char)(48 + num);

+            /* Record the first non-zero digit, note that this is a number

+             * starting at 1, it's not actually the array index.

+             */

+            if (first == 16 && num > 0)

+               first = ndigits;

+            num = tmp;

+         }

+

+         if (ndigits > 0)

+         {

+            while (ndigits > 5) *ascii++ = digits[--ndigits];

+            /* The remaining digits are fractional digits, ndigits is '5' or

+             * smaller at this point.  It is certainly not zero.  Check for a

+             * non-zero fractional digit:

+             */

+            if (first <= 5)

+            {

+               unsigned int i;

+               *ascii++ = 46; /* decimal point */

+               /* ndigits may be <5 for small numbers, output leading zeros

+                * then ndigits digits to first:

+                */

+               i = 5;

+               while (ndigits < i) *ascii++ = 48, --i;

+               while (ndigits >= first) *ascii++ = digits[--ndigits];

+               /* Don't output the trailing zeros! */

+            }

+         }

+         else

+            *ascii++ = 48;

+

+         /* And null terminate the string: */

+         *ascii = 0;

+         return;

+      }

+   }

+

+   /* Here on buffer too small. */

+   png_error(png_ptr, "ASCII conversion buffer too small");

+}

+#   endif /* FIXED_POINT */

+#endif /* READ_SCAL */

+

+#if defined(PNG_FLOATING_POINT_SUPPORTED) && \

+   !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \

+   (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \

+   defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \

+   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \

+   (defined(PNG_sCAL_SUPPORTED) && \

+   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))

+png_fixed_point

+png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)

+{

+   double r = floor(100000 * fp + .5);

+

+   if (r > 2147483647. || r < -2147483648.)

+      png_fixed_error(png_ptr, text);

+

+   return (png_fixed_point)r;

+}

+#endif

+

+#if defined(PNG_READ_GAMMA_SUPPORTED) || \

+    defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)

+/* muldiv functions */

+/* This API takes signed arguments and rounds the result to the nearest

+ * integer (or, for a fixed point number - the standard argument - to

+ * the nearest .00001).  Overflow and divide by zero are signalled in

+ * the result, a boolean - true on success, false on overflow.

+ */

+int

+png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,

+    png_int_32 divisor)

+{

+   /* Return a * times / divisor, rounded. */

+   if (divisor != 0)

+   {

+      if (a == 0 || times == 0)

+      {

+         *res = 0;

+         return 1;

+      }

+      else

+      {

+#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED

+         double r = a;

+         r *= times;

+         r /= divisor;

+         r = floor(r+.5);

+

+         /* A png_fixed_point is a 32-bit integer. */

+         if (r <= 2147483647. && r >= -2147483648.)

+         {

+            *res = (png_fixed_point)r;

+            return 1;

+         }

+#else

+         int negative = 0;

+         png_uint_32 A, T, D;

+         png_uint_32 s16, s32, s00;

+

+         if (a < 0)

+            negative = 1, A = -a;

+         else

+            A = a;

+

+         if (times < 0)

+            negative = !negative, T = -times;

+         else

+            T = times;

+

+         if (divisor < 0)

+            negative = !negative, D = -divisor;

+         else

+            D = divisor;

+

+         /* Following can't overflow because the arguments only

+          * have 31 bits each, however the result may be 32 bits.

+          */

+         s16 = (A >> 16) * (T & 0xffff) +

+                           (A & 0xffff) * (T >> 16);

+         /* Can't overflow because the a*times bit is only 30

+          * bits at most.

+          */

+         s32 = (A >> 16) * (T >> 16) + (s16 >> 16);

+         s00 = (A & 0xffff) * (T & 0xffff);

+

+         s16 = (s16 & 0xffff) << 16;

+         s00 += s16;

+

+         if (s00 < s16)

+            ++s32; /* carry */

+

+         if (s32 < D) /* else overflow */

+         {

+            /* s32.s00 is now the 64-bit product, do a standard

+             * division, we know that s32 < D, so the maximum

+             * required shift is 31.

+             */

+            int bitshift = 32;

+            png_fixed_point result = 0; /* NOTE: signed */

+

+            while (--bitshift >= 0)

+            {

+               png_uint_32 d32, d00;

+

+               if (bitshift > 0)

+                  d32 = D >> (32-bitshift), d00 = D << bitshift;

+

+               else

+                  d32 = 0, d00 = D;

+

+               if (s32 > d32)

+               {

+                  if (s00 < d00) --s32; /* carry */

+                  s32 -= d32, s00 -= d00, result += 1<<bitshift;

+               }

+

+               else

+                  if (s32 == d32 && s00 >= d00)

+                     s32 = 0, s00 -= d00, result += 1<<bitshift;

+            }

+

+            /* Handle the rounding. */

+            if (s00 >= (D >> 1))

+               ++result;

+

+            if (negative)

+               result = -result;

+

+            /* Check for overflow. */

+            if ((negative && result <= 0) || (!negative && result >= 0))

+            {

+               *res = result;

+               return 1;

+            }

+         }

+#endif

+      }

+   }

+

+   return 0;

+}

+#endif /* READ_GAMMA || INCH_CONVERSIONS */

+

+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)

+/* The following is for when the caller doesn't much care about the

+ * result.

+ */

+png_fixed_point

+png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times,

+    png_int_32 divisor)

+{

+   png_fixed_point result;

+

+   if (png_muldiv(&result, a, times, divisor))

+      return result;

+

+   png_warning(png_ptr, "fixed point overflow ignored");

+   return 0;

+}

+#endif

+

+#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */

+/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */

+png_fixed_point

+png_reciprocal(png_fixed_point a)

+{

+#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED

+   double r = floor(1E10/a+.5);

+

+   if (r <= 2147483647. && r >= -2147483648.)

+      return (png_fixed_point)r;

+#else

+   png_fixed_point res;

+

+   if (png_muldiv(&res, 100000, 100000, a))

+      return res;

+#endif

+

+   return 0; /* error/overflow */

+}

+

+/* This is the shared test on whether a gamma value is 'significant' - whether

+ * it is worth doing gamma correction.

+ */

+int /* PRIVATE */

+png_gamma_significant(png_fixed_point gamma_val)

+{

+   return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||

+       gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;

+}

+#endif

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+/* A local convenience routine. */

+static png_fixed_point

+png_product2(png_fixed_point a, png_fixed_point b)

+{

+   /* The required result is 1/a * 1/b; the following preserves accuracy. */

+#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED

+   double r = a * 1E-5;

+   r *= b;

+   r = floor(r+.5);

+

+   if (r <= 2147483647. && r >= -2147483648.)

+      return (png_fixed_point)r;

+#else

+   png_fixed_point res;

+

+   if (png_muldiv(&res, a, b, 100000))

+      return res;

+#endif

+

+   return 0; /* overflow */

+}

+

+/* The inverse of the above. */

+png_fixed_point

+png_reciprocal2(png_fixed_point a, png_fixed_point b)

+{

+   /* The required result is 1/a * 1/b; the following preserves accuracy. */

+#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED

+   double r = 1E15/a;

+   r /= b;

+   r = floor(r+.5);

+

+   if (r <= 2147483647. && r >= -2147483648.)

+      return (png_fixed_point)r;

+#else

+   /* This may overflow because the range of png_fixed_point isn't symmetric,

+    * but this API is only used for the product of file and screen gamma so it

+    * doesn't matter that the smallest number it can produce is 1/21474, not

+    * 1/100000

+    */

+   png_fixed_point res = png_product2(a, b);

+

+   if (res != 0)

+      return png_reciprocal(res);

+#endif

+

+   return 0; /* overflow */

+}

+#endif /* READ_GAMMA */

+

+#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */

+#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED

+/* Fixed point gamma.

+ *

+ * The code to calculate the tables used below can be found in the shell script

+ * contrib/tools/intgamma.sh

+ *

+ * To calculate gamma this code implements fast log() and exp() calls using only

+ * fixed point arithmetic.  This code has sufficient precision for either 8-bit

+ * or 16-bit sample values.

+ *

+ * The tables used here were calculated using simple 'bc' programs, but C double

+ * precision floating point arithmetic would work fine.

+ *

+ * 8-bit log table

+ *   This is a table of -log(value/255)/log(2) for 'value' in the range 128 to

+ *   255, so it's the base 2 logarithm of a normalized 8-bit floating point

+ *   mantissa.  The numbers are 32-bit fractions.

+ */

+static const png_uint_32

+png_8bit_l2[128] =

+{

+   4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,

+   3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,

+   3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,

+   3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,

+   3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,

+   2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,

+   2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,

+   2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,

+   2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,

+   2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,

+   1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,

+   1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,

+   1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,

+   1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,

+   1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,

+   971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,

+   803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,

+   639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,

+   479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,

+   324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,

+   172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,

+   24347096U, 0U

+

+#if 0

+   /* The following are the values for 16-bit tables - these work fine for the

+    * 8-bit conversions but produce very slightly larger errors in the 16-bit

+    * log (about 1.2 as opposed to 0.7 absolute error in the final value).  To

+    * use these all the shifts below must be adjusted appropriately.

+    */

+   65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,

+   57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,

+   50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,

+   43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,

+   37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,

+   31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,

+   25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,

+   20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,

+   15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,

+   10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,

+   6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,

+   1119, 744, 372

+#endif

+};

+

+static png_int_32

+png_log8bit(unsigned int x)

+{

+   unsigned int lg2 = 0;

+   /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,

+    * because the log is actually negate that means adding 1.  The final

+    * returned value thus has the range 0 (for 255 input) to 7.994 (for 1

+    * input), return -1 for the overflow (log 0) case, - so the result is

+    * always at most 19 bits.

+    */

+   if ((x &= 0xff) == 0)

+      return -1;

+

+   if ((x & 0xf0) == 0)

+      lg2  = 4, x <<= 4;

+

+   if ((x & 0xc0) == 0)

+      lg2 += 2, x <<= 2;

+

+   if ((x & 0x80) == 0)

+      lg2 += 1, x <<= 1;

+

+   /* result is at most 19 bits, so this cast is safe: */

+   return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));

+}

+

+/* The above gives exact (to 16 binary places) log2 values for 8-bit images,

+ * for 16-bit images we use the most significant 8 bits of the 16-bit value to

+ * get an approximation then multiply the approximation by a correction factor

+ * determined by the remaining up to 8 bits.  This requires an additional step

+ * in the 16-bit case.

+ *

+ * We want log2(value/65535), we have log2(v'/255), where:

+ *

+ *    value = v' * 256 + v''

+ *          = v' * f

+ *

+ * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128

+ * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less

+ * than 258.  The final factor also needs to correct for the fact that our 8-bit

+ * value is scaled by 255, whereas the 16-bit values must be scaled by 65535.

+ *

+ * This gives a final formula using a calculated value 'x' which is value/v' and

+ * scaling by 65536 to match the above table:

+ *

+ *   log2(x/257) * 65536

+ *

+ * Since these numbers are so close to '1' we can use simple linear

+ * interpolation between the two end values 256/257 (result -368.61) and 258/257

+ * (result 367.179).  The values used below are scaled by a further 64 to give

+ * 16-bit precision in the interpolation:

+ *

+ * Start (256): -23591

+ * Zero  (257):      0

+ * End   (258):  23499

+ */

+static png_int_32

+png_log16bit(png_uint_32 x)

+{

+   unsigned int lg2 = 0;

+

+   /* As above, but now the input has 16 bits. */

+   if ((x &= 0xffff) == 0)

+      return -1;

+

+   if ((x & 0xff00) == 0)

+      lg2  = 8, x <<= 8;

+

+   if ((x & 0xf000) == 0)

+      lg2 += 4, x <<= 4;

+

+   if ((x & 0xc000) == 0)

+      lg2 += 2, x <<= 2;

+

+   if ((x & 0x8000) == 0)

+      lg2 += 1, x <<= 1;

+

+   /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional

+    * value.

+    */

+   lg2 <<= 28;

+   lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;

+

+   /* Now we need to interpolate the factor, this requires a division by the top

+    * 8 bits.  Do this with maximum precision.

+    */

+   x = ((x << 16) + (x >> 9)) / (x >> 8);

+

+   /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,

+    * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly

+    * 16 bits to interpolate to get the low bits of the result.  Round the

+    * answer.  Note that the end point values are scaled by 64 to retain overall

+    * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust

+    * the overall scaling by 6-12.  Round at every step.

+    */

+   x -= 1U << 24;

+

+   if (x <= 65536U) /* <= '257' */

+      lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);

+

+   else

+      lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);

+

+   /* Safe, because the result can't have more than 20 bits: */

+   return (png_int_32)((lg2 + 2048) >> 12);

+}

+

+/* The 'exp()' case must invert the above, taking a 20-bit fixed point

+ * logarithmic value and returning a 16 or 8-bit number as appropriate.  In

+ * each case only the low 16 bits are relevant - the fraction - since the

+ * integer bits (the top 4) simply determine a shift.

+ *

+ * The worst case is the 16-bit distinction between 65535 and 65534, this

+ * requires perhaps spurious accuracty in the decoding of the logarithm to

+ * distinguish log2(65535/65534.5) - 10^-5 or 17 bits.  There is little chance

+ * of getting this accuracy in practice.

+ *

+ * To deal with this the following exp() function works out the exponent of the

+ * frational part of the logarithm by using an accurate 32-bit value from the

+ * top four fractional bits then multiplying in the remaining bits.

+ */

+static const png_uint_32

+png_32bit_exp[16] =

+{

+   /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */

+   4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,

+   3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,

+   2553802834U, 2445529972U, 2341847524U, 2242560872U

+};

+

+/* Adjustment table; provided to explain the numbers in the code below. */

+#if 0

+for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}

+   11 44937.64284865548751208448

+   10 45180.98734845585101160448

+    9 45303.31936980687359311872

+    8 45364.65110595323018870784

+    7 45395.35850361789624614912

+    6 45410.72259715102037508096

+    5 45418.40724413220722311168

+    4 45422.25021786898173001728

+    3 45424.17186732298419044352

+    2 45425.13273269940811464704

+    1 45425.61317555035558641664

+    0 45425.85339951654943850496

+#endif

+

+static png_uint_32

+png_exp(png_fixed_point x)

+{

+   if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */

+   {

+      /* Obtain a 4-bit approximation */

+      png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf];

+

+      /* Incorporate the low 12 bits - these decrease the returned value by

+       * multiplying by a number less than 1 if the bit is set.  The multiplier

+       * is determined by the above table and the shift. Notice that the values

+       * converge on 45426 and this is used to allow linear interpolation of the

+       * low bits.

+       */

+      if (x & 0x800)

+         e -= (((e >> 16) * 44938U) +  16U) >> 5;

+

+      if (x & 0x400)

+         e -= (((e >> 16) * 45181U) +  32U) >> 6;

+

+      if (x & 0x200)

+         e -= (((e >> 16) * 45303U) +  64U) >> 7;

+

+      if (x & 0x100)

+         e -= (((e >> 16) * 45365U) + 128U) >> 8;

+

+      if (x & 0x080)

+         e -= (((e >> 16) * 45395U) + 256U) >> 9;

+

+      if (x & 0x040)

+         e -= (((e >> 16) * 45410U) + 512U) >> 10;

+

+      /* And handle the low 6 bits in a single block. */

+      e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;

+

+      /* Handle the upper bits of x. */

+      e >>= x >> 16;

+      return e;

+   }

+

+   /* Check for overflow */

+   if (x <= 0)

+      return png_32bit_exp[0];

+

+   /* Else underflow */

+   return 0;

+}

+

+static png_byte

+png_exp8bit(png_fixed_point lg2)

+{

+   /* Get a 32-bit value: */

+   png_uint_32 x = png_exp(lg2);

+

+   /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the

+    * second, rounding, step can't overflow because of the first, subtraction,

+    * step.

+    */

+   x -= x >> 8;

+   return (png_byte)((x + 0x7fffffU) >> 24);

+}

+

+static png_uint_16

+png_exp16bit(png_fixed_point lg2)

+{

+   /* Get a 32-bit value: */

+   png_uint_32 x = png_exp(lg2);

+

+   /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */

+   x -= x >> 16;

+   return (png_uint_16)((x + 32767U) >> 16);

+}

+#endif /* FLOATING_ARITHMETIC */

+

+png_byte

+png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)

+{

+   if (value > 0 && value < 255)

+   {

+#     ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED

+         double r = floor(255*pow(value/255.,gamma_val*.00001)+.5);

+         return (png_byte)r;

+#     else

+         png_int_32 lg2 = png_log8bit(value);

+         png_fixed_point res;

+

+         if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1))

+            return png_exp8bit(res);

+

+         /* Overflow. */

+         value = 0;

+#     endif

+   }

+

+   return (png_byte)value;

+}

+

+png_uint_16

+png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)

+{

+   if (value > 0 && value < 65535)

+   {

+#     ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED

+         double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5);

+         return (png_uint_16)r;

+#     else

+         png_int_32 lg2 = png_log16bit(value);

+         png_fixed_point res;

+

+         if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1))

+            return png_exp16bit(res);

+

+         /* Overflow. */

+         value = 0;

+#     endif

+   }

+

+   return (png_uint_16)value;

+}

+

+/* This does the right thing based on the bit_depth field of the

+ * png_struct, interpreting values as 8-bit or 16-bit.  While the result

+ * is nominally a 16-bit value if bit depth is 8 then the result is

+ * 8-bit (as are the arguments.)

+ */

+png_uint_16 /* PRIVATE */

+png_gamma_correct(png_structrp png_ptr, unsigned int value,

+    png_fixed_point gamma_val)

+{

+   if (png_ptr->bit_depth == 8)

+      return png_gamma_8bit_correct(value, gamma_val);

+

+   else

+      return png_gamma_16bit_correct(value, gamma_val);

+}

+

+/* Internal function to build a single 16-bit table - the table consists of

+ * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount

+ * to shift the input values right (or 16-number_of_signifiant_bits).

+ *

+ * The caller is responsible for ensuring that the table gets cleaned up on

+ * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument

+ * should be somewhere that will be cleaned.

+ */

+static void

+png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable,

+   PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)

+{

+   /* Various values derived from 'shift': */

+   PNG_CONST unsigned int num = 1U << (8U - shift);

+   PNG_CONST unsigned int max = (1U << (16U - shift))-1U;

+   PNG_CONST unsigned int max_by_2 = 1U << (15U-shift);

+   unsigned int i;

+

+   png_uint_16pp table = *ptable =

+       (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p)));

+

+   for (i = 0; i < num; i++)

+   {

+      png_uint_16p sub_table = table[i] =

+          (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16)));

+

+      /* The 'threshold' test is repeated here because it can arise for one of

+       * the 16-bit tables even if the others don't hit it.

+       */

+      if (png_gamma_significant(gamma_val))

+      {

+         /* The old code would overflow at the end and this would cause the

+          * 'pow' function to return a result >1, resulting in an

+          * arithmetic error.  This code follows the spec exactly; ig is

+          * the recovered input sample, it always has 8-16 bits.

+          *

+          * We want input * 65535/max, rounded, the arithmetic fits in 32

+          * bits (unsigned) so long as max <= 32767.

+          */

+         unsigned int j;

+         for (j = 0; j < 256; j++)

+         {

+            png_uint_32 ig = (j << (8-shift)) + i;

+#           ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED

+               /* Inline the 'max' scaling operation: */

+               double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5);

+               sub_table[j] = (png_uint_16)d;

+#           else

+               if (shift)

+                  ig = (ig * 65535U + max_by_2)/max;

+

+               sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);

+#           endif

+         }

+      }

+      else

+      {

+         /* We must still build a table, but do it the fast way. */

+         unsigned int j;

+

+         for (j = 0; j < 256; j++)

+         {

+            png_uint_32 ig = (j << (8-shift)) + i;

+

+            if (shift)

+               ig = (ig * 65535U + max_by_2)/max;

+

+            sub_table[j] = (png_uint_16)ig;

+         }

+      }

+   }

+}

+

+/* NOTE: this function expects the *inverse* of the overall gamma transformation

+ * required.

+ */

+static void

+png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable,

+   PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)

+{

+   PNG_CONST unsigned int num = 1U << (8U - shift);

+   PNG_CONST unsigned int max = (1U << (16U - shift))-1U;

+   unsigned int i;

+   png_uint_32 last;

+

+   png_uint_16pp table = *ptable =

+       (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p)));

+

+   /* 'num' is the number of tables and also the number of low bits of low

+    * bits of the input 16-bit value used to select a table.  Each table is

+    * itself index by the high 8 bits of the value.

+    */

+   for (i = 0; i < num; i++)

+      table[i] = (png_uint_16p)png_malloc(png_ptr,

+          256 * (sizeof (png_uint_16)));

+

+   /* 'gamma_val' is set to the reciprocal of the value calculated above, so

+    * pow(out,g) is an *input* value.  'last' is the last input value set.

+    *

+    * In the loop 'i' is used to find output values.  Since the output is

+    * 8-bit there are only 256 possible values.  The tables are set up to

+    * select the closest possible output value for each input by finding

+    * the input value at the boundary between each pair of output values

+    * and filling the table up to that boundary with the lower output

+    * value.

+    *

+    * The boundary values are 0.5,1.5..253.5,254.5.  Since these are 9-bit

+    * values the code below uses a 16-bit value in i; the values start at

+    * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last

+    * entries are filled with 255).  Start i at 128 and fill all 'last'

+    * table entries <= 'max'

+    */

+   last = 0;

+   for (i = 0; i < 255; ++i) /* 8-bit output value */

+   {

+      /* Find the corresponding maximum input value */

+      png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */

+

+      /* Find the boundary value in 16 bits: */

+      png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);

+

+      /* Adjust (round) to (16-shift) bits: */

+      bound = (bound * max + 32768U)/65535U + 1U;

+

+      while (last < bound)

+      {

+         table[last & (0xffU >> shift)][last >> (8U - shift)] = out;

+         last++;

+      }

+   }

+

+   /* And fill in the final entries. */

+   while (last < (num << 8))

+   {

+      table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;

+      last++;

+   }

+}

+

+/* Build a single 8-bit table: same as the 16-bit case but much simpler (and

+ * typically much faster).  Note that libpng currently does no sBIT processing

+ * (apparently contrary to the spec) so a 256 entry table is always generated.

+ */

+static void

+png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable,

+   PNG_CONST png_fixed_point gamma_val)

+{

+   unsigned int i;

+   png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256);

+

+   if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++)

+      table[i] = png_gamma_8bit_correct(i, gamma_val);

+

+   else for (i=0; i<256; ++i)

+      table[i] = (png_byte)i;

+}

+

+/* Used from png_read_destroy and below to release the memory used by the gamma

+ * tables.

+ */

+void /* PRIVATE */

+png_destroy_gamma_table(png_structrp png_ptr)

+{

+   png_free(png_ptr, png_ptr->gamma_table);

+   png_ptr->gamma_table = NULL;

+

+   if (png_ptr->gamma_16_table != NULL)

+   {

+      int i;

+      int istop = (1 << (8 - png_ptr->gamma_shift));

+      for (i = 0; i < istop; i++)

+      {

+         png_free(png_ptr, png_ptr->gamma_16_table[i]);

+      }

+   png_free(png_ptr, png_ptr->gamma_16_table);

+   png_ptr->gamma_16_table = NULL;

+   }

+

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \

+   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)

+   png_free(png_ptr, png_ptr->gamma_from_1);

+   png_ptr->gamma_from_1 = NULL;

+   png_free(png_ptr, png_ptr->gamma_to_1);

+   png_ptr->gamma_to_1 = NULL;

+

+   if (png_ptr->gamma_16_from_1 != NULL)

+   {

+      int i;

+      int istop = (1 << (8 - png_ptr->gamma_shift));

+      for (i = 0; i < istop; i++)

+      {

+         png_free(png_ptr, png_ptr->gamma_16_from_1[i]);

+      }

+   png_free(png_ptr, png_ptr->gamma_16_from_1);

+   png_ptr->gamma_16_from_1 = NULL;

+   }

+   if (png_ptr->gamma_16_to_1 != NULL)

+   {

+      int i;

+      int istop = (1 << (8 - png_ptr->gamma_shift));

+      for (i = 0; i < istop; i++)

+      {

+         png_free(png_ptr, png_ptr->gamma_16_to_1[i]);

+      }

+   png_free(png_ptr, png_ptr->gamma_16_to_1);

+   png_ptr->gamma_16_to_1 = NULL;

+   }

+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */

+}

+

+/* We build the 8- or 16-bit gamma tables here.  Note that for 16-bit

+ * tables, we don't make a full table if we are reducing to 8-bit in

+ * the future.  Note also how the gamma_16 tables are segmented so that

+ * we don't need to allocate > 64K chunks for a full 16-bit table.

+ */

+void /* PRIVATE */

+png_build_gamma_table(png_structrp png_ptr, int bit_depth)

+{

+  png_debug(1, "in png_build_gamma_table");

+

+  /* Remove any existing table; this copes with multiple calls to

+   * png_read_update_info.  The warning is because building the gamma tables

+   * multiple times is a performance hit - it's harmless but the ability to call

+   * png_read_update_info() multiple times is new in 1.5.6 so it seems sensible

+   * to warn if the app introduces such a hit.

+   */

+  if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL)

+  {

+    png_warning(png_ptr, "gamma table being rebuilt");

+    png_destroy_gamma_table(png_ptr);

+  }

+

+  if (bit_depth <= 8)

+  {

+     png_build_8bit_table(png_ptr, &png_ptr->gamma_table,

+         png_ptr->screen_gamma > 0 ?  png_reciprocal2(png_ptr->colorspace.gamma,

+         png_ptr->screen_gamma) : PNG_FP_1);

+

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \

+   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)

+     if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))

+     {

+        png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,

+            png_reciprocal(png_ptr->colorspace.gamma));

+

+        png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,

+            png_ptr->screen_gamma > 0 ?  png_reciprocal(png_ptr->screen_gamma) :

+            png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);

+     }

+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */

+  }

+  else

+  {

+     png_byte shift, sig_bit;

+

+     if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)

+     {

+        sig_bit = png_ptr->sig_bit.red;

+

+        if (png_ptr->sig_bit.green > sig_bit)

+           sig_bit = png_ptr->sig_bit.green;

+

+        if (png_ptr->sig_bit.blue > sig_bit)

+           sig_bit = png_ptr->sig_bit.blue;

+     }

+     else

+        sig_bit = png_ptr->sig_bit.gray;

+

+     /* 16-bit gamma code uses this equation:

+      *

+      *   ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]

+      *

+      * Where 'iv' is the input color value and 'ov' is the output value -

+      * pow(iv, gamma).

+      *

+      * Thus the gamma table consists of up to 256 256 entry tables.  The table

+      * is selected by the (8-gamma_shift) most significant of the low 8 bits of

+      * the color value then indexed by the upper 8 bits:

+      *

+      *   table[low bits][high 8 bits]

+      *

+      * So the table 'n' corresponds to all those 'iv' of:

+      *

+      *   <all high 8-bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>

+      *

+      */

+     if (sig_bit > 0 && sig_bit < 16U)

+        shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */

+

+     else

+        shift = 0; /* keep all 16 bits */

+

+     if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8))

+     {

+        /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively

+         * the significant bits in the *input* when the output will

+         * eventually be 8 bits.  By default it is 11.

+         */

+        if (shift < (16U - PNG_MAX_GAMMA_8))

+           shift = (16U - PNG_MAX_GAMMA_8);

+     }

+

+     if (shift > 8U)

+        shift = 8U; /* Guarantees at least one table! */

+

+     png_ptr->gamma_shift = shift;

+

+#ifdef PNG_16BIT_SUPPORTED

+     /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now

+      * PNG_COMPOSE).  This effectively smashed the background calculation for

+      * 16-bit output because the 8-bit table assumes the result will be reduced

+      * to 8 bits.

+      */

+     if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8))

+#endif

+         png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,

+         png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma,

+         png_ptr->screen_gamma) : PNG_FP_1);

+

+#ifdef PNG_16BIT_SUPPORTED

+     else

+         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,

+         png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,

+         png_ptr->screen_gamma) : PNG_FP_1);

+#endif

+

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \

+   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)

+     if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))

+     {

+        png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,

+            png_reciprocal(png_ptr->colorspace.gamma));

+

+        /* Notice that the '16 from 1' table should be full precision, however

+         * the lookup on this table still uses gamma_shift, so it can't be.

+         * TODO: fix this.

+         */

+        png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,

+            png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :

+            png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);

+     }

+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */

+  }

+}

+#endif /* READ_GAMMA */

+

+/* HARDWARE OPTION SUPPORT */

+#ifdef PNG_SET_OPTION_SUPPORTED

+int PNGAPI

+png_set_option(png_structrp png_ptr, int option, int onoff)

+{

+   if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT &&

+      (option & 1) == 0)

+   {

+      int mask = 3 << option;

+      int setting = (2 + (onoff != 0)) << option;

+      int current = png_ptr->options;

+

+      png_ptr->options = (png_byte)((current & ~mask) | setting);

+

+      return (current & mask) >> option;

+   }

+

+   return PNG_OPTION_INVALID;

+}

+#endif

+

+/* sRGB support */

+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\

+   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)

+/* sRGB conversion tables; these are machine generated with the code in

+ * contrib/tools/makesRGB.c.  The actual sRGB transfer curve defined in the

+ * specification (see the article at http://en.wikipedia.org/wiki/SRGB)

+ * is used, not the gamma=1/2.2 approximation use elsewhere in libpng.

+ * The sRGB to linear table is exact (to the nearest 16 bit linear fraction).

+ * The inverse (linear to sRGB) table has accuracies as follows:

+ *

+ * For all possible (255*65535+1) input values:

+ *

+ *    error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact

+ *

+ * For the input values corresponding to the 65536 16-bit values:

+ *

+ *    error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact

+ *

+ * In all cases the inexact readings are off by one.

+ */

+

+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED

+/* The convert-to-sRGB table is only currently required for read. */

+const png_uint_16 png_sRGB_table[256] =

+{

+   0,20,40,60,80,99,119,139,

+   159,179,199,219,241,264,288,313,

+   340,367,396,427,458,491,526,562,

+   599,637,677,718,761,805,851,898,

+   947,997,1048,1101,1156,1212,1270,1330,

+   1391,1453,1517,1583,1651,1720,1790,1863,

+   1937,2013,2090,2170,2250,2333,2418,2504,

+   2592,2681,2773,2866,2961,3058,3157,3258,

+   3360,3464,3570,3678,3788,3900,4014,4129,

+   4247,4366,4488,4611,4736,4864,4993,5124,

+   5257,5392,5530,5669,5810,5953,6099,6246,

+   6395,6547,6700,6856,7014,7174,7335,7500,

+   7666,7834,8004,8177,8352,8528,8708,8889,

+   9072,9258,9445,9635,9828,10022,10219,10417,

+   10619,10822,11028,11235,11446,11658,11873,12090,

+   12309,12530,12754,12980,13209,13440,13673,13909,

+   14146,14387,14629,14874,15122,15371,15623,15878,

+   16135,16394,16656,16920,17187,17456,17727,18001,

+   18277,18556,18837,19121,19407,19696,19987,20281,

+   20577,20876,21177,21481,21787,22096,22407,22721,

+   23038,23357,23678,24002,24329,24658,24990,25325,

+   25662,26001,26344,26688,27036,27386,27739,28094,

+   28452,28813,29176,29542,29911,30282,30656,31033,

+   31412,31794,32179,32567,32957,33350,33745,34143,

+   34544,34948,35355,35764,36176,36591,37008,37429,

+   37852,38278,38706,39138,39572,40009,40449,40891,

+   41337,41785,42236,42690,43147,43606,44069,44534,

+   45002,45473,45947,46423,46903,47385,47871,48359,

+   48850,49344,49841,50341,50844,51349,51858,52369,

+   52884,53401,53921,54445,54971,55500,56032,56567,

+   57105,57646,58190,58737,59287,59840,60396,60955,

+   61517,62082,62650,63221,63795,64372,64952,65535

+};

+

+#endif /* simplified read only */

+

+/* The base/delta tables are required for both read and write (but currently

+ * only the simplified versions.)

+ */

+const png_uint_16 png_sRGB_base[512] =

+{

+   128,1782,3383,4644,5675,6564,7357,8074,

+   8732,9346,9921,10463,10977,11466,11935,12384,

+   12816,13233,13634,14024,14402,14769,15125,15473,

+   15812,16142,16466,16781,17090,17393,17690,17981,

+   18266,18546,18822,19093,19359,19621,19879,20133,

+   20383,20630,20873,21113,21349,21583,21813,22041,

+   22265,22487,22707,22923,23138,23350,23559,23767,

+   23972,24175,24376,24575,24772,24967,25160,25352,

+   25542,25730,25916,26101,26284,26465,26645,26823,

+   27000,27176,27350,27523,27695,27865,28034,28201,

+   28368,28533,28697,28860,29021,29182,29341,29500,

+   29657,29813,29969,30123,30276,30429,30580,30730,

+   30880,31028,31176,31323,31469,31614,31758,31902,

+   32045,32186,32327,32468,32607,32746,32884,33021,

+   33158,33294,33429,33564,33697,33831,33963,34095,

+   34226,34357,34486,34616,34744,34873,35000,35127,

+   35253,35379,35504,35629,35753,35876,35999,36122,

+   36244,36365,36486,36606,36726,36845,36964,37083,

+   37201,37318,37435,37551,37668,37783,37898,38013,

+   38127,38241,38354,38467,38580,38692,38803,38915,

+   39026,39136,39246,39356,39465,39574,39682,39790,

+   39898,40005,40112,40219,40325,40431,40537,40642,

+   40747,40851,40955,41059,41163,41266,41369,41471,

+   41573,41675,41777,41878,41979,42079,42179,42279,

+   42379,42478,42577,42676,42775,42873,42971,43068,

+   43165,43262,43359,43456,43552,43648,43743,43839,

+   43934,44028,44123,44217,44311,44405,44499,44592,

+   44685,44778,44870,44962,45054,45146,45238,45329,

+   45420,45511,45601,45692,45782,45872,45961,46051,

+   46140,46229,46318,46406,46494,46583,46670,46758,

+   46846,46933,47020,47107,47193,47280,47366,47452,

+   47538,47623,47709,47794,47879,47964,48048,48133,

+   48217,48301,48385,48468,48552,48635,48718,48801,

+   48884,48966,49048,49131,49213,49294,49376,49458,

+   49539,49620,49701,49782,49862,49943,50023,50103,

+   50183,50263,50342,50422,50501,50580,50659,50738,

+   50816,50895,50973,51051,51129,51207,51285,51362,

+   51439,51517,51594,51671,51747,51824,51900,51977,

+   52053,52129,52205,52280,52356,52432,52507,52582,

+   52657,52732,52807,52881,52956,53030,53104,53178,

+   53252,53326,53400,53473,53546,53620,53693,53766,

+   53839,53911,53984,54056,54129,54201,54273,54345,

+   54417,54489,54560,54632,54703,54774,54845,54916,

+   54987,55058,55129,55199,55269,55340,55410,55480,

+   55550,55620,55689,55759,55828,55898,55967,56036,

+   56105,56174,56243,56311,56380,56448,56517,56585,

+   56653,56721,56789,56857,56924,56992,57059,57127,

+   57194,57261,57328,57395,57462,57529,57595,57662,

+   57728,57795,57861,57927,57993,58059,58125,58191,

+   58256,58322,58387,58453,58518,58583,58648,58713,

+   58778,58843,58908,58972,59037,59101,59165,59230,

+   59294,59358,59422,59486,59549,59613,59677,59740,

+   59804,59867,59930,59993,60056,60119,60182,60245,

+   60308,60370,60433,60495,60558,60620,60682,60744,

+   60806,60868,60930,60992,61054,61115,61177,61238,

+   61300,61361,61422,61483,61544,61605,61666,61727,

+   61788,61848,61909,61969,62030,62090,62150,62211,

+   62271,62331,62391,62450,62510,62570,62630,62689,

+   62749,62808,62867,62927,62986,63045,63104,63163,

+   63222,63281,63340,63398,63457,63515,63574,63632,

+   63691,63749,63807,63865,63923,63981,64039,64097,

+   64155,64212,64270,64328,64385,64443,64500,64557,

+   64614,64672,64729,64786,64843,64900,64956,65013,

+   65070,65126,65183,65239,65296,65352,65409,65465

+};

+

+const png_byte png_sRGB_delta[512] =

+{

+   207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54,

+   52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36,

+   35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28,

+   28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24,

+   23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21,

+   21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,

+   19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,

+   17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,

+   16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,

+   15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,

+   14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,

+   13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,

+   12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,

+   12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,

+   11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,

+   11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,

+   11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,

+   10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,

+   10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,

+   10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,

+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,

+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,

+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,

+   9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,

+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,

+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,

+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,

+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,

+   8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,

+   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,

+   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,

+   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7

+};

+#endif /* SIMPLIFIED READ/WRITE sRGB support */

+

+/* SIMPLIFIED READ/WRITE SUPPORT */

+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\

+   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)

+static int

+png_image_free_function(png_voidp argument)

+{

+   png_imagep image = png_voidcast(png_imagep, argument);

+   png_controlp cp = image->opaque;

+   png_control c;

+

+   /* Double check that we have a png_ptr - it should be impossible to get here

+    * without one.

+    */

+   if (cp->png_ptr == NULL)

+      return 0;

+

+   /* First free any data held in the control structure. */

+#  ifdef PNG_STDIO_SUPPORTED

+      if (cp->owned_file)

+      {

+         FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);

+         cp->owned_file = 0;

+

+         /* Ignore errors here. */

+         if (fp != NULL)

+         {

+            cp->png_ptr->io_ptr = NULL;

+            (void)fclose(fp);

+         }

+      }

+#  endif

+

+   /* Copy the control structure so that the original, allocated, version can be

+    * safely freed.  Notice that a png_error here stops the remainder of the

+    * cleanup, but this is probably fine because that would indicate bad memory

+    * problems anyway.

+    */

+   c = *cp;

+   image->opaque = &c;

+   png_free(c.png_ptr, cp);

+

+   /* Then the structures, calling the correct API. */

+   if (c.for_write)

+   {

+#     ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED

+         png_destroy_write_struct(&c.png_ptr, &c.info_ptr);

+#     else

+         png_error(c.png_ptr, "simplified write not supported");

+#     endif

+   }

+   else

+   {

+#     ifdef PNG_SIMPLIFIED_READ_SUPPORTED

+         png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL);

+#     else

+         png_error(c.png_ptr, "simplified read not supported");

+#     endif

+   }

+

+   /* Success. */

+   return 1;

+}

+

+void PNGAPI

+png_image_free(png_imagep image)

+{

+   /* Safely call the real function, but only if doing so is safe at this point

+    * (if not inside an error handling context).  Otherwise assume

+    * png_safe_execute will call this API after the return.

+    */

+   if (image != NULL && image->opaque != NULL &&

+      image->opaque->error_buf == NULL)

+   {

+      /* Ignore errors here: */

+      (void)png_safe_execute(image, png_image_free_function, image);

+      image->opaque = NULL;

+   }

+}

+

+int /* PRIVATE */

+png_image_error(png_imagep image, png_const_charp error_message)

+{

+   /* Utility to log an error. */

+   png_safecat(image->message, (sizeof image->message), 0, error_message);

+   image->warning_or_error |= PNG_IMAGE_ERROR;

+   png_image_free(image);

+   return 0;

+}

+

+#endif /* SIMPLIFIED READ/WRITE */

+#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngerror.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngerror.c
new file mode 100644
index 0000000..e53c932
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngerror.c
@@ -0,0 +1,933 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngerror.c - stub functions for i/o and memory allocation

+ *

+ * Last changed in libpng 1.6.1 [March 28, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ * This file provides a location for all error handling.  Users who

+ * need special error handling are expected to write replacement functions

+ * and use png_set_error_fn() to use those functions.  See the instructions

+ * at each function.

+ */

+

+#include "pngpriv.h"

+

+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

+

+static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr,

+    png_const_charp error_message)),PNG_NORETURN);

+

+#ifdef PNG_WARNINGS_SUPPORTED

+static void /* PRIVATE */

+png_default_warning PNGARG((png_const_structrp png_ptr,

+   png_const_charp warning_message));

+#endif /* PNG_WARNINGS_SUPPORTED */

+

+/* This function is called whenever there is a fatal error.  This function

+ * should not be changed.  If there is a need to handle errors differently,

+ * you should supply a replacement error function and use png_set_error_fn()

+ * to replace the error function at run-time.

+ */

+#ifdef PNG_ERROR_TEXT_SUPPORTED

+PNG_FUNCTION(void,PNGAPI

+png_error,(png_const_structrp png_ptr, png_const_charp error_message),

+   PNG_NORETURN)

+{

+#ifdef PNG_ERROR_NUMBERS_SUPPORTED

+   char msg[16];

+   if (png_ptr != NULL)

+   {

+      if (png_ptr->flags&

+         (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))

+      {

+         if (*error_message == PNG_LITERAL_SHARP)

+         {

+            /* Strip "#nnnn " from beginning of error message. */

+            int offset;

+            for (offset = 1; offset<15; offset++)

+               if (error_message[offset] == ' ')

+                  break;

+

+            if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)

+            {

+               int i;

+               for (i = 0; i < offset - 1; i++)

+                  msg[i] = error_message[i + 1];

+               msg[i - 1] = '\0';

+               error_message = msg;

+            }

+

+            else

+               error_message += offset;

+      }

+

+      else

+      {

+         if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)

+         {

+            msg[0] = '0';

+            msg[1] = '\0';

+            error_message = msg;

+         }

+       }

+     }

+   }

+#endif

+   if (png_ptr != NULL && png_ptr->error_fn != NULL)

+      (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),

+          error_message);

+

+   /* If the custom handler doesn't exist, or if it returns,

+      use the default handler, which will not return. */

+   png_default_error(png_ptr, error_message);

+}

+#else

+PNG_FUNCTION(void,PNGAPI

+png_err,(png_const_structrp png_ptr),PNG_NORETURN)

+{

+   /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed

+    * erroneously as '\0', instead of the empty string "".  This was

+    * apparently an error, introduced in libpng-1.2.20, and png_default_error

+    * will crash in this case.

+    */

+   if (png_ptr != NULL && png_ptr->error_fn != NULL)

+      (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), "");

+

+   /* If the custom handler doesn't exist, or if it returns,

+      use the default handler, which will not return. */

+   png_default_error(png_ptr, "");

+}

+#endif /* PNG_ERROR_TEXT_SUPPORTED */

+

+/* Utility to safely appends strings to a buffer.  This never errors out so

+ * error checking is not required in the caller.

+ */

+size_t

+png_safecat(png_charp buffer, size_t bufsize, size_t pos,

+   png_const_charp string)

+{

+   if (buffer != NULL && pos < bufsize)

+   {

+      if (string != NULL)

+         while (*string != '\0' && pos < bufsize-1)

+           buffer[pos++] = *string++;

+

+      buffer[pos] = '\0';

+   }

+

+   return pos;

+}

+

+#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)

+/* Utility to dump an unsigned value into a buffer, given a start pointer and

+ * and end pointer (which should point just *beyond* the end of the buffer!)

+ * Returns the pointer to the start of the formatted string.

+ */

+png_charp

+png_format_number(png_const_charp start, png_charp end, int format,

+   png_alloc_size_t number)

+{

+   int count = 0;    /* number of digits output */

+   int mincount = 1; /* minimum number required */

+   int output = 0;   /* digit output (for the fixed point format) */

+

+   *--end = '\0';

+

+   /* This is written so that the loop always runs at least once, even with

+    * number zero.

+    */

+   while (end > start && (number != 0 || count < mincount))

+   {

+

+      static const char digits[] = "0123456789ABCDEF";

+

+      switch (format)

+      {

+         case PNG_NUMBER_FORMAT_fixed:

+            /* Needs five digits (the fraction) */

+            mincount = 5;

+            if (output || number % 10 != 0)

+            {

+               *--end = digits[number % 10];

+               output = 1;

+            }

+            number /= 10;

+            break;

+

+         case PNG_NUMBER_FORMAT_02u:

+            /* Expects at least 2 digits. */

+            mincount = 2;

+            /* FALL THROUGH */

+

+         case PNG_NUMBER_FORMAT_u:

+            *--end = digits[number % 10];

+            number /= 10;

+            break;

+

+         case PNG_NUMBER_FORMAT_02x:

+            /* This format expects at least two digits */

+            mincount = 2;

+            /* FALL THROUGH */

+

+         case PNG_NUMBER_FORMAT_x:

+            *--end = digits[number & 0xf];

+            number >>= 4;

+            break;

+

+         default: /* an error */

+            number = 0;

+            break;

+      }

+

+      /* Keep track of the number of digits added */

+      ++count;

+

+      /* Float a fixed number here: */

+      if (format == PNG_NUMBER_FORMAT_fixed) if (count == 5) if (end > start)

+      {

+         /* End of the fraction, but maybe nothing was output?  In that case

+          * drop the decimal point.  If the number is a true zero handle that

+          * here.

+          */

+         if (output)

+            *--end = '.';

+         else if (number == 0) /* and !output */

+            *--end = '0';

+      }

+   }

+

+   return end;

+}

+#endif

+

+#ifdef PNG_WARNINGS_SUPPORTED

+/* This function is called whenever there is a non-fatal error.  This function

+ * should not be changed.  If there is a need to handle warnings differently,

+ * you should supply a replacement warning function and use

+ * png_set_error_fn() to replace the warning function at run-time.

+ */

+void PNGAPI

+png_warning(png_const_structrp png_ptr, png_const_charp warning_message)

+{

+   int offset = 0;

+   if (png_ptr != NULL)

+   {

+#ifdef PNG_ERROR_NUMBERS_SUPPORTED

+   if (png_ptr->flags&

+       (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))

+#endif

+      {

+         if (*warning_message == PNG_LITERAL_SHARP)

+         {

+            for (offset = 1; offset < 15; offset++)

+               if (warning_message[offset] == ' ')

+                  break;

+         }

+      }

+   }

+   if (png_ptr != NULL && png_ptr->warning_fn != NULL)

+      (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),

+         warning_message + offset);

+   else

+      png_default_warning(png_ptr, warning_message + offset);

+}

+

+/* These functions support 'formatted' warning messages with up to

+ * PNG_WARNING_PARAMETER_COUNT parameters.  In the format string the parameter

+ * is introduced by @<number>, where 'number' starts at 1.  This follows the

+ * standard established by X/Open for internationalizable error messages.

+ */

+void

+png_warning_parameter(png_warning_parameters p, int number,

+   png_const_charp string)

+{

+   if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT)

+      (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string);

+}

+

+void

+png_warning_parameter_unsigned(png_warning_parameters p, int number, int format,

+   png_alloc_size_t value)

+{

+   char buffer[PNG_NUMBER_BUFFER_SIZE];

+   png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));

+}

+

+void

+png_warning_parameter_signed(png_warning_parameters p, int number, int format,

+   png_int_32 value)

+{

+   png_alloc_size_t u;

+   png_charp str;

+   char buffer[PNG_NUMBER_BUFFER_SIZE];

+

+   /* Avoid overflow by doing the negate in a png_alloc_size_t: */

+   u = (png_alloc_size_t)value;

+   if (value < 0)

+      u = ~u + 1;

+

+   str = PNG_FORMAT_NUMBER(buffer, format, u);

+

+   if (value < 0 && str > buffer)

+      *--str = '-';

+

+   png_warning_parameter(p, number, str);

+}

+

+void

+png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p,

+   png_const_charp message)

+{

+   /* The internal buffer is just 192 bytes - enough for all our messages,

+    * overflow doesn't happen because this code checks!  If someone figures

+    * out how to send us a message longer than 192 bytes, all that will

+    * happen is that the message will be truncated appropriately.

+    */

+   size_t i = 0; /* Index in the msg[] buffer: */

+   char msg[192];

+

+   /* Each iteration through the following loop writes at most one character

+    * to msg[i++] then returns here to validate that there is still space for

+    * the trailing '\0'.  It may (in the case of a parameter) read more than

+    * one character from message[]; it must check for '\0' and continue to the

+    * test if it finds the end of string.

+    */

+   while (i<(sizeof msg)-1 && *message != '\0')

+   {

+      /* '@' at end of string is now just printed (previously it was skipped);

+       * it is an error in the calling code to terminate the string with @.

+       */

+      if (p != NULL && *message == '@' && message[1] != '\0')

+      {

+         int parameter_char = *++message; /* Consume the '@' */

+         static const char valid_parameters[] = "123456789";

+         int parameter = 0;

+

+         /* Search for the parameter digit, the index in the string is the

+          * parameter to use.

+          */

+         while (valid_parameters[parameter] != parameter_char &&

+            valid_parameters[parameter] != '\0')

+            ++parameter;

+

+         /* If the parameter digit is out of range it will just get printed. */

+         if (parameter < PNG_WARNING_PARAMETER_COUNT)

+         {

+            /* Append this parameter */

+            png_const_charp parm = p[parameter];

+            png_const_charp pend = p[parameter] + (sizeof p[parameter]);

+

+            /* No need to copy the trailing '\0' here, but there is no guarantee

+             * that parm[] has been initialized, so there is no guarantee of a

+             * trailing '\0':

+             */

+            while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend)

+               msg[i++] = *parm++;

+

+            /* Consume the parameter digit too: */

+            ++message;

+            continue;

+         }

+

+         /* else not a parameter and there is a character after the @ sign; just

+          * copy that.  This is known not to be '\0' because of the test above.

+          */

+      }

+

+      /* At this point *message can't be '\0', even in the bad parameter case

+       * above where there is a lone '@' at the end of the message string.

+       */

+      msg[i++] = *message++;

+   }

+

+   /* i is always less than (sizeof msg), so: */

+   msg[i] = '\0';

+

+   /* And this is the formatted message. It may be larger than

+    * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these

+    * are not (currently) formatted.

+    */

+   png_warning(png_ptr, msg);

+}

+#endif /* PNG_WARNINGS_SUPPORTED */

+

+#ifdef PNG_BENIGN_ERRORS_SUPPORTED

+void PNGAPI

+png_benign_error(png_const_structrp png_ptr, png_const_charp error_message)

+{

+   if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)

+   {

+#     ifdef PNG_READ_SUPPORTED

+         if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&

+            png_ptr->chunk_name != 0)

+            png_chunk_warning(png_ptr, error_message);

+         else

+#     endif

+      png_warning(png_ptr, error_message);

+   }

+

+   else

+   {

+#     ifdef PNG_READ_SUPPORTED

+         if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&

+            png_ptr->chunk_name != 0)

+            png_chunk_error(png_ptr, error_message);

+         else

+#     endif

+      png_error(png_ptr, error_message);

+   }

+}

+

+void /* PRIVATE */

+png_app_warning(png_const_structrp png_ptr, png_const_charp error_message)

+{

+  if (png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN)

+     png_warning(png_ptr, error_message);

+  else

+     png_error(png_ptr, error_message);

+}

+

+void /* PRIVATE */

+png_app_error(png_const_structrp png_ptr, png_const_charp error_message)

+{

+  if (png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN)

+     png_warning(png_ptr, error_message);

+  else

+     png_error(png_ptr, error_message);

+}

+#endif /* BENIGN_ERRORS */

+

+/* These utilities are used internally to build an error message that relates

+ * to the current chunk.  The chunk name comes from png_ptr->chunk_name,

+ * this is used to prefix the message.  The message is limited in length

+ * to 63 bytes, the name characters are output as hex digits wrapped in []

+ * if the character is invalid.

+ */

+#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))

+static PNG_CONST char png_digit[16] = {

+   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',

+   'A', 'B', 'C', 'D', 'E', 'F'

+};

+

+#define PNG_MAX_ERROR_TEXT 196 /* Currently limited be profile_error in png.c */

+#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED)

+static void /* PRIVATE */

+png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp

+    error_message)

+{

+   png_uint_32 chunk_name = png_ptr->chunk_name;

+   int iout = 0, ishift = 24;

+

+   while (ishift >= 0)

+   {

+      int c = (int)(chunk_name >> ishift) & 0xff;

+

+      ishift -= 8;

+      if (isnonalpha(c))

+      {

+         buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET;

+         buffer[iout++] = png_digit[(c & 0xf0) >> 4];

+         buffer[iout++] = png_digit[c & 0x0f];

+         buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET;

+      }

+

+      else

+      {

+         buffer[iout++] = (char)c;

+      }

+   }

+

+   if (error_message == NULL)

+      buffer[iout] = '\0';

+

+   else

+   {

+      int iin = 0;

+

+      buffer[iout++] = ':';

+      buffer[iout++] = ' ';

+

+      while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0')

+         buffer[iout++] = error_message[iin++];

+

+      /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */

+      buffer[iout] = '\0';

+   }

+}

+#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */

+

+#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)

+PNG_FUNCTION(void,PNGAPI

+png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message),

+   PNG_NORETURN)

+{

+   char msg[18+PNG_MAX_ERROR_TEXT];

+   if (png_ptr == NULL)

+      png_error(png_ptr, error_message);

+

+   else

+   {

+      png_format_buffer(png_ptr, msg, error_message);

+      png_error(png_ptr, msg);

+   }

+}

+#endif /* PNG_READ_SUPPORTED && PNG_ERROR_TEXT_SUPPORTED */

+

+#ifdef PNG_WARNINGS_SUPPORTED

+void PNGAPI

+png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message)

+{

+   char msg[18+PNG_MAX_ERROR_TEXT];

+   if (png_ptr == NULL)

+      png_warning(png_ptr, warning_message);

+

+   else

+   {

+      png_format_buffer(png_ptr, msg, warning_message);

+      png_warning(png_ptr, msg);

+   }

+}

+#endif /* PNG_WARNINGS_SUPPORTED */

+

+#ifdef PNG_READ_SUPPORTED

+#ifdef PNG_BENIGN_ERRORS_SUPPORTED

+void PNGAPI

+png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp

+    error_message)

+{

+   if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)

+      png_chunk_warning(png_ptr, error_message);

+

+   else

+      png_chunk_error(png_ptr, error_message);

+}

+#endif

+#endif /* PNG_READ_SUPPORTED */

+

+void /* PRIVATE */

+png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)

+{

+   /* This is always supported, but for just read or just write it

+    * unconditionally does the right thing.

+    */

+#  if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)

+      if (png_ptr->mode & PNG_IS_READ_STRUCT)

+#  endif

+

+#  ifdef PNG_READ_SUPPORTED

+      {

+         if (error < PNG_CHUNK_ERROR)

+            png_chunk_warning(png_ptr, message);

+

+         else

+            png_chunk_benign_error(png_ptr, message);

+      }

+#  endif

+

+#  if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)

+      else if (!(png_ptr->mode & PNG_IS_READ_STRUCT))

+#  endif

+

+#  ifdef PNG_WRITE_SUPPORTED

+      {

+         if (error < PNG_CHUNK_WRITE_ERROR)

+            png_app_warning(png_ptr, message);

+

+         else

+            png_app_error(png_ptr, message);

+      }

+#  endif

+}

+

+#ifdef PNG_ERROR_TEXT_SUPPORTED

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+PNG_FUNCTION(void,

+png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)

+{

+#  define fixed_message "fixed point overflow in "

+#  define fixed_message_ln ((sizeof fixed_message)-1)

+   int  iin;

+   char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT];

+   memcpy(msg, fixed_message, fixed_message_ln);

+   iin = 0;

+   if (name != NULL) while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)

+   {

+      msg[fixed_message_ln + iin] = name[iin];

+      ++iin;

+   }

+   msg[fixed_message_ln + iin] = 0;

+   png_error(png_ptr, msg);

+}

+#endif

+#endif

+

+#ifdef PNG_SETJMP_SUPPORTED

+/* This API only exists if ANSI-C style error handling is used,

+ * otherwise it is necessary for png_default_error to be overridden.

+ */

+jmp_buf* PNGAPI

+png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn,

+    size_t jmp_buf_size)

+{

+   /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value

+    * and it must not change after that.  Libpng doesn't care how big the

+    * buffer is, just that it doesn't change.

+    *

+    * If the buffer size is no *larger* than the size of jmp_buf when libpng is

+    * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0

+    * semantics that this call will not fail.  If the size is larger, however,

+    * the buffer is allocated and this may fail, causing the function to return

+    * NULL.

+    */

+   if (png_ptr == NULL)

+      return NULL;

+

+   if (png_ptr->jmp_buf_ptr == NULL)

+   {

+      png_ptr->jmp_buf_size = 0; /* not allocated */

+

+      if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local))

+         png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local;

+

+      else

+      {

+         png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *,

+            png_malloc_warn(png_ptr, jmp_buf_size));

+

+         if (png_ptr->jmp_buf_ptr == NULL)

+            return NULL; /* new NULL return on OOM */

+

+         png_ptr->jmp_buf_size = jmp_buf_size;

+      }

+   }

+

+   else /* Already allocated: check the size */

+   {

+      size_t size = png_ptr->jmp_buf_size;

+

+      if (size == 0)

+      {

+         size = (sizeof png_ptr->jmp_buf_local);

+         if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local)

+         {

+            /* This is an internal error in libpng: somehow we have been left

+             * with a stack allocated jmp_buf when the application regained

+             * control.  It's always possible to fix this up, but for the moment

+             * this is a png_error because that makes it easy to detect.

+             */

+            png_error(png_ptr, "Libpng jmp_buf still allocated");

+            /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */

+         }

+      }

+

+      if (size != jmp_buf_size)

+      {

+         png_warning(png_ptr, "Application jmp_buf size changed");

+         return NULL; /* caller will probably crash: no choice here */

+      }

+   }

+

+   /* Finally fill in the function, now we have a satisfactory buffer. It is

+    * valid to change the function on every call.

+    */

+   png_ptr->longjmp_fn = longjmp_fn;

+   return png_ptr->jmp_buf_ptr;

+}

+

+void /* PRIVATE */

+png_free_jmpbuf(png_structrp png_ptr)

+{

+   if (png_ptr != NULL)

+   {

+      jmp_buf *jb = png_ptr->jmp_buf_ptr;

+

+      /* A size of 0 is used to indicate a local, stack, allocation of the

+       * pointer; used here and in png.c

+       */

+      if (jb != NULL && png_ptr->jmp_buf_size > 0)

+      {

+

+         /* This stuff is so that a failure to free the error control structure

+          * does not leave libpng in a state with no valid error handling: the

+          * free always succeeds, if there is an error it gets ignored.

+          */

+         if (jb != &png_ptr->jmp_buf_local)

+         {

+            /* Make an internal, libpng, jmp_buf to return here */

+            jmp_buf free_jmp_buf;

+

+            if (!setjmp(free_jmp_buf))

+            {

+               png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */

+               png_ptr->jmp_buf_size = 0; /* stack allocation */

+               png_ptr->longjmp_fn = longjmp;

+               png_free(png_ptr, jb); /* Return to setjmp on error */

+            }

+         }

+      }

+

+      /* *Always* cancel everything out: */

+      png_ptr->jmp_buf_size = 0;

+      png_ptr->jmp_buf_ptr = NULL;

+      png_ptr->longjmp_fn = 0;

+   }

+}

+#endif

+

+/* This is the default error handling function.  Note that replacements for

+ * this function MUST NOT RETURN, or the program will likely crash.  This

+ * function is used by default, or if the program supplies NULL for the

+ * error function pointer in png_set_error_fn().

+ */

+static PNG_FUNCTION(void /* PRIVATE */,

+png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),

+   PNG_NORETURN)

+{

+#ifdef PNG_CONSOLE_IO_SUPPORTED

+#ifdef PNG_ERROR_NUMBERS_SUPPORTED

+   /* Check on NULL only added in 1.5.4 */

+   if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)

+   {

+      /* Strip "#nnnn " from beginning of error message. */

+      int offset;

+      char error_number[16];

+      for (offset = 0; offset<15; offset++)

+      {

+         error_number[offset] = error_message[offset + 1];

+         if (error_message[offset] == ' ')

+            break;

+      }

+

+      if ((offset > 1) && (offset < 15))

+      {

+         error_number[offset - 1] = '\0';

+         fprintf(stderr, "libpng error no. %s: %s",

+             error_number, error_message + offset + 1);

+         fprintf(stderr, PNG_STRING_NEWLINE);

+      }

+

+      else

+      {

+         fprintf(stderr, "libpng error: %s, offset=%d",

+             error_message, offset);

+         fprintf(stderr, PNG_STRING_NEWLINE);

+      }

+   }

+   else

+#endif

+   {

+      fprintf(stderr, "libpng error: %s", error_message ? error_message :

+         "undefined");

+      fprintf(stderr, PNG_STRING_NEWLINE);

+   }

+#else

+   PNG_UNUSED(error_message) /* Make compiler happy */

+#endif

+   png_longjmp(png_ptr, 1);

+}

+

+PNG_FUNCTION(void,PNGAPI

+png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)

+{

+#ifdef PNG_SETJMP_SUPPORTED

+   if (png_ptr && png_ptr->longjmp_fn && png_ptr->jmp_buf_ptr)

+      png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val);

+#endif

+

+   /* Here if not setjmp support or if png_ptr is null. */

+   PNG_ABORT();

+}

+

+#ifdef PNG_WARNINGS_SUPPORTED

+/* This function is called when there is a warning, but the library thinks

+ * it can continue anyway.  Replacement functions don't have to do anything

+ * here if you don't want them to.  In the default configuration, png_ptr is

+ * not used, but it is passed in case it may be useful.

+ */

+static void /* PRIVATE */

+png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)

+{

+#ifdef PNG_CONSOLE_IO_SUPPORTED

+#  ifdef PNG_ERROR_NUMBERS_SUPPORTED

+   if (*warning_message == PNG_LITERAL_SHARP)

+   {

+      int offset;

+      char warning_number[16];

+      for (offset = 0; offset < 15; offset++)

+      {

+         warning_number[offset] = warning_message[offset + 1];

+         if (warning_message[offset] == ' ')

+            break;

+      }

+

+      if ((offset > 1) && (offset < 15))

+      {

+         warning_number[offset + 1] = '\0';

+         fprintf(stderr, "libpng warning no. %s: %s",

+             warning_number, warning_message + offset);

+         fprintf(stderr, PNG_STRING_NEWLINE);

+      }

+

+      else

+      {

+         fprintf(stderr, "libpng warning: %s",

+             warning_message);

+         fprintf(stderr, PNG_STRING_NEWLINE);

+      }

+   }

+   else

+#  endif

+

+   {

+      fprintf(stderr, "libpng warning: %s", warning_message);

+      fprintf(stderr, PNG_STRING_NEWLINE);

+   }

+#else

+   PNG_UNUSED(warning_message) /* Make compiler happy */

+#endif

+   PNG_UNUSED(png_ptr) /* Make compiler happy */

+}

+#endif /* PNG_WARNINGS_SUPPORTED */

+

+/* This function is called when the application wants to use another method

+ * of handling errors and warnings.  Note that the error function MUST NOT

+ * return to the calling routine or serious problems will occur.  The return

+ * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1)

+ */

+void PNGAPI

+png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr,

+    png_error_ptr error_fn, png_error_ptr warning_fn)

+{

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->error_ptr = error_ptr;

+   png_ptr->error_fn = error_fn;

+#ifdef PNG_WARNINGS_SUPPORTED

+   png_ptr->warning_fn = warning_fn;

+#else

+   PNG_UNUSED(warning_fn)

+#endif

+}

+

+

+/* This function returns a pointer to the error_ptr associated with the user

+ * functions.  The application should free any memory associated with this

+ * pointer before png_write_destroy and png_read_destroy are called.

+ */

+png_voidp PNGAPI

+png_get_error_ptr(png_const_structrp png_ptr)

+{

+   if (png_ptr == NULL)

+      return NULL;

+

+   return ((png_voidp)png_ptr->error_ptr);

+}

+

+

+#ifdef PNG_ERROR_NUMBERS_SUPPORTED

+void PNGAPI

+png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)

+{

+   if (png_ptr != NULL)

+   {

+      png_ptr->flags &=

+         ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |

+         PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);

+   }

+}

+#endif

+

+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\

+   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)

+   /* Currently the above both depend on SETJMP_SUPPORTED, however it would be

+    * possible to implement without setjmp support just so long as there is some

+    * way to handle the error return here:

+    */

+PNG_FUNCTION(void /* PRIVATE */,

+png_safe_error,(png_structp png_nonconst_ptr, png_const_charp error_message),

+   PNG_NORETURN)

+{

+   const png_const_structrp png_ptr = png_nonconst_ptr;

+   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);

+

+   /* An error is always logged here, overwriting anything (typically a warning)

+    * that is already there:

+    */

+   if (image != NULL)

+   {

+      png_safecat(image->message, (sizeof image->message), 0, error_message);

+      image->warning_or_error |= PNG_IMAGE_ERROR;

+

+      /* Retrieve the jmp_buf from within the png_control, making this work for

+       * C++ compilation too is pretty tricky: C++ wants a pointer to the first

+       * element of a jmp_buf, but C doesn't tell us the type of that.

+       */

+      if (image->opaque != NULL && image->opaque->error_buf != NULL)

+         longjmp(png_control_jmp_buf(image->opaque), 1);

+

+      /* Missing longjmp buffer, the following is to help debugging: */

+      {

+         size_t pos = png_safecat(image->message, (sizeof image->message), 0,

+            "bad longjmp: ");

+         png_safecat(image->message, (sizeof image->message), pos,

+             error_message);

+      }

+   }

+

+   /* Here on an internal programming error. */

+   abort();

+}

+

+#ifdef PNG_WARNINGS_SUPPORTED

+void /* PRIVATE */

+png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)

+{

+   const png_const_structrp png_ptr = png_nonconst_ptr;

+   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);

+

+   /* A warning is only logged if there is no prior warning or error. */

+   if (image->warning_or_error == 0)

+   {

+      png_safecat(image->message, (sizeof image->message), 0, warning_message);

+      image->warning_or_error |= PNG_IMAGE_WARNING;

+   }

+}

+#endif

+

+int /* PRIVATE */

+png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg)

+{

+   volatile png_imagep image = image_in;

+   volatile int result;

+   volatile png_voidp saved_error_buf;

+   jmp_buf safe_jmpbuf;

+

+   /* Safely execute function(arg) with png_error returning to this function. */

+   saved_error_buf = image->opaque->error_buf;

+   result = setjmp(safe_jmpbuf) == 0;

+

+   if (result)

+   {

+

+      image->opaque->error_buf = safe_jmpbuf;

+      result = function(arg);

+   }

+

+   image->opaque->error_buf = saved_error_buf;

+

+   /* And do the cleanup prior to any failure return. */

+   if (!result)

+      png_image_free(image);

+

+   return result;

+}

+#endif /* SIMPLIFIED READ/WRITE */

+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngget.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngget.c
new file mode 100644
index 0000000..56ba970
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngget.c
@@ -0,0 +1,1178 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngget.c - retrieval of values from info struct

+ *

+ * Last changed in libpng 1.6.1 [March 28, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ */

+

+#include "pngpriv.h"

+

+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

+

+png_uint_32 PNGAPI

+png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    png_uint_32 flag)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return(info_ptr->valid & flag);

+

+   return(0);

+}

+

+png_size_t PNGAPI

+png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return(info_ptr->rowbytes);

+

+   return(0);

+}

+

+#ifdef PNG_INFO_IMAGE_SUPPORTED

+png_bytepp PNGAPI

+png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return(info_ptr->row_pointers);

+

+   return(0);

+}

+#endif

+

+#ifdef PNG_EASY_ACCESS_SUPPORTED

+/* Easy access to info, added in libpng-0.99 */

+png_uint_32 PNGAPI

+png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return info_ptr->width;

+

+   return (0);

+}

+

+png_uint_32 PNGAPI

+png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return info_ptr->height;

+

+   return (0);

+}

+

+png_byte PNGAPI

+png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return info_ptr->bit_depth;

+

+   return (0);

+}

+

+png_byte PNGAPI

+png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return info_ptr->color_type;

+

+   return (0);

+}

+

+png_byte PNGAPI

+png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return info_ptr->filter_type;

+

+   return (0);

+}

+

+png_byte PNGAPI

+png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return info_ptr->interlace_type;

+

+   return (0);

+}

+

+png_byte PNGAPI

+png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return info_ptr->compression_type;

+

+   return (0);

+}

+

+png_uint_32 PNGAPI

+png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp

+   info_ptr)

+{

+#ifdef PNG_pHYs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))

+      {

+         png_debug1(1, "in %s retrieval function",

+             "png_get_x_pixels_per_meter");

+

+         if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)

+            return (info_ptr->x_pixels_per_unit);

+      }

+#endif

+

+   return (0);

+}

+

+png_uint_32 PNGAPI

+png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp

+    info_ptr)

+{

+#ifdef PNG_pHYs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))

+   {

+      png_debug1(1, "in %s retrieval function",

+          "png_get_y_pixels_per_meter");

+

+      if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)

+         return (info_ptr->y_pixels_per_unit);

+   }

+#endif

+

+   return (0);

+}

+

+png_uint_32 PNGAPI

+png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+#ifdef PNG_pHYs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))

+   {

+      png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter");

+

+      if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER &&

+          info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit)

+         return (info_ptr->x_pixels_per_unit);

+   }

+#endif

+

+   return (0);

+}

+

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+float PNGAPI

+png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp

+   info_ptr)

+{

+#ifdef PNG_READ_pHYs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))

+   {

+      png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio");

+

+      if (info_ptr->x_pixels_per_unit != 0)

+         return ((float)((float)info_ptr->y_pixels_per_unit

+             /(float)info_ptr->x_pixels_per_unit));

+   }

+#else

+   PNG_UNUSED(png_ptr)

+   PNG_UNUSED(info_ptr)

+#endif

+

+   return ((float)0.0);

+}

+#endif

+

+#ifdef PNG_FIXED_POINT_SUPPORTED

+png_fixed_point PNGAPI

+png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr,

+    png_const_inforp info_ptr)

+{

+#ifdef PNG_READ_pHYs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)

+       && info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0

+       && info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX

+       && info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX)

+   {

+      png_fixed_point res;

+

+      png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed");

+

+      /* The following casts work because a PNG 4 byte integer only has a valid

+       * range of 0..2^31-1; otherwise the cast might overflow.

+       */

+      if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1,

+          (png_int_32)info_ptr->x_pixels_per_unit))

+         return res;

+   }

+#else

+   PNG_UNUSED(png_ptr)

+   PNG_UNUSED(info_ptr)

+#endif

+

+   return 0;

+}

+#endif

+

+png_int_32 PNGAPI

+png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+#ifdef PNG_oFFs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))

+   {

+      png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns");

+

+      if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)

+         return (info_ptr->x_offset);

+   }

+#endif

+

+   return (0);

+}

+

+png_int_32 PNGAPI

+png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+#ifdef PNG_oFFs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))

+   {

+      png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns");

+

+      if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)

+         return (info_ptr->y_offset);

+   }

+#endif

+

+   return (0);

+}

+

+png_int_32 PNGAPI

+png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+#ifdef PNG_oFFs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))

+   {

+      png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels");

+

+      if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)

+         return (info_ptr->x_offset);

+   }

+#endif

+

+   return (0);

+}

+

+png_int_32 PNGAPI

+png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+#ifdef PNG_oFFs_SUPPORTED

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))

+   {

+      png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels");

+

+      if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)

+         return (info_ptr->y_offset);

+   }

+#endif

+

+   return (0);

+}

+

+#ifdef PNG_INCH_CONVERSIONS_SUPPORTED

+static png_uint_32

+ppi_from_ppm(png_uint_32 ppm)

+{

+#if 0

+   /* The conversion is *(2.54/100), in binary (32 digits):

+    * .00000110100000001001110101001001

+    */

+   png_uint_32 t1001, t1101;

+   ppm >>= 1;                  /* .1 */

+   t1001 = ppm + (ppm >> 3);   /* .1001 */

+   t1101 = t1001 + (ppm >> 1); /* .1101 */

+   ppm >>= 20;                 /* .000000000000000000001 */

+   t1101 += t1101 >> 15;       /* .1101000000000001101 */

+   t1001 >>= 11;               /* .000000000001001 */

+   t1001 += t1001 >> 12;       /* .000000000001001000000001001 */

+   ppm += t1001;               /* .000000000001001000001001001 */

+   ppm += t1101;               /* .110100000001001110101001001 */

+   return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */

+#else

+   /* The argument is a PNG unsigned integer, so it is not permitted

+    * to be bigger than 2^31.

+    */

+   png_fixed_point result;

+   if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127,

+       5000))

+      return result;

+

+   /* Overflow. */

+   return 0;

+#endif

+}

+

+png_uint_32 PNGAPI

+png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr));

+}

+

+png_uint_32 PNGAPI

+png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr));

+}

+

+png_uint_32 PNGAPI

+png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr));

+}

+

+#ifdef PNG_FIXED_POINT_SUPPORTED

+static png_fixed_point

+png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns)

+{

+   /* Convert from metres * 1,000,000 to inches * 100,000, meters to

+    * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127.

+    * Notice that this can overflow - a warning is output and 0 is

+    * returned.

+    */

+   return png_muldiv_warn(png_ptr, microns, 500, 127);

+}

+

+png_fixed_point PNGAPI

+png_get_x_offset_inches_fixed(png_const_structrp png_ptr,

+    png_const_inforp info_ptr)

+{

+   return png_fixed_inches_from_microns(png_ptr,

+       png_get_x_offset_microns(png_ptr, info_ptr));

+}

+#endif

+

+#ifdef PNG_FIXED_POINT_SUPPORTED

+png_fixed_point PNGAPI

+png_get_y_offset_inches_fixed(png_const_structrp png_ptr,

+    png_const_inforp info_ptr)

+{

+   return png_fixed_inches_from_microns(png_ptr,

+       png_get_y_offset_microns(png_ptr, info_ptr));

+}

+#endif

+

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+float PNGAPI

+png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   /* To avoid the overflow do the conversion directly in floating

+    * point.

+    */

+   return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937);

+}

+#endif

+

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+float PNGAPI

+png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   /* To avoid the overflow do the conversion directly in floating

+    * point.

+    */

+   return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937);

+}

+#endif

+

+#ifdef PNG_pHYs_SUPPORTED

+png_uint_32 PNGAPI

+png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)

+{

+   png_uint_32 retval = 0;

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))

+   {

+      png_debug1(1, "in %s retrieval function", "pHYs");

+

+      if (res_x != NULL)

+      {

+         *res_x = info_ptr->x_pixels_per_unit;

+         retval |= PNG_INFO_pHYs;

+      }

+

+      if (res_y != NULL)

+      {

+         *res_y = info_ptr->y_pixels_per_unit;

+         retval |= PNG_INFO_pHYs;

+      }

+

+      if (unit_type != NULL)

+      {

+         *unit_type = (int)info_ptr->phys_unit_type;

+         retval |= PNG_INFO_pHYs;

+

+         if (*unit_type == 1)

+         {

+            if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50);

+            if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50);

+         }

+      }

+   }

+

+   return (retval);

+}

+#endif /* PNG_pHYs_SUPPORTED */

+#endif  /* PNG_INCH_CONVERSIONS_SUPPORTED */

+

+/* png_get_channels really belongs in here, too, but it's been around longer */

+

+#endif  /* PNG_EASY_ACCESS_SUPPORTED */

+

+

+png_byte PNGAPI

+png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return(info_ptr->channels);

+

+   return (0);

+}

+

+#ifdef PNG_READ_SUPPORTED

+png_const_bytep PNGAPI

+png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return(info_ptr->signature);

+

+   return (NULL);

+}

+#endif

+

+#ifdef PNG_bKGD_SUPPORTED

+png_uint_32 PNGAPI

+png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,

+   png_color_16p *background)

+{

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)

+       && background != NULL)

+   {

+      png_debug1(1, "in %s retrieval function", "bKGD");

+

+      *background = &(info_ptr->background);

+      return (PNG_INFO_bKGD);

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_cHRM_SUPPORTED

+/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the

+ * same time to correct the rgb grayscale coefficient defaults obtained from the

+ * cHRM chunk in 1.5.4

+ */

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+png_uint_32 PNGAPI

+png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    double *white_x, double *white_y, double *red_x, double *red_y,

+    double *green_x, double *green_y, double *blue_x, double *blue_y)

+{

+   /* Quiet API change: this code used to only return the end points if a cHRM

+    * chunk was present, but the end points can also come from iCCP or sRGB

+    * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and

+    * the png_set_ APIs merely check that set end points are mutually

+    * consistent.

+    */

+   if (png_ptr != NULL && info_ptr != NULL &&

+      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS))

+   {

+      png_debug1(1, "in %s retrieval function", "cHRM");

+

+      if (white_x != NULL)

+         *white_x = png_float(png_ptr,

+            info_ptr->colorspace.end_points_xy.whitex, "cHRM white X");

+      if (white_y != NULL)

+         *white_y = png_float(png_ptr,

+            info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y");

+      if (red_x != NULL)

+         *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx,

+            "cHRM red X");

+      if (red_y != NULL)

+         *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy,

+            "cHRM red Y");

+      if (green_x != NULL)

+         *green_x = png_float(png_ptr,

+            info_ptr->colorspace.end_points_xy.greenx, "cHRM green X");

+      if (green_y != NULL)

+         *green_y = png_float(png_ptr,

+            info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y");

+      if (blue_x != NULL)

+         *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex,

+            "cHRM blue X");

+      if (blue_y != NULL)

+         *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey,

+            "cHRM blue Y");

+      return (PNG_INFO_cHRM);

+   }

+

+   return (0);

+}

+

+png_uint_32 PNGAPI

+png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,

+   double *red_X, double *red_Y, double *red_Z, double *green_X,

+   double *green_Y, double *green_Z, double *blue_X, double *blue_Y,

+   double *blue_Z)

+{

+   if (png_ptr != NULL && info_ptr != NULL &&

+      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS))

+   {

+      png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)");

+

+      if (red_X != NULL)

+         *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X,

+            "cHRM red X");

+      if (red_Y != NULL)

+         *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y,

+            "cHRM red Y");

+      if (red_Z != NULL)

+         *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z,

+            "cHRM red Z");

+      if (green_X != NULL)

+         *green_X = png_float(png_ptr,

+            info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X");

+      if (green_Y != NULL)

+         *green_Y = png_float(png_ptr,

+            info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y");

+      if (green_Z != NULL)

+         *green_Z = png_float(png_ptr,

+            info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z");

+      if (blue_X != NULL)

+         *blue_X = png_float(png_ptr,

+            info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X");

+      if (blue_Y != NULL)

+         *blue_Y = png_float(png_ptr,

+            info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y");

+      if (blue_Z != NULL)

+         *blue_Z = png_float(png_ptr,

+            info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z");

+      return (PNG_INFO_cHRM);

+   }

+

+   return (0);

+}

+#  endif

+

+#  ifdef PNG_FIXED_POINT_SUPPORTED

+png_uint_32 PNGAPI

+png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    png_fixed_point *int_red_X, png_fixed_point *int_red_Y,

+    png_fixed_point *int_red_Z, png_fixed_point *int_green_X,

+    png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,

+    png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,

+    png_fixed_point *int_blue_Z)

+{

+   if (png_ptr != NULL && info_ptr != NULL &&

+      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS))

+   {

+      png_debug1(1, "in %s retrieval function", "cHRM_XYZ");

+

+      if (int_red_X != NULL)

+         *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X;

+      if (int_red_Y != NULL)

+         *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y;

+      if (int_red_Z != NULL)

+         *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z;

+      if (int_green_X != NULL)

+         *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X;

+      if (int_green_Y != NULL)

+         *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y;

+      if (int_green_Z != NULL)

+         *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z;

+      if (int_blue_X != NULL)

+         *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X;

+      if (int_blue_Y != NULL)

+         *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y;

+      if (int_blue_Z != NULL)

+         *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z;

+      return (PNG_INFO_cHRM);

+   }

+

+   return (0);

+}

+

+png_uint_32 PNGAPI

+png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x,

+    png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y,

+    png_fixed_point *blue_x, png_fixed_point *blue_y)

+{

+   png_debug1(1, "in %s retrieval function", "cHRM");

+

+   if (png_ptr != NULL && info_ptr != NULL &&

+      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS))

+   {

+      if (white_x != NULL)

+         *white_x = info_ptr->colorspace.end_points_xy.whitex;

+      if (white_y != NULL)

+         *white_y = info_ptr->colorspace.end_points_xy.whitey;

+      if (red_x != NULL)

+         *red_x = info_ptr->colorspace.end_points_xy.redx;

+      if (red_y != NULL)

+         *red_y = info_ptr->colorspace.end_points_xy.redy;

+      if (green_x != NULL)

+         *green_x = info_ptr->colorspace.end_points_xy.greenx;

+      if (green_y != NULL)

+         *green_y = info_ptr->colorspace.end_points_xy.greeny;

+      if (blue_x != NULL)

+         *blue_x = info_ptr->colorspace.end_points_xy.bluex;

+      if (blue_y != NULL)

+         *blue_y = info_ptr->colorspace.end_points_xy.bluey;

+      return (PNG_INFO_cHRM);

+   }

+

+   return (0);

+}

+#  endif

+#endif

+

+#ifdef PNG_gAMA_SUPPORTED

+#  ifdef PNG_FIXED_POINT_SUPPORTED

+png_uint_32 PNGAPI

+png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    png_fixed_point *file_gamma)

+{

+   png_debug1(1, "in %s retrieval function", "gAMA");

+

+   if (png_ptr != NULL && info_ptr != NULL &&

+      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) &&

+      file_gamma != NULL)

+   {

+      *file_gamma = info_ptr->colorspace.gamma;

+      return (PNG_INFO_gAMA);

+   }

+

+   return (0);

+}

+#  endif

+

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+png_uint_32 PNGAPI

+png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    double *file_gamma)

+{

+   png_debug1(1, "in %s retrieval function", "gAMA(float)");

+

+   if (png_ptr != NULL && info_ptr != NULL &&

+      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) &&

+      file_gamma != NULL)

+   {

+      *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma,

+         "png_get_gAMA");

+      return (PNG_INFO_gAMA);

+   }

+

+   return (0);

+}

+#  endif

+#endif

+

+#ifdef PNG_sRGB_SUPPORTED

+png_uint_32 PNGAPI

+png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    int *file_srgb_intent)

+{

+   png_debug1(1, "in %s retrieval function", "sRGB");

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)

+       && file_srgb_intent != NULL)

+   {

+      *file_srgb_intent = info_ptr->colorspace.rendering_intent;

+      return (PNG_INFO_sRGB);

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_iCCP_SUPPORTED

+png_uint_32 PNGAPI

+png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_charpp name, int *compression_type,

+    png_bytepp profile, png_uint_32 *proflen)

+{

+   png_debug1(1, "in %s retrieval function", "iCCP");

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)

+       && name != NULL && compression_type != NULL && profile != NULL &&

+		 proflen != NULL)

+   {

+      *name = info_ptr->iccp_name;

+      *profile = info_ptr->iccp_profile;

+      *proflen = png_get_uint_32(info_ptr->iccp_profile);

+      /* This is somewhat irrelevant since the profile data returned has

+       * actually been uncompressed.

+       */

+      *compression_type = PNG_COMPRESSION_TYPE_BASE;

+      return (PNG_INFO_iCCP);

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_sPLT_SUPPORTED

+int PNGAPI

+png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_sPLT_tpp spalettes)

+{

+   if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL)

+   {

+      *spalettes = info_ptr->splt_palettes;

+      return info_ptr->splt_palettes_num;

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_hIST_SUPPORTED

+png_uint_32 PNGAPI

+png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_uint_16p *hist)

+{

+   png_debug1(1, "in %s retrieval function", "hIST");

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)

+       && hist != NULL)

+   {

+      *hist = info_ptr->hist;

+      return (PNG_INFO_hIST);

+   }

+

+   return (0);

+}

+#endif

+

+png_uint_32 PNGAPI

+png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    png_uint_32 *width, png_uint_32 *height, int *bit_depth,

+    int *color_type, int *interlace_type, int *compression_type,

+    int *filter_type)

+{

+   png_debug1(1, "in %s retrieval function", "IHDR");

+

+   if (png_ptr == NULL || info_ptr == NULL || width == NULL ||

+       height == NULL || bit_depth == NULL || color_type == NULL)

+      return (0);

+

+   *width = info_ptr->width;

+   *height = info_ptr->height;

+   *bit_depth = info_ptr->bit_depth;

+   *color_type = info_ptr->color_type;

+

+   if (compression_type != NULL)

+      *compression_type = info_ptr->compression_type;

+

+   if (filter_type != NULL)

+      *filter_type = info_ptr->filter_type;

+

+   if (interlace_type != NULL)

+      *interlace_type = info_ptr->interlace_type;

+

+   /* This is redundant if we can be sure that the info_ptr values were all

+    * assigned in png_set_IHDR().  We do the check anyhow in case an

+    * application has ignored our advice not to mess with the members

+    * of info_ptr directly.

+    */

+   png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height,

+       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,

+       info_ptr->compression_type, info_ptr->filter_type);

+

+   return (1);

+}

+

+#ifdef PNG_oFFs_SUPPORTED

+png_uint_32 PNGAPI

+png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)

+{

+   png_debug1(1, "in %s retrieval function", "oFFs");

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)

+       && offset_x != NULL && offset_y != NULL && unit_type != NULL)

+   {

+      *offset_x = info_ptr->x_offset;

+      *offset_y = info_ptr->y_offset;

+      *unit_type = (int)info_ptr->offset_unit_type;

+      return (PNG_INFO_oFFs);

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_pCAL_SUPPORTED

+png_uint_32 PNGAPI

+png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,

+    png_charp *units, png_charpp *params)

+{

+   png_debug1(1, "in %s retrieval function", "pCAL");

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)

+       && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&

+       nparams != NULL && units != NULL && params != NULL)

+   {

+      *purpose = info_ptr->pcal_purpose;

+      *X0 = info_ptr->pcal_X0;

+      *X1 = info_ptr->pcal_X1;

+      *type = (int)info_ptr->pcal_type;

+      *nparams = (int)info_ptr->pcal_nparams;

+      *units = info_ptr->pcal_units;

+      *params = info_ptr->pcal_params;

+      return (PNG_INFO_pCAL);

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_sCAL_SUPPORTED

+#  ifdef PNG_FIXED_POINT_SUPPORTED

+#    if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \

+         defined(PNG_FLOATING_POINT_SUPPORTED)

+png_uint_32 PNGAPI

+png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    int *unit, png_fixed_point *width, png_fixed_point *height)

+{

+   if (png_ptr != NULL && info_ptr != NULL &&

+       (info_ptr->valid & PNG_INFO_sCAL))

+   {

+      *unit = info_ptr->scal_unit;

+      /*TODO: make this work without FP support; the API is currently eliminated

+       * if neither floating point APIs nor internal floating point arithmetic

+       * are enabled.

+       */

+      *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width");

+      *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height),

+         "sCAL height");

+      return (PNG_INFO_sCAL);

+   }

+

+   return(0);

+}

+#    endif /* FLOATING_ARITHMETIC */

+#  endif /* FIXED_POINT */

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+png_uint_32 PNGAPI

+png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    int *unit, double *width, double *height)

+{

+   if (png_ptr != NULL && info_ptr != NULL &&

+       (info_ptr->valid & PNG_INFO_sCAL))

+   {

+      *unit = info_ptr->scal_unit;

+      *width = atof(info_ptr->scal_s_width);

+      *height = atof(info_ptr->scal_s_height);

+      return (PNG_INFO_sCAL);

+   }

+

+   return(0);

+}

+#  endif /* FLOATING POINT */

+png_uint_32 PNGAPI

+png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    int *unit, png_charpp width, png_charpp height)

+{

+   if (png_ptr != NULL && info_ptr != NULL &&

+       (info_ptr->valid & PNG_INFO_sCAL))

+   {

+      *unit = info_ptr->scal_unit;

+      *width = info_ptr->scal_s_width;

+      *height = info_ptr->scal_s_height;

+      return (PNG_INFO_sCAL);

+   }

+

+   return(0);

+}

+#endif /* sCAL */

+

+#ifdef PNG_pHYs_SUPPORTED

+png_uint_32 PNGAPI

+png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr,

+    png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)

+{

+   png_uint_32 retval = 0;

+

+   png_debug1(1, "in %s retrieval function", "pHYs");

+

+   if (png_ptr != NULL && info_ptr != NULL &&

+       (info_ptr->valid & PNG_INFO_pHYs))

+   {

+      if (res_x != NULL)

+      {

+         *res_x = info_ptr->x_pixels_per_unit;

+         retval |= PNG_INFO_pHYs;

+      }

+

+      if (res_y != NULL)

+      {

+         *res_y = info_ptr->y_pixels_per_unit;

+         retval |= PNG_INFO_pHYs;

+      }

+

+      if (unit_type != NULL)

+      {

+         *unit_type = (int)info_ptr->phys_unit_type;

+         retval |= PNG_INFO_pHYs;

+      }

+   }

+

+   return (retval);

+}

+#endif /* pHYs */

+

+png_uint_32 PNGAPI

+png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_colorp *palette, int *num_palette)

+{

+   png_debug1(1, "in %s retrieval function", "PLTE");

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE)

+       && palette != NULL)

+   {

+      *palette = info_ptr->palette;

+      *num_palette = info_ptr->num_palette;

+      png_debug1(3, "num_palette = %d", *num_palette);

+      return (PNG_INFO_PLTE);

+   }

+

+   return (0);

+}

+

+#ifdef PNG_sBIT_SUPPORTED

+png_uint_32 PNGAPI

+png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_color_8p *sig_bit)

+{

+   png_debug1(1, "in %s retrieval function", "sBIT");

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)

+       && sig_bit != NULL)

+   {

+      *sig_bit = &(info_ptr->sig_bit);

+      return (PNG_INFO_sBIT);

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_TEXT_SUPPORTED

+int PNGAPI

+png_get_text(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_textp *text_ptr, int *num_text)

+{

+   if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)

+   {

+      png_debug1(1, "in 0x%lx retrieval function",

+         (unsigned long)png_ptr->chunk_name);

+

+      if (text_ptr != NULL)

+         *text_ptr = info_ptr->text;

+

+      if (num_text != NULL)

+         *num_text = info_ptr->num_text;

+

+      return info_ptr->num_text;

+   }

+

+   if (num_text != NULL)

+      *num_text = 0;

+

+   return(0);

+}

+#endif

+

+#ifdef PNG_tIME_SUPPORTED

+png_uint_32 PNGAPI

+png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_timep *mod_time)

+{

+   png_debug1(1, "in %s retrieval function", "tIME");

+

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)

+       && mod_time != NULL)

+   {

+      *mod_time = &(info_ptr->mod_time);

+      return (PNG_INFO_tIME);

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_tRNS_SUPPORTED

+png_uint_32 PNGAPI

+png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)

+{

+   png_uint_32 retval = 0;

+   if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))

+   {

+      png_debug1(1, "in %s retrieval function", "tRNS");

+

+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      {

+         if (trans_alpha != NULL)

+         {

+            *trans_alpha = info_ptr->trans_alpha;

+            retval |= PNG_INFO_tRNS;

+         }

+

+         if (trans_color != NULL)

+            *trans_color = &(info_ptr->trans_color);

+      }

+

+      else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */

+      {

+         if (trans_color != NULL)

+         {

+            *trans_color = &(info_ptr->trans_color);

+            retval |= PNG_INFO_tRNS;

+         }

+

+         if (trans_alpha != NULL)

+            *trans_alpha = NULL;

+      }

+

+      if (num_trans != NULL)

+      {

+         *num_trans = info_ptr->num_trans;

+         retval |= PNG_INFO_tRNS;

+      }

+   }

+

+   return (retval);

+}

+#endif

+

+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED

+int PNGAPI

+png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_unknown_chunkpp unknowns)

+{

+   if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL)

+   {

+      *unknowns = info_ptr->unknown_chunks;

+      return info_ptr->unknown_chunks_num;

+   }

+

+   return (0);

+}

+#endif

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+png_byte PNGAPI

+png_get_rgb_to_gray_status (png_const_structrp png_ptr)

+{

+   return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0);

+}

+#endif

+

+#ifdef PNG_USER_CHUNKS_SUPPORTED

+png_voidp PNGAPI

+png_get_user_chunk_ptr(png_const_structrp png_ptr)

+{

+   return (png_ptr ? png_ptr->user_chunk_ptr : NULL);

+}

+#endif

+

+png_size_t PNGAPI

+png_get_compression_buffer_size(png_const_structrp png_ptr)

+{

+   if (png_ptr == NULL)

+      return 0;

+

+#  ifdef PNG_WRITE_SUPPORTED

+      if (png_ptr->mode & PNG_IS_READ_STRUCT)

+#  endif

+   {

+#     ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+         return png_ptr->IDAT_read_size;

+#     else

+         return PNG_IDAT_READ_SIZE;

+#     endif

+   }

+

+#  ifdef PNG_WRITE_SUPPORTED

+      else

+         return png_ptr->zbuffer_size;

+#  endif

+}

+

+#ifdef PNG_SET_USER_LIMITS_SUPPORTED

+/* These functions were added to libpng 1.2.6 and were enabled

+ * by default in libpng-1.4.0 */

+png_uint_32 PNGAPI

+png_get_user_width_max (png_const_structrp png_ptr)

+{

+   return (png_ptr ? png_ptr->user_width_max : 0);

+}

+

+png_uint_32 PNGAPI

+png_get_user_height_max (png_const_structrp png_ptr)

+{

+   return (png_ptr ? png_ptr->user_height_max : 0);

+}

+

+/* This function was added to libpng 1.4.0 */

+png_uint_32 PNGAPI

+png_get_chunk_cache_max (png_const_structrp png_ptr)

+{

+   return (png_ptr ? png_ptr->user_chunk_cache_max : 0);

+}

+

+/* This function was added to libpng 1.4.1 */

+png_alloc_size_t PNGAPI

+png_get_chunk_malloc_max (png_const_structrp png_ptr)

+{

+   return (png_ptr ? png_ptr->user_chunk_malloc_max : 0);

+}

+#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */

+

+/* These functions were added to libpng 1.4.0 */

+#ifdef PNG_IO_STATE_SUPPORTED

+png_uint_32 PNGAPI

+png_get_io_state (png_const_structrp png_ptr)

+{

+   return png_ptr->io_state;

+}

+

+png_uint_32 PNGAPI

+png_get_io_chunk_type (png_const_structrp png_ptr)

+{

+   return png_ptr->chunk_name;

+}

+#endif /* ?PNG_IO_STATE_SUPPORTED */

+

+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED

+#  ifdef PNG_GET_PALETTE_MAX_SUPPORTED

+int PNGAPI

+png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)

+{

+   if (png_ptr != NULL && info_ptr != NULL)

+      return png_ptr->num_palette_max;

+

+   return (-1);

+}

+#  endif

+#endif

+

+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngmem.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngmem.c
new file mode 100644
index 0000000..446bc68
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngmem.c
@@ -0,0 +1,291 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngmem.c - stub functions for memory allocation

+ *

+ * Last changed in libpng 1.6.0 [February 14, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ * This file provides a location for all memory allocation.  Users who

+ * need special memory handling are expected to supply replacement

+ * functions for png_malloc() and png_free(), and to use

+ * png_create_read_struct_2() and png_create_write_struct_2() to

+ * identify the replacement functions.

+ */

+

+#include "pngpriv.h"

+

+#if defined(_FX_MANAGED_CODE_) && defined(__cplusplus)

+extern "C" {

+#endif

+

+void*	FXMEM_DefaultAlloc(int byte_size, int);

+void	FXMEM_DefaultFree(void* pointer, int);

+

+#if defined(_FX_MANAGED_CODE_) && defined(__cplusplus)

+}

+#endif

+

+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

+/* Free a png_struct */

+void /* PRIVATE */

+png_destroy_png_struct(png_structrp png_ptr)

+{

+   if (png_ptr != NULL)

+   {

+      /* png_free might call png_error and may certainly call

+       * png_get_mem_ptr, so fake a temporary png_struct to support this.

+       */

+      png_struct dummy_struct = *png_ptr;

+      memset(png_ptr, 0, (sizeof *png_ptr));

+      png_free(&dummy_struct, png_ptr);

+

+#     ifdef PNG_SETJMP_SUPPORTED

+         /* We may have a jmp_buf left to deallocate. */

+         png_free_jmpbuf(&dummy_struct);

+#     endif

+   }

+}

+

+/* Allocate memory.  For reasonable files, size should never exceed

+ * 64K.  However, zlib may allocate more then 64K if you don't tell

+ * it not to.  See zconf.h and png.h for more information.  zlib does

+ * need to allocate exactly 64K, so whatever you call here must

+ * have the ability to do that.

+ */

+PNG_FUNCTION(png_voidp,PNGAPI

+png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)

+{

+   png_voidp ret;

+

+   ret = png_malloc(png_ptr, size);

+

+   if (ret != NULL)

+      memset(ret, 0, size);

+

+   return ret;

+}

+

+/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of

+ * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED.

+ * Checking and error handling must happen outside this routine; it returns NULL

+ * if the allocation cannot be done (for any reason.)

+ */

+PNG_FUNCTION(png_voidp /* PRIVATE */,

+png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size),

+   PNG_ALLOCATED)

+{

+   /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS

+    * allocators have also been removed in 1.6.0, so any 16-bit system now has

+    * to implement a user memory handler.  This checks to be sure it isn't

+    * called with big numbers.

+    */

+#ifdef PNG_USER_MEM_SUPPORTED

+   PNG_UNUSED(png_ptr)

+#endif

+   if (size > 0 && size <= PNG_SIZE_MAX

+#     ifdef PNG_MAX_MALLOC_64K

+         && size <= 65536U

+#     endif

+      )

+   {

+#ifdef PNG_USER_MEM_SUPPORTED

+      if (png_ptr != NULL && png_ptr->malloc_fn != NULL)

+         return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size);

+

+      else

+#endif

+         return FXMEM_DefaultAlloc((int)size, 0);

+         //return malloc((size_t)size); /* checked for truncation above */

+   }

+

+   else

+      return NULL;

+}

+

+/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7

+ * that arises because of the checks in png_realloc_array that are repeated in

+ * png_malloc_array.

+ */

+static png_voidp

+png_malloc_array_checked(png_const_structrp png_ptr, int nelements,

+   size_t element_size)

+{

+   png_alloc_size_t req = nelements; /* known to be > 0 */

+

+   if (req <= PNG_SIZE_MAX/element_size)

+      return png_malloc_base(png_ptr, req * element_size);

+

+   /* The failure case when the request is too large */

+   return NULL;

+}

+

+PNG_FUNCTION(png_voidp /* PRIVATE */,

+png_malloc_array,(png_const_structrp png_ptr, int nelements,

+   size_t element_size),PNG_ALLOCATED)

+{

+   if (nelements <= 0 || element_size == 0)

+      png_error(png_ptr, "internal error: array alloc");

+

+   return png_malloc_array_checked(png_ptr, nelements, element_size);

+}

+

+PNG_FUNCTION(png_voidp /* PRIVATE */,

+png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array,

+   int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED)

+{

+   /* These are internal errors: */

+   if (add_elements <= 0 || element_size == 0 || old_elements < 0 ||

+      (old_array == NULL && old_elements > 0))

+      png_error(png_ptr, "internal error: array realloc");

+

+   /* Check for overflow on the elements count (so the caller does not have to

+    * check.)

+    */

+   if (add_elements <= INT_MAX - old_elements)

+   {

+      png_voidp new_array = png_malloc_array_checked(png_ptr,

+         old_elements+add_elements, element_size);

+

+      if (new_array != NULL)

+      {

+         /* Because png_malloc_array worked the size calculations below cannot

+          * overflow.

+          */

+         if (old_elements > 0)

+            memcpy(new_array, old_array, element_size*(unsigned)old_elements);

+

+         memset((char*)new_array + element_size*(unsigned)old_elements, 0,

+            element_size*(unsigned)add_elements);

+

+         return new_array;

+      }

+   }

+

+   return NULL; /* error */

+}

+

+/* Various functions that have different error handling are derived from this.

+ * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate

+ * function png_malloc_default is also provided.

+ */

+PNG_FUNCTION(png_voidp,PNGAPI

+png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)

+{

+   png_voidp ret;

+

+   if (png_ptr == NULL)

+      return NULL;

+

+   ret = png_malloc_base(png_ptr, size);

+

+   if (ret == NULL)

+       png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */

+

+   return ret;

+}

+

+#ifdef PNG_USER_MEM_SUPPORTED

+PNG_FUNCTION(png_voidp,PNGAPI

+png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size),

+   PNG_ALLOCATED PNG_DEPRECATED)

+{

+   png_voidp ret;

+

+   if (png_ptr == NULL)

+      return NULL;

+

+   /* Passing 'NULL' here bypasses the application provided memory handler. */

+   ret = png_malloc_base(NULL/*use malloc*/, size);

+

+   if (ret == NULL)

+      png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */

+

+   return ret;

+}

+#endif /* PNG_USER_MEM_SUPPORTED */

+

+/* This function was added at libpng version 1.2.3.  The png_malloc_warn()

+ * function will issue a png_warning and return NULL instead of issuing a

+ * png_error, if it fails to allocate the requested memory.

+ */

+PNG_FUNCTION(png_voidp,PNGAPI

+png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size),

+   PNG_ALLOCATED)

+{

+   if (png_ptr != NULL)

+   {

+      png_voidp ret = png_malloc_base(png_ptr, size);

+

+      if (ret != NULL)

+         return ret;

+

+      png_warning(png_ptr, "Out of memory");

+   }

+

+   return NULL;

+}

+

+/* Free a pointer allocated by png_malloc().  If ptr is NULL, return

+ * without taking any action.

+ */

+void PNGAPI

+png_free(png_const_structrp png_ptr, png_voidp ptr)

+{

+   if (png_ptr == NULL || ptr == NULL)

+      return;

+

+#ifdef PNG_USER_MEM_SUPPORTED

+   if (png_ptr->free_fn != NULL)

+      png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr);

+

+   else

+      png_free_default(png_ptr, ptr);

+}

+

+PNG_FUNCTION(void,PNGAPI

+png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED)

+{

+   if (png_ptr == NULL || ptr == NULL)

+      return;

+#endif /* PNG_USER_MEM_SUPPORTED */

+

+   FXMEM_DefaultFree(ptr, 0);

+   //free(ptr);

+}

+

+#ifdef PNG_USER_MEM_SUPPORTED

+/* This function is called when the application wants to use another method

+ * of allocating and freeing memory.

+ */

+void PNGAPI

+png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr

+  malloc_fn, png_free_ptr free_fn)

+{

+   if (png_ptr != NULL)

+   {

+      png_ptr->mem_ptr = mem_ptr;

+      png_ptr->malloc_fn = malloc_fn;

+      png_ptr->free_fn = free_fn;

+   }

+}

+

+/* This function returns a pointer to the mem_ptr associated with the user

+ * functions.  The application should free any memory associated with this

+ * pointer before png_write_destroy and png_read_destroy are called.

+ */

+png_voidp PNGAPI

+png_get_mem_ptr(png_const_structrp png_ptr)

+{

+   if (png_ptr == NULL)

+      return NULL;

+

+   return png_ptr->mem_ptr;

+}

+#endif /* PNG_USER_MEM_SUPPORTED */

+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngpread.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngpread.c
new file mode 100644
index 0000000..6d5053f
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngpread.c
@@ -0,0 +1,1292 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngpread.c - read a png file in push mode

+ *

+ * Last changed in libpng 1.6.0 [February 14, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+

+#include "pngpriv.h"

+

+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED

+

+/* Push model modes */

+#define PNG_READ_SIG_MODE   0

+#define PNG_READ_CHUNK_MODE 1

+#define PNG_READ_IDAT_MODE  2

+#define PNG_SKIP_MODE       3

+#define PNG_READ_tEXt_MODE  4

+#define PNG_READ_zTXt_MODE  5

+#define PNG_READ_DONE_MODE  6

+#define PNG_READ_iTXt_MODE  7

+#define PNG_ERROR_MODE      8

+

+void PNGAPI

+png_process_data(png_structrp png_ptr, png_inforp info_ptr,

+    png_bytep buffer, png_size_t buffer_size)

+{

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   png_push_restore_buffer(png_ptr, buffer, buffer_size);

+

+   while (png_ptr->buffer_size)

+   {

+      png_process_some_data(png_ptr, info_ptr);

+   }

+}

+

+png_size_t PNGAPI

+png_process_data_pause(png_structrp png_ptr, int save)

+{

+   if (png_ptr != NULL)

+   {

+      /* It's easiest for the caller if we do the save, then the caller doesn't

+       * have to supply the same data again:

+       */

+      if (save)

+         png_push_save_buffer(png_ptr);

+      else

+      {

+         /* This includes any pending saved bytes: */

+         png_size_t remaining = png_ptr->buffer_size;

+         png_ptr->buffer_size = 0;

+

+         /* So subtract the saved buffer size, unless all the data

+          * is actually 'saved', in which case we just return 0

+          */

+         if (png_ptr->save_buffer_size < remaining)

+            return remaining - png_ptr->save_buffer_size;

+      }

+   }

+

+   return 0;

+}

+

+png_uint_32 PNGAPI

+png_process_data_skip(png_structrp png_ptr)

+{

+   png_uint_32 remaining = 0;

+

+   if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE &&

+      png_ptr->skip_length > 0)

+   {

+      /* At the end of png_process_data the buffer size must be 0 (see the loop

+       * above) so we can detect a broken call here:

+       */

+      if (png_ptr->buffer_size != 0)

+         png_error(png_ptr,

+            "png_process_data_skip called inside png_process_data");

+

+      /* If is impossible for there to be a saved buffer at this point -

+       * otherwise we could not be in SKIP mode.  This will also happen if

+       * png_process_skip is called inside png_process_data (but only very

+       * rarely.)

+       */

+      if (png_ptr->save_buffer_size != 0)

+         png_error(png_ptr, "png_process_data_skip called with saved data");

+

+      remaining = png_ptr->skip_length;

+      png_ptr->skip_length = 0;

+      png_ptr->process_mode = PNG_READ_CHUNK_MODE;

+   }

+

+   return remaining;

+}

+

+/* What we do with the incoming data depends on what we were previously

+ * doing before we ran out of data...

+ */

+void /* PRIVATE */

+png_process_some_data(png_structrp png_ptr, png_inforp info_ptr)

+{

+   if (png_ptr == NULL)

+      return;

+

+   switch (png_ptr->process_mode)

+   {

+      case PNG_READ_SIG_MODE:

+      {

+         png_push_read_sig(png_ptr, info_ptr);

+         break;

+      }

+

+      case PNG_READ_CHUNK_MODE:

+      {

+         png_push_read_chunk(png_ptr, info_ptr);

+         break;

+      }

+

+      case PNG_READ_IDAT_MODE:

+      {

+         png_push_read_IDAT(png_ptr);

+         break;

+      }

+

+      case PNG_SKIP_MODE:

+      {

+         png_push_crc_finish(png_ptr);

+         break;

+      }

+

+      default:

+      {

+         png_ptr->buffer_size = 0;

+         break;

+      }

+   }

+}

+

+/* Read any remaining signature bytes from the stream and compare them with

+ * the correct PNG signature.  It is possible that this routine is called

+ * with bytes already read from the signature, either because they have been

+ * checked by the calling application, or because of multiple calls to this

+ * routine.

+ */

+void /* PRIVATE */

+png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr)

+{

+   png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */ 

+             num_to_check = 8 - num_checked;

+

+   if (png_ptr->buffer_size < num_to_check)

+   {

+      num_to_check = png_ptr->buffer_size;

+   }

+

+   png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]),

+       num_to_check);

+   png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check);

+

+   if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))

+   {

+      if (num_checked < 4 &&

+          png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))

+         png_error(png_ptr, "Not a PNG file");

+

+      else

+         png_error(png_ptr, "PNG file corrupted by ASCII conversion");

+   }

+   else

+   {

+      if (png_ptr->sig_bytes >= 8)

+      {

+         png_ptr->process_mode = PNG_READ_CHUNK_MODE;

+      }

+   }

+}

+

+void /* PRIVATE */

+png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)

+{

+   png_uint_32 chunk_name;

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+   int keep; /* unknown handling method */

+#endif

+

+   /* First we make sure we have enough data for the 4 byte chunk name

+    * and the 4 byte chunk length before proceeding with decoding the

+    * chunk data.  To fully decode each of these chunks, we also make

+    * sure we have enough data in the buffer for the 4 byte CRC at the

+    * end of every chunk (except IDAT, which is handled separately).

+    */

+   if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))

+   {

+      png_byte chunk_length[4];

+      png_byte chunk_tag[4];

+

+      if (png_ptr->buffer_size < 8)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_push_fill_buffer(png_ptr, chunk_length, 4);

+      png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);

+      png_reset_crc(png_ptr);

+      png_crc_read(png_ptr, chunk_tag, 4);

+      png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);

+      png_check_chunk_name(png_ptr, png_ptr->chunk_name);

+      png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;

+   }

+

+   chunk_name = png_ptr->chunk_name;

+

+   if (chunk_name == png_IDAT)

+   {

+      if (png_ptr->mode & PNG_AFTER_IDAT)

+         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;

+

+      /* If we reach an IDAT chunk, this means we have read all of the

+       * header chunks, and we can start reading the image (or if this

+       * is called after the image has been read - we have an error).

+       */

+      if (!(png_ptr->mode & PNG_HAVE_IHDR))

+         png_error(png_ptr, "Missing IHDR before IDAT");

+

+      else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&

+          !(png_ptr->mode & PNG_HAVE_PLTE))

+         png_error(png_ptr, "Missing PLTE before IDAT");

+

+      png_ptr->mode |= PNG_HAVE_IDAT;

+

+      if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))

+         if (png_ptr->push_length == 0)

+            return;

+

+      if (png_ptr->mode & PNG_AFTER_IDAT)

+         png_benign_error(png_ptr, "Too many IDATs found");

+   }

+

+   if (chunk_name == png_IHDR)

+   {

+      if (png_ptr->push_length != 13)

+         png_error(png_ptr, "Invalid IHDR length");

+

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+   else if (chunk_name == png_IEND)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);

+

+      png_ptr->process_mode = PNG_READ_DONE_MODE;

+      png_push_have_end(png_ptr, info_ptr);

+   }

+

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+   else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep);

+

+      if (chunk_name == png_PLTE)

+         png_ptr->mode |= PNG_HAVE_PLTE;

+   }

+

+#endif

+   else if (chunk_name == png_PLTE)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+      png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+   else if (chunk_name == png_IDAT)

+   {

+      png_ptr->idat_size = png_ptr->push_length;

+      png_ptr->process_mode = PNG_READ_IDAT_MODE;

+      png_push_have_info(png_ptr, info_ptr);

+      png_ptr->zstream.avail_out =

+          (uInt) PNG_ROWBYTES(png_ptr->pixel_depth,

+          png_ptr->iwidth) + 1;

+      png_ptr->zstream.next_out = png_ptr->row_buf;

+      return;

+   }

+

+#ifdef PNG_READ_gAMA_SUPPORTED

+   else if (png_ptr->chunk_name == png_gAMA)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_sBIT_SUPPORTED

+   else if (png_ptr->chunk_name == png_sBIT)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_cHRM_SUPPORTED

+   else if (png_ptr->chunk_name == png_cHRM)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_sRGB_SUPPORTED

+   else if (chunk_name == png_sRGB)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_iCCP_SUPPORTED

+   else if (png_ptr->chunk_name == png_iCCP)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_sPLT_SUPPORTED

+   else if (chunk_name == png_sPLT)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_tRNS_SUPPORTED

+   else if (chunk_name == png_tRNS)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_bKGD_SUPPORTED

+   else if (chunk_name == png_bKGD)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_hIST_SUPPORTED

+   else if (chunk_name == png_hIST)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_pHYs_SUPPORTED

+   else if (chunk_name == png_pHYs)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_oFFs_SUPPORTED

+   else if (chunk_name == png_oFFs)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);

+   }

+#endif

+

+#ifdef PNG_READ_pCAL_SUPPORTED

+   else if (chunk_name == png_pCAL)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_sCAL_SUPPORTED

+   else if (chunk_name == png_sCAL)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_tIME_SUPPORTED

+   else if (chunk_name == png_tIME)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_tEXt_SUPPORTED

+   else if (chunk_name == png_tEXt)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_zTXt_SUPPORTED

+   else if (chunk_name == png_zTXt)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+#ifdef PNG_READ_iTXt_SUPPORTED

+   else if (chunk_name == png_iTXt)

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);

+   }

+

+#endif

+   else

+   {

+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+      png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length,

+         PNG_HANDLE_CHUNK_AS_DEFAULT);

+   }

+

+   png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;

+}

+

+void /* PRIVATE */

+png_push_crc_skip(png_structrp png_ptr, png_uint_32 skip)

+{

+   png_ptr->process_mode = PNG_SKIP_MODE;

+   png_ptr->skip_length = skip;

+}

+

+void /* PRIVATE */

+png_push_crc_finish(png_structrp png_ptr)

+{

+   if (png_ptr->skip_length && png_ptr->save_buffer_size)

+   {

+      png_size_t save_size = png_ptr->save_buffer_size;

+      png_uint_32 skip_length = png_ptr->skip_length;

+

+      /* We want the smaller of 'skip_length' and 'save_buffer_size', but

+       * they are of different types and we don't know which variable has the

+       * fewest bits.  Carefully select the smaller and cast it to the type of

+       * the larger - this cannot overflow.  Do not cast in the following test

+       * - it will break on either 16 or 64 bit platforms.

+       */

+      if (skip_length < save_size)

+         save_size = (png_size_t)skip_length;

+

+      else

+         skip_length = (png_uint_32)save_size;

+

+      png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);

+

+      png_ptr->skip_length -= skip_length;

+      png_ptr->buffer_size -= save_size;

+      png_ptr->save_buffer_size -= save_size;

+      png_ptr->save_buffer_ptr += save_size;

+   }

+   if (png_ptr->skip_length && png_ptr->current_buffer_size)

+   {

+      png_size_t save_size = png_ptr->current_buffer_size;

+      png_uint_32 skip_length = png_ptr->skip_length;

+

+      /* We want the smaller of 'skip_length' and 'current_buffer_size', here,

+       * the same problem exists as above and the same solution.

+       */

+      if (skip_length < save_size)

+         save_size = (png_size_t)skip_length;

+

+      else

+         skip_length = (png_uint_32)save_size;

+

+      png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);

+

+      png_ptr->skip_length -= skip_length;

+      png_ptr->buffer_size -= save_size;

+      png_ptr->current_buffer_size -= save_size;

+      png_ptr->current_buffer_ptr += save_size;

+   }

+   if (!png_ptr->skip_length)

+   {

+      if (png_ptr->buffer_size < 4)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_crc_finish(png_ptr, 0);

+      png_ptr->process_mode = PNG_READ_CHUNK_MODE;

+   }

+}

+

+void PNGCBAPI

+png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)

+{

+   png_bytep ptr;

+

+   if (png_ptr == NULL)

+      return;

+

+   ptr = buffer;

+   if (png_ptr->save_buffer_size)

+   {

+      png_size_t save_size;

+

+      if (length < png_ptr->save_buffer_size)

+         save_size = length;

+

+      else

+         save_size = png_ptr->save_buffer_size;

+

+      memcpy(ptr, png_ptr->save_buffer_ptr, save_size);

+      length -= save_size;

+      ptr += save_size;

+      png_ptr->buffer_size -= save_size;

+      png_ptr->save_buffer_size -= save_size;

+      png_ptr->save_buffer_ptr += save_size;

+   }

+   if (length && png_ptr->current_buffer_size)

+   {

+      png_size_t save_size;

+

+      if (length < png_ptr->current_buffer_size)

+         save_size = length;

+

+      else

+         save_size = png_ptr->current_buffer_size;

+

+      memcpy(ptr, png_ptr->current_buffer_ptr, save_size);

+      png_ptr->buffer_size -= save_size;

+      png_ptr->current_buffer_size -= save_size;

+      png_ptr->current_buffer_ptr += save_size;

+   }

+}

+

+void /* PRIVATE */

+png_push_save_buffer(png_structrp png_ptr)

+{

+   if (png_ptr->save_buffer_size)

+   {

+      if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)

+      {

+         png_size_t i, istop;

+         png_bytep sp;

+         png_bytep dp;

+

+         istop = png_ptr->save_buffer_size;

+         for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;

+             i < istop; i++, sp++, dp++)

+         {

+            *dp = *sp;

+         }

+      }

+   }

+   if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >

+       png_ptr->save_buffer_max)

+   {

+      png_size_t new_max;

+      png_bytep old_buffer;

+

+      if (png_ptr->save_buffer_size > PNG_SIZE_MAX -

+          (png_ptr->current_buffer_size + 256))

+      {

+         png_error(png_ptr, "Potential overflow of save_buffer");

+      }

+

+      new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;

+      old_buffer = png_ptr->save_buffer;

+      png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr,

+          (png_size_t)new_max);

+

+      if (png_ptr->save_buffer == NULL)

+      {

+         png_free(png_ptr, old_buffer);

+         png_error(png_ptr, "Insufficient memory for save_buffer");

+      }

+

+      memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);

+      png_free(png_ptr, old_buffer);

+      png_ptr->save_buffer_max = new_max;

+   }

+   if (png_ptr->current_buffer_size)

+   {

+      memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,

+         png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);

+      png_ptr->save_buffer_size += png_ptr->current_buffer_size;

+      png_ptr->current_buffer_size = 0;

+   }

+   png_ptr->save_buffer_ptr = png_ptr->save_buffer;

+   png_ptr->buffer_size = 0;

+}

+

+void /* PRIVATE */

+png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer,

+   png_size_t buffer_length)

+{

+   png_ptr->current_buffer = buffer;

+   png_ptr->current_buffer_size = buffer_length;

+   png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size;

+   png_ptr->current_buffer_ptr = png_ptr->current_buffer;

+}

+

+void /* PRIVATE */

+png_push_read_IDAT(png_structrp png_ptr)

+{

+   if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))

+   {

+      png_byte chunk_length[4];

+      png_byte chunk_tag[4];

+

+      /* TODO: this code can be commoned up with the same code in push_read */

+      if (png_ptr->buffer_size < 8)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_push_fill_buffer(png_ptr, chunk_length, 4);

+      png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);

+      png_reset_crc(png_ptr);

+      png_crc_read(png_ptr, chunk_tag, 4);

+      png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);

+      png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;

+

+      if (png_ptr->chunk_name != png_IDAT)

+      {

+         png_ptr->process_mode = PNG_READ_CHUNK_MODE;

+

+         if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))

+            png_error(png_ptr, "Not enough compressed data");

+

+         return;

+      }

+

+      png_ptr->idat_size = png_ptr->push_length;

+   }

+

+   if (png_ptr->idat_size && png_ptr->save_buffer_size)

+   {

+      png_size_t save_size = png_ptr->save_buffer_size;

+      png_uint_32 idat_size = png_ptr->idat_size;

+

+      /* We want the smaller of 'idat_size' and 'current_buffer_size', but they

+       * are of different types and we don't know which variable has the fewest

+       * bits.  Carefully select the smaller and cast it to the type of the

+       * larger - this cannot overflow.  Do not cast in the following test - it

+       * will break on either 16 or 64 bit platforms.

+       */

+      if (idat_size < save_size)

+         save_size = (png_size_t)idat_size;

+

+      else

+         idat_size = (png_uint_32)save_size;

+

+      png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);

+

+      png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);

+

+      png_ptr->idat_size -= idat_size;

+      png_ptr->buffer_size -= save_size;

+      png_ptr->save_buffer_size -= save_size;

+      png_ptr->save_buffer_ptr += save_size;

+   }

+

+   if (png_ptr->idat_size && png_ptr->current_buffer_size)

+   {

+      png_size_t save_size = png_ptr->current_buffer_size;

+      png_uint_32 idat_size = png_ptr->idat_size;

+

+      /* We want the smaller of 'idat_size' and 'current_buffer_size', but they

+       * are of different types and we don't know which variable has the fewest

+       * bits.  Carefully select the smaller and cast it to the type of the

+       * larger - this cannot overflow.

+       */

+      if (idat_size < save_size)

+         save_size = (png_size_t)idat_size;

+

+      else

+         idat_size = (png_uint_32)save_size;

+

+      png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);

+

+      png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);

+

+      png_ptr->idat_size -= idat_size;

+      png_ptr->buffer_size -= save_size;

+      png_ptr->current_buffer_size -= save_size;

+      png_ptr->current_buffer_ptr += save_size;

+   }

+   if (!png_ptr->idat_size)

+   {

+      if (png_ptr->buffer_size < 4)

+      {

+         png_push_save_buffer(png_ptr);

+         return;

+      }

+

+      png_crc_finish(png_ptr, 0);

+      png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;

+      png_ptr->mode |= PNG_AFTER_IDAT;

+      png_ptr->zowner = 0;

+   }

+}

+

+void /* PRIVATE */

+png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,

+   png_size_t buffer_length)

+{

+   /* The caller checks for a non-zero buffer length. */

+   if (!(buffer_length > 0) || buffer == NULL)

+      png_error(png_ptr, "No IDAT data (internal error)");

+

+   /* This routine must process all the data it has been given

+    * before returning, calling the row callback as required to

+    * handle the uncompressed results.

+    */

+   png_ptr->zstream.next_in = buffer;

+   /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */

+   png_ptr->zstream.avail_in = (uInt)buffer_length;

+

+   /* Keep going until the decompressed data is all processed

+    * or the stream marked as finished.

+    */

+   while (png_ptr->zstream.avail_in > 0 &&

+      !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))

+   {

+      int ret;

+

+      /* We have data for zlib, but we must check that zlib

+       * has someplace to put the results.  It doesn't matter

+       * if we don't expect any results -- it may be the input

+       * data is just the LZ end code.

+       */

+      if (!(png_ptr->zstream.avail_out > 0))

+      {

+         /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */

+         png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth,

+             png_ptr->iwidth) + 1);

+

+         png_ptr->zstream.next_out = png_ptr->row_buf;

+      }

+

+      /* Using Z_SYNC_FLUSH here means that an unterminated

+       * LZ stream (a stream with a missing end code) can still

+       * be handled, otherwise (Z_NO_FLUSH) a future zlib

+       * implementation might defer output and therefore

+       * change the current behavior (see comments in inflate.c

+       * for why this doesn't happen at present with zlib 1.2.5).

+       */

+      ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH);

+

+      /* Check for any failure before proceeding. */

+      if (ret != Z_OK && ret != Z_STREAM_END)

+      {

+         /* Terminate the decompression. */

+         png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;

+         png_ptr->zowner = 0;

+

+         /* This may be a truncated stream (missing or

+          * damaged end code).  Treat that as a warning.

+          */

+         if (png_ptr->row_number >= png_ptr->num_rows ||

+             png_ptr->pass > 6)

+            png_warning(png_ptr, "Truncated compressed data in IDAT");

+

+         else

+            png_error(png_ptr, "Decompression error in IDAT");

+

+         /* Skip the check on unprocessed input */

+         return;

+      }

+

+      /* Did inflate output any data? */

+      if (png_ptr->zstream.next_out != png_ptr->row_buf)

+      {

+         /* Is this unexpected data after the last row?

+          * If it is, artificially terminate the LZ output

+          * here.

+          */

+         if (png_ptr->row_number >= png_ptr->num_rows ||

+             png_ptr->pass > 6)

+         {

+            /* Extra data. */

+            png_warning(png_ptr, "Extra compressed data in IDAT");

+            png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;

+            png_ptr->zowner = 0;

+

+            /* Do no more processing; skip the unprocessed

+             * input check below.

+             */

+            return;

+         }

+

+         /* Do we have a complete row? */

+         if (png_ptr->zstream.avail_out == 0)

+            png_push_process_row(png_ptr);

+      }

+

+      /* And check for the end of the stream. */

+      if (ret == Z_STREAM_END)

+         png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;

+   }

+

+   /* All the data should have been processed, if anything

+    * is left at this point we have bytes of IDAT data

+    * after the zlib end code.

+    */

+   if (png_ptr->zstream.avail_in > 0)

+      png_warning(png_ptr, "Extra compression data in IDAT");

+}

+

+void /* PRIVATE */

+png_push_process_row(png_structrp png_ptr)

+{

+   /* 1.5.6: row_info moved out of png_struct to a local here. */

+   png_row_info row_info;

+

+   row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */

+   row_info.color_type = png_ptr->color_type;

+   row_info.bit_depth = png_ptr->bit_depth;

+   row_info.channels = png_ptr->channels;

+   row_info.pixel_depth = png_ptr->pixel_depth;

+   row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);

+

+   if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)

+   {

+      if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST)

+         png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1,

+            png_ptr->prev_row + 1, png_ptr->row_buf[0]);

+      else

+         png_error(png_ptr, "bad adaptive filter value");

+   }

+

+   /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before

+    * 1.5.6, while the buffer really is this big in current versions of libpng

+    * it may not be in the future, so this was changed just to copy the

+    * interlaced row count:

+    */

+   memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1);

+

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+   if (png_ptr->transformations)

+      png_do_read_transformations(png_ptr, &row_info);

+#endif

+

+   /* The transformed pixel depth should match the depth now in row_info. */

+   if (png_ptr->transformed_pixel_depth == 0)

+   {

+      png_ptr->transformed_pixel_depth = row_info.pixel_depth;

+      if (row_info.pixel_depth > png_ptr->maximum_pixel_depth)

+         png_error(png_ptr, "progressive row overflow");

+   }

+

+   else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth)

+      png_error(png_ptr, "internal progressive row size calculation error");

+

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   /* Blow up interlaced rows to full size */

+   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))

+   {

+      if (png_ptr->pass < 6)

+         png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,

+            png_ptr->transformations);

+

+    switch (png_ptr->pass)

+    {

+         case 0:

+         {

+            int i;

+            for (i = 0; i < 8 && png_ptr->pass == 0; i++)

+            {

+               png_push_have_row(png_ptr, png_ptr->row_buf + 1);

+               png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */

+            }

+

+            if (png_ptr->pass == 2) /* Pass 1 might be empty */

+            {

+               for (i = 0; i < 4 && png_ptr->pass == 2; i++)

+               {

+                  png_push_have_row(png_ptr, NULL);

+                  png_read_push_finish_row(png_ptr);

+               }

+            }

+

+            if (png_ptr->pass == 4 && png_ptr->height <= 4)

+            {

+               for (i = 0; i < 2 && png_ptr->pass == 4; i++)

+               {

+                  png_push_have_row(png_ptr, NULL);

+                  png_read_push_finish_row(png_ptr);

+               }

+            }

+

+            if (png_ptr->pass == 6 && png_ptr->height <= 4)

+            {

+                png_push_have_row(png_ptr, NULL);

+                png_read_push_finish_row(png_ptr);

+            }

+

+            break;

+         }

+

+         case 1:

+         {

+            int i;

+            for (i = 0; i < 8 && png_ptr->pass == 1; i++)

+            {

+               png_push_have_row(png_ptr, png_ptr->row_buf + 1);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            if (png_ptr->pass == 2) /* Skip top 4 generated rows */

+            {

+               for (i = 0; i < 4 && png_ptr->pass == 2; i++)

+               {

+                  png_push_have_row(png_ptr, NULL);

+                  png_read_push_finish_row(png_ptr);

+               }

+            }

+

+            break;

+         }

+

+         case 2:

+         {

+            int i;

+

+            for (i = 0; i < 4 && png_ptr->pass == 2; i++)

+            {

+               png_push_have_row(png_ptr, png_ptr->row_buf + 1);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            for (i = 0; i < 4 && png_ptr->pass == 2; i++)

+            {

+               png_push_have_row(png_ptr, NULL);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            if (png_ptr->pass == 4) /* Pass 3 might be empty */

+            {

+               for (i = 0; i < 2 && png_ptr->pass == 4; i++)

+               {

+                  png_push_have_row(png_ptr, NULL);

+                  png_read_push_finish_row(png_ptr);

+               }

+            }

+

+            break;

+         }

+

+         case 3:

+         {

+            int i;

+

+            for (i = 0; i < 4 && png_ptr->pass == 3; i++)

+            {

+               png_push_have_row(png_ptr, png_ptr->row_buf + 1);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            if (png_ptr->pass == 4) /* Skip top two generated rows */

+            {

+               for (i = 0; i < 2 && png_ptr->pass == 4; i++)

+               {

+                  png_push_have_row(png_ptr, NULL);

+                  png_read_push_finish_row(png_ptr);

+               }

+            }

+

+            break;

+         }

+

+         case 4:

+         {

+            int i;

+

+            for (i = 0; i < 2 && png_ptr->pass == 4; i++)

+            {

+               png_push_have_row(png_ptr, png_ptr->row_buf + 1);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            for (i = 0; i < 2 && png_ptr->pass == 4; i++)

+            {

+               png_push_have_row(png_ptr, NULL);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            if (png_ptr->pass == 6) /* Pass 5 might be empty */

+            {

+               png_push_have_row(png_ptr, NULL);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            break;

+         }

+

+         case 5:

+         {

+            int i;

+

+            for (i = 0; i < 2 && png_ptr->pass == 5; i++)

+            {

+               png_push_have_row(png_ptr, png_ptr->row_buf + 1);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            if (png_ptr->pass == 6) /* Skip top generated row */

+            {

+               png_push_have_row(png_ptr, NULL);

+               png_read_push_finish_row(png_ptr);

+            }

+

+            break;

+         }

+

+         default:

+         case 6:

+         {

+            png_push_have_row(png_ptr, png_ptr->row_buf + 1);

+            png_read_push_finish_row(png_ptr);

+

+            if (png_ptr->pass != 6)

+               break;

+

+            png_push_have_row(png_ptr, NULL);

+            png_read_push_finish_row(png_ptr);

+         }

+      }

+   }

+   else

+#endif

+   {

+      png_push_have_row(png_ptr, png_ptr->row_buf + 1);

+      png_read_push_finish_row(png_ptr);

+   }

+}

+

+void /* PRIVATE */

+png_read_push_finish_row(png_structrp png_ptr)

+{

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */

+

+   /* Start of interlace block */

+   static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};

+

+   /* Offset to next interlace block */

+   static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};

+

+   /* Start of interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};

+

+   /* Offset to next interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};

+

+   /* Height of interlace block.  This is not currently used - if you need

+    * it, uncomment it here and in png.h

+   static PNG_CONST png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};

+   */

+#endif

+

+   png_ptr->row_number++;

+   if (png_ptr->row_number < png_ptr->num_rows)

+      return;

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   if (png_ptr->interlaced)

+   {

+      png_ptr->row_number = 0;

+      memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);

+

+      do

+      {

+         png_ptr->pass++;

+         if ((png_ptr->pass == 1 && png_ptr->width < 5) ||

+             (png_ptr->pass == 3 && png_ptr->width < 3) ||

+             (png_ptr->pass == 5 && png_ptr->width < 2))

+            png_ptr->pass++;

+

+         if (png_ptr->pass > 7)

+            png_ptr->pass--;

+

+         if (png_ptr->pass >= 7)

+            break;

+

+         png_ptr->iwidth = (png_ptr->width +

+             png_pass_inc[png_ptr->pass] - 1 -

+             png_pass_start[png_ptr->pass]) /

+             png_pass_inc[png_ptr->pass];

+

+         if (png_ptr->transformations & PNG_INTERLACE)

+            break;

+

+         png_ptr->num_rows = (png_ptr->height +

+             png_pass_yinc[png_ptr->pass] - 1 -

+             png_pass_ystart[png_ptr->pass]) /

+             png_pass_yinc[png_ptr->pass];

+

+      } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0);

+   }

+#endif /* PNG_READ_INTERLACING_SUPPORTED */

+}

+

+void /* PRIVATE */

+png_push_have_info(png_structrp png_ptr, png_inforp info_ptr)

+{

+   if (png_ptr->info_fn != NULL)

+      (*(png_ptr->info_fn))(png_ptr, info_ptr);

+}

+

+void /* PRIVATE */

+png_push_have_end(png_structrp png_ptr, png_inforp info_ptr)

+{

+   if (png_ptr->end_fn != NULL)

+      (*(png_ptr->end_fn))(png_ptr, info_ptr);

+}

+

+void /* PRIVATE */

+png_push_have_row(png_structrp png_ptr, png_bytep row)

+{

+   if (png_ptr->row_fn != NULL)

+      (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,

+         (int)png_ptr->pass);

+}

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+void PNGAPI

+png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row,

+    png_const_bytep new_row)

+{

+   if (png_ptr == NULL)

+      return;

+

+   /* new_row is a flag here - if it is NULL then the app callback was called

+    * from an empty row (see the calls to png_struct::row_fn below), otherwise

+    * it must be png_ptr->row_buf+1

+    */

+   if (new_row != NULL)

+      png_combine_row(png_ptr, old_row, 1/*display*/);

+}

+#endif /* PNG_READ_INTERLACING_SUPPORTED */

+

+void PNGAPI

+png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr,

+    png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,

+    png_progressive_end_ptr end_fn)

+{

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->info_fn = info_fn;

+   png_ptr->row_fn = row_fn;

+   png_ptr->end_fn = end_fn;

+

+   png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);

+}

+

+png_voidp PNGAPI

+png_get_progressive_ptr(png_const_structrp png_ptr)

+{

+   if (png_ptr == NULL)

+      return (NULL);

+

+   return png_ptr->io_ptr;

+}

+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngread.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngread.c
new file mode 100644
index 0000000..3918e83
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngread.c
@@ -0,0 +1,4001 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngread.c - read a PNG file

+ *

+ * Last changed in libpng 1.6.1 [March 28, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ * This file contains routines that an application calls directly to

+ * read a PNG file or stream.

+ */

+

+#include "pngpriv.h"

+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)

+#  include <errno.h>

+#endif

+

+#ifdef PNG_READ_SUPPORTED

+

+/* Create a PNG structure for reading, and allocate any memory needed. */

+PNG_FUNCTION(png_structp,PNGAPI

+png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr,

+    png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)

+{

+#ifndef PNG_USER_MEM_SUPPORTED

+   png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,

+      error_fn, warn_fn, NULL, NULL, NULL);

+#else

+   return png_create_read_struct_2(user_png_ver, error_ptr, error_fn,

+       warn_fn, NULL, NULL, NULL);

+}

+

+/* Alternate create PNG structure for reading, and allocate any memory

+ * needed.

+ */

+PNG_FUNCTION(png_structp,PNGAPI

+png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,

+    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,

+    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)

+{

+   png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,

+      error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);

+#endif /* PNG_USER_MEM_SUPPORTED */

+

+   if (png_ptr != NULL)

+   {

+      png_ptr->mode = PNG_IS_READ_STRUCT;

+

+      /* Added in libpng-1.6.0; this can be used to detect a read structure if

+       * required (it will be zero in a write structure.)

+       */

+#     ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+         png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE;

+#     endif

+

+#     ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED

+         png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;

+

+         /* In stable builds only warn if an application error can be completely

+          * handled.

+          */

+#        if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC

+            png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;

+#        endif

+#     endif

+

+      /* TODO: delay this, it can be done in png_init_io (if the app doesn't

+       * do it itself) avoiding setting the default function if it is not

+       * required.

+       */

+      png_set_read_fn(png_ptr, NULL, NULL);

+   }

+

+   return png_ptr;

+}

+

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+/* Read the information before the actual image data.  This has been

+ * changed in v0.90 to allow reading a file that already has the magic

+ * bytes read from the stream.  You can tell libpng how many bytes have

+ * been read from the beginning of the stream (up to the maximum of 8)

+ * via png_set_sig_bytes(), and we will only check the remaining bytes

+ * here.  The application can then have access to the signature bytes we

+ * read if it is determined that this isn't a valid PNG file.

+ */

+void PNGAPI

+png_read_info(png_structrp png_ptr, png_inforp info_ptr)

+{

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+   int keep;

+#endif

+

+   png_debug(1, "in png_read_info");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   /* Read and check the PNG file signature. */

+   png_read_sig(png_ptr, info_ptr);

+

+   for (;;)

+   {

+      png_uint_32 length = png_read_chunk_header(png_ptr);

+      png_uint_32 chunk_name = png_ptr->chunk_name;

+

+      /* IDAT logic needs to happen here to simplify getting the two flags

+       * right.

+       */

+      if (chunk_name == png_IDAT)

+      {

+         if (!(png_ptr->mode & PNG_HAVE_IHDR))

+            png_chunk_error(png_ptr, "Missing IHDR before IDAT");

+

+         else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&

+             !(png_ptr->mode & PNG_HAVE_PLTE))

+            png_chunk_error(png_ptr, "Missing PLTE before IDAT");

+

+         else if (png_ptr->mode & PNG_AFTER_IDAT)

+            png_chunk_benign_error(png_ptr, "Too many IDATs found");

+

+         png_ptr->mode |= PNG_HAVE_IDAT;

+      }

+

+      else if (png_ptr->mode & PNG_HAVE_IDAT)

+         png_ptr->mode |= PNG_AFTER_IDAT;

+

+      /* This should be a binary subdivision search or a hash for

+       * matching the chunk name rather than a linear search.

+       */

+      if (chunk_name == png_IHDR)

+         png_handle_IHDR(png_ptr, info_ptr, length);

+

+      else if (chunk_name == png_IEND)

+         png_handle_IEND(png_ptr, info_ptr, length);

+

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+      else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)

+      {

+         png_handle_unknown(png_ptr, info_ptr, length, keep);

+

+         if (chunk_name == png_PLTE)

+            png_ptr->mode |= PNG_HAVE_PLTE;

+

+         else if (chunk_name == png_IDAT)

+         {

+            png_ptr->idat_size = 0; /* It has been consumed */

+            break;

+         }

+      }

+#endif

+      else if (chunk_name == png_PLTE)

+         png_handle_PLTE(png_ptr, info_ptr, length);

+

+      else if (chunk_name == png_IDAT)

+      {

+         png_ptr->idat_size = length;

+         break;

+      }

+

+#ifdef PNG_READ_bKGD_SUPPORTED

+      else if (chunk_name == png_bKGD)

+         png_handle_bKGD(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_cHRM_SUPPORTED

+      else if (chunk_name == png_cHRM)

+         png_handle_cHRM(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_gAMA_SUPPORTED

+      else if (chunk_name == png_gAMA)

+         png_handle_gAMA(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_hIST_SUPPORTED

+      else if (chunk_name == png_hIST)

+         png_handle_hIST(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_oFFs_SUPPORTED

+      else if (chunk_name == png_oFFs)

+         png_handle_oFFs(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_pCAL_SUPPORTED

+      else if (chunk_name == png_pCAL)

+         png_handle_pCAL(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_sCAL_SUPPORTED

+      else if (chunk_name == png_sCAL)

+         png_handle_sCAL(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_pHYs_SUPPORTED

+      else if (chunk_name == png_pHYs)

+         png_handle_pHYs(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_sBIT_SUPPORTED

+      else if (chunk_name == png_sBIT)

+         png_handle_sBIT(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_sRGB_SUPPORTED

+      else if (chunk_name == png_sRGB)

+         png_handle_sRGB(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_iCCP_SUPPORTED

+      else if (chunk_name == png_iCCP)

+         png_handle_iCCP(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_sPLT_SUPPORTED

+      else if (chunk_name == png_sPLT)

+         png_handle_sPLT(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_tEXt_SUPPORTED

+      else if (chunk_name == png_tEXt)

+         png_handle_tEXt(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_tIME_SUPPORTED

+      else if (chunk_name == png_tIME)

+         png_handle_tIME(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_tRNS_SUPPORTED

+      else if (chunk_name == png_tRNS)

+         png_handle_tRNS(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_zTXt_SUPPORTED

+      else if (chunk_name == png_zTXt)

+         png_handle_zTXt(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_iTXt_SUPPORTED

+      else if (chunk_name == png_iTXt)

+         png_handle_iTXt(png_ptr, info_ptr, length);

+#endif

+

+      else

+         png_handle_unknown(png_ptr, info_ptr, length,

+            PNG_HANDLE_CHUNK_AS_DEFAULT);

+   }

+}

+#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */

+

+/* Optional call to update the users info_ptr structure */

+void PNGAPI

+png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)

+{

+   png_debug(1, "in png_read_update_info");

+

+   if (png_ptr != NULL)

+   {

+      if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)

+      {

+         png_read_start_row(png_ptr);

+

+#        ifdef PNG_READ_TRANSFORMS_SUPPORTED

+            png_read_transform_info(png_ptr, info_ptr);

+#        else

+            PNG_UNUSED(info_ptr)

+#        endif

+      }

+

+      /* New in 1.6.0 this avoids the bug of doing the initializations twice */

+      else

+         png_app_error(png_ptr,

+            "png_read_update_info/png_start_read_image: duplicate call");

+   }

+}

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+/* Initialize palette, background, etc, after transformations

+ * are set, but before any reading takes place.  This allows

+ * the user to obtain a gamma-corrected palette, for example.

+ * If the user doesn't call this, we will do it ourselves.

+ */

+void PNGAPI

+png_start_read_image(png_structrp png_ptr)

+{

+   png_debug(1, "in png_start_read_image");

+

+   if (png_ptr != NULL)

+   {

+      if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)

+         png_read_start_row(png_ptr);

+

+      /* New in 1.6.0 this avoids the bug of doing the initializations twice */

+      else

+         png_app_error(png_ptr,

+            "png_start_read_image/png_read_update_info: duplicate call");

+   }

+}

+#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+void PNGAPI

+png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)

+{

+   png_row_info row_info;

+

+   if (png_ptr == NULL)

+      return;

+

+   png_debug2(1, "in png_read_row (row %lu, pass %d)",

+       (unsigned long)png_ptr->row_number, png_ptr->pass);

+

+   /* png_read_start_row sets the information (in particular iwidth) for this

+    * interlace pass.

+    */

+   if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))

+      png_read_start_row(png_ptr);

+

+   /* 1.5.6: row_info moved out of png_struct to a local here. */

+   row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */

+   row_info.color_type = png_ptr->color_type;

+   row_info.bit_depth = png_ptr->bit_depth;

+   row_info.channels = png_ptr->channels;

+   row_info.pixel_depth = png_ptr->pixel_depth;

+   row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);

+

+   if (png_ptr->row_number == 0 && png_ptr->pass == 0)

+   {

+   /* Check for transforms that have been set but were defined out */

+#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED)

+   if (png_ptr->transformations & PNG_INVERT_MONO)

+      png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined");

+#endif

+

+#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED)

+   if (png_ptr->transformations & PNG_FILLER)

+      png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined");

+#endif

+

+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \

+    !defined(PNG_READ_PACKSWAP_SUPPORTED)

+   if (png_ptr->transformations & PNG_PACKSWAP)

+      png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined");

+#endif

+

+#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED)

+   if (png_ptr->transformations & PNG_PACK)

+      png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined");

+#endif

+

+#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED)

+   if (png_ptr->transformations & PNG_SHIFT)

+      png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined");

+#endif

+

+#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED)

+   if (png_ptr->transformations & PNG_BGR)

+      png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined");

+#endif

+

+#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED)

+   if (png_ptr->transformations & PNG_SWAP_BYTES)

+      png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined");

+#endif

+   }

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   /* If interlaced and we do not need a new row, combine row and return.

+    * Notice that the pixels we have from previous rows have been transformed

+    * already; we can only combine like with like (transformed or

+    * untransformed) and, because of the libpng API for interlaced images, this

+    * means we must transform before de-interlacing.

+    */

+   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))

+   {

+      switch (png_ptr->pass)

+      {

+         case 0:

+            if (png_ptr->row_number & 0x07)

+            {

+               if (dsp_row != NULL)

+                  png_combine_row(png_ptr, dsp_row, 1/*display*/);

+               png_read_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 1:

+            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)

+            {

+               if (dsp_row != NULL)

+                  png_combine_row(png_ptr, dsp_row, 1/*display*/);

+

+               png_read_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 2:

+            if ((png_ptr->row_number & 0x07) != 4)

+            {

+               if (dsp_row != NULL && (png_ptr->row_number & 4))

+                  png_combine_row(png_ptr, dsp_row, 1/*display*/);

+

+               png_read_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 3:

+            if ((png_ptr->row_number & 3) || png_ptr->width < 3)

+            {

+               if (dsp_row != NULL)

+                  png_combine_row(png_ptr, dsp_row, 1/*display*/);

+

+               png_read_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 4:

+            if ((png_ptr->row_number & 3) != 2)

+            {

+               if (dsp_row != NULL && (png_ptr->row_number & 2))

+                  png_combine_row(png_ptr, dsp_row, 1/*display*/);

+

+               png_read_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 5:

+            if ((png_ptr->row_number & 1) || png_ptr->width < 2)

+            {

+               if (dsp_row != NULL)

+                  png_combine_row(png_ptr, dsp_row, 1/*display*/);

+

+               png_read_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         default:

+         case 6:

+            if (!(png_ptr->row_number & 1))

+            {

+               png_read_finish_row(png_ptr);

+               return;

+            }

+            break;

+      }

+   }

+#endif

+

+   if (!(png_ptr->mode & PNG_HAVE_IDAT))

+      png_error(png_ptr, "Invalid attempt to read row data");

+

+   /* Fill the row with IDAT data: */

+   png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1);

+

+   if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)

+   {

+      if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST)

+         png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1,

+            png_ptr->prev_row + 1, png_ptr->row_buf[0]);

+      else

+         png_error(png_ptr, "bad adaptive filter value");

+   }

+

+   /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before

+    * 1.5.6, while the buffer really is this big in current versions of libpng

+    * it may not be in the future, so this was changed just to copy the

+    * interlaced count:

+    */

+   memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1);

+

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&

+       (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))

+   {

+      /* Intrapixel differencing */

+      png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1);

+   }

+#endif

+

+

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+   if (png_ptr->transformations)

+      png_do_read_transformations(png_ptr, &row_info);

+#endif

+

+   /* The transformed pixel depth should match the depth now in row_info. */

+   if (png_ptr->transformed_pixel_depth == 0)

+   {

+      png_ptr->transformed_pixel_depth = row_info.pixel_depth;

+      if (row_info.pixel_depth > png_ptr->maximum_pixel_depth)

+         png_error(png_ptr, "sequential row overflow");

+   }

+

+   else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth)

+      png_error(png_ptr, "internal sequential row size calculation error");

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   /* Blow up interlaced rows to full size */

+   if (png_ptr->interlaced &&

+      (png_ptr->transformations & PNG_INTERLACE))

+   {

+      if (png_ptr->pass < 6)

+         png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,

+            png_ptr->transformations);

+

+      if (dsp_row != NULL)

+         png_combine_row(png_ptr, dsp_row, 1/*display*/);

+

+      if (row != NULL)

+         png_combine_row(png_ptr, row, 0/*row*/);

+   }

+

+   else

+#endif

+   {

+      if (row != NULL)

+         png_combine_row(png_ptr, row, -1/*ignored*/);

+

+      if (dsp_row != NULL)

+         png_combine_row(png_ptr, dsp_row, -1/*ignored*/);

+   }

+   png_read_finish_row(png_ptr);

+

+   if (png_ptr->read_row_fn != NULL)

+      (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);

+

+}

+#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+/* Read one or more rows of image data.  If the image is interlaced,

+ * and png_set_interlace_handling() has been called, the rows need to

+ * contain the contents of the rows from the previous pass.  If the

+ * image has alpha or transparency, and png_handle_alpha()[*] has been

+ * called, the rows contents must be initialized to the contents of the

+ * screen.

+ *

+ * "row" holds the actual image, and pixels are placed in it

+ * as they arrive.  If the image is displayed after each pass, it will

+ * appear to "sparkle" in.  "display_row" can be used to display a

+ * "chunky" progressive image, with finer detail added as it becomes

+ * available.  If you do not want this "chunky" display, you may pass

+ * NULL for display_row.  If you do not want the sparkle display, and

+ * you have not called png_handle_alpha(), you may pass NULL for rows.

+ * If you have called png_handle_alpha(), and the image has either an

+ * alpha channel or a transparency chunk, you must provide a buffer for

+ * rows.  In this case, you do not have to provide a display_row buffer

+ * also, but you may.  If the image is not interlaced, or if you have

+ * not called png_set_interlace_handling(), the display_row buffer will

+ * be ignored, so pass NULL to it.

+ *

+ * [*] png_handle_alpha() does not exist yet, as of this version of libpng

+ */

+

+void PNGAPI

+png_read_rows(png_structrp png_ptr, png_bytepp row,

+    png_bytepp display_row, png_uint_32 num_rows)

+{

+   png_uint_32 i;

+   png_bytepp rp;

+   png_bytepp dp;

+

+   png_debug(1, "in png_read_rows");

+

+   if (png_ptr == NULL)

+      return;

+

+   rp = row;

+   dp = display_row;

+   if (rp != NULL && dp != NULL)

+      for (i = 0; i < num_rows; i++)

+      {

+         png_bytep rptr = *rp++;

+         png_bytep dptr = *dp++;

+

+         png_read_row(png_ptr, rptr, dptr);

+      }

+

+   else if (rp != NULL)

+      for (i = 0; i < num_rows; i++)

+      {

+         png_bytep rptr = *rp;

+         png_read_row(png_ptr, rptr, NULL);

+         rp++;

+      }

+

+   else if (dp != NULL)

+      for (i = 0; i < num_rows; i++)

+      {

+         png_bytep dptr = *dp;

+         png_read_row(png_ptr, NULL, dptr);

+         dp++;

+      }

+}

+#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+/* Read the entire image.  If the image has an alpha channel or a tRNS

+ * chunk, and you have called png_handle_alpha()[*], you will need to

+ * initialize the image to the current image that PNG will be overlaying.

+ * We set the num_rows again here, in case it was incorrectly set in

+ * png_read_start_row() by a call to png_read_update_info() or

+ * png_start_read_image() if png_set_interlace_handling() wasn't called

+ * prior to either of these functions like it should have been.  You can

+ * only call this function once.  If you desire to have an image for

+ * each pass of a interlaced image, use png_read_rows() instead.

+ *

+ * [*] png_handle_alpha() does not exist yet, as of this version of libpng

+ */

+void PNGAPI

+png_read_image(png_structrp png_ptr, png_bytepp image)

+{

+   png_uint_32 i, image_height;

+   int pass, j;

+   png_bytepp rp;

+

+   png_debug(1, "in png_read_image");

+

+   if (png_ptr == NULL)

+      return;

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))

+   {

+      pass = png_set_interlace_handling(png_ptr);

+      /* And make sure transforms are initialized. */

+      png_start_read_image(png_ptr);

+   }

+   else

+   {

+      if (png_ptr->interlaced && !(png_ptr->transformations & PNG_INTERLACE))

+      {

+         /* Caller called png_start_read_image or png_read_update_info without

+          * first turning on the PNG_INTERLACE transform.  We can fix this here,

+          * but the caller should do it!

+          */

+         png_warning(png_ptr, "Interlace handling should be turned on when "

+            "using png_read_image");

+         /* Make sure this is set correctly */

+         png_ptr->num_rows = png_ptr->height;

+      }

+

+      /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in

+       * the above error case.

+       */

+      pass = png_set_interlace_handling(png_ptr);

+   }

+#else

+   if (png_ptr->interlaced)

+      png_error(png_ptr,

+          "Cannot read interlaced image -- interlace handler disabled");

+

+   pass = 1;

+#endif

+

+   image_height=png_ptr->height;

+

+   for (j = 0; j < pass; j++)

+   {

+      rp = image;

+      for (i = 0; i < image_height; i++)

+      {

+         png_read_row(png_ptr, *rp, NULL);

+         rp++;

+      }

+   }

+}

+#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+/* Read the end of the PNG file.  Will not read past the end of the

+ * file, will verify the end is accurate, and will read any comments

+ * or time information at the end of the file, if info is not NULL.

+ */

+void PNGAPI

+png_read_end(png_structrp png_ptr, png_inforp info_ptr)

+{

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+   int keep;

+#endif

+

+   png_debug(1, "in png_read_end");

+

+   if (png_ptr == NULL)

+      return;

+

+   /* If png_read_end is called in the middle of reading the rows there may

+    * still be pending IDAT data and an owned zstream.  Deal with this here.

+    */

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+   if (!png_chunk_unknown_handling(png_ptr, png_IDAT))

+#endif

+      png_read_finish_IDAT(png_ptr);

+

+#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED

+   /* Report invalid palette index; added at libng-1.5.10 */

+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&

+      png_ptr->num_palette_max > png_ptr->num_palette)

+     png_benign_error(png_ptr, "Read palette index exceeding num_palette");

+#endif

+

+   do

+   {

+      png_uint_32 length = png_read_chunk_header(png_ptr);

+      png_uint_32 chunk_name = png_ptr->chunk_name;

+

+      if (chunk_name == png_IHDR)

+         png_handle_IHDR(png_ptr, info_ptr, length);

+

+      else if (chunk_name == png_IEND)

+         png_handle_IEND(png_ptr, info_ptr, length);

+

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+      else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)

+      {

+         if (chunk_name == png_IDAT)

+         {

+            if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))

+               png_benign_error(png_ptr, "Too many IDATs found");

+         }

+         png_handle_unknown(png_ptr, info_ptr, length, keep);

+         if (chunk_name == png_PLTE)

+            png_ptr->mode |= PNG_HAVE_PLTE;

+      }

+#endif

+

+      else if (chunk_name == png_IDAT)

+      {

+         /* Zero length IDATs are legal after the last IDAT has been

+          * read, but not after other chunks have been read.

+          */

+         if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))

+            png_benign_error(png_ptr, "Too many IDATs found");

+

+         png_crc_finish(png_ptr, length);

+      }

+      else if (chunk_name == png_PLTE)

+         png_handle_PLTE(png_ptr, info_ptr, length);

+

+#ifdef PNG_READ_bKGD_SUPPORTED

+      else if (chunk_name == png_bKGD)

+         png_handle_bKGD(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_cHRM_SUPPORTED

+      else if (chunk_name == png_cHRM)

+         png_handle_cHRM(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_gAMA_SUPPORTED

+      else if (chunk_name == png_gAMA)

+         png_handle_gAMA(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_hIST_SUPPORTED

+      else if (chunk_name == png_hIST)

+         png_handle_hIST(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_oFFs_SUPPORTED

+      else if (chunk_name == png_oFFs)

+         png_handle_oFFs(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_pCAL_SUPPORTED

+      else if (chunk_name == png_pCAL)

+         png_handle_pCAL(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_sCAL_SUPPORTED

+      else if (chunk_name == png_sCAL)

+         png_handle_sCAL(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_pHYs_SUPPORTED

+      else if (chunk_name == png_pHYs)

+         png_handle_pHYs(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_sBIT_SUPPORTED

+      else if (chunk_name == png_sBIT)

+         png_handle_sBIT(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_sRGB_SUPPORTED

+      else if (chunk_name == png_sRGB)

+         png_handle_sRGB(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_iCCP_SUPPORTED

+      else if (chunk_name == png_iCCP)

+         png_handle_iCCP(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_sPLT_SUPPORTED

+      else if (chunk_name == png_sPLT)

+         png_handle_sPLT(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_tEXt_SUPPORTED

+      else if (chunk_name == png_tEXt)

+         png_handle_tEXt(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_tIME_SUPPORTED

+      else if (chunk_name == png_tIME)

+         png_handle_tIME(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_tRNS_SUPPORTED

+      else if (chunk_name == png_tRNS)

+         png_handle_tRNS(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_zTXt_SUPPORTED

+      else if (chunk_name == png_zTXt)

+         png_handle_zTXt(png_ptr, info_ptr, length);

+#endif

+

+#ifdef PNG_READ_iTXt_SUPPORTED

+      else if (chunk_name == png_iTXt)

+         png_handle_iTXt(png_ptr, info_ptr, length);

+#endif

+

+      else

+         png_handle_unknown(png_ptr, info_ptr, length,

+            PNG_HANDLE_CHUNK_AS_DEFAULT);

+   } while (!(png_ptr->mode & PNG_HAVE_IEND));

+}

+#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */

+

+/* Free all memory used in the read struct */

+static void

+png_read_destroy(png_structrp png_ptr)

+{

+   png_debug(1, "in png_read_destroy");

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+   png_destroy_gamma_table(png_ptr);

+#endif

+

+   png_free(png_ptr, png_ptr->big_row_buf);

+   png_free(png_ptr, png_ptr->big_prev_row);

+   png_free(png_ptr, png_ptr->read_buffer);

+

+#ifdef PNG_READ_QUANTIZE_SUPPORTED

+   png_free(png_ptr, png_ptr->palette_lookup);

+   png_free(png_ptr, png_ptr->quantize_index);

+#endif

+

+   if (png_ptr->free_me & PNG_FREE_PLTE)

+      png_zfree(png_ptr, png_ptr->palette);

+   png_ptr->free_me &= ~PNG_FREE_PLTE;

+

+#if defined(PNG_tRNS_SUPPORTED) || \

+    defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)

+   if (png_ptr->free_me & PNG_FREE_TRNS)

+      png_free(png_ptr, png_ptr->trans_alpha);

+   png_ptr->free_me &= ~PNG_FREE_TRNS;

+#endif

+

+   inflateEnd(&png_ptr->zstream);

+

+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED

+   png_free(png_ptr, png_ptr->save_buffer);

+#endif

+

+#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) &&\

+   defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)

+   png_free(png_ptr, png_ptr->unknown_chunk.data);

+#endif

+

+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+   png_free(png_ptr, png_ptr->chunk_list);

+#endif

+

+   /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error

+    * callbacks are still set at this point.  They are required to complete the

+    * destruction of the png_struct itself.

+    */

+}

+

+/* Free all memory used by the read */

+void PNGAPI

+png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,

+    png_infopp end_info_ptr_ptr)

+{

+   png_structrp png_ptr = NULL;

+

+   png_debug(1, "in png_destroy_read_struct");

+

+   if (png_ptr_ptr != NULL)

+      png_ptr = *png_ptr_ptr;

+

+   if (png_ptr == NULL)

+      return;

+

+   /* libpng 1.6.0: use the API to destroy info structs to ensure consistent

+    * behavior.  Prior to 1.6.0 libpng did extra 'info' destruction in this API.

+    * The extra was, apparently, unnecessary yet this hides memory leak bugs.

+    */

+   png_destroy_info_struct(png_ptr, end_info_ptr_ptr);

+   png_destroy_info_struct(png_ptr, info_ptr_ptr);

+

+   *png_ptr_ptr = NULL;

+   png_read_destroy(png_ptr);

+   png_destroy_png_struct(png_ptr);

+}

+

+void PNGAPI

+png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn)

+{

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->read_row_fn = read_row_fn;

+}

+

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+#ifdef PNG_INFO_IMAGE_SUPPORTED

+void PNGAPI

+png_read_png(png_structrp png_ptr, png_inforp info_ptr,

+                           int transforms,

+                           voidp params)

+{

+   int row;

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   /* png_read_info() gives us all of the information from the

+    * PNG file before the first IDAT (image data chunk).

+    */

+   png_read_info(png_ptr, info_ptr);

+   if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep)))

+      png_error(png_ptr, "Image is too high to process with png_read_png()");

+

+   /* -------------- image transformations start here ------------------- */

+

+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED

+   /* Tell libpng to strip 16-bit/color files down to 8 bits per color.

+    */

+   if (transforms & PNG_TRANSFORM_SCALE_16)

+   {

+     /* Added at libpng-1.5.4. "strip_16" produces the same result that it

+      * did in earlier versions, while "scale_16" is now more accurate.

+      */

+      png_set_scale_16(png_ptr);

+   }

+#endif

+

+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED

+   /* If both SCALE and STRIP are required pngrtran will effectively cancel the

+    * latter by doing SCALE first.  This is ok and allows apps not to check for

+    * which is supported to get the right answer.

+    */

+   if (transforms & PNG_TRANSFORM_STRIP_16)

+      png_set_strip_16(png_ptr);

+#endif

+

+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED

+   /* Strip alpha bytes from the input data without combining with

+    * the background (not recommended).

+    */

+   if (transforms & PNG_TRANSFORM_STRIP_ALPHA)

+      png_set_strip_alpha(png_ptr);

+#endif

+

+#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)

+   /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single

+    * byte into separate bytes (useful for paletted and grayscale images).

+    */

+   if (transforms & PNG_TRANSFORM_PACKING)

+      png_set_packing(png_ptr);

+#endif

+

+#ifdef PNG_READ_PACKSWAP_SUPPORTED

+   /* Change the order of packed pixels to least significant bit first

+    * (not useful if you are using png_set_packing).

+    */

+   if (transforms & PNG_TRANSFORM_PACKSWAP)

+      png_set_packswap(png_ptr);

+#endif

+

+#ifdef PNG_READ_EXPAND_SUPPORTED

+   /* Expand paletted colors into true RGB triplets

+    * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel

+    * Expand paletted or RGB images with transparency to full alpha

+    * channels so the data will be available as RGBA quartets.

+    */

+   if (transforms & PNG_TRANSFORM_EXPAND)

+      if ((png_ptr->bit_depth < 8) ||

+          (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||

+          (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))

+         png_set_expand(png_ptr);

+#endif

+

+   /* We don't handle background color or gamma transformation or quantizing.

+    */

+

+#ifdef PNG_READ_INVERT_SUPPORTED

+   /* Invert monochrome files to have 0 as white and 1 as black

+    */

+   if (transforms & PNG_TRANSFORM_INVERT_MONO)

+      png_set_invert_mono(png_ptr);

+#endif

+

+#ifdef PNG_READ_SHIFT_SUPPORTED

+   /* If you want to shift the pixel values from the range [0,255] or

+    * [0,65535] to the original [0,7] or [0,31], or whatever range the

+    * colors were originally in:

+    */

+   if ((transforms & PNG_TRANSFORM_SHIFT)

+       && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))

+   {

+      png_color_8p sig_bit;

+

+      png_get_sBIT(png_ptr, info_ptr, &sig_bit);

+      png_set_shift(png_ptr, sig_bit);

+   }

+#endif

+

+#ifdef PNG_READ_BGR_SUPPORTED

+   /* Flip the RGB pixels to BGR (or RGBA to BGRA) */

+   if (transforms & PNG_TRANSFORM_BGR)

+      png_set_bgr(png_ptr);

+#endif

+

+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED

+   /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */

+   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)

+      png_set_swap_alpha(png_ptr);

+#endif

+

+#ifdef PNG_READ_SWAP_SUPPORTED

+   /* Swap bytes of 16-bit files to least significant byte first */

+   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)

+      png_set_swap(png_ptr);

+#endif

+

+/* Added at libpng-1.2.41 */

+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED

+   /* Invert the alpha channel from opacity to transparency */

+   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)

+      png_set_invert_alpha(png_ptr);

+#endif

+

+/* Added at libpng-1.2.41 */

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+   /* Expand grayscale image to RGB */

+   if (transforms & PNG_TRANSFORM_GRAY_TO_RGB)

+      png_set_gray_to_rgb(png_ptr);

+#endif

+

+/* Added at libpng-1.5.4 */

+#ifdef PNG_READ_EXPAND_16_SUPPORTED

+   if (transforms & PNG_TRANSFORM_EXPAND_16)

+      png_set_expand_16(png_ptr);

+#endif

+

+   /* We don't handle adding filler bytes */

+

+   /* We use png_read_image and rely on that for interlace handling, but we also

+    * call png_read_update_info therefore must turn on interlace handling now:

+    */

+   (void)png_set_interlace_handling(png_ptr);

+

+   /* Optional call to gamma correct and add the background to the palette

+    * and update info structure.  REQUIRED if you are expecting libpng to

+    * update the palette for you (i.e., you selected such a transform above).

+    */

+   png_read_update_info(png_ptr, info_ptr);

+

+   /* -------------- image transformations end here ------------------- */

+

+   png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);

+   if (info_ptr->row_pointers == NULL)

+   {

+      png_uint_32 iptr;

+

+      info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,

+          info_ptr->height * (sizeof (png_bytep)));

+      for (iptr=0; iptr<info_ptr->height; iptr++)

+         info_ptr->row_pointers[iptr] = NULL;

+

+      info_ptr->free_me |= PNG_FREE_ROWS;

+

+      for (row = 0; row < (int)info_ptr->height; row++)

+         info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,

+            png_get_rowbytes(png_ptr, info_ptr));

+   }

+

+   png_read_image(png_ptr, info_ptr->row_pointers);

+   info_ptr->valid |= PNG_INFO_IDAT;

+

+   /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */

+   png_read_end(png_ptr, info_ptr);

+

+   PNG_UNUSED(transforms)   /* Quiet compiler warnings */

+   PNG_UNUSED(params)

+

+}

+#endif /* PNG_INFO_IMAGE_SUPPORTED */

+#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */

+

+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED

+/* SIMPLIFIED READ

+ *

+ * This code currently relies on the sequential reader, though it could easily

+ * be made to work with the progressive one.

+ */

+/* Arguments to png_image_finish_read: */

+

+/* Encoding of PNG data (used by the color-map code) */

+/* TODO: change these, dang, ANSI-C reserves the 'E' namespace. */

+#  define E_NOTSET  0 /* File encoding not yet known */

+#  define E_sRGB    1 /* 8-bit encoded to sRGB gamma */

+#  define E_LINEAR  2 /* 16-bit linear: not encoded, NOT pre-multiplied! */

+#  define E_FILE    3 /* 8-bit encoded to file gamma, not sRGB or linear */

+#  define E_LINEAR8 4 /* 8-bit linear: only from a file value */

+

+/* Color-map processing: after libpng has run on the PNG image further

+ * processing may be needed to conver the data to color-map indicies.

+ */

+#define PNG_CMAP_NONE      0

+#define PNG_CMAP_GA        1 /* Process GA data to a color-map with alpha */

+#define PNG_CMAP_TRANS     2 /* Process GA data to a background index */

+#define PNG_CMAP_RGB       3 /* Process RGB data */

+#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */

+

+/* The following document where the background is for each processing case. */

+#define PNG_CMAP_NONE_BACKGROUND      256

+#define PNG_CMAP_GA_BACKGROUND        231

+#define PNG_CMAP_TRANS_BACKGROUND     254

+#define PNG_CMAP_RGB_BACKGROUND       256

+#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216

+

+typedef struct

+{

+   /* Arguments: */

+   png_imagep image;

+   png_voidp  buffer;

+   png_int_32 row_stride;

+   png_voidp  colormap;

+   png_const_colorp background;

+   /* Local variables: */

+   png_voidp       local_row;

+   png_voidp       first_row;

+   ptrdiff_t       row_bytes;           /* step between rows */

+   int             file_encoding;       /* E_ values above */

+   png_fixed_point gamma_to_linear;     /* For E_FILE, reciprocal of gamma */

+   int             colormap_processing; /* PNG_CMAP_ values above */

+} png_image_read_control;

+

+/* Do all the *safe* initialization - 'safe' means that png_error won't be

+ * called, so setting up the jmp_buf is not required.  This means that anything

+ * called from here must *not* call png_malloc - it has to call png_malloc_warn

+ * instead so that control is returned safely back to this routine.

+ */

+static int

+png_image_read_init(png_imagep image)

+{

+   if (image->opaque == NULL)

+   {

+      png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image,

+          png_safe_error, png_safe_warning);

+

+      /* And set the rest of the structure to NULL to ensure that the various

+       * fields are consistent.

+       */

+      memset(image, 0, (sizeof *image));

+      image->version = PNG_IMAGE_VERSION;

+

+      if (png_ptr != NULL)

+      {

+         png_infop info_ptr = png_create_info_struct(png_ptr);

+

+         if (info_ptr != NULL)

+         {

+            png_controlp control = png_voidcast(png_controlp,

+               png_malloc_warn(png_ptr, (sizeof *control)));

+

+            if (control != NULL)

+            {

+               memset(control, 0, (sizeof *control));

+

+               control->png_ptr = png_ptr;

+               control->info_ptr = info_ptr;

+               control->for_write = 0;

+

+               image->opaque = control;

+               return 1;

+            }

+

+            /* Error clean up */

+            png_destroy_info_struct(png_ptr, &info_ptr);

+         }

+

+         png_destroy_read_struct(&png_ptr, NULL, NULL);

+      }

+

+      return png_image_error(image, "png_image_read: out of memory");

+   }

+

+   return png_image_error(image, "png_image_read: opaque pointer not NULL");

+}

+

+/* Utility to find the base format of a PNG file from a png_struct. */

+static png_uint_32

+png_image_format(png_structrp png_ptr)

+{

+   png_uint_32 format = 0;

+

+   if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)

+      format |= PNG_FORMAT_FLAG_COLOR;

+

+   if (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)

+      format |= PNG_FORMAT_FLAG_ALPHA;

+

+   /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS

+    * sets the png_struct fields; that's all we are interested in here.  The

+    * precise interaction with an app call to png_set_tRNS and PNG file reading

+    * is unclear.

+    */

+   else if (png_ptr->num_trans > 0)

+      format |= PNG_FORMAT_FLAG_ALPHA;

+

+   if (png_ptr->bit_depth == 16)

+      format |= PNG_FORMAT_FLAG_LINEAR;

+

+   if (png_ptr->color_type & PNG_COLOR_MASK_PALETTE)

+      format |= PNG_FORMAT_FLAG_COLORMAP;

+

+   return format;

+}

+

+/* Is the given gamma significantly different from sRGB?  The test is the same

+ * one used in pngrtran.c when deciding whether to do gamma correction.  The

+ * arithmetic optimizes the division by using the fact that the inverse of the

+ * file sRGB gamma is 2.2

+ */

+static int

+png_gamma_not_sRGB(png_fixed_point g)

+{

+   if (g < PNG_FP_1)

+   {

+      /* An uninitialized gamma is assumed to be sRGB for the simplified API. */

+      if (g == 0)

+         return 0;

+

+      return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);

+   }

+

+   return 1;

+}

+

+/* Do the main body of a 'png_image_begin_read' function; read the PNG file

+ * header and fill in all the information.  This is executed in a safe context,

+ * unlike the init routine above.

+ */

+static int

+png_image_read_header(png_voidp argument)

+{

+   png_imagep image = png_voidcast(png_imagep, argument);

+   png_structrp png_ptr = image->opaque->png_ptr;

+   png_inforp info_ptr = image->opaque->info_ptr;

+

+   png_set_benign_errors(png_ptr, 1/*warn*/);

+   png_read_info(png_ptr, info_ptr);

+

+   /* Do this the fast way; just read directly out of png_struct. */

+   image->width = png_ptr->width;

+   image->height = png_ptr->height;

+

+   {

+      png_uint_32 format = png_image_format(png_ptr);

+

+      image->format = format;

+

+#ifdef PNG_COLORSPACE_SUPPORTED

+      /* Does the colorspace match sRGB?  If there is no color endpoint

+       * (colorant) information assume yes, otherwise require the

+       * 'ENDPOINTS_MATCHE_sRGB' colorspace flag to have been set.  If the

+       * colorspace has been determined to be invalid ignore it.

+       */

+      if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags

+         & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB|

+            PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS))

+         image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB;

+#endif

+   }

+

+   /* We need the maximum number of entries regardless of the format the

+    * application sets here.

+    */

+   {

+      png_uint_32 cmap_entries;

+

+      switch (png_ptr->color_type)

+      {

+         case PNG_COLOR_TYPE_GRAY:

+            cmap_entries = 1U << png_ptr->bit_depth;

+            break;

+

+         case PNG_COLOR_TYPE_PALETTE:

+            cmap_entries = png_ptr->num_palette;

+            break;

+

+         default:

+            cmap_entries = 256;

+            break;

+      }

+

+      if (cmap_entries > 256)

+         cmap_entries = 256;

+

+      image->colormap_entries = cmap_entries;

+   }

+

+   return 1;

+}

+

+#ifdef PNG_STDIO_SUPPORTED

+int PNGAPI

+png_image_begin_read_from_stdio(png_imagep image, FILE* file)

+{

+   if (image != NULL && image->version == PNG_IMAGE_VERSION)

+   {

+      if (file != NULL)

+      {

+         if (png_image_read_init(image))

+         {

+            /* This is slightly evil, but png_init_io doesn't do anything other

+             * than this and we haven't changed the standard IO functions so

+             * this saves a 'safe' function.

+             */

+            image->opaque->png_ptr->io_ptr = file;

+            return png_safe_execute(image, png_image_read_header, image);

+         }

+      }

+

+      else

+         return png_image_error(image,

+            "png_image_begin_read_from_stdio: invalid argument");

+   }

+

+   else if (image != NULL)

+      return png_image_error(image,

+         "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION");

+

+   return 0;

+}

+

+int PNGAPI

+png_image_begin_read_from_file(png_imagep image, const char *file_name)

+{

+   if (image != NULL && image->version == PNG_IMAGE_VERSION)

+   {

+      if (file_name != NULL)

+      {

+         FILE *fp = fopen(file_name, "rb");

+

+         if (fp != NULL)

+         {

+            if (png_image_read_init(image))

+            {

+               image->opaque->png_ptr->io_ptr = fp;

+               image->opaque->owned_file = 1;

+               return png_safe_execute(image, png_image_read_header, image);

+            }

+

+            /* Clean up: just the opened file. */

+            (void)fclose(fp);

+         }

+

+         else

+            return png_image_error(image, strerror(errno));

+      }

+

+      else

+         return png_image_error(image,

+            "png_image_begin_read_from_file: invalid argument");

+   }

+

+   else if (image != NULL)

+      return png_image_error(image,

+         "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION");

+

+   return 0;

+}

+#endif /* PNG_STDIO_SUPPORTED */

+

+static void PNGCBAPI

+png_image_memory_read(png_structp png_ptr, png_bytep out, png_size_t need)

+{

+   if (png_ptr != NULL)

+   {

+      png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr);

+      if (image != NULL)

+      {

+         png_controlp cp = image->opaque;

+         if (cp != NULL)

+         {

+            png_const_bytep memory = cp->memory;

+            png_size_t size = cp->size;

+

+            if (memory != NULL && size >= need)

+            {

+               memcpy(out, memory, need);

+               cp->memory = memory + need;

+               cp->size = size - need;

+               return;

+            }

+

+            png_error(png_ptr, "read beyond end of data");

+         }

+      }

+

+      png_error(png_ptr, "invalid memory read");

+   }

+}

+

+int PNGAPI png_image_begin_read_from_memory(png_imagep image,

+   png_const_voidp memory, png_size_t size)

+{

+   if (image != NULL && image->version == PNG_IMAGE_VERSION)

+   {

+      if (memory != NULL && size > 0)

+      {

+         if (png_image_read_init(image))

+         {

+            /* Now set the IO functions to read from the memory buffer and

+             * store it into io_ptr.  Again do this in-place to avoid calling a

+             * libpng function that requires error handling.

+             */

+            image->opaque->memory = png_voidcast(png_const_bytep, memory);

+            image->opaque->size = size;

+            image->opaque->png_ptr->io_ptr = image;

+            image->opaque->png_ptr->read_data_fn = png_image_memory_read;

+

+            return png_safe_execute(image, png_image_read_header, image);

+         }

+      }

+

+      else

+         return png_image_error(image,

+            "png_image_begin_read_from_memory: invalid argument");

+   }

+

+   else if (image != NULL)

+      return png_image_error(image,

+         "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION");

+

+   return 0;

+}

+

+/* Utility function to skip chunks that are not used by the simplified image

+ * read functions and an appropriate macro to call it.

+ */

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+static void

+png_image_skip_unused_chunks(png_structrp png_ptr)

+{

+   /* Prepare the reader to ignore all recognized chunks whose data will not

+    * be used, i.e., all chunks recognized by libpng except for those

+    * involved in basic image reading:

+    *

+    *    IHDR, PLTE, IDAT, IEND

+    *

+    * Or image data handling:

+    *

+    *    tRNS, bKGD, gAMA, cHRM, sRGB, iCCP and sBIT.

+    *

+    * This provides a small performance improvement and eliminates any

+    * potential vulnerability to security problems in the unused chunks.

+    */

+   {

+         static PNG_CONST png_byte chunks_to_process[] = {

+            98,  75,  71,  68, '\0',  /* bKGD */

+            99,  72,  82,  77, '\0',  /* cHRM */

+           103,  65,  77,  65, '\0',  /* gAMA */

+           105,  67,  67,  80, '\0',  /* iCCP */

+           115,  66,  73,  84, '\0',  /* sBIT */

+           115,  82,  71,  66, '\0',  /* sRGB */

+           };

+

+       /* Ignore unknown chunks and all other chunks except for the

+        * IHDR, PLTE, tRNS, IDAT, and IEND chunks.

+        */

+       png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER,

+         NULL, -1);

+

+       /* But do not ignore image data handling chunks */

+       png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT,

+         chunks_to_process, (sizeof chunks_to_process)/5);

+    }

+}

+

+#  define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p)

+#else

+#  define PNG_SKIP_CHUNKS(p) ((void)0)

+#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */

+

+/* The following macro gives the exact rounded answer for all values in the

+ * range 0..255 (it actually divides by 51.2, but the rounding still generates

+ * the correct numbers 0..5

+ */

+#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8)

+

+/* Utility functions to make particular color-maps */

+static void

+set_file_encoding(png_image_read_control *display)

+{

+   png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma;

+   if (png_gamma_significant(g))

+   {

+      if (png_gamma_not_sRGB(g))

+      {

+         display->file_encoding = E_FILE;

+         display->gamma_to_linear = png_reciprocal(g);

+      }

+

+      else

+         display->file_encoding = E_sRGB;

+   }

+

+   else

+      display->file_encoding = E_LINEAR8;

+}

+

+static unsigned int

+decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding)

+{

+   if (encoding == E_FILE) /* double check */

+      encoding = display->file_encoding;

+

+   if (encoding == E_NOTSET) /* must be the file encoding */

+   {

+      set_file_encoding(display);

+      encoding = display->file_encoding;

+   }

+

+   switch (encoding)

+   {

+      case E_FILE:

+         value = png_gamma_16bit_correct(value*257, display->gamma_to_linear);

+         break;

+

+      case E_sRGB:

+         value = png_sRGB_table[value];

+         break;

+

+      case E_LINEAR:

+         break;

+

+      case E_LINEAR8:

+         value *= 257;

+         break;

+

+      default:

+         png_error(display->image->opaque->png_ptr,

+            "unexpected encoding (internal error)");

+         break;

+   }

+

+   return value;

+}

+

+static png_uint_32

+png_colormap_compose(png_image_read_control *display,

+   png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha,

+   png_uint_32 background, int encoding)

+{

+   /* The file value is composed on the background, the background has the given

+    * encoding and so does the result, the file is encoded with E_FILE and the

+    * file and alpha are 8-bit values.  The (output) encoding will always be

+    * E_LINEAR or E_sRGB.

+    */

+   png_uint_32 f = decode_gamma(display, foreground, foreground_encoding);

+   png_uint_32 b = decode_gamma(display, background, encoding);

+

+   /* The alpha is always an 8-bit value (it comes from the palette), the value

+    * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires.

+    */

+   f = f * alpha + b * (255-alpha);

+

+   if (encoding == E_LINEAR)

+   {

+      /* Scale to 65535; divide by 255, approximately (in fact this is extremely

+       * accurate, it divides by 255.00000005937181414556, with no overflow.)

+       */

+      f *= 257; /* Now scaled by 65535 */

+      f += f >> 16;

+      f = (f+32768) >> 16;

+   }

+

+   else /* E_sRGB */

+      f = PNG_sRGB_FROM_LINEAR(f);

+

+   return f;

+}

+

+/* NOTE: E_LINEAR values to this routine must be 16-bit, but E_FILE values must

+ * be 8-bit.

+ */

+static void

+png_create_colormap_entry(png_image_read_control *display,

+   png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue,

+   png_uint_32 alpha, int encoding)

+{

+   png_imagep image = display->image;

+   const int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) ?

+      E_LINEAR : E_sRGB;

+   const int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 &&

+      (red != green || green != blue);

+

+   if (ip > 255)

+      png_error(image->opaque->png_ptr, "color-map index out of range");

+

+   /* Update the cache with whether the file gamma is significantly different

+    * from sRGB.

+    */

+   if (encoding == E_FILE)

+   {

+      if (display->file_encoding == E_NOTSET)

+         set_file_encoding(display);

+

+      /* Note that the cached value may be E_FILE too, but if it is then the

+       * gamma_to_linear member has been set.

+       */

+      encoding = display->file_encoding;

+   }

+

+   if (encoding == E_FILE)

+   {

+      png_fixed_point g = display->gamma_to_linear;

+

+      red = png_gamma_16bit_correct(red*257, g);

+      green = png_gamma_16bit_correct(green*257, g);

+      blue = png_gamma_16bit_correct(blue*257, g);

+

+      if (convert_to_Y || output_encoding == E_LINEAR)

+      {

+         alpha *= 257;

+         encoding = E_LINEAR;

+      }

+

+      else

+      {

+         red = PNG_sRGB_FROM_LINEAR(red * 255);

+         green = PNG_sRGB_FROM_LINEAR(green * 255);

+         blue = PNG_sRGB_FROM_LINEAR(blue * 255);

+         encoding = E_sRGB;

+      }

+   }

+

+   else if (encoding == E_LINEAR8)

+   {

+      /* This encoding occurs quite frequently in test cases because PngSuite

+       * includes a gAMA 1.0 chunk with most images.

+       */

+      red *= 257;

+      green *= 257;

+      blue *= 257;

+      alpha *= 257;

+      encoding = E_LINEAR;

+   }

+

+   else if (encoding == E_sRGB && (convert_to_Y || output_encoding == E_LINEAR))

+   {

+      /* The values are 8-bit sRGB values, but must be converted to 16-bit

+       * linear.

+       */

+      red = png_sRGB_table[red];

+      green = png_sRGB_table[green];

+      blue = png_sRGB_table[blue];

+      alpha *= 257;

+      encoding = E_LINEAR;

+   }

+

+   /* This is set if the color isn't gray but the output is. */

+   if (encoding == E_LINEAR)

+   {

+      if (convert_to_Y)

+      {

+         /* NOTE: these values are copied from png_do_rgb_to_gray */

+         png_uint_32 y = (png_uint_32)6968 * red  + (png_uint_32)23434 * green +

+            (png_uint_32)2366 * blue;

+

+         if (output_encoding == E_LINEAR)

+            y = (y + 16384) >> 15;

+

+         else

+         {

+            /* y is scaled by 32768, we need it scaled by 255: */

+            y = (y + 128) >> 8;

+            y *= 255;

+            y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7);

+            encoding = E_sRGB;

+         }

+

+         blue = red = green = y;

+      }

+

+      else if (output_encoding == E_sRGB)

+      {

+         red = PNG_sRGB_FROM_LINEAR(red * 255);

+         green = PNG_sRGB_FROM_LINEAR(green * 255);

+         blue = PNG_sRGB_FROM_LINEAR(blue * 255);

+         alpha = PNG_DIV257(alpha);

+         encoding = E_sRGB;

+      }

+   }

+

+   if (encoding != output_encoding)

+      png_error(image->opaque->png_ptr, "bad encoding (internal error)");

+

+   /* Store the value. */

+   {

+#     ifdef PNG_FORMAT_BGR_SUPPORTED

+         const int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 &&

+            (image->format & PNG_FORMAT_FLAG_ALPHA) != 0;

+#     else

+#        define afirst 0

+#     endif

+#     ifdef PNG_FORMAT_BGR_SUPPORTED

+         const int bgr = (image->format & PNG_FORMAT_FLAG_BGR) ? 2 : 0;

+#     else

+#        define bgr 0

+#     endif

+

+      if (output_encoding == E_LINEAR)

+      {

+         png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap);

+

+         entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format);

+

+         /* The linear 16-bit values must be pre-multiplied by the alpha channel

+          * value, if less than 65535 (this is, effectively, composite on black

+          * if the alpha channel is removed.)

+          */

+         switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))

+         {

+            case 4:

+               entry[afirst ? 0 : 3] = (png_uint_16)alpha;

+               /* FALL THROUGH */

+

+            case 3:

+               if (alpha < 65535)

+               {

+                  if (alpha > 0)

+                  {

+                     blue = (blue * alpha + 32767U)/65535U;

+                     green = (green * alpha + 32767U)/65535U;

+                     red = (red * alpha + 32767U)/65535U;

+                  }

+

+                  else

+                     red = green = blue = 0;

+               }

+               entry[afirst + (2 ^ bgr)] = (png_uint_16)blue;

+               entry[afirst + 1] = (png_uint_16)green;

+               entry[afirst + bgr] = (png_uint_16)red;

+               break;

+

+            case 2:

+               entry[1 ^ afirst] = (png_uint_16)alpha;

+               /* FALL THROUGH */

+

+            case 1:

+               if (alpha < 65535)

+               {

+                  if (alpha > 0)

+                     green = (green * alpha + 32767U)/65535U;

+

+                  else

+                     green = 0;

+               }

+               entry[afirst] = (png_uint_16)green;

+               break;

+

+            default:

+               break;

+         }

+      }

+

+      else /* output encoding is E_sRGB */

+      {

+         png_bytep entry = png_voidcast(png_bytep, display->colormap);

+

+         entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format);

+

+         switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))

+         {

+            case 4:

+               entry[afirst ? 0 : 3] = (png_byte)alpha;

+            case 3:

+               entry[afirst + (2 ^ bgr)] = (png_byte)blue;

+               entry[afirst + 1] = (png_byte)green;

+               entry[afirst + bgr] = (png_byte)red;

+               break;

+

+            case 2:

+               entry[1 ^ afirst] = (png_byte)alpha;

+            case 1:

+               entry[afirst] = (png_byte)green;

+               break;

+

+            default:

+               break;

+         }

+      }

+

+#     ifdef afirst

+#        undef afirst

+#     endif

+#     ifdef bgr

+#        undef bgr

+#     endif

+   }

+}

+

+static int

+make_gray_file_colormap(png_image_read_control *display)

+{

+   unsigned int i;

+

+   for (i=0; i<256; ++i)

+      png_create_colormap_entry(display, i, i, i, i, 255, E_FILE);

+

+   return i;

+}

+

+static int

+make_gray_colormap(png_image_read_control *display)

+{

+   unsigned int i;

+

+   for (i=0; i<256; ++i)

+      png_create_colormap_entry(display, i, i, i, i, 255, E_sRGB);

+

+   return i;

+}

+#define PNG_GRAY_COLORMAP_ENTRIES 256

+

+static int

+make_ga_colormap(png_image_read_control *display)

+{

+   unsigned int i, a;

+

+   /* Alpha is retained, the output will be a color-map with entries

+    * selected by six levels of alpha.  One transparent entry, 6 gray

+    * levels for all the intermediate alpha values, leaving 230 entries

+    * for the opaque grays.  The color-map entries are the six values

+    * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the

+    * relevant entry.

+    *

+    * if (alpha > 229) // opaque

+    * {

+    *    // The 231 entries are selected to make the math below work:

+    *    base = 0;

+    *    entry = (231 * gray + 128) >> 8;

+    * }

+    * else if (alpha < 26) // transparent

+    * {

+    *    base = 231;

+    *    entry = 0;

+    * }

+    * else // partially opaque

+    * {

+    *    base = 226 + 6 * PNG_DIV51(alpha);

+    *    entry = PNG_DIV51(gray);

+    * }

+    */

+   i = 0;

+   while (i < 231)

+   {

+      unsigned int gray = (i * 256 + 115) / 231;

+      png_create_colormap_entry(display, i++, gray, gray, gray, 255, E_sRGB);

+   }

+

+   /* 255 is used here for the component values for consistency with the code

+    * that undoes premultiplication in pngwrite.c.

+    */

+   png_create_colormap_entry(display, i++, 255, 255, 255, 0, E_sRGB);

+

+   for (a=1; a<5; ++a)

+   {

+      unsigned int g;

+

+      for (g=0; g<6; ++g)

+         png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51,

+            E_sRGB);

+   }

+

+   return i;

+}

+

+#define PNG_GA_COLORMAP_ENTRIES 256

+

+static int

+make_rgb_colormap(png_image_read_control *display)

+{

+   unsigned int i, r;

+

+   /* Build a 6x6x6 opaque RGB cube */

+   for (i=r=0; r<6; ++r)

+   {

+      unsigned int g;

+

+      for (g=0; g<6; ++g)

+      {

+         unsigned int b;

+

+         for (b=0; b<6; ++b)

+            png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255,

+               E_sRGB);

+      }

+   }

+

+   return i;

+}

+

+#define PNG_RGB_COLORMAP_ENTRIES 216

+

+/* Return a palette index to the above palette given three 8-bit sRGB values. */

+#define PNG_RGB_INDEX(r,g,b) \

+   ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b)))

+

+static int

+png_image_read_colormap(png_voidp argument)

+{

+   png_image_read_control *display =

+      png_voidcast(png_image_read_control*, argument);

+   const png_imagep image = display->image;

+

+   const png_structrp png_ptr = image->opaque->png_ptr;

+   const png_uint_32 output_format = image->format;

+   const int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) ?

+      E_LINEAR : E_sRGB;

+

+   unsigned int cmap_entries;

+   unsigned int output_processing;        /* Output processing option */

+   unsigned int data_encoding = E_NOTSET; /* Encoding libpng must produce */

+

+   /* Background information; the background color and the index of this color

+    * in the color-map if it exists (else 256).

+    */

+   unsigned int background_index = 256;

+   png_uint_32 back_r, back_g, back_b;

+

+   /* Flags to accumulate things that need to be done to the input. */

+   int expand_tRNS = 0;

+

+   /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is

+    * very difficult to do, the results look awful, and it is difficult to see

+    * what possible use it is because the application can't control the

+    * color-map.

+    */

+   if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 ||

+         png_ptr->num_trans > 0) /* alpha in input */ &&

+      ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */)

+   {

+      if (output_encoding == E_LINEAR) /* compose on black */

+         back_b = back_g = back_r = 0;

+

+      else if (display->background == NULL /* no way to remove it */)

+         png_error(png_ptr,

+            "a background color must be supplied to remove alpha/transparency");

+

+      /* Get a copy of the background color (this avoids repeating the checks

+       * below.)  The encoding is 8-bit sRGB or 16-bit linear, depending on the

+       * output format.

+       */

+      else

+      {

+         back_g = display->background->green;

+         if (output_format & PNG_FORMAT_FLAG_COLOR)

+         {

+            back_r = display->background->red;

+            back_b = display->background->blue;

+         }

+         else

+            back_b = back_r = back_g;

+      }

+   }

+

+   else if (output_encoding == E_LINEAR)

+      back_b = back_r = back_g = 65535;

+

+   else

+      back_b = back_r = back_g = 255;

+

+   /* Default the input file gamma if required - this is necessary because

+    * libpng assumes that if no gamma information is present the data is in the

+    * output format, but the simplified API deduces the gamma from the input

+    * format.

+    */

+   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0)

+   {

+      /* Do this directly, not using the png_colorspace functions, to ensure

+       * that it happens even if the colorspace is invalid (though probably if

+       * it is the setting will be ignored)  Note that the same thing can be

+       * achieved at the application interface with png_set_gAMA.

+       */

+      if (png_ptr->bit_depth == 16 &&

+         (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)

+         png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR;

+

+      else

+         png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE;

+

+      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;

+   }

+

+   /* Decide what to do based on the PNG color type of the input data.  The

+    * utility function png_create_colormap_entry deals with most aspects of the

+    * output transformations; this code works out how to produce bytes of

+    * color-map entries from the original format.

+    */

+   switch (png_ptr->color_type)

+   {

+      case PNG_COLOR_TYPE_GRAY:

+         if (png_ptr->bit_depth <= 8)

+         {

+            /* There at most 256 colors in the output, regardless of

+             * transparency.

+             */

+            unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0;

+

+            cmap_entries = 1U << png_ptr->bit_depth;

+            if (cmap_entries > image->colormap_entries)

+               png_error(png_ptr, "gray[8] color-map: too few entries");

+

+            step = 255 / (cmap_entries - 1);

+            output_processing = PNG_CMAP_NONE;

+

+            /* If there is a tRNS chunk then this either selects a transparent

+             * value or, if the output has no alpha, the background color.

+             */

+            if (png_ptr->num_trans > 0)

+            {

+               trans = png_ptr->trans_color.gray;

+

+               if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0)

+                  back_alpha = output_encoding == E_LINEAR ? 65535 : 255;

+            }

+

+            /* png_create_colormap_entry just takes an RGBA and writes the

+             * corresponding color-map entry using the format from 'image',

+             * including the required conversion to sRGB or linear as

+             * appropriate.  The input values are always either sRGB (if the

+             * gamma correction flag is 0) or 0..255 scaled file encoded values

+             * (if the function must gamma correct them).

+             */

+            for (i=val=0; i<cmap_entries; ++i, val += step)

+            {

+               /* 'i' is a file value.  While this will result in duplicated

+                * entries for 8-bit non-sRGB encoded files it is necessary to

+                * have non-gamma corrected values to do tRNS handling.

+                */

+               if (i != trans)

+                  png_create_colormap_entry(display, i, val, val, val, 255,

+                     E_FILE/*8-bit with file gamma*/);

+

+               /* Else this entry is transparent.  The colors don't matter if

+                * there is an alpha channel (back_alpha == 0), but it does no

+                * harm to pass them in; the values are not set above so this

+                * passes in white.

+                *

+                * NOTE: this preserves the full precision of the application

+                * supplied background color when it is used.

+                */

+               else

+                  png_create_colormap_entry(display, i, back_r, back_g, back_b,

+                     back_alpha, output_encoding);

+            }

+

+            /* We need libpng to preserve the original encoding. */

+            data_encoding = E_FILE;

+

+            /* The rows from libpng, while technically gray values, are now also

+             * color-map indicies; however, they may need to be expanded to 1

+             * byte per pixel.  This is what png_set_packing does (i.e., it

+             * unpacks the bit values into bytes.)

+             */

+            if (png_ptr->bit_depth < 8)

+               png_set_packing(png_ptr);

+         }

+

+         else /* bit depth is 16 */

+         {

+            /* The 16-bit input values can be converted directly to 8-bit gamma

+             * encoded values; however, if a tRNS chunk is present 257 color-map

+             * entries are required.  This means that the extra entry requires

+             * special processing; add an alpha channel, sacrifice gray level

+             * 254 and convert transparent (alpha==0) entries to that.

+             *

+             * Use libpng to chop the data to 8 bits.  Convert it to sRGB at the

+             * same time to minimize quality loss.  If a tRNS chunk is present

+             * this means libpng must handle it too; otherwise it is impossible

+             * to do the exact match on the 16-bit value.

+             *

+             * If the output has no alpha channel *and* the background color is

+             * gray then it is possible to let libpng handle the substitution by

+             * ensuring that the corresponding gray level matches the background

+             * color exactly.

+             */

+            data_encoding = E_sRGB;

+

+            if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)

+               png_error(png_ptr, "gray[16] color-map: too few entries");

+

+            cmap_entries = make_gray_colormap(display);

+

+            if (png_ptr->num_trans > 0)

+            {

+               unsigned int back_alpha;

+

+               if (output_format & PNG_FORMAT_FLAG_ALPHA)

+                  back_alpha = 0;

+

+               else

+               {

+                  if (back_r == back_g && back_g == back_b)

+                  {

+                     /* Background is gray; no special processing will be

+                      * required.

+                      */

+                     png_color_16 c;

+                     png_uint_32 gray = back_g;

+

+                     if (output_encoding == E_LINEAR)

+                     {

+                        gray = PNG_sRGB_FROM_LINEAR(gray * 255);

+

+                        /* And make sure the corresponding palette entry

+                         * matches.

+                         */

+                        png_create_colormap_entry(display, gray, back_g, back_g,

+                           back_g, 65535, E_LINEAR);

+                     }

+

+                     /* The background passed to libpng, however, must be the

+                      * sRGB value.

+                      */

+                     c.index = 0; /*unused*/

+                     c.gray = c.red = c.green = c.blue = (png_uint_16)gray;

+

+                     /* NOTE: does this work without expanding tRNS to alpha?

+                      * It should be the color->gray case below apparently

+                      * doesn't.

+                      */

+                     png_set_background_fixed(png_ptr, &c,

+                        PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,

+                        0/*gamma: not used*/);

+

+                     output_processing = PNG_CMAP_NONE;

+                     break;

+                  }

+

+                  back_alpha = output_encoding == E_LINEAR ? 65535 : 255;

+               }

+

+               /* output_processing means that the libpng-processed row will be

+                * 8-bit GA and it has to be processing to single byte color-map

+                * values.  Entry 254 is replaced by either a completely

+                * transparent entry or by the background color at full

+                * precision (and the background color is not a simple gray leve

+                * in this case.)

+                */

+               expand_tRNS = 1;

+               output_processing = PNG_CMAP_TRANS;

+               background_index = 254;

+

+               /* And set (overwrite) color-map entry 254 to the actual

+                * background color at full precision.

+                */

+               png_create_colormap_entry(display, 254, back_r, back_g, back_b,

+                  back_alpha, output_encoding);

+            }

+

+            else

+               output_processing = PNG_CMAP_NONE;

+         }

+         break;

+

+      case PNG_COLOR_TYPE_GRAY_ALPHA:

+         /* 8-bit or 16-bit PNG with two channels - gray and alpha.  A minimum

+          * of 65536 combinations.  If, however, the alpha channel is to be

+          * removed there are only 256 possibilities if the background is gray.

+          * (Otherwise there is a subset of the 65536 possibilities defined by

+          * the triangle between black, white and the background color.)

+          *

+          * Reduce 16-bit files to 8-bit and sRGB encode the result.  No need to

+          * worry about tRNS matching - tRNS is ignored if there is an alpha

+          * channel.

+          */

+         data_encoding = E_sRGB;

+

+         if (output_format & PNG_FORMAT_FLAG_ALPHA)

+         {

+            if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)

+               png_error(png_ptr, "gray+alpha color-map: too few entries");

+

+            cmap_entries = make_ga_colormap(display);

+

+            background_index = PNG_CMAP_GA_BACKGROUND;

+            output_processing = PNG_CMAP_GA;

+         }

+

+         else /* alpha is removed */

+         {

+            /* Alpha must be removed as the PNG data is processed when the

+             * background is a color because the G and A channels are

+             * independent and the vector addition (non-parallel vectors) is a

+             * 2-D problem.

+             *

+             * This can be reduced to the same algorithm as above by making a

+             * colormap containing gray levels (for the opaque grays), a

+             * background entry (for a transparent pixel) and a set of four six

+             * level color values, one set for each intermediate alpha value.

+             * See the comments in make_ga_colormap for how this works in the

+             * per-pixel processing.

+             *

+             * If the background is gray, however, we only need a 256 entry gray

+             * level color map.  It is sufficient to make the entry generated

+             * for the background color be exactly the color specified.

+             */

+            if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 ||

+               (back_r == back_g && back_g == back_b))

+            {

+               /* Background is gray; no special processing will be required. */

+               png_color_16 c;

+               png_uint_32 gray = back_g;

+

+               if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)

+                  png_error(png_ptr, "gray-alpha color-map: too few entries");

+

+               cmap_entries = make_gray_colormap(display);

+

+               if (output_encoding == E_LINEAR)

+               {

+                  gray = PNG_sRGB_FROM_LINEAR(gray * 255);

+

+                  /* And make sure the corresponding palette entry matches. */

+                  png_create_colormap_entry(display, gray, back_g, back_g,

+                     back_g, 65535, E_LINEAR);

+               }

+

+               /* The background passed to libpng, however, must be the sRGB

+                * value.

+                */

+               c.index = 0; /*unused*/

+               c.gray = c.red = c.green = c.blue = (png_uint_16)gray;

+

+               png_set_background_fixed(png_ptr, &c,

+                  PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,

+                  0/*gamma: not used*/);

+

+               output_processing = PNG_CMAP_NONE;

+            }

+

+            else

+            {

+               png_uint_32 i, a;

+

+               /* This is the same as png_make_ga_colormap, above, except that

+                * the entries are all opaque.

+                */

+               if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)

+                  png_error(png_ptr, "ga-alpha color-map: too few entries");

+

+               i = 0;

+               while (i < 231)

+               {

+                  png_uint_32 gray = (i * 256 + 115) / 231;

+                  png_create_colormap_entry(display, i++, gray, gray, gray,

+                     255, E_sRGB);

+               }

+

+               /* NOTE: this preserves the full precision of the application

+                * background color.

+                */

+               background_index = i;

+               png_create_colormap_entry(display, i++, back_r, back_g, back_b,

+                  output_encoding == E_LINEAR ? 65535U : 255U, output_encoding);

+

+               /* For non-opaque input composite on the sRGB background - this

+                * requires inverting the encoding for each component.  The input

+                * is still converted to the sRGB encoding because this is a

+                * reasonable approximate to the logarithmic curve of human

+                * visual sensitivity, at least over the narrow range which PNG

+                * represents.  Consequently 'G' is always sRGB encoded, while

+                * 'A' is linear.  We need the linear background colors.

+                */

+               if (output_encoding == E_sRGB) /* else already linear */

+               {

+                  /* This may produce a value not exactly matching the

+                   * background, but that's ok because these numbers are only

+                   * used when alpha != 0

+                   */

+                  back_r = png_sRGB_table[back_r];

+                  back_g = png_sRGB_table[back_g];

+                  back_b = png_sRGB_table[back_b];

+               }

+

+               for (a=1; a<5; ++a)

+               {

+                  unsigned int g;

+

+                  /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled

+                   * by an 8-bit alpha value (0..255).

+                   */

+                  png_uint_32 alpha = 51 * a;

+                  png_uint_32 back_rx = (255-alpha) * back_r;

+                  png_uint_32 back_gx = (255-alpha) * back_g;

+                  png_uint_32 back_bx = (255-alpha) * back_b;

+

+                  for (g=0; g<6; ++g)

+                  {

+                     png_uint_32 gray = png_sRGB_table[g*51] * alpha;

+

+                     png_create_colormap_entry(display, i++,

+                        PNG_sRGB_FROM_LINEAR(gray + back_rx),

+                        PNG_sRGB_FROM_LINEAR(gray + back_gx),

+                        PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, E_sRGB);

+                  }

+               }

+

+               cmap_entries = i;

+               output_processing = PNG_CMAP_GA;

+            }

+         }

+         break;

+

+      case PNG_COLOR_TYPE_RGB:

+      case PNG_COLOR_TYPE_RGB_ALPHA:

+         /* Exclude the case where the output is gray; we can always handle this

+          * with the cases above.

+          */

+         if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0)

+         {

+            /* The color-map will be grayscale, so we may as well convert the

+             * input RGB values to a simple grayscale and use the grayscale

+             * code above.

+             *

+             * NOTE: calling this apparently damages the recognition of the

+             * transparent color in background color handling; call

+             * png_set_tRNS_to_alpha before png_set_background_fixed.

+             */

+            png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1,

+               -1);

+            data_encoding = E_sRGB;

+

+            /* The output will now be one or two 8-bit gray or gray+alpha

+             * channels.  The more complex case arises when the input has alpha.

+             */

+            if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||

+               png_ptr->num_trans > 0) &&

+               (output_format & PNG_FORMAT_FLAG_ALPHA) != 0)

+            {

+               /* Both input and output have an alpha channel, so no background

+                * processing is required; just map the GA bytes to the right

+                * color-map entry.

+                */

+               expand_tRNS = 1;

+

+               if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)

+                  png_error(png_ptr, "rgb[ga] color-map: too few entries");

+

+               cmap_entries = make_ga_colormap(display);

+               background_index = PNG_CMAP_GA_BACKGROUND;

+               output_processing = PNG_CMAP_GA;

+            }

+

+            else

+            {

+               /* Either the input or the output has no alpha channel, so there

+                * will be no non-opaque pixels in the color-map; it will just be

+                * grayscale.

+                */

+               if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)

+                  png_error(png_ptr, "rgb[gray] color-map: too few entries");

+

+               /* Ideally this code would use libpng to do the gamma correction,

+                * but if an input alpha channel is to be removed we will hit the

+                * libpng bug in gamma+compose+rgb-to-gray (the double gamma

+                * correction bug).  Fix this by dropping the gamma correction in

+                * this case and doing it in the palette; this will result in

+                * duplicate palette entries, but that's better than the

+                * alternative of double gamma correction.

+                */

+               if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||

+                  png_ptr->num_trans > 0) &&

+                  png_gamma_not_sRGB(png_ptr->colorspace.gamma))

+               {

+                  cmap_entries = make_gray_file_colormap(display);

+                  data_encoding = E_FILE;

+               }

+

+               else

+                  cmap_entries = make_gray_colormap(display);

+

+               /* But if the input has alpha or transparency it must be removed

+                */

+               if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||

+                  png_ptr->num_trans > 0)

+               {

+                  png_color_16 c;

+                  png_uint_32 gray = back_g;

+

+                  /* We need to ensure that the application background exists in

+                   * the colormap and that completely transparent pixels map to

+                   * it.  Achieve this simply by ensuring that the entry

+                   * selected for the background really is the background color.

+                   */

+                  if (data_encoding == E_FILE) /* from the fixup above */

+                  {

+                     /* The app supplied a gray which is in output_encoding, we

+                      * need to convert it to a value of the input (E_FILE)

+                      * encoding then set this palette entry to the required

+                      * output encoding.

+                      */

+                     if (output_encoding == E_sRGB)

+                        gray = png_sRGB_table[gray]; /* now E_LINEAR */

+

+                     gray = PNG_DIV257(png_gamma_16bit_correct(gray,

+                        png_ptr->colorspace.gamma)); /* now E_FILE */

+

+                     /* And make sure the corresponding palette entry contains

+                      * exactly the required sRGB value.

+                      */

+                     png_create_colormap_entry(display, gray, back_g, back_g,

+                        back_g, 0/*unused*/, output_encoding);

+                  }

+

+                  else if (output_encoding == E_LINEAR)

+                  {

+                     gray = PNG_sRGB_FROM_LINEAR(gray * 255);

+

+                     /* And make sure the corresponding palette entry matches.

+                      */

+                     png_create_colormap_entry(display, gray, back_g, back_g,

+                        back_g, 0/*unused*/, E_LINEAR);

+                  }

+

+                  /* The background passed to libpng, however, must be the

+                   * output (normally sRGB) value.

+                   */

+                  c.index = 0; /*unused*/

+                  c.gray = c.red = c.green = c.blue = (png_uint_16)gray;

+

+                  /* NOTE: the following is apparently a bug in libpng. Without

+                   * it the transparent color recognition in

+                   * png_set_background_fixed seems to go wrong.

+                   */

+                  expand_tRNS = 1;

+                  png_set_background_fixed(png_ptr, &c,

+                     PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,

+                     0/*gamma: not used*/);

+               }

+

+               output_processing = PNG_CMAP_NONE;

+            }

+         }

+

+         else /* output is color */

+         {

+            /* We could use png_quantize here so long as there is no transparent

+             * color or alpha; png_quantize ignores alpha.  Easier overall just

+             * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube.

+             * Consequently we always want libpng to produce sRGB data.

+             */

+            data_encoding = E_sRGB;

+

+            /* Is there any transparency or alpha? */

+            if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||

+               png_ptr->num_trans > 0)

+            {

+               /* Is there alpha in the output too?  If so all four channels are

+                * processed into a special RGB cube with alpha support.

+                */

+               if (output_format & PNG_FORMAT_FLAG_ALPHA)

+               {

+                  png_uint_32 r;

+

+                  if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)

+                     png_error(png_ptr, "rgb+alpha color-map: too few entries");

+

+                  cmap_entries = make_rgb_colormap(display);

+

+                  /* Add a transparent entry. */

+                  png_create_colormap_entry(display, cmap_entries, 255, 255,

+                     255, 0, E_sRGB);

+

+                  /* This is stored as the background index for the processing

+                   * algorithm.

+                   */

+                  background_index = cmap_entries++;

+

+                  /* Add 27 r,g,b entries each with alpha 0.5. */

+                  for (r=0; r<256; r = (r << 1) | 0x7f)

+                  {

+                     png_uint_32 g;

+

+                     for (g=0; g<256; g = (g << 1) | 0x7f)

+                     {

+                        png_uint_32 b;

+

+                        /* This generates components with the values 0, 127 and

+                         * 255

+                         */

+                        for (b=0; b<256; b = (b << 1) | 0x7f)

+                           png_create_colormap_entry(display, cmap_entries++,

+                              r, g, b, 128, E_sRGB);

+                     }

+                  }

+

+                  expand_tRNS = 1;

+                  output_processing = PNG_CMAP_RGB_ALPHA;

+               }

+

+               else

+               {

+                  /* Alpha/transparency must be removed.  The background must

+                   * exist in the color map (achieved by setting adding it after

+                   * the 666 color-map).  If the standard processing code will

+                   * pick up this entry automatically that's all that is

+                   * required; libpng can be called to do the background

+                   * processing.

+                   */

+                  unsigned int sample_size =

+                     PNG_IMAGE_SAMPLE_SIZE(output_format);

+                  png_uint_32 r, g, b; /* sRGB background */

+

+                  if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)

+                     png_error(png_ptr, "rgb-alpha color-map: too few entries");

+

+                  cmap_entries = make_rgb_colormap(display);

+

+                  png_create_colormap_entry(display, cmap_entries, back_r,

+                        back_g, back_b, 0/*unused*/, output_encoding);

+

+                  if (output_encoding == E_LINEAR)

+                  {

+                     r = PNG_sRGB_FROM_LINEAR(back_r * 255);

+                     g = PNG_sRGB_FROM_LINEAR(back_g * 255);

+                     b = PNG_sRGB_FROM_LINEAR(back_b * 255);

+                  }

+

+                  else

+                  {

+                     r = back_r;

+                     g = back_g;

+                     b = back_g;

+                  }

+

+                  /* Compare the newly-created color-map entry with the one the

+                   * PNG_CMAP_RGB algorithm will use.  If the two entries don't

+                   * match, add the new one and set this as the background

+                   * index.

+                   */

+                  if (memcmp((png_const_bytep)display->colormap +

+                        sample_size * cmap_entries,

+                     (png_const_bytep)display->colormap +

+                        sample_size * PNG_RGB_INDEX(r,g,b),

+                     sample_size) != 0)

+                  {

+                     /* The background color must be added. */

+                     background_index = cmap_entries++;

+

+                     /* Add 27 r,g,b entries each with created by composing with

+                      * the background at alpha 0.5.

+                      */

+                     for (r=0; r<256; r = (r << 1) | 0x7f)

+                     {

+                        for (g=0; g<256; g = (g << 1) | 0x7f)

+                        {

+                           /* This generates components with the values 0, 127

+                            * and 255

+                            */

+                           for (b=0; b<256; b = (b << 1) | 0x7f)

+                              png_create_colormap_entry(display, cmap_entries++,

+                                 png_colormap_compose(display, r, E_sRGB, 128,

+                                    back_r, output_encoding),

+                                 png_colormap_compose(display, g, E_sRGB, 128,

+                                    back_g, output_encoding),

+                                 png_colormap_compose(display, b, E_sRGB, 128,

+                                    back_b, output_encoding),

+                                 0/*unused*/, output_encoding);

+                        }

+                     }

+

+                     expand_tRNS = 1;

+                     output_processing = PNG_CMAP_RGB_ALPHA;

+                  }

+

+                  else /* background color is in the standard color-map */

+                  {

+                     png_color_16 c;

+

+                     c.index = 0; /*unused*/

+                     c.red = (png_uint_16)back_r;

+                     c.gray = c.green = (png_uint_16)back_g;

+                     c.blue = (png_uint_16)back_b;

+

+                     png_set_background_fixed(png_ptr, &c,

+                        PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,

+                        0/*gamma: not used*/);

+

+                     output_processing = PNG_CMAP_RGB;

+                  }

+               }

+            }

+

+            else /* no alpha or transparency in the input */

+            {

+               /* Alpha in the output is irrelevant, simply map the opaque input

+                * pixels to the 6x6x6 color-map.

+                */

+               if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries)

+                  png_error(png_ptr, "rgb color-map: too few entries");

+

+               cmap_entries = make_rgb_colormap(display);

+               output_processing = PNG_CMAP_RGB;

+            }

+         }

+         break;

+

+      case PNG_COLOR_TYPE_PALETTE:

+         /* It's already got a color-map.  It may be necessary to eliminate the

+          * tRNS entries though.

+          */

+         {

+            unsigned int num_trans = png_ptr->num_trans;

+            png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL;

+            png_const_colorp colormap = png_ptr->palette;

+            const int do_background = trans != NULL &&

+               (output_format & PNG_FORMAT_FLAG_ALPHA) == 0;

+            unsigned int i;

+

+            /* Just in case: */

+            if (trans == NULL)

+               num_trans = 0;

+

+            output_processing = PNG_CMAP_NONE;

+            data_encoding = E_FILE; /* Don't change from color-map indicies */

+            cmap_entries = png_ptr->num_palette;

+            if (cmap_entries > 256)

+               cmap_entries = 256;

+

+            if (cmap_entries > image->colormap_entries)

+               png_error(png_ptr, "palette color-map: too few entries");

+

+            for (i=0; i < cmap_entries; ++i)

+            {

+               if (do_background && i < num_trans && trans[i] < 255)

+               {

+                  if (trans[i] == 0)

+                     png_create_colormap_entry(display, i, back_r, back_g,

+                        back_b, 0, output_encoding);

+

+                  else

+                  {

+                     /* Must compose the PNG file color in the color-map entry

+                      * on the sRGB color in 'back'.

+                      */

+                     png_create_colormap_entry(display, i,

+                        png_colormap_compose(display, colormap[i].red, E_FILE,

+                           trans[i], back_r, output_encoding),

+                        png_colormap_compose(display, colormap[i].green, E_FILE,

+                           trans[i], back_g, output_encoding),

+                        png_colormap_compose(display, colormap[i].blue, E_FILE,

+                           trans[i], back_b, output_encoding),

+                        output_encoding == E_LINEAR ? trans[i] * 257U :

+                           trans[i],

+                        output_encoding);

+                  }

+               }

+

+               else

+                  png_create_colormap_entry(display, i, colormap[i].red,

+                     colormap[i].green, colormap[i].blue,

+                     i < num_trans ? trans[i] : 255U, E_FILE/*8-bit*/);

+            }

+

+            /* The PNG data may have indicies packed in fewer than 8 bits, it

+             * must be expanded if so.

+             */

+            if (png_ptr->bit_depth < 8)

+               png_set_packing(png_ptr);

+         }

+         break;

+

+      default:

+         png_error(png_ptr, "invalid PNG color type");

+         /*NOT REACHED*/

+         break;

+   }

+

+   /* Now deal with the output processing */

+   if (expand_tRNS && png_ptr->num_trans > 0 &&

+      (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0)

+      png_set_tRNS_to_alpha(png_ptr);

+

+   switch (data_encoding)

+   {

+      default:

+         png_error(png_ptr, "bad data option (internal error)");

+         break;

+

+      case E_sRGB:

+         /* Change to 8-bit sRGB */

+         png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB);

+         /* FALL THROUGH */

+

+      case E_FILE:

+         if (png_ptr->bit_depth > 8)

+            png_set_scale_16(png_ptr);

+         break;

+   }

+

+   if (cmap_entries > 256 || cmap_entries > image->colormap_entries)

+      png_error(png_ptr, "color map overflow (BAD internal error)");

+

+   image->colormap_entries = cmap_entries;

+

+   /* Double check using the recorded background index */

+   switch (output_processing)

+   {

+      case PNG_CMAP_NONE:

+         if (background_index != PNG_CMAP_NONE_BACKGROUND)

+            goto bad_background;

+         break;

+

+      case PNG_CMAP_GA:

+         if (background_index != PNG_CMAP_GA_BACKGROUND)

+            goto bad_background;

+         break;

+

+      case PNG_CMAP_TRANS:

+         if (background_index >= cmap_entries ||

+            background_index != PNG_CMAP_TRANS_BACKGROUND)

+            goto bad_background;

+         break;

+

+      case PNG_CMAP_RGB:

+         if (background_index != PNG_CMAP_RGB_BACKGROUND)

+            goto bad_background;

+         break;

+

+      case PNG_CMAP_RGB_ALPHA:

+         if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND)

+            goto bad_background;

+         break;

+

+      default:

+         png_error(png_ptr, "bad processing option (internal error)");

+

+      bad_background:

+         png_error(png_ptr, "bad background index (internal error)");

+   }

+

+   display->colormap_processing = output_processing;

+

+   return 1/*ok*/;

+}

+

+/* The final part of the color-map read called from png_image_finish_read. */

+static int

+png_image_read_and_map(png_voidp argument)

+{

+   png_image_read_control *display = png_voidcast(png_image_read_control*,

+      argument);

+   png_imagep image = display->image;

+   png_structrp png_ptr = image->opaque->png_ptr;

+   int passes;

+

+   /* Called when the libpng data must be transformed into the color-mapped

+    * form.  There is a local row buffer in display->local and this routine must

+    * do the interlace handling.

+    */

+   switch (png_ptr->interlaced)

+   {

+      case PNG_INTERLACE_NONE:

+         passes = 1;

+         break;

+

+      case PNG_INTERLACE_ADAM7:

+         passes = PNG_INTERLACE_ADAM7_PASSES;

+         break;

+

+      default:

+         passes = 0;

+         png_error(png_ptr, "unknown interlace type");

+   }

+

+   {

+      png_uint_32  height = image->height;

+      png_uint_32  width = image->width;

+      int          proc = display->colormap_processing;

+      png_bytep    first_row = png_voidcast(png_bytep, display->first_row);

+      ptrdiff_t    step_row = display->row_bytes;

+      int pass;

+

+      for (pass = 0; pass < passes; ++pass)

+      {

+         unsigned int     startx, stepx, stepy;

+         png_uint_32      y;

+

+         if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)

+         {

+            /* The row may be empty for a short image: */

+            if (PNG_PASS_COLS(width, pass) == 0)

+               continue;

+

+            startx = PNG_PASS_START_COL(pass);

+            stepx = PNG_PASS_COL_OFFSET(pass);

+            y = PNG_PASS_START_ROW(pass);

+            stepy = PNG_PASS_ROW_OFFSET(pass);

+         }

+

+         else

+         {

+            y = 0;

+            startx = 0;

+            stepx = stepy = 1;

+         }

+

+         for (; y<height; y += stepy)

+         {

+            png_bytep inrow = png_voidcast(png_bytep, display->local_row);

+            png_bytep outrow = first_row + y * step_row;

+            png_const_bytep end_row = outrow + width;

+

+            /* Read read the libpng data into the temporary buffer. */

+            png_read_row(png_ptr, inrow, NULL);

+

+            /* Now process the row according to the processing option, note

+             * that the caller verifies that the format of the libpng output

+             * data is as required.

+             */

+            outrow += startx;

+            switch (proc)

+            {

+               case PNG_CMAP_GA:

+                  for (; outrow < end_row; outrow += stepx)

+                  {

+                     /* The data is always in the PNG order */

+                     unsigned int gray = *inrow++;

+                     unsigned int alpha = *inrow++;

+                     unsigned int entry;

+

+                     /* NOTE: this code is copied as a comment in

+                      * make_ga_colormap above.  Please update the

+                      * comment if you change this code!

+                      */

+                     if (alpha > 229) /* opaque */

+                     {

+                        entry = (231 * gray + 128) >> 8;

+                     }

+                     else if (alpha < 26) /* transparent */

+                     {

+                        entry = 231;

+                     }

+                     else /* partially opaque */

+                     {

+                        entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray);

+                     }

+

+                     *outrow = (png_byte)entry;

+                  }

+                  break;

+

+               case PNG_CMAP_TRANS:

+                  for (; outrow < end_row; outrow += stepx)

+                  {

+                     png_byte gray = *inrow++;

+                     png_byte alpha = *inrow++;

+

+                     if (alpha == 0)

+                        *outrow = PNG_CMAP_TRANS_BACKGROUND;

+

+                     else if (gray != PNG_CMAP_TRANS_BACKGROUND)

+                        *outrow = gray;

+

+                     else

+                        *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1);

+                  }

+                  break;

+

+               case PNG_CMAP_RGB:

+                  for (; outrow < end_row; outrow += stepx)

+                  {

+                     *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]);

+                     inrow += 3;

+                  }

+                  break;

+

+               case PNG_CMAP_RGB_ALPHA:

+                  for (; outrow < end_row; outrow += stepx)

+                  {

+                     unsigned int alpha = inrow[3];

+

+                     /* Because the alpha entries only hold alpha==0.5 values

+                      * split the processing at alpha==0.25 (64) and 0.75

+                      * (196).

+                      */

+

+                     if (alpha >= 196)

+                        *outrow = PNG_RGB_INDEX(inrow[0], inrow[1],

+                           inrow[2]);

+

+                     else if (alpha < 64)

+                        *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND;

+

+                     else

+                     {

+                        /* Likewise there are three entries for each of r, g

+                         * and b.  We could select the entry by popcount on

+                         * the top two bits on those architectures that

+                         * support it, this is what the code below does,

+                         * crudely.

+                         */

+                        unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1;

+

+                        /* Here are how the values map:

+                         *

+                         * 0x00 .. 0x3f -> 0

+                         * 0x40 .. 0xbf -> 1

+                         * 0xc0 .. 0xff -> 2

+                         *

+                         * So, as above with the explicit alpha checks, the

+                         * breakpoints are at 64 and 196.

+                         */

+                        if (inrow[0] & 0x80) back_i += 9; /* red */

+                        if (inrow[0] & 0x40) back_i += 9;

+                        if (inrow[0] & 0x80) back_i += 3; /* green */

+                        if (inrow[0] & 0x40) back_i += 3;

+                        if (inrow[0] & 0x80) back_i += 1; /* blue */

+                        if (inrow[0] & 0x40) back_i += 1;

+

+                        *outrow = (png_byte)back_i;

+                     }

+

+                     inrow += 4;

+                  }

+                  break;

+

+               default:

+                  break;

+            }

+         }

+      }

+   }

+

+   return 1;

+}

+

+static int

+png_image_read_colormapped(png_voidp argument)

+{

+   png_image_read_control *display = png_voidcast(png_image_read_control*,

+      argument);

+   png_imagep image = display->image;

+   png_controlp control = image->opaque;

+   png_structrp png_ptr = control->png_ptr;

+   png_inforp info_ptr = control->info_ptr;

+

+   int passes = 0; /* As a flag */

+

+   PNG_SKIP_CHUNKS(png_ptr);

+

+   /* Update the 'info' structure and make sure the result is as required; first

+    * make sure to turn on the interlace handling if it will be required

+    * (because it can't be turned on *after* the call to png_read_update_info!)

+    */

+   if (display->colormap_processing == PNG_CMAP_NONE)

+      passes = png_set_interlace_handling(png_ptr);

+

+   png_read_update_info(png_ptr, info_ptr);

+

+   /* The expected output can be deduced from the colormap_processing option. */

+   switch (display->colormap_processing)

+   {

+      case PNG_CMAP_NONE:

+         /* Output must be one channel and one byte per pixel, the output

+          * encoding can be anything.

+          */

+         if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||

+            info_ptr->color_type == PNG_COLOR_TYPE_GRAY) &&

+            info_ptr->bit_depth == 8)

+            break;

+

+         goto bad_output;

+

+      case PNG_CMAP_TRANS:

+      case PNG_CMAP_GA:

+         /* Output must be two channels and the 'G' one must be sRGB, the latter

+          * can be checked with an exact number because it should have been set

+          * to this number above!

+          */

+         if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&

+            info_ptr->bit_depth == 8 &&

+            png_ptr->screen_gamma == PNG_GAMMA_sRGB &&

+            image->colormap_entries == 256)

+            break;

+

+         goto bad_output;

+

+      case PNG_CMAP_RGB:

+         /* Output must be 8-bit sRGB encoded RGB */

+         if (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&

+            info_ptr->bit_depth == 8 &&

+            png_ptr->screen_gamma == PNG_GAMMA_sRGB &&

+            image->colormap_entries == 216)

+            break;

+

+         goto bad_output;

+

+      case PNG_CMAP_RGB_ALPHA:

+         /* Output must be 8-bit sRGB encoded RGBA */

+         if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&

+            info_ptr->bit_depth == 8 &&

+            png_ptr->screen_gamma == PNG_GAMMA_sRGB &&

+            image->colormap_entries == 244 /* 216 + 1 + 27 */)

+            break;

+

+         /* goto bad_output; */

+         /* FALL THROUGH */

+

+      default:

+      bad_output:

+         png_error(png_ptr, "bad color-map processing (internal error)");

+   }

+

+   /* Now read the rows.  Do this here if it is possible to read directly into

+    * the output buffer, otherwise allocate a local row buffer of the maximum

+    * size libpng requires and call the relevant processing routine safely.

+    */

+   {

+      png_voidp first_row = display->buffer;

+      ptrdiff_t row_bytes = display->row_stride;

+

+      /* The following expression is designed to work correctly whether it gives

+       * a signed or an unsigned result.

+       */

+      if (row_bytes < 0)

+      {

+         char *ptr = png_voidcast(char*, first_row);

+         ptr += (image->height-1) * (-row_bytes);

+         first_row = png_voidcast(png_voidp, ptr);

+      }

+

+      display->first_row = first_row;

+      display->row_bytes = row_bytes;

+   }

+

+   if (passes == 0)

+   {

+      int result;

+      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));

+

+      display->local_row = row;

+      result = png_safe_execute(image, png_image_read_and_map, display);

+      display->local_row = NULL;

+      png_free(png_ptr, row);

+

+      return result;

+   }

+

+   else

+   {

+      png_alloc_size_t row_bytes = display->row_bytes;

+

+      while (--passes >= 0)

+      {

+         png_uint_32      y = image->height;

+         png_bytep        row = png_voidcast(png_bytep, display->first_row);

+

+         while (y-- > 0)

+         {

+            png_read_row(png_ptr, row, NULL);

+            row += row_bytes;

+         }

+      }

+

+      return 1;

+   }

+}

+

+/* Just the row reading part of png_image_read. */

+static int

+png_image_read_composite(png_voidp argument)

+{

+   png_image_read_control *display = png_voidcast(png_image_read_control*,

+      argument);

+   png_imagep image = display->image;

+   png_structrp png_ptr = image->opaque->png_ptr;

+   int passes;

+

+   switch (png_ptr->interlaced)

+   {

+      case PNG_INTERLACE_NONE:

+         passes = 1;

+         break;

+

+      case PNG_INTERLACE_ADAM7:

+         passes = PNG_INTERLACE_ADAM7_PASSES;

+         break;

+

+      default:

+         passes = 0;

+         png_error(png_ptr, "unknown interlace type");

+   }

+

+   {

+      png_uint_32  height = image->height;

+      png_uint_32  width = image->width;

+      ptrdiff_t    step_row = display->row_bytes;

+      unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1;

+      int pass;

+

+      for (pass = 0; pass < passes; ++pass)

+      {

+         unsigned int     startx, stepx, stepy;

+         png_uint_32      y;

+

+         if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)

+         {

+            /* The row may be empty for a short image: */

+            if (PNG_PASS_COLS(width, pass) == 0)

+               continue;

+

+            startx = PNG_PASS_START_COL(pass) * channels;

+            stepx = PNG_PASS_COL_OFFSET(pass) * channels;

+            y = PNG_PASS_START_ROW(pass);

+            stepy = PNG_PASS_ROW_OFFSET(pass);

+         }

+

+         else

+         {

+            y = 0;

+            startx = 0;

+            stepx = channels;

+            stepy = 1;

+         }

+

+         for (; y<height; y += stepy)

+         {

+            png_bytep inrow = png_voidcast(png_bytep, display->local_row);

+            png_bytep outrow;

+            png_const_bytep end_row;

+

+            /* Read the row, which is packed: */

+            png_read_row(png_ptr, inrow, NULL);

+

+            outrow = png_voidcast(png_bytep, display->first_row);

+            outrow += y * step_row;

+            end_row = outrow + width * channels;

+

+            /* Now do the composition on each pixel in this row. */

+            outrow += startx;

+            for (; outrow < end_row; outrow += stepx)

+            {

+               png_byte alpha = inrow[channels];

+

+               if (alpha > 0) /* else no change to the output */

+               {

+                  unsigned int c;

+

+                  for (c=0; c<channels; ++c)

+                  {

+                     png_uint_32 component = inrow[c];

+

+                     if (alpha < 255) /* else just use component */

+                     {

+                        /* This is PNG_OPTIMIZED_ALPHA, the component value

+                         * is a linear 8-bit value.  Combine this with the

+                         * current outrow[c] value which is sRGB encoded.

+                         * Arithmetic here is 16-bits to preserve the output

+                         * values correctly.

+                         */

+                        component *= 257*255; /* =65535 */

+                        component += (255-alpha)*png_sRGB_table[outrow[c]];

+

+                        /* So 'component' is scaled by 255*65535 and is

+                         * therefore appropriate for the sRGB to linear

+                         * conversion table.

+                         */

+                        component = PNG_sRGB_FROM_LINEAR(component);

+                     }

+

+                     outrow[c] = (png_byte)component;

+                  }

+               }

+

+               inrow += channels+1; /* components and alpha channel */

+            }

+         }

+      }

+   }

+

+   return 1;

+}

+

+/* The do_local_background case; called when all the following transforms are to

+ * be done:

+ *

+ * PNG_RGB_TO_GRAY

+ * PNG_COMPOSITE

+ * PNG_GAMMA

+ *

+ * This is a work-round for the fact that both the PNG_RGB_TO_GRAY and

+ * PNG_COMPOSITE code performs gamma correction, so we get double gamma

+ * correction.  The fix-up is to prevent the PNG_COMPOSITE operation happening

+ * inside libpng, so this routine sees an 8 or 16-bit gray+alpha row and handles

+ * the removal or pre-multiplication of the alpha channel.

+ */

+static int

+png_image_read_background(png_voidp argument)

+{

+   png_image_read_control *display = png_voidcast(png_image_read_control*,

+      argument);

+   png_imagep image = display->image;

+   png_structrp png_ptr = image->opaque->png_ptr;

+   png_inforp info_ptr = image->opaque->info_ptr;

+   png_uint_32 height = image->height;

+   png_uint_32 width = image->width;

+   int pass, passes;

+

+   /* Double check the convoluted logic below.  We expect to get here with

+    * libpng doing rgb to gray and gamma correction but background processing

+    * left to the png_image_read_background function.  The rows libpng produce

+    * might be 8 or 16-bit but should always have two channels; gray plus alpha.

+    */

+   if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)

+      png_error(png_ptr, "lost rgb to gray");

+

+   if ((png_ptr->transformations & PNG_COMPOSE) != 0)

+      png_error(png_ptr, "unexpected compose");

+

+   if (png_get_channels(png_ptr, info_ptr) != 2)

+      png_error(png_ptr, "lost/gained channels");

+

+   /* Expect the 8-bit case to always remove the alpha channel */

+   if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 &&

+      (image->format & PNG_FORMAT_FLAG_ALPHA) != 0)

+      png_error(png_ptr, "unexpected 8-bit transformation");

+

+   switch (png_ptr->interlaced)

+   {

+      case PNG_INTERLACE_NONE:

+         passes = 1;

+         break;

+

+      case PNG_INTERLACE_ADAM7:

+         passes = PNG_INTERLACE_ADAM7_PASSES;

+         break;

+

+      default:

+         passes = 0;

+         png_error(png_ptr, "unknown interlace type");

+   }

+

+   switch (png_get_bit_depth(png_ptr, info_ptr))

+   {

+      default:

+         png_error(png_ptr, "unexpected bit depth");

+         break;

+

+      case 8:

+         /* 8-bit sRGB gray values with an alpha channel; the alpha channel is

+          * to be removed by composing on a backgroundi: either the row if

+          * display->background is NULL or display->background->green if not.

+          * Unlike the code above ALPHA_OPTIMIZED has *not* been done.

+          */

+         {

+            png_bytep first_row = png_voidcast(png_bytep, display->first_row);

+            ptrdiff_t step_row = display->row_bytes;

+

+            for (pass = 0; pass < passes; ++pass)

+            {

+               png_bytep        row = png_voidcast(png_bytep,

+                                                   display->first_row);

+               unsigned int     startx, stepx, stepy;

+               png_uint_32      y;

+

+               if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)

+               {

+                  /* The row may be empty for a short image: */

+                  if (PNG_PASS_COLS(width, pass) == 0)

+                     continue;

+

+                  startx = PNG_PASS_START_COL(pass);

+                  stepx = PNG_PASS_COL_OFFSET(pass);

+                  y = PNG_PASS_START_ROW(pass);

+                  stepy = PNG_PASS_ROW_OFFSET(pass);

+               }

+

+               else

+               {

+                  y = 0;

+                  startx = 0;

+                  stepx = stepy = 1;

+               }

+

+               if (display->background == NULL)

+               {

+                  for (; y<height; y += stepy)

+                  {

+                     png_bytep inrow = png_voidcast(png_bytep,

+                        display->local_row);

+                     png_bytep outrow = first_row + y * step_row;

+                     png_const_bytep end_row = outrow + width;

+

+                     /* Read the row, which is packed: */

+                     png_read_row(png_ptr, inrow, NULL);

+

+                     /* Now do the composition on each pixel in this row. */

+                     outrow += startx;

+                     for (; outrow < end_row; outrow += stepx)

+                     {

+                        png_byte alpha = inrow[1];

+

+                        if (alpha > 0) /* else no change to the output */

+                        {

+                           png_uint_32 component = inrow[0];

+

+                           if (alpha < 255) /* else just use component */

+                           {

+                              /* Since PNG_OPTIMIZED_ALPHA was not set it is

+                               * necessary to invert the sRGB transfer

+                               * function and multiply the alpha out.

+                               */

+                              component = png_sRGB_table[component] * alpha;

+                              component += png_sRGB_table[outrow[0]] *

+                                 (255-alpha);

+                              component = PNG_sRGB_FROM_LINEAR(component);

+                           }

+

+                           outrow[0] = (png_byte)component;

+                        }

+

+                        inrow += 2; /* gray and alpha channel */

+                     }

+                  }

+               }

+

+               else /* constant background value */

+               {

+                  png_byte background8 = display->background->green;

+                  png_uint_16 background = png_sRGB_table[background8];

+

+                  for (; y<height; y += stepy)

+                  {

+                     png_bytep inrow = png_voidcast(png_bytep,

+                        display->local_row);

+                     png_bytep outrow = first_row + y * step_row;

+                     png_const_bytep end_row = outrow + width;

+

+                     /* Read the row, which is packed: */

+                     png_read_row(png_ptr, inrow, NULL);

+

+                     /* Now do the composition on each pixel in this row. */

+                     outrow += startx;

+                     for (; outrow < end_row; outrow += stepx)

+                     {

+                        png_byte alpha = inrow[1];

+

+                        if (alpha > 0) /* else use background */

+                        {

+                           png_uint_32 component = inrow[0];

+

+                           if (alpha < 255) /* else just use component */

+                           {

+                              component = png_sRGB_table[component] * alpha;

+                              component += background * (255-alpha);

+                              component = PNG_sRGB_FROM_LINEAR(component);

+                           }

+

+                           outrow[0] = (png_byte)component;

+                        }

+

+                        else

+                           outrow[0] = background8;

+

+                        inrow += 2; /* gray and alpha channel */

+                     }

+

+                     row += display->row_bytes;

+                  }

+               }

+            }

+         }

+         break;

+

+      case 16:

+         /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must

+          * still be done and, maybe, the alpha channel removed.  This code also

+          * handles the alpha-first option.

+          */

+         {

+            png_uint_16p first_row = png_voidcast(png_uint_16p,

+               display->first_row);

+            /* The division by two is safe because the caller passed in a

+             * stride which was multiplied by 2 (below) to get row_bytes.

+             */

+            ptrdiff_t    step_row = display->row_bytes / 2;

+            int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0;

+            unsigned int outchannels = 1+preserve_alpha;

+            int swap_alpha = 0;

+

+            if (preserve_alpha && (image->format & PNG_FORMAT_FLAG_AFIRST))

+               swap_alpha = 1;

+

+            for (pass = 0; pass < passes; ++pass)

+            {

+               unsigned int     startx, stepx, stepy;

+               png_uint_32      y;

+

+               /* The 'x' start and step are adjusted to output components here.

+                */

+               if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)

+               {

+                  /* The row may be empty for a short image: */

+                  if (PNG_PASS_COLS(width, pass) == 0)

+                     continue;

+

+                  startx = PNG_PASS_START_COL(pass) * outchannels;

+                  stepx = PNG_PASS_COL_OFFSET(pass) * outchannels;

+                  y = PNG_PASS_START_ROW(pass);

+                  stepy = PNG_PASS_ROW_OFFSET(pass);

+               }

+

+               else

+               {

+                  y = 0;

+                  startx = 0;

+                  stepx = outchannels;

+                  stepy = 1;

+               }

+

+               for (; y<height; y += stepy)

+               {

+                  png_const_uint_16p inrow;

+                  png_uint_16p outrow = first_row + y*step_row;

+                  png_uint_16p end_row = outrow + width * outchannels;

+

+                  /* Read the row, which is packed: */

+                  png_read_row(png_ptr, png_voidcast(png_bytep,

+                     display->local_row), NULL);

+                  inrow = png_voidcast(png_const_uint_16p, display->local_row);

+

+                  /* Now do the pre-multiplication on each pixel in this row.

+                   */

+                  outrow += startx;

+                  for (; outrow < end_row; outrow += stepx)

+                  {

+                     png_uint_32 component = inrow[0];

+                     png_uint_16 alpha = inrow[1];

+

+                     if (alpha > 0) /* else 0 */

+                     {

+                        if (alpha < 65535) /* else just use component */

+                        {

+                           component *= alpha;

+                           component += 32767;

+                           component /= 65535;

+                        }

+                     }

+

+                     else

+                        component = 0;

+

+                     outrow[swap_alpha] = (png_uint_16)component;

+                     if (preserve_alpha)

+                        outrow[1 ^ swap_alpha] = alpha;

+

+                     inrow += 2; /* components and alpha channel */

+                  }

+               }

+            }

+         }

+         break;

+   }

+

+   return 1;

+}

+

+/* The guts of png_image_finish_read as a png_safe_execute callback. */

+static int

+png_image_read_direct(png_voidp argument)

+{

+   png_image_read_control *display = png_voidcast(png_image_read_control*,

+      argument);

+   png_imagep image = display->image;

+   png_structrp png_ptr = image->opaque->png_ptr;

+   png_inforp info_ptr = image->opaque->info_ptr;

+

+   png_uint_32 format = image->format;

+   int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;

+   int do_local_compose = 0;

+   int do_local_background = 0; /* to avoid double gamma correction bug */

+   int passes = 0;

+

+   /* Add transforms to ensure the correct output format is produced then check

+    * that the required implementation support is there.  Always expand; always

+    * need 8 bits minimum, no palette and expanded tRNS.

+    */

+   png_set_expand(png_ptr);

+

+   /* Now check the format to see if it was modified. */

+   {

+      png_uint_32 base_format = png_image_format(png_ptr) &

+         ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */;

+      png_uint_32 change = format ^ base_format;

+      png_fixed_point output_gamma;

+      int mode; /* alpha mode */

+

+      /* Do this first so that we have a record if rgb to gray is happening. */

+      if (change & PNG_FORMAT_FLAG_COLOR)

+      {

+         /* gray<->color transformation required. */

+         if (format & PNG_FORMAT_FLAG_COLOR)

+            png_set_gray_to_rgb(png_ptr);

+

+         else

+         {

+            /* libpng can't do both rgb to gray and

+             * background/pre-multiplication if there is also significant gamma

+             * correction, because both operations require linear colors and

+             * the code only supports one transform doing the gamma correction.

+             * Handle this by doing the pre-multiplication or background

+             * operation in this code, if necessary.

+             *

+             * TODO: fix this by rewriting pngrtran.c (!)

+             *

+             * For the moment (given that fixing this in pngrtran.c is an

+             * enormous change) 'do_local_background' is used to indicate that

+             * the problem exists.

+             */

+            if (base_format & PNG_FORMAT_FLAG_ALPHA)

+               do_local_background = 1/*maybe*/;

+

+            png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE,

+               PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);

+         }

+

+         change &= ~PNG_FORMAT_FLAG_COLOR;

+      }

+

+      /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise.

+       */

+      {

+         png_fixed_point input_gamma_default;

+

+         if ((base_format & PNG_FORMAT_FLAG_LINEAR) &&

+            (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)

+            input_gamma_default = PNG_GAMMA_LINEAR;

+         else

+            input_gamma_default = PNG_DEFAULT_sRGB;

+

+         /* Call png_set_alpha_mode to set the default for the input gamma; the

+          * output gamma is set by a second call below.

+          */

+         png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default);

+      }

+

+      if (linear)

+      {

+         /* If there *is* an alpha channel in the input it must be multiplied

+          * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG.

+          */

+         if (base_format & PNG_FORMAT_FLAG_ALPHA)

+            mode = PNG_ALPHA_STANDARD; /* associated alpha */

+

+         else

+            mode = PNG_ALPHA_PNG;

+

+         output_gamma = PNG_GAMMA_LINEAR;

+      }

+

+      else

+      {

+         mode = PNG_ALPHA_PNG;

+         output_gamma = PNG_DEFAULT_sRGB;

+      }

+

+      /* If 'do_local_background' is set check for the presence of gamma

+       * correction; this is part of the work-round for the libpng bug

+       * described above.

+       *

+       * TODO: fix libpng and remove this.

+       */

+      if (do_local_background)

+      {

+         png_fixed_point gtest;

+

+         /* This is 'png_gamma_threshold' from pngrtran.c; the test used for

+          * gamma correction, the screen gamma hasn't been set on png_struct

+          * yet; it's set below.  png_struct::gamma, however, is set to the

+          * final value.

+          */

+         if (png_muldiv(&gtest, output_gamma, png_ptr->colorspace.gamma,

+               PNG_FP_1) && !png_gamma_significant(gtest))

+            do_local_background = 0;

+

+         else if (mode == PNG_ALPHA_STANDARD)

+         {

+            do_local_background = 2/*required*/;

+            mode = PNG_ALPHA_PNG; /* prevent libpng doing it */

+         }

+

+         /* else leave as 1 for the checks below */

+      }

+

+      /* If the bit-depth changes then handle that here. */

+      if (change & PNG_FORMAT_FLAG_LINEAR)

+      {

+         if (linear /*16-bit output*/)

+            png_set_expand_16(png_ptr);

+

+         else /* 8-bit output */

+            png_set_scale_16(png_ptr);

+

+         change &= ~PNG_FORMAT_FLAG_LINEAR;

+      }

+

+      /* Now the background/alpha channel changes. */

+      if (change & PNG_FORMAT_FLAG_ALPHA)

+      {

+         /* Removing an alpha channel requires composition for the 8-bit

+          * formats; for the 16-bit it is already done, above, by the

+          * pre-multiplication and the channel just needs to be stripped.

+          */

+         if (base_format & PNG_FORMAT_FLAG_ALPHA)

+         {

+            /* If RGB->gray is happening the alpha channel must be left and the

+             * operation completed locally.

+             *

+             * TODO: fix libpng and remove this.

+             */

+            if (do_local_background)

+               do_local_background = 2/*required*/;

+

+            /* 16-bit output: just remove the channel */

+            else if (linear) /* compose on black (well, pre-multiply) */

+               png_set_strip_alpha(png_ptr);

+

+            /* 8-bit output: do an appropriate compose */

+            else if (display->background != NULL)

+            {

+               png_color_16 c;

+

+               c.index = 0; /*unused*/

+               c.red = display->background->red;

+               c.green = display->background->green;

+               c.blue = display->background->blue;

+               c.gray = display->background->green;

+

+               /* This is always an 8-bit sRGB value, using the 'green' channel

+                * for gray is much better than calculating the luminance here;

+                * we can get off-by-one errors in that calculation relative to

+                * the app expectations and that will show up in transparent

+                * pixels.

+                */

+               png_set_background_fixed(png_ptr, &c,

+                  PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,

+                  0/*gamma: not used*/);

+            }

+

+            else /* compose on row: implemented below. */

+            {

+               do_local_compose = 1;

+               /* This leaves the alpha channel in the output, so it has to be

+                * removed by the code below.  Set the encoding to the 'OPTIMIZE'

+                * one so the code only has to hack on the pixels that require

+                * composition.

+                */

+               mode = PNG_ALPHA_OPTIMIZED;

+            }

+         }

+

+         else /* output needs an alpha channel */

+         {

+            /* This is tricky because it happens before the swap operation has

+             * been accomplished; however, the swap does *not* swap the added

+             * alpha channel (weird API), so it must be added in the correct

+             * place.

+             */

+            png_uint_32 filler; /* opaque filler */

+            int where;

+

+            if (linear)

+               filler = 65535;

+

+            else

+               filler = 255;

+

+#           ifdef PNG_FORMAT_AFIRST_SUPPORTED

+               if (format & PNG_FORMAT_FLAG_AFIRST)

+               {

+                  where = PNG_FILLER_BEFORE;

+                  change &= ~PNG_FORMAT_FLAG_AFIRST;

+               }

+

+               else

+#           endif

+               where = PNG_FILLER_AFTER;

+

+            png_set_add_alpha(png_ptr, filler, where);

+         }

+

+         /* This stops the (irrelevant) call to swap_alpha below. */

+         change &= ~PNG_FORMAT_FLAG_ALPHA;

+      }

+

+      /* Now set the alpha mode correctly; this is always done, even if there is

+       * no alpha channel in either the input or the output because it correctly

+       * sets the output gamma.

+       */

+      png_set_alpha_mode_fixed(png_ptr, mode, output_gamma);

+

+#     ifdef PNG_FORMAT_BGR_SUPPORTED

+         if (change & PNG_FORMAT_FLAG_BGR)

+         {

+            /* Check only the output format; PNG is never BGR; don't do this if

+             * the output is gray, but fix up the 'format' value in that case.

+             */

+            if (format & PNG_FORMAT_FLAG_COLOR)

+               png_set_bgr(png_ptr);

+

+            else

+               format &= ~PNG_FORMAT_FLAG_BGR;

+

+            change &= ~PNG_FORMAT_FLAG_BGR;

+         }

+#     endif

+

+#     ifdef PNG_FORMAT_AFIRST_SUPPORTED

+         if (change & PNG_FORMAT_FLAG_AFIRST)

+         {

+            /* Only relevant if there is an alpha channel - it's particularly

+             * important to handle this correctly because do_local_compose may

+             * be set above and then libpng will keep the alpha channel for this

+             * code to remove.

+             */

+            if (format & PNG_FORMAT_FLAG_ALPHA)

+            {

+               /* Disable this if doing a local background,

+                * TODO: remove this when local background is no longer required.

+                */

+               if (do_local_background != 2)

+                  png_set_swap_alpha(png_ptr);

+            }

+

+            else

+               format &= ~PNG_FORMAT_FLAG_AFIRST;

+

+            change &= ~PNG_FORMAT_FLAG_AFIRST;

+         }

+#     endif

+

+      /* If the *output* is 16-bit then we need to check for a byte-swap on this

+       * architecture.

+       */

+      if (linear)

+      {

+         PNG_CONST png_uint_16 le = 0x0001;

+

+         if (*(png_const_bytep)&le)

+            png_set_swap(png_ptr);

+      }

+

+      /* If change is not now 0 some transformation is missing - error out. */

+      if (change)

+         png_error(png_ptr, "png_read_image: unsupported transformation");

+   }

+

+   PNG_SKIP_CHUNKS(png_ptr);

+

+   /* Update the 'info' structure and make sure the result is as required; first

+    * make sure to turn on the interlace handling if it will be required

+    * (because it can't be turned on *after* the call to png_read_update_info!)

+    *

+    * TODO: remove the do_local_background fixup below.

+    */

+   if (!do_local_compose && do_local_background != 2)

+      passes = png_set_interlace_handling(png_ptr);

+

+   png_read_update_info(png_ptr, info_ptr);

+

+   {

+      png_uint_32 info_format = 0;

+

+      if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)

+         info_format |= PNG_FORMAT_FLAG_COLOR;

+

+      if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)

+      {

+         /* do_local_compose removes this channel below. */

+         if (!do_local_compose)

+         {

+            /* do_local_background does the same if required. */

+            if (do_local_background != 2 ||

+               (format & PNG_FORMAT_FLAG_ALPHA) != 0)

+               info_format |= PNG_FORMAT_FLAG_ALPHA;

+         }

+      }

+

+      else if (do_local_compose) /* internal error */

+         png_error(png_ptr, "png_image_read: alpha channel lost");

+

+      if (info_ptr->bit_depth == 16)

+         info_format |= PNG_FORMAT_FLAG_LINEAR;

+

+#     ifdef PNG_FORMAT_BGR_SUPPORTED

+         if (png_ptr->transformations & PNG_BGR)

+            info_format |= PNG_FORMAT_FLAG_BGR;

+#     endif

+

+#     ifdef PNG_FORMAT_AFIRST_SUPPORTED

+         if (do_local_background == 2)

+         {

+            if (format & PNG_FORMAT_FLAG_AFIRST)

+               info_format |= PNG_FORMAT_FLAG_AFIRST;

+         }

+

+         if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 ||

+            ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 &&

+            (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0))

+         {

+            if (do_local_background == 2)

+               png_error(png_ptr, "unexpected alpha swap transformation");

+

+            info_format |= PNG_FORMAT_FLAG_AFIRST;

+         }

+#     endif

+

+      /* This is actually an internal error. */

+      if (info_format != format)

+         png_error(png_ptr, "png_read_image: invalid transformations");

+   }

+

+   /* Now read the rows.  If do_local_compose is set then it is necessary to use

+    * a local row buffer.  The output will be GA, RGBA or BGRA and must be

+    * converted to G, RGB or BGR as appropriate.  The 'local_row' member of the

+    * display acts as a flag.

+    */

+   {

+      png_voidp first_row = display->buffer;

+      ptrdiff_t row_bytes = display->row_stride;

+

+      if (linear)

+         row_bytes *= 2;

+

+      /* The following expression is designed to work correctly whether it gives

+       * a signed or an unsigned result.

+       */

+      if (row_bytes < 0)

+      {

+         char *ptr = png_voidcast(char*, first_row);

+         ptr += (image->height-1) * (-row_bytes);

+         first_row = png_voidcast(png_voidp, ptr);

+      }

+

+      display->first_row = first_row;

+      display->row_bytes = row_bytes;

+   }

+

+   if (do_local_compose)

+   {

+      int result;

+      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));

+

+      display->local_row = row;

+      result = png_safe_execute(image, png_image_read_composite, display);

+      display->local_row = NULL;

+      png_free(png_ptr, row);

+

+      return result;

+   }

+

+   else if (do_local_background == 2)

+   {

+      int result;

+      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));

+

+      display->local_row = row;

+      result = png_safe_execute(image, png_image_read_background, display);

+      display->local_row = NULL;

+      png_free(png_ptr, row);

+

+      return result;

+   }

+

+   else

+   {

+      png_alloc_size_t row_bytes = display->row_bytes;

+

+      while (--passes >= 0)

+      {

+         png_uint_32      y = image->height;

+         png_bytep        row = png_voidcast(png_bytep, display->first_row);

+

+         while (y-- > 0)

+         {

+            png_read_row(png_ptr, row, NULL);

+            row += row_bytes;

+         }

+      }

+

+      return 1;

+   }

+}

+

+int PNGAPI

+png_image_finish_read(png_imagep image, png_const_colorp background,

+   void *buffer, png_int_32 row_stride, void *colormap)

+{

+   if (image != NULL && image->version == PNG_IMAGE_VERSION)

+   {

+      png_uint_32 check;

+

+      if (row_stride == 0)

+         row_stride = PNG_IMAGE_ROW_STRIDE(*image);

+

+      if (row_stride < 0)

+         check = -row_stride;

+

+      else

+         check = row_stride;

+

+      if (image->opaque != NULL && buffer != NULL &&

+         check >= PNG_IMAGE_ROW_STRIDE(*image))

+      {

+         if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 ||

+            (image->colormap_entries > 0 && colormap != NULL))

+         {

+            int result;

+            png_image_read_control display;

+

+            memset(&display, 0, (sizeof display));

+            display.image = image;

+            display.buffer = buffer;

+            display.row_stride = row_stride;

+            display.colormap = colormap;

+            display.background = background;

+            display.local_row = NULL;

+

+            /* Choose the correct 'end' routine; for the color-map case all the

+             * setup has already been done.

+             */

+            if (image->format & PNG_FORMAT_FLAG_COLORMAP)

+               result =

+                  png_safe_execute(image, png_image_read_colormap, &display) &&

+                  png_safe_execute(image, png_image_read_colormapped, &display);

+

+            else

+               result =

+                  png_safe_execute(image, png_image_read_direct, &display);

+

+            png_image_free(image);

+            return result;

+         }

+

+         else

+            return png_image_error(image,

+               "png_image_finish_read[color-map]: no color-map");

+      }

+

+      else

+         return png_image_error(image,

+            "png_image_finish_read: invalid argument");

+   }

+

+   else if (image != NULL)

+      return png_image_error(image,

+         "png_image_finish_read: damaged PNG_IMAGE_VERSION");

+

+   return 0;

+}

+

+#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */

+#endif /* PNG_READ_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrio.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrio.c
new file mode 100644
index 0000000..5f927d1
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrio.c
@@ -0,0 +1,119 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngrio.c - functions for data input

+ *

+ * Last changed in libpng 1.6.0 [February 14, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ * This file provides a location for all input.  Users who need

+ * special handling are expected to write a function that has the same

+ * arguments as this and performs a similar function, but that possibly

+ * has a different input method.  Note that you shouldn't change this

+ * function, but rather write a replacement function and then make

+ * libpng use it at run time with png_set_read_fn(...).

+ */

+

+#include "pngpriv.h"

+

+#ifdef PNG_READ_SUPPORTED

+

+/* Read the data from whatever input you are using.  The default routine

+ * reads from a file pointer.  Note that this routine sometimes gets called

+ * with very small lengths, so you should implement some kind of simple

+ * buffering if you are using unbuffered reads.  This should never be asked

+ * to read more then 64K on a 16 bit machine.

+ */

+void /* PRIVATE */

+png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length)

+{

+   png_debug1(4, "reading %d bytes", (int)length);

+

+   if (png_ptr->read_data_fn != NULL)

+      (*(png_ptr->read_data_fn))(png_ptr, data, length);

+

+   else

+      png_error(png_ptr, "Call to NULL read function");

+}

+

+#ifdef PNG_STDIO_SUPPORTED

+/* This is the function that does the actual reading of data.  If you are

+ * not reading from a standard C stream, you should create a replacement

+ * read_data function and use it at run time with png_set_read_fn(), rather

+ * than changing the library.

+ */

+void PNGCBAPI

+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)

+{

+   png_size_t check;

+

+   if (png_ptr == NULL)

+      return;

+

+   /* fread() returns 0 on error, so it is OK to store this in a png_size_t

+    * instead of an int, which is what fread() actually returns.

+    */

+   check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));

+

+   if (check != length)

+      png_error(png_ptr, "Read Error");

+}

+#endif

+

+/* This function allows the application to supply a new input function

+ * for libpng if standard C streams aren't being used.

+ *

+ * This function takes as its arguments:

+ *

+ * png_ptr      - pointer to a png input data structure

+ *

+ * io_ptr       - pointer to user supplied structure containing info about

+ *                the input functions.  May be NULL.

+ *

+ * read_data_fn - pointer to a new input function that takes as its

+ *                arguments a pointer to a png_struct, a pointer to

+ *                a location where input data can be stored, and a 32-bit

+ *                unsigned int that is the number of bytes to be read.

+ *                To exit and output any fatal error messages the new write

+ *                function should call png_error(png_ptr, "Error msg").

+ *                May be NULL, in which case libpng's default function will

+ *                be used.

+ */

+void PNGAPI

+png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr,

+   png_rw_ptr read_data_fn)

+{

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->io_ptr = io_ptr;

+

+#ifdef PNG_STDIO_SUPPORTED

+   if (read_data_fn != NULL)

+      png_ptr->read_data_fn = read_data_fn;

+

+   else

+      png_ptr->read_data_fn = png_default_read_data;

+#else

+   png_ptr->read_data_fn = read_data_fn;

+#endif

+

+   /* It is an error to write to a read device */

+   if (png_ptr->write_data_fn != NULL)

+   {

+      png_ptr->write_data_fn = NULL;

+      png_warning(png_ptr,

+          "Can't set both read_data_fn and write_data_fn in the"

+          " same structure");

+   }

+

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+   png_ptr->output_flush_fn = NULL;

+#endif

+}

+#endif /* PNG_READ_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrtran.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrtran.c
new file mode 100644
index 0000000..4a279be
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrtran.c
@@ -0,0 +1,5104 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngrtran.c - transforms the data in a row for PNG readers

+ *

+ * Last changed in libpng 1.6.2 [April 25, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ * This file contains functions optionally called by an application

+ * in order to tell libpng how to handle data when reading a PNG.

+ * Transformations that are used in both reading and writing are

+ * in pngtrans.c.

+ */

+

+#include "pngpriv.h"

+

+#ifdef PNG_READ_SUPPORTED

+

+/* Set the action on getting a CRC error for an ancillary or critical chunk. */

+void PNGAPI

+png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)

+{

+   png_debug(1, "in png_set_crc_action");

+

+   if (png_ptr == NULL)

+      return;

+

+   /* Tell libpng how we react to CRC errors in critical chunks */

+   switch (crit_action)

+   {

+      case PNG_CRC_NO_CHANGE:                        /* Leave setting as is */

+         break;

+

+      case PNG_CRC_WARN_USE:                               /* Warn/use data */

+         png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;

+         png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;

+         break;

+

+      case PNG_CRC_QUIET_USE:                             /* Quiet/use data */

+         png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;

+         png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |

+                           PNG_FLAG_CRC_CRITICAL_IGNORE;

+         break;

+

+      case PNG_CRC_WARN_DISCARD:    /* Not a valid action for critical data */

+         png_warning(png_ptr,

+            "Can't discard critical data on CRC error");

+      case PNG_CRC_ERROR_QUIT:                                /* Error/quit */

+

+      case PNG_CRC_DEFAULT:

+      default:

+         png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;

+         break;

+   }

+

+   /* Tell libpng how we react to CRC errors in ancillary chunks */

+   switch (ancil_action)

+   {

+      case PNG_CRC_NO_CHANGE:                       /* Leave setting as is */

+         break;

+

+      case PNG_CRC_WARN_USE:                              /* Warn/use data */

+         png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;

+         png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;

+         break;

+

+      case PNG_CRC_QUIET_USE:                            /* Quiet/use data */

+         png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;

+         png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |

+                           PNG_FLAG_CRC_ANCILLARY_NOWARN;

+         break;

+

+      case PNG_CRC_ERROR_QUIT:                               /* Error/quit */

+         png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;

+         png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;

+         break;

+

+      case PNG_CRC_WARN_DISCARD:                      /* Warn/discard data */

+

+      case PNG_CRC_DEFAULT:

+      default:

+         png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;

+         break;

+   }

+}

+

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+/* Is it OK to set a transformation now?  Only if png_start_read_image or

+ * png_read_update_info have not been called.  It is not necessary for the IHDR

+ * to have been read in all cases, the parameter allows for this check too.

+ */

+static int

+png_rtran_ok(png_structrp png_ptr, int need_IHDR)

+{

+   if (png_ptr != NULL)

+   {

+      if (png_ptr->flags & PNG_FLAG_ROW_INIT)

+         png_app_error(png_ptr,

+            "invalid after png_start_read_image or png_read_update_info");

+

+      else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0)

+         png_app_error(png_ptr, "invalid before the PNG header has been read");

+

+      else

+      {

+         /* Turn on failure to initialize correctly for all transforms. */

+         png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;

+

+         return 1; /* Ok */

+      }

+   }

+

+   return 0; /* no png_error possible! */

+}

+#endif

+

+#ifdef PNG_READ_BACKGROUND_SUPPORTED

+/* Handle alpha and tRNS via a background color */

+void PNGFAPI

+png_set_background_fixed(png_structrp png_ptr,

+    png_const_color_16p background_color, int background_gamma_code,

+    int need_expand, png_fixed_point background_gamma)

+{

+   png_debug(1, "in png_set_background_fixed");

+

+   if (!png_rtran_ok(png_ptr, 0) || background_color == NULL)

+      return;

+

+   if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)

+   {

+      png_warning(png_ptr, "Application must supply a known background gamma");

+      return;

+   }

+

+   png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA;

+   png_ptr->transformations &= ~PNG_ENCODE_ALPHA;

+   png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;

+

+   png_ptr->background = *background_color;

+   png_ptr->background_gamma = background_gamma;

+   png_ptr->background_gamma_type = (png_byte)(background_gamma_code);

+   if (need_expand)

+      png_ptr->transformations |= PNG_BACKGROUND_EXPAND;

+   else

+      png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;

+}

+

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+void PNGAPI

+png_set_background(png_structrp png_ptr,

+    png_const_color_16p background_color, int background_gamma_code,

+    int need_expand, double background_gamma)

+{

+   png_set_background_fixed(png_ptr, background_color, background_gamma_code,

+      need_expand, png_fixed(png_ptr, background_gamma, "png_set_background"));

+}

+#  endif  /* FLOATING_POINT */

+#endif /* READ_BACKGROUND */

+

+/* Scale 16-bit depth files to 8-bit depth.  If both of these are set then the

+ * one that pngrtran does first (scale) happens.  This is necessary to allow the

+ * TRANSFORM and API behavior to be somewhat consistent, and it's simpler.

+ */

+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED

+void PNGAPI

+png_set_scale_16(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_scale_16");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= PNG_SCALE_16_TO_8;

+}

+#endif

+

+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED

+/* Chop 16-bit depth files to 8-bit depth */

+void PNGAPI

+png_set_strip_16(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_strip_16");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= PNG_16_TO_8;

+}

+#endif

+

+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED

+void PNGAPI

+png_set_strip_alpha(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_strip_alpha");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= PNG_STRIP_ALPHA;

+}

+#endif

+

+#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)

+static png_fixed_point

+translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,

+   int is_screen)

+{

+   /* Check for flag values.  The main reason for having the old Mac value as a

+    * flag is that it is pretty near impossible to work out what the correct

+    * value is from Apple documentation - a working Mac system is needed to

+    * discover the value!

+    */

+   if (output_gamma == PNG_DEFAULT_sRGB ||

+      output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)

+   {

+      /* If there is no sRGB support this just sets the gamma to the standard

+       * sRGB value.  (This is a side effect of using this function!)

+       */

+#     ifdef PNG_READ_sRGB_SUPPORTED

+         png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;

+#     else

+         PNG_UNUSED(png_ptr)

+#     endif

+      if (is_screen)

+         output_gamma = PNG_GAMMA_sRGB;

+      else

+         output_gamma = PNG_GAMMA_sRGB_INVERSE;

+   }

+

+   else if (output_gamma == PNG_GAMMA_MAC_18 ||

+      output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)

+   {

+      if (is_screen)

+         output_gamma = PNG_GAMMA_MAC_OLD;

+      else

+         output_gamma = PNG_GAMMA_MAC_INVERSE;

+   }

+

+   return output_gamma;

+}

+

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+static png_fixed_point

+convert_gamma_value(png_structrp png_ptr, double output_gamma)

+{

+   /* The following silently ignores cases where fixed point (times 100,000)

+    * gamma values are passed to the floating point API.  This is safe and it

+    * means the fixed point constants work just fine with the floating point

+    * API.  The alternative would just lead to undetected errors and spurious

+    * bug reports.  Negative values fail inside the _fixed API unless they

+    * correspond to the flag values.

+    */

+   if (output_gamma > 0 && output_gamma < 128)

+      output_gamma *= PNG_FP_1;

+

+   /* This preserves -1 and -2 exactly: */

+   output_gamma = floor(output_gamma + .5);

+

+   if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN)

+      png_fixed_error(png_ptr, "gamma value");

+

+   return (png_fixed_point)output_gamma;

+}

+#  endif

+#endif /* READ_ALPHA_MODE || READ_GAMMA */

+

+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED

+void PNGFAPI

+png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,

+   png_fixed_point output_gamma)

+{

+   int compose = 0;

+   png_fixed_point file_gamma;

+

+   png_debug(1, "in png_set_alpha_mode");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);

+

+   /* Validate the value to ensure it is in a reasonable range. The value

+    * is expected to be 1 or greater, but this range test allows for some

+    * viewing correction values.  The intent is to weed out users of this API

+    * who use the inverse of the gamma value accidentally!  Since some of these

+    * values are reasonable this may have to be changed.

+    */

+   if (output_gamma < 70000 || output_gamma > 300000)

+      png_error(png_ptr, "output gamma out of expected range");

+

+   /* The default file gamma is the inverse of the output gamma; the output

+    * gamma may be changed below so get the file value first:

+    */

+   file_gamma = png_reciprocal(output_gamma);

+

+   /* There are really 8 possibilities here, composed of any combination

+    * of:

+    *

+    *    premultiply the color channels

+    *    do not encode non-opaque pixels

+    *    encode the alpha as well as the color channels

+    *

+    * The differences disappear if the input/output ('screen') gamma is 1.0,

+    * because then the encoding is a no-op and there is only the choice of

+    * premultiplying the color channels or not.

+    *

+    * png_set_alpha_mode and png_set_background interact because both use

+    * png_compose to do the work.  Calling both is only useful when

+    * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along

+    * with a default gamma value.  Otherwise PNG_COMPOSE must not be set.

+    */

+   switch (mode)

+   {

+      case PNG_ALPHA_PNG:        /* default: png standard */

+         /* No compose, but it may be set by png_set_background! */

+         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;

+         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;

+         break;

+

+      case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */

+         compose = 1;

+         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;

+         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;

+         /* The output is linear: */

+         output_gamma = PNG_FP_1;

+         break;

+

+      case PNG_ALPHA_OPTIMIZED:  /* associated, non-opaque pixels linear */

+         compose = 1;

+         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;

+         png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA;

+         /* output_gamma records the encoding of opaque pixels! */

+         break;

+

+      case PNG_ALPHA_BROKEN:     /* associated, non-linear, alpha encoded */

+         compose = 1;

+         png_ptr->transformations |= PNG_ENCODE_ALPHA;

+         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;

+         break;

+

+      default:

+         png_error(png_ptr, "invalid alpha mode");

+   }

+

+   /* Only set the default gamma if the file gamma has not been set (this has

+    * the side effect that the gamma in a second call to png_set_alpha_mode will

+    * be ignored.)

+    */

+   if (png_ptr->colorspace.gamma == 0)

+   {

+      png_ptr->colorspace.gamma = file_gamma;

+      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;

+   }

+

+   /* But always set the output gamma: */

+   png_ptr->screen_gamma = output_gamma;

+

+   /* Finally, if pre-multiplying, set the background fields to achieve the

+    * desired result.

+    */

+   if (compose)

+   {

+      /* And obtain alpha pre-multiplication by composing on black: */

+      memset(&png_ptr->background, 0, (sizeof png_ptr->background));

+      png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */

+      png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE;

+      png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;

+

+      if (png_ptr->transformations & PNG_COMPOSE)

+         png_error(png_ptr,

+            "conflicting calls to set alpha mode and background");

+

+      png_ptr->transformations |= PNG_COMPOSE;

+   }

+}

+

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+void PNGAPI

+png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma)

+{

+   png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr,

+      output_gamma));

+}

+#  endif

+#endif

+

+#ifdef PNG_READ_QUANTIZE_SUPPORTED

+/* Dither file to 8-bit.  Supply a palette, the current number

+ * of elements in the palette, the maximum number of elements

+ * allowed, and a histogram if possible.  If the current number

+ * of colors is greater then the maximum number, the palette will be

+ * modified to fit in the maximum number.  "full_quantize" indicates

+ * whether we need a quantizing cube set up for RGB images, or if we

+ * simply are reducing the number of colors in a paletted image.

+ */

+

+typedef struct png_dsort_struct

+{

+   struct png_dsort_struct * next;

+   png_byte left;

+   png_byte right;

+} png_dsort;

+typedef png_dsort *   png_dsortp;

+typedef png_dsort * * png_dsortpp;

+

+void PNGAPI

+png_set_quantize(png_structrp png_ptr, png_colorp palette,

+    int num_palette, int maximum_colors, png_const_uint_16p histogram,

+    int full_quantize)

+{

+   png_debug(1, "in png_set_quantize");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= PNG_QUANTIZE;

+

+   if (!full_quantize)

+   {

+      int i;

+

+      png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,

+          (png_uint_32)(num_palette * (sizeof (png_byte))));

+      for (i = 0; i < num_palette; i++)

+         png_ptr->quantize_index[i] = (png_byte)i;

+   }

+

+   if (num_palette > maximum_colors)

+   {

+      if (histogram != NULL)

+      {

+         /* This is easy enough, just throw out the least used colors.

+          * Perhaps not the best solution, but good enough.

+          */

+

+         int i;

+

+         /* Initialize an array to sort colors */

+         png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,

+             (png_uint_32)(num_palette * (sizeof (png_byte))));

+

+         /* Initialize the quantize_sort array */

+         for (i = 0; i < num_palette; i++)

+            png_ptr->quantize_sort[i] = (png_byte)i;

+

+         /* Find the least used palette entries by starting a

+          * bubble sort, and running it until we have sorted

+          * out enough colors.  Note that we don't care about

+          * sorting all the colors, just finding which are

+          * least used.

+          */

+

+         for (i = num_palette - 1; i >= maximum_colors; i--)

+         {

+            int done; /* To stop early if the list is pre-sorted */

+            int j;

+

+            done = 1;

+            for (j = 0; j < i; j++)

+            {

+               if (histogram[png_ptr->quantize_sort[j]]

+                   < histogram[png_ptr->quantize_sort[j + 1]])

+               {

+                  png_byte t;

+

+                  t = png_ptr->quantize_sort[j];

+                  png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];

+                  png_ptr->quantize_sort[j + 1] = t;

+                  done = 0;

+               }

+            }

+

+            if (done)

+               break;

+         }

+

+         /* Swap the palette around, and set up a table, if necessary */

+         if (full_quantize)

+         {

+            int j = num_palette;

+

+            /* Put all the useful colors within the max, but don't

+             * move the others.

+             */

+            for (i = 0; i < maximum_colors; i++)

+            {

+               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)

+               {

+                  do

+                     j--;

+                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);

+

+                  palette[i] = palette[j];

+               }

+            }

+         }

+         else

+         {

+            int j = num_palette;

+

+            /* Move all the used colors inside the max limit, and

+             * develop a translation table.

+             */

+            for (i = 0; i < maximum_colors; i++)

+            {

+               /* Only move the colors we need to */

+               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)

+               {

+                  png_color tmp_color;

+

+                  do

+                     j--;

+                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);

+

+                  tmp_color = palette[j];

+                  palette[j] = palette[i];

+                  palette[i] = tmp_color;

+                  /* Indicate where the color went */

+                  png_ptr->quantize_index[j] = (png_byte)i;

+                  png_ptr->quantize_index[i] = (png_byte)j;

+               }

+            }

+

+            /* Find closest color for those colors we are not using */

+            for (i = 0; i < num_palette; i++)

+            {

+               if ((int)png_ptr->quantize_index[i] >= maximum_colors)

+               {

+                  int min_d, k, min_k, d_index;

+

+                  /* Find the closest color to one we threw out */

+                  d_index = png_ptr->quantize_index[i];

+                  min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);

+                  for (k = 1, min_k = 0; k < maximum_colors; k++)

+                  {

+                     int d;

+

+                     d = PNG_COLOR_DIST(palette[d_index], palette[k]);

+

+                     if (d < min_d)

+                     {

+                        min_d = d;

+                        min_k = k;

+                     }

+                  }

+                  /* Point to closest color */

+                  png_ptr->quantize_index[i] = (png_byte)min_k;

+               }

+            }

+         }

+         png_free(png_ptr, png_ptr->quantize_sort);

+         png_ptr->quantize_sort = NULL;

+      }

+      else

+      {

+         /* This is much harder to do simply (and quickly).  Perhaps

+          * we need to go through a median cut routine, but those

+          * don't always behave themselves with only a few colors

+          * as input.  So we will just find the closest two colors,

+          * and throw out one of them (chosen somewhat randomly).

+          * [We don't understand this at all, so if someone wants to

+          *  work on improving it, be our guest - AED, GRP]

+          */

+         int i;

+         int max_d;

+         int num_new_palette;

+         png_dsortp t;

+         png_dsortpp hash;

+

+         t = NULL;

+

+         /* Initialize palette index arrays */

+         png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,

+             (png_uint_32)(num_palette * (sizeof (png_byte))));

+         png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,

+             (png_uint_32)(num_palette * (sizeof (png_byte))));

+

+         /* Initialize the sort array */

+         for (i = 0; i < num_palette; i++)

+         {

+            png_ptr->index_to_palette[i] = (png_byte)i;

+            png_ptr->palette_to_index[i] = (png_byte)i;

+         }

+

+         hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *

+             (sizeof (png_dsortp))));

+

+         num_new_palette = num_palette;

+

+         /* Initial wild guess at how far apart the farthest pixel

+          * pair we will be eliminating will be.  Larger

+          * numbers mean more areas will be allocated, Smaller

+          * numbers run the risk of not saving enough data, and

+          * having to do this all over again.

+          *

+          * I have not done extensive checking on this number.

+          */

+         max_d = 96;

+

+         while (num_new_palette > maximum_colors)

+         {

+            for (i = 0; i < num_new_palette - 1; i++)

+            {

+               int j;

+

+               for (j = i + 1; j < num_new_palette; j++)

+               {

+                  int d;

+

+                  d = PNG_COLOR_DIST(palette[i], palette[j]);

+

+                  if (d <= max_d)

+                  {

+

+                     t = (png_dsortp)png_malloc_warn(png_ptr,

+                         (png_uint_32)(sizeof (png_dsort)));

+

+                     if (t == NULL)

+                         break;

+

+                     t->next = hash[d];

+                     t->left = (png_byte)i;

+                     t->right = (png_byte)j;

+                     hash[d] = t;

+                  }

+               }

+               if (t == NULL)

+                  break;

+            }

+

+            if (t != NULL)

+            for (i = 0; i <= max_d; i++)

+            {

+               if (hash[i] != NULL)

+               {

+                  png_dsortp p;

+

+                  for (p = hash[i]; p; p = p->next)

+                  {

+                     if ((int)png_ptr->index_to_palette[p->left]

+                         < num_new_palette &&

+                         (int)png_ptr->index_to_palette[p->right]

+                         < num_new_palette)

+                     {

+                        int j, next_j;

+

+                        if (num_new_palette & 0x01)

+                        {

+                           j = p->left;

+                           next_j = p->right;

+                        }

+                        else

+                        {

+                           j = p->right;

+                           next_j = p->left;

+                        }

+

+                        num_new_palette--;

+                        palette[png_ptr->index_to_palette[j]]

+                            = palette[num_new_palette];

+                        if (!full_quantize)

+                        {

+                           int k;

+

+                           for (k = 0; k < num_palette; k++)

+                           {

+                              if (png_ptr->quantize_index[k] ==

+                                  png_ptr->index_to_palette[j])

+                                 png_ptr->quantize_index[k] =

+                                     png_ptr->index_to_palette[next_j];

+

+                              if ((int)png_ptr->quantize_index[k] ==

+                                  num_new_palette)

+                                 png_ptr->quantize_index[k] =

+                                     png_ptr->index_to_palette[j];

+                           }

+                        }

+

+                        png_ptr->index_to_palette[png_ptr->palette_to_index

+                            [num_new_palette]] = png_ptr->index_to_palette[j];

+

+                        png_ptr->palette_to_index[png_ptr->index_to_palette[j]]

+                            = png_ptr->palette_to_index[num_new_palette];

+

+                        png_ptr->index_to_palette[j] =

+                            (png_byte)num_new_palette;

+

+                        png_ptr->palette_to_index[num_new_palette] =

+                            (png_byte)j;

+                     }

+                     if (num_new_palette <= maximum_colors)

+                        break;

+                  }

+                  if (num_new_palette <= maximum_colors)

+                     break;

+               }

+            }

+

+            for (i = 0; i < 769; i++)

+            {

+               if (hash[i] != NULL)

+               {

+                  png_dsortp p = hash[i];

+                  while (p)

+                  {

+                     t = p->next;

+                     png_free(png_ptr, p);

+                     p = t;

+                  }

+               }

+               hash[i] = 0;

+            }

+            max_d += 96;

+         }

+         png_free(png_ptr, hash);

+         png_free(png_ptr, png_ptr->palette_to_index);

+         png_free(png_ptr, png_ptr->index_to_palette);

+         png_ptr->palette_to_index = NULL;

+         png_ptr->index_to_palette = NULL;

+      }

+      num_palette = maximum_colors;

+   }

+   if (png_ptr->palette == NULL)

+   {

+      png_ptr->palette = palette;

+   }

+   png_ptr->num_palette = (png_uint_16)num_palette;

+

+   if (full_quantize)

+   {

+      int i;

+      png_bytep distance;

+      int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS +

+          PNG_QUANTIZE_BLUE_BITS;

+      int num_red = (1 << PNG_QUANTIZE_RED_BITS);

+      int num_green = (1 << PNG_QUANTIZE_GREEN_BITS);

+      int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS);

+      png_size_t num_entries = ((png_size_t)1 << total_bits);

+

+      png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,

+          (png_uint_32)(num_entries * (sizeof (png_byte))));

+

+      distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *

+          (sizeof (png_byte))));

+

+      memset(distance, 0xff, num_entries * (sizeof (png_byte)));

+

+      for (i = 0; i < num_palette; i++)

+      {

+         int ir, ig, ib;

+         int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS));

+         int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS));

+         int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS));

+

+         for (ir = 0; ir < num_red; ir++)

+         {

+            /* int dr = abs(ir - r); */

+            int dr = ((ir > r) ? ir - r : r - ir);

+            int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS +

+                PNG_QUANTIZE_GREEN_BITS));

+

+            for (ig = 0; ig < num_green; ig++)

+            {

+               /* int dg = abs(ig - g); */

+               int dg = ((ig > g) ? ig - g : g - ig);

+               int dt = dr + dg;

+               int dm = ((dr > dg) ? dr : dg);

+               int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS);

+

+               for (ib = 0; ib < num_blue; ib++)

+               {

+                  int d_index = index_g | ib;

+                  /* int db = abs(ib - b); */

+                  int db = ((ib > b) ? ib - b : b - ib);

+                  int dmax = ((dm > db) ? dm : db);

+                  int d = dmax + dt + db;

+

+                  if (d < (int)distance[d_index])

+                  {

+                     distance[d_index] = (png_byte)d;

+                     png_ptr->palette_lookup[d_index] = (png_byte)i;

+                  }

+               }

+            }

+         }

+      }

+

+      png_free(png_ptr, distance);

+   }

+}

+#endif /* PNG_READ_QUANTIZE_SUPPORTED */

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+void PNGFAPI

+png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,

+   png_fixed_point file_gamma)

+{

+   png_debug(1, "in png_set_gamma_fixed");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   /* New in libpng-1.5.4 - reserve particular negative values as flags. */

+   scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);

+   file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);

+

+   /* Checking the gamma values for being >0 was added in 1.5.4 along with the

+    * premultiplied alpha support; this actually hides an undocumented feature

+    * of the previous implementation which allowed gamma processing to be

+    * disabled in background handling.  There is no evidence (so far) that this

+    * was being used; however, png_set_background itself accepted and must still

+    * accept '0' for the gamma value it takes, because it isn't always used.

+    *

+    * Since this is an API change (albeit a very minor one that removes an

+    * undocumented API feature) the following checks were only enabled in

+    * libpng-1.6.0.

+    */

+   if (file_gamma <= 0)

+      png_error(png_ptr, "invalid file gamma in png_set_gamma");

+

+   if (scrn_gamma <= 0)

+      png_error(png_ptr, "invalid screen gamma in png_set_gamma");

+

+   /* Set the gamma values unconditionally - this overrides the value in the PNG

+    * file if a gAMA chunk was present.  png_set_alpha_mode provides a

+    * different, easier, way to default the file gamma.

+    */

+   png_ptr->colorspace.gamma = file_gamma;

+   png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;

+   png_ptr->screen_gamma = scrn_gamma;

+}

+

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+void PNGAPI

+png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma)

+{

+   png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma),

+      convert_gamma_value(png_ptr, file_gamma));

+}

+#  endif /* FLOATING_POINT_SUPPORTED */

+#endif /* READ_GAMMA */

+

+#ifdef PNG_READ_EXPAND_SUPPORTED

+/* Expand paletted images to RGB, expand grayscale images of

+ * less than 8-bit depth to 8-bit depth, and expand tRNS chunks

+ * to alpha channels.

+ */

+void PNGAPI

+png_set_expand(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_expand");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);

+}

+

+/* GRR 19990627:  the following three functions currently are identical

+ *  to png_set_expand().  However, it is entirely reasonable that someone

+ *  might wish to expand an indexed image to RGB but *not* expand a single,

+ *  fully transparent palette entry to a full alpha channel--perhaps instead

+ *  convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace

+ *  the transparent color with a particular RGB value, or drop tRNS entirely.

+ *  IOW, a future version of the library may make the transformations flag

+ *  a bit more fine-grained, with separate bits for each of these three

+ *  functions.

+ *

+ *  More to the point, these functions make it obvious what libpng will be

+ *  doing, whereas "expand" can (and does) mean any number of things.

+ *

+ *  GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified

+ *  to expand only the sample depth but not to expand the tRNS to alpha

+ *  and its name was changed to png_set_expand_gray_1_2_4_to_8().

+ */

+

+/* Expand paletted images to RGB. */

+void PNGAPI

+png_set_palette_to_rgb(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_palette_to_rgb");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);

+}

+

+/* Expand grayscale images of less than 8-bit depth to 8 bits. */

+void PNGAPI

+png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_expand_gray_1_2_4_to_8");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= PNG_EXPAND;

+}

+

+/* Expand tRNS chunks to alpha channels. */

+void PNGAPI

+png_set_tRNS_to_alpha(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_tRNS_to_alpha");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);

+}

+#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */

+

+#ifdef PNG_READ_EXPAND_16_SUPPORTED

+/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise

+ * it may not work correctly.)

+ */

+void PNGAPI

+png_set_expand_16(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_expand_16");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS);

+}

+#endif

+

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+void PNGAPI

+png_set_gray_to_rgb(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_gray_to_rgb");

+

+   if (!png_rtran_ok(png_ptr, 0))

+      return;

+

+   /* Because rgb must be 8 bits or more: */

+   png_set_expand_gray_1_2_4_to_8(png_ptr);

+   png_ptr->transformations |= PNG_GRAY_TO_RGB;

+}

+#endif

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+void PNGFAPI

+png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,

+    png_fixed_point red, png_fixed_point green)

+{

+   png_debug(1, "in png_set_rgb_to_gray");

+

+   /* Need the IHDR here because of the check on color_type below. */

+   /* TODO: fix this */

+   if (!png_rtran_ok(png_ptr, 1))

+      return;

+

+   switch(error_action)

+   {

+      case PNG_ERROR_ACTION_NONE:

+         png_ptr->transformations |= PNG_RGB_TO_GRAY;

+         break;

+

+      case PNG_ERROR_ACTION_WARN:

+         png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;

+         break;

+

+      case PNG_ERROR_ACTION_ERROR:

+         png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;

+         break;

+

+      default:

+         png_error(png_ptr, "invalid error action to rgb_to_gray");

+         break;

+   }

+

+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+#ifdef PNG_READ_EXPAND_SUPPORTED

+      png_ptr->transformations |= PNG_EXPAND;

+#else

+   {

+      /* Make this an error in 1.6 because otherwise the application may assume

+       * that it just worked and get a memory overwrite.

+       */

+      png_error(png_ptr,

+        "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");

+

+      /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */

+   }

+#endif

+   {

+      if (red >= 0 && green >= 0 && red + green <= PNG_FP_1)

+      {

+         png_uint_16 red_int, green_int;

+

+         /* NOTE: this calculation does not round, but this behavior is retained

+          * for consistency, the inaccuracy is very small.  The code here always

+          * overwrites the coefficients, regardless of whether they have been

+          * defaulted or set already.

+          */

+         red_int = (png_uint_16)(((png_uint_32)red*32768)/100000);

+         green_int = (png_uint_16)(((png_uint_32)green*32768)/100000);

+

+         png_ptr->rgb_to_gray_red_coeff   = red_int;

+         png_ptr->rgb_to_gray_green_coeff = green_int;

+         png_ptr->rgb_to_gray_coefficients_set = 1;

+      }

+

+      else

+      {

+         if (red >= 0 && green >= 0)

+            png_app_warning(png_ptr,

+               "ignoring out of range rgb_to_gray coefficients");

+

+         /* Use the defaults, from the cHRM chunk if set, else the historical

+          * values which are close to the sRGB/HDTV/ITU-Rec 709 values.  See

+          * png_do_rgb_to_gray for more discussion of the values.  In this case

+          * the coefficients are not marked as 'set' and are not overwritten if

+          * something has already provided a default.

+          */

+         if (png_ptr->rgb_to_gray_red_coeff == 0 &&

+            png_ptr->rgb_to_gray_green_coeff == 0)

+         {

+            png_ptr->rgb_to_gray_red_coeff   = 6968;

+            png_ptr->rgb_to_gray_green_coeff = 23434;

+            /* png_ptr->rgb_to_gray_blue_coeff  = 2366; */

+         }

+      }

+   }

+}

+

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+/* Convert a RGB image to a grayscale of the same width.  This allows us,

+ * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.

+ */

+

+void PNGAPI

+png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,

+   double green)

+{

+   png_set_rgb_to_gray_fixed(png_ptr, error_action,

+      png_fixed(png_ptr, red, "rgb to gray red coefficient"),

+      png_fixed(png_ptr, green, "rgb to gray green coefficient"));

+}

+#endif /* FLOATING POINT */

+

+#endif /* RGB_TO_GRAY */

+

+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \

+    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)

+void PNGAPI

+png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr

+    read_user_transform_fn)

+{

+   png_debug(1, "in png_set_read_user_transform_fn");

+

+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED

+   png_ptr->transformations |= PNG_USER_TRANSFORM;

+   png_ptr->read_user_transform_fn = read_user_transform_fn;

+#endif

+}

+#endif

+

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+#ifdef PNG_READ_GAMMA_SUPPORTED

+/* In the case of gamma transformations only do transformations on images where

+ * the [file] gamma and screen_gamma are not close reciprocals, otherwise it

+ * slows things down slightly, and also needlessly introduces small errors.

+ */

+static int /* PRIVATE */

+png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)

+{

+   /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma

+    * correction as a difference of the overall transform from 1.0

+    *

+    * We want to compare the threshold with s*f - 1, if we get

+    * overflow here it is because of wacky gamma values so we

+    * turn on processing anyway.

+    */

+   png_fixed_point gtest;

+   return !png_muldiv(&gtest, screen_gamma, file_gamma, PNG_FP_1) ||

+       png_gamma_significant(gtest);

+}

+#endif

+

+/* Initialize everything needed for the read.  This includes modifying

+ * the palette.

+ */

+

+/*For the moment 'png_init_palette_transformations' and

+ * 'png_init_rgb_transformations' only do some flag canceling optimizations.

+ * The intent is that these two routines should have palette or rgb operations

+ * extracted from 'png_init_read_transformations'.

+ */

+static void /* PRIVATE */

+png_init_palette_transformations(png_structrp png_ptr)

+{

+   /* Called to handle the (input) palette case.  In png_do_read_transformations

+    * the first step is to expand the palette if requested, so this code must

+    * take care to only make changes that are invariant with respect to the

+    * palette expansion, or only do them if there is no expansion.

+    *

+    * STRIP_ALPHA has already been handled in the caller (by setting num_trans

+    * to 0.)

+    */

+   int input_has_alpha = 0;

+   int input_has_transparency = 0;

+

+   if (png_ptr->num_trans > 0)

+   {

+      int i;

+

+      /* Ignore if all the entries are opaque (unlikely!) */

+      for (i=0; i<png_ptr->num_trans; ++i)

+         if (png_ptr->trans_alpha[i] == 255)

+            continue;

+         else if (png_ptr->trans_alpha[i] == 0)

+            input_has_transparency = 1;

+         else

+            input_has_alpha = 1;

+   }

+

+   /* If no alpha we can optimize. */

+   if (!input_has_alpha)

+   {

+      /* Any alpha means background and associative alpha processing is

+       * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA

+       * and ENCODE_ALPHA are irrelevant.

+       */

+      png_ptr->transformations &= ~PNG_ENCODE_ALPHA;

+      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;

+

+      if (!input_has_transparency)

+         png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);

+   }

+

+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)

+   /* png_set_background handling - deals with the complexity of whether the

+    * background color is in the file format or the screen format in the case

+    * where an 'expand' will happen.

+    */

+

+   /* The following code cannot be entered in the alpha pre-multiplication case

+    * because PNG_BACKGROUND_EXPAND is cancelled below.

+    */

+   if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&

+       (png_ptr->transformations & PNG_EXPAND))

+   {

+      {

+         png_ptr->background.red   =

+             png_ptr->palette[png_ptr->background.index].red;

+         png_ptr->background.green =

+             png_ptr->palette[png_ptr->background.index].green;

+         png_ptr->background.blue  =

+             png_ptr->palette[png_ptr->background.index].blue;

+

+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED

+        if (png_ptr->transformations & PNG_INVERT_ALPHA)

+        {

+           if (!(png_ptr->transformations & PNG_EXPAND_tRNS))

+           {

+              /* Invert the alpha channel (in tRNS) unless the pixels are

+               * going to be expanded, in which case leave it for later

+               */

+              int i, istop = png_ptr->num_trans;

+

+              for (i=0; i<istop; i++)

+                 png_ptr->trans_alpha[i] = (png_byte)(255 -

+                    png_ptr->trans_alpha[i]);

+           }

+        }

+#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */

+      }

+   } /* background expand and (therefore) no alpha association. */

+#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */

+}

+

+static void /* PRIVATE */

+png_init_rgb_transformations(png_structrp png_ptr)

+{

+   /* Added to libpng-1.5.4: check the color type to determine whether there

+    * is any alpha or transparency in the image and simply cancel the

+    * background and alpha mode stuff if there isn't.

+    */

+   int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0;

+   int input_has_transparency = png_ptr->num_trans > 0;

+

+   /* If no alpha we can optimize. */

+   if (!input_has_alpha)

+   {

+      /* Any alpha means background and associative alpha processing is

+       * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA

+       * and ENCODE_ALPHA are irrelevant.

+       */

+#     ifdef PNG_READ_ALPHA_MODE_SUPPORTED

+         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;

+         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;

+#     endif

+

+      if (!input_has_transparency)

+         png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);

+   }

+

+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)

+   /* png_set_background handling - deals with the complexity of whether the

+    * background color is in the file format or the screen format in the case

+    * where an 'expand' will happen.

+    */

+

+   /* The following code cannot be entered in the alpha pre-multiplication case

+    * because PNG_BACKGROUND_EXPAND is cancelled below.

+    */

+   if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&

+       (png_ptr->transformations & PNG_EXPAND) &&

+       !(png_ptr->color_type & PNG_COLOR_MASK_COLOR))

+       /* i.e., GRAY or GRAY_ALPHA */

+   {

+      {

+         /* Expand background and tRNS chunks */

+         int gray = png_ptr->background.gray;

+         int trans_gray = png_ptr->trans_color.gray;

+

+         switch (png_ptr->bit_depth)

+         {

+            case 1:

+               gray *= 0xff;

+               trans_gray *= 0xff;

+               break;

+

+            case 2:

+               gray *= 0x55;

+               trans_gray *= 0x55;

+               break;

+

+            case 4:

+               gray *= 0x11;

+               trans_gray *= 0x11;

+               break;

+

+            default:

+

+            case 8:

+               /* FALL THROUGH (Already 8 bits) */

+

+            case 16:

+               /* Already a full 16 bits */

+               break;

+         }

+

+         png_ptr->background.red = png_ptr->background.green =

+            png_ptr->background.blue = (png_uint_16)gray;

+

+         if (!(png_ptr->transformations & PNG_EXPAND_tRNS))

+         {

+            png_ptr->trans_color.red = png_ptr->trans_color.green =

+               png_ptr->trans_color.blue = (png_uint_16)trans_gray;

+         }

+      }

+   } /* background expand and (therefore) no alpha association. */

+#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */

+}

+

+void /* PRIVATE */

+png_init_read_transformations(png_structrp png_ptr)

+{

+   png_debug(1, "in png_init_read_transformations");

+

+   /* This internal function is called from png_read_start_row in pngrutil.c

+    * and it is called before the 'rowbytes' calculation is done, so the code

+    * in here can change or update the transformations flags.

+    *

+    * First do updates that do not depend on the details of the PNG image data

+    * being processed.

+    */

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+   /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds

+    * png_set_alpha_mode and this is another source for a default file gamma so

+    * the test needs to be performed later - here.  In addition prior to 1.5.4

+    * the tests were repeated for the PALETTE color type here - this is no

+    * longer necessary (and doesn't seem to have been necessary before.)

+    */

+   {

+      /* The following temporary indicates if overall gamma correction is

+       * required.

+       */

+      int gamma_correction = 0;

+

+      if (png_ptr->colorspace.gamma != 0) /* has been set */

+      {

+         if (png_ptr->screen_gamma != 0) /* screen set too */

+            gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma,

+               png_ptr->screen_gamma);

+

+         else

+            /* Assume the output matches the input; a long time default behavior

+             * of libpng, although the standard has nothing to say about this.

+             */

+            png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma);

+      }

+

+      else if (png_ptr->screen_gamma != 0)

+         /* The converse - assume the file matches the screen, note that this

+          * perhaps undesireable default can (from 1.5.4) be changed by calling

+          * png_set_alpha_mode (even if the alpha handling mode isn't required

+          * or isn't changed from the default.)

+          */

+         png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma);

+

+      else /* neither are set */

+         /* Just in case the following prevents any processing - file and screen

+          * are both assumed to be linear and there is no way to introduce a

+          * third gamma value other than png_set_background with 'UNIQUE', and,

+          * prior to 1.5.4

+          */

+         png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1;

+

+      /* We have a gamma value now. */

+      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;

+

+      /* Now turn the gamma transformation on or off as appropriate.  Notice

+       * that PNG_GAMMA just refers to the file->screen correction.  Alpha

+       * composition may independently cause gamma correction because it needs

+       * linear data (e.g. if the file has a gAMA chunk but the screen gamma

+       * hasn't been specified.)  In any case this flag may get turned off in

+       * the code immediately below if the transform can be handled outside the

+       * row loop.

+       */

+      if (gamma_correction)

+         png_ptr->transformations |= PNG_GAMMA;

+

+      else

+         png_ptr->transformations &= ~PNG_GAMMA;

+   }

+#endif

+

+   /* Certain transformations have the effect of preventing other

+    * transformations that happen afterward in png_do_read_transformations,

+    * resolve the interdependencies here.  From the code of

+    * png_do_read_transformations the order is:

+    *

+    *  1) PNG_EXPAND (including PNG_EXPAND_tRNS)

+    *  2) PNG_STRIP_ALPHA (if no compose)

+    *  3) PNG_RGB_TO_GRAY

+    *  4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY

+    *  5) PNG_COMPOSE

+    *  6) PNG_GAMMA

+    *  7) PNG_STRIP_ALPHA (if compose)

+    *  8) PNG_ENCODE_ALPHA

+    *  9) PNG_SCALE_16_TO_8

+    * 10) PNG_16_TO_8

+    * 11) PNG_QUANTIZE (converts to palette)

+    * 12) PNG_EXPAND_16

+    * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY

+    * 14) PNG_INVERT_MONO

+    * 15) PNG_SHIFT

+    * 16) PNG_PACK

+    * 17) PNG_BGR

+    * 18) PNG_PACKSWAP

+    * 19) PNG_FILLER (includes PNG_ADD_ALPHA)

+    * 20) PNG_INVERT_ALPHA

+    * 21) PNG_SWAP_ALPHA

+    * 22) PNG_SWAP_BYTES

+    * 23) PNG_USER_TRANSFORM [must be last]

+    */

+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED

+   if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&

+      !(png_ptr->transformations & PNG_COMPOSE))

+   {

+      /* Stripping the alpha channel happens immediately after the 'expand'

+       * transformations, before all other transformation, so it cancels out

+       * the alpha handling.  It has the side effect negating the effect of

+       * PNG_EXPAND_tRNS too:

+       */

+      png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA |

+         PNG_EXPAND_tRNS);

+      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;

+

+      /* Kill the tRNS chunk itself too.  Prior to 1.5.4 this did not happen

+       * so transparency information would remain just so long as it wasn't

+       * expanded.  This produces unexpected API changes if the set of things

+       * that do PNG_EXPAND_tRNS changes (perfectly possible given the

+       * documentation - which says ask for what you want, accept what you

+       * get.)  This makes the behavior consistent from 1.5.4:

+       */

+      png_ptr->num_trans = 0;

+   }

+#endif /* STRIP_ALPHA supported, no COMPOSE */

+

+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED

+   /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA

+    * settings will have no effect.

+    */

+   if (!png_gamma_significant(png_ptr->screen_gamma))

+   {

+      png_ptr->transformations &= ~PNG_ENCODE_ALPHA;

+      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;

+   }

+#endif

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+   /* Make sure the coefficients for the rgb to gray conversion are set

+    * appropriately.

+    */

+   if (png_ptr->transformations & PNG_RGB_TO_GRAY)

+      png_colorspace_set_rgb_coefficients(png_ptr);

+#endif

+

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)

+   /* Detect gray background and attempt to enable optimization for

+    * gray --> RGB case.

+    *

+    * Note:  if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or

+    * RGB_ALPHA (in which case need_expand is superfluous anyway), the

+    * background color might actually be gray yet not be flagged as such.

+    * This is not a problem for the current code, which uses

+    * PNG_BACKGROUND_IS_GRAY only to decide when to do the

+    * png_do_gray_to_rgb() transformation.

+    *

+    * TODO: this code needs to be revised to avoid the complexity and

+    * interdependencies.  The color type of the background should be recorded in

+    * png_set_background, along with the bit depth, then the code has a record

+    * of exactly what color space the background is currently in.

+    */

+   if (png_ptr->transformations & PNG_BACKGROUND_EXPAND)

+   {

+      /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if

+       * the file was grayscale the background value is gray.

+       */

+      if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR))

+         png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;

+   }

+

+   else if (png_ptr->transformations & PNG_COMPOSE)

+   {

+      /* PNG_COMPOSE: png_set_background was called with need_expand false,

+       * so the color is in the color space of the output or png_set_alpha_mode

+       * was called and the color is black.  Ignore RGB_TO_GRAY because that

+       * happens before GRAY_TO_RGB.

+       */

+      if (png_ptr->transformations & PNG_GRAY_TO_RGB)

+      {

+         if (png_ptr->background.red == png_ptr->background.green &&

+             png_ptr->background.red == png_ptr->background.blue)

+         {

+            png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;

+            png_ptr->background.gray = png_ptr->background.red;

+         }

+      }

+   }

+#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */

+#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */

+

+   /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations

+    * can be performed directly on the palette, and some (such as rgb to gray)

+    * can be optimized inside the palette.  This is particularly true of the

+    * composite (background and alpha) stuff, which can be pretty much all done

+    * in the palette even if the result is expanded to RGB or gray afterward.

+    *

+    * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and

+    * earlier and the palette stuff is actually handled on the first row.  This

+    * leads to the reported bug that the palette returned by png_get_PLTE is not

+    * updated.

+    */

+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      png_init_palette_transformations(png_ptr);

+

+   else

+      png_init_rgb_transformations(png_ptr);

+

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \

+   defined(PNG_READ_EXPAND_16_SUPPORTED)

+   if ((png_ptr->transformations & PNG_EXPAND_16) &&

+      (png_ptr->transformations & PNG_COMPOSE) &&

+      !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&

+      png_ptr->bit_depth != 16)

+   {

+      /* TODO: fix this.  Because the expand_16 operation is after the compose

+       * handling the background color must be 8, not 16, bits deep, but the

+       * application will supply a 16-bit value so reduce it here.

+       *

+       * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at

+       * present, so that case is ok (until do_expand_16 is moved.)

+       *

+       * NOTE: this discards the low 16 bits of the user supplied background

+       * color, but until expand_16 works properly there is no choice!

+       */

+#     define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x))

+      CHOP(png_ptr->background.red);

+      CHOP(png_ptr->background.green);

+      CHOP(png_ptr->background.blue);

+      CHOP(png_ptr->background.gray);

+#     undef CHOP

+   }

+#endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */

+

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \

+   (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \

+   defined(PNG_READ_STRIP_16_TO_8_SUPPORTED))

+   if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) &&

+      (png_ptr->transformations & PNG_COMPOSE) &&

+      !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&

+      png_ptr->bit_depth == 16)

+   {

+      /* On the other hand, if a 16-bit file is to be reduced to 8-bits per

+       * component this will also happen after PNG_COMPOSE and so the background

+       * color must be pre-expanded here.

+       *

+       * TODO: fix this too.

+       */

+      png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257);

+      png_ptr->background.green =

+         (png_uint_16)(png_ptr->background.green * 257);

+      png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257);

+      png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257);

+   }

+#endif

+

+   /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the

+    * background support (see the comments in scripts/pnglibconf.dfa), this

+    * allows pre-multiplication of the alpha channel to be implemented as

+    * compositing on black.  This is probably sub-optimal and has been done in

+    * 1.5.4 betas simply to enable external critique and testing (i.e. to

+    * implement the new API quickly, without lots of internal changes.)

+    */

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+#  ifdef PNG_READ_BACKGROUND_SUPPORTED

+      /* Includes ALPHA_MODE */

+      png_ptr->background_1 = png_ptr->background;

+#  endif

+

+   /* This needs to change - in the palette image case a whole set of tables are

+    * built when it would be quicker to just calculate the correct value for

+    * each palette entry directly.  Also, the test is too tricky - why check

+    * PNG_RGB_TO_GRAY if PNG_GAMMA is not set?  The answer seems to be that

+    * PNG_GAMMA is cancelled even if the gamma is known?  The test excludes the

+    * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction

+    * the gamma tables will not be built even if composition is required on a

+    * gamma encoded value.

+    *

+    * In 1.5.4 this is addressed below by an additional check on the individual

+    * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the

+    * tables.

+    */

+   if ((png_ptr->transformations & PNG_GAMMA)

+      || ((png_ptr->transformations & PNG_RGB_TO_GRAY)

+         && (png_gamma_significant(png_ptr->colorspace.gamma) ||

+            png_gamma_significant(png_ptr->screen_gamma)))

+      || ((png_ptr->transformations & PNG_COMPOSE)

+         && (png_gamma_significant(png_ptr->colorspace.gamma)

+            || png_gamma_significant(png_ptr->screen_gamma)

+#  ifdef PNG_READ_BACKGROUND_SUPPORTED

+            || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE

+               && png_gamma_significant(png_ptr->background_gamma))

+#  endif

+      )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA)

+         && png_gamma_significant(png_ptr->screen_gamma))

+      )

+   {

+      png_build_gamma_table(png_ptr, png_ptr->bit_depth);

+

+#ifdef PNG_READ_BACKGROUND_SUPPORTED

+      if (png_ptr->transformations & PNG_COMPOSE)

+      {

+         /* Issue a warning about this combination: because RGB_TO_GRAY is

+          * optimized to do the gamma transform if present yet do_background has

+          * to do the same thing if both options are set a

+          * double-gamma-correction happens.  This is true in all versions of

+          * libpng to date.

+          */

+         if (png_ptr->transformations & PNG_RGB_TO_GRAY)

+            png_warning(png_ptr,

+               "libpng does not support gamma+background+rgb_to_gray");

+

+         if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+         {

+            /* We don't get to here unless there is a tRNS chunk with non-opaque

+             * entries - see the checking code at the start of this function.

+             */

+            png_color back, back_1;

+            png_colorp palette = png_ptr->palette;

+            int num_palette = png_ptr->num_palette;

+            int i;

+            if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)

+            {

+

+               back.red = png_ptr->gamma_table[png_ptr->background.red];

+               back.green = png_ptr->gamma_table[png_ptr->background.green];

+               back.blue = png_ptr->gamma_table[png_ptr->background.blue];

+

+               back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];

+               back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];

+               back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];

+            }

+            else

+            {

+               png_fixed_point g, gs;

+

+               switch (png_ptr->background_gamma_type)

+               {

+                  case PNG_BACKGROUND_GAMMA_SCREEN:

+                     g = (png_ptr->screen_gamma);

+                     gs = PNG_FP_1;

+                     break;

+

+                  case PNG_BACKGROUND_GAMMA_FILE:

+                     g = png_reciprocal(png_ptr->colorspace.gamma);

+                     gs = png_reciprocal2(png_ptr->colorspace.gamma,

+                        png_ptr->screen_gamma);

+                     break;

+

+                  case PNG_BACKGROUND_GAMMA_UNIQUE:

+                     g = png_reciprocal(png_ptr->background_gamma);

+                     gs = png_reciprocal2(png_ptr->background_gamma,

+                        png_ptr->screen_gamma);

+                     break;

+                  default:

+                     g = PNG_FP_1;    /* back_1 */

+                     gs = PNG_FP_1;   /* back */

+                     break;

+               }

+

+               if (png_gamma_significant(gs))

+               {

+                  back.red = png_gamma_8bit_correct(png_ptr->background.red,

+                      gs);

+                  back.green = png_gamma_8bit_correct(png_ptr->background.green,

+                      gs);

+                  back.blue = png_gamma_8bit_correct(png_ptr->background.blue,

+                      gs);

+               }

+

+               else

+               {

+                  back.red   = (png_byte)png_ptr->background.red;

+                  back.green = (png_byte)png_ptr->background.green;

+                  back.blue  = (png_byte)png_ptr->background.blue;

+               }

+

+               if (png_gamma_significant(g))

+               {

+                  back_1.red = png_gamma_8bit_correct(png_ptr->background.red,

+                     g);

+                  back_1.green = png_gamma_8bit_correct(

+                     png_ptr->background.green, g);

+                  back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue,

+                     g);

+               }

+

+               else

+               {

+                  back_1.red   = (png_byte)png_ptr->background.red;

+                  back_1.green = (png_byte)png_ptr->background.green;

+                  back_1.blue  = (png_byte)png_ptr->background.blue;

+               }

+            }

+

+            for (i = 0; i < num_palette; i++)

+            {

+               if (i < (int)png_ptr->num_trans &&

+                   png_ptr->trans_alpha[i] != 0xff)

+               {

+                  if (png_ptr->trans_alpha[i] == 0)

+                  {

+                     palette[i] = back;

+                  }

+                  else /* if (png_ptr->trans_alpha[i] != 0xff) */

+                  {

+                     png_byte v, w;

+

+                     v = png_ptr->gamma_to_1[palette[i].red];

+                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);

+                     palette[i].red = png_ptr->gamma_from_1[w];

+

+                     v = png_ptr->gamma_to_1[palette[i].green];

+                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);

+                     palette[i].green = png_ptr->gamma_from_1[w];

+

+                     v = png_ptr->gamma_to_1[palette[i].blue];

+                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);

+                     palette[i].blue = png_ptr->gamma_from_1[w];

+                  }

+               }

+               else

+               {

+                  palette[i].red = png_ptr->gamma_table[palette[i].red];

+                  palette[i].green = png_ptr->gamma_table[palette[i].green];

+                  palette[i].blue = png_ptr->gamma_table[palette[i].blue];

+               }

+            }

+

+            /* Prevent the transformations being done again.

+             *

+             * NOTE: this is highly dubious; it removes the transformations in

+             * place.  This seems inconsistent with the general treatment of the

+             * transformations elsewhere.

+             */

+            png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA);

+         } /* color_type == PNG_COLOR_TYPE_PALETTE */

+

+         /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */

+         else /* color_type != PNG_COLOR_TYPE_PALETTE */

+         {

+            int gs_sig, g_sig;

+            png_fixed_point g = PNG_FP_1;  /* Correction to linear */

+            png_fixed_point gs = PNG_FP_1; /* Correction to screen */

+

+            switch (png_ptr->background_gamma_type)

+            {

+               case PNG_BACKGROUND_GAMMA_SCREEN:

+                  g = png_ptr->screen_gamma;

+                  /* gs = PNG_FP_1; */

+                  break;

+

+               case PNG_BACKGROUND_GAMMA_FILE:

+                  g = png_reciprocal(png_ptr->colorspace.gamma);

+                  gs = png_reciprocal2(png_ptr->colorspace.gamma,

+                     png_ptr->screen_gamma);

+                  break;

+

+               case PNG_BACKGROUND_GAMMA_UNIQUE:

+                  g = png_reciprocal(png_ptr->background_gamma);

+                  gs = png_reciprocal2(png_ptr->background_gamma,

+                      png_ptr->screen_gamma);

+                  break;

+

+               default:

+                  png_error(png_ptr, "invalid background gamma type");

+            }

+

+            g_sig = png_gamma_significant(g);

+            gs_sig = png_gamma_significant(gs);

+

+            if (g_sig)

+               png_ptr->background_1.gray = png_gamma_correct(png_ptr,

+                   png_ptr->background.gray, g);

+

+            if (gs_sig)

+               png_ptr->background.gray = png_gamma_correct(png_ptr,

+                   png_ptr->background.gray, gs);

+

+            if ((png_ptr->background.red != png_ptr->background.green) ||

+                (png_ptr->background.red != png_ptr->background.blue) ||

+                (png_ptr->background.red != png_ptr->background.gray))

+            {

+               /* RGB or RGBA with color background */

+               if (g_sig)

+               {

+                  png_ptr->background_1.red = png_gamma_correct(png_ptr,

+                      png_ptr->background.red, g);

+

+                  png_ptr->background_1.green = png_gamma_correct(png_ptr,

+                      png_ptr->background.green, g);

+

+                  png_ptr->background_1.blue = png_gamma_correct(png_ptr,

+                      png_ptr->background.blue, g);

+               }

+

+               if (gs_sig)

+               {

+                  png_ptr->background.red = png_gamma_correct(png_ptr,

+                      png_ptr->background.red, gs);

+

+                  png_ptr->background.green = png_gamma_correct(png_ptr,

+                      png_ptr->background.green, gs);

+

+                  png_ptr->background.blue = png_gamma_correct(png_ptr,

+                      png_ptr->background.blue, gs);

+               }

+            }

+

+            else

+            {

+               /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */

+               png_ptr->background_1.red = png_ptr->background_1.green

+                   = png_ptr->background_1.blue = png_ptr->background_1.gray;

+

+               png_ptr->background.red = png_ptr->background.green

+                   = png_ptr->background.blue = png_ptr->background.gray;

+            }

+

+            /* The background is now in screen gamma: */

+            png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN;

+         } /* color_type != PNG_COLOR_TYPE_PALETTE */

+      }/* png_ptr->transformations & PNG_BACKGROUND */

+

+      else

+      /* Transformation does not include PNG_BACKGROUND */

+#endif /* PNG_READ_BACKGROUND_SUPPORTED */

+      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+         /* RGB_TO_GRAY needs to have non-gamma-corrected values! */

+         && ((png_ptr->transformations & PNG_EXPAND) == 0 ||

+         (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)

+#endif

+         )

+      {

+         png_colorp palette = png_ptr->palette;

+         int num_palette = png_ptr->num_palette;

+         int i;

+

+         /* NOTE: there are other transformations that should probably be in

+          * here too.

+          */

+         for (i = 0; i < num_palette; i++)

+         {

+            palette[i].red = png_ptr->gamma_table[palette[i].red];

+            palette[i].green = png_ptr->gamma_table[palette[i].green];

+            palette[i].blue = png_ptr->gamma_table[palette[i].blue];

+         }

+

+         /* Done the gamma correction. */

+         png_ptr->transformations &= ~PNG_GAMMA;

+      } /* color_type == PALETTE && !PNG_BACKGROUND transformation */

+   }

+#ifdef PNG_READ_BACKGROUND_SUPPORTED

+   else

+#endif

+#endif /* PNG_READ_GAMMA_SUPPORTED */

+

+#ifdef PNG_READ_BACKGROUND_SUPPORTED

+   /* No GAMMA transformation (see the hanging else 4 lines above) */

+   if ((png_ptr->transformations & PNG_COMPOSE) &&

+       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))

+   {

+      int i;

+      int istop = (int)png_ptr->num_trans;

+      png_color back;

+      png_colorp palette = png_ptr->palette;

+

+      back.red   = (png_byte)png_ptr->background.red;

+      back.green = (png_byte)png_ptr->background.green;

+      back.blue  = (png_byte)png_ptr->background.blue;

+

+      for (i = 0; i < istop; i++)

+      {

+         if (png_ptr->trans_alpha[i] == 0)

+         {

+            palette[i] = back;

+         }

+

+         else if (png_ptr->trans_alpha[i] != 0xff)

+         {

+            /* The png_composite() macro is defined in png.h */

+            png_composite(palette[i].red, palette[i].red,

+                png_ptr->trans_alpha[i], back.red);

+

+            png_composite(palette[i].green, palette[i].green,

+                png_ptr->trans_alpha[i], back.green);

+

+            png_composite(palette[i].blue, palette[i].blue,

+                png_ptr->trans_alpha[i], back.blue);

+         }

+      }

+

+      png_ptr->transformations &= ~PNG_COMPOSE;

+	  

+  	  //png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; /* Add by Sunliang.Liu */

+   }

+#endif /* PNG_READ_BACKGROUND_SUPPORTED */

+

+#ifdef PNG_READ_SHIFT_SUPPORTED

+   if ((png_ptr->transformations & PNG_SHIFT) &&

+      !(png_ptr->transformations & PNG_EXPAND) &&

+       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))

+   {

+      int i;

+      int istop = png_ptr->num_palette;

+      int shift = 8 - png_ptr->sig_bit.red;

+

+      png_ptr->transformations &= ~PNG_SHIFT;

+

+      /* significant bits can be in the range 1 to 7 for a meaninful result, if

+       * the number of significant bits is 0 then no shift is done (this is an

+       * error condition which is silently ignored.)

+       */

+      if (shift > 0 && shift < 8) for (i=0; i<istop; ++i)

+      {

+         int component = png_ptr->palette[i].red;

+

+         component >>= shift;

+         png_ptr->palette[i].red = (png_byte)component;

+      }

+

+      shift = 8 - png_ptr->sig_bit.green;

+      if (shift > 0 && shift < 8) for (i=0; i<istop; ++i)

+      {

+         int component = png_ptr->palette[i].green;

+

+         component >>= shift;

+         png_ptr->palette[i].green = (png_byte)component;

+      }

+

+      shift = 8 - png_ptr->sig_bit.blue;

+      if (shift > 0 && shift < 8) for (i=0; i<istop; ++i)

+      {

+         int component = png_ptr->palette[i].blue;

+

+         component >>= shift;

+         png_ptr->palette[i].blue = (png_byte)component;

+      }

+   }

+#endif  /* PNG_READ_SHIFT_SUPPORTED */

+}

+

+/* Modify the info structure to reflect the transformations.  The

+ * info should be updated so a PNG file could be written with it,

+ * assuming the transformations result in valid PNG data.

+ */

+void /* PRIVATE */

+png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)

+{

+   png_debug(1, "in png_read_transform_info");

+

+#ifdef PNG_READ_EXPAND_SUPPORTED

+   if (png_ptr->transformations & PNG_EXPAND)

+   {

+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      {

+         /* This check must match what actually happens in

+          * png_do_expand_palette; if it ever checks the tRNS chunk to see if

+          * it is all opaque we must do the same (at present it does not.)

+          */

+         if (png_ptr->num_trans > 0)

+            info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;

+

+         else

+            info_ptr->color_type = PNG_COLOR_TYPE_RGB;

+

+         info_ptr->bit_depth = 8;

+         info_ptr->num_trans = 0;

+      }

+      else

+      {

+         if (png_ptr->num_trans)

+         {

+            if (png_ptr->transformations & PNG_EXPAND_tRNS)

+               info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;

+         }

+         if (info_ptr->bit_depth < 8)

+            info_ptr->bit_depth = 8;

+

+         info_ptr->num_trans = 0;

+      }

+   }

+#endif

+

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)

+   /* The following is almost certainly wrong unless the background value is in

+    * the screen space!

+    */

+   if (png_ptr->transformations & PNG_COMPOSE)

+      info_ptr->background = png_ptr->background;

+#endif

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+   /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4),

+    * however it seems that the code in png_init_read_transformations, which has

+    * been called before this from png_read_update_info->png_read_start_row

+    * sometimes does the gamma transform and cancels the flag.

+    *

+    * TODO: this looks wrong; the info_ptr should end up with a gamma equal to

+    * the screen_gamma value.  The following probably results in weirdness if

+    * the info_ptr is used by the app after the rows have been read.

+    */

+   info_ptr->colorspace.gamma = png_ptr->colorspace.gamma;

+#endif

+

+   if (info_ptr->bit_depth == 16)

+   {

+#  ifdef PNG_READ_16BIT_SUPPORTED

+#     ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED

+         if (png_ptr->transformations & PNG_SCALE_16_TO_8)

+            info_ptr->bit_depth = 8;

+#     endif

+

+#     ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED

+         if (png_ptr->transformations & PNG_16_TO_8)

+            info_ptr->bit_depth = 8;

+#     endif

+

+#  else

+      /* No 16 bit support: force chopping 16-bit input down to 8, in this case

+       * the app program can chose if both APIs are available by setting the

+       * correct scaling to use.

+       */

+#     ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED

+         /* For compatibility with previous versions use the strip method by

+          * default.  This code works because if PNG_SCALE_16_TO_8 is already

+          * set the code below will do that in preference to the chop.

+          */

+         png_ptr->transformations |= PNG_16_TO_8;

+         info_ptr->bit_depth = 8;

+#     else

+

+#        ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED

+            png_ptr->transformations |= PNG_SCALE_16_TO_8;

+            info_ptr->bit_depth = 8;

+#        else

+

+            CONFIGURATION ERROR: you must enable at least one 16 to 8 method

+#        endif

+#    endif

+#endif /* !READ_16BIT_SUPPORTED */

+   }

+

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+   if (png_ptr->transformations & PNG_GRAY_TO_RGB)

+      info_ptr->color_type = (png_byte)(info_ptr->color_type |

+         PNG_COLOR_MASK_COLOR);

+#endif

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+   if (png_ptr->transformations & PNG_RGB_TO_GRAY)

+      info_ptr->color_type = (png_byte)(info_ptr->color_type &

+         ~PNG_COLOR_MASK_COLOR);

+#endif

+

+#ifdef PNG_READ_QUANTIZE_SUPPORTED

+   if (png_ptr->transformations & PNG_QUANTIZE)

+   {

+      if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||

+          (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&

+          png_ptr->palette_lookup && info_ptr->bit_depth == 8)

+      {

+         info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;

+      }

+   }

+#endif

+

+#ifdef PNG_READ_EXPAND_16_SUPPORTED

+   if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 &&

+      info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)

+   {

+      info_ptr->bit_depth = 16;

+   }

+#endif

+

+#ifdef PNG_READ_PACK_SUPPORTED

+   if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))

+      info_ptr->bit_depth = 8;

+#endif

+

+   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      info_ptr->channels = 1;

+

+   else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)

+      info_ptr->channels = 3;

+

+   else

+      info_ptr->channels = 1;

+

+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED

+   if (png_ptr->transformations & PNG_STRIP_ALPHA)

+   {

+      info_ptr->color_type = (png_byte)(info_ptr->color_type &

+         ~PNG_COLOR_MASK_ALPHA);

+      info_ptr->num_trans = 0;

+   }

+#endif

+

+   if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)

+      info_ptr->channels++;

+

+#ifdef PNG_READ_FILLER_SUPPORTED

+   /* STRIP_ALPHA and FILLER allowed:  MASK_ALPHA bit stripped above */

+   if ((png_ptr->transformations & PNG_FILLER) &&

+       ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||

+       (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))

+   {

+      info_ptr->channels++;

+      /* If adding a true alpha channel not just filler */

+      if (png_ptr->transformations & PNG_ADD_ALPHA)

+         info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;

+   }

+#endif

+

+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \

+defined(PNG_READ_USER_TRANSFORM_SUPPORTED)

+   if (png_ptr->transformations & PNG_USER_TRANSFORM)

+   {

+      if (info_ptr->bit_depth < png_ptr->user_transform_depth)

+         info_ptr->bit_depth = png_ptr->user_transform_depth;

+

+      if (info_ptr->channels < png_ptr->user_transform_channels)

+         info_ptr->channels = png_ptr->user_transform_channels;

+   }

+#endif

+

+   info_ptr->pixel_depth = (png_byte)(info_ptr->channels *

+       info_ptr->bit_depth);

+

+   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);

+

+   /* Adding in 1.5.4: cache the above value in png_struct so that we can later

+    * check in png_rowbytes that the user buffer won't get overwritten.  Note

+    * that the field is not always set - if png_read_update_info isn't called

+    * the application has to either not do any transforms or get the calculation

+    * right itself.

+    */

+   png_ptr->info_rowbytes = info_ptr->rowbytes;

+

+#ifndef PNG_READ_EXPAND_SUPPORTED

+   if (png_ptr)

+      return;

+#endif

+}

+

+/* Transform the row.  The order of transformations is significant,

+ * and is very touchy.  If you add a transformation, take care to

+ * decide how it fits in with the other transformations here.

+ */

+void /* PRIVATE */

+png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)

+{

+   png_debug(1, "in png_do_read_transformations");

+

+   if (png_ptr->row_buf == NULL)

+   {

+      /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this

+       * error is incredibly rare and incredibly easy to debug without this

+       * information.

+       */

+      png_error(png_ptr, "NULL row buffer");

+   }

+

+   /* The following is debugging; prior to 1.5.4 the code was never compiled in;

+    * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro

+    * PNG_WARN_UNINITIALIZED_ROW removed.  In 1.6 the new flag is set only for

+    * all transformations, however in practice the ROW_INIT always gets done on

+    * demand, if necessary.

+    */

+   if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 &&

+      !(png_ptr->flags & PNG_FLAG_ROW_INIT))

+   {

+      /* Application has failed to call either png_read_start_image() or

+       * png_read_update_info() after setting transforms that expand pixels.

+       * This check added to libpng-1.2.19 (but not enabled until 1.5.4).

+       */

+      png_error(png_ptr, "Uninitialized row");

+   }

+

+#ifdef PNG_READ_EXPAND_SUPPORTED

+   if (png_ptr->transformations & PNG_EXPAND)

+   {

+      if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)

+      {

+         png_do_expand_palette(row_info, png_ptr->row_buf + 1,

+             png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);

+      }

+

+      else

+      {

+         if (png_ptr->num_trans &&

+             (png_ptr->transformations & PNG_EXPAND_tRNS))

+            png_do_expand(row_info, png_ptr->row_buf + 1,

+                &(png_ptr->trans_color));

+

+         else

+            png_do_expand(row_info, png_ptr->row_buf + 1,

+                NULL);

+      }

+   }

+#endif

+

+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED

+   if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&

+      !(png_ptr->transformations & PNG_COMPOSE) &&

+      (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||

+      row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))

+      png_do_strip_channel(row_info, png_ptr->row_buf + 1,

+         0 /* at_start == false, because SWAP_ALPHA happens later */);

+#endif

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+   if (png_ptr->transformations & PNG_RGB_TO_GRAY)

+   {

+      int rgb_error =

+          png_do_rgb_to_gray(png_ptr, row_info,

+              png_ptr->row_buf + 1);

+

+      if (rgb_error)

+      {

+         png_ptr->rgb_to_gray_status=1;

+         if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==

+             PNG_RGB_TO_GRAY_WARN)

+            png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");

+

+         if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==

+             PNG_RGB_TO_GRAY_ERR)

+            png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");

+      }

+   }

+#endif

+

+/* From Andreas Dilger e-mail to png-implement, 26 March 1998:

+ *

+ *   In most cases, the "simple transparency" should be done prior to doing

+ *   gray-to-RGB, or you will have to test 3x as many bytes to check if a

+ *   pixel is transparent.  You would also need to make sure that the

+ *   transparency information is upgraded to RGB.

+ *

+ *   To summarize, the current flow is:

+ *   - Gray + simple transparency -> compare 1 or 2 gray bytes and composite

+ *                                   with background "in place" if transparent,

+ *                                   convert to RGB if necessary

+ *   - Gray + alpha -> composite with gray background and remove alpha bytes,

+ *                                   convert to RGB if necessary

+ *

+ *   To support RGB backgrounds for gray images we need:

+ *   - Gray + simple transparency -> convert to RGB + simple transparency,

+ *                                   compare 3 or 6 bytes and composite with

+ *                                   background "in place" if transparent

+ *                                   (3x compare/pixel compared to doing

+ *                                   composite with gray bkgrnd)

+ *   - Gray + alpha -> convert to RGB + alpha, composite with background and

+ *                                   remove alpha bytes (3x float

+ *                                   operations/pixel compared with composite

+ *                                   on gray background)

+ *

+ *  Greg's change will do this.  The reason it wasn't done before is for

+ *  performance, as this increases the per-pixel operations.  If we would check

+ *  in advance if the background was gray or RGB, and position the gray-to-RGB

+ *  transform appropriately, then it would save a lot of work/time.

+ */

+

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+   /* If gray -> RGB, do so now only if background is non-gray; else do later

+    * for performance reasons

+    */

+   if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&

+       !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))

+      png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);

+#endif

+

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)

+   if (png_ptr->transformations & PNG_COMPOSE)

+      png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr);

+#endif

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+   if ((png_ptr->transformations & PNG_GAMMA) &&

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+      /* Because RGB_TO_GRAY does the gamma transform. */

+      !(png_ptr->transformations & PNG_RGB_TO_GRAY) &&

+#endif

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)

+      /* Because PNG_COMPOSE does the gamma transform if there is something to

+       * do (if there is an alpha channel or transparency.)

+       */

+       !((png_ptr->transformations & PNG_COMPOSE) &&

+       ((png_ptr->num_trans != 0) ||

+       (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&

+#endif

+      /* Because png_init_read_transformations transforms the palette, unless

+       * RGB_TO_GRAY will do the transform.

+       */

+       (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))

+      png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr);

+#endif

+

+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED

+   if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&

+      (png_ptr->transformations & PNG_COMPOSE) &&

+      (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||

+      row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))

+      png_do_strip_channel(row_info, png_ptr->row_buf + 1,

+         0 /* at_start == false, because SWAP_ALPHA happens later */);

+#endif

+

+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED

+   if ((png_ptr->transformations & PNG_ENCODE_ALPHA) &&

+      (row_info->color_type & PNG_COLOR_MASK_ALPHA))

+      png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr);

+#endif

+

+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED

+   if (png_ptr->transformations & PNG_SCALE_16_TO_8)

+      png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED

+   /* There is no harm in doing both of these because only one has any effect,

+    * by putting the 'scale' option first if the app asks for scale (either by

+    * calling the API or in a TRANSFORM flag) this is what happens.

+    */

+   if (png_ptr->transformations & PNG_16_TO_8)

+      png_do_chop(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_QUANTIZE_SUPPORTED

+   if (png_ptr->transformations & PNG_QUANTIZE)

+   {

+      png_do_quantize(row_info, png_ptr->row_buf + 1,

+          png_ptr->palette_lookup, png_ptr->quantize_index);

+

+      if (row_info->rowbytes == 0)

+         png_error(png_ptr, "png_do_quantize returned rowbytes=0");

+   }

+#endif /* PNG_READ_QUANTIZE_SUPPORTED */

+

+#ifdef PNG_READ_EXPAND_16_SUPPORTED

+   /* Do the expansion now, after all the arithmetic has been done.  Notice

+    * that previous transformations can handle the PNG_EXPAND_16 flag if this

+    * is efficient (particularly true in the case of gamma correction, where

+    * better accuracy results faster!)

+    */

+   if (png_ptr->transformations & PNG_EXPAND_16)

+      png_do_expand_16(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+   /* NOTE: moved here in 1.5.4 (from much later in this list.) */

+   if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&

+       (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))

+      png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_INVERT_SUPPORTED

+   if (png_ptr->transformations & PNG_INVERT_MONO)

+      png_do_invert(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_SHIFT_SUPPORTED

+   if (png_ptr->transformations & PNG_SHIFT)

+      png_do_unshift(row_info, png_ptr->row_buf + 1,

+          &(png_ptr->shift));

+#endif

+

+#ifdef PNG_READ_PACK_SUPPORTED

+   if (png_ptr->transformations & PNG_PACK)

+      png_do_unpack(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED

+   /* Added at libpng-1.5.10 */

+   if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&

+       png_ptr->num_palette_max >= 0)

+      png_do_check_palette_indexes(png_ptr, row_info);

+#endif

+

+#ifdef PNG_READ_BGR_SUPPORTED

+   if (png_ptr->transformations & PNG_BGR)

+      png_do_bgr(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_PACKSWAP_SUPPORTED

+   if (png_ptr->transformations & PNG_PACKSWAP)

+      png_do_packswap(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_FILLER_SUPPORTED

+   if (png_ptr->transformations & PNG_FILLER)

+      png_do_read_filler(row_info, png_ptr->row_buf + 1,

+          (png_uint_32)png_ptr->filler, png_ptr->flags);

+#endif

+

+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED

+   if (png_ptr->transformations & PNG_INVERT_ALPHA)

+      png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED

+   if (png_ptr->transformations & PNG_SWAP_ALPHA)

+      png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+#ifdef PNG_READ_SWAP_SUPPORTED

+   if (png_ptr->transformations & PNG_SWAP_BYTES)

+      png_do_swap(row_info, png_ptr->row_buf + 1);

+#endif

+#endif

+

+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED

+   if (png_ptr->transformations & PNG_USER_TRANSFORM)

+    {

+      if (png_ptr->read_user_transform_fn != NULL)

+         (*(png_ptr->read_user_transform_fn)) /* User read transform function */

+             (png_ptr,     /* png_ptr */

+             row_info,     /* row_info: */

+                /*  png_uint_32 width;       width of row */

+                /*  png_size_t rowbytes;     number of bytes in row */

+                /*  png_byte color_type;     color type of pixels */

+                /*  png_byte bit_depth;      bit depth of samples */

+                /*  png_byte channels;       number of channels (1-4) */

+                /*  png_byte pixel_depth;    bits per pixel (depth*channels) */

+             png_ptr->row_buf + 1);    /* start of pixel data for row */

+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED

+      if (png_ptr->user_transform_depth)

+         row_info->bit_depth = png_ptr->user_transform_depth;

+

+      if (png_ptr->user_transform_channels)

+         row_info->channels = png_ptr->user_transform_channels;

+#endif

+      row_info->pixel_depth = (png_byte)(row_info->bit_depth *

+          row_info->channels);

+

+      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width);

+   }

+#endif

+}

+

+#ifdef PNG_READ_PACK_SUPPORTED

+/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,

+ * without changing the actual values.  Thus, if you had a row with

+ * a bit depth of 1, you would end up with bytes that only contained

+ * the numbers 0 or 1.  If you would rather they contain 0 and 255, use

+ * png_do_shift() after this.

+ */

+void /* PRIVATE */

+png_do_unpack(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_unpack");

+

+   if (row_info->bit_depth < 8)

+   {

+      png_uint_32 i;

+      png_uint_32 row_width=row_info->width;

+

+      switch (row_info->bit_depth)

+      {

+         case 1:

+         {

+            png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);

+            png_bytep dp = row + (png_size_t)row_width - 1;

+            png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);

+            for (i = 0; i < row_width; i++)

+            {

+               *dp = (png_byte)((*sp >> shift) & 0x01);

+

+               if (shift == 7)

+               {

+                  shift = 0;

+                  sp--;

+               }

+

+               else

+                  shift++;

+

+               dp--;

+            }

+            break;

+         }

+

+         case 2:

+         {

+

+            png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);

+            png_bytep dp = row + (png_size_t)row_width - 1;

+            png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);

+            for (i = 0; i < row_width; i++)

+            {

+               *dp = (png_byte)((*sp >> shift) & 0x03);

+

+               if (shift == 6)

+               {

+                  shift = 0;

+                  sp--;

+               }

+

+               else

+                  shift += 2;

+

+               dp--;

+            }

+            break;

+         }

+

+         case 4:

+         {

+            png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);

+            png_bytep dp = row + (png_size_t)row_width - 1;

+            png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);

+            for (i = 0; i < row_width; i++)

+            {

+               *dp = (png_byte)((*sp >> shift) & 0x0f);

+

+               if (shift == 4)

+               {

+                  shift = 0;

+                  sp--;

+               }

+

+               else

+                  shift = 4;

+

+               dp--;

+            }

+            break;

+         }

+

+         default:

+            break;

+      }

+      row_info->bit_depth = 8;

+      row_info->pixel_depth = (png_byte)(8 * row_info->channels);

+      row_info->rowbytes = row_width * row_info->channels;

+   }

+}

+#endif

+

+#ifdef PNG_READ_SHIFT_SUPPORTED

+/* Reverse the effects of png_do_shift.  This routine merely shifts the

+ * pixels back to their significant bits values.  Thus, if you have

+ * a row of bit depth 8, but only 5 are significant, this will shift

+ * the values back to 0 through 31.

+ */

+void /* PRIVATE */

+png_do_unshift(png_row_infop row_info, png_bytep row,

+    png_const_color_8p sig_bits)

+{

+   int color_type;

+

+   png_debug(1, "in png_do_unshift");

+

+   /* The palette case has already been handled in the _init routine. */

+   color_type = row_info->color_type;

+

+   if (color_type != PNG_COLOR_TYPE_PALETTE)

+   {

+      int shift[4];

+      int channels = 0;

+      int bit_depth = row_info->bit_depth;

+

+      if (color_type & PNG_COLOR_MASK_COLOR)

+      {

+         shift[channels++] = bit_depth - sig_bits->red;

+         shift[channels++] = bit_depth - sig_bits->green;

+         shift[channels++] = bit_depth - sig_bits->blue;

+      }

+

+      else

+      {

+         shift[channels++] = bit_depth - sig_bits->gray;

+      }

+

+      if (color_type & PNG_COLOR_MASK_ALPHA)

+      {

+         shift[channels++] = bit_depth - sig_bits->alpha;

+      }

+

+      {

+         int c, have_shift;

+

+         for (c = have_shift = 0; c < channels; ++c)

+         {

+            /* A shift of more than the bit depth is an error condition but it

+             * gets ignored here.

+             */

+            if (shift[c] <= 0 || shift[c] >= bit_depth)

+               shift[c] = 0;

+

+            else

+               have_shift = 1;

+         }

+

+         if (!have_shift)

+            return;

+      }

+

+      switch (bit_depth)

+      {

+         default:

+         /* Must be 1bpp gray: should not be here! */

+            /* NOTREACHED */

+            break;

+

+         case 2:

+         /* Must be 2bpp gray */

+         /* assert(channels == 1 && shift[0] == 1) */

+         {

+            png_bytep bp = row;

+            png_bytep bp_end = bp + row_info->rowbytes;

+

+            while (bp < bp_end)

+            {

+               int b = (*bp >> 1) & 0x55;

+               *bp++ = (png_byte)b;

+            }

+            break;

+         }

+

+         case 4:

+         /* Must be 4bpp gray */

+         /* assert(channels == 1) */

+         {

+            png_bytep bp = row;

+            png_bytep bp_end = bp + row_info->rowbytes;

+            int gray_shift = shift[0];

+            int mask =  0xf >> gray_shift;

+

+            mask |= mask << 4;

+

+            while (bp < bp_end)

+            {

+               int b = (*bp >> gray_shift) & mask;

+               *bp++ = (png_byte)b;

+            }

+            break;

+         }

+

+         case 8:

+         /* Single byte components, G, GA, RGB, RGBA */

+         {

+            png_bytep bp = row;

+            png_bytep bp_end = bp + row_info->rowbytes;

+            int channel = 0;

+

+            while (bp < bp_end)

+            {

+               int b = *bp >> shift[channel];

+               if (++channel >= channels)

+                  channel = 0;

+               *bp++ = (png_byte)b;

+            }

+            break;

+         }

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+         case 16:

+         /* Double byte components, G, GA, RGB, RGBA */

+         {

+            png_bytep bp = row;

+            png_bytep bp_end = bp + row_info->rowbytes;

+            int channel = 0;

+

+            while (bp < bp_end)

+            {

+               int value = (bp[0] << 8) + bp[1];

+

+               value >>= shift[channel];

+               if (++channel >= channels)

+                  channel = 0;

+               *bp++ = (png_byte)(value >> 8);

+               *bp++ = (png_byte)(value & 0xff);

+            }

+            break;

+         }

+#endif

+      }

+   }

+}

+#endif

+

+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED

+/* Scale rows of bit depth 16 down to 8 accurately */

+void /* PRIVATE */

+png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_scale_16_to_8");

+

+   if (row_info->bit_depth == 16)

+   {

+      png_bytep sp = row; /* source */

+      png_bytep dp = row; /* destination */

+      png_bytep ep = sp + row_info->rowbytes; /* end+1 */

+

+      while (sp < ep)

+      {

+         /* The input is an array of 16 bit components, these must be scaled to

+          * 8 bits each.  For a 16 bit value V the required value (from the PNG

+          * specification) is:

+          *

+          *    (V * 255) / 65535

+          *

+          * This reduces to round(V / 257), or floor((V + 128.5)/257)

+          *

+          * Represent V as the two byte value vhi.vlo.  Make a guess that the

+          * result is the top byte of V, vhi, then the correction to this value

+          * is:

+          *

+          *    error = floor(((V-vhi.vhi) + 128.5) / 257)

+          *          = floor(((vlo-vhi) + 128.5) / 257)

+          *

+          * This can be approximated using integer arithmetic (and a signed

+          * shift):

+          *

+          *    error = (vlo-vhi+128) >> 8;

+          *

+          * The approximate differs from the exact answer only when (vlo-vhi) is

+          * 128; it then gives a correction of +1 when the exact correction is

+          * 0.  This gives 128 errors.  The exact answer (correct for all 16 bit

+          * input values) is:

+          *

+          *    error = (vlo-vhi+128)*65535 >> 24;

+          *

+          * An alternative arithmetic calculation which also gives no errors is:

+          *

+          *    (V * 255 + 32895) >> 16

+          */

+

+         png_int_32 tmp = *sp++; /* must be signed! */

+         tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24;

+         *dp++ = (png_byte)tmp;

+      }

+

+      row_info->bit_depth = 8;

+      row_info->pixel_depth = (png_byte)(8 * row_info->channels);

+      row_info->rowbytes = row_info->width * row_info->channels;

+   }

+}

+#endif

+

+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED

+void /* PRIVATE */

+/* Simply discard the low byte.  This was the default behavior prior

+ * to libpng-1.5.4.

+ */

+png_do_chop(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_chop");

+

+   if (row_info->bit_depth == 16)

+   {

+      png_bytep sp = row; /* source */

+      png_bytep dp = row; /* destination */

+      png_bytep ep = sp + row_info->rowbytes; /* end+1 */

+

+      while (sp < ep)

+      {

+         *dp++ = *sp;

+         sp += 2; /* skip low byte */

+      }

+

+      row_info->bit_depth = 8;

+      row_info->pixel_depth = (png_byte)(8 * row_info->channels);

+      row_info->rowbytes = row_info->width * row_info->channels;

+   }

+}

+#endif

+

+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED

+void /* PRIVATE */

+png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_read_swap_alpha");

+

+   {

+      png_uint_32 row_width = row_info->width;

+      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+      {

+         /* This converts from RGBA to ARGB */

+         if (row_info->bit_depth == 8)

+         {

+            png_bytep sp = row + row_info->rowbytes;

+            png_bytep dp = sp;

+            png_byte save;

+            png_uint_32 i;

+

+            for (i = 0; i < row_width; i++)

+            {

+               save = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = save;

+            }

+         }

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+         /* This converts from RRGGBBAA to AARRGGBB */

+         else

+         {

+            png_bytep sp = row + row_info->rowbytes;

+            png_bytep dp = sp;

+            png_byte save[2];

+            png_uint_32 i;

+

+            for (i = 0; i < row_width; i++)

+            {

+               save[0] = *(--sp);

+               save[1] = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = save[0];

+               *(--dp) = save[1];

+            }

+         }

+#endif

+      }

+

+      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

+      {

+         /* This converts from GA to AG */

+         if (row_info->bit_depth == 8)

+         {

+            png_bytep sp = row + row_info->rowbytes;

+            png_bytep dp = sp;

+            png_byte save;

+            png_uint_32 i;

+

+            for (i = 0; i < row_width; i++)

+            {

+               save = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = save;

+            }

+         }

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+         /* This converts from GGAA to AAGG */

+         else

+         {

+            png_bytep sp = row + row_info->rowbytes;

+            png_bytep dp = sp;

+            png_byte save[2];

+            png_uint_32 i;

+

+            for (i = 0; i < row_width; i++)

+            {

+               save[0] = *(--sp);

+               save[1] = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = save[0];

+               *(--dp) = save[1];

+            }

+         }

+#endif

+      }

+   }

+}

+#endif

+

+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED

+void /* PRIVATE */

+png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)

+{

+   png_uint_32 row_width;

+   png_debug(1, "in png_do_read_invert_alpha");

+

+   row_width = row_info->width;

+   if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+   {

+      if (row_info->bit_depth == 8)

+      {

+         /* This inverts the alpha channel in RGBA */

+         png_bytep sp = row + row_info->rowbytes;

+         png_bytep dp = sp;

+         png_uint_32 i;

+

+         for (i = 0; i < row_width; i++)

+         {

+            *(--dp) = (png_byte)(255 - *(--sp));

+

+/*          This does nothing:

+            *(--dp) = *(--sp);

+            *(--dp) = *(--sp);

+            *(--dp) = *(--sp);

+            We can replace it with:

+*/

+            sp-=3;

+            dp=sp;

+         }

+      }

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+      /* This inverts the alpha channel in RRGGBBAA */

+      else

+      {

+         png_bytep sp = row + row_info->rowbytes;

+         png_bytep dp = sp;

+         png_uint_32 i;

+

+         for (i = 0; i < row_width; i++)

+         {

+            *(--dp) = (png_byte)(255 - *(--sp));

+            *(--dp) = (png_byte)(255 - *(--sp));

+

+/*          This does nothing:

+            *(--dp) = *(--sp);

+            *(--dp) = *(--sp);

+            *(--dp) = *(--sp);

+            *(--dp) = *(--sp);

+            *(--dp) = *(--sp);

+            *(--dp) = *(--sp);

+            We can replace it with:

+*/

+            sp-=6;

+            dp=sp;

+         }

+      }

+#endif

+   }

+   else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

+   {

+      if (row_info->bit_depth == 8)

+      {

+         /* This inverts the alpha channel in GA */

+         png_bytep sp = row + row_info->rowbytes;

+         png_bytep dp = sp;

+         png_uint_32 i;

+

+         for (i = 0; i < row_width; i++)

+         {

+            *(--dp) = (png_byte)(255 - *(--sp));

+            *(--dp) = *(--sp);

+         }

+      }

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+      else

+      {

+         /* This inverts the alpha channel in GGAA */

+         png_bytep sp  = row + row_info->rowbytes;

+         png_bytep dp = sp;

+         png_uint_32 i;

+

+         for (i = 0; i < row_width; i++)

+         {

+            *(--dp) = (png_byte)(255 - *(--sp));

+            *(--dp) = (png_byte)(255 - *(--sp));

+/*

+            *(--dp) = *(--sp);

+            *(--dp) = *(--sp);

+*/

+            sp-=2;

+            dp=sp;

+         }

+      }

+#endif

+   }

+}

+#endif

+

+#ifdef PNG_READ_FILLER_SUPPORTED

+/* Add filler channel if we have RGB color */

+void /* PRIVATE */

+png_do_read_filler(png_row_infop row_info, png_bytep row,

+    png_uint_32 filler, png_uint_32 flags)

+{

+   png_uint_32 i;

+   png_uint_32 row_width = row_info->width;

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+   png_byte hi_filler = (png_byte)((filler>>8) & 0xff);

+#endif

+   png_byte lo_filler = (png_byte)(filler & 0xff);

+

+   png_debug(1, "in png_do_read_filler");

+

+   if (

+       row_info->color_type == PNG_COLOR_TYPE_GRAY)

+   {

+      if (row_info->bit_depth == 8)

+      {

+         if (flags & PNG_FLAG_FILLER_AFTER)

+         {

+            /* This changes the data from G to GX */

+            png_bytep sp = row + (png_size_t)row_width;

+            png_bytep dp =  sp + (png_size_t)row_width;

+            for (i = 1; i < row_width; i++)

+            {

+               *(--dp) = lo_filler;

+               *(--dp) = *(--sp);

+            }

+            *(--dp) = lo_filler;

+            row_info->channels = 2;

+            row_info->pixel_depth = 16;

+            row_info->rowbytes = row_width * 2;

+         }

+

+         else

+         {

+            /* This changes the data from G to XG */

+            png_bytep sp = row + (png_size_t)row_width;

+            png_bytep dp = sp  + (png_size_t)row_width;

+            for (i = 0; i < row_width; i++)

+            {

+               *(--dp) = *(--sp);

+               *(--dp) = lo_filler;

+            }

+            row_info->channels = 2;

+            row_info->pixel_depth = 16;

+            row_info->rowbytes = row_width * 2;

+         }

+      }

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+      else if (row_info->bit_depth == 16)

+      {

+         if (flags & PNG_FLAG_FILLER_AFTER)

+         {

+            /* This changes the data from GG to GGXX */

+            png_bytep sp = row + (png_size_t)row_width * 2;

+            png_bytep dp = sp  + (png_size_t)row_width * 2;

+            for (i = 1; i < row_width; i++)

+            {

+               *(--dp) = hi_filler;

+               *(--dp) = lo_filler;

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+            }

+            *(--dp) = hi_filler;

+            *(--dp) = lo_filler;

+            row_info->channels = 2;

+            row_info->pixel_depth = 32;

+            row_info->rowbytes = row_width * 4;

+         }

+

+         else

+         {

+            /* This changes the data from GG to XXGG */

+            png_bytep sp = row + (png_size_t)row_width * 2;

+            png_bytep dp = sp  + (png_size_t)row_width * 2;

+            for (i = 0; i < row_width; i++)

+            {

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = hi_filler;

+               *(--dp) = lo_filler;

+            }

+            row_info->channels = 2;

+            row_info->pixel_depth = 32;

+            row_info->rowbytes = row_width * 4;

+         }

+      }

+#endif

+   } /* COLOR_TYPE == GRAY */

+   else if (row_info->color_type == PNG_COLOR_TYPE_RGB)

+   {

+      if (row_info->bit_depth == 8)

+      {

+         if (flags & PNG_FLAG_FILLER_AFTER)

+         {

+            /* This changes the data from RGB to RGBX */

+            png_bytep sp = row + (png_size_t)row_width * 3;

+            png_bytep dp = sp  + (png_size_t)row_width;

+            for (i = 1; i < row_width; i++)

+            {

+               *(--dp) = lo_filler;

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+            }

+            *(--dp) = lo_filler;

+            row_info->channels = 4;

+            row_info->pixel_depth = 32;

+            row_info->rowbytes = row_width * 4;

+         }

+

+         else

+         {

+            /* This changes the data from RGB to XRGB */

+            png_bytep sp = row + (png_size_t)row_width * 3;

+            png_bytep dp = sp + (png_size_t)row_width;

+            for (i = 0; i < row_width; i++)

+            {

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = lo_filler;

+            }

+            row_info->channels = 4;

+            row_info->pixel_depth = 32;

+            row_info->rowbytes = row_width * 4;

+         }

+      }

+

+#ifdef PNG_READ_16BIT_SUPPORTED

+      else if (row_info->bit_depth == 16)

+      {

+         if (flags & PNG_FLAG_FILLER_AFTER)

+         {

+            /* This changes the data from RRGGBB to RRGGBBXX */

+            png_bytep sp = row + (png_size_t)row_width * 6;

+            png_bytep dp = sp  + (png_size_t)row_width * 2;

+            for (i = 1; i < row_width; i++)

+            {

+               *(--dp) = hi_filler;

+               *(--dp) = lo_filler;

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+            }

+            *(--dp) = hi_filler;

+            *(--dp) = lo_filler;

+            row_info->channels = 4;

+            row_info->pixel_depth = 64;

+            row_info->rowbytes = row_width * 8;

+         }

+

+         else

+         {

+            /* This changes the data from RRGGBB to XXRRGGBB */

+            png_bytep sp = row + (png_size_t)row_width * 6;

+            png_bytep dp = sp  + (png_size_t)row_width * 2;

+            for (i = 0; i < row_width; i++)

+            {

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = *(--sp);

+               *(--dp) = hi_filler;

+               *(--dp) = lo_filler;

+            }

+

+            row_info->channels = 4;

+            row_info->pixel_depth = 64;

+            row_info->rowbytes = row_width * 8;

+         }

+      }

+#endif

+   } /* COLOR_TYPE == RGB */

+}

+#endif

+

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+/* Expand grayscale files to RGB, with or without alpha */

+void /* PRIVATE */

+png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)

+{

+   png_uint_32 i;

+   png_uint_32 row_width = row_info->width;

+

+   png_debug(1, "in png_do_gray_to_rgb");

+

+   if (row_info->bit_depth >= 8 &&

+       !(row_info->color_type & PNG_COLOR_MASK_COLOR))

+   {

+      if (row_info->color_type == PNG_COLOR_TYPE_GRAY)

+      {

+         if (row_info->bit_depth == 8)

+         {

+            /* This changes G to RGB */

+            png_bytep sp = row + (png_size_t)row_width - 1;

+            png_bytep dp = sp  + (png_size_t)row_width * 2;

+            for (i = 0; i < row_width; i++)

+            {

+               *(dp--) = *sp;

+               *(dp--) = *sp;

+               *(dp--) = *(sp--);

+            }

+         }

+

+         else

+         {

+            /* This changes GG to RRGGBB */

+            png_bytep sp = row + (png_size_t)row_width * 2 - 1;

+            png_bytep dp = sp  + (png_size_t)row_width * 4;

+            for (i = 0; i < row_width; i++)

+            {

+               *(dp--) = *sp;

+               *(dp--) = *(sp - 1);

+               *(dp--) = *sp;

+               *(dp--) = *(sp - 1);

+               *(dp--) = *(sp--);

+               *(dp--) = *(sp--);

+            }

+         }

+      }

+

+      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

+      {

+         if (row_info->bit_depth == 8)

+         {

+            /* This changes GA to RGBA */

+            png_bytep sp = row + (png_size_t)row_width * 2 - 1;

+            png_bytep dp = sp  + (png_size_t)row_width * 2;

+            for (i = 0; i < row_width; i++)

+            {

+               *(dp--) = *(sp--);

+               *(dp--) = *sp;

+               *(dp--) = *sp;

+               *(dp--) = *(sp--);

+            }

+         }

+

+         else

+         {

+            /* This changes GGAA to RRGGBBAA */

+            png_bytep sp = row + (png_size_t)row_width * 4 - 1;

+            png_bytep dp = sp  + (png_size_t)row_width * 4;

+            for (i = 0; i < row_width; i++)

+            {

+               *(dp--) = *(sp--);

+               *(dp--) = *(sp--);

+               *(dp--) = *sp;

+               *(dp--) = *(sp - 1);

+               *(dp--) = *sp;

+               *(dp--) = *(sp - 1);

+               *(dp--) = *(sp--);

+               *(dp--) = *(sp--);

+            }

+         }

+      }

+      row_info->channels = (png_byte)(row_info->channels + 2);

+      row_info->color_type |= PNG_COLOR_MASK_COLOR;

+      row_info->pixel_depth = (png_byte)(row_info->channels *

+          row_info->bit_depth);

+      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);

+   }

+}

+#endif

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+/* Reduce RGB files to grayscale, with or without alpha

+ * using the equation given in Poynton's ColorFAQ of 1998-01-04 at

+ * <http://www.inforamp.net/~poynton/>  (THIS LINK IS DEAD June 2008 but

+ * versions dated 1998 through November 2002 have been archived at

+ * http://web.archive.org/web/20000816232553/http://www.inforamp.net/

+ * ~poynton/notes/colour_and_gamma/ColorFAQ.txt )

+ * Charles Poynton poynton at poynton.com

+ *

+ *     Y = 0.212671 * R + 0.715160 * G + 0.072169 * B

+ *

+ *  which can be expressed with integers as

+ *

+ *     Y = (6969 * R + 23434 * G + 2365 * B)/32768

+ *

+ * Poynton's current link (as of January 2003 through July 2011):

+ * <http://www.poynton.com/notes/colour_and_gamma/>

+ * has changed the numbers slightly:

+ *

+ *     Y = 0.2126*R + 0.7152*G + 0.0722*B

+ *

+ *  which can be expressed with integers as

+ *

+ *     Y = (6966 * R + 23436 * G + 2366 * B)/32768

+ *

+ *  Historically, however, libpng uses numbers derived from the ITU-R Rec 709

+ *  end point chromaticities and the D65 white point.  Depending on the

+ *  precision used for the D65 white point this produces a variety of different

+ *  numbers, however if the four decimal place value used in ITU-R Rec 709 is

+ *  used (0.3127,0.3290) the Y calculation would be:

+ *

+ *     Y = (6968 * R + 23435 * G + 2366 * B)/32768

+ *

+ *  While this is correct the rounding results in an overflow for white, because

+ *  the sum of the rounded coefficients is 32769, not 32768.  Consequently

+ *  libpng uses, instead, the closest non-overflowing approximation:

+ *

+ *     Y = (6968 * R + 23434 * G + 2366 * B)/32768

+ *

+ *  Starting with libpng-1.5.5, if the image being converted has a cHRM chunk

+ *  (including an sRGB chunk) then the chromaticities are used to calculate the

+ *  coefficients.  See the chunk handling in pngrutil.c for more information.

+ *

+ *  In all cases the calculation is to be done in a linear colorspace.  If no

+ *  gamma information is available to correct the encoding of the original RGB

+ *  values this results in an implicit assumption that the original PNG RGB

+ *  values were linear.

+ *

+ *  Other integer coefficents can be used via png_set_rgb_to_gray().  Because

+ *  the API takes just red and green coefficients the blue coefficient is

+ *  calculated to make the sum 32768.  This will result in different rounding

+ *  to that used above.

+ */

+int /* PRIVATE */

+png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row)

+

+{

+   int rgb_error = 0;

+

+   png_debug(1, "in png_do_rgb_to_gray");

+

+   if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) &&

+       (row_info->color_type & PNG_COLOR_MASK_COLOR))

+   {

+      PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;

+      PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;

+      PNG_CONST png_uint_32 bc = 32768 - rc - gc;

+      PNG_CONST png_uint_32 row_width = row_info->width;

+      PNG_CONST int have_alpha =

+         (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0;

+

+      if (row_info->bit_depth == 8)

+      {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+         /* Notice that gamma to/from 1 are not necessarily inverses (if

+          * there is an overall gamma correction).  Prior to 1.5.5 this code

+          * checked the linearized values for equality; this doesn't match

+          * the documentation, the original values must be checked.

+          */

+         if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)

+         {

+            png_bytep sp = row;

+            png_bytep dp = row;

+            png_uint_32 i;

+

+            for (i = 0; i < row_width; i++)

+            {

+               png_byte red   = *(sp++);

+               png_byte green = *(sp++);

+               png_byte blue  = *(sp++);

+

+               if (red != green || red != blue)

+               {

+                  red = png_ptr->gamma_to_1[red];

+                  green = png_ptr->gamma_to_1[green];

+                  blue = png_ptr->gamma_to_1[blue];

+

+                  rgb_error |= 1;

+                  *(dp++) = png_ptr->gamma_from_1[

+                      (rc*red + gc*green + bc*blue + 16384)>>15];

+               }

+

+               else

+               {

+                  /* If there is no overall correction the table will not be

+                   * set.

+                   */

+                  if (png_ptr->gamma_table != NULL)

+                     red = png_ptr->gamma_table[red];

+

+                  *(dp++) = red;

+               }

+

+               if (have_alpha)

+                  *(dp++) = *(sp++);

+            }

+         }

+         else

+#endif

+         {

+            png_bytep sp = row;

+            png_bytep dp = row;

+            png_uint_32 i;

+

+            for (i = 0; i < row_width; i++)

+            {

+               png_byte red   = *(sp++);

+               png_byte green = *(sp++);

+               png_byte blue  = *(sp++);

+

+               if (red != green || red != blue)

+               {

+                  rgb_error |= 1;

+                  /* NOTE: this is the historical approach which simply

+                   * truncates the results.

+                   */

+                  *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);

+               }

+

+               else

+                  *(dp++) = red;

+

+               if (have_alpha)

+                  *(dp++) = *(sp++);

+            }

+         }

+      }

+

+      else /* RGB bit_depth == 16 */

+      {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+         if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL)

+         {

+            png_bytep sp = row;

+            png_bytep dp = row;

+            png_uint_32 i;

+

+            for (i = 0; i < row_width; i++)

+            {

+               png_uint_16 red, green, blue, w;

+

+               red   = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;

+               green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;

+               blue  = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;

+

+               if (red == green && red == blue)

+               {

+                  if (png_ptr->gamma_16_table != NULL)

+                     w = png_ptr->gamma_16_table[(red&0xff)

+                         >> png_ptr->gamma_shift][red>>8];

+

+                  else

+                     w = red;

+               }

+

+               else

+               {

+                  png_uint_16 red_1   = png_ptr->gamma_16_to_1[(red&0xff)

+                      >> png_ptr->gamma_shift][red>>8];

+                  png_uint_16 green_1 =

+                      png_ptr->gamma_16_to_1[(green&0xff) >>

+                      png_ptr->gamma_shift][green>>8];

+                  png_uint_16 blue_1  = png_ptr->gamma_16_to_1[(blue&0xff)

+                      >> png_ptr->gamma_shift][blue>>8];

+                  png_uint_16 gray16  = (png_uint_16)((rc*red_1 + gc*green_1

+                      + bc*blue_1 + 16384)>>15);

+                  w = png_ptr->gamma_16_from_1[(gray16&0xff) >>

+                      png_ptr->gamma_shift][gray16 >> 8];

+                  rgb_error |= 1;

+               }

+

+               *(dp++) = (png_byte)((w>>8) & 0xff);

+               *(dp++) = (png_byte)(w & 0xff);

+

+               if (have_alpha)

+               {

+                  *(dp++) = *(sp++);

+                  *(dp++) = *(sp++);

+               }

+            }

+         }

+         else

+#endif

+         {

+            png_bytep sp = row;

+            png_bytep dp = row;

+            png_uint_32 i;

+

+            for (i = 0; i < row_width; i++)

+            {

+               png_uint_16 red, green, blue, gray16;

+

+               red   = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;

+               green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;

+               blue  = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;

+

+               if (red != green || red != blue)

+                  rgb_error |= 1;

+

+               /* From 1.5.5 in the 16 bit case do the accurate conversion even

+                * in the 'fast' case - this is because this is where the code

+                * ends up when handling linear 16 bit data.

+                */

+               gray16  = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >>

+                  15);

+               *(dp++) = (png_byte)((gray16>>8) & 0xff);

+               *(dp++) = (png_byte)(gray16 & 0xff);

+

+               if (have_alpha)

+               {

+                  *(dp++) = *(sp++);

+                  *(dp++) = *(sp++);

+               }

+            }

+         }

+      }

+

+      row_info->channels = (png_byte)(row_info->channels - 2);

+      row_info->color_type = (png_byte)(row_info->color_type &

+          ~PNG_COLOR_MASK_COLOR);

+      row_info->pixel_depth = (png_byte)(row_info->channels *

+          row_info->bit_depth);

+      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);

+   }

+   return rgb_error;

+}

+#endif

+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */

+

+#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED

+/* Build a grayscale palette.  Palette is assumed to be 1 << bit_depth

+ * large of png_color.  This lets grayscale images be treated as

+ * paletted.  Most useful for gamma correction and simplification

+ * of code.  This API is not used internally.

+ */

+void PNGAPI

+png_build_grayscale_palette(int bit_depth, png_colorp palette)

+{

+   int num_palette;

+   int color_inc;

+   int i;

+   int v;

+

+   png_debug(1, "in png_do_build_grayscale_palette");

+

+   if (palette == NULL)

+      return;

+

+   switch (bit_depth)

+   {

+      case 1:

+         num_palette = 2;

+         color_inc = 0xff;

+         break;

+

+      case 2:

+         num_palette = 4;

+         color_inc = 0x55;

+         break;

+

+      case 4:

+         num_palette = 16;

+         color_inc = 0x11;

+         break;

+

+      case 8:

+         num_palette = 256;

+         color_inc = 1;

+         break;

+

+      default:

+         num_palette = 0;

+         color_inc = 0;

+         break;

+   }

+

+   for (i = 0, v = 0; i < num_palette; i++, v += color_inc)

+   {

+      palette[i].red = (png_byte)v;

+      palette[i].green = (png_byte)v;

+      palette[i].blue = (png_byte)v;

+   }

+}

+#endif

+

+

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)

+/* Replace any alpha or transparency with the supplied background color.

+ * "background" is already in the screen gamma, while "background_1" is

+ * at a gamma of 1.0.  Paletted files have already been taken care of.

+ */

+void /* PRIVATE */

+png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)

+{

+#ifdef PNG_READ_GAMMA_SUPPORTED

+   png_const_bytep gamma_table = png_ptr->gamma_table;

+   png_const_bytep gamma_from_1 = png_ptr->gamma_from_1;

+   png_const_bytep gamma_to_1 = png_ptr->gamma_to_1;

+   png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table;

+   png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1;

+   png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1;

+   int gamma_shift = png_ptr->gamma_shift;

+   int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0;

+#endif

+

+   png_bytep sp;

+   png_uint_32 i;

+   png_uint_32 row_width = row_info->width;

+   int shift;

+

+   png_debug(1, "in png_do_compose");

+

+   {

+      switch (row_info->color_type)

+      {

+         case PNG_COLOR_TYPE_GRAY:

+         {

+            switch (row_info->bit_depth)

+            {

+               case 1:

+               {

+                  sp = row;

+                  shift = 7;

+                  for (i = 0; i < row_width; i++)

+                  {

+                     if ((png_uint_16)((*sp >> shift) & 0x01)

+                        == png_ptr->trans_color.gray)

+                     {

+                        unsigned int tmp = *sp & (0x7f7f >> (7 - shift));

+                        tmp |= png_ptr->background.gray << shift;

+                        *sp = (png_byte)(tmp & 0xff);

+                     }

+

+                     if (!shift)

+                     {

+                        shift = 7;

+                        sp++;

+                     }

+

+                     else

+                        shift--;

+                  }

+                  break;

+               }

+

+               case 2:

+               {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+                  if (gamma_table != NULL)

+                  {

+                     sp = row;

+                     shift = 6;

+                     for (i = 0; i < row_width; i++)

+                     {

+                        if ((png_uint_16)((*sp >> shift) & 0x03)

+                            == png_ptr->trans_color.gray)

+                        {

+                           unsigned int tmp = *sp & (0x3f3f >> (6 - shift));

+                           tmp |= png_ptr->background.gray << shift;

+                           *sp = (png_byte)(tmp & 0xff);

+                        }

+

+                        else

+                        {

+                           unsigned int p = (*sp >> shift) & 0x03;

+                           unsigned int g = (gamma_table [p | (p << 2) |

+                               (p << 4) | (p << 6)] >> 6) & 0x03;

+                           unsigned int tmp = *sp & (0x3f3f >> (6 - shift));

+                           tmp |= g << shift;

+                           *sp = (png_byte)(tmp & 0xff);

+                        }

+

+                        if (!shift)

+                        {

+                           shift = 6;

+                           sp++;

+                        }

+

+                        else

+                           shift -= 2;

+                     }

+                  }

+

+                  else

+#endif

+                  {

+                     sp = row;

+                     shift = 6;

+                     for (i = 0; i < row_width; i++)

+                     {

+                        if ((png_uint_16)((*sp >> shift) & 0x03)

+                            == png_ptr->trans_color.gray)

+                        {

+                           unsigned int tmp = *sp & (0x3f3f >> (6 - shift));

+                           tmp |= png_ptr->background.gray << shift;

+                           *sp = (png_byte)(tmp & 0xff);

+                        }

+

+                        if (!shift)

+                        {

+                           shift = 6;

+                           sp++;

+                        }

+

+                        else

+                           shift -= 2;

+                     }

+                  }

+                  break;

+               }

+

+               case 4:

+               {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+                  if (gamma_table != NULL)

+                  {

+                     sp = row;

+                     shift = 4;

+                     for (i = 0; i < row_width; i++)

+                     {

+                        if ((png_uint_16)((*sp >> shift) & 0x0f)

+                            == png_ptr->trans_color.gray)

+                        {

+                           unsigned int tmp = *sp & (0xf0f >> (4 - shift));

+                           tmp |= png_ptr->background.gray << shift;

+                           *sp = (png_byte)(tmp & 0xff);

+                        }

+

+                        else

+                        {

+                           unsigned int p = (*sp >> shift) & 0x0f;

+                           unsigned int g = (gamma_table[p | (p << 4)] >> 4) &

+                              0x0f;

+                           unsigned int tmp = *sp & (0xf0f >> (4 - shift));

+                           tmp |= g << shift;

+                           *sp = (png_byte)(tmp & 0xff);

+                        }

+

+                        if (!shift)

+                        {

+                           shift = 4;

+                           sp++;

+                        }

+

+                        else

+                           shift -= 4;

+                     }

+                  }

+

+                  else

+#endif

+                  {

+                     sp = row;

+                     shift = 4;

+                     for (i = 0; i < row_width; i++)

+                     {

+                        if ((png_uint_16)((*sp >> shift) & 0x0f)

+                            == png_ptr->trans_color.gray)

+                        {

+                           unsigned int tmp = *sp & (0xf0f >> (4 - shift));

+                           tmp |= png_ptr->background.gray << shift;

+                           *sp = (png_byte)(tmp & 0xff);

+                        }

+

+                        if (!shift)

+                        {

+                           shift = 4;

+                           sp++;

+                        }

+

+                        else

+                           shift -= 4;

+                     }

+                  }

+                  break;

+               }

+

+               case 8:

+               {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+                  if (gamma_table != NULL)

+                  {

+                     sp = row;

+                     for (i = 0; i < row_width; i++, sp++)

+                     {

+                        if (*sp == png_ptr->trans_color.gray)

+                           *sp = (png_byte)png_ptr->background.gray;

+

+                        else

+                           *sp = gamma_table[*sp];

+                     }

+                  }

+                  else

+#endif

+                  {

+                     sp = row;

+                     for (i = 0; i < row_width; i++, sp++)

+                     {

+                        if (*sp == png_ptr->trans_color.gray)

+                           *sp = (png_byte)png_ptr->background.gray;

+                     }

+                  }

+                  break;

+               }

+

+               case 16:

+               {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+                  if (gamma_16 != NULL)

+                  {

+                     sp = row;

+                     for (i = 0; i < row_width; i++, sp += 2)

+                     {

+                        png_uint_16 v;

+

+                        v = (png_uint_16)(((*sp) << 8) + *(sp + 1));

+

+                        if (v == png_ptr->trans_color.gray)

+                        {

+                           /* Background is already in screen gamma */

+                           *sp = (png_byte)((png_ptr->background.gray >> 8)

+                                & 0xff);

+                           *(sp + 1) = (png_byte)(png_ptr->background.gray

+                                & 0xff);

+                        }

+

+                        else

+                        {

+                           v = gamma_16[*(sp + 1) >> gamma_shift][*sp];

+                           *sp = (png_byte)((v >> 8) & 0xff);

+                           *(sp + 1) = (png_byte)(v & 0xff);

+                        }

+                     }

+                  }

+                  else

+#endif

+                  {

+                     sp = row;

+                     for (i = 0; i < row_width; i++, sp += 2)

+                     {

+                        png_uint_16 v;

+

+                        v = (png_uint_16)(((*sp) << 8) + *(sp + 1));

+

+                        if (v == png_ptr->trans_color.gray)

+                        {

+                           *sp = (png_byte)((png_ptr->background.gray >> 8)

+                                & 0xff);

+                           *(sp + 1) = (png_byte)(png_ptr->background.gray

+                                & 0xff);

+                        }

+                     }

+                  }

+                  break;

+               }

+

+               default:

+                  break;

+            }

+            break;

+         }

+

+         case PNG_COLOR_TYPE_RGB:

+         {

+            if (row_info->bit_depth == 8)

+            {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+               if (gamma_table != NULL)

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 3)

+                  {

+                     if (*sp == png_ptr->trans_color.red &&

+                         *(sp + 1) == png_ptr->trans_color.green &&

+                         *(sp + 2) == png_ptr->trans_color.blue)

+                     {

+                        *sp = (png_byte)png_ptr->background.red;

+                        *(sp + 1) = (png_byte)png_ptr->background.green;

+                        *(sp + 2) = (png_byte)png_ptr->background.blue;

+                     }

+

+                     else

+                     {

+                        *sp = gamma_table[*sp];

+                        *(sp + 1) = gamma_table[*(sp + 1)];

+                        *(sp + 2) = gamma_table[*(sp + 2)];

+                     }

+                  }

+               }

+               else

+#endif

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 3)

+                  {

+                     if (*sp == png_ptr->trans_color.red &&

+                         *(sp + 1) == png_ptr->trans_color.green &&

+                         *(sp + 2) == png_ptr->trans_color.blue)

+                     {

+                        *sp = (png_byte)png_ptr->background.red;

+                        *(sp + 1) = (png_byte)png_ptr->background.green;

+                        *(sp + 2) = (png_byte)png_ptr->background.blue;

+                     }

+                  }

+               }

+            }

+            else /* if (row_info->bit_depth == 16) */

+            {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+               if (gamma_16 != NULL)

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 6)

+                  {

+                     png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));

+

+                     png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)

+                         + *(sp + 3));

+

+                     png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)

+                         + *(sp + 5));

+

+                     if (r == png_ptr->trans_color.red &&

+                         g == png_ptr->trans_color.green &&

+                         b == png_ptr->trans_color.blue)

+                     {

+                        /* Background is already in screen gamma */

+                        *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);

+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)

+                                & 0xff);

+                        *(sp + 3) = (png_byte)(png_ptr->background.green

+                                & 0xff);

+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)

+                                & 0xff);

+                        *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);

+                     }

+

+                     else

+                     {

+                        png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];

+                        *sp = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(v & 0xff);

+

+                        v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];

+                        *(sp + 2) = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 3) = (png_byte)(v & 0xff);

+

+                        v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];

+                        *(sp + 4) = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 5) = (png_byte)(v & 0xff);

+                     }

+                  }

+               }

+

+               else

+#endif

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 6)

+                  {

+                     png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));

+

+                     png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)

+                         + *(sp + 3));

+

+                     png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)

+                         + *(sp + 5));

+

+                     if (r == png_ptr->trans_color.red &&

+                         g == png_ptr->trans_color.green &&

+                         b == png_ptr->trans_color.blue)

+                     {

+                        *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);

+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)

+                                & 0xff);

+                        *(sp + 3) = (png_byte)(png_ptr->background.green

+                                & 0xff);

+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)

+                                & 0xff);

+                        *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);

+                     }

+                  }

+               }

+            }

+            break;

+         }

+

+         case PNG_COLOR_TYPE_GRAY_ALPHA:

+         {

+            if (row_info->bit_depth == 8)

+            {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+               if (gamma_to_1 != NULL && gamma_from_1 != NULL &&

+                   gamma_table != NULL)

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 2)

+                  {

+                     png_uint_16 a = *(sp + 1);

+

+                     if (a == 0xff)

+                        *sp = gamma_table[*sp];

+

+                     else if (a == 0)

+                     {

+                        /* Background is already in screen gamma */

+                        *sp = (png_byte)png_ptr->background.gray;

+                     }

+

+                     else

+                     {

+                        png_byte v, w;

+

+                        v = gamma_to_1[*sp];

+                        png_composite(w, v, a, png_ptr->background_1.gray);

+                        if (!optimize)

+                           w = gamma_from_1[w];

+                        *sp = w;

+                     }

+                  }

+               }

+               else

+#endif

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 2)

+                  {

+                     png_byte a = *(sp + 1);

+

+                     if (a == 0)

+                        *sp = (png_byte)png_ptr->background.gray;

+

+                     else if (a < 0xff)

+                        png_composite(*sp, *sp, a, png_ptr->background.gray);

+                  }

+               }

+            }

+            else /* if (png_ptr->bit_depth == 16) */

+            {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+               if (gamma_16 != NULL && gamma_16_from_1 != NULL &&

+                   gamma_16_to_1 != NULL)

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 4)

+                  {

+                     png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)

+                         + *(sp + 3));

+

+                     if (a == (png_uint_16)0xffff)

+                     {

+                        png_uint_16 v;

+

+                        v = gamma_16[*(sp + 1) >> gamma_shift][*sp];

+                        *sp = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(v & 0xff);

+                     }

+

+                     else if (a == 0)

+                     {

+                        /* Background is already in screen gamma */

+                        *sp = (png_byte)((png_ptr->background.gray >> 8)

+                                & 0xff);

+                        *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);

+                     }

+

+                     else

+                     {

+                        png_uint_16 g, v, w;

+

+                        g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];

+                        png_composite_16(v, g, a, png_ptr->background_1.gray);

+                        if (optimize)

+                           w = v;

+                        else

+                           w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];

+                        *sp = (png_byte)((w >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(w & 0xff);

+                     }

+                  }

+               }

+               else

+#endif

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 4)

+                  {

+                     png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)

+                         + *(sp + 3));

+

+                     if (a == 0)

+                     {

+                        *sp = (png_byte)((png_ptr->background.gray >> 8)

+                                & 0xff);

+                        *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);

+                     }

+

+                     else if (a < 0xffff)

+                     {

+                        png_uint_16 g, v;

+

+                        g = (png_uint_16)(((*sp) << 8) + *(sp + 1));

+                        png_composite_16(v, g, a, png_ptr->background.gray);

+                        *sp = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(v & 0xff);

+                     }

+                  }

+               }

+            }

+            break;

+         }

+

+         case PNG_COLOR_TYPE_RGB_ALPHA:

+         {

+            if (row_info->bit_depth == 8)

+            {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+               if (gamma_to_1 != NULL && gamma_from_1 != NULL &&

+                   gamma_table != NULL)

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 4)

+                  {

+                     png_byte a = *(sp + 3);

+

+                     if (a == 0xff)

+                     {

+                        *sp = gamma_table[*sp];

+                        *(sp + 1) = gamma_table[*(sp + 1)];

+                        *(sp + 2) = gamma_table[*(sp + 2)];

+                     }

+

+                     else if (a == 0)

+                     {

+                        /* Background is already in screen gamma */

+                        *sp = (png_byte)png_ptr->background.red;

+                        *(sp + 1) = (png_byte)png_ptr->background.green;

+                        *(sp + 2) = (png_byte)png_ptr->background.blue;

+                     }

+

+                     else

+                     {

+                        png_byte v, w;

+

+                        v = gamma_to_1[*sp];

+                        png_composite(w, v, a, png_ptr->background_1.red);

+                        if (!optimize) w = gamma_from_1[w];

+                        *sp = w;

+

+                        v = gamma_to_1[*(sp + 1)];

+                        png_composite(w, v, a, png_ptr->background_1.green);

+                        if (!optimize) w = gamma_from_1[w];

+                        *(sp + 1) = w;

+

+                        v = gamma_to_1[*(sp + 2)];

+                        png_composite(w, v, a, png_ptr->background_1.blue);

+                        if (!optimize) w = gamma_from_1[w];

+                        *(sp + 2) = w;

+                     }

+                  }

+               }

+               else

+#endif

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 4)

+                  {

+                     png_byte a = *(sp + 3);

+

+                     if (a == 0)

+                     {

+                        *sp = (png_byte)png_ptr->background.red;

+                        *(sp + 1) = (png_byte)png_ptr->background.green;

+                        *(sp + 2) = (png_byte)png_ptr->background.blue;

+                     }

+

+                     else if (a < 0xff)

+                     {

+                        png_composite(*sp, *sp, a, png_ptr->background.red);

+

+                        png_composite(*(sp + 1), *(sp + 1), a,

+                            png_ptr->background.green);

+

+                        png_composite(*(sp + 2), *(sp + 2), a,

+                            png_ptr->background.blue);

+                     }

+                  }

+               }

+            }

+            else /* if (row_info->bit_depth == 16) */

+            {

+#ifdef PNG_READ_GAMMA_SUPPORTED

+               if (gamma_16 != NULL && gamma_16_from_1 != NULL &&

+                   gamma_16_to_1 != NULL)

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 8)

+                  {

+                     png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))

+                         << 8) + (png_uint_16)(*(sp + 7)));

+

+                     if (a == (png_uint_16)0xffff)

+                     {

+                        png_uint_16 v;

+

+                        v = gamma_16[*(sp + 1) >> gamma_shift][*sp];

+                        *sp = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(v & 0xff);

+

+                        v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];

+                        *(sp + 2) = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 3) = (png_byte)(v & 0xff);

+

+                        v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];

+                        *(sp + 4) = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 5) = (png_byte)(v & 0xff);

+                     }

+

+                     else if (a == 0)

+                     {

+                        /* Background is already in screen gamma */

+                        *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);

+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)

+                                & 0xff);

+                        *(sp + 3) = (png_byte)(png_ptr->background.green

+                                & 0xff);

+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)

+                                & 0xff);

+                        *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);

+                     }

+

+                     else

+                     {

+                        png_uint_16 v, w;

+

+                        v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];

+                        png_composite_16(w, v, a, png_ptr->background_1.red);

+                        if (!optimize)

+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >>

+                                8];

+                        *sp = (png_byte)((w >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(w & 0xff);

+

+                        v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];

+                        png_composite_16(w, v, a, png_ptr->background_1.green);

+                        if (!optimize)

+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >>

+                                8];

+

+                        *(sp + 2) = (png_byte)((w >> 8) & 0xff);

+                        *(sp + 3) = (png_byte)(w & 0xff);

+

+                        v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];

+                        png_composite_16(w, v, a, png_ptr->background_1.blue);

+                        if (!optimize)

+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >>

+                                8];

+

+                        *(sp + 4) = (png_byte)((w >> 8) & 0xff);

+                        *(sp + 5) = (png_byte)(w & 0xff);

+                     }

+                  }

+               }

+

+               else

+#endif

+               {

+                  sp = row;

+                  for (i = 0; i < row_width; i++, sp += 8)

+                  {

+                     png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))

+                         << 8) + (png_uint_16)(*(sp + 7)));

+

+                     if (a == 0)

+                     {

+                        *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);

+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)

+                                & 0xff);

+                        *(sp + 3) = (png_byte)(png_ptr->background.green

+                                & 0xff);

+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)

+                                & 0xff);

+                        *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);

+                     }

+

+                     else if (a < 0xffff)

+                     {

+                        png_uint_16 v;

+

+                        png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));

+                        png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)

+                            + *(sp + 3));

+                        png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)

+                            + *(sp + 5));

+

+                        png_composite_16(v, r, a, png_ptr->background.red);

+                        *sp = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 1) = (png_byte)(v & 0xff);

+

+                        png_composite_16(v, g, a, png_ptr->background.green);

+                        *(sp + 2) = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 3) = (png_byte)(v & 0xff);

+

+                        png_composite_16(v, b, a, png_ptr->background.blue);

+                        *(sp + 4) = (png_byte)((v >> 8) & 0xff);

+                        *(sp + 5) = (png_byte)(v & 0xff);

+                     }

+                  }

+               }

+            }

+            break;

+         }

+

+         default:

+            break;

+      }

+   }

+}

+#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_READ_ALPHA_MODE_SUPPORTED */

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+/* Gamma correct the image, avoiding the alpha channel.  Make sure

+ * you do this after you deal with the transparency issue on grayscale

+ * or RGB images. If your bit depth is 8, use gamma_table, if it

+ * is 16, use gamma_16_table and gamma_shift.  Build these with

+ * build_gamma_table().

+ */

+void /* PRIVATE */

+png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr)

+{

+   png_const_bytep gamma_table = png_ptr->gamma_table;

+   png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table;

+   int gamma_shift = png_ptr->gamma_shift;

+

+   png_bytep sp;

+   png_uint_32 i;

+   png_uint_32 row_width=row_info->width;

+

+   png_debug(1, "in png_do_gamma");

+

+   if (((row_info->bit_depth <= 8 && gamma_table != NULL) ||

+       (row_info->bit_depth == 16 && gamma_16_table != NULL)))

+   {

+      switch (row_info->color_type)

+      {

+         case PNG_COLOR_TYPE_RGB:

+         {

+            if (row_info->bit_depth == 8)

+            {

+               sp = row;

+               for (i = 0; i < row_width; i++)

+               {

+                  *sp = gamma_table[*sp];

+                  sp++;

+                  *sp = gamma_table[*sp];

+                  sp++;

+                  *sp = gamma_table[*sp];

+                  sp++;

+               }

+            }

+

+            else /* if (row_info->bit_depth == 16) */

+            {

+               sp = row;

+               for (i = 0; i < row_width; i++)

+               {

+                  png_uint_16 v;

+

+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];

+                  *sp = (png_byte)((v >> 8) & 0xff);

+                  *(sp + 1) = (png_byte)(v & 0xff);

+                  sp += 2;

+

+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];

+                  *sp = (png_byte)((v >> 8) & 0xff);

+                  *(sp + 1) = (png_byte)(v & 0xff);

+                  sp += 2;

+

+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];

+                  *sp = (png_byte)((v >> 8) & 0xff);

+                  *(sp + 1) = (png_byte)(v & 0xff);

+                  sp += 2;

+               }

+            }

+            break;

+         }

+

+         case PNG_COLOR_TYPE_RGB_ALPHA:

+         {

+            if (row_info->bit_depth == 8)

+            {

+               sp = row;

+               for (i = 0; i < row_width; i++)

+               {

+                  *sp = gamma_table[*sp];

+                  sp++;

+

+                  *sp = gamma_table[*sp];

+                  sp++;

+

+                  *sp = gamma_table[*sp];

+                  sp++;

+

+                  sp++;

+               }

+            }

+

+            else /* if (row_info->bit_depth == 16) */

+            {

+               sp = row;

+               for (i = 0; i < row_width; i++)

+               {

+                  png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];

+                  *sp = (png_byte)((v >> 8) & 0xff);

+                  *(sp + 1) = (png_byte)(v & 0xff);

+                  sp += 2;

+

+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];

+                  *sp = (png_byte)((v >> 8) & 0xff);

+                  *(sp + 1) = (png_byte)(v & 0xff);

+                  sp += 2;

+

+                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];

+                  *sp = (png_byte)((v >> 8) & 0xff);

+                  *(sp + 1) = (png_byte)(v & 0xff);

+                  sp += 4;

+               }

+            }

+            break;

+         }

+

+         case PNG_COLOR_TYPE_GRAY_ALPHA:

+         {

+            if (row_info->bit_depth == 8)

+            {

+               sp = row;

+               for (i = 0; i < row_width; i++)

+               {

+                  *sp = gamma_table[*sp];

+                  sp += 2;

+               }

+            }

+

+            else /* if (row_info->bit_depth == 16) */

+            {

+               sp = row;

+               for (i = 0; i < row_width; i++)

+               {

+                  png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];

+                  *sp = (png_byte)((v >> 8) & 0xff);

+                  *(sp + 1) = (png_byte)(v & 0xff);

+                  sp += 4;

+               }

+            }

+            break;

+         }

+

+         case PNG_COLOR_TYPE_GRAY:

+         {

+            if (row_info->bit_depth == 2)

+            {

+               sp = row;

+               for (i = 0; i < row_width; i += 4)

+               {

+                  int a = *sp & 0xc0;

+                  int b = *sp & 0x30;

+                  int c = *sp & 0x0c;

+                  int d = *sp & 0x03;

+

+                  *sp = (png_byte)(

+                      ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)])   ) & 0xc0)|

+                      ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|

+                      ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|

+                      ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));

+                  sp++;

+               }

+            }

+

+            if (row_info->bit_depth == 4)

+            {

+               sp = row;

+               for (i = 0; i < row_width; i += 2)

+               {

+                  int msb = *sp & 0xf0;

+                  int lsb = *sp & 0x0f;

+

+                  *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)

+                      | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));

+                  sp++;

+               }

+            }

+

+            else if (row_info->bit_depth == 8)

+            {

+               sp = row;

+               for (i = 0; i < row_width; i++)

+               {

+                  *sp = gamma_table[*sp];

+                  sp++;

+               }

+            }

+

+            else if (row_info->bit_depth == 16)

+            {

+               sp = row;

+               for (i = 0; i < row_width; i++)

+               {

+                  png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];

+                  *sp = (png_byte)((v >> 8) & 0xff);

+                  *(sp + 1) = (png_byte)(v & 0xff);

+                  sp += 2;

+               }

+            }

+            break;

+         }

+

+         default:

+            break;

+      }

+   }

+}

+#endif

+

+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED

+/* Encode the alpha channel to the output gamma (the input channel is always

+ * linear.)  Called only with color types that have an alpha channel.  Needs the

+ * from_1 tables.

+ */

+void /* PRIVATE */

+png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr)

+{

+   png_uint_32 row_width = row_info->width;

+

+   png_debug(1, "in png_do_encode_alpha");

+

+   if (row_info->color_type & PNG_COLOR_MASK_ALPHA)

+   {

+      if (row_info->bit_depth == 8)

+      {

+         PNG_CONST png_bytep table = png_ptr->gamma_from_1;

+

+         if (table != NULL)

+         {

+            PNG_CONST int step =

+               (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2;

+

+            /* The alpha channel is the last component: */

+            row += step - 1;

+

+            for (; row_width > 0; --row_width, row += step)

+               *row = table[*row];

+

+            return;

+         }

+      }

+

+      else if (row_info->bit_depth == 16)

+      {

+         PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1;

+         PNG_CONST int gamma_shift = png_ptr->gamma_shift;

+

+         if (table != NULL)

+         {

+            PNG_CONST int step =

+               (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4;

+

+            /* The alpha channel is the last component: */

+            row += step - 2;

+

+            for (; row_width > 0; --row_width, row += step)

+            {

+               png_uint_16 v;

+

+               v = table[*(row + 1) >> gamma_shift][*row];

+               *row = (png_byte)((v >> 8) & 0xff);

+               *(row + 1) = (png_byte)(v & 0xff);

+            }

+

+            return;

+         }

+      }

+   }

+

+   /* Only get to here if called with a weird row_info; no harm has been done,

+    * so just issue a warning.

+    */

+   png_warning(png_ptr, "png_do_encode_alpha: unexpected call");

+}

+#endif

+

+#ifdef PNG_READ_EXPAND_SUPPORTED

+/* Expands a palette row to an RGB or RGBA row depending

+ * upon whether you supply trans and num_trans.

+ */

+void /* PRIVATE */

+png_do_expand_palette(png_row_infop row_info, png_bytep row,

+   png_const_colorp palette, png_const_bytep trans_alpha, int num_trans)

+{

+   int shift, value;

+   png_bytep sp, dp;

+   png_uint_32 i;

+   png_uint_32 row_width=row_info->width;

+

+   png_debug(1, "in png_do_expand_palette");

+

+   if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)

+   {

+      if (row_info->bit_depth < 8)

+      {

+         switch (row_info->bit_depth)

+         {

+            case 1:

+            {

+               sp = row + (png_size_t)((row_width - 1) >> 3);

+               dp = row + (png_size_t)row_width - 1;

+               shift = 7 - (int)((row_width + 7) & 0x07);

+               for (i = 0; i < row_width; i++)

+               {

+                  if ((*sp >> shift) & 0x01)

+                     *dp = 1;

+

+                  else

+                     *dp = 0;

+

+                  if (shift == 7)

+                  {

+                     shift = 0;

+                     sp--;

+                  }

+

+                  else

+                     shift++;

+

+                  dp--;

+               }

+               break;

+            }

+

+            case 2:

+            {

+               sp = row + (png_size_t)((row_width - 1) >> 2);

+               dp = row + (png_size_t)row_width - 1;

+               shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);

+               for (i = 0; i < row_width; i++)

+               {

+                  value = (*sp >> shift) & 0x03;

+                  *dp = (png_byte)value;

+                  if (shift == 6)

+                  {

+                     shift = 0;

+                     sp--;

+                  }

+

+                  else

+                     shift += 2;

+

+                  dp--;

+               }

+               break;

+            }

+

+            case 4:

+            {

+               sp = row + (png_size_t)((row_width - 1) >> 1);

+               dp = row + (png_size_t)row_width - 1;

+               shift = (int)((row_width & 0x01) << 2);

+               for (i = 0; i < row_width; i++)

+               {

+                  value = (*sp >> shift) & 0x0f;

+                  *dp = (png_byte)value;

+                  if (shift == 4)

+                  {

+                     shift = 0;

+                     sp--;

+                  }

+

+                  else

+                     shift += 4;

+

+                  dp--;

+               }

+               break;

+            }

+

+            default:

+               break;

+         }

+         row_info->bit_depth = 8;

+         row_info->pixel_depth = 8;

+         row_info->rowbytes = row_width;

+      }

+

+      if (row_info->bit_depth == 8)

+      {

+         {

+            if (num_trans > 0)

+            {

+               sp = row + (png_size_t)row_width - 1;

+               dp = row + (png_size_t)(row_width << 2) - 1;

+

+               for (i = 0; i < row_width; i++)

+               {

+                  if ((int)(*sp) >= num_trans)

+                     *dp-- = 0xff;

+

+                  else

+                     *dp-- = trans_alpha[*sp];

+

+                  *dp-- = palette[*sp].blue;

+                  *dp-- = palette[*sp].green;

+                  *dp-- = palette[*sp].red;

+                  sp--;

+               }

+               row_info->bit_depth = 8;

+               row_info->pixel_depth = 32;

+               row_info->rowbytes = row_width * 4;

+               row_info->color_type = 6;

+               row_info->channels = 4;

+            }

+

+            else

+            {

+               sp = row + (png_size_t)row_width - 1;

+               dp = row + (png_size_t)(row_width * 3) - 1;

+

+               for (i = 0; i < row_width; i++)

+               {

+                  *dp-- = palette[*sp].blue;

+                  *dp-- = palette[*sp].green;

+                  *dp-- = palette[*sp].red;

+                  sp--;

+               }

+

+               row_info->bit_depth = 8;

+               row_info->pixel_depth = 24;

+               row_info->rowbytes = row_width * 3;

+               row_info->color_type = 2;

+               row_info->channels = 3;

+            }

+         }

+      }

+   }

+}

+

+/* If the bit depth < 8, it is expanded to 8.  Also, if the already

+ * expanded transparency value is supplied, an alpha channel is built.

+ */

+void /* PRIVATE */

+png_do_expand(png_row_infop row_info, png_bytep row,

+    png_const_color_16p trans_color)

+{

+   int shift, value;

+   png_bytep sp, dp;

+   png_uint_32 i;

+   png_uint_32 row_width=row_info->width;

+

+   png_debug(1, "in png_do_expand");

+

+   {

+      if (row_info->color_type == PNG_COLOR_TYPE_GRAY)

+      {

+         unsigned int gray = trans_color ? trans_color->gray : 0;

+

+         if (row_info->bit_depth < 8)

+         {

+            switch (row_info->bit_depth)

+            {

+               case 1:

+               {

+                  gray = (gray & 0x01) * 0xff;

+                  sp = row + (png_size_t)((row_width - 1) >> 3);

+                  dp = row + (png_size_t)row_width - 1;

+                  shift = 7 - (int)((row_width + 7) & 0x07);

+                  for (i = 0; i < row_width; i++)

+                  {

+                     if ((*sp >> shift) & 0x01)

+                        *dp = 0xff;

+

+                     else

+                        *dp = 0;

+

+                     if (shift == 7)

+                     {

+                        shift = 0;

+                        sp--;

+                     }

+

+                     else

+                        shift++;

+

+                     dp--;

+                  }

+                  break;

+               }

+

+               case 2:

+               {

+                  gray = (gray & 0x03) * 0x55;

+                  sp = row + (png_size_t)((row_width - 1) >> 2);

+                  dp = row + (png_size_t)row_width - 1;

+                  shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);

+                  for (i = 0; i < row_width; i++)

+                  {

+                     value = (*sp >> shift) & 0x03;

+                     *dp = (png_byte)(value | (value << 2) | (value << 4) |

+                        (value << 6));

+                     if (shift == 6)

+                     {

+                        shift = 0;

+                        sp--;

+                     }

+

+                     else

+                        shift += 2;

+

+                     dp--;

+                  }

+                  break;

+               }

+

+               case 4:

+               {

+                  gray = (gray & 0x0f) * 0x11;

+                  sp = row + (png_size_t)((row_width - 1) >> 1);

+                  dp = row + (png_size_t)row_width - 1;

+                  shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);

+                  for (i = 0; i < row_width; i++)

+                  {

+                     value = (*sp >> shift) & 0x0f;

+                     *dp = (png_byte)(value | (value << 4));

+                     if (shift == 4)

+                     {

+                        shift = 0;

+                        sp--;

+                     }

+

+                     else

+                        shift = 4;

+

+                     dp--;

+                  }

+                  break;

+               }

+

+               default:

+                  break;

+            }

+

+            row_info->bit_depth = 8;

+            row_info->pixel_depth = 8;

+            row_info->rowbytes = row_width;

+         }

+

+         if (trans_color != NULL)

+         {

+            if (row_info->bit_depth == 8)

+            {

+               gray = gray & 0xff;

+               sp = row + (png_size_t)row_width - 1;

+               dp = row + (png_size_t)(row_width << 1) - 1;

+

+               for (i = 0; i < row_width; i++)

+               {

+                  if (*sp == gray)

+                     *dp-- = 0;

+

+                  else

+                     *dp-- = 0xff;

+

+                  *dp-- = *sp--;

+               }

+            }

+

+            else if (row_info->bit_depth == 16)

+            {

+               unsigned int gray_high = (gray >> 8) & 0xff;

+               unsigned int gray_low = gray & 0xff;

+               sp = row + row_info->rowbytes - 1;

+               dp = row + (row_info->rowbytes << 1) - 1;

+               for (i = 0; i < row_width; i++)

+               {

+                  if (*(sp - 1) == gray_high && *(sp) == gray_low)

+                  {

+                     *dp-- = 0;

+                     *dp-- = 0;

+                  }

+

+                  else

+                  {

+                     *dp-- = 0xff;

+                     *dp-- = 0xff;

+                  }

+

+                  *dp-- = *sp--;

+                  *dp-- = *sp--;

+               }

+            }

+

+            row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;

+            row_info->channels = 2;

+            row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);

+            row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,

+               row_width);

+         }

+      }

+      else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color)

+      {

+         if (row_info->bit_depth == 8)

+         {

+            png_byte red = (png_byte)(trans_color->red & 0xff);

+            png_byte green = (png_byte)(trans_color->green & 0xff);

+            png_byte blue = (png_byte)(trans_color->blue & 0xff);

+            sp = row + (png_size_t)row_info->rowbytes - 1;

+            dp = row + (png_size_t)(row_width << 2) - 1;

+            for (i = 0; i < row_width; i++)

+            {

+               if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)

+                  *dp-- = 0;

+

+               else

+                  *dp-- = 0xff;

+

+               *dp-- = *sp--;

+               *dp-- = *sp--;

+               *dp-- = *sp--;

+            }

+         }

+         else if (row_info->bit_depth == 16)

+         {

+            png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff);

+            png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff);

+            png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff);

+            png_byte red_low = (png_byte)(trans_color->red & 0xff);

+            png_byte green_low = (png_byte)(trans_color->green & 0xff);

+            png_byte blue_low = (png_byte)(trans_color->blue & 0xff);

+            sp = row + row_info->rowbytes - 1;

+            dp = row + (png_size_t)(row_width << 3) - 1;

+            for (i = 0; i < row_width; i++)

+            {

+               if (*(sp - 5) == red_high &&

+                   *(sp - 4) == red_low &&

+                   *(sp - 3) == green_high &&

+                   *(sp - 2) == green_low &&

+                   *(sp - 1) == blue_high &&

+                   *(sp    ) == blue_low)

+               {

+                  *dp-- = 0;

+                  *dp-- = 0;

+               }

+

+               else

+               {

+                  *dp-- = 0xff;

+                  *dp-- = 0xff;

+               }

+

+               *dp-- = *sp--;

+               *dp-- = *sp--;

+               *dp-- = *sp--;

+               *dp-- = *sp--;

+               *dp-- = *sp--;

+               *dp-- = *sp--;

+            }

+         }

+         row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;

+         row_info->channels = 4;

+         row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);

+         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);

+      }

+   }

+}

+#endif

+

+#ifdef PNG_READ_EXPAND_16_SUPPORTED

+/* If the bit depth is 8 and the color type is not a palette type expand the

+ * whole row to 16 bits.  Has no effect otherwise.

+ */

+void /* PRIVATE */

+png_do_expand_16(png_row_infop row_info, png_bytep row)

+{

+   if (row_info->bit_depth == 8 &&

+      row_info->color_type != PNG_COLOR_TYPE_PALETTE)

+   {

+      /* The row have a sequence of bytes containing [0..255] and we need

+       * to turn it into another row containing [0..65535], to do this we

+       * calculate:

+       *

+       *  (input / 255) * 65535

+       *

+       *  Which happens to be exactly input * 257 and this can be achieved

+       *  simply by byte replication in place (copying backwards).

+       */

+      png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */

+      png_byte *dp = sp + row_info->rowbytes;  /* destination, end + 1 */

+      while (dp > sp)

+         dp[-2] = dp[-1] = *--sp, dp -= 2;

+

+      row_info->rowbytes *= 2;

+      row_info->bit_depth = 16;

+      row_info->pixel_depth = (png_byte)(row_info->channels * 16);

+   }

+}

+#endif

+

+#ifdef PNG_READ_QUANTIZE_SUPPORTED

+void /* PRIVATE */

+png_do_quantize(png_row_infop row_info, png_bytep row,

+    png_const_bytep palette_lookup, png_const_bytep quantize_lookup)

+{

+   png_bytep sp, dp;

+   png_uint_32 i;

+   png_uint_32 row_width=row_info->width;

+

+   png_debug(1, "in png_do_quantize");

+

+   if (row_info->bit_depth == 8)

+   {

+      if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup)

+      {

+         int r, g, b, p;

+         sp = row;

+         dp = row;

+         for (i = 0; i < row_width; i++)

+         {

+            r = *sp++;

+            g = *sp++;

+            b = *sp++;

+

+            /* This looks real messy, but the compiler will reduce

+             * it down to a reasonable formula.  For example, with

+             * 5 bits per color, we get:

+             * p = (((r >> 3) & 0x1f) << 10) |

+             *    (((g >> 3) & 0x1f) << 5) |

+             *    ((b >> 3) & 0x1f);

+             */

+            p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &

+                ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<

+                (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |

+                (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &

+                ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<

+                (PNG_QUANTIZE_BLUE_BITS)) |

+                ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &

+                ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));

+

+            *dp++ = palette_lookup[p];

+         }

+

+         row_info->color_type = PNG_COLOR_TYPE_PALETTE;

+         row_info->channels = 1;

+         row_info->pixel_depth = row_info->bit_depth;

+         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);

+      }

+

+      else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&

+         palette_lookup != NULL)

+      {

+         int r, g, b, p;

+         sp = row;

+         dp = row;

+         for (i = 0; i < row_width; i++)

+         {

+            r = *sp++;

+            g = *sp++;

+            b = *sp++;

+            sp++;

+

+            p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &

+                ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<

+                (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |

+                (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &

+                ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<

+                (PNG_QUANTIZE_BLUE_BITS)) |

+                ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &

+                ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));

+

+            *dp++ = palette_lookup[p];

+         }

+

+         row_info->color_type = PNG_COLOR_TYPE_PALETTE;

+         row_info->channels = 1;

+         row_info->pixel_depth = row_info->bit_depth;

+         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);

+      }

+

+      else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&

+         quantize_lookup)

+      {

+         sp = row;

+

+         for (i = 0; i < row_width; i++, sp++)

+         {

+            *sp = quantize_lookup[*sp];

+         }

+      }

+   }

+}

+#endif /* PNG_READ_QUANTIZE_SUPPORTED */

+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */

+

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+/* Undoes intrapixel differencing  */

+void /* PRIVATE */

+png_do_read_intrapixel(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_read_intrapixel");

+

+   if (

+       (row_info->color_type & PNG_COLOR_MASK_COLOR))

+   {

+      int bytes_per_pixel;

+      png_uint_32 row_width = row_info->width;

+

+      if (row_info->bit_depth == 8)

+      {

+         png_bytep rp;

+         png_uint_32 i;

+

+         if (row_info->color_type == PNG_COLOR_TYPE_RGB)

+            bytes_per_pixel = 3;

+

+         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+            bytes_per_pixel = 4;

+

+         else

+            return;

+

+         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)

+         {

+            *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff);

+            *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff);

+         }

+      }

+      else if (row_info->bit_depth == 16)

+      {

+         png_bytep rp;

+         png_uint_32 i;

+

+         if (row_info->color_type == PNG_COLOR_TYPE_RGB)

+            bytes_per_pixel = 6;

+

+         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+            bytes_per_pixel = 8;

+

+         else

+            return;

+

+         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)

+         {

+            png_uint_32 s0   = (*(rp    ) << 8) | *(rp + 1);

+            png_uint_32 s1   = (*(rp + 2) << 8) | *(rp + 3);

+            png_uint_32 s2   = (*(rp + 4) << 8) | *(rp + 5);

+            png_uint_32 red  = (s0 + s1 + 65536) & 0xffff;

+            png_uint_32 blue = (s2 + s1 + 65536) & 0xffff;

+            *(rp    ) = (png_byte)((red >> 8) & 0xff);

+            *(rp + 1) = (png_byte)(red & 0xff);

+            *(rp + 4) = (png_byte)((blue >> 8) & 0xff);

+            *(rp + 5) = (png_byte)(blue & 0xff);

+         }

+      }

+   }

+}

+#endif /* PNG_MNG_FEATURES_SUPPORTED */

+#endif /* PNG_READ_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrutil.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrutil.c
new file mode 100644
index 0000000..d12395a
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrutil.c
@@ -0,0 +1,4473 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngrutil.c - utilities to read a PNG file

+ *

+ * Last changed in libpng 1.6.3 [July 18, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ * This file contains routines that are only called from within

+ * libpng itself during the course of reading an image.

+ */

+

+#include "pngpriv.h"

+

+#ifdef PNG_READ_SUPPORTED

+

+png_uint_32 PNGAPI

+png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)

+{

+   png_uint_32 uval = png_get_uint_32(buf);

+

+   if (uval > PNG_UINT_31_MAX)

+      png_error(png_ptr, "PNG unsigned integer out of range");

+

+   return (uval);

+}

+

+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)

+/* The following is a variation on the above for use with the fixed

+ * point values used for gAMA and cHRM.  Instead of png_error it

+ * issues a warning and returns (-1) - an invalid value because both

+ * gAMA and cHRM use *unsigned* integers for fixed point values.

+ */

+#define PNG_FIXED_ERROR (-1)

+

+static png_fixed_point /* PRIVATE */

+png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf)

+{

+   png_uint_32 uval = png_get_uint_32(buf);

+

+   if (uval <= PNG_UINT_31_MAX)

+      return (png_fixed_point)uval; /* known to be in range */

+

+   /* The caller can turn off the warning by passing NULL. */

+   if (png_ptr != NULL)

+      png_warning(png_ptr, "PNG fixed point integer out of range");

+

+   return PNG_FIXED_ERROR;

+}

+#endif

+

+#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED

+/* NOTE: the read macros will obscure these definitions, so that if

+ * PNG_USE_READ_MACROS is set the library will not use them internally,

+ * but the APIs will still be available externally.

+ *

+ * The parentheses around "PNGAPI function_name" in the following three

+ * functions are necessary because they allow the macros to co-exist with

+ * these (unused but exported) functions.

+ */

+

+/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */

+png_uint_32 (PNGAPI

+png_get_uint_32)(png_const_bytep buf)

+{

+   png_uint_32 uval =

+       ((png_uint_32)(*(buf    )) << 24) +

+       ((png_uint_32)(*(buf + 1)) << 16) +

+       ((png_uint_32)(*(buf + 2)) <<  8) +

+       ((png_uint_32)(*(buf + 3))      ) ;

+

+   return uval;

+}

+

+/* Grab a signed 32-bit integer from a buffer in big-endian format.  The

+ * data is stored in the PNG file in two's complement format and there

+ * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore

+ * the following code does a two's complement to native conversion.

+ */

+png_int_32 (PNGAPI

+png_get_int_32)(png_const_bytep buf)

+{

+   png_uint_32 uval = png_get_uint_32(buf);

+   if ((uval & 0x80000000) == 0) /* non-negative */

+      return uval;

+

+   uval = (uval ^ 0xffffffff) + 1;  /* 2's complement: -x = ~x+1 */

+   return -(png_int_32)uval;

+}

+

+/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */

+png_uint_16 (PNGAPI

+png_get_uint_16)(png_const_bytep buf)

+{

+   /* ANSI-C requires an int value to accomodate at least 16 bits so this

+    * works and allows the compiler not to worry about possible narrowing

+    * on 32 bit systems.  (Pre-ANSI systems did not make integers smaller

+    * than 16 bits either.)

+    */

+   unsigned int val =

+       ((unsigned int)(*buf) << 8) +

+       ((unsigned int)(*(buf + 1)));

+

+   return (png_uint_16)val;

+}

+

+#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */

+

+/* Read and check the PNG file signature */

+void /* PRIVATE */

+png_read_sig(png_structrp png_ptr, png_inforp info_ptr)

+{

+   png_size_t num_checked, num_to_check;

+

+   /* Exit if the user application does not expect a signature. */

+   if (png_ptr->sig_bytes >= 8)

+      return;

+

+   num_checked = png_ptr->sig_bytes;

+   num_to_check = 8 - num_checked;

+

+#ifdef PNG_IO_STATE_SUPPORTED

+   png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE;

+#endif

+

+   /* The signature must be serialized in a single I/O call. */

+   png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);

+   png_ptr->sig_bytes = 8;

+

+   if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))

+   {

+      if (num_checked < 4 &&

+          png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))

+         png_error(png_ptr, "Not a PNG file");

+      else

+         png_error(png_ptr, "PNG file corrupted by ASCII conversion");

+   }

+   if (num_checked < 3)

+      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;

+}

+

+/* Read the chunk header (length + type name).

+ * Put the type name into png_ptr->chunk_name, and return the length.

+ */

+png_uint_32 /* PRIVATE */

+png_read_chunk_header(png_structrp png_ptr)

+{

+   png_byte buf[8];

+   png_uint_32 length;

+

+#ifdef PNG_IO_STATE_SUPPORTED

+   png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;

+#endif

+

+   /* Read the length and the chunk name.

+    * This must be performed in a single I/O call.

+    */

+   png_read_data(png_ptr, buf, 8);

+   length = png_get_uint_31(png_ptr, buf);

+

+   /* Put the chunk name into png_ptr->chunk_name. */

+   png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4);

+

+   png_debug2(0, "Reading %lx chunk, length = %lu",

+       (unsigned long)png_ptr->chunk_name, (unsigned long)length);

+

+   /* Reset the crc and run it over the chunk name. */

+   png_reset_crc(png_ptr);

+   png_calculate_crc(png_ptr, buf + 4, 4);

+

+   /* Check to see if chunk name is valid. */

+   png_check_chunk_name(png_ptr, png_ptr->chunk_name);

+

+#ifdef PNG_IO_STATE_SUPPORTED

+   png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;

+#endif

+

+   return length;

+}

+

+/* Read data, and (optionally) run it through the CRC. */

+void /* PRIVATE */

+png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length)

+{

+   if (png_ptr == NULL)

+      return;

+

+   png_read_data(png_ptr, buf, length);

+   png_calculate_crc(png_ptr, buf, length);

+}

+

+/* Optionally skip data and then check the CRC.  Depending on whether we

+ * are reading an ancillary or critical chunk, and how the program has set

+ * things up, we may calculate the CRC on the data and print a message.

+ * Returns '1' if there was a CRC error, '0' otherwise.

+ */

+int /* PRIVATE */

+png_crc_finish(png_structrp png_ptr, png_uint_32 skip)

+{

+   /* The size of the local buffer for inflate is a good guess as to a

+    * reasonable size to use for buffering reads from the application.

+    */

+   while (skip > 0)

+   {

+      png_uint_32 len;

+      png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];

+

+      len = (sizeof tmpbuf);

+      if (len > skip)

+         len = skip;

+      skip -= len;

+

+      png_crc_read(png_ptr, tmpbuf, len);

+   }

+

+   if (png_crc_error(png_ptr))

+   {

+      if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) ?

+          !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) :

+          (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))

+      {

+         png_chunk_warning(png_ptr, "CRC error");

+      }

+

+      else

+      {

+         png_chunk_benign_error(png_ptr, "CRC error");

+         return (0);

+      }

+

+      return (1);

+   }

+

+   return (0);

+}

+

+/* Compare the CRC stored in the PNG file with that calculated by libpng from

+ * the data it has read thus far.

+ */

+int /* PRIVATE */

+png_crc_error(png_structrp png_ptr)

+{

+   png_byte crc_bytes[4];

+   png_uint_32 crc;

+   int need_crc = 1;

+

+   if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))

+   {

+      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==

+          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))

+         need_crc = 0;

+   }

+

+   else /* critical */

+   {

+      if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)

+         need_crc = 0;

+   }

+

+#ifdef PNG_IO_STATE_SUPPORTED

+   png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;

+#endif

+

+   /* The chunk CRC must be serialized in a single I/O call. */

+   png_read_data(png_ptr, crc_bytes, 4);

+

+   if (need_crc)

+   {

+      crc = png_get_uint_32(crc_bytes);

+      return ((int)(crc != png_ptr->crc));

+   }

+

+   else

+      return (0);

+}

+

+/* Manage the read buffer; this simply reallocates the buffer if it is not small

+ * enough (or if it is not allocated).  The routine returns a pointer to the

+ * buffer; if an error occurs and 'warn' is set the routine returns NULL, else

+ * it will call png_error (via png_malloc) on failure.  (warn == 2 means

+ * 'silent').

+ */

+static png_bytep

+png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)

+{

+   png_bytep buffer = png_ptr->read_buffer;

+

+   if (buffer != NULL && new_size > png_ptr->read_buffer_size)

+   {

+      png_ptr->read_buffer = NULL;

+      png_ptr->read_buffer = NULL;

+      png_ptr->read_buffer_size = 0;

+      png_free(png_ptr, buffer);

+      buffer = NULL;

+   }

+

+   if (buffer == NULL)

+   {

+      buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size));

+

+      if (buffer != NULL)

+      {

+         png_ptr->read_buffer = buffer;

+         png_ptr->read_buffer_size = new_size;

+      }

+

+      else if (warn < 2) /* else silent */

+      {

+#ifdef PNG_WARNINGS_SUPPORTED

+         if (warn)

+             png_chunk_warning(png_ptr, "insufficient memory to read chunk");

+         else

+#endif

+         {

+#ifdef PNG_ERROR_TEXT_SUPPORTED

+             png_chunk_error(png_ptr, "insufficient memory to read chunk");

+#endif

+         }

+      }

+   }

+

+   return buffer;

+}

+

+/* png_inflate_claim: claim the zstream for some nefarious purpose that involves

+ * decompression.  Returns Z_OK on success, else a zlib error code.  It checks

+ * the owner but, in final release builds, just issues a warning if some other

+ * chunk apparently owns the stream.  Prior to release it does a png_error.

+ */

+static int

+png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)

+{

+   if (png_ptr->zowner != 0)

+   {

+      char msg[64];

+

+      PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner);

+      /* So the message that results is "<chunk> using zstream"; this is an

+       * internal error, but is very useful for debugging.  i18n requirements

+       * are minimal.

+       */

+      (void)png_safecat(msg, (sizeof msg), 4, " using zstream");

+#     if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC

+         png_chunk_warning(png_ptr, msg);

+         png_ptr->zowner = 0;

+#     else

+         png_chunk_error(png_ptr, msg);

+#     endif

+   }

+

+   /* Implementation note: unlike 'png_deflate_claim' this internal function

+    * does not take the size of the data as an argument.  Some efficiency could

+    * be gained by using this when it is known *if* the zlib stream itself does

+    * not record the number; however, this is an illusion: the original writer

+    * of the PNG may have selected a lower window size, and we really must

+    * follow that because, for systems with with limited capabilities, we

+    * would otherwise reject the application's attempts to use a smaller window

+    * size (zlib doesn't have an interface to say "this or lower"!).

+    *

+    * inflateReset2 was added to zlib 1.2.4; before this the window could not be

+    * reset, therefore it is necessary to always allocate the maximum window

+    * size with earlier zlibs just in case later compressed chunks need it.

+    */

+   {

+      int ret; /* zlib return code */

+#     if PNG_ZLIB_VERNUM >= 0x1240

+

+#        if defined(PNG_SET_OPTION_SUPPORTED) && \

+            defined(PNG_MAXIMUM_INFLATE_WINDOW)

+            int window_bits;

+

+            if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) ==

+               PNG_OPTION_ON)

+               window_bits = 15;

+

+            else

+               window_bits = 0;

+#        else

+#           define window_bits 0

+#        endif

+#     endif

+

+      /* Set this for safety, just in case the previous owner left pointers to

+       * memory allocations.

+       */

+      png_ptr->zstream.next_in = NULL;

+      png_ptr->zstream.avail_in = 0;

+      png_ptr->zstream.next_out = NULL;

+      png_ptr->zstream.avail_out = 0;

+

+      if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)

+      {

+#        if PNG_ZLIB_VERNUM < 0x1240

+            ret = inflateReset(&png_ptr->zstream);

+#        else

+            ret = inflateReset2(&png_ptr->zstream, window_bits);

+#        endif

+      }

+

+      else

+      {

+#        if PNG_ZLIB_VERNUM < 0x1240

+            ret = inflateInit(&png_ptr->zstream);

+#        else

+            ret = inflateInit2(&png_ptr->zstream, window_bits);

+#        endif

+

+         if (ret == Z_OK)

+            png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;

+      }

+

+      if (ret == Z_OK)

+         png_ptr->zowner = owner;

+

+      else

+         png_zstream_error(png_ptr, ret);

+

+      return ret;

+   }

+

+#  ifdef window_bits

+#     undef window_bits

+#  endif

+}

+

+#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED

+/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to

+ * allow the caller to do multiple calls if required.  If the 'finish' flag is

+ * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must

+ * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and

+ * Z_OK or Z_STREAM_END will be returned on success.

+ *

+ * The input and output sizes are updated to the actual amounts of data consumed

+ * or written, not the amount available (as in a z_stream).  The data pointers

+ * are not changed, so the next input is (data+input_size) and the next

+ * available output is (output+output_size).

+ */

+static int

+png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish,

+    /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr,

+    /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr)

+{

+   if (png_ptr->zowner == owner) /* Else not claimed */

+   {

+      int ret;

+      png_alloc_size_t avail_out = *output_size_ptr;

+      png_uint_32 avail_in = *input_size_ptr;

+

+      /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it

+       * can't even necessarily handle 65536 bytes) because the type uInt is

+       * "16 bits or more".  Consequently it is necessary to chunk the input to

+       * zlib.  This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the

+       * maximum value that can be stored in a uInt.)  It is possible to set

+       * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have

+       * a performance advantage, because it reduces the amount of data accessed

+       * at each step and that may give the OS more time to page it in.

+       */

+      png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);

+      /* avail_in and avail_out are set below from 'size' */

+      png_ptr->zstream.avail_in = 0;

+      png_ptr->zstream.avail_out = 0;

+

+      /* Read directly into the output if it is available (this is set to

+       * a local buffer below if output is NULL).

+       */

+      if (output != NULL)

+         png_ptr->zstream.next_out = output;

+

+      do

+      {

+         uInt avail;

+         Byte local_buffer[PNG_INFLATE_BUF_SIZE];

+

+         /* zlib INPUT BUFFER */

+         /* The setting of 'avail_in' used to be outside the loop; by setting it

+          * inside it is possible to chunk the input to zlib and simply rely on

+          * zlib to advance the 'next_in' pointer.  This allows arbitrary

+          * amounts of data to be passed through zlib at the unavoidable cost of

+          * requiring a window save (memcpy of up to 32768 output bytes)

+          * every ZLIB_IO_MAX input bytes.

+          */

+         avail_in += png_ptr->zstream.avail_in; /* not consumed last time */

+

+         avail = ZLIB_IO_MAX;

+

+         if (avail_in < avail)

+            avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */

+

+         avail_in -= avail;

+         png_ptr->zstream.avail_in = avail;

+

+         /* zlib OUTPUT BUFFER */

+         avail_out += png_ptr->zstream.avail_out; /* not written last time */

+

+         avail = ZLIB_IO_MAX; /* maximum zlib can process */

+

+         if (output == NULL)

+         {

+            /* Reset the output buffer each time round if output is NULL and

+             * make available the full buffer, up to 'remaining_space'

+             */

+            png_ptr->zstream.next_out = local_buffer;

+            if ((sizeof local_buffer) < avail)

+               avail = (sizeof local_buffer);

+         }

+

+         if (avail_out < avail)

+            avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */

+

+         png_ptr->zstream.avail_out = avail;

+         avail_out -= avail;

+

+         /* zlib inflate call */

+         /* In fact 'avail_out' may be 0 at this point, that happens at the end

+          * of the read when the final LZ end code was not passed at the end of

+          * the previous chunk of input data.  Tell zlib if we have reached the

+          * end of the output buffer.

+          */

+         ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH :

+            (finish ? Z_FINISH : Z_SYNC_FLUSH));

+      } while (ret == Z_OK);

+

+      /* For safety kill the local buffer pointer now */

+      if (output == NULL)

+         png_ptr->zstream.next_out = NULL;

+

+      /* Claw back the 'size' and 'remaining_space' byte counts. */

+      avail_in += png_ptr->zstream.avail_in;

+      avail_out += png_ptr->zstream.avail_out;

+

+      /* Update the input and output sizes; the updated values are the amount

+       * consumed or written, effectively the inverse of what zlib uses.

+       */

+      if (avail_out > 0)

+         *output_size_ptr -= avail_out;

+

+      if (avail_in > 0)

+         *input_size_ptr -= avail_in;

+

+      /* Ensure png_ptr->zstream.msg is set (even in the success case!) */

+      png_zstream_error(png_ptr, ret);

+      return ret;

+   }

+

+   else

+   {

+      /* This is a bad internal error.  The recovery assigns to the zstream msg

+       * pointer, which is not owned by the caller, but this is safe; it's only

+       * used on errors!

+       */

+      png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed");

+      return Z_STREAM_ERROR;

+   }

+}

+

+/*

+ * Decompress trailing data in a chunk.  The assumption is that read_buffer

+ * points at an allocated area holding the contents of a chunk with a

+ * trailing compressed part.  What we get back is an allocated area

+ * holding the original prefix part and an uncompressed version of the

+ * trailing part (the malloc area passed in is freed).

+ */

+static int

+png_decompress_chunk(png_structrp png_ptr,

+   png_uint_32 chunklength, png_uint_32 prefix_size,

+   png_alloc_size_t *newlength /* must be initialized to the maximum! */,

+   int terminate /*add a '\0' to the end of the uncompressed data*/)

+{

+   /* TODO: implement different limits for different types of chunk.

+    *

+    * The caller supplies *newlength set to the maximum length of the

+    * uncompressed data, but this routine allocates space for the prefix and

+    * maybe a '\0' terminator too.  We have to assume that 'prefix_size' is

+    * limited only by the maximum chunk size.

+    */

+   png_alloc_size_t limit = PNG_SIZE_MAX;

+

+#  ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED

+      if (png_ptr->user_chunk_malloc_max > 0 &&

+         png_ptr->user_chunk_malloc_max < limit)

+         limit = png_ptr->user_chunk_malloc_max;

+#  elif PNG_USER_CHUNK_MALLOC_MAX > 0

+      if (PNG_USER_CHUNK_MALLOC_MAX < limit)

+         limit = PNG_USER_CHUNK_MALLOC_MAX;

+#  endif

+

+   if (limit >= prefix_size + (terminate != 0))

+   {

+      int ret;

+

+      limit -= prefix_size + (terminate != 0);

+

+      if (limit < *newlength)

+         *newlength = limit;

+

+      /* Now try to claim the stream. */

+      ret = png_inflate_claim(png_ptr, png_ptr->chunk_name);

+

+      if (ret == Z_OK)

+      {

+         png_uint_32 lzsize = chunklength - prefix_size;

+

+         ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,

+            /* input: */ png_ptr->read_buffer + prefix_size, &lzsize,

+            /* output: */ NULL, newlength);

+

+         if (ret == Z_STREAM_END)

+         {

+            /* Use 'inflateReset' here, not 'inflateReset2' because this

+             * preserves the previously decided window size (otherwise it would

+             * be necessary to store the previous window size.)  In practice

+             * this doesn't matter anyway, because png_inflate will call inflate

+             * with Z_FINISH in almost all cases, so the window will not be

+             * maintained.

+             */

+            if (inflateReset(&png_ptr->zstream) == Z_OK)

+            {

+               /* Because of the limit checks above we know that the new,

+                * expanded, size will fit in a size_t (let alone an

+                * png_alloc_size_t).  Use png_malloc_base here to avoid an

+                * extra OOM message.

+                */

+               png_alloc_size_t new_size = *newlength;

+               png_alloc_size_t buffer_size = prefix_size + new_size +

+                  (terminate != 0);

+               png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr,

+                  buffer_size));

+

+               if (text != NULL)

+               {

+                  ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,

+                     png_ptr->read_buffer + prefix_size, &lzsize,

+                     text + prefix_size, newlength);

+

+                  if (ret == Z_STREAM_END)

+                  {

+                     if (new_size == *newlength)

+                     {

+                        if (terminate)

+                           text[prefix_size + *newlength] = 0;

+

+                        if (prefix_size > 0)

+                           memcpy(text, png_ptr->read_buffer, prefix_size);

+

+                        {

+                           png_bytep old_ptr = png_ptr->read_buffer;

+

+                           png_ptr->read_buffer = text;

+                           png_ptr->read_buffer_size = buffer_size;

+                           text = old_ptr; /* freed below */

+                        }

+                     }

+

+                     else

+                     {

+                        /* The size changed on the second read, there can be no

+                         * guarantee that anything is correct at this point.

+                         * The 'msg' pointer has been set to "unexpected end of

+                         * LZ stream", which is fine, but return an error code

+                         * that the caller won't accept.

+                         */

+                        ret = PNG_UNEXPECTED_ZLIB_RETURN;

+                     }

+                  }

+

+                  else if (ret == Z_OK)

+                     ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */

+

+                  /* Free the text pointer (this is the old read_buffer on

+                   * success)

+                   */

+                  png_free(png_ptr, text);

+

+                  /* This really is very benign, but it's still an error because

+                   * the extra space may otherwise be used as a Trojan Horse.

+                   */

+                  if (ret == Z_STREAM_END &&

+                     chunklength - prefix_size != lzsize)

+                     png_chunk_benign_error(png_ptr, "extra compressed data");

+               }

+

+               else

+               {

+                  /* Out of memory allocating the buffer */

+                  ret = Z_MEM_ERROR;

+                  png_zstream_error(png_ptr, Z_MEM_ERROR);

+               }

+            }

+

+            else

+            {

+               /* inflateReset failed, store the error message */

+               png_zstream_error(png_ptr, ret);

+

+               if (ret == Z_STREAM_END)

+                  ret = PNG_UNEXPECTED_ZLIB_RETURN;

+            }

+         }

+

+         else if (ret == Z_OK)

+            ret = PNG_UNEXPECTED_ZLIB_RETURN;

+

+         /* Release the claimed stream */

+         png_ptr->zowner = 0;

+      }

+

+      else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */

+         ret = PNG_UNEXPECTED_ZLIB_RETURN;

+

+      return ret;

+   }

+

+   else

+   {

+      /* Application/configuration limits exceeded */

+      png_zstream_error(png_ptr, Z_MEM_ERROR);

+      return Z_MEM_ERROR;

+   }

+}

+#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */

+

+#ifdef PNG_READ_iCCP_SUPPORTED

+/* Perform a partial read and decompress, producing 'avail_out' bytes and

+ * reading from the current chunk as required.

+ */

+static int

+png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size,

+   png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size,

+   int finish)

+{

+   if (png_ptr->zowner == png_ptr->chunk_name)

+   {

+      int ret;

+

+      /* next_in and avail_in must have been initialized by the caller. */

+      png_ptr->zstream.next_out = next_out;

+      png_ptr->zstream.avail_out = 0; /* set in the loop */

+

+      do

+      {

+         if (png_ptr->zstream.avail_in == 0)

+         {

+            if (read_size > *chunk_bytes)

+               read_size = (uInt)*chunk_bytes;

+            *chunk_bytes -= read_size;

+

+            if (read_size > 0)

+               png_crc_read(png_ptr, read_buffer, read_size);

+

+            png_ptr->zstream.next_in = read_buffer;

+            png_ptr->zstream.avail_in = read_size;

+         }

+

+         if (png_ptr->zstream.avail_out == 0)

+         {

+            uInt avail = ZLIB_IO_MAX;

+            if (avail > *out_size)

+               avail = (uInt)*out_size;

+            *out_size -= avail;

+

+            png_ptr->zstream.avail_out = avail;

+         }

+

+         /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all

+          * the available output is produced; this allows reading of truncated

+          * streams.

+          */

+         ret = inflate(&png_ptr->zstream,

+            *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH));

+      }

+      while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0));

+

+      *out_size += png_ptr->zstream.avail_out;

+      png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */

+

+      /* Ensure the error message pointer is always set: */

+      png_zstream_error(png_ptr, ret);

+      return ret;

+   }

+

+   else

+   {

+      png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed");

+      return Z_STREAM_ERROR;

+   }

+}

+#endif

+

+/* Read and check the IDHR chunk */

+void /* PRIVATE */

+png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_byte buf[13];

+   png_uint_32 width, height;

+   int bit_depth, color_type, compression_type, filter_type;

+   int interlace_type;

+

+   png_debug(1, "in png_handle_IHDR");

+

+   if (png_ptr->mode & PNG_HAVE_IHDR)

+      png_chunk_error(png_ptr, "out of place");

+

+   /* Check the length */

+   if (length != 13)

+      png_chunk_error(png_ptr, "invalid");

+

+   png_ptr->mode |= PNG_HAVE_IHDR;

+

+   png_crc_read(png_ptr, buf, 13);

+   png_crc_finish(png_ptr, 0);

+

+   width = png_get_uint_31(png_ptr, buf);

+   height = png_get_uint_31(png_ptr, buf + 4);

+   bit_depth = buf[8];

+   color_type = buf[9];

+   compression_type = buf[10];

+   filter_type = buf[11];

+   interlace_type = buf[12];

+

+   /* Set internal variables */

+   png_ptr->width = width;

+   png_ptr->height = height;

+   png_ptr->bit_depth = (png_byte)bit_depth;

+   png_ptr->interlaced = (png_byte)interlace_type;

+   png_ptr->color_type = (png_byte)color_type;

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+   png_ptr->filter_type = (png_byte)filter_type;

+#endif

+   png_ptr->compression_type = (png_byte)compression_type;

+

+   /* Find number of channels */

+   switch (png_ptr->color_type)

+   {

+      default: /* invalid, png_set_IHDR calls png_error */

+      case PNG_COLOR_TYPE_GRAY:

+      case PNG_COLOR_TYPE_PALETTE:

+         png_ptr->channels = 1;

+         break;

+

+      case PNG_COLOR_TYPE_RGB:

+         png_ptr->channels = 3;

+         break;

+

+      case PNG_COLOR_TYPE_GRAY_ALPHA:

+         png_ptr->channels = 2;

+         break;

+

+      case PNG_COLOR_TYPE_RGB_ALPHA:

+         png_ptr->channels = 4;

+         break;

+   }

+

+   /* Set up other useful info */

+   png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *

+   png_ptr->channels);

+   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);

+   png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);

+   png_debug1(3, "channels = %d", png_ptr->channels);

+   png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes);

+   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,

+       color_type, interlace_type, compression_type, filter_type);

+}

+

+/* Read and check the palette */

+void /* PRIVATE */

+png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_color palette[PNG_MAX_PALETTE_LENGTH];

+   int num, i;

+#ifdef PNG_POINTER_INDEXING_SUPPORTED

+   png_colorp pal_ptr;

+#endif

+

+   png_debug(1, "in png_handle_PLTE");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   /* Moved to before the 'after IDAT' check below because otherwise duplicate

+    * PLTE chunks are potentially ignored (the spec says there shall not be more

+    * than one PLTE, the error is not treated as benign, so this check trumps

+    * the requirement that PLTE appears before IDAT.)

+    */

+   else if (png_ptr->mode & PNG_HAVE_PLTE)

+      png_chunk_error(png_ptr, "duplicate");

+

+   else if (png_ptr->mode & PNG_HAVE_IDAT)

+   {

+      /* This is benign because the non-benign error happened before, when an

+       * IDAT was encountered in a color-mapped image with no PLTE.

+       */

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   png_ptr->mode |= PNG_HAVE_PLTE;

+

+   if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "ignored in grayscale PNG");

+      return;

+   }

+

+#ifndef PNG_READ_OPT_PLTE_SUPPORTED

+   if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)

+   {

+      png_crc_finish(png_ptr, length);

+      return;

+   }

+#endif

+

+   if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)

+   {

+      png_crc_finish(png_ptr, length);

+

+      if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)

+         png_chunk_benign_error(png_ptr, "invalid");

+

+      else

+         png_chunk_error(png_ptr, "invalid");

+

+      return;

+   }

+

+   /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */

+   num = (int)length / 3;

+

+#ifdef PNG_POINTER_INDEXING_SUPPORTED

+   for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)

+   {

+      png_byte buf[3];

+

+      png_crc_read(png_ptr, buf, 3);

+      pal_ptr->red = buf[0];

+      pal_ptr->green = buf[1];

+      pal_ptr->blue = buf[2];

+   }

+#else

+   for (i = 0; i < num; i++)

+   {

+      png_byte buf[3];

+

+      png_crc_read(png_ptr, buf, 3);

+      /* Don't depend upon png_color being any order */

+      palette[i].red = buf[0];

+      palette[i].green = buf[1];

+      palette[i].blue = buf[2];

+   }

+#endif

+

+   /* If we actually need the PLTE chunk (ie for a paletted image), we do

+    * whatever the normal CRC configuration tells us.  However, if we

+    * have an RGB image, the PLTE can be considered ancillary, so

+    * we will act as though it is.

+    */

+#ifndef PNG_READ_OPT_PLTE_SUPPORTED

+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+#endif

+   {

+      png_crc_finish(png_ptr, 0);

+   }

+

+#ifndef PNG_READ_OPT_PLTE_SUPPORTED

+   else if (png_crc_error(png_ptr))  /* Only if we have a CRC error */

+   {

+      /* If we don't want to use the data from an ancillary chunk,

+       * we have two options: an error abort, or a warning and we

+       * ignore the data in this chunk (which should be OK, since

+       * it's considered ancillary for a RGB or RGBA image).

+       *

+       * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the

+       * chunk type to determine whether to check the ancillary or the critical

+       * flags.

+       */

+      if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))

+      {

+         if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)

+         {

+            png_chunk_benign_error(png_ptr, "CRC error");

+         }

+

+         else

+         {

+            png_chunk_warning(png_ptr, "CRC error");

+            return;

+         }

+      }

+

+      /* Otherwise, we (optionally) emit a warning and use the chunk. */

+      else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))

+      {

+         png_chunk_warning(png_ptr, "CRC error");

+      }

+   }

+#endif

+

+   /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its

+    * own copy of the palette.  This has the side effect that when png_start_row

+    * is called (this happens after any call to png_read_update_info) the

+    * info_ptr palette gets changed.  This is extremely unexpected and

+    * confusing.

+    *

+    * Fix this by not sharing the palette in this way.

+    */

+   png_set_PLTE(png_ptr, info_ptr, palette, num);

+

+   /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before

+    * IDAT.  Prior to 1.6.0 this was not checked; instead the code merely

+    * checked the apparent validity of a tRNS chunk inserted before PLTE on a

+    * palette PNG.  1.6.0 attempts to rigorously follow the standard and

+    * therefore does a benign error if the erroneous condition is detected *and*

+    * cancels the tRNS if the benign error returns.  The alternative is to

+    * amend the standard since it would be rather hypocritical of the standards

+    * maintainers to ignore it.

+    */

+#ifdef PNG_READ_tRNS_SUPPORTED

+   if (png_ptr->num_trans > 0 ||

+      (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0))

+   {

+      /* Cancel this because otherwise it would be used if the transforms

+       * require it.  Don't cancel the 'valid' flag because this would prevent

+       * detection of duplicate chunks.

+       */

+      png_ptr->num_trans = 0;

+

+      if (info_ptr != NULL)

+         info_ptr->num_trans = 0;

+

+      png_chunk_benign_error(png_ptr, "tRNS must be after");

+   }

+#endif

+

+#ifdef PNG_READ_hIST_SUPPORTED

+   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)

+      png_chunk_benign_error(png_ptr, "hIST must be after");

+#endif

+

+#ifdef PNG_READ_bKGD_SUPPORTED

+   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)

+      png_chunk_benign_error(png_ptr, "bKGD must be after");

+#endif

+}

+

+void /* PRIVATE */

+png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_debug(1, "in png_handle_IEND");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))

+      png_chunk_error(png_ptr, "out of place");

+

+   png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);

+

+   png_crc_finish(png_ptr, length);

+

+   if (length != 0)

+      png_chunk_benign_error(png_ptr, "invalid");

+

+   PNG_UNUSED(info_ptr)

+}

+

+#ifdef PNG_READ_gAMA_SUPPORTED

+void /* PRIVATE */

+png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_fixed_point igamma;

+   png_byte buf[4];

+

+   png_debug(1, "in png_handle_gAMA");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   if (length != 4)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_crc_read(png_ptr, buf, 4);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   igamma = png_get_fixed_point(NULL, buf);

+

+   png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma);

+   png_colorspace_sync(png_ptr, info_ptr);

+}

+#endif

+

+#ifdef PNG_READ_sBIT_SUPPORTED

+void /* PRIVATE */

+png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   unsigned int truelen;

+   png_byte buf[4];

+

+   png_debug(1, "in png_handle_sBIT");

+

+   buf[0] = buf[1] = buf[2] = buf[3] = 0;

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      truelen = 3;

+

+   else

+      truelen = png_ptr->channels;

+

+   if (length != truelen || length > 4)

+   {

+      png_chunk_benign_error(png_ptr, "invalid");

+      png_crc_finish(png_ptr, length);

+      return;

+   }

+

+   png_crc_read(png_ptr, buf, truelen);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)

+   {

+      png_ptr->sig_bit.red = buf[0];

+      png_ptr->sig_bit.green = buf[1];

+      png_ptr->sig_bit.blue = buf[2];

+      png_ptr->sig_bit.alpha = buf[3];

+   }

+

+   else

+   {

+      png_ptr->sig_bit.gray = buf[0];

+      png_ptr->sig_bit.red = buf[0];

+      png_ptr->sig_bit.green = buf[0];

+      png_ptr->sig_bit.blue = buf[0];

+      png_ptr->sig_bit.alpha = buf[1];

+   }

+

+   png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));

+}

+#endif

+

+#ifdef PNG_READ_cHRM_SUPPORTED

+void /* PRIVATE */

+png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_byte buf[32];

+   png_xy xy;

+

+   png_debug(1, "in png_handle_cHRM");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   if (length != 32)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_crc_read(png_ptr, buf, 32);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   xy.whitex = png_get_fixed_point(NULL, buf);

+   xy.whitey = png_get_fixed_point(NULL, buf + 4);

+   xy.redx   = png_get_fixed_point(NULL, buf + 8);

+   xy.redy   = png_get_fixed_point(NULL, buf + 12);

+   xy.greenx = png_get_fixed_point(NULL, buf + 16);

+   xy.greeny = png_get_fixed_point(NULL, buf + 20);

+   xy.bluex  = png_get_fixed_point(NULL, buf + 24);

+   xy.bluey  = png_get_fixed_point(NULL, buf + 28);

+

+   if (xy.whitex == PNG_FIXED_ERROR ||

+       xy.whitey == PNG_FIXED_ERROR ||

+       xy.redx   == PNG_FIXED_ERROR ||

+       xy.redy   == PNG_FIXED_ERROR ||

+       xy.greenx == PNG_FIXED_ERROR ||

+       xy.greeny == PNG_FIXED_ERROR ||

+       xy.bluex  == PNG_FIXED_ERROR ||

+       xy.bluey  == PNG_FIXED_ERROR)

+   {

+      png_chunk_benign_error(png_ptr, "invalid values");

+      return;

+   }

+

+   /* If a colorspace error has already been output skip this chunk */

+   if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)

+      return;

+

+   if (png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM)

+   {

+      png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;

+      png_colorspace_sync(png_ptr, info_ptr);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;

+   (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy,

+      1/*prefer cHRM values*/);

+   png_colorspace_sync(png_ptr, info_ptr);

+}

+#endif

+

+#ifdef PNG_READ_sRGB_SUPPORTED

+void /* PRIVATE */

+png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_byte intent;

+

+   png_debug(1, "in png_handle_sRGB");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   if (length != 1)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_crc_read(png_ptr, &intent, 1);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   /* If a colorspace error has already been output skip this chunk */

+   if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)

+      return;

+

+   /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect

+    * this.

+    */

+   if (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT)

+   {

+      png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;

+      png_colorspace_sync(png_ptr, info_ptr);

+      png_chunk_benign_error(png_ptr, "too many profiles");

+      return;

+   }

+

+   (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent);

+   png_colorspace_sync(png_ptr, info_ptr);

+}

+#endif /* PNG_READ_sRGB_SUPPORTED */

+

+#ifdef PNG_READ_iCCP_SUPPORTED

+void /* PRIVATE */

+png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+/* Note: this does not properly handle profiles that are > 64K under DOS */

+{

+   png_const_charp errmsg = NULL; /* error message output, or no error */

+   int finished = 0; /* crc checked */

+

+   png_debug(1, "in png_handle_iCCP");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   /* Consistent with all the above colorspace handling an obviously *invalid*

+    * chunk is just ignored, so does not invalidate the color space.  An

+    * alternative is to set the 'invalid' flags at the start of this routine

+    * and only clear them in they were not set before and all the tests pass.

+    * The minimum 'deflate' stream is assumed to be just the 2 byte header and 4

+    * byte checksum.  The keyword must be one character and there is a

+    * terminator (0) byte and the compression method.

+    */

+   if (length < 9)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "too short");

+      return;

+   }

+

+   /* If a colorspace error has already been output skip this chunk */

+   if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)

+   {

+      png_crc_finish(png_ptr, length);

+      return;

+   }

+

+   /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect

+    * this.

+    */

+   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0)

+   {

+      uInt read_length, keyword_length;

+      char keyword[81];

+

+      /* Find the keyword; the keyword plus separator and compression method

+       * bytes can be at most 81 characters long.

+       */

+      read_length = 81; /* maximum */

+      if (read_length > length)

+         read_length = (uInt)length;

+

+      png_crc_read(png_ptr, (png_bytep)keyword, read_length);

+      length -= read_length;

+

+      keyword_length = 0;

+      while (keyword_length < 80 && keyword_length < read_length &&

+         keyword[keyword_length] != 0)

+         ++keyword_length;

+

+      /* TODO: make the keyword checking common */

+      if (keyword_length >= 1 && keyword_length <= 79)

+      {

+         /* We only understand '0' compression - deflate - so if we get a

+          * different value we can't safely decode the chunk.

+          */

+         if (keyword_length+1 < read_length &&

+            keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE)

+         {

+            read_length -= keyword_length+2;

+

+            if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK)

+            {

+               Byte profile_header[132];

+               Byte local_buffer[PNG_INFLATE_BUF_SIZE];

+               png_alloc_size_t size = (sizeof profile_header);

+

+               png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2);

+               png_ptr->zstream.avail_in = read_length;

+               (void)png_inflate_read(png_ptr, local_buffer,

+                  (sizeof local_buffer), &length, profile_header, &size,

+                  0/*finish: don't, because the output is too small*/);

+

+               if (size == 0)

+               {

+                  /* We have the ICC profile header; do the basic header checks.

+                   */

+                  const png_uint_32 profile_length =

+                     png_get_uint_32(profile_header);

+

+                  if (png_icc_check_length(png_ptr, &png_ptr->colorspace,

+                     keyword, profile_length))

+                  {

+                     /* The length is apparently ok, so we can check the 132

+                      * byte header.

+                      */

+                     if (png_icc_check_header(png_ptr, &png_ptr->colorspace,

+                        keyword, profile_length, profile_header,

+                        png_ptr->color_type))

+                     {

+                        /* Now read the tag table; a variable size buffer is

+                         * needed at this point, allocate one for the whole

+                         * profile.  The header check has already validated

+                         * that none of these stuff will overflow.

+                         */

+                        const png_uint_32 tag_count = png_get_uint_32(

+                           profile_header+128);

+                        png_bytep profile = png_read_buffer(png_ptr,

+                           profile_length, 2/*silent*/);

+

+                        if (profile != NULL)

+                        {

+                           memcpy(profile, profile_header,

+                              (sizeof profile_header));

+

+                           size = 12 * tag_count;

+

+                           (void)png_inflate_read(png_ptr, local_buffer,

+                              (sizeof local_buffer), &length,

+                              profile + (sizeof profile_header), &size, 0);

+

+                           /* Still expect a a buffer error because we expect

+                            * there to be some tag data!

+                            */

+                           if (size == 0)

+                           {

+                              if (png_icc_check_tag_table(png_ptr,

+                                 &png_ptr->colorspace, keyword, profile_length,

+                                 profile))

+                              {

+                                 /* The profile has been validated for basic

+                                  * security issues, so read the whole thing in.

+                                  */

+                                 size = profile_length - (sizeof profile_header)

+                                    - 12 * tag_count;

+

+                                 (void)png_inflate_read(png_ptr, local_buffer,

+                                    (sizeof local_buffer), &length,

+                                    profile + (sizeof profile_header) +

+                                    12 * tag_count, &size, 1/*finish*/);

+

+                                 if (length > 0 && !(png_ptr->flags &

+                                       PNG_FLAG_BENIGN_ERRORS_WARN))

+                                    errmsg = "extra compressed data";

+

+                                 /* But otherwise allow extra data: */

+                                 else if (size == 0)

+                                 {

+                                    if (length > 0)

+                                    {

+                                       /* This can be handled completely, so

+                                        * keep going.

+                                        */

+                                       png_chunk_warning(png_ptr,

+                                          "extra compressed data");

+                                    }

+

+                                    png_crc_finish(png_ptr, length);

+                                    finished = 1;

+

+#                                   ifdef PNG_sRGB_SUPPORTED

+                                       /* Check for a match against sRGB */

+                                       png_icc_set_sRGB(png_ptr,

+                                          &png_ptr->colorspace, profile,

+                                          png_ptr->zstream.adler);

+#                                   endif

+

+                                    /* Steal the profile for info_ptr. */

+                                    if (info_ptr != NULL)

+                                    {

+                                       png_free_data(png_ptr, info_ptr,

+                                          PNG_FREE_ICCP, 0);

+

+                                       info_ptr->iccp_name = png_voidcast(char*,

+                                          png_malloc_base(png_ptr,

+                                          keyword_length+1));

+                                       if (info_ptr->iccp_name != NULL)

+                                       {

+                                          memcpy(info_ptr->iccp_name, keyword,

+                                             keyword_length+1);

+                                          info_ptr->iccp_proflen =

+                                             profile_length;

+                                          info_ptr->iccp_profile = profile;

+                                          png_ptr->read_buffer = NULL; /*steal*/

+                                          info_ptr->free_me |= PNG_FREE_ICCP;

+                                          info_ptr->valid |= PNG_INFO_iCCP;

+                                       }

+

+                                       else

+                                       {

+                                          png_ptr->colorspace.flags |=

+                                             PNG_COLORSPACE_INVALID;

+                                          errmsg = "out of memory";

+                                       }

+                                    }

+

+                                    /* else the profile remains in the read

+                                     * buffer which gets reused for subsequent

+                                     * chunks.

+                                     */

+

+                                    if (info_ptr != NULL)

+                                       png_colorspace_sync(png_ptr, info_ptr);

+

+                                    if (errmsg == NULL)

+                                    {

+                                       png_ptr->zowner = 0;

+                                       return;

+                                    }

+                                 }

+

+                                 else if (size > 0)

+                                    errmsg = "truncated";

+

+                                 else

+                                    errmsg = png_ptr->zstream.msg;

+                              }

+

+                              /* else png_icc_check_tag_table output an error */

+                           }

+

+                           else /* profile truncated */

+                              errmsg = png_ptr->zstream.msg;

+                        }

+

+                        else

+                           errmsg = "out of memory";

+                     }

+

+                     /* else png_icc_check_header output an error */

+                  }

+

+                  /* else png_icc_check_length output an error */

+               }

+

+               else /* profile truncated */

+                  errmsg = png_ptr->zstream.msg;

+

+               /* Release the stream */

+               png_ptr->zowner = 0;

+            }

+

+            else /* png_inflate_claim failed */

+               errmsg = png_ptr->zstream.msg;

+         }

+

+         else

+            errmsg = "bad compression method"; /* or missing */

+      }

+

+      else

+         errmsg = "bad keyword";

+   }

+

+   else

+      errmsg = "too many profiles";

+

+   /* Failure: the reason is in 'errmsg' */

+   if (!finished)

+      png_crc_finish(png_ptr, length);

+

+   png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;

+   png_colorspace_sync(png_ptr, info_ptr);

+   if (errmsg != NULL) /* else already output */

+      png_chunk_benign_error(png_ptr, errmsg);

+}

+#endif /* PNG_READ_iCCP_SUPPORTED */

+

+#ifdef PNG_READ_sPLT_SUPPORTED

+void /* PRIVATE */

+png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+/* Note: this does not properly handle chunks that are > 64K under DOS */

+{

+   png_bytep entry_start, buffer;

+   png_sPLT_t new_palette;

+   png_sPLT_entryp pp;

+   png_uint_32 data_length;

+   int entry_size, i;

+   png_uint_32 skip = 0;

+   png_uint_32 dl;

+   png_size_t max_dl;

+

+   png_debug(1, "in png_handle_sPLT");

+

+#ifdef PNG_USER_LIMITS_SUPPORTED

+   if (png_ptr->user_chunk_cache_max != 0)

+   {

+      if (png_ptr->user_chunk_cache_max == 1)

+      {

+         png_crc_finish(png_ptr, length);

+         return;

+      }

+

+      if (--png_ptr->user_chunk_cache_max == 1)

+      {

+         png_warning(png_ptr, "No space in chunk cache for sPLT");

+         png_crc_finish(png_ptr, length);

+         return;

+      }

+   }

+#endif

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & PNG_HAVE_IDAT)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+#ifdef PNG_MAX_MALLOC_64K

+   if (length > 65535U)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "too large to fit in memory");

+      return;

+   }

+#endif

+

+   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);

+   if (buffer == NULL)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of memory");

+      return;

+   }

+

+

+   /* WARNING: this may break if size_t is less than 32 bits; it is assumed

+    * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a

+    * potential breakage point if the types in pngconf.h aren't exactly right.

+    */

+   png_crc_read(png_ptr, buffer, length);

+

+   if (png_crc_finish(png_ptr, skip))

+      return;

+

+   buffer[length] = 0;

+

+   for (entry_start = buffer; *entry_start; entry_start++)

+      /* Empty loop to find end of name */ ;

+

+   ++entry_start;

+

+   /* A sample depth should follow the separator, and we should be on it  */

+   if (entry_start > buffer + length - 2)

+   {

+      png_warning(png_ptr, "malformed sPLT chunk");

+      return;

+   }

+

+   new_palette.depth = *entry_start++;

+   entry_size = (new_palette.depth == 8 ? 6 : 10);

+   /* This must fit in a png_uint_32 because it is derived from the original

+    * chunk data length.

+    */

+   data_length = length - (png_uint_32)(entry_start - buffer);

+

+   /* Integrity-check the data length */

+   if (data_length % entry_size)

+   {

+      png_warning(png_ptr, "sPLT chunk has bad length");

+      return;

+   }

+

+   dl = (png_int_32)(data_length / entry_size);

+   max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry));

+

+   if (dl > max_dl)

+   {

+       png_warning(png_ptr, "sPLT chunk too long");

+       return;

+   }

+

+   new_palette.nentries = (png_int_32)(data_length / entry_size);

+

+   new_palette.entries = (png_sPLT_entryp)png_malloc_warn(

+       png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry)));

+

+   if (new_palette.entries == NULL)

+   {

+       png_warning(png_ptr, "sPLT chunk requires too much memory");

+       return;

+   }

+

+#ifdef PNG_POINTER_INDEXING_SUPPORTED

+   for (i = 0; i < new_palette.nentries; i++)

+   {

+      pp = new_palette.entries + i;

+

+      if (new_palette.depth == 8)

+      {

+         pp->red = *entry_start++;

+         pp->green = *entry_start++;

+         pp->blue = *entry_start++;

+         pp->alpha = *entry_start++;

+      }

+

+      else

+      {

+         pp->red   = png_get_uint_16(entry_start); entry_start += 2;

+         pp->green = png_get_uint_16(entry_start); entry_start += 2;

+         pp->blue  = png_get_uint_16(entry_start); entry_start += 2;

+         pp->alpha = png_get_uint_16(entry_start); entry_start += 2;

+      }

+

+      pp->frequency = png_get_uint_16(entry_start); entry_start += 2;

+   }

+#else

+   pp = new_palette.entries;

+

+   for (i = 0; i < new_palette.nentries; i++)

+   {

+

+      if (new_palette.depth == 8)

+      {

+         pp[i].red   = *entry_start++;

+         pp[i].green = *entry_start++;

+         pp[i].blue  = *entry_start++;

+         pp[i].alpha = *entry_start++;

+      }

+

+      else

+      {

+         pp[i].red   = png_get_uint_16(entry_start); entry_start += 2;

+         pp[i].green = png_get_uint_16(entry_start); entry_start += 2;

+         pp[i].blue  = png_get_uint_16(entry_start); entry_start += 2;

+         pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;

+      }

+

+      pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2;

+   }

+#endif

+

+   /* Discard all chunk data except the name and stash that */

+   new_palette.name = (png_charp)buffer;

+

+   png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);

+

+   png_free(png_ptr, new_palette.entries);

+}

+#endif /* PNG_READ_sPLT_SUPPORTED */

+

+#ifdef PNG_READ_tRNS_SUPPORTED

+void /* PRIVATE */

+png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_byte readbuf[PNG_MAX_PALETTE_LENGTH];

+

+   png_debug(1, "in png_handle_tRNS");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & PNG_HAVE_IDAT)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)

+   {

+      png_byte buf[2];

+

+      if (length != 2)

+      {

+         png_crc_finish(png_ptr, length);

+         png_chunk_benign_error(png_ptr, "invalid");

+         return;

+      }

+

+      png_crc_read(png_ptr, buf, 2);

+      png_ptr->num_trans = 1;

+      png_ptr->trans_color.gray = png_get_uint_16(buf);

+   }

+

+   else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)

+   {

+      png_byte buf[6];

+

+      if (length != 6)

+      {

+         png_crc_finish(png_ptr, length);

+         png_chunk_benign_error(png_ptr, "invalid");

+         return;

+      }

+

+      png_crc_read(png_ptr, buf, length);

+      png_ptr->num_trans = 1;

+      png_ptr->trans_color.red = png_get_uint_16(buf);

+      png_ptr->trans_color.green = png_get_uint_16(buf + 2);

+      png_ptr->trans_color.blue = png_get_uint_16(buf + 4);

+   }

+

+   else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+   {

+      if (!(png_ptr->mode & PNG_HAVE_PLTE))

+      {

+         /* TODO: is this actually an error in the ISO spec? */

+         png_crc_finish(png_ptr, length);

+         png_chunk_benign_error(png_ptr, "out of place");

+         return;

+      }

+

+      if (length > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH ||

+         length == 0)

+      {

+         png_crc_finish(png_ptr, length);

+         png_chunk_benign_error(png_ptr, "invalid");

+         return;

+      }

+

+      png_crc_read(png_ptr, readbuf, length);

+      png_ptr->num_trans = (png_uint_16)length;

+   }

+

+   else

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid with alpha channel");

+      return;

+   }

+

+   if (png_crc_finish(png_ptr, 0))

+   {

+      png_ptr->num_trans = 0;

+      return;

+   }

+

+   /* TODO: this is a horrible side effect in the palette case because the

+    * png_struct ends up with a pointer to the tRNS buffer owned by the

+    * png_info.  Fix this.

+    */

+   png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,

+       &(png_ptr->trans_color));

+}

+#endif

+

+#ifdef PNG_READ_bKGD_SUPPORTED

+void /* PRIVATE */

+png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   unsigned int truelen;

+   png_byte buf[6];

+   png_color_16 background;

+

+   png_debug(1, "in png_handle_bKGD");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if ((png_ptr->mode & PNG_HAVE_IDAT) ||

+      (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&

+       !(png_ptr->mode & PNG_HAVE_PLTE)))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      truelen = 1;

+

+   else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)

+      truelen = 6;

+

+   else

+      truelen = 2;

+

+   if (length != truelen)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_crc_read(png_ptr, buf, truelen);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   /* We convert the index value into RGB components so that we can allow

+    * arbitrary RGB values for background when we have transparency, and

+    * so it is easy to determine the RGB values of the background color

+    * from the info_ptr struct.

+    */

+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+   {

+      background.index = buf[0];

+

+      if (info_ptr && info_ptr->num_palette)

+      {

+         if (buf[0] >= info_ptr->num_palette)

+         {

+            png_chunk_benign_error(png_ptr, "invalid index");

+            return;

+         }

+

+         background.red = (png_uint_16)png_ptr->palette[buf[0]].red;

+         background.green = (png_uint_16)png_ptr->palette[buf[0]].green;

+         background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;

+      }

+

+      else

+         background.red = background.green = background.blue = 0;

+

+      background.gray = 0;

+   }

+

+   else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */

+   {

+      background.index = 0;

+      background.red =

+      background.green =

+      background.blue =

+      background.gray = png_get_uint_16(buf);

+   }

+

+   else

+   {

+      background.index = 0;

+      background.red = png_get_uint_16(buf);

+      background.green = png_get_uint_16(buf + 2);

+      background.blue = png_get_uint_16(buf + 4);

+      background.gray = 0;

+   }

+

+   png_set_bKGD(png_ptr, info_ptr, &background);

+}

+#endif

+

+#ifdef PNG_READ_hIST_SUPPORTED

+void /* PRIVATE */

+png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   unsigned int num, i;

+   png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];

+

+   png_debug(1, "in png_handle_hIST");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if ((png_ptr->mode & PNG_HAVE_IDAT) || !(png_ptr->mode & PNG_HAVE_PLTE))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   num = length / 2 ;

+

+   if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   for (i = 0; i < num; i++)

+   {

+      png_byte buf[2];

+

+      png_crc_read(png_ptr, buf, 2);

+      readbuf[i] = png_get_uint_16(buf);

+   }

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   png_set_hIST(png_ptr, info_ptr, readbuf);

+}

+#endif

+

+#ifdef PNG_READ_pHYs_SUPPORTED

+void /* PRIVATE */

+png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_byte buf[9];

+   png_uint_32 res_x, res_y;

+   int unit_type;

+

+   png_debug(1, "in png_handle_pHYs");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & PNG_HAVE_IDAT)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   if (length != 9)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_crc_read(png_ptr, buf, 9);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   res_x = png_get_uint_32(buf);

+   res_y = png_get_uint_32(buf + 4);

+   unit_type = buf[8];

+   png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);

+}

+#endif

+

+#ifdef PNG_READ_oFFs_SUPPORTED

+void /* PRIVATE */

+png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_byte buf[9];

+   png_int_32 offset_x, offset_y;

+   int unit_type;

+

+   png_debug(1, "in png_handle_oFFs");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & PNG_HAVE_IDAT)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   if (length != 9)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_crc_read(png_ptr, buf, 9);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   offset_x = png_get_int_32(buf);

+   offset_y = png_get_int_32(buf + 4);

+   unit_type = buf[8];

+   png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);

+}

+#endif

+

+#ifdef PNG_READ_pCAL_SUPPORTED

+/* Read the pCAL chunk (described in the PNG Extensions document) */

+void /* PRIVATE */

+png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_int_32 X0, X1;

+   png_byte type, nparams;

+   png_bytep buffer, buf, units, endptr;

+   png_charpp params;

+   int i;

+

+   png_debug(1, "in png_handle_pCAL");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & PNG_HAVE_IDAT)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",

+       length + 1);

+

+   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);

+

+   if (buffer == NULL)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of memory");

+      return;

+   }

+

+   png_crc_read(png_ptr, buffer, length);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   buffer[length] = 0; /* Null terminate the last string */

+

+   png_debug(3, "Finding end of pCAL purpose string");

+   for (buf = buffer; *buf; buf++)

+      /* Empty loop */ ;

+

+   endptr = buffer + length;

+

+   /* We need to have at least 12 bytes after the purpose string

+    * in order to get the parameter information.

+    */

+   if (endptr <= buf + 12)

+   {

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");

+   X0 = png_get_int_32((png_bytep)buf+1);

+   X1 = png_get_int_32((png_bytep)buf+5);

+   type = buf[9];

+   nparams = buf[10];

+   units = buf + 11;

+

+   png_debug(3, "Checking pCAL equation type and number of parameters");

+   /* Check that we have the right number of parameters for known

+    * equation types.

+    */

+   if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||

+       (type == PNG_EQUATION_BASE_E && nparams != 3) ||

+       (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||

+       (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))

+   {

+      png_chunk_benign_error(png_ptr, "invalid parameter count");

+      return;

+   }

+

+   else if (type >= PNG_EQUATION_LAST)

+   {

+      png_chunk_benign_error(png_ptr, "unrecognized equation type");

+   }

+

+   for (buf = units; *buf; buf++)

+      /* Empty loop to move past the units string. */ ;

+

+   png_debug(3, "Allocating pCAL parameters array");

+

+   params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,

+       nparams * (sizeof (png_charp))));

+

+   if (params == NULL)

+   {

+      png_chunk_benign_error(png_ptr, "out of memory");

+      return;

+   }

+

+   /* Get pointers to the start of each parameter string. */

+   for (i = 0; i < nparams; i++)

+   {

+      buf++; /* Skip the null string terminator from previous parameter. */

+

+      png_debug1(3, "Reading pCAL parameter %d", i);

+

+      for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++)

+         /* Empty loop to move past each parameter string */ ;

+

+      /* Make sure we haven't run out of data yet */

+      if (buf > endptr)

+      {

+         png_free(png_ptr, params);

+         png_chunk_benign_error(png_ptr, "invalid data");

+         return;

+      }

+   }

+

+   png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams,

+      (png_charp)units, params);

+

+   png_free(png_ptr, params);

+}

+#endif

+

+#ifdef PNG_READ_sCAL_SUPPORTED

+/* Read the sCAL chunk */

+void /* PRIVATE */

+png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_bytep buffer;

+   png_size_t i;

+   int state;

+

+   png_debug(1, "in png_handle_sCAL");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (png_ptr->mode & PNG_HAVE_IDAT)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of place");

+      return;

+   }

+

+   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   /* Need unit type, width, \0, height: minimum 4 bytes */

+   else if (length < 4)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",

+      length + 1);

+

+   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);

+

+   if (buffer == NULL)

+   {

+      png_chunk_benign_error(png_ptr, "out of memory");

+      png_crc_finish(png_ptr, length);

+      return;

+   }

+

+   png_crc_read(png_ptr, buffer, length);

+   buffer[length] = 0; /* Null terminate the last string */

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   /* Validate the unit. */

+   if (buffer[0] != 1 && buffer[0] != 2)

+   {

+      png_chunk_benign_error(png_ptr, "invalid unit");

+      return;

+   }

+

+   /* Validate the ASCII numbers, need two ASCII numbers separated by

+    * a '\0' and they need to fit exactly in the chunk data.

+    */

+   i = 1;

+   state = 0;

+

+   if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) ||

+       i >= length || buffer[i++] != 0)

+      png_chunk_benign_error(png_ptr, "bad width format");

+

+   else if (!PNG_FP_IS_POSITIVE(state))

+      png_chunk_benign_error(png_ptr, "non-positive width");

+

+   else

+   {

+      png_size_t heighti = i;

+

+      state = 0;

+      if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) ||

+         i != length)

+         png_chunk_benign_error(png_ptr, "bad height format");

+

+      else if (!PNG_FP_IS_POSITIVE(state))

+         png_chunk_benign_error(png_ptr, "non-positive height");

+

+      else

+         /* This is the (only) success case. */

+         png_set_sCAL_s(png_ptr, info_ptr, buffer[0],

+            (png_charp)buffer+1, (png_charp)buffer+heighti);

+   }

+}

+#endif

+

+#ifdef PNG_READ_tIME_SUPPORTED

+void /* PRIVATE */

+png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_byte buf[7];

+   png_time mod_time;

+

+   png_debug(1, "in png_handle_tIME");

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "duplicate");

+      return;

+   }

+

+   if (png_ptr->mode & PNG_HAVE_IDAT)

+      png_ptr->mode |= PNG_AFTER_IDAT;

+

+   if (length != 7)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "invalid");

+      return;

+   }

+

+   png_crc_read(png_ptr, buf, 7);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   mod_time.second = buf[6];

+   mod_time.minute = buf[5];

+   mod_time.hour = buf[4];

+   mod_time.day = buf[3];

+   mod_time.month = buf[2];

+   mod_time.year = png_get_uint_16(buf);

+

+   png_set_tIME(png_ptr, info_ptr, &mod_time);

+}

+#endif

+

+#ifdef PNG_READ_tEXt_SUPPORTED

+/* Note: this does not properly handle chunks that are > 64K under DOS */

+void /* PRIVATE */

+png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_text  text_info;

+   png_bytep buffer;

+   png_charp key;

+   png_charp text;

+   png_uint_32 skip = 0;

+

+   png_debug(1, "in png_handle_tEXt");

+

+#ifdef PNG_USER_LIMITS_SUPPORTED

+   if (png_ptr->user_chunk_cache_max != 0)

+   {

+      if (png_ptr->user_chunk_cache_max == 1)

+      {

+         png_crc_finish(png_ptr, length);

+         return;

+      }

+

+      if (--png_ptr->user_chunk_cache_max == 1)

+      {

+         png_crc_finish(png_ptr, length);

+         png_chunk_benign_error(png_ptr, "no space in chunk cache");

+         return;

+      }

+   }

+#endif

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   if (png_ptr->mode & PNG_HAVE_IDAT)

+      png_ptr->mode |= PNG_AFTER_IDAT;

+

+#ifdef PNG_MAX_MALLOC_64K

+   if (length > 65535U)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "too large to fit in memory");

+      return;

+   }

+#endif

+

+   buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);

+

+   if (buffer == NULL)

+   {

+     png_chunk_benign_error(png_ptr, "out of memory");

+     return;

+   }

+

+   png_crc_read(png_ptr, buffer, length);

+

+   if (png_crc_finish(png_ptr, skip))

+      return;

+

+   key = (png_charp)buffer;

+   key[length] = 0;

+

+   for (text = key; *text; text++)

+      /* Empty loop to find end of key */ ;

+

+   if (text != key + length)

+      text++;

+

+   text_info.compression = PNG_TEXT_COMPRESSION_NONE;

+   text_info.key = key;

+   text_info.lang = NULL;

+   text_info.lang_key = NULL;

+   text_info.itxt_length = 0;

+   text_info.text = text;

+   text_info.text_length = strlen(text);

+

+   if (png_set_text_2(png_ptr, info_ptr, &text_info, 1))

+      png_warning(png_ptr, "Insufficient memory to process text chunk");

+}

+#endif

+

+#ifdef PNG_READ_zTXt_SUPPORTED

+/* Note: this does not correctly handle chunks that are > 64K under DOS */

+void /* PRIVATE */

+png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_const_charp errmsg = NULL;

+   png_bytep       buffer;

+   png_uint_32     keyword_length;

+

+   png_debug(1, "in png_handle_zTXt");

+

+#ifdef PNG_USER_LIMITS_SUPPORTED

+   if (png_ptr->user_chunk_cache_max != 0)

+   {

+      if (png_ptr->user_chunk_cache_max == 1)

+      {

+         png_crc_finish(png_ptr, length);

+         return;

+      }

+

+      if (--png_ptr->user_chunk_cache_max == 1)

+      {

+         png_crc_finish(png_ptr, length);

+         png_chunk_benign_error(png_ptr, "no space in chunk cache");

+         return;

+      }

+   }

+#endif

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   if (png_ptr->mode & PNG_HAVE_IDAT)

+      png_ptr->mode |= PNG_AFTER_IDAT;

+

+   buffer = png_read_buffer(png_ptr, length, 2/*silent*/);

+

+   if (buffer == NULL)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of memory");

+      return;

+   }

+

+   png_crc_read(png_ptr, buffer, length);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   /* TODO: also check that the keyword contents match the spec! */

+   for (keyword_length = 0;

+      keyword_length < length && buffer[keyword_length] != 0;

+      ++keyword_length)

+      /* Empty loop to find end of name */ ;

+

+   if (keyword_length > 79 || keyword_length < 1)

+      errmsg = "bad keyword";

+

+   /* zTXt must have some LZ data after the keyword, although it may expand to

+    * zero bytes; we need a '\0' at the end of the keyword, the compression type

+    * then the LZ data:

+    */

+   else if (keyword_length + 3 > length)

+      errmsg = "truncated";

+

+   else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE)

+      errmsg = "unknown compression type";

+

+   else

+   {

+      png_alloc_size_t uncompressed_length = PNG_SIZE_MAX;

+

+      /* TODO: at present png_decompress_chunk imposes a single application

+       * level memory limit, this should be split to different values for iCCP

+       * and text chunks.

+       */

+      if (png_decompress_chunk(png_ptr, length, keyword_length+2,

+         &uncompressed_length, 1/*terminate*/) == Z_STREAM_END)

+      {

+         png_text text;

+

+         /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except

+          * for the extra compression type byte and the fact that it isn't

+          * necessarily '\0' terminated.

+          */

+         buffer = png_ptr->read_buffer;

+         buffer[uncompressed_length+(keyword_length+2)] = 0;

+

+         text.compression = PNG_TEXT_COMPRESSION_zTXt;

+         text.key = (png_charp)buffer;

+         text.text = (png_charp)(buffer + keyword_length+2);

+         text.text_length = uncompressed_length;

+         text.itxt_length = 0;

+         text.lang = NULL;

+         text.lang_key = NULL;

+

+         if (png_set_text_2(png_ptr, info_ptr, &text, 1))

+            errmsg = "insufficient memory";

+      }

+

+      else

+         errmsg = png_ptr->zstream.msg;

+   }

+

+   if (errmsg != NULL)

+      png_chunk_benign_error(png_ptr, errmsg);

+}

+#endif

+

+#ifdef PNG_READ_iTXt_SUPPORTED

+/* Note: this does not correctly handle chunks that are > 64K under DOS */

+void /* PRIVATE */

+png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)

+{

+   png_const_charp errmsg = NULL;

+   png_bytep buffer;

+   png_uint_32 prefix_length;

+

+   png_debug(1, "in png_handle_iTXt");

+

+#ifdef PNG_USER_LIMITS_SUPPORTED

+   if (png_ptr->user_chunk_cache_max != 0)

+   {

+      if (png_ptr->user_chunk_cache_max == 1)

+      {

+         png_crc_finish(png_ptr, length);

+         return;

+      }

+

+      if (--png_ptr->user_chunk_cache_max == 1)

+      {

+         png_crc_finish(png_ptr, length);

+         png_chunk_benign_error(png_ptr, "no space in chunk cache");

+         return;

+      }

+   }

+#endif

+

+   if (!(png_ptr->mode & PNG_HAVE_IHDR))

+      png_chunk_error(png_ptr, "missing IHDR");

+

+   if (png_ptr->mode & PNG_HAVE_IDAT)

+      png_ptr->mode |= PNG_AFTER_IDAT;

+

+   buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);

+

+   if (buffer == NULL)

+   {

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "out of memory");

+      return;

+   }

+

+   png_crc_read(png_ptr, buffer, length);

+

+   if (png_crc_finish(png_ptr, 0))

+      return;

+

+   /* First the keyword. */

+   for (prefix_length=0;

+      prefix_length < length && buffer[prefix_length] != 0;

+      ++prefix_length)

+      /* Empty loop */ ;

+

+   /* Perform a basic check on the keyword length here. */

+   if (prefix_length > 79 || prefix_length < 1)

+      errmsg = "bad keyword";

+

+   /* Expect keyword, compression flag, compression type, language, translated

+    * keyword (both may be empty but are 0 terminated) then the text, which may

+    * be empty.

+    */

+   else if (prefix_length + 5 > length)

+      errmsg = "truncated";

+

+   else if (buffer[prefix_length+1] == 0 ||

+      (buffer[prefix_length+1] == 1 &&

+      buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE))

+   {

+      int compressed = buffer[prefix_length+1] != 0;

+      png_uint_32 language_offset, translated_keyword_offset;

+      png_alloc_size_t uncompressed_length = 0;

+

+      /* Now the language tag */

+      prefix_length += 3;

+      language_offset = prefix_length;

+

+      for (; prefix_length < length && buffer[prefix_length] != 0;

+         ++prefix_length)

+         /* Empty loop */ ;

+

+      /* WARNING: the length may be invalid here, this is checked below. */

+      translated_keyword_offset = ++prefix_length;

+

+      for (; prefix_length < length && buffer[prefix_length] != 0;

+         ++prefix_length)

+         /* Empty loop */ ;

+

+      /* prefix_length should now be at the trailing '\0' of the translated

+       * keyword, but it may already be over the end.  None of this arithmetic

+       * can overflow because chunks are at most 2^31 bytes long, but on 16-bit

+       * systems the available allocaton may overflow.

+       */

+      ++prefix_length;

+

+      if (!compressed && prefix_length <= length)

+         uncompressed_length = length - prefix_length;

+

+      else if (compressed && prefix_length < length)

+      {

+         uncompressed_length = PNG_SIZE_MAX;

+

+         /* TODO: at present png_decompress_chunk imposes a single application

+          * level memory limit, this should be split to different values for

+          * iCCP and text chunks.

+          */

+         if (png_decompress_chunk(png_ptr, length, prefix_length,

+            &uncompressed_length, 1/*terminate*/) == Z_STREAM_END)

+            buffer = png_ptr->read_buffer;

+

+         else

+            errmsg = png_ptr->zstream.msg;

+      }

+

+      else

+         errmsg = "truncated";

+

+      if (errmsg == NULL)

+      {

+         png_text text;

+

+         buffer[uncompressed_length+prefix_length] = 0;

+

+         if (compressed)

+            text.compression = PNG_ITXT_COMPRESSION_NONE;

+

+         else

+            text.compression = PNG_ITXT_COMPRESSION_zTXt;

+

+         text.key = (png_charp)buffer;

+         text.lang = (png_charp)buffer + language_offset;

+         text.lang_key = (png_charp)buffer + translated_keyword_offset;

+         text.text = (png_charp)buffer + prefix_length;

+         text.text_length = 0;

+         text.itxt_length = uncompressed_length;

+

+         if (png_set_text_2(png_ptr, info_ptr, &text, 1))

+            errmsg = "insufficient memory";

+      }

+   }

+

+   else

+      errmsg = "bad compression info";

+

+   if (errmsg != NULL)

+      png_chunk_benign_error(png_ptr, errmsg);

+}

+#endif

+

+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED

+/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */

+static int

+png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)

+{

+   png_alloc_size_t limit = PNG_SIZE_MAX;

+

+   if (png_ptr->unknown_chunk.data != NULL)

+   {

+      png_free(png_ptr, png_ptr->unknown_chunk.data);

+      png_ptr->unknown_chunk.data = NULL;

+   }

+

+#  ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED

+      if (png_ptr->user_chunk_malloc_max > 0 &&

+         png_ptr->user_chunk_malloc_max < limit)

+         limit = png_ptr->user_chunk_malloc_max;

+

+#  elif PNG_USER_CHUNK_MALLOC_MAX > 0

+      if (PNG_USER_CHUNK_MALLOC_MAX < limit)

+         limit = PNG_USER_CHUNK_MALLOC_MAX;

+#  endif

+

+   if (length <= limit)

+   {

+      PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);

+      /* The following is safe because of the PNG_SIZE_MAX init above */

+      png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/;

+      /* 'mode' is a flag array, only the bottom four bits matter here */

+      png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/;

+

+      if (length == 0)

+         png_ptr->unknown_chunk.data = NULL;

+

+      else

+      {

+         /* Do a 'warn' here - it is handled below. */

+         png_ptr->unknown_chunk.data = png_voidcast(png_bytep,

+            png_malloc_warn(png_ptr, length));

+      }

+   }

+

+   if (png_ptr->unknown_chunk.data == NULL && length > 0)

+   {

+      /* This is benign because we clean up correctly */

+      png_crc_finish(png_ptr, length);

+      png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits");

+      return 0;

+   }

+

+   else

+   {

+      if (length > 0)

+         png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length);

+      png_crc_finish(png_ptr, 0);

+      return 1;

+   }

+}

+#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */

+

+/* Handle an unknown, or known but disabled, chunk */

+void /* PRIVATE */

+png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,

+   png_uint_32 length, int keep)

+{

+   int handled = 0; /* the chunk was handled */

+

+   png_debug(1, "in png_handle_unknown");

+

+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED

+   /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing

+    * the bug which meant that setting a non-default behavior for a specific

+    * chunk would be ignored (the default was always used unless a user

+    * callback was installed).

+    *

+    * 'keep' is the value from the png_chunk_unknown_handling, the setting for

+    * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it

+    * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here.

+    * This is just an optimization to avoid multiple calls to the lookup

+    * function.

+    */

+#  ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+#     ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+         keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name);

+#     endif

+#  endif

+

+   /* One of the following methods will read the chunk or skip it (at least one

+    * of these is always defined because this is the only way to switch on

+    * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)

+    */

+#  ifdef PNG_READ_USER_CHUNKS_SUPPORTED

+      /* The user callback takes precedence over the chunk keep value, but the

+       * keep value is still required to validate a save of a critical chunk.

+       */

+      if (png_ptr->read_user_chunk_fn != NULL)

+      {

+         if (png_cache_unknown_chunk(png_ptr, length))

+         {

+            /* Callback to user unknown chunk handler */

+            int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr,

+               &png_ptr->unknown_chunk);

+

+            /* ret is:

+             * negative: An error occured, png_chunk_error will be called.

+             *     zero: The chunk was not handled, the chunk will be discarded

+             *           unless png_set_keep_unknown_chunks has been used to set

+             *           a 'keep' behavior for this particular chunk, in which

+             *           case that will be used.  A critical chunk will cause an

+             *           error at this point unless it is to be saved.

+             * positive: The chunk was handled, libpng will ignore/discard it.

+             */

+            if (ret < 0)

+               png_chunk_error(png_ptr, "error in user chunk");

+

+            else if (ret == 0)

+            {

+               /* If the keep value is 'default' or 'never' override it, but

+                * still error out on critical chunks unless the keep value is

+                * 'always'  While this is weird it is the behavior in 1.4.12.

+                * A possible improvement would be to obey the value set for the

+                * chunk, but this would be an API change that would probably

+                * damage some applications.

+                *

+                * The png_app_warning below catches the case that matters, where

+                * the application has not set specific save or ignore for this

+                * chunk or global save or ignore.

+                */

+               if (keep < PNG_HANDLE_CHUNK_IF_SAFE)

+               {

+#                 ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+                     if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE)

+                     {

+                        png_chunk_warning(png_ptr, "Saving unknown chunk:");

+                        png_app_warning(png_ptr,

+                           "forcing save of an unhandled chunk;"

+                           " please call png_set_keep_unknown_chunks");

+                           /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */

+                     }

+#                 endif

+                  keep = PNG_HANDLE_CHUNK_IF_SAFE;

+               }

+            }

+

+            else /* chunk was handled */

+            {

+               handled = 1;

+               /* Critical chunks can be safely discarded at this point. */

+               keep = PNG_HANDLE_CHUNK_NEVER;

+            }

+         }

+

+         else

+            keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */

+      }

+

+      else

+         /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */

+#  endif /* PNG_READ_USER_CHUNKS_SUPPORTED */

+

+#  ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED

+      {

+         /* keep is currently just the per-chunk setting, if there was no

+          * setting change it to the global default now (not that this may

+          * still be AS_DEFAULT) then obtain the cache of the chunk if required,

+          * if not simply skip the chunk.

+          */

+         if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT)

+            keep = png_ptr->unknown_default;

+

+         if (keep == PNG_HANDLE_CHUNK_ALWAYS ||

+            (keep == PNG_HANDLE_CHUNK_IF_SAFE &&

+             PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)))

+         {

+            if (!png_cache_unknown_chunk(png_ptr, length))

+               keep = PNG_HANDLE_CHUNK_NEVER;

+         }

+

+         else

+            png_crc_finish(png_ptr, length);

+      }

+#  else

+#     ifndef PNG_READ_USER_CHUNKS_SUPPORTED

+#        error no method to support READ_UNKNOWN_CHUNKS

+#     endif

+

+      {

+         /* If here there is no read callback pointer set and no support is

+          * compiled in to just save the unknown chunks, so simply skip this

+          * chunk.  If 'keep' is something other than AS_DEFAULT or NEVER then

+          * the app has erroneously asked for unknown chunk saving when there

+          * is no support.

+          */

+         if (keep > PNG_HANDLE_CHUNK_NEVER)

+            png_app_error(png_ptr, "no unknown chunk support available");

+

+         png_crc_finish(png_ptr, length);

+      }

+#  endif

+

+#  ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED

+      /* Now store the chunk in the chunk list if appropriate, and if the limits

+       * permit it.

+       */

+      if (keep == PNG_HANDLE_CHUNK_ALWAYS ||

+         (keep == PNG_HANDLE_CHUNK_IF_SAFE &&

+          PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)))

+      {

+#     ifdef PNG_USER_LIMITS_SUPPORTED

+         switch (png_ptr->user_chunk_cache_max)

+         {

+            case 2:

+               png_ptr->user_chunk_cache_max = 1;

+               png_chunk_benign_error(png_ptr, "no space in chunk cache");

+               /* FALL THROUGH */

+            case 1:

+               /* NOTE: prior to 1.6.0 this case resulted in an unknown critical

+                * chunk being skipped, now there will be a hard error below.

+                */

+               break;

+

+            default: /* not at limit */

+               --(png_ptr->user_chunk_cache_max);

+               /* FALL THROUGH */

+            case 0: /* no limit */

+#     endif /* PNG_USER_LIMITS_SUPPORTED */

+               /* Here when the limit isn't reached or when limits are compiled

+                * out; store the chunk.

+                */

+               png_set_unknown_chunks(png_ptr, info_ptr,

+                  &png_ptr->unknown_chunk, 1);

+               handled = 1;

+#     ifdef PNG_USER_LIMITS_SUPPORTED

+               break;

+         }

+#     endif

+      }

+#  else /* no store support! */

+      PNG_UNUSED(info_ptr)

+#     error untested code (reading unknown chunks with no store support)

+#  endif

+

+   /* Regardless of the error handling below the cached data (if any) can be

+    * freed now.  Notice that the data is not freed if there is a png_error, but

+    * it will be freed by destroy_read_struct.

+    */

+   if (png_ptr->unknown_chunk.data != NULL)

+      png_free(png_ptr, png_ptr->unknown_chunk.data);

+   png_ptr->unknown_chunk.data = NULL;

+

+#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */

+   /* There is no support to read an unknown chunk, so just skip it. */

+   png_crc_finish(png_ptr, length);

+   PNG_UNUSED(info_ptr)

+   PNG_UNUSED(keep)

+#endif /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */

+

+   /* Check for unhandled critical chunks */

+   if (!handled && PNG_CHUNK_CRITICAL(png_ptr->chunk_name))

+      png_chunk_error(png_ptr, "unhandled critical chunk");

+}

+

+/* This function is called to verify that a chunk name is valid.

+ * This function can't have the "critical chunk check" incorporated

+ * into it, since in the future we will need to be able to call user

+ * functions to handle unknown critical chunks after we check that

+ * the chunk name itself is valid.

+ */

+

+/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is:

+ *

+ * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))

+ */

+

+void /* PRIVATE */

+png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name)

+{

+   int i;

+

+   png_debug(1, "in png_check_chunk_name");

+

+   for (i=1; i<=4; ++i)

+   {

+      int c = chunk_name & 0xff;

+

+      if (c < 65 || c > 122 || (c > 90 && c < 97))

+         png_chunk_error(png_ptr, "invalid chunk type");

+

+      chunk_name >>= 8;

+   }

+}

+

+/* Combines the row recently read in with the existing pixels in the row.  This

+ * routine takes care of alpha and transparency if requested.  This routine also

+ * handles the two methods of progressive display of interlaced images,

+ * depending on the 'display' value; if 'display' is true then the whole row

+ * (dp) is filled from the start by replicating the available pixels.  If

+ * 'display' is false only those pixels present in the pass are filled in.

+ */

+void /* PRIVATE */

+png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display)

+{

+   unsigned int pixel_depth = png_ptr->transformed_pixel_depth;

+   png_const_bytep sp = png_ptr->row_buf + 1;

+   png_uint_32 row_width = png_ptr->width;

+   unsigned int pass = png_ptr->pass;

+   png_bytep end_ptr = 0;

+   png_byte end_byte = 0;

+   unsigned int end_mask;

+

+   png_debug(1, "in png_combine_row");

+

+   /* Added in 1.5.6: it should not be possible to enter this routine until at

+    * least one row has been read from the PNG data and transformed.

+    */

+   if (pixel_depth == 0)

+      png_error(png_ptr, "internal row logic error");

+

+   /* Added in 1.5.4: the pixel depth should match the information returned by

+    * any call to png_read_update_info at this point.  Do not continue if we got

+    * this wrong.

+    */

+   if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes !=

+          PNG_ROWBYTES(pixel_depth, row_width))

+      png_error(png_ptr, "internal row size calculation error");

+

+   /* Don't expect this to ever happen: */

+   if (row_width == 0)

+      png_error(png_ptr, "internal row width error");

+

+   /* Preserve the last byte in cases where only part of it will be overwritten,

+    * the multiply below may overflow, we don't care because ANSI-C guarantees

+    * we get the low bits.

+    */

+   end_mask = (pixel_depth * row_width) & 7;

+   if (end_mask != 0)

+   {

+      /* end_ptr == NULL is a flag to say do nothing */

+      end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1;

+      end_byte = *end_ptr;

+#     ifdef PNG_READ_PACKSWAP_SUPPORTED

+         if (png_ptr->transformations & PNG_PACKSWAP) /* little-endian byte */

+            end_mask = 0xff << end_mask;

+

+         else /* big-endian byte */

+#     endif

+         end_mask = 0xff >> end_mask;

+      /* end_mask is now the bits to *keep* from the destination row */

+   }

+

+   /* For non-interlaced images this reduces to a memcpy(). A memcpy()

+    * will also happen if interlacing isn't supported or if the application

+    * does not call png_set_interlace_handling().  In the latter cases the

+    * caller just gets a sequence of the unexpanded rows from each interlace

+    * pass.

+    */

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE) &&

+      pass < 6 && (display == 0 ||

+      /* The following copies everything for 'display' on passes 0, 2 and 4. */

+      (display == 1 && (pass & 1) != 0)))

+   {

+      /* Narrow images may have no bits in a pass; the caller should handle

+       * this, but this test is cheap:

+       */

+      if (row_width <= PNG_PASS_START_COL(pass))

+         return;

+

+      if (pixel_depth < 8)

+      {

+         /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit

+          * into 32 bits, then a single loop over the bytes using the four byte

+          * values in the 32-bit mask can be used.  For the 'display' option the

+          * expanded mask may also not require any masking within a byte.  To

+          * make this work the PACKSWAP option must be taken into account - it

+          * simply requires the pixels to be reversed in each byte.

+          *

+          * The 'regular' case requires a mask for each of the first 6 passes,

+          * the 'display' case does a copy for the even passes in the range

+          * 0..6.  This has already been handled in the test above.

+          *

+          * The masks are arranged as four bytes with the first byte to use in

+          * the lowest bits (little-endian) regardless of the order (PACKSWAP or

+          * not) of the pixels in each byte.

+          *

+          * NOTE: the whole of this logic depends on the caller of this function

+          * only calling it on rows appropriate to the pass.  This function only

+          * understands the 'x' logic; the 'y' logic is handled by the caller.

+          *

+          * The following defines allow generation of compile time constant bit

+          * masks for each pixel depth and each possibility of swapped or not

+          * swapped bytes.  Pass 'p' is in the range 0..6; 'x', a pixel index,

+          * is in the range 0..7; and the result is 1 if the pixel is to be

+          * copied in the pass, 0 if not.  'S' is for the sparkle method, 'B'

+          * for the block method.

+          *

+          * With some compilers a compile time expression of the general form:

+          *

+          *    (shift >= 32) ? (a >> (shift-32)) : (b >> shift)

+          *

+          * Produces warnings with values of 'shift' in the range 33 to 63

+          * because the right hand side of the ?: expression is evaluated by

+          * the compiler even though it isn't used.  Microsoft Visual C (various

+          * versions) and the Intel C compiler are known to do this.  To avoid

+          * this the following macros are used in 1.5.6.  This is a temporary

+          * solution to avoid destabilizing the code during the release process.

+          */

+#        if PNG_USE_COMPILE_TIME_MASKS

+#           define PNG_LSR(x,s) ((x)>>((s) & 0x1f))

+#           define PNG_LSL(x,s) ((x)<<((s) & 0x1f))

+#        else

+#           define PNG_LSR(x,s) ((x)>>(s))

+#           define PNG_LSL(x,s) ((x)<<(s))

+#        endif

+#        define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\

+           PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1)

+#        define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\

+           PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1)

+

+         /* Return a mask for pass 'p' pixel 'x' at depth 'd'.  The mask is

+          * little endian - the first pixel is at bit 0 - however the extra

+          * parameter 's' can be set to cause the mask position to be swapped

+          * within each byte, to match the PNG format.  This is done by XOR of

+          * the shift with 7, 6 or 4 for bit depths 1, 2 and 4.

+          */

+#        define PIXEL_MASK(p,x,d,s) \

+            (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0))))

+

+         /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask.

+          */

+#        define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)

+#        define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)

+

+         /* Combine 8 of these to get the full mask.  For the 1-bpp and 2-bpp

+          * cases the result needs replicating, for the 4-bpp case the above

+          * generates a full 32 bits.

+          */

+#        define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1)))

+

+#        define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\

+            S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\

+            S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d)

+

+#        define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\

+            B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\

+            B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d)

+

+#if PNG_USE_COMPILE_TIME_MASKS

+         /* Utility macros to construct all the masks for a depth/swap

+          * combination.  The 's' parameter says whether the format is PNG

+          * (big endian bytes) or not.  Only the three odd-numbered passes are

+          * required for the display/block algorithm.

+          */

+#        define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\

+            S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) }

+

+#        define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) }

+

+#        define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2))

+

+         /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and

+          * then pass:

+          */

+         static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] =

+         {

+            /* Little-endian byte masks for PACKSWAP */

+            { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) },

+            /* Normal (big-endian byte) masks - PNG format */

+            { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) }

+         };

+

+         /* display_mask has only three entries for the odd passes, so index by

+          * pass>>1.

+          */

+         static PNG_CONST png_uint_32 display_mask[2][3][3] =

+         {

+            /* Little-endian byte masks for PACKSWAP */

+            { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) },

+            /* Normal (big-endian byte) masks - PNG format */

+            { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) }

+         };

+

+#        define MASK(pass,depth,display,png)\

+            ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\

+               row_mask[png][DEPTH_INDEX(depth)][pass])

+

+#else /* !PNG_USE_COMPILE_TIME_MASKS */

+         /* This is the runtime alternative: it seems unlikely that this will

+          * ever be either smaller or faster than the compile time approach.

+          */

+#        define MASK(pass,depth,display,png)\

+            ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png))

+#endif /* !PNG_USE_COMPILE_TIME_MASKS */

+

+         /* Use the appropriate mask to copy the required bits.  In some cases

+          * the byte mask will be 0 or 0xff, optimize these cases.  row_width is

+          * the number of pixels, but the code copies bytes, so it is necessary

+          * to special case the end.

+          */

+         png_uint_32 pixels_per_byte = 8 / pixel_depth;

+         png_uint_32 mask;

+

+#        ifdef PNG_READ_PACKSWAP_SUPPORTED

+            if (png_ptr->transformations & PNG_PACKSWAP)

+               mask = MASK(pass, pixel_depth, display, 0);

+

+            else

+#        endif

+            mask = MASK(pass, pixel_depth, display, 1);

+

+         for (;;)

+         {

+            png_uint_32 m;

+

+            /* It doesn't matter in the following if png_uint_32 has more than

+             * 32 bits because the high bits always match those in m<<24; it is,

+             * however, essential to use OR here, not +, because of this.

+             */

+            m = mask;

+            mask = (m >> 8) | (m << 24); /* rotate right to good compilers */

+            m &= 0xff;

+

+            if (m != 0) /* something to copy */

+            {

+               if (m != 0xff)

+                  *dp = (png_byte)((*dp & ~m) | (*sp & m));

+               else

+                  *dp = *sp;

+            }

+

+            /* NOTE: this may overwrite the last byte with garbage if the image

+             * is not an exact number of bytes wide; libpng has always done

+             * this.

+             */

+            if (row_width <= pixels_per_byte)

+               break; /* May need to restore part of the last byte */

+

+            row_width -= pixels_per_byte;

+            ++dp;

+            ++sp;

+         }

+      }

+

+      else /* pixel_depth >= 8 */

+      {

+         unsigned int bytes_to_copy, bytes_to_jump;

+

+         /* Validate the depth - it must be a multiple of 8 */

+         if (pixel_depth & 7)

+            png_error(png_ptr, "invalid user transform pixel depth");

+

+         pixel_depth >>= 3; /* now in bytes */

+         row_width *= pixel_depth;

+

+         /* Regardless of pass number the Adam 7 interlace always results in a

+          * fixed number of pixels to copy then to skip.  There may be a

+          * different number of pixels to skip at the start though.

+          */

+         {

+            unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth;

+

+            row_width -= offset;

+            dp += offset;

+            sp += offset;

+         }

+

+         /* Work out the bytes to copy. */

+         if (display)

+         {

+            /* When doing the 'block' algorithm the pixel in the pass gets

+             * replicated to adjacent pixels.  This is why the even (0,2,4,6)

+             * passes are skipped above - the entire expanded row is copied.

+             */

+            bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth;

+

+            /* But don't allow this number to exceed the actual row width. */

+            if (bytes_to_copy > row_width)

+               bytes_to_copy = row_width;

+         }

+

+         else /* normal row; Adam7 only ever gives us one pixel to copy. */

+            bytes_to_copy = pixel_depth;

+

+         /* In Adam7 there is a constant offset between where the pixels go. */

+         bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth;

+

+         /* And simply copy these bytes.  Some optimization is possible here,

+          * depending on the value of 'bytes_to_copy'.  Special case the low

+          * byte counts, which we know to be frequent.

+          *

+          * Notice that these cases all 'return' rather than 'break' - this

+          * avoids an unnecessary test on whether to restore the last byte

+          * below.

+          */

+         switch (bytes_to_copy)

+         {

+            case 1:

+               for (;;)

+               {

+                  *dp = *sp;

+

+                  if (row_width <= bytes_to_jump)

+                     return;

+

+                  dp += bytes_to_jump;

+                  sp += bytes_to_jump;

+                  row_width -= bytes_to_jump;

+               }

+

+            case 2:

+               /* There is a possibility of a partial copy at the end here; this

+                * slows the code down somewhat.

+                */

+               do

+               {

+                  dp[0] = sp[0], dp[1] = sp[1];

+

+                  if (row_width <= bytes_to_jump)

+                     return;

+

+                  sp += bytes_to_jump;

+                  dp += bytes_to_jump;

+                  row_width -= bytes_to_jump;

+               }

+               while (row_width > 1);

+

+               /* And there can only be one byte left at this point: */

+               *dp = *sp;

+               return;

+

+            case 3:

+               /* This can only be the RGB case, so each copy is exactly one

+                * pixel and it is not necessary to check for a partial copy.

+                */

+               for(;;)

+               {

+                  dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2];

+

+                  if (row_width <= bytes_to_jump)

+                     return;

+

+                  sp += bytes_to_jump;

+                  dp += bytes_to_jump;

+                  row_width -= bytes_to_jump;

+               }

+

+            default:

+#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE

+               /* Check for double byte alignment and, if possible, use a

+                * 16-bit copy.  Don't attempt this for narrow images - ones that

+                * are less than an interlace panel wide.  Don't attempt it for

+                * wide bytes_to_copy either - use the memcpy there.

+                */

+               if (bytes_to_copy < 16 /*else use memcpy*/ &&

+                  png_isaligned(dp, png_uint_16) &&

+                  png_isaligned(sp, png_uint_16) &&

+                  bytes_to_copy % (sizeof (png_uint_16)) == 0 &&

+                  bytes_to_jump % (sizeof (png_uint_16)) == 0)

+               {

+                  /* Everything is aligned for png_uint_16 copies, but try for

+                   * png_uint_32 first.

+                   */

+                  if (png_isaligned(dp, png_uint_32) &&

+                     png_isaligned(sp, png_uint_32) &&

+                     bytes_to_copy % (sizeof (png_uint_32)) == 0 &&

+                     bytes_to_jump % (sizeof (png_uint_32)) == 0)

+                  {

+                     png_uint_32p dp32 = png_aligncast(png_uint_32p,dp);

+                     png_const_uint_32p sp32 = png_aligncastconst(

+                        png_const_uint_32p, sp);

+                     size_t skip = (bytes_to_jump-bytes_to_copy) /

+                        (sizeof (png_uint_32));

+

+                     do

+                     {

+                        size_t c = bytes_to_copy;

+                        do

+                        {

+                           *dp32++ = *sp32++;

+                           c -= (sizeof (png_uint_32));

+                        }

+                        while (c > 0);

+

+                        if (row_width <= bytes_to_jump)

+                           return;

+

+                        dp32 += skip;

+                        sp32 += skip;

+                        row_width -= bytes_to_jump;

+                     }

+                     while (bytes_to_copy <= row_width);

+

+                     /* Get to here when the row_width truncates the final copy.

+                      * There will be 1-3 bytes left to copy, so don't try the

+                      * 16-bit loop below.

+                      */

+                     dp = (png_bytep)dp32;

+                     sp = (png_const_bytep)sp32;

+                     do

+                        *dp++ = *sp++;

+                     while (--row_width > 0);

+                     return;

+                  }

+

+                  /* Else do it in 16-bit quantities, but only if the size is

+                   * not too large.

+                   */

+                  else

+                  {

+                     png_uint_16p dp16 = png_aligncast(png_uint_16p, dp);

+                     png_const_uint_16p sp16 = png_aligncastconst(

+                        png_const_uint_16p, sp);

+                     size_t skip = (bytes_to_jump-bytes_to_copy) /

+                        (sizeof (png_uint_16));

+

+                     do

+                     {

+                        size_t c = bytes_to_copy;

+                        do

+                        {

+                           *dp16++ = *sp16++;

+                           c -= (sizeof (png_uint_16));

+                        }

+                        while (c > 0);

+

+                        if (row_width <= bytes_to_jump)

+                           return;

+

+                        dp16 += skip;

+                        sp16 += skip;

+                        row_width -= bytes_to_jump;

+                     }

+                     while (bytes_to_copy <= row_width);

+

+                     /* End of row - 1 byte left, bytes_to_copy > row_width: */

+                     dp = (png_bytep)dp16;

+                     sp = (png_const_bytep)sp16;

+                     do

+                        *dp++ = *sp++;

+                     while (--row_width > 0);

+                     return;

+                  }

+               }

+#endif /* PNG_ALIGN_ code */

+

+               /* The true default - use a memcpy: */

+               for (;;)

+               {

+                  memcpy(dp, sp, bytes_to_copy);

+

+                  if (row_width <= bytes_to_jump)

+                     return;

+

+                  sp += bytes_to_jump;

+                  dp += bytes_to_jump;

+                  row_width -= bytes_to_jump;

+                  if (bytes_to_copy > row_width)

+                     bytes_to_copy = row_width;

+               }

+         }

+

+         /* NOT REACHED*/

+      } /* pixel_depth >= 8 */

+

+      /* Here if pixel_depth < 8 to check 'end_ptr' below. */

+   }

+   else

+#endif

+

+   /* If here then the switch above wasn't used so just memcpy the whole row

+    * from the temporary row buffer (notice that this overwrites the end of the

+    * destination row if it is a partial byte.)

+    */

+   memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width));

+

+   /* Restore the overwritten bits from the last byte if necessary. */

+   if (end_ptr != NULL)

+      *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask));

+}

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+void /* PRIVATE */

+png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,

+   png_uint_32 transformations /* Because these may affect the byte layout */)

+{

+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */

+   /* Offset to next interlace block */

+   static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};

+

+   png_debug(1, "in png_do_read_interlace");

+   if (row != NULL && row_info != NULL)

+   {

+      png_uint_32 final_width;

+

+      final_width = row_info->width * png_pass_inc[pass];

+

+      switch (row_info->pixel_depth)

+      {

+         case 1:

+         {

+            png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);

+            png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);

+            int sshift, dshift;

+            int s_start, s_end, s_inc;

+            int jstop = png_pass_inc[pass];

+            png_byte v;

+            png_uint_32 i;

+            int j;

+

+#ifdef PNG_READ_PACKSWAP_SUPPORTED

+            if (transformations & PNG_PACKSWAP)

+            {

+                sshift = (int)((row_info->width + 7) & 0x07);

+                dshift = (int)((final_width + 7) & 0x07);

+                s_start = 7;

+                s_end = 0;

+                s_inc = -1;

+            }

+

+            else

+#endif

+            {

+                sshift = 7 - (int)((row_info->width + 7) & 0x07);

+                dshift = 7 - (int)((final_width + 7) & 0x07);

+                s_start = 0;

+                s_end = 7;

+                s_inc = 1;

+            }

+

+            for (i = 0; i < row_info->width; i++)

+            {

+               v = (png_byte)((*sp >> sshift) & 0x01);

+               for (j = 0; j < jstop; j++)

+               {

+                  unsigned int tmp = *dp & (0x7f7f >> (7 - dshift));

+                  tmp |= v << dshift;

+                  *dp = (png_byte)(tmp & 0xff);

+

+                  if (dshift == s_end)

+                  {

+                     dshift = s_start;

+                     dp--;

+                  }

+

+                  else

+                     dshift += s_inc;

+               }

+

+               if (sshift == s_end)

+               {

+                  sshift = s_start;

+                  sp--;

+               }

+

+               else

+                  sshift += s_inc;

+            }

+            break;

+         }

+

+         case 2:

+         {

+            png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);

+            png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);

+            int sshift, dshift;

+            int s_start, s_end, s_inc;

+            int jstop = png_pass_inc[pass];

+            png_uint_32 i;

+

+#ifdef PNG_READ_PACKSWAP_SUPPORTED

+            if (transformations & PNG_PACKSWAP)

+            {

+               sshift = (int)(((row_info->width + 3) & 0x03) << 1);

+               dshift = (int)(((final_width + 3) & 0x03) << 1);

+               s_start = 6;

+               s_end = 0;

+               s_inc = -2;

+            }

+

+            else

+#endif

+            {

+               sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);

+               dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);

+               s_start = 0;

+               s_end = 6;

+               s_inc = 2;

+            }

+

+            for (i = 0; i < row_info->width; i++)

+            {

+               png_byte v;

+               int j;

+

+               v = (png_byte)((*sp >> sshift) & 0x03);

+               for (j = 0; j < jstop; j++)

+               {

+                  unsigned int tmp = *dp & (0x3f3f >> (6 - dshift));

+                  tmp |= v << dshift;

+                  *dp = (png_byte)(tmp & 0xff);

+

+                  if (dshift == s_end)

+                  {

+                     dshift = s_start;

+                     dp--;

+                  }

+

+                  else

+                     dshift += s_inc;

+               }

+

+               if (sshift == s_end)

+               {

+                  sshift = s_start;

+                  sp--;

+               }

+

+               else

+                  sshift += s_inc;

+            }

+            break;

+         }

+

+         case 4:

+         {

+            png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);

+            png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);

+            int sshift, dshift;

+            int s_start, s_end, s_inc;

+            png_uint_32 i;

+            int jstop = png_pass_inc[pass];

+

+#ifdef PNG_READ_PACKSWAP_SUPPORTED

+            if (transformations & PNG_PACKSWAP)

+            {

+               sshift = (int)(((row_info->width + 1) & 0x01) << 2);

+               dshift = (int)(((final_width + 1) & 0x01) << 2);

+               s_start = 4;

+               s_end = 0;

+               s_inc = -4;

+            }

+

+            else

+#endif

+            {

+               sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);

+               dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);

+               s_start = 0;

+               s_end = 4;

+               s_inc = 4;

+            }

+

+            for (i = 0; i < row_info->width; i++)

+            {

+               png_byte v = (png_byte)((*sp >> sshift) & 0x0f);

+               int j;

+

+               for (j = 0; j < jstop; j++)

+               {

+                  unsigned int tmp = *dp & (0xf0f >> (4 - dshift));

+                  tmp |= v << dshift;

+                  *dp = (png_byte)(tmp & 0xff);

+

+                  if (dshift == s_end)

+                  {

+                     dshift = s_start;

+                     dp--;

+                  }

+

+                  else

+                     dshift += s_inc;

+               }

+

+               if (sshift == s_end)

+               {

+                  sshift = s_start;

+                  sp--;

+               }

+

+               else

+                  sshift += s_inc;

+            }

+            break;

+         }

+

+         default:

+         {

+            png_size_t pixel_bytes = (row_info->pixel_depth >> 3);

+

+            png_bytep sp = row + (png_size_t)(row_info->width - 1)

+                * pixel_bytes;

+

+            png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;

+

+            int jstop = png_pass_inc[pass];

+            png_uint_32 i;

+

+            for (i = 0; i < row_info->width; i++)

+            {

+               png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */

+               int j;

+

+               memcpy(v, sp, pixel_bytes);

+

+               for (j = 0; j < jstop; j++)

+               {

+                  memcpy(dp, v, pixel_bytes);

+                  dp -= pixel_bytes;

+               }

+

+               sp -= pixel_bytes;

+            }

+            break;

+         }

+      }

+

+      row_info->width = final_width;

+      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);

+   }

+#ifndef PNG_READ_PACKSWAP_SUPPORTED

+   PNG_UNUSED(transformations)  /* Silence compiler warning */

+#endif

+}

+#endif /* PNG_READ_INTERLACING_SUPPORTED */

+

+static void

+png_read_filter_row_sub(png_row_infop row_info, png_bytep row,

+   png_const_bytep prev_row)

+{

+   png_size_t i;

+   png_size_t istop = row_info->rowbytes;

+   unsigned int bpp = (row_info->pixel_depth + 7) >> 3;

+   png_bytep rp = row + bpp;

+

+   PNG_UNUSED(prev_row)

+

+   for (i = bpp; i < istop; i++)

+   {

+      *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);

+      rp++;

+   }

+}

+

+static void

+png_read_filter_row_up(png_row_infop row_info, png_bytep row,

+   png_const_bytep prev_row)

+{

+   png_size_t i;

+   png_size_t istop = row_info->rowbytes;

+   png_bytep rp = row;

+   png_const_bytep pp = prev_row;

+

+   for (i = 0; i < istop; i++)

+   {

+      *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);

+      rp++;

+   }

+}

+

+static void

+png_read_filter_row_avg(png_row_infop row_info, png_bytep row,

+   png_const_bytep prev_row)

+{

+   png_size_t i;

+   png_bytep rp = row;

+   png_const_bytep pp = prev_row;

+   unsigned int bpp = (row_info->pixel_depth + 7) >> 3;

+   png_size_t istop = row_info->rowbytes - bpp;

+

+   for (i = 0; i < bpp; i++)

+   {

+      *rp = (png_byte)(((int)(*rp) +

+         ((int)(*pp++) / 2 )) & 0xff);

+

+      rp++;

+   }

+

+   for (i = 0; i < istop; i++)

+   {

+      *rp = (png_byte)(((int)(*rp) +

+         (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);

+

+      rp++;

+   }

+}

+

+static void

+png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row,

+   png_const_bytep prev_row)

+{

+   png_bytep rp_end = row + row_info->rowbytes;

+   int a, c;

+

+   /* First pixel/byte */

+   c = *prev_row++;

+   a = *row + c;

+   *row++ = (png_byte)a;

+

+   /* Remainder */

+   while (row < rp_end)

+   {

+      int b, pa, pb, pc, p;

+

+      a &= 0xff; /* From previous iteration or start */

+      b = *prev_row++;

+

+      p = b - c;

+      pc = a - c;

+

+#     ifdef PNG_USE_ABS

+         pa = abs(p);

+         pb = abs(pc);

+         pc = abs(p + pc);

+#     else

+         pa = p < 0 ? -p : p;

+         pb = pc < 0 ? -pc : pc;

+         pc = (p + pc) < 0 ? -(p + pc) : p + pc;

+#     endif

+

+      /* Find the best predictor, the least of pa, pb, pc favoring the earlier

+       * ones in the case of a tie.

+       */

+      if (pb < pa) pa = pb, a = b;

+      if (pc < pa) a = c;

+

+      /* Calculate the current pixel in a, and move the previous row pixel to c

+       * for the next time round the loop

+       */

+      c = b;

+      a += *row;

+      *row++ = (png_byte)a;

+   }

+}

+

+static void

+png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,

+   png_const_bytep prev_row)

+{

+   int bpp = (row_info->pixel_depth + 7) >> 3;

+   png_bytep rp_end = row + bpp;

+

+   /* Process the first pixel in the row completely (this is the same as 'up'

+    * because there is only one candidate predictor for the first row).

+    */

+   while (row < rp_end)

+   {

+      int a = *row + *prev_row++;

+      *row++ = (png_byte)a;

+   }

+

+   /* Remainder */

+   rp_end += row_info->rowbytes - bpp;

+

+   while (row < rp_end)

+   {

+      int a, b, c, pa, pb, pc, p;

+

+      c = *(prev_row - bpp);

+      a = *(row - bpp);

+      b = *prev_row++;

+

+      p = b - c;

+      pc = a - c;

+

+#     ifdef PNG_USE_ABS

+         pa = abs(p);

+         pb = abs(pc);

+         pc = abs(p + pc);

+#     else

+         pa = p < 0 ? -p : p;

+         pb = pc < 0 ? -pc : pc;

+         pc = (p + pc) < 0 ? -(p + pc) : p + pc;

+#     endif

+

+      if (pb < pa) pa = pb, a = b;

+      if (pc < pa) a = c;

+

+      c = b;

+      a += *row;

+      *row++ = (png_byte)a;

+   }

+}

+

+static void

+png_init_filter_functions(png_structrp pp)

+   /* This function is called once for every PNG image to set the

+    * implementations required to reverse the filtering of PNG rows.  Reversing

+    * the filter is the first transformation performed on the row data.  It is

+    * performed in place, therefore an implementation can be selected based on

+    * the image pixel format.  If the implementation depends on image width then

+    * take care to ensure that it works correctly if the image is interlaced -

+    * interlacing causes the actual row width to vary.

+    */

+{

+   unsigned int bpp = (pp->pixel_depth + 7) >> 3;

+

+   pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub;

+   pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up;

+   pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg;

+   if (bpp == 1)

+      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =

+         png_read_filter_row_paeth_1byte_pixel;

+   else

+      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =

+         png_read_filter_row_paeth_multibyte_pixel;

+

+#ifdef PNG_FILTER_OPTIMIZATIONS

+   /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to

+    * call to install hardware optimizations for the above functions; simply

+    * replace whatever elements of the pp->read_filter[] array with a hardware

+    * specific (or, for that matter, generic) optimization.

+    *

+    * To see an example of this examine what configure.ac does when

+    * --enable-arm-neon is specified on the command line.

+    */

+   PNG_FILTER_OPTIMIZATIONS(pp, bpp);

+#endif

+}

+

+void /* PRIVATE */

+png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row,

+   png_const_bytep prev_row, int filter)

+{

+   /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define

+    * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic

+    * implementations.  See png_init_filter_functions above.

+    */

+   if (pp->read_filter[0] == NULL)

+      png_init_filter_functions(pp);

+   if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST)

+      pp->read_filter[filter-1](row_info, row, prev_row);

+}

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+void /* PRIVATE */

+png_read_IDAT_data(png_structrp png_ptr, png_bytep output,

+   png_alloc_size_t avail_out)

+{

+   /* Loop reading IDATs and decompressing the result into output[avail_out] */

+   png_ptr->zstream.next_out = output;

+   png_ptr->zstream.avail_out = 0; /* safety: set below */

+

+   if (output == NULL)

+      avail_out = 0;

+

+   do

+   {

+      int ret;

+      png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];

+

+      if (png_ptr->zstream.avail_in == 0)

+      {

+         uInt avail_in;

+         png_bytep buffer;

+

+         while (png_ptr->idat_size == 0)

+         {

+            png_crc_finish(png_ptr, 0);

+

+            png_ptr->idat_size = png_read_chunk_header(png_ptr);

+            /* This is an error even in the 'check' case because the code just

+             * consumed a non-IDAT header.

+             */

+            if (png_ptr->chunk_name != png_IDAT)

+               png_error(png_ptr, "Not enough image data");

+         }

+

+         avail_in = png_ptr->IDAT_read_size;

+

+         if (avail_in > png_ptr->idat_size)

+            avail_in = (uInt)png_ptr->idat_size;

+

+         /* A PNG with a gradually increasing IDAT size will defeat this attempt

+          * to minimize memory usage by causing lots of re-allocs, but

+          * realistically doing IDAT_read_size re-allocs is not likely to be a

+          * big problem.

+          */

+         buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/);

+

+         png_crc_read(png_ptr, buffer, avail_in);

+         png_ptr->idat_size -= avail_in;

+

+         png_ptr->zstream.next_in = buffer;

+         png_ptr->zstream.avail_in = avail_in;

+      }

+

+      /* And set up the output side. */

+      if (output != NULL) /* standard read */

+      {

+         uInt out = ZLIB_IO_MAX;

+

+         if (out > avail_out)

+            out = (uInt)avail_out;

+

+         avail_out -= out;

+         png_ptr->zstream.avail_out = out;

+      }

+

+      else /* after last row, checking for end */

+      {

+         png_ptr->zstream.next_out = tmpbuf;

+         png_ptr->zstream.avail_out = (sizeof tmpbuf);

+      }

+

+      /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the

+       * process.  If the LZ stream is truncated the sequential reader will

+       * terminally damage the stream, above, by reading the chunk header of the

+       * following chunk (it then exits with png_error).

+       *

+       * TODO: deal more elegantly with truncated IDAT lists.

+       */

+      ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);

+

+      /* Take the unconsumed output back. */

+      if (output != NULL)

+         avail_out += png_ptr->zstream.avail_out;

+

+      else /* avail_out counts the extra bytes */

+         avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out;

+

+      png_ptr->zstream.avail_out = 0;

+

+      if (ret == Z_STREAM_END)

+      {

+         /* Do this for safety; we won't read any more into this row. */

+         png_ptr->zstream.next_out = NULL;

+

+         png_ptr->mode |= PNG_AFTER_IDAT;

+         png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;

+

+         if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)

+            png_chunk_benign_error(png_ptr, "Extra compressed data");

+         break;

+      }

+

+      if (ret != Z_OK)

+      {

+         png_zstream_error(png_ptr, ret);

+

+         if (output != NULL)

+            png_chunk_error(png_ptr, png_ptr->zstream.msg);

+

+         else /* checking */

+         {

+            png_chunk_benign_error(png_ptr, png_ptr->zstream.msg);

+            return;

+         }

+      }

+   } while (avail_out > 0);

+

+   if (avail_out > 0)

+   {

+      /* The stream ended before the image; this is the same as too few IDATs so

+       * should be handled the same way.

+       */

+      if (output != NULL)

+         png_error(png_ptr, "Not enough image data");

+

+      else /* the deflate stream contained extra data */

+         png_chunk_benign_error(png_ptr, "Too much image data");

+   }

+}

+

+void /* PRIVATE */

+png_read_finish_IDAT(png_structrp png_ptr)

+{

+   /* We don't need any more data and the stream should have ended, however the

+    * LZ end code may actually not have been processed.  In this case we must

+    * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk

+    * may still remain to be consumed.

+    */

+   if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))

+   {

+      /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in

+       * the compressed stream, but the stream may be damaged too, so even after

+       * this call we may need to terminate the zstream ownership.

+       */

+      png_read_IDAT_data(png_ptr, NULL, 0);

+      png_ptr->zstream.next_out = NULL; /* safety */

+

+      /* Now clear everything out for safety; the following may not have been

+       * done.

+       */

+      if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))

+      {

+         png_ptr->mode |= PNG_AFTER_IDAT;

+         png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;

+      }

+   }

+

+   /* If the zstream has not been released do it now *and* terminate the reading

+    * of the final IDAT chunk.

+    */

+   if (png_ptr->zowner == png_IDAT)

+   {

+      /* Always do this; the pointers otherwise point into the read buffer. */

+      png_ptr->zstream.next_in = NULL;

+      png_ptr->zstream.avail_in = 0;

+

+      /* Now we no longer own the zstream. */

+      png_ptr->zowner = 0;

+

+      /* The slightly weird semantics of the sequential IDAT reading is that we

+       * are always in or at the end of an IDAT chunk, so we always need to do a

+       * crc_finish here.  If idat_size is non-zero we also need to read the

+       * spurious bytes at the end of the chunk now.

+       */

+      (void)png_crc_finish(png_ptr, png_ptr->idat_size);

+   }

+}

+

+void /* PRIVATE */

+png_read_finish_row(png_structrp png_ptr)

+{

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */

+

+   /* Start of interlace block */

+   static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};

+

+   /* Offset to next interlace block */

+   static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};

+

+   /* Start of interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};

+

+   /* Offset to next interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};

+#endif /* PNG_READ_INTERLACING_SUPPORTED */

+

+   png_debug(1, "in png_read_finish_row");

+   png_ptr->row_number++;

+   if (png_ptr->row_number < png_ptr->num_rows)

+      return;

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   if (png_ptr->interlaced)

+   {

+      png_ptr->row_number = 0;

+

+      /* TO DO: don't do this if prev_row isn't needed (requires

+       * read-ahead of the next row's filter byte.

+       */

+      memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);

+

+      do

+      {

+         png_ptr->pass++;

+

+         if (png_ptr->pass >= 7)

+            break;

+

+         png_ptr->iwidth = (png_ptr->width +

+            png_pass_inc[png_ptr->pass] - 1 -

+            png_pass_start[png_ptr->pass]) /

+            png_pass_inc[png_ptr->pass];

+

+         if (!(png_ptr->transformations & PNG_INTERLACE))

+         {

+            png_ptr->num_rows = (png_ptr->height +

+                png_pass_yinc[png_ptr->pass] - 1 -

+                png_pass_ystart[png_ptr->pass]) /

+                png_pass_yinc[png_ptr->pass];

+         }

+

+         else  /* if (png_ptr->transformations & PNG_INTERLACE) */

+            break; /* libpng deinterlacing sees every row */

+

+      } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0);

+

+      if (png_ptr->pass < 7)

+         return;

+   }

+#endif /* PNG_READ_INTERLACING_SUPPORTED */

+

+   /* Here after at the end of the last row of the last pass. */

+   png_read_finish_IDAT(png_ptr);

+}

+#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */

+

+void /* PRIVATE */

+png_read_start_row(png_structrp png_ptr)

+{

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */

+

+   /* Start of interlace block */

+   static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};

+

+   /* Offset to next interlace block */

+   static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};

+

+   /* Start of interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};

+

+   /* Offset to next interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};

+#endif

+

+   int max_pixel_depth;

+   png_size_t row_bytes;

+

+   png_debug(1, "in png_read_start_row");

+

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+   png_init_read_transformations(png_ptr);

+#endif

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+   if (png_ptr->interlaced)

+   {

+      if (!(png_ptr->transformations & PNG_INTERLACE))

+         png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -

+             png_pass_ystart[0]) / png_pass_yinc[0];

+

+      else

+         png_ptr->num_rows = png_ptr->height;

+

+      png_ptr->iwidth = (png_ptr->width +

+          png_pass_inc[png_ptr->pass] - 1 -

+          png_pass_start[png_ptr->pass]) /

+          png_pass_inc[png_ptr->pass];

+   }

+

+   else

+#endif /* PNG_READ_INTERLACING_SUPPORTED */

+   {

+      png_ptr->num_rows = png_ptr->height;

+      png_ptr->iwidth = png_ptr->width;

+   }

+

+   max_pixel_depth = png_ptr->pixel_depth;

+

+   /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of

+    * calculations to calculate the final pixel depth, then

+    * png_do_read_transforms actually does the transforms.  This means that the

+    * code which effectively calculates this value is actually repeated in three

+    * separate places.  They must all match.  Innocent changes to the order of

+    * transformations can and will break libpng in a way that causes memory

+    * overwrites.

+    *

+    * TODO: fix this.

+    */

+#ifdef PNG_READ_PACK_SUPPORTED

+   if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)

+      max_pixel_depth = 8;

+#endif

+

+#ifdef PNG_READ_EXPAND_SUPPORTED

+   if (png_ptr->transformations & PNG_EXPAND)

+   {

+      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      {

+         if (png_ptr->num_trans)

+            max_pixel_depth = 32;

+

+         else

+            max_pixel_depth = 24;

+      }

+

+      else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)

+      {

+         if (max_pixel_depth < 8)

+            max_pixel_depth = 8;

+

+         if (png_ptr->num_trans)

+            max_pixel_depth *= 2;

+      }

+

+      else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)

+      {

+         if (png_ptr->num_trans)

+         {

+            max_pixel_depth *= 4;

+            max_pixel_depth /= 3;

+         }

+      }

+   }

+#endif

+

+#ifdef PNG_READ_EXPAND_16_SUPPORTED

+   if (png_ptr->transformations & PNG_EXPAND_16)

+   {

+#     ifdef PNG_READ_EXPAND_SUPPORTED

+         /* In fact it is an error if it isn't supported, but checking is

+          * the safe way.

+          */

+         if (png_ptr->transformations & PNG_EXPAND)

+         {

+            if (png_ptr->bit_depth < 16)

+               max_pixel_depth *= 2;

+         }

+         else

+#     endif

+         png_ptr->transformations &= ~PNG_EXPAND_16;

+   }

+#endif

+

+#ifdef PNG_READ_FILLER_SUPPORTED

+   if (png_ptr->transformations & (PNG_FILLER))

+   {

+      if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)

+      {

+         if (max_pixel_depth <= 8)

+            max_pixel_depth = 16;

+

+         else

+            max_pixel_depth = 32;

+      }

+

+      else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB ||

+         png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      {

+         if (max_pixel_depth <= 32)

+            max_pixel_depth = 32;

+

+         else

+            max_pixel_depth = 64;

+      }

+   }

+#endif

+

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+   if (png_ptr->transformations & PNG_GRAY_TO_RGB)

+   {

+      if (

+#ifdef PNG_READ_EXPAND_SUPPORTED

+          (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||

+#endif

+#ifdef PNG_READ_FILLER_SUPPORTED

+          (png_ptr->transformations & (PNG_FILLER)) ||

+#endif

+          png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

+      {

+         if (max_pixel_depth <= 16)

+            max_pixel_depth = 32;

+

+         else

+            max_pixel_depth = 64;

+      }

+

+      else

+      {

+         if (max_pixel_depth <= 8)

+         {

+            if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+               max_pixel_depth = 32;

+

+            else

+               max_pixel_depth = 24;

+         }

+

+         else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+            max_pixel_depth = 64;

+

+         else

+            max_pixel_depth = 48;

+      }

+   }

+#endif

+

+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \

+defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)

+   if (png_ptr->transformations & PNG_USER_TRANSFORM)

+   {

+      int user_pixel_depth = png_ptr->user_transform_depth *

+         png_ptr->user_transform_channels;

+

+      if (user_pixel_depth > max_pixel_depth)

+         max_pixel_depth = user_pixel_depth;

+   }

+#endif

+

+   /* This value is stored in png_struct and double checked in the row read

+    * code.

+    */

+   png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth;

+   png_ptr->transformed_pixel_depth = 0; /* calculated on demand */

+

+   /* Align the width on the next larger 8 pixels.  Mainly used

+    * for interlacing

+    */

+   row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));

+   /* Calculate the maximum bytes needed, adding a byte and a pixel

+    * for safety's sake

+    */

+   row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +

+       1 + ((max_pixel_depth + 7) >> 3);

+

+#ifdef PNG_MAX_MALLOC_64K

+   if (row_bytes > (png_uint_32)65536L)

+      png_error(png_ptr, "This image requires a row greater than 64KB");

+#endif

+

+   if (row_bytes + 48 > png_ptr->old_big_row_buf_size)

+   {

+     png_free(png_ptr, png_ptr->big_row_buf);

+     png_free(png_ptr, png_ptr->big_prev_row);

+

+     if (png_ptr->interlaced)

+        png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,

+            row_bytes + 48);

+

+     else

+        png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48);

+

+     png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48);

+

+#ifdef PNG_ALIGNED_MEMORY_SUPPORTED

+     /* Use 16-byte aligned memory for row_buf with at least 16 bytes

+      * of padding before and after row_buf; treat prev_row similarly.

+      * NOTE: the alignment is to the start of the pixels, one beyond the start

+      * of the buffer, because of the filter byte.  Prior to libpng 1.5.6 this

+      * was incorrect; the filter byte was aligned, which had the exact

+      * opposite effect of that intended.

+      */

+     {

+        png_bytep temp = png_ptr->big_row_buf + 32;

+        int extra = (int)((temp - (png_bytep)0) & 0x0f);

+        png_ptr->row_buf = temp - extra - 1/*filter byte*/;

+

+        temp = png_ptr->big_prev_row + 32;

+        extra = (int)((temp - (png_bytep)0) & 0x0f);

+        png_ptr->prev_row = temp - extra - 1/*filter byte*/;

+     }

+

+#else

+     /* Use 31 bytes of padding before and 17 bytes after row_buf. */

+     png_ptr->row_buf = png_ptr->big_row_buf + 31;

+     png_ptr->prev_row = png_ptr->big_prev_row + 31;

+#endif

+     png_ptr->old_big_row_buf_size = row_bytes + 48;

+   }

+

+#ifdef PNG_MAX_MALLOC_64K

+   if (png_ptr->rowbytes > 65535)

+      png_error(png_ptr, "This image requires a row greater than 64KB");

+

+#endif

+   if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))

+      png_error(png_ptr, "Row has too many bytes to allocate in memory");

+

+   memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);

+

+   png_debug1(3, "width = %u,", png_ptr->width);

+   png_debug1(3, "height = %u,", png_ptr->height);

+   png_debug1(3, "iwidth = %u,", png_ptr->iwidth);

+   png_debug1(3, "num_rows = %u,", png_ptr->num_rows);

+   png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes);

+   png_debug1(3, "irowbytes = %lu",

+       (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);

+

+   /* The sequential reader needs a buffer for IDAT, but the progressive reader

+    * does not, so free the read buffer now regardless; the sequential reader

+    * reallocates it on demand.

+    */

+   if (png_ptr->read_buffer)

+   {

+      png_bytep buffer = png_ptr->read_buffer;

+

+      png_ptr->read_buffer_size = 0;

+      png_ptr->read_buffer = NULL;

+      png_free(png_ptr, buffer);

+   }

+

+   /* Finally claim the zstream for the inflate of the IDAT data, use the bits

+    * value from the stream (note that this will result in a fatal error if the

+    * IDAT stream has a bogus deflate header window_bits value, but this should

+    * not be happening any longer!)

+    */

+   if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK)

+      png_error(png_ptr, png_ptr->zstream.msg);

+

+   png_ptr->flags |= PNG_FLAG_ROW_INIT;

+}

+#endif /* PNG_READ_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngset.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngset.c
new file mode 100644
index 0000000..8fd7445
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngset.c
@@ -0,0 +1,1598 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngset.c - storage of image information into info struct

+ *

+ * Last changed in libpng 1.6.3 [July 18, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ * The functions here are used during reads to store data from the file

+ * into the info struct, and during writes to store application data

+ * into the info struct for writing into the file.  This abstracts the

+ * info struct and allows us to change the structure in the future.

+ */

+

+#include "pngpriv.h"

+

+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

+

+#ifdef PNG_bKGD_SUPPORTED

+void PNGAPI

+png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_const_color_16p background)

+{

+   png_debug1(1, "in %s storage function", "bKGD");

+

+   if (png_ptr == NULL || info_ptr == NULL || background == NULL)

+      return;

+

+   info_ptr->background = *background;

+   info_ptr->valid |= PNG_INFO_bKGD;

+}

+#endif

+

+#ifdef PNG_cHRM_SUPPORTED

+void PNGFAPI

+png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,

+    png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,

+    png_fixed_point blue_x, png_fixed_point blue_y)

+{

+   png_xy xy;

+

+   png_debug1(1, "in %s storage function", "cHRM fixed");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   xy.redx = red_x;

+   xy.redy = red_y;

+   xy.greenx = green_x;

+   xy.greeny = green_y;

+   xy.bluex = blue_x;

+   xy.bluey = blue_y;

+   xy.whitex = white_x;

+   xy.whitey = white_y;

+

+   if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy,

+      2/* override with app values*/))

+      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;

+

+   png_colorspace_sync_info(png_ptr, info_ptr);

+}

+

+void PNGFAPI

+png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_fixed_point int_red_X, png_fixed_point int_red_Y,

+    png_fixed_point int_red_Z, png_fixed_point int_green_X,

+    png_fixed_point int_green_Y, png_fixed_point int_green_Z,

+    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,

+    png_fixed_point int_blue_Z)

+{

+   png_XYZ XYZ;

+

+   png_debug1(1, "in %s storage function", "cHRM XYZ fixed");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   XYZ.red_X = int_red_X;

+   XYZ.red_Y = int_red_Y;

+   XYZ.red_Z = int_red_Z;

+   XYZ.green_X = int_green_X;

+   XYZ.green_Y = int_green_Y;

+   XYZ.green_Z = int_green_Z;

+   XYZ.blue_X = int_blue_X;

+   XYZ.blue_Y = int_blue_Y;

+   XYZ.blue_Z = int_blue_Z;

+

+   if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, &XYZ, 2))

+      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;

+

+   png_colorspace_sync_info(png_ptr, info_ptr);

+}

+

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+void PNGAPI

+png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,

+    double white_x, double white_y, double red_x, double red_y,

+    double green_x, double green_y, double blue_x, double blue_y)

+{

+   png_set_cHRM_fixed(png_ptr, info_ptr,

+      png_fixed(png_ptr, white_x, "cHRM White X"),

+      png_fixed(png_ptr, white_y, "cHRM White Y"),

+      png_fixed(png_ptr, red_x, "cHRM Red X"),

+      png_fixed(png_ptr, red_y, "cHRM Red Y"),

+      png_fixed(png_ptr, green_x, "cHRM Green X"),

+      png_fixed(png_ptr, green_y, "cHRM Green Y"),

+      png_fixed(png_ptr, blue_x, "cHRM Blue X"),

+      png_fixed(png_ptr, blue_y, "cHRM Blue Y"));

+}

+

+void PNGAPI

+png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,

+    double red_Y, double red_Z, double green_X, double green_Y, double green_Z,

+    double blue_X, double blue_Y, double blue_Z)

+{

+   png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,

+      png_fixed(png_ptr, red_X, "cHRM Red X"),

+      png_fixed(png_ptr, red_Y, "cHRM Red Y"),

+      png_fixed(png_ptr, red_Z, "cHRM Red Z"),

+      png_fixed(png_ptr, green_X, "cHRM Red X"),

+      png_fixed(png_ptr, green_Y, "cHRM Red Y"),

+      png_fixed(png_ptr, green_Z, "cHRM Red Z"),

+      png_fixed(png_ptr, blue_X, "cHRM Red X"),

+      png_fixed(png_ptr, blue_Y, "cHRM Red Y"),

+      png_fixed(png_ptr, blue_Z, "cHRM Red Z"));

+}

+#  endif /* PNG_FLOATING_POINT_SUPPORTED */

+

+#endif /* PNG_cHRM_SUPPORTED */

+

+#ifdef PNG_gAMA_SUPPORTED

+void PNGFAPI

+png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_fixed_point file_gamma)

+{

+   png_debug1(1, "in %s storage function", "gAMA");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);

+   png_colorspace_sync_info(png_ptr, info_ptr);

+}

+

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+void PNGAPI

+png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)

+{

+   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,

+       "png_set_gAMA"));

+}

+#  endif

+#endif

+

+#ifdef PNG_hIST_SUPPORTED

+void PNGAPI

+png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_const_uint_16p hist)

+{

+   int i;

+

+   png_debug1(1, "in %s storage function", "hIST");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   if (info_ptr->num_palette == 0 || info_ptr->num_palette

+       > PNG_MAX_PALETTE_LENGTH)

+   {

+      png_warning(png_ptr,

+          "Invalid palette size, hIST allocation skipped");

+

+      return;

+   }

+

+   png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);

+

+   /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in

+    * version 1.2.1

+    */

+   info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,

+       PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));

+

+   if (info_ptr->hist == NULL)

+   {

+      png_warning(png_ptr, "Insufficient memory for hIST chunk data");

+      return;

+   }

+

+   info_ptr->free_me |= PNG_FREE_HIST;

+

+   for (i = 0; i < info_ptr->num_palette; i++)

+      info_ptr->hist[i] = hist[i];

+

+   info_ptr->valid |= PNG_INFO_hIST;

+}

+#endif

+

+void PNGAPI

+png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_uint_32 width, png_uint_32 height, int bit_depth,

+    int color_type, int interlace_type, int compression_type,

+    int filter_type)

+{

+   png_debug1(1, "in %s storage function", "IHDR");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   info_ptr->width = width;

+   info_ptr->height = height;

+   info_ptr->bit_depth = (png_byte)bit_depth;

+   info_ptr->color_type = (png_byte)color_type;

+   info_ptr->compression_type = (png_byte)compression_type;

+   info_ptr->filter_type = (png_byte)filter_type;

+   info_ptr->interlace_type = (png_byte)interlace_type;

+

+   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,

+       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,

+       info_ptr->compression_type, info_ptr->filter_type);

+

+   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      info_ptr->channels = 1;

+

+   else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)

+      info_ptr->channels = 3;

+

+   else

+      info_ptr->channels = 1;

+

+   if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)

+      info_ptr->channels++;

+

+   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);

+

+   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);

+}

+

+#ifdef PNG_oFFs_SUPPORTED

+void PNGAPI

+png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_int_32 offset_x, png_int_32 offset_y, int unit_type)

+{

+   png_debug1(1, "in %s storage function", "oFFs");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   info_ptr->x_offset = offset_x;

+   info_ptr->y_offset = offset_y;

+   info_ptr->offset_unit_type = (png_byte)unit_type;

+   info_ptr->valid |= PNG_INFO_oFFs;

+}

+#endif

+

+#ifdef PNG_pCAL_SUPPORTED

+void PNGAPI

+png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,

+    int nparams, png_const_charp units, png_charpp params)

+{

+   png_size_t length;

+   int i;

+

+   png_debug1(1, "in %s storage function", "pCAL");

+

+   if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL

+      || (nparams > 0 && params == NULL))

+      return;

+

+   length = strlen(purpose) + 1;

+   png_debug1(3, "allocating purpose for info (%lu bytes)",

+       (unsigned long)length);

+

+   /* TODO: validate format of calibration name and unit name */

+

+   /* Check that the type matches the specification. */

+   if (type < 0 || type > 3)

+      png_error(png_ptr, "Invalid pCAL equation type");

+

+   if (nparams < 0 || nparams > 255)

+      png_error(png_ptr, "Invalid pCAL parameter count");

+

+   /* Validate params[nparams] */

+   for (i=0; i<nparams; ++i)

+      if (params[i] == NULL ||

+         !png_check_fp_string(params[i], strlen(params[i])))

+         png_error(png_ptr, "Invalid format for pCAL parameter");

+

+   info_ptr->pcal_purpose = png_voidcast(png_charp,

+      png_malloc_warn(png_ptr, length));

+

+   if (info_ptr->pcal_purpose == NULL)

+   {

+      png_warning(png_ptr, "Insufficient memory for pCAL purpose");

+      return;

+   }

+

+   memcpy(info_ptr->pcal_purpose, purpose, length);

+

+   png_debug(3, "storing X0, X1, type, and nparams in info");

+   info_ptr->pcal_X0 = X0;

+   info_ptr->pcal_X1 = X1;

+   info_ptr->pcal_type = (png_byte)type;

+   info_ptr->pcal_nparams = (png_byte)nparams;

+

+   length = strlen(units) + 1;

+   png_debug1(3, "allocating units for info (%lu bytes)",

+     (unsigned long)length);

+

+   info_ptr->pcal_units = png_voidcast(png_charp,

+      png_malloc_warn(png_ptr, length));

+

+   if (info_ptr->pcal_units == NULL)

+   {

+      png_warning(png_ptr, "Insufficient memory for pCAL units");

+      return;

+   }

+

+   memcpy(info_ptr->pcal_units, units, length);

+

+   info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,

+       (png_size_t)((nparams + 1) * (sizeof (png_charp)))));

+

+   if (info_ptr->pcal_params == NULL)

+   {

+      png_warning(png_ptr, "Insufficient memory for pCAL params");

+      return;

+   }

+

+   memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp)));

+

+   for (i = 0; i < nparams; i++)

+   {

+      length = strlen(params[i]) + 1;

+      png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,

+          (unsigned long)length);

+

+      info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);

+

+      if (info_ptr->pcal_params[i] == NULL)

+      {

+         png_warning(png_ptr, "Insufficient memory for pCAL parameter");

+         return;

+      }

+

+      memcpy(info_ptr->pcal_params[i], params[i], length);

+   }

+

+   info_ptr->valid |= PNG_INFO_pCAL;

+   info_ptr->free_me |= PNG_FREE_PCAL;

+}

+#endif

+

+#ifdef PNG_sCAL_SUPPORTED

+void PNGAPI

+png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,

+    int unit, png_const_charp swidth, png_const_charp sheight)

+{

+   png_size_t lengthw = 0, lengthh = 0;

+

+   png_debug1(1, "in %s storage function", "sCAL");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   /* Double check the unit (should never get here with an invalid

+    * unit unless this is an API call.)

+    */

+   if (unit != 1 && unit != 2)

+      png_error(png_ptr, "Invalid sCAL unit");

+

+   if (swidth == NULL || (lengthw = strlen(swidth)) == 0 ||

+       swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))

+      png_error(png_ptr, "Invalid sCAL width");

+

+   if (sheight == NULL || (lengthh = strlen(sheight)) == 0 ||

+       sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))

+      png_error(png_ptr, "Invalid sCAL height");

+

+   info_ptr->scal_unit = (png_byte)unit;

+

+   ++lengthw;

+

+   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw);

+

+   info_ptr->scal_s_width = png_voidcast(png_charp,

+      png_malloc_warn(png_ptr, lengthw));

+

+   if (info_ptr->scal_s_width == NULL)

+   {

+      png_warning(png_ptr, "Memory allocation failed while processing sCAL");

+      return;

+   }

+

+   memcpy(info_ptr->scal_s_width, swidth, lengthw);

+

+   ++lengthh;

+

+   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh);

+

+   info_ptr->scal_s_height = png_voidcast(png_charp,

+      png_malloc_warn(png_ptr, lengthh));

+

+   if (info_ptr->scal_s_height == NULL)

+   {

+      png_free (png_ptr, info_ptr->scal_s_width);

+      info_ptr->scal_s_width = NULL;

+

+      png_warning(png_ptr, "Memory allocation failed while processing sCAL");

+      return;

+   }

+

+   memcpy(info_ptr->scal_s_height, sheight, lengthh);

+

+   info_ptr->valid |= PNG_INFO_sCAL;

+   info_ptr->free_me |= PNG_FREE_SCAL;

+}

+

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+void PNGAPI

+png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit,

+    double width, double height)

+{

+   png_debug1(1, "in %s storage function", "sCAL");

+

+   /* Check the arguments. */

+   if (width <= 0)

+      png_warning(png_ptr, "Invalid sCAL width ignored");

+

+   else if (height <= 0)

+      png_warning(png_ptr, "Invalid sCAL height ignored");

+

+   else

+   {

+      /* Convert 'width' and 'height' to ASCII. */

+      char swidth[PNG_sCAL_MAX_DIGITS+1];

+      char sheight[PNG_sCAL_MAX_DIGITS+1];

+

+      png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,

+         PNG_sCAL_PRECISION);

+      png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,

+         PNG_sCAL_PRECISION);

+

+      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);

+   }

+}

+#  endif

+

+#  ifdef PNG_FIXED_POINT_SUPPORTED

+void PNGAPI

+png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit,

+    png_fixed_point width, png_fixed_point height)

+{

+   png_debug1(1, "in %s storage function", "sCAL");

+

+   /* Check the arguments. */

+   if (width <= 0)

+      png_warning(png_ptr, "Invalid sCAL width ignored");

+

+   else if (height <= 0)

+      png_warning(png_ptr, "Invalid sCAL height ignored");

+

+   else

+   {

+      /* Convert 'width' and 'height' to ASCII. */

+      char swidth[PNG_sCAL_MAX_DIGITS+1];

+      char sheight[PNG_sCAL_MAX_DIGITS+1];

+

+      png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);

+      png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);

+

+      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);

+   }

+}

+#  endif

+#endif

+

+#ifdef PNG_pHYs_SUPPORTED

+void PNGAPI

+png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_uint_32 res_x, png_uint_32 res_y, int unit_type)

+{

+   png_debug1(1, "in %s storage function", "pHYs");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   info_ptr->x_pixels_per_unit = res_x;

+   info_ptr->y_pixels_per_unit = res_y;

+   info_ptr->phys_unit_type = (png_byte)unit_type;

+   info_ptr->valid |= PNG_INFO_pHYs;

+}

+#endif

+

+void PNGAPI

+png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,

+    png_const_colorp palette, int num_palette)

+{

+

+   png_debug1(1, "in %s storage function", "PLTE");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)

+   {

+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+         png_error(png_ptr, "Invalid palette length");

+

+      else

+      {

+         png_warning(png_ptr, "Invalid palette length");

+         return;

+      }

+   }

+

+   if ((num_palette > 0 && palette == NULL) ||

+      (num_palette == 0

+#        ifdef PNG_MNG_FEATURES_SUPPORTED

+            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0

+#        endif

+      ))

+   {

+      png_chunk_report(png_ptr, "Invalid palette", PNG_CHUNK_ERROR);

+      return;

+   }

+

+   /* It may not actually be necessary to set png_ptr->palette here;

+    * we do it for backward compatibility with the way the png_handle_tRNS

+    * function used to do the allocation.

+    *

+    * 1.6.0: the above statement appears to be incorrect; something has to set

+    * the palette inside png_struct on read.

+    */

+   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);

+

+   /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead

+    * of num_palette entries, in case of an invalid PNG file that has

+    * too-large sample values.

+    */

+   png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,

+       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));

+

+   if (num_palette > 0)

+      memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color)));

+   info_ptr->palette = png_ptr->palette;

+   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;

+

+   info_ptr->free_me |= PNG_FREE_PLTE;

+

+   info_ptr->valid |= PNG_INFO_PLTE;

+}

+

+#ifdef PNG_sBIT_SUPPORTED

+void PNGAPI

+png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_const_color_8p sig_bit)

+{

+   png_debug1(1, "in %s storage function", "sBIT");

+

+   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)

+      return;

+

+   info_ptr->sig_bit = *sig_bit;

+   info_ptr->valid |= PNG_INFO_sBIT;

+}

+#endif

+

+#ifdef PNG_sRGB_SUPPORTED

+void PNGAPI

+png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)

+{

+   png_debug1(1, "in %s storage function", "sRGB");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);

+   png_colorspace_sync_info(png_ptr, info_ptr);

+}

+

+void PNGAPI

+png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,

+    int srgb_intent)

+{

+   png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent))

+   {

+      /* This causes the gAMA and cHRM to be written too */

+      info_ptr->colorspace.flags |=

+         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;

+   }

+

+   png_colorspace_sync_info(png_ptr, info_ptr);

+}

+#endif /* sRGB */

+

+

+#ifdef PNG_iCCP_SUPPORTED

+void PNGAPI

+png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_const_charp name, int compression_type,

+    png_const_bytep profile, png_uint_32 proflen)

+{

+   png_charp new_iccp_name;

+   png_bytep new_iccp_profile;

+   png_size_t length;

+

+   png_debug1(1, "in %s storage function", "iCCP");

+

+   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)

+      return;

+

+   if (compression_type != PNG_COMPRESSION_TYPE_BASE)

+      png_app_error(png_ptr, "Invalid iCCP compression method");

+

+   /* Set the colorspace first because this validates the profile; do not

+    * override previously set app cHRM or gAMA here (because likely as not the

+    * application knows better than libpng what the correct values are.)  Pass

+    * the info_ptr color_type field to png_colorspace_set_ICC because in the

+    * write case it has not yet been stored in png_ptr.

+    */

+   {

+      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,

+         proflen, profile, info_ptr->color_type);

+

+      png_colorspace_sync_info(png_ptr, info_ptr);

+

+      /* Don't do any of the copying if the profile was bad, or inconsistent. */

+      if (!result)

+         return;

+

+      /* But do write the gAMA and cHRM chunks from the profile. */

+      info_ptr->colorspace.flags |=

+         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;

+   }

+

+   length = strlen(name)+1;

+   new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));

+

+   if (new_iccp_name == NULL)

+   {

+      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");

+      return;

+   }

+

+   memcpy(new_iccp_name, name, length);

+   new_iccp_profile = png_voidcast(png_bytep,

+      png_malloc_warn(png_ptr, proflen));

+

+   if (new_iccp_profile == NULL)

+   {

+      png_free(png_ptr, new_iccp_name);

+      png_benign_error(png_ptr,

+          "Insufficient memory to process iCCP profile");

+      return;

+   }

+

+   memcpy(new_iccp_profile, profile, proflen);

+

+   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);

+

+   info_ptr->iccp_proflen = proflen;

+   info_ptr->iccp_name = new_iccp_name;

+   info_ptr->iccp_profile = new_iccp_profile;

+   info_ptr->free_me |= PNG_FREE_ICCP;

+   info_ptr->valid |= PNG_INFO_iCCP;

+}

+#endif

+

+#ifdef PNG_TEXT_SUPPORTED

+void PNGAPI

+png_set_text(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_const_textp text_ptr, int num_text)

+{

+   int ret;

+   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);

+

+   if (ret)

+      png_error(png_ptr, "Insufficient memory to store text");

+}

+

+int /* PRIVATE */

+png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_const_textp text_ptr, int num_text)

+{

+   int i;

+

+   png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" :

+      (unsigned long)png_ptr->chunk_name);

+

+   if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)

+      return(0);

+

+   /* Make sure we have enough space in the "text" array in info_struct

+    * to hold all of the incoming text_ptr objects.  This compare can't overflow

+    * because max_text >= num_text (anyway, subtract of two positive integers

+    * can't overflow in any case.)

+    */

+   if (num_text > info_ptr->max_text - info_ptr->num_text)

+   {

+      int old_num_text = info_ptr->num_text;

+      int max_text;

+      png_textp new_text = NULL;

+

+      /* Calculate an appropriate max_text, checking for overflow. */

+      max_text = old_num_text;

+      if (num_text <= INT_MAX - max_text)

+      {

+         max_text += num_text;

+

+         /* Round up to a multiple of 8 */

+         if (max_text < INT_MAX-8)

+            max_text = (max_text + 8) & ~0x7;

+

+         else

+            max_text = INT_MAX;

+

+         /* Now allocate a new array and copy the old members in, this does all

+          * the overflow checks.

+          */

+         new_text = png_voidcast(png_textp,png_realloc_array(png_ptr,

+            info_ptr->text, old_num_text, max_text-old_num_text,

+            sizeof *new_text));

+      }

+

+      if (new_text == NULL)

+      {

+         png_chunk_report(png_ptr, "too many text chunks",

+            PNG_CHUNK_WRITE_ERROR);

+         return 1;

+      }

+

+      png_free(png_ptr, info_ptr->text);

+

+      info_ptr->text = new_text;

+      info_ptr->free_me |= PNG_FREE_TEXT;

+      info_ptr->max_text = max_text;

+      /* num_text is adjusted below as the entries are copied in */

+

+      png_debug1(3, "allocated %d entries for info_ptr->text", max_text);

+   }

+

+   for (i = 0; i < num_text; i++)

+   {

+      size_t text_length, key_len;

+      size_t lang_len, lang_key_len;

+      png_textp textp = &(info_ptr->text[info_ptr->num_text]);

+

+      if (text_ptr[i].key == NULL)

+          continue;

+

+      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||

+          text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)

+      {

+         png_chunk_report(png_ptr, "text compression mode is out of range",

+            PNG_CHUNK_WRITE_ERROR);

+         continue;

+      }

+

+      key_len = strlen(text_ptr[i].key);

+

+      if (text_ptr[i].compression <= 0)

+      {

+         lang_len = 0;

+         lang_key_len = 0;

+      }

+

+      else

+#  ifdef PNG_iTXt_SUPPORTED

+      {

+         /* Set iTXt data */

+

+         if (text_ptr[i].lang != NULL)

+            lang_len = strlen(text_ptr[i].lang);

+

+         else

+            lang_len = 0;

+

+         if (text_ptr[i].lang_key != NULL)

+            lang_key_len = strlen(text_ptr[i].lang_key);

+

+         else

+            lang_key_len = 0;

+      }

+#  else /* PNG_iTXt_SUPPORTED */

+      {

+         png_chunk_report(png_ptr, "iTXt chunk not supported",

+            PNG_CHUNK_WRITE_ERROR);

+         continue;

+      }

+#  endif

+

+      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')

+      {

+         text_length = 0;

+#  ifdef PNG_iTXt_SUPPORTED

+         if (text_ptr[i].compression > 0)

+            textp->compression = PNG_ITXT_COMPRESSION_NONE;

+

+         else

+#  endif

+            textp->compression = PNG_TEXT_COMPRESSION_NONE;

+      }

+

+      else

+      {

+         text_length = strlen(text_ptr[i].text);

+         textp->compression = text_ptr[i].compression;

+      }

+

+      textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr,

+          key_len + text_length + lang_len + lang_key_len + 4));

+

+      if (textp->key == NULL)

+      {

+         png_chunk_report(png_ptr, "text chunk: out of memory",

+               PNG_CHUNK_WRITE_ERROR);

+         return 1;

+      }

+

+      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",

+          (unsigned long)(png_uint_32)

+          (key_len + lang_len + lang_key_len + text_length + 4),

+          textp->key);

+

+      memcpy(textp->key, text_ptr[i].key, key_len);

+      *(textp->key + key_len) = '\0';

+

+      if (text_ptr[i].compression > 0)

+      {

+         textp->lang = textp->key + key_len + 1;

+         memcpy(textp->lang, text_ptr[i].lang, lang_len);

+         *(textp->lang + lang_len) = '\0';

+         textp->lang_key = textp->lang + lang_len + 1;

+         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);

+         *(textp->lang_key + lang_key_len) = '\0';

+         textp->text = textp->lang_key + lang_key_len + 1;

+      }

+

+      else

+      {

+         textp->lang=NULL;

+         textp->lang_key=NULL;

+         textp->text = textp->key + key_len + 1;

+      }

+

+      if (text_length)

+         memcpy(textp->text, text_ptr[i].text, text_length);

+

+      *(textp->text + text_length) = '\0';

+

+#  ifdef PNG_iTXt_SUPPORTED

+      if (textp->compression > 0)

+      {

+         textp->text_length = 0;

+         textp->itxt_length = text_length;

+      }

+

+      else

+#  endif

+      {

+         textp->text_length = text_length;

+         textp->itxt_length = 0;

+      }

+

+      info_ptr->num_text++;

+      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);

+   }

+

+   return(0);

+}

+#endif

+

+#ifdef PNG_tIME_SUPPORTED

+void PNGAPI

+png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_const_timep mod_time)

+{

+   png_debug1(1, "in %s storage function", "tIME");

+

+   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||

+       (png_ptr->mode & PNG_WROTE_tIME))

+      return;

+

+   if (mod_time->month == 0   || mod_time->month > 12  ||

+       mod_time->day   == 0   || mod_time->day   > 31  ||

+       mod_time->hour  > 23   || mod_time->minute > 59 ||

+       mod_time->second > 60)

+   {

+      png_warning(png_ptr, "Ignoring invalid time value");

+      return;

+   }

+

+   info_ptr->mod_time = *mod_time;

+   info_ptr->valid |= PNG_INFO_tIME;

+}

+#endif

+

+#ifdef PNG_tRNS_SUPPORTED

+void PNGAPI

+png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,

+    png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)

+{

+   png_debug1(1, "in %s storage function", "tRNS");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   if (trans_alpha != NULL)

+   {

+       /* It may not actually be necessary to set png_ptr->trans_alpha here;

+        * we do it for backward compatibility with the way the png_handle_tRNS

+        * function used to do the allocation.

+        *

+        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively

+        * relies on png_set_tRNS storing the information in png_struct

+        * (otherwise it won't be there for the code in pngrtran.c).

+        */

+

+       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);

+

+       /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */

+       png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep,

+         png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));

+

+       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)

+          memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);

+   }

+

+   if (trans_color != NULL)

+   {

+      int sample_max = (1 << info_ptr->bit_depth);

+

+      if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&

+          trans_color->gray > sample_max) ||

+          (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&

+          (trans_color->red > sample_max ||

+          trans_color->green > sample_max ||

+          trans_color->blue > sample_max)))

+         png_warning(png_ptr,

+            "tRNS chunk has out-of-range samples for bit_depth");

+

+      info_ptr->trans_color = *trans_color;

+

+      if (num_trans == 0)

+         num_trans = 1;

+   }

+

+   info_ptr->num_trans = (png_uint_16)num_trans;

+

+   if (num_trans != 0)

+   {

+      info_ptr->valid |= PNG_INFO_tRNS;

+      info_ptr->free_me |= PNG_FREE_TRNS;

+   }

+}

+#endif

+

+#ifdef PNG_sPLT_SUPPORTED

+void PNGAPI

+png_set_sPLT(png_const_structrp png_ptr,

+    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)

+/*

+ *  entries        - array of png_sPLT_t structures

+ *                   to be added to the list of palettes

+ *                   in the info structure.

+ *

+ *  nentries       - number of palette structures to be

+ *                   added.

+ */

+{

+   png_sPLT_tp np;

+

+   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)

+      return;

+

+   /* Use the internal realloc function, which checks for all the possible

+    * overflows.  Notice that the parameters are (int) and (size_t)

+    */

+   np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,

+      info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,

+      sizeof *np));

+

+   if (np == NULL)

+   {

+      /* Out of memory or too many chunks */

+      png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);

+      return;

+   }

+

+   png_free(png_ptr, info_ptr->splt_palettes);

+   info_ptr->splt_palettes = np;

+   info_ptr->free_me |= PNG_FREE_SPLT;

+

+   np += info_ptr->splt_palettes_num;

+

+   do

+   {

+      png_size_t length;

+

+      /* Skip invalid input entries */

+      if (entries->name == NULL || entries->entries == NULL)

+      {

+         /* png_handle_sPLT doesn't do this, so this is an app error */

+         png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");

+         /* Just skip the invalid entry */

+         continue;

+      }

+

+      np->depth = entries->depth;

+

+      /* In the even of out-of-memory just return - there's no point keeping on

+       * trying to add sPLT chunks.

+       */

+      length = strlen(entries->name) + 1;

+      np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));

+

+      if (np->name == NULL)

+         break;

+

+      memcpy(np->name, entries->name, length);

+

+      /* IMPORTANT: we have memory now that won't get freed if something else

+       * goes wrong, this code must free it.  png_malloc_array produces no

+       * warnings, use a png_chunk_report (below) if there is an error.

+       */

+      np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,

+          entries->nentries, sizeof (png_sPLT_entry)));

+

+      if (np->entries == NULL)

+      {

+         png_free(png_ptr, np->name);

+         break;

+      }

+

+      np->nentries = entries->nentries;

+      /* This multiply can't overflow because png_malloc_array has already

+       * checked it when doing the allocation.

+       */

+      memcpy(np->entries, entries->entries,

+         entries->nentries * sizeof (png_sPLT_entry));

+

+      /* Note that 'continue' skips the advance of the out pointer and out

+       * count, so an invalid entry is not added.

+       */

+      info_ptr->valid |= PNG_INFO_sPLT;

+      ++(info_ptr->splt_palettes_num);

+      ++np;

+   }

+   while (++entries, --nentries);

+

+   if (nentries > 0)

+      png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);

+}

+#endif /* PNG_sPLT_SUPPORTED */

+

+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED

+static png_byte

+check_location(png_const_structrp png_ptr, int location)

+{

+   location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);

+

+   /* New in 1.6.0; copy the location and check it.  This is an API

+    * change, previously the app had to use the

+    * png_set_unknown_chunk_location API below for each chunk.

+    */

+   if (location == 0 && !(png_ptr->mode & PNG_IS_READ_STRUCT))

+   {

+      /* Write struct, so unknown chunks come from the app */

+      png_app_warning(png_ptr,

+         "png_set_unknown_chunks now expects a valid location");

+      /* Use the old behavior */

+      location = (png_byte)(png_ptr->mode &

+         (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));

+   }

+

+   /* This need not be an internal error - if the app calls

+    * png_set_unknown_chunks on a read pointer it must get the location right.

+    */

+   if (location == 0)

+      png_error(png_ptr, "invalid location in png_set_unknown_chunks");

+

+   /* Now reduce the location to the top-most set bit by removing each least

+    * significant bit in turn.

+    */

+   while (location != (location & -location))

+      location &= ~(location & -location);

+

+   /* The cast is safe because 'location' is a bit mask and only the low four

+    * bits are significant.

+    */

+   return (png_byte)location;

+}

+

+void PNGAPI

+png_set_unknown_chunks(png_const_structrp png_ptr,

+   png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)

+{

+   png_unknown_chunkp np;

+

+   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||

+      unknowns == NULL)

+      return;

+

+   /* Check for the failure cases where support has been disabled at compile

+    * time.  This code is hardly ever compiled - it's here because

+    * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this

+    * code) but may be meaningless if the read or write handling of unknown

+    * chunks is not compiled in.

+    */

+#  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \

+      defined(PNG_READ_SUPPORTED)

+      if (png_ptr->mode & PNG_IS_READ_STRUCT)

+      {

+         png_app_error(png_ptr, "no unknown chunk support on read");

+         return;

+      }

+#  endif

+#  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \

+      defined(PNG_WRITE_SUPPORTED)

+      if (!(png_ptr->mode & PNG_IS_READ_STRUCT))

+      {

+         png_app_error(png_ptr, "no unknown chunk support on write");

+         return;

+      }

+#  endif

+

+   /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that

+    * unknown critical chunks could be lost with just a warning resulting in

+    * undefined behavior.  Now png_chunk_report is used to provide behavior

+    * appropriate to read or write.

+    */

+   np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,

+         info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,

+         sizeof *np));

+

+   if (np == NULL)

+   {

+      png_chunk_report(png_ptr, "too many unknown chunks",

+         PNG_CHUNK_WRITE_ERROR);

+      return;

+   }

+

+   png_free(png_ptr, info_ptr->unknown_chunks);

+   info_ptr->unknown_chunks = np; /* safe because it is initialized */

+   info_ptr->free_me |= PNG_FREE_UNKN;

+

+   np += info_ptr->unknown_chunks_num;

+

+   /* Increment unknown_chunks_num each time round the loop to protect the

+    * just-allocated chunk data.

+    */

+   for (; num_unknowns > 0; --num_unknowns, ++unknowns)

+   {

+      memcpy(np->name, unknowns->name, (sizeof np->name));

+      np->name[(sizeof np->name)-1] = '\0';

+      np->location = check_location(png_ptr, unknowns->location);

+

+      if (unknowns->size == 0)

+      {

+         np->data = NULL;

+         np->size = 0;

+      }

+

+      else

+      {

+         np->data = png_voidcast(png_bytep,

+            png_malloc_base(png_ptr, unknowns->size));

+

+         if (np->data == NULL)

+         {

+            png_chunk_report(png_ptr, "unknown chunk: out of memory",

+               PNG_CHUNK_WRITE_ERROR);

+            /* But just skip storing the unknown chunk */

+            continue;

+         }

+

+         memcpy(np->data, unknowns->data, unknowns->size);

+         np->size = unknowns->size;

+      }

+

+      /* These increments are skipped on out-of-memory for the data - the

+       * unknown chunk entry gets overwritten if the png_chunk_report returns.

+       * This is correct in the read case (the chunk is just dropped.)

+       */

+      ++np;

+      ++(info_ptr->unknown_chunks_num);

+   }

+}

+

+void PNGAPI

+png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,

+    int chunk, int location)

+{

+   /* This API is pretty pointless in 1.6.0 because the location can be set

+    * before the call to png_set_unknown_chunks.

+    *

+    * TODO: add a png_app_warning in 1.7

+    */

+   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&

+      chunk < info_ptr->unknown_chunks_num)

+   {

+      if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)

+      {

+         png_app_error(png_ptr, "invalid unknown chunk location");

+         /* Fake out the pre 1.6.0 behavior: */

+         if ((location & PNG_HAVE_IDAT)) /* undocumented! */

+            location = PNG_AFTER_IDAT;

+

+         else

+            location = PNG_HAVE_IHDR; /* also undocumented */

+      }

+

+      info_ptr->unknown_chunks[chunk].location =

+         check_location(png_ptr, location);

+   }

+}

+#endif

+

+

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+png_uint_32 PNGAPI

+png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)

+{

+   png_debug(1, "in png_permit_mng_features");

+

+   if (png_ptr == NULL)

+      return 0;

+

+   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;

+

+   return png_ptr->mng_features_permitted;

+}

+#endif

+

+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+static unsigned int

+add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)

+{

+   unsigned int i;

+

+   /* Utility function: update the 'keep' state of a chunk if it is already in

+    * the list, otherwise add it to the list.

+    */

+   for (i=0; i<count; ++i, list += 5) if (memcmp(list, add, 4) == 0)

+   {

+      list[4] = (png_byte)keep;

+      return count;

+   }

+

+   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)

+   {

+      ++count;

+      memcpy(list, add, 4);

+      list[4] = (png_byte)keep;

+   }

+

+   return count;

+}

+

+void PNGAPI

+png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,

+    png_const_bytep chunk_list, int num_chunks_in)

+{

+   png_bytep new_list;

+   unsigned int num_chunks, old_num_chunks;

+

+   if (png_ptr == NULL)

+      return;

+

+   if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)

+   {

+      png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");

+      return;

+   }

+

+   if (num_chunks_in <= 0)

+   {

+      png_ptr->unknown_default = keep;

+

+      /* '0' means just set the flags, so stop here */

+      if (num_chunks_in == 0)

+        return;

+   }

+

+   if (num_chunks_in < 0)

+   {

+      /* Ignore all unknown chunks and all chunks recognized by

+       * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND

+       */

+      static PNG_CONST png_byte chunks_to_ignore[] = {

+         98,  75,  71,  68, '\0',  /* bKGD */

+         99,  72,  82,  77, '\0',  /* cHRM */

+        103,  65,  77,  65, '\0',  /* gAMA */

+        104,  73,  83,  84, '\0',  /* hIST */

+        105,  67,  67,  80, '\0',  /* iCCP */

+        105,  84,  88, 116, '\0',  /* iTXt */

+        111,  70,  70, 115, '\0',  /* oFFs */

+        112,  67,  65,  76, '\0',  /* pCAL */

+        112,  72,  89, 115, '\0',  /* pHYs */

+        115,  66,  73,  84, '\0',  /* sBIT */

+        115,  67,  65,  76, '\0',  /* sCAL */

+        115,  80,  76,  84, '\0',  /* sPLT */

+        115,  84,  69,  82, '\0',  /* sTER */

+        115,  82,  71,  66, '\0',  /* sRGB */

+        116,  69,  88, 116, '\0',  /* tEXt */

+        116,  73,  77,  69, '\0',  /* tIME */

+        122,  84,  88, 116, '\0'   /* zTXt */

+      };

+

+      chunk_list = chunks_to_ignore;

+      num_chunks = (sizeof chunks_to_ignore)/5;

+   }

+

+   else /* num_chunks_in > 0 */

+   {

+      if (chunk_list == NULL)

+      {

+         /* Prior to 1.6.0 this was silently ignored, now it is an app_error

+          * which can be switched off.

+          */

+         png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");

+         return;

+      }

+

+      num_chunks = num_chunks_in;

+   }

+

+   old_num_chunks = png_ptr->num_chunk_list;

+   if (png_ptr->chunk_list == NULL)

+      old_num_chunks = 0;

+

+   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.

+    */

+   if (num_chunks + old_num_chunks > UINT_MAX/5)

+   {

+      png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");

+      return;

+   }

+

+   /* If these chunks are being reset to the default then no more memory is

+    * required because add_one_chunk above doesn't extend the list if the 'keep'

+    * parameter is the default.

+    */

+   if (keep)

+   {

+      new_list = png_voidcast(png_bytep, png_malloc(png_ptr,

+          5 * (num_chunks + old_num_chunks)));

+

+      if (old_num_chunks > 0)

+         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);

+   }

+

+   else if (old_num_chunks > 0)

+      new_list = png_ptr->chunk_list;

+

+   else

+      new_list = NULL;

+

+   /* Add the new chunks together with each one's handling code.  If the chunk

+    * already exists the code is updated, otherwise the chunk is added to the

+    * end.  (In libpng 1.6.0 order no longer matters because this code enforces

+    * the earlier convention that the last setting is the one that is used.)

+    */

+   if (new_list != NULL)

+   {

+      png_const_bytep inlist;

+      png_bytep outlist;

+      unsigned int i;

+

+      for (i=0; i<num_chunks; ++i)

+         old_num_chunks = add_one_chunk(new_list, old_num_chunks,

+            chunk_list+5*i, keep);

+

+      /* Now remove any spurious 'default' entries. */

+      num_chunks = 0;

+      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)

+         if (inlist[4])

+         {

+            if (outlist != inlist)

+               memcpy(outlist, inlist, 5);

+            outlist += 5;

+            ++num_chunks;

+         }

+

+      /* This means the application has removed all the specialized handling. */

+      if (num_chunks == 0)

+      {

+         if (png_ptr->chunk_list != new_list)

+            png_free(png_ptr, new_list);

+

+         new_list = NULL;

+      }

+   }

+

+   else

+      num_chunks = 0;

+

+   png_ptr->num_chunk_list = num_chunks;

+

+   if (png_ptr->chunk_list != new_list)

+   {

+      if (png_ptr->chunk_list != NULL)

+         png_free(png_ptr, png_ptr->chunk_list);

+

+      png_ptr->chunk_list = new_list;

+   }

+}

+#endif

+

+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED

+void PNGAPI

+png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,

+    png_user_chunk_ptr read_user_chunk_fn)

+{

+   png_debug(1, "in png_set_read_user_chunk_fn");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->read_user_chunk_fn = read_user_chunk_fn;

+   png_ptr->user_chunk_ptr = user_chunk_ptr;

+}

+#endif

+

+#ifdef PNG_INFO_IMAGE_SUPPORTED

+void PNGAPI

+png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,

+    png_bytepp row_pointers)

+{

+   png_debug1(1, "in %s storage function", "rows");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))

+      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);

+

+   info_ptr->row_pointers = row_pointers;

+

+   if (row_pointers)

+      info_ptr->valid |= PNG_INFO_IDAT;

+}

+#endif

+

+void PNGAPI

+png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)

+{

+    if (png_ptr == NULL)

+       return;

+

+    if (size == 0 || size > PNG_UINT_31_MAX)

+       png_error(png_ptr, "invalid compression buffer size");

+

+#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+      if (png_ptr->mode & PNG_IS_READ_STRUCT)

+      {

+         png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */

+         return;

+      }

+#  endif

+

+#  ifdef PNG_WRITE_SUPPORTED

+      if (!(png_ptr->mode & PNG_IS_READ_STRUCT))

+      {

+         if (png_ptr->zowner != 0)

+         {

+            png_warning(png_ptr,

+              "Compression buffer size cannot be changed because it is in use");

+            return;

+         }

+

+         if (size > ZLIB_IO_MAX)

+         {

+            png_warning(png_ptr,

+               "Compression buffer size limited to system maximum");

+            size = ZLIB_IO_MAX; /* must fit */

+         }

+

+         else if (size < 6)

+         {

+            /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH

+             * if this is permitted.

+             */

+            png_warning(png_ptr,

+               "Compression buffer size cannot be reduced below 6");

+            return;

+         }

+

+         if (png_ptr->zbuffer_size != size)

+         {

+            png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);

+            png_ptr->zbuffer_size = (uInt)size;

+         }

+      }

+#  endif

+}

+

+void PNGAPI

+png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)

+{

+   if (png_ptr && info_ptr)

+      info_ptr->valid &= ~mask;

+}

+

+

+#ifdef PNG_SET_USER_LIMITS_SUPPORTED

+/* This function was added to libpng 1.2.6 */

+void PNGAPI

+png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,

+    png_uint_32 user_height_max)

+{

+   /* Images with dimensions larger than these limits will be

+    * rejected by png_set_IHDR().  To accept any PNG datastream

+    * regardless of dimensions, set both limits to 0x7ffffffL.

+    */

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->user_width_max = user_width_max;

+   png_ptr->user_height_max = user_height_max;

+}

+

+/* This function was added to libpng 1.4.0 */

+void PNGAPI

+png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)

+{

+    if (png_ptr)

+       png_ptr->user_chunk_cache_max = user_chunk_cache_max;

+}

+

+/* This function was added to libpng 1.4.1 */

+void PNGAPI

+png_set_chunk_malloc_max (png_structrp png_ptr,

+    png_alloc_size_t user_chunk_malloc_max)

+{

+   if (png_ptr)

+      png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;

+}

+#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */

+

+

+#ifdef PNG_BENIGN_ERRORS_SUPPORTED

+void PNGAPI

+png_set_benign_errors(png_structrp png_ptr, int allowed)

+{

+   png_debug(1, "in png_set_benign_errors");

+

+   /* If allowed is 1, png_benign_error() is treated as a warning.

+    *

+    * If allowed is 0, png_benign_error() is treated as an error (which

+    * is the default behavior if png_set_benign_errors() is not called).

+    */

+

+   if (allowed)

+      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |

+         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;

+

+   else

+      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |

+         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);

+}

+#endif /* PNG_BENIGN_ERRORS_SUPPORTED */

+

+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED

+   /* Whether to report invalid palette index; added at libng-1.5.10.

+    * It is possible for an indexed (color-type==3) PNG file to contain

+    * pixels with invalid (out-of-range) indexes if the PLTE chunk has

+    * fewer entries than the image's bit-depth would allow. We recover

+    * from this gracefully by filling any incomplete palette with zeroes

+    * (opaque black).  By default, when this occurs libpng will issue

+    * a benign error.  This API can be used to override that behavior.

+    */

+void PNGAPI

+png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)

+{

+   png_debug(1, "in png_set_check_for_invalid_index");

+

+   if (allowed > 0)

+      png_ptr->num_palette_max = 0;

+

+   else

+      png_ptr->num_palette_max = -1;

+}

+#endif

+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngtrans.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngtrans.c
new file mode 100644
index 0000000..a46b0fc
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngtrans.c
@@ -0,0 +1,842 @@
+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+/* pngtrans.c - transforms the data in a row (used by both readers and writers)

+ *

+ * Last changed in libpng 1.6.2 [April 25, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+

+#include "pngpriv.h"

+

+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

+

+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)

+/* Turn on BGR-to-RGB mapping */

+void PNGAPI

+png_set_bgr(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_bgr");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->transformations |= PNG_BGR;

+}

+#endif

+

+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)

+/* Turn on 16 bit byte swapping */

+void PNGAPI

+png_set_swap(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_swap");

+

+   if (png_ptr == NULL)

+      return;

+

+   if (png_ptr->bit_depth == 16)

+      png_ptr->transformations |= PNG_SWAP_BYTES;

+}

+#endif

+

+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)

+/* Turn on pixel packing */

+void PNGAPI

+png_set_packing(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_packing");

+

+   if (png_ptr == NULL)

+      return;

+

+   if (png_ptr->bit_depth < 8)

+   {

+      png_ptr->transformations |= PNG_PACK;

+      png_ptr->usr_bit_depth = 8;

+   }

+}

+#endif

+

+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)

+/* Turn on packed pixel swapping */

+void PNGAPI

+png_set_packswap(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_packswap");

+

+   if (png_ptr == NULL)

+      return;

+

+   if (png_ptr->bit_depth < 8)

+      png_ptr->transformations |= PNG_PACKSWAP;

+}

+#endif

+

+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)

+void PNGAPI

+png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits)

+{

+   png_debug(1, "in png_set_shift");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->transformations |= PNG_SHIFT;

+   png_ptr->shift = *true_bits;

+}

+#endif

+

+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \

+    defined(PNG_WRITE_INTERLACING_SUPPORTED)

+int PNGAPI

+png_set_interlace_handling(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_interlace handling");

+

+   if (png_ptr && png_ptr->interlaced)

+   {

+      png_ptr->transformations |= PNG_INTERLACE;

+      return (7);

+   }

+

+   return (1);

+}

+#endif

+

+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)

+/* Add a filler byte on read, or remove a filler or alpha byte on write.

+ * The filler type has changed in v0.95 to allow future 2-byte fillers

+ * for 48-bit input data, as well as to avoid problems with some compilers

+ * that don't like bytes as parameters.

+ */

+void PNGAPI

+png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc)

+{

+   png_debug(1, "in png_set_filler");

+

+   if (png_ptr == NULL)

+      return;

+

+   /* In libpng 1.6 it is possible to determine whether this is a read or write

+    * operation and therefore to do more checking here for a valid call.

+    */

+   if (png_ptr->mode & PNG_IS_READ_STRUCT)

+   {

+#     ifdef PNG_READ_FILLER_SUPPORTED

+         /* On read png_set_filler is always valid, regardless of the base PNG

+          * format, because other transformations can give a format where the

+          * filler code can execute (basically an 8 or 16-bit component RGB or G

+          * format.)

+          *

+          * NOTE: usr_channels is not used by the read code!  (This has led to

+          * confusion in the past.)  The filler is only used in the read code.

+          */

+         png_ptr->filler = (png_uint_16)filler;

+#     else

+         png_app_error(png_ptr, "png_set_filler not supported on read");

+         PNG_UNUSED(filler) /* not used in the write case */

+         return;

+#     endif

+   }

+

+   else /* write */

+   {

+#     ifdef PNG_WRITE_FILLER_SUPPORTED

+         /* On write the usr_channels parameter must be set correctly at the

+          * start to record the number of channels in the app-supplied data.

+          */

+         switch (png_ptr->color_type)

+         {

+            case PNG_COLOR_TYPE_RGB:

+               png_ptr->usr_channels = 4;

+               break;

+

+            case PNG_COLOR_TYPE_GRAY:

+               if (png_ptr->bit_depth >= 8)

+               {

+                  png_ptr->usr_channels = 2;

+                  break;

+               }

+

+               else

+               {

+                  /* There simply isn't any code in libpng to strip out bits

+                   * from bytes when the components are less than a byte in

+                   * size!

+                   */

+                  png_app_error(png_ptr,

+                     "png_set_filler is invalid for low bit depth gray output");

+                  return;

+               }

+

+            default:

+               png_app_error(png_ptr,

+                  "png_set_filler: inappropriate color type");

+               return;

+         }

+#     else

+         png_app_error(png_ptr, "png_set_filler not supported on write");

+         return;

+#     endif

+   }

+

+   /* Here on success - libpng supports the operation, set the transformation

+    * and the flag to say where the filler channel is.

+    */

+   png_ptr->transformations |= PNG_FILLER;

+

+   if (filler_loc == PNG_FILLER_AFTER)

+      png_ptr->flags |= PNG_FLAG_FILLER_AFTER;

+

+   else

+      png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;

+}

+

+/* Added to libpng-1.2.7 */

+void PNGAPI

+png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc)

+{

+   png_debug(1, "in png_set_add_alpha");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_set_filler(png_ptr, filler, filler_loc);

+   /* The above may fail to do anything. */

+   if (png_ptr->transformations & PNG_FILLER)

+      png_ptr->transformations |= PNG_ADD_ALPHA;

+}

+

+#endif

+

+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \

+    defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)

+void PNGAPI

+png_set_swap_alpha(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_swap_alpha");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->transformations |= PNG_SWAP_ALPHA;

+}

+#endif

+

+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \

+    defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)

+void PNGAPI

+png_set_invert_alpha(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_invert_alpha");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->transformations |= PNG_INVERT_ALPHA;

+}

+#endif

+

+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)

+void PNGAPI

+png_set_invert_mono(png_structrp png_ptr)

+{

+   png_debug(1, "in png_set_invert_mono");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->transformations |= PNG_INVERT_MONO;

+}

+

+/* Invert monochrome grayscale data */

+void /* PRIVATE */

+png_do_invert(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_invert");

+

+  /* This test removed from libpng version 1.0.13 and 1.2.0:

+   *   if (row_info->bit_depth == 1 &&

+   */

+   if (row_info->color_type == PNG_COLOR_TYPE_GRAY)

+   {

+      png_bytep rp = row;

+      png_size_t i;

+      png_size_t istop = row_info->rowbytes;

+

+      for (i = 0; i < istop; i++)

+      {

+         *rp = (png_byte)(~(*rp));

+         rp++;

+      }

+   }

+

+   else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&

+      row_info->bit_depth == 8)

+   {

+      png_bytep rp = row;

+      png_size_t i;

+      png_size_t istop = row_info->rowbytes;

+

+      for (i = 0; i < istop; i += 2)

+      {

+         *rp = (png_byte)(~(*rp));

+         rp += 2;

+      }

+   }

+

+#ifdef PNG_16BIT_SUPPORTED

+   else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&

+      row_info->bit_depth == 16)

+   {

+      png_bytep rp = row;

+      png_size_t i;

+      png_size_t istop = row_info->rowbytes;

+

+      for (i = 0; i < istop; i += 4)

+      {

+         *rp = (png_byte)(~(*rp));

+         *(rp + 1) = (png_byte)(~(*(rp + 1)));

+         rp += 4;

+      }

+   }

+#endif

+}

+#endif

+

+#ifdef PNG_16BIT_SUPPORTED

+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)

+/* Swaps byte order on 16 bit depth images */

+void /* PRIVATE */

+png_do_swap(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_swap");

+

+   if (row_info->bit_depth == 16)

+   {

+      png_bytep rp = row;

+      png_uint_32 i;

+      png_uint_32 istop= row_info->width * row_info->channels;

+

+      for (i = 0; i < istop; i++, rp += 2)

+      {

+         png_byte t = *rp;

+         *rp = *(rp + 1);

+         *(rp + 1) = t;

+      }

+   }

+}

+#endif

+#endif

+

+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)

+static PNG_CONST png_byte onebppswaptable[256] = {

+   0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,

+   0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,

+   0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,

+   0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,

+   0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,

+   0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,

+   0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,

+   0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,

+   0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,

+   0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,

+   0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,

+   0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,

+   0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,

+   0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,

+   0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,

+   0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,

+   0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,

+   0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,

+   0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,

+   0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,

+   0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,

+   0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,

+   0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,

+   0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,

+   0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,

+   0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,

+   0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,

+   0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,

+   0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,

+   0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,

+   0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,

+   0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF

+};

+

+static PNG_CONST png_byte twobppswaptable[256] = {

+   0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,

+   0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,

+   0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,

+   0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,

+   0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,

+   0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,

+   0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,

+   0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,

+   0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,

+   0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,

+   0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,

+   0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,

+   0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,

+   0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,

+   0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,

+   0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,

+   0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,

+   0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,

+   0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,

+   0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,

+   0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,

+   0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,

+   0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,

+   0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,

+   0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,

+   0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,

+   0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,

+   0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,

+   0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,

+   0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,

+   0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,

+   0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF

+};

+

+static PNG_CONST png_byte fourbppswaptable[256] = {

+   0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,

+   0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,

+   0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,

+   0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,

+   0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,

+   0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,

+   0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,

+   0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,

+   0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,

+   0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,

+   0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,

+   0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,

+   0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,

+   0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,

+   0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,

+   0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,

+   0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,

+   0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,

+   0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,

+   0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,

+   0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,

+   0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,

+   0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,

+   0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,

+   0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,

+   0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,

+   0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,

+   0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,

+   0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,

+   0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,

+   0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,

+   0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF

+};

+

+/* Swaps pixel packing order within bytes */

+void /* PRIVATE */

+png_do_packswap(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_packswap");

+

+   if (row_info->bit_depth < 8)

+   {

+      png_bytep rp;

+      png_const_bytep end, table;

+

+      end = row + row_info->rowbytes;

+

+      if (row_info->bit_depth == 1)

+         table = onebppswaptable;

+

+      else if (row_info->bit_depth == 2)

+         table = twobppswaptable;

+

+      else if (row_info->bit_depth == 4)

+         table = fourbppswaptable;

+

+      else

+         return;

+

+      for (rp = row; rp < end; rp++)

+         *rp = table[*rp];

+   }

+}

+#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */

+

+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \

+    defined(PNG_READ_STRIP_ALPHA_SUPPORTED)

+/* Remove a channel - this used to be 'png_do_strip_filler' but it used a

+ * somewhat weird combination of flags to determine what to do.  All the calls

+ * to png_do_strip_filler are changed in 1.5.2 to call this instead with the

+ * correct arguments.

+ *

+ * The routine isn't general - the channel must be the channel at the start or

+ * end (not in the middle) of each pixel.

+ */

+void /* PRIVATE */

+png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)

+{

+   png_bytep sp = row; /* source pointer */

+   png_bytep dp = row; /* destination pointer */

+   png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */

+

+   /* At the start sp will point to the first byte to copy and dp to where

+    * it is copied to.  ep always points just beyond the end of the row, so

+    * the loop simply copies (channels-1) channels until sp reaches ep.

+    *

+    * at_start:        0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc.

+    *            nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc.

+    */

+

+   /* GA, GX, XG cases */

+   if (row_info->channels == 2)

+   {

+      if (row_info->bit_depth == 8)

+      {

+         if (at_start) /* Skip initial filler */

+            ++sp;

+         else          /* Skip initial channel and, for sp, the filler */

+            sp += 2, ++dp;

+

+         /* For a 1 pixel wide image there is nothing to do */

+         while (sp < ep)

+            *dp++ = *sp, sp += 2;

+

+         row_info->pixel_depth = 8;

+      }

+

+      else if (row_info->bit_depth == 16)

+      {

+         if (at_start) /* Skip initial filler */

+            sp += 2;

+         else          /* Skip initial channel and, for sp, the filler */

+            sp += 4, dp += 2;

+

+         while (sp < ep)

+            *dp++ = *sp++, *dp++ = *sp, sp += 3;

+

+         row_info->pixel_depth = 16;

+      }

+

+      else

+         return; /* bad bit depth */

+

+      row_info->channels = 1;

+

+      /* Finally fix the color type if it records an alpha channel */

+      if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

+         row_info->color_type = PNG_COLOR_TYPE_GRAY;

+   }

+

+   /* RGBA, RGBX, XRGB cases */

+   else if (row_info->channels == 4)

+   {

+      if (row_info->bit_depth == 8)

+      {

+         if (at_start) /* Skip initial filler */

+            ++sp;

+         else          /* Skip initial channels and, for sp, the filler */

+            sp += 4, dp += 3;

+

+         /* Note that the loop adds 3 to dp and 4 to sp each time. */

+         while (sp < ep)

+            *dp++ = *sp++, *dp++ = *sp++, *dp++ = *sp, sp += 2;

+

+         row_info->pixel_depth = 24;

+      }

+

+      else if (row_info->bit_depth == 16)

+      {

+         if (at_start) /* Skip initial filler */

+            sp += 2;

+         else          /* Skip initial channels and, for sp, the filler */

+            sp += 8, dp += 6;

+

+         while (sp < ep)

+         {

+            /* Copy 6 bytes, skip 2 */

+            *dp++ = *sp++, *dp++ = *sp++;

+            *dp++ = *sp++, *dp++ = *sp++;

+            *dp++ = *sp++, *dp++ = *sp, sp += 3;

+         }

+

+         row_info->pixel_depth = 48;

+      }

+

+      else

+         return; /* bad bit depth */

+

+      row_info->channels = 3;

+

+      /* Finally fix the color type if it records an alpha channel */

+      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+         row_info->color_type = PNG_COLOR_TYPE_RGB;

+   }

+

+   else

+      return; /* The filler channel has gone already */

+

+   /* Fix the rowbytes value. */

+   row_info->rowbytes = dp-row;

+}

+#endif

+

+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)

+/* Swaps red and blue bytes within a pixel */

+void /* PRIVATE */

+png_do_bgr(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_bgr");

+

+   if ((row_info->color_type & PNG_COLOR_MASK_COLOR))

+   {

+      png_uint_32 row_width = row_info->width;

+      if (row_info->bit_depth == 8)

+      {

+         if (row_info->color_type == PNG_COLOR_TYPE_RGB)

+         {

+            png_bytep rp;

+            png_uint_32 i;

+

+            for (i = 0, rp = row; i < row_width; i++, rp += 3)

+            {

+               png_byte save = *rp;

+               *rp = *(rp + 2);

+               *(rp + 2) = save;

+            }

+         }

+

+         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+         {

+            png_bytep rp;

+            png_uint_32 i;

+

+            for (i = 0, rp = row; i < row_width; i++, rp += 4)

+            {

+               png_byte save = *rp;

+               *rp = *(rp + 2);

+               *(rp + 2) = save;

+            }

+         }

+      }

+

+#ifdef PNG_16BIT_SUPPORTED

+      else if (row_info->bit_depth == 16)

+      {

+         if (row_info->color_type == PNG_COLOR_TYPE_RGB)

+         {

+            png_bytep rp;

+            png_uint_32 i;

+

+            for (i = 0, rp = row; i < row_width; i++, rp += 6)

+            {

+               png_byte save = *rp;

+               *rp = *(rp + 4);

+               *(rp + 4) = save;

+               save = *(rp + 1);

+               *(rp + 1) = *(rp + 5);

+               *(rp + 5) = save;

+            }

+         }

+

+         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+         {

+            png_bytep rp;

+            png_uint_32 i;

+

+            for (i = 0, rp = row; i < row_width; i++, rp += 8)

+            {

+               png_byte save = *rp;

+               *rp = *(rp + 4);

+               *(rp + 4) = save;

+               save = *(rp + 1);

+               *(rp + 1) = *(rp + 5);

+               *(rp + 5) = save;

+            }

+         }

+      }

+#endif

+   }

+}

+#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */

+

+#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \

+    defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)

+/* Added at libpng-1.5.10 */

+void /* PRIVATE */

+png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)

+{

+   if (png_ptr->num_palette < (1 << row_info->bit_depth) &&

+      png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */

+   {

+      /* Calculations moved outside switch in an attempt to stop different

+       * compiler warnings.  'padding' is in *bits* within the last byte, it is

+       * an 'int' because pixel_depth becomes an 'int' in the expression below,

+       * and this calculation is used because it avoids warnings that other

+       * forms produced on either GCC or MSVC.

+       */

+      int padding = (-row_info->pixel_depth * row_info->width) & 7;

+      png_bytep rp = png_ptr->row_buf + row_info->rowbytes;

+

+      switch (row_info->bit_depth)

+      {

+         case 1:

+         {

+            /* in this case, all bytes must be 0 so we don't need

+             * to unpack the pixels except for the rightmost one.

+             */

+            for (; rp > png_ptr->row_buf; rp--)

+            {

+              if (*rp >> padding != 0)

+                 png_ptr->num_palette_max = 1;

+              padding = 0;

+            }

+

+            break;

+         }

+

+         case 2:

+         {

+            for (; rp > png_ptr->row_buf; rp--)

+            {

+              int i = ((*rp >> padding) & 0x03);

+

+              if (i > png_ptr->num_palette_max)

+                 png_ptr->num_palette_max = i;

+

+              i = (((*rp >> padding) >> 2) & 0x03);

+

+              if (i > png_ptr->num_palette_max)

+                 png_ptr->num_palette_max = i;

+

+              i = (((*rp >> padding) >> 4) & 0x03);

+

+              if (i > png_ptr->num_palette_max)

+                 png_ptr->num_palette_max = i;

+

+              i = (((*rp >> padding) >> 6) & 0x03);

+

+              if (i > png_ptr->num_palette_max)

+                 png_ptr->num_palette_max = i;

+

+              padding = 0;

+            }

+

+            break;

+         }

+

+         case 4:

+         {

+            for (; rp > png_ptr->row_buf; rp--)

+            {

+              int i = ((*rp >> padding) & 0x0f);

+

+              if (i > png_ptr->num_palette_max)

+                 png_ptr->num_palette_max = i;

+

+              i = (((*rp >> padding) >> 4) & 0x0f);

+

+              if (i > png_ptr->num_palette_max)

+                 png_ptr->num_palette_max = i;

+

+              padding = 0;

+            }

+

+            break;

+         }

+

+         case 8:

+         {

+            for (; rp > png_ptr->row_buf; rp--)

+            {

+               if (*rp > png_ptr->num_palette_max)

+                  png_ptr->num_palette_max = (int) *rp;

+            }

+

+            break;

+         }

+

+         default:

+            break;

+      }

+   }

+}

+#endif /* PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED */

+

+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \

+    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)

+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED

+void PNGAPI

+png_set_user_transform_info(png_structrp png_ptr, png_voidp

+   user_transform_ptr, int user_transform_depth, int user_transform_channels)

+{

+   png_debug(1, "in png_set_user_transform_info");

+

+   if (png_ptr == NULL)

+      return;

+

+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED

+   if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&

+      (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0)

+   {

+      png_app_error(png_ptr,

+            "info change after png_start_read_image or png_read_update_info");

+      return;

+   }

+#endif

+

+   png_ptr->user_transform_ptr = user_transform_ptr;

+   png_ptr->user_transform_depth = (png_byte)user_transform_depth;

+   png_ptr->user_transform_channels = (png_byte)user_transform_channels;

+}

+#endif

+

+/* This function returns a pointer to the user_transform_ptr associated with

+ * the user transform functions.  The application should free any memory

+ * associated with this pointer before png_write_destroy and png_read_destroy

+ * are called.

+ */

+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED

+png_voidp PNGAPI

+png_get_user_transform_ptr(png_const_structrp png_ptr)

+{

+   if (png_ptr == NULL)

+      return (NULL);

+

+   return png_ptr->user_transform_ptr;

+}

+#endif

+

+#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED

+png_uint_32 PNGAPI

+png_get_current_row_number(png_const_structrp png_ptr)

+{

+   /* See the comments in png.h - this is the sub-image row when reading and

+    * interlaced image.

+    */

+   if (png_ptr != NULL)

+      return png_ptr->row_number;

+

+   return PNG_UINT_32_MAX; /* help the app not to fail silently */

+}

+

+png_byte PNGAPI

+png_get_current_pass_number(png_const_structrp png_ptr)

+{

+   if (png_ptr != NULL)

+      return png_ptr->pass;

+   return 8; /* invalid */

+}

+#endif /* PNG_USER_TRANSFORM_INFO_SUPPORTED */

+#endif /* PNG_READ_USER_TRANSFORM_SUPPORTED ||

+          PNG_WRITE_USER_TRANSFORM_SUPPORTED */

+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

+#endif

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwio.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwio.c
new file mode 100644
index 0000000..5f3133e
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwio.c
@@ -0,0 +1,165 @@
+

+/* pngwio.c - functions for data output

+ *

+ * Last changed in libpng 1.6.0 [February 14, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ * This file provides a location for all output.  Users who need

+ * special handling are expected to write functions that have the same

+ * arguments as these and perform similar functions, but that possibly

+ * use different output methods.  Note that you shouldn't change these

+ * functions, but rather write replacement functions and then change

+ * them at run time with png_set_write_fn(...).

+ */

+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+#include "pngpriv.h"

+

+#ifdef PNG_WRITE_SUPPORTED

+

+/* Write the data to whatever output you are using.  The default routine

+ * writes to a file pointer.  Note that this routine sometimes gets called

+ * with very small lengths, so you should implement some kind of simple

+ * buffering if you are using unbuffered writes.  This should never be asked

+ * to write more than 64K on a 16 bit machine.

+ */

+

+void /* PRIVATE */

+png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length)

+{

+   /* NOTE: write_data_fn must not change the buffer! */

+   if (png_ptr->write_data_fn != NULL )

+      (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data),

+         length);

+

+   else

+      png_error(png_ptr, "Call to NULL write function");

+}

+

+#ifdef PNG_STDIO_SUPPORTED

+/* This is the function that does the actual writing of data.  If you are

+ * not writing to a standard C stream, you should create a replacement

+ * write_data function and use it at run time with png_set_write_fn(), rather

+ * than changing the library.

+ */

+void PNGCBAPI

+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)

+{

+   png_size_t check;

+

+   if (png_ptr == NULL)

+      return;

+

+   check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));

+

+   if (check != length)

+      png_error(png_ptr, "Write Error");

+}

+#endif

+

+/* This function is called to output any data pending writing (normally

+ * to disk).  After png_flush is called, there should be no data pending

+ * writing in any buffers.

+ */

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+void /* PRIVATE */

+png_flush(png_structrp png_ptr)

+{

+   if (png_ptr->output_flush_fn != NULL)

+      (*(png_ptr->output_flush_fn))(png_ptr);

+}

+

+#  ifdef PNG_STDIO_SUPPORTED

+void PNGCBAPI

+png_default_flush(png_structp png_ptr)

+{

+   png_FILE_p io_ptr;

+

+   if (png_ptr == NULL)

+      return;

+

+   io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr));

+   fflush(io_ptr);

+}

+#  endif

+#endif

+

+/* This function allows the application to supply new output functions for

+ * libpng if standard C streams aren't being used.

+ *

+ * This function takes as its arguments:

+ * png_ptr       - pointer to a png output data structure

+ * io_ptr        - pointer to user supplied structure containing info about

+ *                 the output functions.  May be NULL.

+ * write_data_fn - pointer to a new output function that takes as its

+ *                 arguments a pointer to a png_struct, a pointer to

+ *                 data to be written, and a 32-bit unsigned int that is

+ *                 the number of bytes to be written.  The new write

+ *                 function should call png_error(png_ptr, "Error msg")

+ *                 to exit and output any fatal error messages.  May be

+ *                 NULL, in which case libpng's default function will

+ *                 be used.

+ * flush_data_fn - pointer to a new flush function that takes as its

+ *                 arguments a pointer to a png_struct.  After a call to

+ *                 the flush function, there should be no data in any buffers

+ *                 or pending transmission.  If the output method doesn't do

+ *                 any buffering of output, a function prototype must still be

+ *                 supplied although it doesn't have to do anything.  If

+ *                 PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile

+ *                 time, output_flush_fn will be ignored, although it must be

+ *                 supplied for compatibility.  May be NULL, in which case

+ *                 libpng's default function will be used, if

+ *                 PNG_WRITE_FLUSH_SUPPORTED is defined.  This is not

+ *                 a good idea if io_ptr does not point to a standard

+ *                 *FILE structure.

+ */

+void PNGAPI

+png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr,

+    png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)

+{

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->io_ptr = io_ptr;

+

+#ifdef PNG_STDIO_SUPPORTED

+   if (write_data_fn != NULL)

+      png_ptr->write_data_fn = write_data_fn;

+

+   else

+      png_ptr->write_data_fn = png_default_write_data;

+#else

+   png_ptr->write_data_fn = write_data_fn;

+#endif

+

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+#  ifdef PNG_STDIO_SUPPORTED

+

+   if (output_flush_fn != NULL)

+      png_ptr->output_flush_fn = output_flush_fn;

+

+   else

+      png_ptr->output_flush_fn = png_default_flush;

+

+#  else

+   png_ptr->output_flush_fn = output_flush_fn;

+#  endif

+#endif /* PNG_WRITE_FLUSH_SUPPORTED */

+

+   /* It is an error to read while writing a png file */

+   if (png_ptr->read_data_fn != NULL)

+   {

+      png_ptr->read_data_fn = NULL;

+

+      png_warning(png_ptr,

+          "Can't set both read_data_fn and write_data_fn in the"

+          " same structure");

+   }

+}

+#endif /* PNG_WRITE_SUPPORTED */

+#endif//_FPDFAPI_MINI_

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwrite.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwrite.c
new file mode 100644
index 0000000..7efcfc3
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwrite.c
@@ -0,0 +1,2331 @@
+

+/* pngwrite.c - general routines to write a PNG file

+ *

+ * Last changed in libpng 1.6.2 [April 25, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+#include "pngpriv.h"

+#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)

+#  include <errno.h>

+#endif

+

+#ifdef PNG_WRITE_SUPPORTED

+

+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED

+/* Write out all the unknown chunks for the current given location */

+static void

+write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,

+   unsigned int where)

+{

+   if (info_ptr->unknown_chunks_num)

+   {

+      png_const_unknown_chunkp up;

+

+      png_debug(5, "writing extra chunks");

+

+      for (up = info_ptr->unknown_chunks;

+           up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;

+           ++up)

+         if (up->location & where)

+      {

+         /* If per-chunk unknown chunk handling is enabled use it, otherwise

+          * just write the chunks the application has set.

+          */

+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+         int keep = png_handle_as_unknown(png_ptr, up->name);

+

+         /* NOTE: this code is radically different from the read side in the

+          * matter of handling an ancillary unknown chunk.  In the read side

+          * the default behavior is to discard it, in the code below the default

+          * behavior is to write it.  Critical chunks are, however, only

+          * written if explicitly listed or if the default is set to write all

+          * unknown chunks.

+          *

+          * The default handling is also slightly weird - it is not possible to

+          * stop the writing of all unsafe-to-copy chunks!

+          *

+          * TODO: REVIEW: this would seem to be a bug.

+          */

+         if (keep != PNG_HANDLE_CHUNK_NEVER &&

+             ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ ||

+              keep == PNG_HANDLE_CHUNK_ALWAYS ||

+              (keep == PNG_HANDLE_CHUNK_AS_DEFAULT &&

+               png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS)))

+#endif

+         {

+            /* TODO: review, what is wrong with a zero length unknown chunk? */

+            if (up->size == 0)

+               png_warning(png_ptr, "Writing zero-length unknown chunk");

+

+            png_write_chunk(png_ptr, up->name, up->data, up->size);

+         }

+      }

+   }

+}

+#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */

+

+/* Writes all the PNG information.  This is the suggested way to use the

+ * library.  If you have a new chunk to add, make a function to write it,

+ * and put it in the correct location here.  If you want the chunk written

+ * after the image data, put it in png_write_end().  I strongly encourage

+ * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing

+ * the chunk, as that will keep the code from breaking if you want to just

+ * write a plain PNG file.  If you have long comments, I suggest writing

+ * them in png_write_end(), and compressing them.

+ */

+void PNGAPI

+png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)

+{

+   png_debug(1, "in png_write_info_before_PLTE");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))

+   {

+   /* Write PNG signature */

+   png_write_sig(png_ptr);

+

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+   if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \

+       (png_ptr->mng_features_permitted))

+   {

+      png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");

+      png_ptr->mng_features_permitted = 0;

+   }

+#endif

+

+   /* Write IHDR information. */

+   png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,

+       info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,

+       info_ptr->filter_type,

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+       info_ptr->interlace_type

+#else

+       0

+#endif

+      );

+

+   /* The rest of these check to see if the valid field has the appropriate

+    * flag set, and if it does, writes the chunk.

+    *

+    * 1.6.0: COLORSPACE support controls the writing of these chunks too, and

+    * the chunks will be written if the WRITE routine is there and information

+    * is available in the COLORSPACE.  (See png_colorspace_sync_info in png.c

+    * for where the valid flags get set.)

+    *

+    * Under certain circumstances the colorspace can be invalidated without

+    * syncing the info_struct 'valid' flags; this happens if libpng detects and

+    * error and calls png_error while the color space is being set, yet the

+    * application continues writing the PNG.  So check the 'invalid' flag here

+    * too.

+    */

+#ifdef PNG_GAMMA_SUPPORTED

+#  ifdef PNG_WRITE_gAMA_SUPPORTED

+      if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&

+         (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) &&

+         (info_ptr->valid & PNG_INFO_gAMA))

+         png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);

+#  endif

+#endif

+

+#ifdef PNG_COLORSPACE_SUPPORTED

+   /* Write only one of sRGB or an ICC profile.  If a profile was supplied

+    * and it matches one of the known sRGB ones issue a warning.

+    */

+#  ifdef PNG_WRITE_iCCP_SUPPORTED

+      if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&

+         (info_ptr->valid & PNG_INFO_iCCP))

+      {

+#        ifdef PNG_WRITE_sRGB_SUPPORTED

+            if (info_ptr->valid & PNG_INFO_sRGB)

+               png_app_warning(png_ptr,

+                  "profile matches sRGB but writing iCCP instead");

+#        endif

+

+         png_write_iCCP(png_ptr, info_ptr->iccp_name,

+            info_ptr->iccp_profile);

+      }

+#     ifdef PNG_WRITE_sRGB_SUPPORTED

+         else

+#     endif

+#  endif

+

+#  ifdef PNG_WRITE_sRGB_SUPPORTED

+      if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&

+         (info_ptr->valid & PNG_INFO_sRGB))

+         png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);

+#  endif /* WRITE_sRGB */

+#endif /* COLORSPACE */

+

+#ifdef PNG_WRITE_sBIT_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_sBIT)

+      png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);

+#endif

+

+#ifdef PNG_COLORSPACE_SUPPORTED

+#  ifdef PNG_WRITE_cHRM_SUPPORTED

+      if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&

+         (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) &&

+         (info_ptr->valid & PNG_INFO_cHRM))

+         png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy);

+#  endif

+#endif

+

+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED

+      write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);

+#endif

+

+      png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;

+   }

+}

+

+void PNGAPI

+png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)

+{

+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)

+   int i;

+#endif

+

+   png_debug(1, "in png_write_info");

+

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   png_write_info_before_PLTE(png_ptr, info_ptr);

+

+   if (info_ptr->valid & PNG_INFO_PLTE)

+      png_write_PLTE(png_ptr, info_ptr->palette,

+          (png_uint_32)info_ptr->num_palette);

+

+   else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      png_error(png_ptr, "Valid palette required for paletted images");

+

+#ifdef PNG_WRITE_tRNS_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_tRNS)

+   {

+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED

+      /* Invert the alpha channel (in tRNS) */

+      if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&

+          info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      {

+         int j;

+         for (j = 0; j<(int)info_ptr->num_trans; j++)

+            info_ptr->trans_alpha[j] =

+               (png_byte)(255 - info_ptr->trans_alpha[j]);

+      }

+#endif

+      png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color),

+          info_ptr->num_trans, info_ptr->color_type);

+   }

+#endif

+#ifdef PNG_WRITE_bKGD_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_bKGD)

+      png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);

+#endif

+

+#ifdef PNG_WRITE_hIST_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_hIST)

+      png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);

+#endif

+

+#ifdef PNG_WRITE_oFFs_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_oFFs)

+      png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,

+          info_ptr->offset_unit_type);

+#endif

+

+#ifdef PNG_WRITE_pCAL_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_pCAL)

+      png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,

+          info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,

+          info_ptr->pcal_units, info_ptr->pcal_params);

+#endif

+

+#ifdef PNG_WRITE_sCAL_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_sCAL)

+      png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,

+          info_ptr->scal_s_width, info_ptr->scal_s_height);

+#endif /* sCAL */

+

+#ifdef PNG_WRITE_pHYs_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_pHYs)

+      png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,

+          info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);

+#endif /* pHYs */

+

+#ifdef PNG_WRITE_tIME_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_tIME)

+   {

+      png_write_tIME(png_ptr, &(info_ptr->mod_time));

+      png_ptr->mode |= PNG_WROTE_tIME;

+   }

+#endif /* tIME */

+

+#ifdef PNG_WRITE_sPLT_SUPPORTED

+   if (info_ptr->valid & PNG_INFO_sPLT)

+      for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)

+         png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);

+#endif /* sPLT */

+

+#ifdef PNG_WRITE_TEXT_SUPPORTED

+   /* Check to see if we need to write text chunks */

+   for (i = 0; i < info_ptr->num_text; i++)

+   {

+      png_debug2(2, "Writing header text chunk %d, type %d", i,

+          info_ptr->text[i].compression);

+      /* An internationalized chunk? */

+      if (info_ptr->text[i].compression > 0)

+      {

+#ifdef PNG_WRITE_iTXt_SUPPORTED

+         /* Write international chunk */

+         png_write_iTXt(png_ptr,

+             info_ptr->text[i].compression,

+             info_ptr->text[i].key,

+             info_ptr->text[i].lang,

+             info_ptr->text[i].lang_key,

+             info_ptr->text[i].text);

+#else

+          png_warning(png_ptr, "Unable to write international text");

+#endif

+          /* Mark this chunk as written */

+          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;

+      }

+

+      /* If we want a compressed text chunk */

+      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)

+      {

+#ifdef PNG_WRITE_zTXt_SUPPORTED

+         /* Write compressed chunk */

+         png_write_zTXt(png_ptr, info_ptr->text[i].key,

+             info_ptr->text[i].text, 0,

+             info_ptr->text[i].compression);

+#else

+         png_warning(png_ptr, "Unable to write compressed text");

+#endif

+         /* Mark this chunk as written */

+         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;

+      }

+

+      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)

+      {

+#ifdef PNG_WRITE_tEXt_SUPPORTED

+         /* Write uncompressed chunk */

+         png_write_tEXt(png_ptr, info_ptr->text[i].key,

+             info_ptr->text[i].text,

+             0);

+         /* Mark this chunk as written */

+         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;

+#else

+         /* Can't get here */

+         png_warning(png_ptr, "Unable to write uncompressed text");

+#endif

+      }

+   }

+#endif /* tEXt */

+

+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED

+   write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE);

+#endif

+}

+

+/* Writes the end of the PNG file.  If you don't want to write comments or

+ * time information, you can pass NULL for info.  If you already wrote these

+ * in png_write_info(), do not write them again here.  If you have long

+ * comments, I suggest writing them here, and compressing them.

+ */

+void PNGAPI

+png_write_end(png_structrp png_ptr, png_inforp info_ptr)

+{

+   png_debug(1, "in png_write_end");

+

+   if (png_ptr == NULL)

+      return;

+

+   if (!(png_ptr->mode & PNG_HAVE_IDAT))

+      png_error(png_ptr, "No IDATs written into file");

+

+#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED

+   if (png_ptr->num_palette_max > png_ptr->num_palette)

+      png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");

+#endif

+

+   /* See if user wants us to write information chunks */

+   if (info_ptr != NULL)

+   {

+#ifdef PNG_WRITE_TEXT_SUPPORTED

+      int i; /* local index variable */

+#endif

+#ifdef PNG_WRITE_tIME_SUPPORTED

+      /* Check to see if user has supplied a time chunk */

+      if ((info_ptr->valid & PNG_INFO_tIME) &&

+          !(png_ptr->mode & PNG_WROTE_tIME))

+         png_write_tIME(png_ptr, &(info_ptr->mod_time));

+

+#endif

+#ifdef PNG_WRITE_TEXT_SUPPORTED

+      /* Loop through comment chunks */

+      for (i = 0; i < info_ptr->num_text; i++)

+      {

+         png_debug2(2, "Writing trailer text chunk %d, type %d", i,

+            info_ptr->text[i].compression);

+         /* An internationalized chunk? */

+         if (info_ptr->text[i].compression > 0)

+         {

+#ifdef PNG_WRITE_iTXt_SUPPORTED

+            /* Write international chunk */

+            png_write_iTXt(png_ptr,

+                info_ptr->text[i].compression,

+                info_ptr->text[i].key,

+                info_ptr->text[i].lang,

+                info_ptr->text[i].lang_key,

+                info_ptr->text[i].text);

+#else

+            png_warning(png_ptr, "Unable to write international text");

+#endif

+            /* Mark this chunk as written */

+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;

+         }

+

+         else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)

+         {

+#ifdef PNG_WRITE_zTXt_SUPPORTED

+            /* Write compressed chunk */

+            png_write_zTXt(png_ptr, info_ptr->text[i].key,

+                info_ptr->text[i].text, 0,

+                info_ptr->text[i].compression);

+#else

+            png_warning(png_ptr, "Unable to write compressed text");

+#endif

+            /* Mark this chunk as written */

+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;

+         }

+

+         else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)

+         {

+#ifdef PNG_WRITE_tEXt_SUPPORTED

+            /* Write uncompressed chunk */

+            png_write_tEXt(png_ptr, info_ptr->text[i].key,

+                info_ptr->text[i].text, 0);

+#else

+            png_warning(png_ptr, "Unable to write uncompressed text");

+#endif

+

+            /* Mark this chunk as written */

+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;

+         }

+      }

+#endif

+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED

+      write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);

+#endif

+   }

+

+   png_ptr->mode |= PNG_AFTER_IDAT;

+

+   /* Write end of PNG file */

+   png_write_IEND(png_ptr);

+   /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,

+    * and restored again in libpng-1.2.30, may cause some applications that

+    * do not set png_ptr->output_flush_fn to crash.  If your application

+    * experiences a problem, please try building libpng with

+    * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to

+    * png-mng-implement at lists.sf.net .

+    */

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+#  ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED

+   png_flush(png_ptr);

+#  endif

+#endif

+}

+

+#ifdef PNG_CONVERT_tIME_SUPPORTED

+void PNGAPI

+png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime)

+{

+   png_debug(1, "in png_convert_from_struct_tm");

+

+   ptime->year = (png_uint_16)(1900 + ttime->tm_year);

+   ptime->month = (png_byte)(ttime->tm_mon + 1);

+   ptime->day = (png_byte)ttime->tm_mday;

+   ptime->hour = (png_byte)ttime->tm_hour;

+   ptime->minute = (png_byte)ttime->tm_min;

+   ptime->second = (png_byte)ttime->tm_sec;

+}

+

+void PNGAPI

+png_convert_from_time_t(png_timep ptime, time_t ttime)

+{

+   struct tm *tbuf;

+

+   png_debug(1, "in png_convert_from_time_t");

+

+   tbuf = gmtime(&ttime);

+   png_convert_from_struct_tm(ptime, tbuf);

+}

+#endif

+

+/* Initialize png_ptr structure, and allocate any memory needed */

+PNG_FUNCTION(png_structp,PNGAPI

+png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,

+    png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)

+{

+#ifndef PNG_USER_MEM_SUPPORTED

+   png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,

+      error_fn, warn_fn, NULL, NULL, NULL);

+#else

+   return png_create_write_struct_2(user_png_ver, error_ptr, error_fn,

+       warn_fn, NULL, NULL, NULL);

+}

+

+/* Alternate initialize png_ptr structure, and allocate any memory needed */

+PNG_FUNCTION(png_structp,PNGAPI

+png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,

+    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,

+    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)

+{

+   png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,

+      error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);

+#endif /* PNG_USER_MEM_SUPPORTED */

+   if (png_ptr != NULL)

+   {

+      /* Set the zlib control values to defaults; they can be overridden by the

+       * application after the struct has been created.

+       */

+      png_ptr->zbuffer_size = PNG_ZBUF_SIZE;

+

+      /* The 'zlib_strategy' setting is irrelevant because png_default_claim in

+       * pngwutil.c defaults it according to whether or not filters will be

+       * used, and ignores this setting.

+       */

+      png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY;

+      png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION;

+      png_ptr->zlib_mem_level = 8;

+      png_ptr->zlib_window_bits = 15;

+      png_ptr->zlib_method = 8;

+

+#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED

+      png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY;

+      png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION;

+      png_ptr->zlib_text_mem_level = 8;

+      png_ptr->zlib_text_window_bits = 15;

+      png_ptr->zlib_text_method = 8;

+#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */

+

+      /* This is a highly dubious configuration option; by default it is off,

+       * but it may be appropriate for private builds that are testing

+       * extensions not conformant to the current specification, or of

+       * applications that must not fail to write at all costs!

+       */

+#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED

+      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;

+      /* In stable builds only warn if an application error can be completely

+       * handled.

+       */

+#endif

+

+      /* App warnings are warnings in release (or release candidate) builds but

+       * are errors during development.

+       */

+#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC

+      png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;

+#endif

+

+      /* TODO: delay this, it can be done in png_init_io() (if the app doesn't

+       * do it itself) avoiding setting the default function if it is not

+       * required.

+       */

+      png_set_write_fn(png_ptr, NULL, NULL, NULL);

+   }

+

+   return png_ptr;

+}

+

+

+/* Write a few rows of image data.  If the image is interlaced,

+ * either you will have to write the 7 sub images, or, if you

+ * have called png_set_interlace_handling(), you will have to

+ * "write" the image seven times.

+ */

+void PNGAPI

+png_write_rows(png_structrp png_ptr, png_bytepp row,

+    png_uint_32 num_rows)

+{

+   png_uint_32 i; /* row counter */

+   png_bytepp rp; /* row pointer */

+

+   png_debug(1, "in png_write_rows");

+

+   if (png_ptr == NULL)

+      return;

+

+   /* Loop through the rows */

+   for (i = 0, rp = row; i < num_rows; i++, rp++)

+   {

+      png_write_row(png_ptr, *rp);

+   }

+}

+

+/* Write the image.  You only need to call this function once, even

+ * if you are writing an interlaced image.

+ */

+void PNGAPI

+png_write_image(png_structrp png_ptr, png_bytepp image)

+{

+   png_uint_32 i; /* row index */

+   int pass, num_pass; /* pass variables */

+   png_bytepp rp; /* points to current row */

+

+   if (png_ptr == NULL)

+      return;

+

+   png_debug(1, "in png_write_image");

+

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+   /* Initialize interlace handling.  If image is not interlaced,

+    * this will set pass to 1

+    */

+   num_pass = png_set_interlace_handling(png_ptr);

+#else

+   num_pass = 1;

+#endif

+   /* Loop through passes */

+   for (pass = 0; pass < num_pass; pass++)

+   {

+      /* Loop through image */

+      for (i = 0, rp = image; i < png_ptr->height; i++, rp++)

+      {

+         png_write_row(png_ptr, *rp);

+      }

+   }

+}

+

+/* Called by user to write a row of image data */

+void PNGAPI

+png_write_row(png_structrp png_ptr, png_const_bytep row)

+{

+   /* 1.5.6: moved from png_struct to be a local structure: */

+   png_row_info row_info;

+

+   if (png_ptr == NULL)

+      return;

+

+   png_debug2(1, "in png_write_row (row %u, pass %d)",

+      png_ptr->row_number, png_ptr->pass);

+

+   /* Initialize transformations and other stuff if first time */

+   if (png_ptr->row_number == 0 && png_ptr->pass == 0)

+   {

+      /* Make sure we wrote the header info */

+      if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))

+         png_error(png_ptr,

+             "png_write_info was never called before png_write_row");

+

+      /* Check for transforms that have been set but were defined out */

+#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)

+      if (png_ptr->transformations & PNG_INVERT_MONO)

+         png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");

+#endif

+

+#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)

+      if (png_ptr->transformations & PNG_FILLER)

+         png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");

+#endif

+#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \

+    defined(PNG_READ_PACKSWAP_SUPPORTED)

+      if (png_ptr->transformations & PNG_PACKSWAP)

+         png_warning(png_ptr,

+             "PNG_WRITE_PACKSWAP_SUPPORTED is not defined");

+#endif

+

+#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)

+      if (png_ptr->transformations & PNG_PACK)

+         png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");

+#endif

+

+#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)

+      if (png_ptr->transformations & PNG_SHIFT)

+         png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");

+#endif

+

+#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)

+      if (png_ptr->transformations & PNG_BGR)

+         png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");

+#endif

+

+#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)

+      if (png_ptr->transformations & PNG_SWAP_BYTES)

+         png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");

+#endif

+

+      png_write_start_row(png_ptr);

+   }

+

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+   /* If interlaced and not interested in row, return */

+   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))

+   {

+      switch (png_ptr->pass)

+      {

+         case 0:

+            if (png_ptr->row_number & 0x07)

+            {

+               png_write_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 1:

+            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)

+            {

+               png_write_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 2:

+            if ((png_ptr->row_number & 0x07) != 4)

+            {

+               png_write_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 3:

+            if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)

+            {

+               png_write_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 4:

+            if ((png_ptr->row_number & 0x03) != 2)

+            {

+               png_write_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 5:

+            if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)

+            {

+               png_write_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         case 6:

+            if (!(png_ptr->row_number & 0x01))

+            {

+               png_write_finish_row(png_ptr);

+               return;

+            }

+            break;

+

+         default: /* error: ignore it */

+            break;

+      }

+   }

+#endif

+

+   /* Set up row info for transformations */

+   row_info.color_type = png_ptr->color_type;

+   row_info.width = png_ptr->usr_width;

+   row_info.channels = png_ptr->usr_channels;

+   row_info.bit_depth = png_ptr->usr_bit_depth;

+   row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels);

+   row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);

+

+   png_debug1(3, "row_info->color_type = %d", row_info.color_type);

+   png_debug1(3, "row_info->width = %u", row_info.width);

+   png_debug1(3, "row_info->channels = %d", row_info.channels);

+   png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth);

+   png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth);

+   png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes);

+

+   /* Copy user's row into buffer, leaving room for filter byte. */

+   memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes);

+

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+   /* Handle interlacing */

+   if (png_ptr->interlaced && png_ptr->pass < 6 &&

+       (png_ptr->transformations & PNG_INTERLACE))

+   {

+      png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);

+      /* This should always get caught above, but still ... */

+      if (!(row_info.width))

+      {

+         png_write_finish_row(png_ptr);

+         return;

+      }

+   }

+#endif

+

+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED

+   /* Handle other transformations */

+   if (png_ptr->transformations)

+      png_do_write_transformations(png_ptr, &row_info);

+#endif

+

+   /* At this point the row_info pixel depth must match the 'transformed' depth,

+    * which is also the output depth.

+    */

+   if (row_info.pixel_depth != png_ptr->pixel_depth ||

+      row_info.pixel_depth != png_ptr->transformed_pixel_depth)

+      png_error(png_ptr, "internal write transform logic error");

+

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+   /* Write filter_method 64 (intrapixel differencing) only if

+    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and

+    * 2. Libpng did not write a PNG signature (this filter_method is only

+    *    used in PNG datastreams that are embedded in MNG datastreams) and

+    * 3. The application called png_permit_mng_features with a mask that

+    *    included PNG_FLAG_MNG_FILTER_64 and

+    * 4. The filter_method is 64 and

+    * 5. The color_type is RGB or RGBA

+    */

+   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&

+       (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))

+   {

+      /* Intrapixel differencing */

+      png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1);

+   }

+#endif

+

+/* Added at libpng-1.5.10 */

+#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED

+   /* Check for out-of-range palette index */

+   if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&

+       png_ptr->num_palette_max >= 0)

+      png_do_check_palette_indexes(png_ptr, &row_info);

+#endif

+

+   /* Find a filter if necessary, filter the row and write it out. */

+   png_write_find_filter(png_ptr, &row_info);

+

+   if (png_ptr->write_row_fn != NULL)

+      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);

+}

+

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+/* Set the automatic flush interval or 0 to turn flushing off */

+void PNGAPI

+png_set_flush(png_structrp png_ptr, int nrows)

+{

+   png_debug(1, "in png_set_flush");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);

+}

+

+/* Flush the current output buffers now */

+void PNGAPI

+png_write_flush(png_structrp png_ptr)

+{

+   png_debug(1, "in png_write_flush");

+

+   if (png_ptr == NULL)

+      return;

+

+   /* We have already written out all of the data */

+   if (png_ptr->row_number >= png_ptr->num_rows)

+      return;

+

+   png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH);

+   png_ptr->flush_rows = 0;

+   png_flush(png_ptr);

+}

+#endif /* PNG_WRITE_FLUSH_SUPPORTED */

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */

+#endif

+

+/* Free any memory used in png_ptr struct without freeing the struct itself. */

+static void

+png_write_destroy(png_structrp png_ptr)

+{

+   png_debug(1, "in png_write_destroy");

+

+   /* Free any memory zlib uses */

+   if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)

+      deflateEnd(&png_ptr->zstream);

+

+   /* Free our memory.  png_free checks NULL for us. */

+   png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);

+   png_free(png_ptr, png_ptr->row_buf);

+#ifdef PNG_WRITE_FILTER_SUPPORTED

+   png_free(png_ptr, png_ptr->prev_row);

+   png_free(png_ptr, png_ptr->sub_row);

+   png_free(png_ptr, png_ptr->up_row);

+   png_free(png_ptr, png_ptr->avg_row);

+   png_free(png_ptr, png_ptr->paeth_row);

+#endif

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+   /* Use this to save a little code space, it doesn't free the filter_costs */

+   png_reset_filter_heuristics(png_ptr);

+   png_free(png_ptr, png_ptr->filter_costs);

+   png_free(png_ptr, png_ptr->inv_filter_costs);

+#endif

+

+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+   png_free(png_ptr, png_ptr->chunk_list);

+#endif

+

+   /* The error handling and memory handling information is left intact at this

+    * point: the jmp_buf may still have to be freed.  See png_destroy_png_struct

+    * for how this happens.

+    */

+}

+

+/* Free all memory used by the write.

+ * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for

+ * *png_ptr_ptr.  Prior to 1.6.0 it would accept such a value and it would free

+ * the passed in info_structs but it would quietly fail to free any of the data

+ * inside them.  In 1.6.0 it quietly does nothing (it has to be quiet because it

+ * has no png_ptr.)

+ */

+void PNGAPI

+png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)

+{

+   png_debug(1, "in png_destroy_write_struct");

+

+   if (png_ptr_ptr != NULL)

+   {

+      png_structrp png_ptr = *png_ptr_ptr;

+

+      if (png_ptr != NULL) /* added in libpng 1.6.0 */

+      {

+         png_destroy_info_struct(png_ptr, info_ptr_ptr);

+

+         *png_ptr_ptr = NULL;

+         png_write_destroy(png_ptr);

+         png_destroy_png_struct(png_ptr);

+      }

+   }

+}

+

+/* Allow the application to select one or more row filters to use. */

+void PNGAPI

+png_set_filter(png_structrp png_ptr, int method, int filters)

+{

+   png_debug(1, "in png_set_filter");

+

+   if (png_ptr == NULL)

+      return;

+

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&

+       (method == PNG_INTRAPIXEL_DIFFERENCING))

+      method = PNG_FILTER_TYPE_BASE;

+

+#endif

+   if (method == PNG_FILTER_TYPE_BASE)

+   {

+      switch (filters & (PNG_ALL_FILTERS | 0x07))

+      {

+#ifdef PNG_WRITE_FILTER_SUPPORTED

+         case 5:

+         case 6:

+         case 7: png_app_error(png_ptr, "Unknown row filter for method 0");

+            /* FALL THROUGH */

+#endif /* PNG_WRITE_FILTER_SUPPORTED */

+         case PNG_FILTER_VALUE_NONE:

+            png_ptr->do_filter = PNG_FILTER_NONE; break;

+

+#ifdef PNG_WRITE_FILTER_SUPPORTED

+         case PNG_FILTER_VALUE_SUB:

+            png_ptr->do_filter = PNG_FILTER_SUB; break;

+

+         case PNG_FILTER_VALUE_UP:

+            png_ptr->do_filter = PNG_FILTER_UP; break;

+

+         case PNG_FILTER_VALUE_AVG:

+            png_ptr->do_filter = PNG_FILTER_AVG; break;

+

+         case PNG_FILTER_VALUE_PAETH:

+            png_ptr->do_filter = PNG_FILTER_PAETH; break;

+

+         default:

+            png_ptr->do_filter = (png_byte)filters; break;

+#else

+         default:

+            png_app_error(png_ptr, "Unknown row filter for method 0");

+#endif /* PNG_WRITE_FILTER_SUPPORTED */

+      }

+

+      /* If we have allocated the row_buf, this means we have already started

+       * with the image and we should have allocated all of the filter buffers

+       * that have been selected.  If prev_row isn't already allocated, then

+       * it is too late to start using the filters that need it, since we

+       * will be missing the data in the previous row.  If an application

+       * wants to start and stop using particular filters during compression,

+       * it should start out with all of the filters, and then add and

+       * remove them after the start of compression.

+       */

+      if (png_ptr->row_buf != NULL)

+      {

+#ifdef PNG_WRITE_FILTER_SUPPORTED

+         if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)

+         {

+            png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,

+                (png_ptr->rowbytes + 1));

+            png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;

+         }

+

+         if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)

+         {

+            if (png_ptr->prev_row == NULL)

+            {

+               png_warning(png_ptr, "Can't add Up filter after starting");

+               png_ptr->do_filter = (png_byte)(png_ptr->do_filter &

+                   ~PNG_FILTER_UP);

+            }

+

+            else

+            {

+               png_ptr->up_row = (png_bytep)png_malloc(png_ptr,

+                   (png_ptr->rowbytes + 1));

+               png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;

+            }

+         }

+

+         if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)

+         {

+            if (png_ptr->prev_row == NULL)

+            {

+               png_warning(png_ptr, "Can't add Average filter after starting");

+               png_ptr->do_filter = (png_byte)(png_ptr->do_filter &

+                   ~PNG_FILTER_AVG);

+            }

+

+            else

+            {

+               png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,

+                   (png_ptr->rowbytes + 1));

+               png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;

+            }

+         }

+

+         if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&

+             png_ptr->paeth_row == NULL)

+         {

+            if (png_ptr->prev_row == NULL)

+            {

+               png_warning(png_ptr, "Can't add Paeth filter after starting");

+               png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);

+            }

+

+            else

+            {

+               png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,

+                   (png_ptr->rowbytes + 1));

+               png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;

+            }

+         }

+

+         if (png_ptr->do_filter == PNG_NO_FILTERS)

+#endif /* PNG_WRITE_FILTER_SUPPORTED */

+            png_ptr->do_filter = PNG_FILTER_NONE;

+      }

+   }

+   else

+      png_error(png_ptr, "Unknown custom filter method");

+}

+

+/* This allows us to influence the way in which libpng chooses the "best"

+ * filter for the current scanline.  While the "minimum-sum-of-absolute-

+ * differences metric is relatively fast and effective, there is some

+ * question as to whether it can be improved upon by trying to keep the

+ * filtered data going to zlib more consistent, hopefully resulting in

+ * better compression.

+ */

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED      /* GRR 970116 */

+/* Convenience reset API. */

+static void

+png_reset_filter_heuristics(png_structrp png_ptr)

+{

+   /* Clear out any old values in the 'weights' - this must be done because if

+    * the app calls set_filter_heuristics multiple times with different

+    * 'num_weights' values we would otherwise potentially have wrong sized

+    * arrays.

+    */

+   png_ptr->num_prev_filters = 0;

+   png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;

+   if (png_ptr->prev_filters != NULL)

+   {

+      png_bytep old = png_ptr->prev_filters;

+      png_ptr->prev_filters = NULL;

+      png_free(png_ptr, old);

+   }

+   if (png_ptr->filter_weights != NULL)

+   {

+      png_uint_16p old = png_ptr->filter_weights;

+      png_ptr->filter_weights = NULL;

+      png_free(png_ptr, old);

+   }

+

+   if (png_ptr->inv_filter_weights != NULL)

+   {

+      png_uint_16p old = png_ptr->inv_filter_weights;

+      png_ptr->inv_filter_weights = NULL;

+      png_free(png_ptr, old);

+   }

+

+   /* Leave the filter_costs - this array is fixed size. */

+}

+

+static int

+png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method,

+   int num_weights)

+{

+   if (png_ptr == NULL)

+      return 0;

+

+   /* Clear out the arrays */

+   png_reset_filter_heuristics(png_ptr);

+

+   /* Check arguments; the 'reset' function makes the correct settings for the

+    * unweighted case, but we must handle the weight case by initializing the

+    * arrays for the caller.

+    */

+   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+   {

+      int i;

+

+      if (num_weights > 0)

+      {

+         png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,

+             (png_uint_32)((sizeof (png_byte)) * num_weights));

+

+         /* To make sure that the weighting starts out fairly */

+         for (i = 0; i < num_weights; i++)

+         {

+            png_ptr->prev_filters[i] = 255;

+         }

+

+         png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,

+             (png_uint_32)((sizeof (png_uint_16)) * num_weights));

+

+         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,

+             (png_uint_32)((sizeof (png_uint_16)) * num_weights));

+

+         for (i = 0; i < num_weights; i++)

+         {

+            png_ptr->inv_filter_weights[i] =

+            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;

+         }

+

+         /* Safe to set this now */

+         png_ptr->num_prev_filters = (png_byte)num_weights;

+      }

+

+      /* If, in the future, there are other filter methods, this would

+       * need to be based on png_ptr->filter.

+       */

+      if (png_ptr->filter_costs == NULL)

+      {

+         png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,

+             (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST));

+

+         png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,

+             (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST));

+      }

+

+      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)

+      {

+         png_ptr->inv_filter_costs[i] =

+         png_ptr->filter_costs[i] = PNG_COST_FACTOR;

+      }

+

+      /* All the arrays are inited, safe to set this: */

+      png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED;

+

+      /* Return the 'ok' code. */

+      return 1;

+   }

+   else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT ||

+      heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)

+   {

+      return 1;

+   }

+   else

+   {

+      png_warning(png_ptr, "Unknown filter heuristic method");

+      return 0;

+   }

+}

+

+/* Provide floating and fixed point APIs */

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+void PNGAPI

+png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method,

+    int num_weights, png_const_doublep filter_weights,

+    png_const_doublep filter_costs)

+{

+   png_debug(1, "in png_set_filter_heuristics");

+

+   /* The internal API allocates all the arrays and ensures that the elements of

+    * those arrays are set to the default value.

+    */

+   if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))

+      return;

+

+   /* If using the weighted method copy in the weights. */

+   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+   {

+      int i;

+      for (i = 0; i < num_weights; i++)

+      {

+         if (filter_weights[i] <= 0.0)

+         {

+            png_ptr->inv_filter_weights[i] =

+            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;

+         }

+

+         else

+         {

+            png_ptr->inv_filter_weights[i] =

+                (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5);

+

+            png_ptr->filter_weights[i] =

+                (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5);

+         }

+      }

+

+      /* Here is where we set the relative costs of the different filters.  We

+       * should take the desired compression level into account when setting

+       * the costs, so that Paeth, for instance, has a high relative cost at low

+       * compression levels, while it has a lower relative cost at higher

+       * compression settings.  The filter types are in order of increasing

+       * relative cost, so it would be possible to do this with an algorithm.

+       */

+      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0)

+      {

+         png_ptr->inv_filter_costs[i] =

+             (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5);

+

+         png_ptr->filter_costs[i] =

+             (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5);

+      }

+   }

+}

+#endif /* FLOATING_POINT */

+

+#ifdef PNG_FIXED_POINT_SUPPORTED

+void PNGAPI

+png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method,

+    int num_weights, png_const_fixed_point_p filter_weights,

+    png_const_fixed_point_p filter_costs)

+{

+   png_debug(1, "in png_set_filter_heuristics_fixed");

+

+   /* The internal API allocates all the arrays and ensures that the elements of

+    * those arrays are set to the default value.

+    */

+   if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))

+      return;

+

+   /* If using the weighted method copy in the weights. */

+   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+   {

+      int i;

+      for (i = 0; i < num_weights; i++)

+      {

+         if (filter_weights[i] <= 0)

+         {

+            png_ptr->inv_filter_weights[i] =

+            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;

+         }

+

+         else

+         {

+            png_ptr->inv_filter_weights[i] = (png_uint_16)

+               ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1);

+

+            png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR*

+               PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]);

+         }

+      }

+

+      /* Here is where we set the relative costs of the different filters.  We

+       * should take the desired compression level into account when setting

+       * the costs, so that Paeth, for instance, has a high relative cost at low

+       * compression levels, while it has a lower relative cost at higher

+       * compression settings.  The filter types are in order of increasing

+       * relative cost, so it would be possible to do this with an algorithm.

+       */

+      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)

+         if (filter_costs[i] >= PNG_FP_1)

+      {

+         png_uint_32 tmp;

+

+         /* Use a 32 bit unsigned temporary here because otherwise the

+          * intermediate value will be a 32 bit *signed* integer (ANSI rules)

+          * and this will get the wrong answer on division.

+          */

+         tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2);

+         tmp /= filter_costs[i];

+

+         png_ptr->inv_filter_costs[i] = (png_uint_16)tmp;

+

+         tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF;

+         tmp /= PNG_FP_1;

+

+         png_ptr->filter_costs[i] = (png_uint_16)tmp;

+      }

+   }

+}

+#endif /* FIXED_POINT */

+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */

+

+void PNGAPI

+png_set_compression_level(png_structrp png_ptr, int level)

+{

+   png_debug(1, "in png_set_compression_level");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->zlib_level = level;

+}

+

+void PNGAPI

+png_set_compression_mem_level(png_structrp png_ptr, int mem_level)

+{

+   png_debug(1, "in png_set_compression_mem_level");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->zlib_mem_level = mem_level;

+}

+

+void PNGAPI

+png_set_compression_strategy(png_structrp png_ptr, int strategy)

+{

+   png_debug(1, "in png_set_compression_strategy");

+

+   if (png_ptr == NULL)

+      return;

+

+   /* The flag setting here prevents the libpng dynamic selection of strategy.

+    */

+   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;

+   png_ptr->zlib_strategy = strategy;

+}

+

+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a

+ * smaller value of window_bits if it can do so safely.

+ */

+void PNGAPI

+png_set_compression_window_bits(png_structrp png_ptr, int window_bits)

+{

+   if (png_ptr == NULL)

+      return;

+

+   /* Prior to 1.6.0 this would warn but then set the window_bits value, this

+    * meant that negative window bits values could be selected which would cause

+    * libpng to write a non-standard PNG file with raw deflate or gzip

+    * compressed IDAT or ancillary chunks.  Such files can be read and there is

+    * no warning on read, so this seems like a very bad idea.

+    */

+   if (window_bits > 15)

+   {

+      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");

+      window_bits = 15;

+   }

+

+   else if (window_bits < 8)

+   {

+      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");

+      window_bits = 8;

+   }

+

+   png_ptr->zlib_window_bits = window_bits;

+}

+

+void PNGAPI

+png_set_compression_method(png_structrp png_ptr, int method)

+{

+   png_debug(1, "in png_set_compression_method");

+

+   if (png_ptr == NULL)

+      return;

+

+   /* This would produce an invalid PNG file if it worked, but it doesn't and

+    * deflate will fault it, so it is harmless to just warn here.

+    */

+   if (method != 8)

+      png_warning(png_ptr, "Only compression method 8 is supported by PNG");

+

+   png_ptr->zlib_method = method;

+}

+

+/* The following were added to libpng-1.5.4 */

+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED

+void PNGAPI

+png_set_text_compression_level(png_structrp png_ptr, int level)

+{

+   png_debug(1, "in png_set_text_compression_level");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->zlib_text_level = level;

+}

+

+void PNGAPI

+png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level)

+{

+   png_debug(1, "in png_set_text_compression_mem_level");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->zlib_text_mem_level = mem_level;

+}

+

+void PNGAPI

+png_set_text_compression_strategy(png_structrp png_ptr, int strategy)

+{

+   png_debug(1, "in png_set_text_compression_strategy");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->zlib_text_strategy = strategy;

+}

+

+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a

+ * smaller value of window_bits if it can do so safely.

+ */

+void PNGAPI

+png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits)

+{

+   if (png_ptr == NULL)

+      return;

+

+   if (window_bits > 15)

+   {

+      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");

+      window_bits = 15;

+   }

+

+   else if (window_bits < 8)

+   {

+      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");

+      window_bits = 8;

+   }

+

+   png_ptr->zlib_text_window_bits = window_bits;

+}

+

+void PNGAPI

+png_set_text_compression_method(png_structrp png_ptr, int method)

+{

+   png_debug(1, "in png_set_text_compression_method");

+

+   if (png_ptr == NULL)

+      return;

+

+   if (method != 8)

+      png_warning(png_ptr, "Only compression method 8 is supported by PNG");

+

+   png_ptr->zlib_text_method = method;

+}

+#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */

+/* end of API added to libpng-1.5.4 */

+

+void PNGAPI

+png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn)

+{

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->write_row_fn = write_row_fn;

+}

+

+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED

+void PNGAPI

+png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr

+    write_user_transform_fn)

+{

+   png_debug(1, "in png_set_write_user_transform_fn");

+

+   if (png_ptr == NULL)

+      return;

+

+   png_ptr->transformations |= PNG_USER_TRANSFORM;

+   png_ptr->write_user_transform_fn = write_user_transform_fn;

+}

+#endif

+

+

+#ifdef PNG_INFO_IMAGE_SUPPORTED

+void PNGAPI

+png_write_png(png_structrp png_ptr, png_inforp info_ptr,

+    int transforms, voidp params)

+{

+   if (png_ptr == NULL || info_ptr == NULL)

+      return;

+

+   /* Write the file header information. */

+   png_write_info(png_ptr, info_ptr);

+

+   /* ------ these transformations don't touch the info structure ------- */

+

+#ifdef PNG_WRITE_INVERT_SUPPORTED

+   /* Invert monochrome pixels */

+   if (transforms & PNG_TRANSFORM_INVERT_MONO)

+      png_set_invert_mono(png_ptr);

+#endif

+

+#ifdef PNG_WRITE_SHIFT_SUPPORTED

+   /* Shift the pixels up to a legal bit depth and fill in

+    * as appropriate to correctly scale the image.

+    */

+   if ((transforms & PNG_TRANSFORM_SHIFT)

+       && (info_ptr->valid & PNG_INFO_sBIT))

+      png_set_shift(png_ptr, &info_ptr->sig_bit);

+#endif

+

+#ifdef PNG_WRITE_PACK_SUPPORTED

+   /* Pack pixels into bytes */

+   if (transforms & PNG_TRANSFORM_PACKING)

+       png_set_packing(png_ptr);

+#endif

+

+#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED

+   /* Swap location of alpha bytes from ARGB to RGBA */

+   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)

+      png_set_swap_alpha(png_ptr);

+#endif

+

+#ifdef PNG_WRITE_FILLER_SUPPORTED

+   /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */

+   if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER)

+      png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);

+

+   else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE)

+      png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);

+#endif

+

+#ifdef PNG_WRITE_BGR_SUPPORTED

+   /* Flip BGR pixels to RGB */

+   if (transforms & PNG_TRANSFORM_BGR)

+      png_set_bgr(png_ptr);

+#endif

+

+#ifdef PNG_WRITE_SWAP_SUPPORTED

+   /* Swap bytes of 16-bit files to most significant byte first */

+   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)

+      png_set_swap(png_ptr);

+#endif

+

+#ifdef PNG_WRITE_PACKSWAP_SUPPORTED

+   /* Swap bits of 1, 2, 4 bit packed pixel formats */

+   if (transforms & PNG_TRANSFORM_PACKSWAP)

+      png_set_packswap(png_ptr);

+#endif

+

+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED

+   /* Invert the alpha channel from opacity to transparency */

+   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)

+      png_set_invert_alpha(png_ptr);

+#endif

+

+   /* ----------------------- end of transformations ------------------- */

+

+   /* Write the bits */

+   if (info_ptr->valid & PNG_INFO_IDAT)

+       png_write_image(png_ptr, info_ptr->row_pointers);

+

+   /* It is REQUIRED to call this to finish writing the rest of the file */

+   png_write_end(png_ptr, info_ptr);

+

+   PNG_UNUSED(transforms)   /* Quiet compiler warnings */

+   PNG_UNUSED(params)

+}

+#endif

+

+

+#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED

+#ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */

+/* Initialize the write structure - general purpose utility. */

+static int

+png_image_write_init(png_imagep image)

+{

+   png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image,

+          png_safe_error, png_safe_warning);

+

+   if (png_ptr != NULL)

+   {

+      png_infop info_ptr = png_create_info_struct(png_ptr);

+

+      if (info_ptr != NULL)

+      {

+         png_controlp control = png_voidcast(png_controlp,

+            png_malloc_warn(png_ptr, (sizeof *control)));

+

+         if (control != NULL)

+         {

+            memset(control, 0, (sizeof *control));

+

+            control->png_ptr = png_ptr;

+            control->info_ptr = info_ptr;

+            control->for_write = 1;

+

+            image->opaque = control;

+            return 1;

+         }

+

+         /* Error clean up */

+         png_destroy_info_struct(png_ptr, &info_ptr);

+      }

+

+      png_destroy_write_struct(&png_ptr, NULL);

+   }

+

+   return png_image_error(image, "png_image_write_: out of memory");

+}

+

+/* Arguments to png_image_write_main: */

+typedef struct

+{

+   /* Arguments: */

+   png_imagep      image;

+   png_const_voidp buffer;

+   png_int_32      row_stride;

+   png_const_voidp colormap;

+   int             convert_to_8bit;

+   /* Local variables: */

+   png_const_voidp first_row;

+   ptrdiff_t       row_bytes;

+   png_voidp       local_row;

+} png_image_write_control;

+

+/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to

+ * do any necessary byte swapping.  The component order is defined by the

+ * png_image format value.

+ */

+static int

+png_write_image_16bit(png_voidp argument)

+{

+   png_image_write_control *display = png_voidcast(png_image_write_control*,

+      argument);

+   png_imagep image = display->image;

+   png_structrp png_ptr = image->opaque->png_ptr;

+

+   png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,

+      display->first_row);

+   png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);

+   png_uint_16p row_end;

+   const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1;

+   int aindex = 0;

+   png_uint_32 y = image->height;

+

+   if (image->format & PNG_FORMAT_FLAG_ALPHA)

+   {

+      if (image->format & PNG_FORMAT_FLAG_AFIRST)

+      {

+         aindex = -1;

+         ++input_row; /* To point to the first component */

+         ++output_row;

+      }

+

+      else

+         aindex = channels;

+   }

+

+   else

+      png_error(png_ptr, "png_write_image: internal call error");

+

+   /* Work out the output row end and count over this, note that the increment

+    * above to 'row' means that row_end can actually be beyond the end of the

+    * row; this is correct.

+    */

+   row_end = output_row + image->width * (channels+1);

+

+   while (y-- > 0)

+   {

+      png_const_uint_16p in_ptr = input_row;

+      png_uint_16p out_ptr = output_row;

+

+      while (out_ptr < row_end)

+      {

+         const png_uint_16 alpha = in_ptr[aindex];

+         png_uint_32 reciprocal = 0;

+         int c;

+

+         out_ptr[aindex] = alpha;

+

+         /* Calculate a reciprocal.  The correct calculation is simply

+          * component/alpha*65535 << 15. (I.e. 15 bits of precision); this

+          * allows correct rounding by adding .5 before the shift.  'reciprocal'

+          * is only initialized when required.

+          */

+         if (alpha > 0 && alpha < 65535)

+            reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;

+

+         c = channels;

+         do /* always at least one channel */

+         {

+            png_uint_16 component = *in_ptr++;

+

+            /* The following gives 65535 for an alpha of 0, which is fine,

+             * otherwise if 0/0 is represented as some other value there is more

+             * likely to be a discontinuity which will probably damage

+             * compression when moving from a fully transparent area to a

+             * nearly transparent one.  (The assumption here is that opaque

+             * areas tend not to be 0 intensity.)

+             */

+            if (component >= alpha)

+               component = 65535;

+

+            /* component<alpha, so component/alpha is less than one and

+             * component*reciprocal is less than 2^31.

+             */

+            else if (component > 0 && alpha < 65535)

+            {

+               png_uint_32 calc = component * reciprocal;

+               calc += 16384; /* round to nearest */

+               component = (png_uint_16)(calc >> 15);

+            }

+

+            *out_ptr++ = component;

+         }

+         while (--c > 0);

+

+         /* Skip to next component (skip the intervening alpha channel) */

+         ++in_ptr;

+         ++out_ptr;

+      }

+

+      png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));

+      input_row += display->row_bytes/(sizeof (png_uint_16));

+   }

+

+   return 1;

+}

+

+/* Given 16-bit input (1 to 4 channels) write 8-bit output.  If an alpha channel

+ * is present it must be removed from the components, the components are then

+ * written in sRGB encoding.  No components are added or removed.

+ *

+ * Calculate an alpha reciprocal to reverse pre-multiplication.  As above the

+ * calculation can be done to 15 bits of accuracy; however, the output needs to

+ * be scaled in the range 0..255*65535, so include that scaling here.

+ */

+#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha)

+

+static png_byte

+png_unpremultiply(png_uint_32 component, png_uint_32 alpha,

+   png_uint_32 reciprocal/*from the above macro*/)

+{

+   /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0

+    * is represented as some other value there is more likely to be a

+    * discontinuity which will probably damage compression when moving from a

+    * fully transparent area to a nearly transparent one.  (The assumption here

+    * is that opaque areas tend not to be 0 intensity.)

+    *

+    * There is a rounding problem here; if alpha is less than 128 it will end up

+    * as 0 when scaled to 8 bits.  To avoid introducing spurious colors into the

+    * output change for this too.

+    */

+   if (component >= alpha || alpha < 128)

+      return 255;

+

+   /* component<alpha, so component/alpha is less than one and

+    * component*reciprocal is less than 2^31.

+    */

+   else if (component > 0)

+   {

+      /* The test is that alpha/257 (rounded) is less than 255, the first value

+       * that becomes 255 is 65407.

+       * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore,

+       * be exact!)  [Could also test reciprocal != 0]

+       */

+      if (alpha < 65407)

+      {

+         component *= reciprocal;

+         component += 64; /* round to nearest */

+         component >>= 7;

+      }

+

+      else

+         component *= 255;

+

+      /* Convert the component to sRGB. */

+      return (png_byte)PNG_sRGB_FROM_LINEAR(component);

+   }

+

+   else

+      return 0;

+}

+

+static int

+png_write_image_8bit(png_voidp argument)

+{

+   png_image_write_control *display = png_voidcast(png_image_write_control*,

+      argument);

+   png_imagep image = display->image;

+   png_structrp png_ptr = image->opaque->png_ptr;

+

+   png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,

+      display->first_row);

+   png_bytep output_row = png_voidcast(png_bytep, display->local_row);

+   png_uint_32 y = image->height;

+   const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1;

+

+   if (image->format & PNG_FORMAT_FLAG_ALPHA)

+   {

+      png_bytep row_end;

+      int aindex;

+

+      if (image->format & PNG_FORMAT_FLAG_AFIRST)

+      {

+         aindex = -1;

+         ++input_row; /* To point to the first component */

+         ++output_row;

+      }

+

+      else

+         aindex = channels;

+

+      /* Use row_end in place of a loop counter: */

+      row_end = output_row + image->width * (channels+1);

+

+      while (y-- > 0)

+      {

+         png_const_uint_16p in_ptr = input_row;

+         png_bytep out_ptr = output_row;

+

+         while (out_ptr < row_end)

+         {

+            png_uint_16 alpha = in_ptr[aindex];

+            png_byte alphabyte = (png_byte)PNG_DIV257(alpha);

+            png_uint_32 reciprocal = 0;

+            int c;

+

+            /* Scale and write the alpha channel. */

+            out_ptr[aindex] = alphabyte;

+

+            if (alphabyte > 0 && alphabyte < 255)

+               reciprocal = UNP_RECIPROCAL(alpha);

+

+            c = channels;

+            do /* always at least one channel */

+               *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);

+            while (--c > 0);

+

+            /* Skip to next component (skip the intervening alpha channel) */

+            ++in_ptr;

+            ++out_ptr;

+         } /* while out_ptr < row_end */

+

+         png_write_row(png_ptr, png_voidcast(png_const_bytep,

+            display->local_row));

+         input_row += display->row_bytes/(sizeof (png_uint_16));

+      } /* while y */

+   }

+

+   else

+   {

+      /* No alpha channel, so the row_end really is the end of the row and it

+       * is sufficient to loop over the components one by one.

+       */

+      png_bytep row_end = output_row + image->width * channels;

+

+      while (y-- > 0)

+      {

+         png_const_uint_16p in_ptr = input_row;

+         png_bytep out_ptr = output_row;

+

+         while (out_ptr < row_end)

+         {

+            png_uint_32 component = *in_ptr++;

+

+            component *= 255;

+            *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component);

+         }

+

+         png_write_row(png_ptr, output_row);

+         input_row += display->row_bytes/(sizeof (png_uint_16));

+      }

+   }

+

+   return 1;

+}

+

+static void

+png_image_set_PLTE(png_image_write_control *display)

+{

+   const png_imagep image = display->image;

+   const void *cmap = display->colormap;

+   const int entries = image->colormap_entries > 256 ? 256 :

+      (int)image->colormap_entries;

+

+   /* NOTE: the caller must check for cmap != NULL and entries != 0 */

+   const png_uint_32 format = image->format;

+   const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);

+

+#  ifdef PNG_FORMAT_BGR_SUPPORTED

+      const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&

+         (format & PNG_FORMAT_FLAG_ALPHA) != 0;

+#  else

+#     define afirst 0

+#  endif

+

+#  ifdef PNG_FORMAT_BGR_SUPPORTED

+      const int bgr = (format & PNG_FORMAT_FLAG_BGR) ? 2 : 0;

+#  else

+#     define bgr 0

+#  endif

+

+   int i, num_trans;

+   png_color palette[256];

+   png_byte tRNS[256];

+

+   memset(tRNS, 255, (sizeof tRNS));

+   memset(palette, 0, (sizeof palette));

+

+   for (i=num_trans=0; i<entries; ++i)

+   {

+      /* This gets automatically converted to sRGB with reversal of the

+       * pre-multiplication if the color-map has an alpha channel.

+       */

+      if (format & PNG_FORMAT_FLAG_LINEAR)

+      {

+         png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap);

+

+         entry += i * channels;

+

+         if (channels & 1) /* no alpha */

+         {

+            if (channels >= 3) /* RGB */

+            {

+               palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 *

+                  entry[(2 ^ bgr)]);

+               palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 *

+                  entry[1]);

+               palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 *

+                  entry[bgr]);

+            }

+

+            else /* Gray */

+               palette[i].blue = palette[i].red = palette[i].green =

+                  (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry);

+         }

+

+         else /* alpha */

+         {

+            png_uint_16 alpha = entry[afirst ? 0 : channels-1];

+            png_byte alphabyte = (png_byte)PNG_DIV257(alpha);

+            png_uint_32 reciprocal = 0;

+

+            /* Calculate a reciprocal, as in the png_write_image_8bit code above

+             * this is designed to produce a value scaled to 255*65535 when

+             * divided by 128 (i.e. asr 7).

+             */

+            if (alphabyte > 0 && alphabyte < 255)

+               reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha;

+

+            tRNS[i] = alphabyte;

+            if (alphabyte < 255)

+               num_trans = i+1;

+

+            if (channels >= 3) /* RGB */

+            {

+               palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)],

+                  alpha, reciprocal);

+               palette[i].green = png_unpremultiply(entry[afirst + 1], alpha,

+                  reciprocal);

+               palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha,

+                  reciprocal);

+            }

+

+            else /* gray */

+               palette[i].blue = palette[i].red = palette[i].green =

+                  png_unpremultiply(entry[afirst], alpha, reciprocal);

+         }

+      }

+

+      else /* Color-map has sRGB values */

+      {

+         png_const_bytep entry = png_voidcast(png_const_bytep, cmap);

+

+         entry += i * channels;

+

+         switch (channels)

+         {

+            case 4:

+               tRNS[i] = entry[afirst ? 0 : 3];

+               if (tRNS[i] < 255)

+                  num_trans = i+1;

+               /* FALL THROUGH */

+            case 3:

+               palette[i].blue = entry[afirst + (2 ^ bgr)];

+               palette[i].green = entry[afirst + 1];

+               palette[i].red = entry[afirst + bgr];

+               break;

+

+            case 2:

+               tRNS[i] = entry[1 ^ afirst];

+               if (tRNS[i] < 255)

+                  num_trans = i+1;

+               /* FALL THROUGH */

+            case 1:

+               palette[i].blue = palette[i].red = palette[i].green =

+                  entry[afirst];

+               break;

+

+            default:

+               break;

+         }

+      }

+   }

+

+#  ifdef afirst

+#     undef afirst

+#  endif

+#  ifdef bgr

+#     undef bgr

+#  endif

+

+   png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,

+      entries);

+

+   if (num_trans > 0)

+      png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,

+         num_trans, NULL);

+

+   image->colormap_entries = entries;

+}

+

+static int

+png_image_write_main(png_voidp argument)

+{

+   png_image_write_control *display = png_voidcast(png_image_write_control*,

+      argument);

+   png_imagep image = display->image;

+   png_structrp png_ptr = image->opaque->png_ptr;

+   png_inforp info_ptr = image->opaque->info_ptr;

+   png_uint_32 format = image->format;

+

+   int colormap = (format & PNG_FORMAT_FLAG_COLORMAP) != 0;

+   int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) != 0; /* input */

+   int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0;

+   int write_16bit = linear && !colormap && !display->convert_to_8bit;

+

+#  ifdef PNG_BENIGN_ERRORS_SUPPORTED

+      /* Make sure we error out on any bad situation */

+      png_set_benign_errors(png_ptr, 0/*error*/);

+#  endif

+

+   /* Default the 'row_stride' parameter if required. */

+   if (display->row_stride == 0)

+      display->row_stride = PNG_IMAGE_ROW_STRIDE(*image);

+

+   /* Set the required transforms then write the rows in the correct order. */

+   if (format & PNG_FORMAT_FLAG_COLORMAP)

+   {

+      if (display->colormap != NULL && image->colormap_entries > 0)

+      {

+         png_uint_32 entries = image->colormap_entries;

+

+         png_set_IHDR(png_ptr, info_ptr, image->width, image->height,

+            entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)),

+            PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,

+            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

+

+         png_image_set_PLTE(display);

+      }

+

+      else

+         png_error(image->opaque->png_ptr,

+            "no color-map for color-mapped image");

+   }

+

+   else

+      png_set_IHDR(png_ptr, info_ptr, image->width, image->height,

+         write_16bit ? 16 : 8,

+         ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) +

+         ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0),

+         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

+

+   /* Counter-intuitively the data transformations must be called *after*

+    * png_write_info, not before as in the read code, but the 'set' functions

+    * must still be called before.  Just set the color space information, never

+    * write an interlaced image.

+    */

+

+   if (write_16bit)

+   {

+      /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */

+      png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR);

+

+      if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB))

+         png_set_cHRM_fixed(png_ptr, info_ptr,

+            /* color      x       y */

+            /* white */ 31270, 32900,

+            /* red   */ 64000, 33000,

+            /* green */ 30000, 60000,

+            /* blue  */ 15000,  6000

+         );

+   }

+

+   else if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB))

+      png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);

+

+   /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit

+    * space must still be gamma encoded.

+    */

+   else

+      png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);

+

+   /* Write the file header. */

+   png_write_info(png_ptr, info_ptr);

+

+   /* Now set up the data transformations (*after* the header is written),

+    * remove the handled transformations from the 'format' flags for checking.

+    *

+    * First check for a little endian system if writing 16 bit files.

+    */

+   if (write_16bit)

+   {

+      PNG_CONST png_uint_16 le = 0x0001;

+

+      if (*(png_const_bytep)&le)

+         png_set_swap(png_ptr);

+   }

+

+#  ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED

+      if (format & PNG_FORMAT_FLAG_BGR)

+      {

+         if (!colormap && (format & PNG_FORMAT_FLAG_COLOR) != 0)

+            png_set_bgr(png_ptr);

+         format &= ~PNG_FORMAT_FLAG_BGR;

+      }

+#  endif

+

+#  ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED

+      if (format & PNG_FORMAT_FLAG_AFIRST)

+      {

+         if (!colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0)

+            png_set_swap_alpha(png_ptr);

+         format &= ~PNG_FORMAT_FLAG_AFIRST;

+      }

+#  endif

+

+   /* If there are 16 or fewer color-map entries we wrote a lower bit depth

+    * above, but the application data is still byte packed.

+    */

+   if (colormap && image->colormap_entries <= 16)

+      png_set_packing(png_ptr);

+

+   /* That should have handled all (both) the transforms. */

+   if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |

+         PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0)

+      png_error(png_ptr, "png_write_image: unsupported transformation");

+

+   {

+      png_const_bytep row = png_voidcast(png_const_bytep, display->buffer);

+      ptrdiff_t row_bytes = display->row_stride;

+

+      if (linear)

+         row_bytes *= (sizeof (png_uint_16));

+

+      if (row_bytes < 0)

+         row += (image->height-1) * (-row_bytes);

+

+      display->first_row = row;

+      display->row_bytes = row_bytes;

+   }

+

+   /* Apply 'fast' options if the flag is set. */

+   if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0)

+   {

+      png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS);

+      /* NOTE: determined by experiment using pngstest, this reflects some

+       * balance between the time to write the image once and the time to read

+       * it about 50 times.  The speed-up in pngstest was about 10-20% of the

+       * total (user) time on a heavily loaded system.

+       */

+      png_set_compression_level(png_ptr, 3);

+   }

+

+   /* Check for the cases that currently require a pre-transform on the row

+    * before it is written.  This only applies when the input is 16-bit and

+    * either there is an alpha channel or it is converted to 8-bit.

+    */

+   if ((linear && alpha) || (!colormap && display->convert_to_8bit))

+   {

+      png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,

+         png_get_rowbytes(png_ptr, info_ptr)));

+      int result;

+

+      display->local_row = row;

+      if (write_16bit)

+         result = png_safe_execute(image, png_write_image_16bit, display);

+      else

+         result = png_safe_execute(image, png_write_image_8bit, display);

+      display->local_row = NULL;

+

+      png_free(png_ptr, row);

+

+      /* Skip the 'write_end' on error: */

+      if (!result)

+         return 0;

+   }

+

+   /* Otherwise this is the case where the input is in a format currently

+    * supported by the rest of the libpng write code; call it directly.

+    */

+   else

+   {

+      png_const_bytep row = png_voidcast(png_const_bytep, display->first_row);

+      ptrdiff_t row_bytes = display->row_bytes;

+      png_uint_32 y = image->height;

+

+      while (y-- > 0)

+      {

+         png_write_row(png_ptr, row);

+         row += row_bytes;

+      }

+   }

+

+   png_write_end(png_ptr, info_ptr);

+   return 1;

+}

+

+int PNGAPI

+png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,

+   const void *buffer, png_int_32 row_stride, const void *colormap)

+{

+   /* Write the image to the given (FILE*). */

+   if (image != NULL && image->version == PNG_IMAGE_VERSION)

+   {

+      if (file != NULL)

+      {

+         if (png_image_write_init(image))

+         {

+            png_image_write_control display;

+            int result;

+

+            /* This is slightly evil, but png_init_io doesn't do anything other

+             * than this and we haven't changed the standard IO functions so

+             * this saves a 'safe' function.

+             */

+            image->opaque->png_ptr->io_ptr = file;

+

+            memset(&display, 0, (sizeof display));

+            display.image = image;

+            display.buffer = buffer;

+            display.row_stride = row_stride;

+            display.colormap = colormap;

+            display.convert_to_8bit = convert_to_8bit;

+

+            result = png_safe_execute(image, png_image_write_main, &display);

+            png_image_free(image);

+            return result;

+         }

+

+         else

+            return 0;

+      }

+

+      else

+         return png_image_error(image,

+            "png_image_write_to_stdio: invalid argument");

+   }

+

+   else if (image != NULL)

+      return png_image_error(image,

+         "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION");

+

+   else

+      return 0;

+}

+

+int PNGAPI

+png_image_write_to_file(png_imagep image, const char *file_name,

+   int convert_to_8bit, const void *buffer, png_int_32 row_stride,

+   const void *colormap)

+{

+   /* Write the image to the named file. */

+   if (image != NULL && image->version == PNG_IMAGE_VERSION)

+   {

+      if (file_name != NULL)

+      {

+         FILE *fp = fopen(file_name, "wb");

+

+         if (fp != NULL)

+         {

+            if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,

+               row_stride, colormap))

+            {

+               int error; /* from fflush/fclose */

+

+               /* Make sure the file is flushed correctly. */

+               if (fflush(fp) == 0 && ferror(fp) == 0)

+               {

+                  if (fclose(fp) == 0)

+                     return 1;

+

+                  error = errno; /* from fclose */

+               }

+

+               else

+               {

+                  error = errno; /* from fflush or ferror */

+                  (void)fclose(fp);

+               }

+

+               (void)remove(file_name);

+               /* The image has already been cleaned up; this is just used to

+                * set the error (because the original write succeeded).

+                */

+               return png_image_error(image, strerror(error));

+            }

+

+            else

+            {

+               /* Clean up: just the opened file. */

+               (void)fclose(fp);

+               (void)remove(file_name);

+               return 0;

+            }

+         }

+

+         else

+            return png_image_error(image, strerror(errno));

+      }

+

+      else

+         return png_image_error(image,

+            "png_image_write_to_file: invalid argument");

+   }

+

+   else if (image != NULL)

+      return png_image_error(image,

+         "png_image_write_to_file: incorrect PNG_IMAGE_VERSION");

+

+   else

+      return 0;

+}

+#endif /* PNG_STDIO_SUPPORTED */

+#endif /* SIMPLIFIED_WRITE */

+#endif /* PNG_WRITE_SUPPORTED */

+#endif//_FPDFAPI_MINI_

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwtran.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwtran.c
new file mode 100644
index 0000000..8f28110
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwtran.c
@@ -0,0 +1,638 @@
+

+/* pngwtran.c - transforms the data in a row for PNG writers

+ *

+ * Last changed in libpng 1.6.0 [February 14, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+#include "pngpriv.h"

+

+#ifdef PNG_WRITE_SUPPORTED

+

+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED

+/* Transform the data according to the user's wishes.  The order of

+ * transformations is significant.

+ */

+void /* PRIVATE */

+png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)

+{

+   png_debug(1, "in png_do_write_transformations");

+

+   if (png_ptr == NULL)

+      return;

+

+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED

+   if (png_ptr->transformations & PNG_USER_TRANSFORM)

+      if (png_ptr->write_user_transform_fn != NULL)

+         (*(png_ptr->write_user_transform_fn)) /* User write transform

+                                                 function */

+             (png_ptr,  /* png_ptr */

+             row_info,  /* row_info: */

+                /*  png_uint_32 width;       width of row */

+                /*  png_size_t rowbytes;     number of bytes in row */

+                /*  png_byte color_type;     color type of pixels */

+                /*  png_byte bit_depth;      bit depth of samples */

+                /*  png_byte channels;       number of channels (1-4) */

+                /*  png_byte pixel_depth;    bits per pixel (depth*channels) */

+             png_ptr->row_buf + 1);      /* start of pixel data for row */

+#endif

+

+#ifdef PNG_WRITE_FILLER_SUPPORTED

+   if (png_ptr->transformations & PNG_FILLER)

+      png_do_strip_channel(row_info, png_ptr->row_buf + 1,

+         !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));

+#endif

+

+#ifdef PNG_WRITE_PACKSWAP_SUPPORTED

+   if (png_ptr->transformations & PNG_PACKSWAP)

+      png_do_packswap(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_WRITE_PACK_SUPPORTED

+   if (png_ptr->transformations & PNG_PACK)

+      png_do_pack(row_info, png_ptr->row_buf + 1,

+          (png_uint_32)png_ptr->bit_depth);

+#endif

+

+#ifdef PNG_WRITE_SWAP_SUPPORTED

+   if (png_ptr->transformations & PNG_SWAP_BYTES)

+      png_do_swap(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_WRITE_SHIFT_SUPPORTED

+   if (png_ptr->transformations & PNG_SHIFT)

+      png_do_shift(row_info, png_ptr->row_buf + 1,

+          &(png_ptr->shift));

+#endif

+

+#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED

+   if (png_ptr->transformations & PNG_SWAP_ALPHA)

+      png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED

+   if (png_ptr->transformations & PNG_INVERT_ALPHA)

+      png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_WRITE_BGR_SUPPORTED

+   if (png_ptr->transformations & PNG_BGR)

+      png_do_bgr(row_info, png_ptr->row_buf + 1);

+#endif

+

+#ifdef PNG_WRITE_INVERT_SUPPORTED

+   if (png_ptr->transformations & PNG_INVERT_MONO)

+      png_do_invert(row_info, png_ptr->row_buf + 1);

+#endif

+}

+

+#ifdef PNG_WRITE_PACK_SUPPORTED

+/* Pack pixels into bytes.  Pass the true bit depth in bit_depth.  The

+ * row_info bit depth should be 8 (one pixel per byte).  The channels

+ * should be 1 (this only happens on grayscale and paletted images).

+ */

+void /* PRIVATE */

+png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)

+{

+   png_debug(1, "in png_do_pack");

+

+   if (row_info->bit_depth == 8 &&

+      row_info->channels == 1)

+   {

+      switch ((int)bit_depth)

+      {

+         case 1:

+         {

+            png_bytep sp, dp;

+            int mask, v;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            sp = row;

+            dp = row;

+            mask = 0x80;

+            v = 0;

+

+            for (i = 0; i < row_width; i++)

+            {

+               if (*sp != 0)

+                  v |= mask;

+

+               sp++;

+

+               if (mask > 1)

+                  mask >>= 1;

+

+               else

+               {

+                  mask = 0x80;

+                  *dp = (png_byte)v;

+                  dp++;

+                  v = 0;

+               }

+            }

+

+            if (mask != 0x80)

+               *dp = (png_byte)v;

+

+            break;

+         }

+

+         case 2:

+         {

+            png_bytep sp, dp;

+            int shift, v;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            sp = row;

+            dp = row;

+            shift = 6;

+            v = 0;

+

+            for (i = 0; i < row_width; i++)

+            {

+               png_byte value;

+

+               value = (png_byte)(*sp & 0x03);

+               v |= (value << shift);

+

+               if (shift == 0)

+               {

+                  shift = 6;

+                  *dp = (png_byte)v;

+                  dp++;

+                  v = 0;

+               }

+

+               else

+                  shift -= 2;

+

+               sp++;

+            }

+

+            if (shift != 6)

+               *dp = (png_byte)v;

+

+            break;

+         }

+

+         case 4:

+         {

+            png_bytep sp, dp;

+            int shift, v;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            sp = row;

+            dp = row;

+            shift = 4;

+            v = 0;

+

+            for (i = 0; i < row_width; i++)

+            {

+               png_byte value;

+

+               value = (png_byte)(*sp & 0x0f);

+               v |= (value << shift);

+

+               if (shift == 0)

+               {

+                  shift = 4;

+                  *dp = (png_byte)v;

+                  dp++;

+                  v = 0;

+               }

+

+               else

+                  shift -= 4;

+

+               sp++;

+            }

+

+            if (shift != 4)

+               *dp = (png_byte)v;

+

+            break;

+         }

+

+         default:

+            break;

+      }

+

+      row_info->bit_depth = (png_byte)bit_depth;

+      row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);

+      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,

+          row_info->width);

+   }

+}

+#endif

+

+#ifdef PNG_WRITE_SHIFT_SUPPORTED

+/* Shift pixel values to take advantage of whole range.  Pass the

+ * true number of bits in bit_depth.  The row should be packed

+ * according to row_info->bit_depth.  Thus, if you had a row of

+ * bit depth 4, but the pixels only had values from 0 to 7, you

+ * would pass 3 as bit_depth, and this routine would translate the

+ * data to 0 to 15.

+ */

+void /* PRIVATE */

+png_do_shift(png_row_infop row_info, png_bytep row,

+    png_const_color_8p bit_depth)

+{

+   png_debug(1, "in png_do_shift");

+

+   if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)

+   {

+      int shift_start[4], shift_dec[4];

+      int channels = 0;

+

+      if (row_info->color_type & PNG_COLOR_MASK_COLOR)

+      {

+         shift_start[channels] = row_info->bit_depth - bit_depth->red;

+         shift_dec[channels] = bit_depth->red;

+         channels++;

+

+         shift_start[channels] = row_info->bit_depth - bit_depth->green;

+         shift_dec[channels] = bit_depth->green;

+         channels++;

+

+         shift_start[channels] = row_info->bit_depth - bit_depth->blue;

+         shift_dec[channels] = bit_depth->blue;

+         channels++;

+      }

+

+      else

+      {

+         shift_start[channels] = row_info->bit_depth - bit_depth->gray;

+         shift_dec[channels] = bit_depth->gray;

+         channels++;

+      }

+

+      if (row_info->color_type & PNG_COLOR_MASK_ALPHA)

+      {

+         shift_start[channels] = row_info->bit_depth - bit_depth->alpha;

+         shift_dec[channels] = bit_depth->alpha;

+         channels++;

+      }

+

+      /* With low row depths, could only be grayscale, so one channel */

+      if (row_info->bit_depth < 8)

+      {

+         png_bytep bp = row;

+         png_size_t i;

+         unsigned int mask;

+         png_size_t row_bytes = row_info->rowbytes;

+

+         if (bit_depth->gray == 1 && row_info->bit_depth == 2)

+            mask = 0x55;

+

+         else if (row_info->bit_depth == 4 && bit_depth->gray == 3)

+            mask = 0x11;

+

+         else

+            mask = 0xff;

+

+         for (i = 0; i < row_bytes; i++, bp++)

+         {

+            int j;

+            unsigned int v, out;

+

+            v = *bp;

+            out = 0;

+

+            for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])

+            {

+               if (j > 0)

+                  out |= v << j;

+

+               else

+                  out |= (v >> (-j)) & mask;

+            }

+

+            *bp = (png_byte)(out & 0xff);

+         }

+      }

+

+      else if (row_info->bit_depth == 8)

+      {

+         png_bytep bp = row;

+         png_uint_32 i;

+         png_uint_32 istop = channels * row_info->width;

+

+         for (i = 0; i < istop; i++, bp++)

+         {

+

+            const unsigned int c = i%channels;

+            int j;

+            unsigned int v, out;

+

+            v = *bp;

+            out = 0;

+

+            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])

+            {

+               if (j > 0)

+                  out |= v << j;

+

+               else

+                  out |= v >> (-j);

+            }

+

+            *bp = (png_byte)(out & 0xff);

+         }

+      }

+

+      else

+      {

+         png_bytep bp;

+         png_uint_32 i;

+         png_uint_32 istop = channels * row_info->width;

+

+         for (bp = row, i = 0; i < istop; i++)

+         {

+            const unsigned int c = i%channels;

+            int j;

+            unsigned int value, v;

+

+            v = png_get_uint_16(bp);

+            value = 0;

+

+            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])

+            {

+               if (j > 0)

+                  value |= v << j;

+

+               else

+                  value |= v >> (-j);

+            }

+            *bp++ = (png_byte)((value >> 8) & 0xff);

+            *bp++ = (png_byte)(value & 0xff);

+         }

+      }

+   }

+}

+#endif

+

+#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED

+void /* PRIVATE */

+png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_write_swap_alpha");

+

+   {

+      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+      {

+         if (row_info->bit_depth == 8)

+         {

+            /* This converts from ARGB to RGBA */

+            png_bytep sp, dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            for (i = 0, sp = dp = row; i < row_width; i++)

+            {

+               png_byte save = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = save;

+            }

+         }

+

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+         else

+         {

+            /* This converts from AARRGGBB to RRGGBBAA */

+            png_bytep sp, dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            for (i = 0, sp = dp = row; i < row_width; i++)

+            {

+               png_byte save[2];

+               save[0] = *(sp++);

+               save[1] = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = save[0];

+               *(dp++) = save[1];

+            }

+         }

+#endif /* PNG_WRITE_16BIT_SUPPORTED */

+      }

+

+      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

+      {

+         if (row_info->bit_depth == 8)

+         {

+            /* This converts from AG to GA */

+            png_bytep sp, dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            for (i = 0, sp = dp = row; i < row_width; i++)

+            {

+               png_byte save = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = save;

+            }

+         }

+

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+         else

+         {

+            /* This converts from AAGG to GGAA */

+            png_bytep sp, dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            for (i = 0, sp = dp = row; i < row_width; i++)

+            {

+               png_byte save[2];

+               save[0] = *(sp++);

+               save[1] = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = save[0];

+               *(dp++) = save[1];

+            }

+         }

+#endif /* PNG_WRITE_16BIT_SUPPORTED */

+      }

+   }

+}

+#endif

+

+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED

+void /* PRIVATE */

+png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_write_invert_alpha");

+

+   {

+      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+      {

+         if (row_info->bit_depth == 8)

+         {

+            /* This inverts the alpha channel in RGBA */

+            png_bytep sp, dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            for (i = 0, sp = dp = row; i < row_width; i++)

+            {

+               /* Does nothing

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               */

+               sp+=3; dp = sp;

+               *(dp++) = (png_byte)(255 - *(sp++));

+            }

+         }

+

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+         else

+         {

+            /* This inverts the alpha channel in RRGGBBAA */

+            png_bytep sp, dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            for (i = 0, sp = dp = row; i < row_width; i++)

+            {

+               /* Does nothing

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               */

+               sp+=6; dp = sp;

+               *(dp++) = (png_byte)(255 - *(sp++));

+               *(dp++) = (png_byte)(255 - *(sp++));

+            }

+         }

+#endif /* PNG_WRITE_16BIT_SUPPORTED */

+      }

+

+      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

+      {

+         if (row_info->bit_depth == 8)

+         {

+            /* This inverts the alpha channel in GA */

+            png_bytep sp, dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            for (i = 0, sp = dp = row; i < row_width; i++)

+            {

+               *(dp++) = *(sp++);

+               *(dp++) = (png_byte)(255 - *(sp++));

+            }

+         }

+

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+         else

+         {

+            /* This inverts the alpha channel in GGAA */

+            png_bytep sp, dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            for (i = 0, sp = dp = row; i < row_width; i++)

+            {

+               /* Does nothing

+               *(dp++) = *(sp++);

+               *(dp++) = *(sp++);

+               */

+               sp+=2; dp = sp;

+               *(dp++) = (png_byte)(255 - *(sp++));

+               *(dp++) = (png_byte)(255 - *(sp++));

+            }

+         }

+#endif /* PNG_WRITE_16BIT_SUPPORTED */

+      }

+   }

+}

+#endif

+#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */

+

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+/* Undoes intrapixel differencing  */

+void /* PRIVATE */

+png_do_write_intrapixel(png_row_infop row_info, png_bytep row)

+{

+   png_debug(1, "in png_do_write_intrapixel");

+

+   if ((row_info->color_type & PNG_COLOR_MASK_COLOR))

+   {

+      int bytes_per_pixel;

+      png_uint_32 row_width = row_info->width;

+      if (row_info->bit_depth == 8)

+      {

+         png_bytep rp;

+         png_uint_32 i;

+

+         if (row_info->color_type == PNG_COLOR_TYPE_RGB)

+            bytes_per_pixel = 3;

+

+         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+            bytes_per_pixel = 4;

+

+         else

+            return;

+

+         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)

+         {

+            *(rp)     = (png_byte)((*rp       - *(rp + 1)) & 0xff);

+            *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff);

+         }

+      }

+

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+      else if (row_info->bit_depth == 16)

+      {

+         png_bytep rp;

+         png_uint_32 i;

+

+         if (row_info->color_type == PNG_COLOR_TYPE_RGB)

+            bytes_per_pixel = 6;

+

+         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)

+            bytes_per_pixel = 8;

+

+         else

+            return;

+

+         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)

+         {

+            png_uint_32 s0   = (*(rp    ) << 8) | *(rp + 1);

+            png_uint_32 s1   = (*(rp + 2) << 8) | *(rp + 3);

+            png_uint_32 s2   = (*(rp + 4) << 8) | *(rp + 5);

+            png_uint_32 red  = (png_uint_32)((s0 - s1) & 0xffffL);

+            png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);

+            *(rp    ) = (png_byte)((red >> 8) & 0xff);

+            *(rp + 1) = (png_byte)(red & 0xff);

+            *(rp + 4) = (png_byte)((blue >> 8) & 0xff);

+            *(rp + 5) = (png_byte)(blue & 0xff);

+         }

+      }

+#endif /* PNG_WRITE_16BIT_SUPPORTED */

+   }

+}

+#endif /* PNG_MNG_FEATURES_SUPPORTED */

+#endif /* PNG_WRITE_SUPPORTED */

+#endif//_FPDFAPI_MINI_

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwutil.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwutil.c
new file mode 100644
index 0000000..40955b9
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwutil.c
@@ -0,0 +1,3024 @@
+

+/* pngwutil.c - utilities to write a PNG file

+ *

+ * Last changed in libpng 1.6.2 [April 25, 2013]

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_)

+#include "pngpriv.h"

+

+#ifdef PNG_WRITE_SUPPORTED

+

+#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED

+/* Place a 32-bit number into a buffer in PNG byte order.  We work

+ * with unsigned numbers for convenience, although one supported

+ * ancillary chunk uses signed (two's complement) numbers.

+ */

+void PNGAPI

+png_save_uint_32(png_bytep buf, png_uint_32 i)

+{

+   buf[0] = (png_byte)((i >> 24) & 0xff);

+   buf[1] = (png_byte)((i >> 16) & 0xff);

+   buf[2] = (png_byte)((i >> 8) & 0xff);

+   buf[3] = (png_byte)(i & 0xff);

+}

+

+/* Place a 16-bit number into a buffer in PNG byte order.

+ * The parameter is declared unsigned int, not png_uint_16,

+ * just to avoid potential problems on pre-ANSI C compilers.

+ */

+void PNGAPI

+png_save_uint_16(png_bytep buf, unsigned int i)

+{

+   buf[0] = (png_byte)((i >> 8) & 0xff);

+   buf[1] = (png_byte)(i & 0xff);

+}

+#endif

+

+/* Simple function to write the signature.  If we have already written

+ * the magic bytes of the signature, or more likely, the PNG stream is

+ * being embedded into another stream and doesn't need its own signature,

+ * we should call png_set_sig_bytes() to tell libpng how many of the

+ * bytes have already been written.

+ */

+void PNGAPI

+png_write_sig(png_structrp png_ptr)

+{

+   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};

+

+#ifdef PNG_IO_STATE_SUPPORTED

+   /* Inform the I/O callback that the signature is being written */

+   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE;

+#endif

+

+   /* Write the rest of the 8 byte signature */

+   png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],

+      (png_size_t)(8 - png_ptr->sig_bytes));

+

+   if (png_ptr->sig_bytes < 3)

+      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;

+}

+

+/* Write the start of a PNG chunk.  The type is the chunk type.

+ * The total_length is the sum of the lengths of all the data you will be

+ * passing in png_write_chunk_data().

+ */

+static void

+png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name,

+    png_uint_32 length)

+{

+   png_byte buf[8];

+

+#if defined(PNG_DEBUG) && (PNG_DEBUG > 0)

+   PNG_CSTRING_FROM_CHUNK(buf, chunk_name);

+   png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length);

+#endif

+

+   if (png_ptr == NULL)

+      return;

+

+#ifdef PNG_IO_STATE_SUPPORTED

+   /* Inform the I/O callback that the chunk header is being written.

+    * PNG_IO_CHUNK_HDR requires a single I/O call.

+    */

+   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR;

+#endif

+

+   /* Write the length and the chunk name */

+   png_save_uint_32(buf, length);

+   png_save_uint_32(buf + 4, chunk_name);

+   png_write_data(png_ptr, buf, 8);

+

+   /* Put the chunk name into png_ptr->chunk_name */

+   png_ptr->chunk_name = chunk_name;

+

+   /* Reset the crc and run it over the chunk name */

+   png_reset_crc(png_ptr);

+

+   png_calculate_crc(png_ptr, buf + 4, 4);

+

+#ifdef PNG_IO_STATE_SUPPORTED

+   /* Inform the I/O callback that chunk data will (possibly) be written.

+    * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.

+    */

+   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA;

+#endif

+}

+

+void PNGAPI

+png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string,

+    png_uint_32 length)

+{

+   png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length);

+}

+

+/* Write the data of a PNG chunk started with png_write_chunk_header().

+ * Note that multiple calls to this function are allowed, and that the

+ * sum of the lengths from these calls *must* add up to the total_length

+ * given to png_write_chunk_header().

+ */

+void PNGAPI

+png_write_chunk_data(png_structrp png_ptr, png_const_bytep data,

+    png_size_t length)

+{

+   /* Write the data, and run the CRC over it */

+   if (png_ptr == NULL)

+      return;

+

+   if (data != NULL && length > 0)

+   {

+      png_write_data(png_ptr, data, length);

+

+      /* Update the CRC after writing the data,

+       * in case that the user I/O routine alters it.

+       */

+      png_calculate_crc(png_ptr, data, length);

+   }

+}

+

+/* Finish a chunk started with png_write_chunk_header(). */

+void PNGAPI

+png_write_chunk_end(png_structrp png_ptr)

+{

+   png_byte buf[4];

+

+   if (png_ptr == NULL) return;

+

+#ifdef PNG_IO_STATE_SUPPORTED

+   /* Inform the I/O callback that the chunk CRC is being written.

+    * PNG_IO_CHUNK_CRC requires a single I/O function call.

+    */

+   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC;

+#endif

+

+   /* Write the crc in a single operation */

+   png_save_uint_32(buf, png_ptr->crc);

+

+   png_write_data(png_ptr, buf, (png_size_t)4);

+}

+

+/* Write a PNG chunk all at once.  The type is an array of ASCII characters

+ * representing the chunk name.  The array must be at least 4 bytes in

+ * length, and does not need to be null terminated.  To be safe, pass the

+ * pre-defined chunk names here, and if you need a new one, define it

+ * where the others are defined.  The length is the length of the data.

+ * All the data must be present.  If that is not possible, use the

+ * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()

+ * functions instead.

+ */

+static void

+png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,

+   png_const_bytep data, png_size_t length)

+{

+   if (png_ptr == NULL)

+      return;

+

+   /* On 64 bit architectures 'length' may not fit in a png_uint_32. */

+   if (length > PNG_UINT_31_MAX)

+      png_error(png_ptr, "length exceeds PNG maxima");

+

+   png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length);

+   png_write_chunk_data(png_ptr, data, length);

+   png_write_chunk_end(png_ptr);

+}

+

+/* This is the API that calls the internal function above. */

+void PNGAPI

+png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,

+   png_const_bytep data, png_size_t length)

+{

+   png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data,

+      length);

+}

+

+/* This is used below to find the size of an image to pass to png_deflate_claim,

+ * so it only needs to be accurate if the size is less than 16384 bytes (the

+ * point at which a lower LZ window size can be used.)

+ */

+static png_alloc_size_t

+png_image_size(png_structrp png_ptr)

+{

+   /* Only return sizes up to the maximum of a png_uint_32, do this by limiting

+    * the width and height used to 15 bits.

+    */

+   png_uint_32 h = png_ptr->height;

+

+   if (png_ptr->rowbytes < 32768 && h < 32768)

+   {

+      if (png_ptr->interlaced)

+      {

+         /* Interlacing makes the image larger because of the replication of

+          * both the filter byte and the padding to a byte boundary.

+          */

+         png_uint_32 w = png_ptr->width;

+         unsigned int pd = png_ptr->pixel_depth;

+         png_alloc_size_t cb_base;

+         int pass;

+

+         for (cb_base=0, pass=0; pass<=6; ++pass)

+         {

+            png_uint_32 pw = PNG_PASS_COLS(w, pass);

+

+            if (pw > 0)

+               cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass);

+         }

+

+         return cb_base;

+      }

+

+      else

+         return (png_ptr->rowbytes+1) * h;

+   }

+

+   else

+      return 0xffffffffU;

+}

+

+#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED

+   /* This is the code to hack the first two bytes of the deflate stream (the

+    * deflate header) to correct the windowBits value to match the actual data

+    * size.  Note that the second argument is the *uncompressed* size but the

+    * first argument is the *compressed* data (and it must be deflate

+    * compressed.)

+    */

+static void

+optimize_cmf(png_bytep data, png_alloc_size_t data_size)

+{

+   /* Optimize the CMF field in the zlib stream.  The resultant zlib stream is

+    * still compliant to the stream specification.

+    */

+   if (data_size <= 16384) /* else windowBits must be 15 */

+   {

+      unsigned int z_cmf = data[0];  /* zlib compression method and flags */

+

+      if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)

+      {

+         unsigned int z_cinfo;

+         unsigned int half_z_window_size;

+

+         z_cinfo = z_cmf >> 4;

+         half_z_window_size = 1U << (z_cinfo + 7);

+

+         if (data_size <= half_z_window_size) /* else no change */

+         {

+            unsigned int tmp;

+

+            do

+            {

+               half_z_window_size >>= 1;

+               --z_cinfo;

+            }

+            while (z_cinfo > 0 && data_size <= half_z_window_size);

+

+            z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);

+

+            data[0] = (png_byte)z_cmf;

+            tmp = data[1] & 0xe0;

+            tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f;

+            data[1] = (png_byte)tmp;

+         }

+      }

+   }

+}

+#else

+#  define optimize_cmf(dp,dl) ((void)0)

+#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */

+

+/* Initialize the compressor for the appropriate type of compression. */

+static int

+png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,

+   png_alloc_size_t data_size)

+{

+   if (png_ptr->zowner != 0)

+   {

+      char msg[64];

+

+      PNG_STRING_FROM_CHUNK(msg, owner);

+      msg[4] = ':';

+      msg[5] = ' ';

+      PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner);

+      /* So the message that results is "<chunk> using zstream"; this is an

+       * internal error, but is very useful for debugging.  i18n requirements

+       * are minimal.

+       */

+      (void)png_safecat(msg, (sizeof msg), 10, " using zstream");

+#     if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC

+         png_warning(png_ptr, msg);

+

+         /* Attempt sane error recovery */

+         if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */

+         {

+            png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT");

+            return Z_STREAM_ERROR;

+         }

+

+         png_ptr->zowner = 0;

+#     else

+         png_error(png_ptr, msg);

+#     endif

+   }

+

+   {

+      int level = png_ptr->zlib_level;

+      int method = png_ptr->zlib_method;

+      int windowBits = png_ptr->zlib_window_bits;

+      int memLevel = png_ptr->zlib_mem_level;

+      int strategy; /* set below */

+      int ret; /* zlib return code */

+

+      if (owner == png_IDAT)

+      {

+         if (png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)

+            strategy = png_ptr->zlib_strategy;

+

+         else if (png_ptr->do_filter != PNG_FILTER_NONE)

+            strategy = PNG_Z_DEFAULT_STRATEGY;

+

+         else

+            strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY;

+      }

+

+      else

+      {

+#        ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED

+            level = png_ptr->zlib_text_level;

+            method = png_ptr->zlib_text_method;

+            windowBits = png_ptr->zlib_text_window_bits;

+            memLevel = png_ptr->zlib_text_mem_level;

+            strategy = png_ptr->zlib_text_strategy;

+#        else

+            /* If customization is not supported the values all come from the

+             * IDAT values except for the strategy, which is fixed to the

+             * default.  (This is the pre-1.6.0 behavior too, although it was

+             * implemented in a very different way.)

+             */

+            strategy = Z_DEFAULT_STRATEGY;

+#        endif

+      }

+

+      /* Adjust 'windowBits' down if larger than 'data_size'; to stop this

+       * happening just pass 32768 as the data_size parameter.  Notice that zlib

+       * requires an extra 262 bytes in the window in addition to the data to be

+       * able to see the whole of the data, so if data_size+262 takes us to the

+       * next windowBits size we need to fix up the value later.  (Because even

+       * though deflate needs the extra window, inflate does not!)

+       */

+      if (data_size <= 16384)

+      {

+         /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to

+          * work round a Microsoft Visual C misbehavior which, contrary to C-90,

+          * widens the result of the following shift to 64-bits if (and,

+          * apparently, only if) it is used in a test.

+          */

+         unsigned int half_window_size = 1U << (windowBits-1);

+

+         while (data_size + 262 <= half_window_size)

+         {

+            half_window_size >>= 1;

+            --windowBits;

+         }

+      }

+

+      /* Check against the previous initialized values, if any. */

+      if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) &&

+         (png_ptr->zlib_set_level != level ||

+         png_ptr->zlib_set_method != method ||

+         png_ptr->zlib_set_window_bits != windowBits ||

+         png_ptr->zlib_set_mem_level != memLevel ||

+         png_ptr->zlib_set_strategy != strategy))

+      {

+         if (deflateEnd(&png_ptr->zstream) != Z_OK)

+            png_warning(png_ptr, "deflateEnd failed (ignored)");

+

+         png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED;

+      }

+

+      /* For safety clear out the input and output pointers (currently zlib

+       * doesn't use them on Init, but it might in the future).

+       */

+      png_ptr->zstream.next_in = NULL;

+      png_ptr->zstream.avail_in = 0;

+      png_ptr->zstream.next_out = NULL;

+      png_ptr->zstream.avail_out = 0;

+

+      /* Now initialize if required, setting the new parameters, otherwise just

+       * to a simple reset to the previous parameters.

+       */

+      if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)

+         ret = deflateReset(&png_ptr->zstream);

+

+      else

+      {

+         ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,

+            memLevel, strategy);

+

+         if (ret == Z_OK)

+            png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;

+      }

+

+      /* The return code is from either deflateReset or deflateInit2; they have

+       * pretty much the same set of error codes.

+       */

+      if (ret == Z_OK)

+         png_ptr->zowner = owner;

+

+      else

+         png_zstream_error(png_ptr, ret);

+

+      return ret;

+   }

+}

+

+/* Clean up (or trim) a linked list of compression buffers. */

+void /* PRIVATE */

+png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)

+{

+   png_compression_bufferp list = *listp;

+

+   if (list != NULL)

+   {

+      *listp = NULL;

+

+      do

+      {

+         png_compression_bufferp next = list->next;

+

+         png_free(png_ptr, list);

+         list = next;

+      }

+      while (list != NULL);

+   }

+}

+

+#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED

+/* This pair of functions encapsulates the operation of (a) compressing a

+ * text string, and (b) issuing it later as a series of chunk data writes.

+ * The compression_state structure is shared context for these functions

+ * set up by the caller to allow access to the relevant local variables.

+ *

+ * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size

+ * temporary buffers.  From 1.6.0 it is retained in png_struct so that it will

+ * be correctly freed in the event of a write error (previous implementations

+ * just leaked memory.)

+ */

+typedef struct

+{

+   png_const_bytep      input;        /* The uncompressed input data */

+   png_alloc_size_t     input_len;    /* Its length */

+   png_uint_32          output_len;   /* Final compressed length */

+   png_byte             output[1024]; /* First block of output */

+} compression_state;

+

+static void

+png_text_compress_init(compression_state *comp, png_const_bytep input,

+   png_alloc_size_t input_len)

+{

+   comp->input = input;

+   comp->input_len = input_len;

+   comp->output_len = 0;

+}

+

+/* Compress the data in the compression state input */

+static int

+png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,

+   compression_state *comp, png_uint_32 prefix_len)

+{

+   int ret;

+

+   /* To find the length of the output it is necessary to first compress the

+    * input, the result is buffered rather than using the two-pass algorithm

+    * that is used on the inflate side; deflate is assumed to be slower and a

+    * PNG writer is assumed to have more memory available than a PNG reader.

+    *

+    * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an

+    * upper limit on the output size, but it is always bigger than the input

+    * size so it is likely to be more efficient to use this linked-list

+    * approach.

+    */

+   ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len);

+

+   if (ret != Z_OK)

+      return ret;

+

+   /* Set up the compression buffers, we need a loop here to avoid overflowing a

+    * uInt.  Use ZLIB_IO_MAX to limit the input.  The output is always limited

+    * by the output buffer size, so there is no need to check that.  Since this

+    * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits

+    * in size.

+    */

+   {

+      png_compression_bufferp *end = &png_ptr->zbuffer_list;

+      png_alloc_size_t input_len = comp->input_len; /* may be zero! */

+      png_uint_32 output_len;

+

+      /* zlib updates these for us: */

+      png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input);

+      png_ptr->zstream.avail_in = 0; /* Set below */

+      png_ptr->zstream.next_out = comp->output;

+      png_ptr->zstream.avail_out = (sizeof comp->output);

+

+      output_len = png_ptr->zstream.avail_out;

+

+      do

+      {

+         uInt avail_in = ZLIB_IO_MAX;

+

+         if (avail_in > input_len)

+            avail_in = (uInt)input_len;

+

+         input_len -= avail_in;

+

+         png_ptr->zstream.avail_in = avail_in;

+

+         if (png_ptr->zstream.avail_out == 0)

+         {

+            png_compression_buffer *next;

+

+            /* Chunk data is limited to 2^31 bytes in length, so the prefix

+             * length must be counted here.

+             */

+            if (output_len + prefix_len > PNG_UINT_31_MAX)

+            {

+               ret = Z_MEM_ERROR;

+               break;

+            }

+

+            /* Need a new (malloc'ed) buffer, but there may be one present

+             * already.

+             */

+            next = *end;

+            if (next == NULL)

+            {

+               next = png_voidcast(png_compression_bufferp, png_malloc_base

+                  (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));

+

+               if (next == NULL)

+               {

+                  ret = Z_MEM_ERROR;

+                  break;

+               }

+

+               /* Link in this buffer (so that it will be freed later) */

+               next->next = NULL;

+               *end = next;

+            }

+

+            png_ptr->zstream.next_out = next->output;

+            png_ptr->zstream.avail_out = png_ptr->zbuffer_size;

+            output_len += png_ptr->zstream.avail_out;

+

+            /* Move 'end' to the next buffer pointer. */

+            end = &next->next;

+         }

+

+         /* Compress the data */

+         ret = deflate(&png_ptr->zstream,

+            input_len > 0 ? Z_NO_FLUSH : Z_FINISH);

+

+         /* Claw back input data that was not consumed (because avail_in is

+          * reset above every time round the loop).

+          */

+         input_len += png_ptr->zstream.avail_in;

+         png_ptr->zstream.avail_in = 0; /* safety */

+      }

+      while (ret == Z_OK);

+

+      /* There may be some space left in the last output buffer, this needs to

+       * be subtracted from output_len.

+       */

+      output_len -= png_ptr->zstream.avail_out;

+      png_ptr->zstream.avail_out = 0; /* safety */

+      comp->output_len = output_len;

+

+      /* Now double check the output length, put in a custom message if it is

+       * too long.  Otherwise ensure the z_stream::msg pointer is set to

+       * something.

+       */

+      if (output_len + prefix_len >= PNG_UINT_31_MAX)

+      {

+         png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long");

+         ret = Z_MEM_ERROR;

+      }

+

+      else

+         png_zstream_error(png_ptr, ret);

+

+      /* Reset zlib for another zTXt/iTXt or image data */

+      png_ptr->zowner = 0;

+

+      /* The only success case is Z_STREAM_END, input_len must be 0, if not this

+       * is an internal error.

+       */

+      if (ret == Z_STREAM_END && input_len == 0)

+      {

+         /* Fix up the deflate header, if required */

+         optimize_cmf(comp->output, comp->input_len);

+

+         /* But Z_OK is returned, not Z_STREAM_END; this allows the claim

+          * function above to return Z_STREAM_END on an error (though it never

+          * does in the current versions of zlib.)

+          */

+         return Z_OK;

+      }

+

+      else

+         return ret;

+   }

+}

+

+/* Ship the compressed text out via chunk writes */

+static void

+png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp)

+{

+   png_uint_32 output_len = comp->output_len;

+   png_const_bytep output = comp->output;

+   png_uint_32 avail = (sizeof comp->output);

+   png_compression_buffer *next = png_ptr->zbuffer_list;

+

+   for (;;)

+   {

+      if (avail > output_len)

+         avail = output_len;

+

+      png_write_chunk_data(png_ptr, output, avail);

+

+      output_len -= avail;

+

+      if (output_len == 0 || next == NULL)

+         break;

+

+      avail = png_ptr->zbuffer_size;

+      output = next->output;

+      next = next->next;

+   }

+

+   /* This is an internal error; 'next' must have been NULL! */

+   if (output_len > 0)

+      png_error(png_ptr, "error writing ancillary chunked compressed data");

+}

+#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */

+

+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \

+    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)

+/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,

+ * and if invalid, correct the keyword rather than discarding the entire

+ * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in

+ * length, forbids leading or trailing whitespace, multiple internal spaces,

+ * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.

+ *

+ * The 'new_key' buffer must be 80 characters in size (for the keyword plus a

+ * trailing '\0').  If this routine returns 0 then there was no keyword, or a

+ * valid one could not be generated, and the caller must png_error.

+ */

+static png_uint_32

+png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)

+{

+   png_const_charp orig_key = key;

+   png_uint_32 key_len = 0;

+   int bad_character = 0;

+   int space = 1;

+

+   png_debug(1, "in png_check_keyword");

+

+   if (key == NULL)

+   {

+      *new_key = 0;

+      return 0;

+   }

+

+   while (*key && key_len < 79)

+   {

+      png_byte ch = (png_byte)(0xff & *key++);

+

+      if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))

+         *new_key++ = ch, ++key_len, space = 0;

+

+      else if (!space)

+      {

+         /* A space or an invalid character when one wasn't seen immediately

+          * before; output just a space.

+          */

+         *new_key++ = 32, ++key_len, space = 1;

+

+         /* If the character was not a space then it is invalid. */

+         if (ch != 32)

+            bad_character = ch;

+      }

+

+      else if (!bad_character)

+         bad_character = ch; /* just skip it, record the first error */

+   }

+

+   if (key_len > 0 && space) /* trailing space */

+   {

+      --key_len, --new_key;

+      if (!bad_character)

+         bad_character = 32;

+   }

+

+   /* Terminate the keyword */

+   *new_key = 0;

+

+   if (key_len == 0)

+      return 0;

+

+   /* Try to only output one warning per keyword: */

+   if (*key) /* keyword too long */

+      png_warning(png_ptr, "keyword truncated");

+

+   else if (bad_character)

+   {

+      PNG_WARNING_PARAMETERS(p)

+

+      png_warning_parameter(p, 1, orig_key);

+      png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);

+

+      png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");

+   }

+

+   return key_len;

+}

+#endif

+

+/* Write the IHDR chunk, and update the png_struct with the necessary

+ * information.  Note that the rest of this code depends upon this

+ * information being correct.

+ */

+void /* PRIVATE */

+png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,

+    int bit_depth, int color_type, int compression_type, int filter_type,

+    int interlace_type)

+{

+   png_byte buf[13]; /* Buffer to store the IHDR info */

+

+   png_debug(1, "in png_write_IHDR");

+

+   /* Check that we have valid input data from the application info */

+   switch (color_type)

+   {

+      case PNG_COLOR_TYPE_GRAY:

+         switch (bit_depth)

+         {

+            case 1:

+            case 2:

+            case 4:

+            case 8:

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+            case 16:

+#endif

+               png_ptr->channels = 1; break;

+

+            default:

+               png_error(png_ptr,

+                   "Invalid bit depth for grayscale image");

+         }

+         break;

+

+      case PNG_COLOR_TYPE_RGB:

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+         if (bit_depth != 8 && bit_depth != 16)

+#else

+         if (bit_depth != 8)

+#endif

+            png_error(png_ptr, "Invalid bit depth for RGB image");

+

+         png_ptr->channels = 3;

+         break;

+

+      case PNG_COLOR_TYPE_PALETTE:

+         switch (bit_depth)

+         {

+            case 1:

+            case 2:

+            case 4:

+            case 8:

+               png_ptr->channels = 1;

+               break;

+

+            default:

+               png_error(png_ptr, "Invalid bit depth for paletted image");

+         }

+         break;

+

+      case PNG_COLOR_TYPE_GRAY_ALPHA:

+         if (bit_depth != 8 && bit_depth != 16)

+            png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");

+

+         png_ptr->channels = 2;

+         break;

+

+      case PNG_COLOR_TYPE_RGB_ALPHA:

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+         if (bit_depth != 8 && bit_depth != 16)

+#else

+         if (bit_depth != 8)

+#endif

+            png_error(png_ptr, "Invalid bit depth for RGBA image");

+

+         png_ptr->channels = 4;

+         break;

+

+      default:

+         png_error(png_ptr, "Invalid image color type specified");

+   }

+

+   if (compression_type != PNG_COMPRESSION_TYPE_BASE)

+   {

+      png_warning(png_ptr, "Invalid compression type specified");

+      compression_type = PNG_COMPRESSION_TYPE_BASE;

+   }

+

+   /* Write filter_method 64 (intrapixel differencing) only if

+    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and

+    * 2. Libpng did not write a PNG signature (this filter_method is only

+    *    used in PNG datastreams that are embedded in MNG datastreams) and

+    * 3. The application called png_permit_mng_features with a mask that

+    *    included PNG_FLAG_MNG_FILTER_64 and

+    * 4. The filter_method is 64 and

+    * 5. The color_type is RGB or RGBA

+    */

+   if (

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+       !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&

+       ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&

+       (color_type == PNG_COLOR_TYPE_RGB ||

+        color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&

+       (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&

+#endif

+       filter_type != PNG_FILTER_TYPE_BASE)

+   {

+      png_warning(png_ptr, "Invalid filter type specified");

+      filter_type = PNG_FILTER_TYPE_BASE;

+   }

+

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+   if (interlace_type != PNG_INTERLACE_NONE &&

+       interlace_type != PNG_INTERLACE_ADAM7)

+   {

+      png_warning(png_ptr, "Invalid interlace type specified");

+      interlace_type = PNG_INTERLACE_ADAM7;

+   }

+#else

+   interlace_type=PNG_INTERLACE_NONE;

+#endif

+

+   /* Save the relevent information */

+   png_ptr->bit_depth = (png_byte)bit_depth;

+   png_ptr->color_type = (png_byte)color_type;

+   png_ptr->interlaced = (png_byte)interlace_type;

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+   png_ptr->filter_type = (png_byte)filter_type;

+#endif

+   png_ptr->compression_type = (png_byte)compression_type;

+   png_ptr->width = width;

+   png_ptr->height = height;

+

+   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);

+   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);

+   /* Set the usr info, so any transformations can modify it */

+   png_ptr->usr_width = png_ptr->width;

+   png_ptr->usr_bit_depth = png_ptr->bit_depth;

+   png_ptr->usr_channels = png_ptr->channels;

+

+   /* Pack the header information into the buffer */

+   png_save_uint_32(buf, width);

+   png_save_uint_32(buf + 4, height);

+   buf[8] = (png_byte)bit_depth;

+   buf[9] = (png_byte)color_type;

+   buf[10] = (png_byte)compression_type;

+   buf[11] = (png_byte)filter_type;

+   buf[12] = (png_byte)interlace_type;

+

+   /* Write the chunk */

+   png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);

+

+   if (!(png_ptr->do_filter))

+   {

+      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||

+          png_ptr->bit_depth < 8)

+         png_ptr->do_filter = PNG_FILTER_NONE;

+

+      else

+         png_ptr->do_filter = PNG_ALL_FILTERS;

+   }

+

+   png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */

+}

+

+/* Write the palette.  We are careful not to trust png_color to be in the

+ * correct order for PNG, so people can redefine it to any convenient

+ * structure.

+ */

+void /* PRIVATE */

+png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,

+    png_uint_32 num_pal)

+{

+   png_uint_32 i;

+   png_const_colorp pal_ptr;

+   png_byte buf[3];

+

+   png_debug(1, "in png_write_PLTE");

+

+   if ((

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+       !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&

+#endif

+       num_pal == 0) || num_pal > 256)

+   {

+      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)

+      {

+         png_error(png_ptr, "Invalid number of colors in palette");

+      }

+

+      else

+      {

+         png_warning(png_ptr, "Invalid number of colors in palette");

+         return;

+      }

+   }

+

+   if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))

+   {

+      png_warning(png_ptr,

+          "Ignoring request to write a PLTE chunk in grayscale PNG");

+

+      return;

+   }

+

+   png_ptr->num_palette = (png_uint_16)num_pal;

+   png_debug1(3, "num_palette = %d", png_ptr->num_palette);

+

+   png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3));

+#ifdef PNG_POINTER_INDEXING_SUPPORTED

+

+   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)

+   {

+      buf[0] = pal_ptr->red;

+      buf[1] = pal_ptr->green;

+      buf[2] = pal_ptr->blue;

+      png_write_chunk_data(png_ptr, buf, (png_size_t)3);

+   }

+

+#else

+   /* This is a little slower but some buggy compilers need to do this

+    * instead

+    */

+   pal_ptr=palette;

+

+   for (i = 0; i < num_pal; i++)

+   {

+      buf[0] = pal_ptr[i].red;

+      buf[1] = pal_ptr[i].green;

+      buf[2] = pal_ptr[i].blue;

+      png_write_chunk_data(png_ptr, buf, (png_size_t)3);

+   }

+

+#endif

+   png_write_chunk_end(png_ptr);

+   png_ptr->mode |= PNG_HAVE_PLTE;

+}

+

+/* This is similar to png_text_compress, above, except that it does not require

+ * all of the data at once and, instead of buffering the compressed result,

+ * writes it as IDAT chunks.  Unlike png_text_compress it *can* png_error out

+ * because it calls the write interface.  As a result it does its own error

+ * reporting and does not return an error code.  In the event of error it will

+ * just call png_error.  The input data length may exceed 32-bits.  The 'flush'

+ * parameter is exactly the same as that to deflate, with the following

+ * meanings:

+ *

+ * Z_NO_FLUSH: normal incremental output of compressed data

+ * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush

+ * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up

+ *

+ * The routine manages the acquire and release of the png_ptr->zstream by

+ * checking and (at the end) clearing png_ptr->zowner, it does some sanity

+ * checks on the 'mode' flags while doing this.

+ */

+void /* PRIVATE */

+png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,

+   png_alloc_size_t input_len, int flush)

+{

+   if (png_ptr->zowner != png_IDAT)

+   {

+      /* First time.   Ensure we have a temporary buffer for compression and

+       * trim the buffer list if it has more than one entry to free memory.

+       * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been

+       * created at this point, but the check here is quick and safe.

+       */

+      if (png_ptr->zbuffer_list == NULL)

+      {

+         png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp,

+            png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));

+         png_ptr->zbuffer_list->next = NULL;

+      }

+

+      else

+         png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next);

+

+      /* It is a terminal error if we can't claim the zstream. */

+      if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK)

+         png_error(png_ptr, png_ptr->zstream.msg);

+

+      /* The output state is maintained in png_ptr->zstream, so it must be

+       * initialized here after the claim.

+       */

+      png_ptr->zstream.next_out = png_ptr->zbuffer_list->output;

+      png_ptr->zstream.avail_out = png_ptr->zbuffer_size;

+   }

+

+   /* Now loop reading and writing until all the input is consumed or an error

+    * terminates the operation.  The _out values are maintained across calls to

+    * this function, but the input must be reset each time.

+    */

+   png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);

+   png_ptr->zstream.avail_in = 0; /* set below */

+   for (;;)

+   {

+      int ret;

+

+      /* INPUT: from the row data */

+      uInt avail = ZLIB_IO_MAX;

+

+      if (avail > input_len)

+         avail = (uInt)input_len; /* safe because of the check */

+

+      png_ptr->zstream.avail_in = avail;

+      input_len -= avail;

+

+      ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush);

+

+      /* Include as-yet unconsumed input */

+      input_len += png_ptr->zstream.avail_in;

+      png_ptr->zstream.avail_in = 0;

+

+      /* OUTPUT: write complete IDAT chunks when avail_out drops to zero, note

+       * that these two zstream fields are preserved across the calls, therefore

+       * there is no need to set these up on entry to the loop.

+       */

+      if (png_ptr->zstream.avail_out == 0)

+      {

+         png_bytep data = png_ptr->zbuffer_list->output;

+         uInt size = png_ptr->zbuffer_size;

+

+         /* Write an IDAT containing the data then reset the buffer.  The

+          * first IDAT may need deflate header optimization.

+          */

+#        ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED

+            if (!(png_ptr->mode & PNG_HAVE_IDAT) &&

+               png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)

+               optimize_cmf(data, png_image_size(png_ptr));

+#        endif

+

+         png_write_complete_chunk(png_ptr, png_IDAT, data, size);

+         png_ptr->mode |= PNG_HAVE_IDAT;

+

+         png_ptr->zstream.next_out = data;

+         png_ptr->zstream.avail_out = size;

+

+         /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with

+          * the same flush parameter until it has finished output, for NO_FLUSH

+          * it doesn't matter.

+          */

+         if (ret == Z_OK && flush != Z_NO_FLUSH)

+            continue;

+      }

+

+      /* The order of these checks doesn't matter much; it just effect which

+       * possible error might be detected if multiple things go wrong at once.

+       */

+      if (ret == Z_OK) /* most likely return code! */

+      {

+         /* If all the input has been consumed then just return.  If Z_FINISH

+          * was used as the flush parameter something has gone wrong if we get

+          * here.

+          */

+         if (input_len == 0)

+         {

+            if (flush == Z_FINISH)

+               png_error(png_ptr, "Z_OK on Z_FINISH with output space");

+

+            return;

+         }

+      }

+

+      else if (ret == Z_STREAM_END && flush == Z_FINISH)

+      {

+         /* This is the end of the IDAT data; any pending output must be

+          * flushed.  For small PNG files we may still be at the beginning.

+          */

+         png_bytep data = png_ptr->zbuffer_list->output;

+         uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out;

+

+#        ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED

+            if (!(png_ptr->mode & PNG_HAVE_IDAT) &&

+               png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)

+               optimize_cmf(data, png_image_size(png_ptr));

+#        endif

+

+         png_write_complete_chunk(png_ptr, png_IDAT, data, size);

+         png_ptr->zstream.avail_out = 0;

+         png_ptr->zstream.next_out = NULL;

+         png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;

+

+         png_ptr->zowner = 0; /* Release the stream */

+         return;

+      }

+

+      else

+      {

+         /* This is an error condition. */

+         png_zstream_error(png_ptr, ret);

+         png_error(png_ptr, png_ptr->zstream.msg);

+      }

+   }

+}

+

+/* Write an IEND chunk */

+void /* PRIVATE */

+png_write_IEND(png_structrp png_ptr)

+{

+   png_debug(1, "in png_write_IEND");

+

+   png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0);

+   png_ptr->mode |= PNG_HAVE_IEND;

+}

+

+#ifdef PNG_WRITE_gAMA_SUPPORTED

+/* Write a gAMA chunk */

+void /* PRIVATE */

+png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma)

+{

+   png_byte buf[4];

+

+   png_debug(1, "in png_write_gAMA");

+

+   /* file_gamma is saved in 1/100,000ths */

+   png_save_uint_32(buf, (png_uint_32)file_gamma);

+   png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);

+}

+#endif

+

+#ifdef PNG_WRITE_sRGB_SUPPORTED

+/* Write a sRGB chunk */

+void /* PRIVATE */

+png_write_sRGB(png_structrp png_ptr, int srgb_intent)

+{

+   png_byte buf[1];

+

+   png_debug(1, "in png_write_sRGB");

+

+   if (srgb_intent >= PNG_sRGB_INTENT_LAST)

+      png_warning(png_ptr,

+          "Invalid sRGB rendering intent specified");

+

+   buf[0]=(png_byte)srgb_intent;

+   png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1);

+}

+#endif

+

+#ifdef PNG_WRITE_iCCP_SUPPORTED

+/* Write an iCCP chunk */

+void /* PRIVATE */

+png_write_iCCP(png_structrp png_ptr, png_const_charp name,

+    png_const_bytep profile)

+{

+   png_uint_32 name_len;

+   png_uint_32 profile_len;

+   png_byte new_name[81]; /* 1 byte for the compression byte */

+   compression_state comp;

+

+   png_debug(1, "in png_write_iCCP");

+

+   /* These are all internal problems: the profile should have been checked

+    * before when it was stored.

+    */

+   if (profile == NULL)

+      png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */

+

+   profile_len = png_get_uint_32(profile);

+

+   if (profile_len < 132)

+      png_error(png_ptr, "ICC profile too short");

+

+   if (profile_len & 0x03)

+      png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");

+

+   {

+      png_uint_32 embedded_profile_len = png_get_uint_32(profile);

+

+      if (profile_len != embedded_profile_len)

+         png_error(png_ptr, "Profile length does not match profile");

+   }

+

+   name_len = png_check_keyword(png_ptr, name, new_name);

+

+   if (name_len == 0)

+      png_error(png_ptr, "iCCP: invalid keyword");

+

+   new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE;

+

+   /* Make sure we include the NULL after the name and the compression type */

+   ++name_len;

+

+   png_text_compress_init(&comp, profile, profile_len);

+

+   /* Allow for keyword terminator and compression byte */

+   if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK)

+      png_error(png_ptr, png_ptr->zstream.msg);

+

+   png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len);

+

+   png_write_chunk_data(png_ptr, new_name, name_len);

+

+   png_write_compressed_data_out(png_ptr, &comp);

+

+   png_write_chunk_end(png_ptr);

+}

+#endif

+

+#ifdef PNG_WRITE_sPLT_SUPPORTED

+/* Write a sPLT chunk */

+void /* PRIVATE */

+png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)

+{

+   png_uint_32 name_len;

+   png_byte new_name[80];

+   png_byte entrybuf[10];

+   png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);

+   png_size_t palette_size = entry_size * spalette->nentries;

+   png_sPLT_entryp ep;

+#ifndef PNG_POINTER_INDEXING_SUPPORTED

+   int i;

+#endif

+

+   png_debug(1, "in png_write_sPLT");

+

+   name_len = png_check_keyword(png_ptr, spalette->name, new_name);

+

+   if (name_len == 0)

+      png_error(png_ptr, "sPLT: invalid keyword");

+

+   /* Make sure we include the NULL after the name */

+   png_write_chunk_header(png_ptr, png_sPLT,

+       (png_uint_32)(name_len + 2 + palette_size));

+

+   png_write_chunk_data(png_ptr, (png_bytep)new_name,

+       (png_size_t)(name_len + 1));

+

+   png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1);

+

+   /* Loop through each palette entry, writing appropriately */

+#ifdef PNG_POINTER_INDEXING_SUPPORTED

+   for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)

+   {

+      if (spalette->depth == 8)

+      {

+         entrybuf[0] = (png_byte)ep->red;

+         entrybuf[1] = (png_byte)ep->green;

+         entrybuf[2] = (png_byte)ep->blue;

+         entrybuf[3] = (png_byte)ep->alpha;

+         png_save_uint_16(entrybuf + 4, ep->frequency);

+      }

+

+      else

+      {

+         png_save_uint_16(entrybuf + 0, ep->red);

+         png_save_uint_16(entrybuf + 2, ep->green);

+         png_save_uint_16(entrybuf + 4, ep->blue);

+         png_save_uint_16(entrybuf + 6, ep->alpha);

+         png_save_uint_16(entrybuf + 8, ep->frequency);

+      }

+

+      png_write_chunk_data(png_ptr, entrybuf, entry_size);

+   }

+#else

+   ep=spalette->entries;

+   for (i = 0; i>spalette->nentries; i++)

+   {

+      if (spalette->depth == 8)

+      {

+         entrybuf[0] = (png_byte)ep[i].red;

+         entrybuf[1] = (png_byte)ep[i].green;

+         entrybuf[2] = (png_byte)ep[i].blue;

+         entrybuf[3] = (png_byte)ep[i].alpha;

+         png_save_uint_16(entrybuf + 4, ep[i].frequency);

+      }

+

+      else

+      {

+         png_save_uint_16(entrybuf + 0, ep[i].red);

+         png_save_uint_16(entrybuf + 2, ep[i].green);

+         png_save_uint_16(entrybuf + 4, ep[i].blue);

+         png_save_uint_16(entrybuf + 6, ep[i].alpha);

+         png_save_uint_16(entrybuf + 8, ep[i].frequency);

+      }

+

+      png_write_chunk_data(png_ptr, entrybuf, entry_size);

+   }

+#endif

+

+   png_write_chunk_end(png_ptr);

+}

+#endif

+

+#ifdef PNG_WRITE_sBIT_SUPPORTED

+/* Write the sBIT chunk */

+void /* PRIVATE */

+png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type)

+{

+   png_byte buf[4];

+   png_size_t size;

+

+   png_debug(1, "in png_write_sBIT");

+

+   /* Make sure we don't depend upon the order of PNG_COLOR_8 */

+   if (color_type & PNG_COLOR_MASK_COLOR)

+   {

+      png_byte maxbits;

+

+      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :

+          png_ptr->usr_bit_depth);

+

+      if (sbit->red == 0 || sbit->red > maxbits ||

+          sbit->green == 0 || sbit->green > maxbits ||

+          sbit->blue == 0 || sbit->blue > maxbits)

+      {

+         png_warning(png_ptr, "Invalid sBIT depth specified");

+         return;

+      }

+

+      buf[0] = sbit->red;

+      buf[1] = sbit->green;

+      buf[2] = sbit->blue;

+      size = 3;

+   }

+

+   else

+   {

+      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)

+      {

+         png_warning(png_ptr, "Invalid sBIT depth specified");

+         return;

+      }

+

+      buf[0] = sbit->gray;

+      size = 1;

+   }

+

+   if (color_type & PNG_COLOR_MASK_ALPHA)

+   {

+      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)

+      {

+         png_warning(png_ptr, "Invalid sBIT depth specified");

+         return;

+      }

+

+      buf[size++] = sbit->alpha;

+   }

+

+   png_write_complete_chunk(png_ptr, png_sBIT, buf, size);

+}

+#endif

+

+#ifdef PNG_WRITE_cHRM_SUPPORTED

+/* Write the cHRM chunk */

+void /* PRIVATE */

+png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy)

+{

+   png_byte buf[32];

+

+   png_debug(1, "in png_write_cHRM");

+

+   /* Each value is saved in 1/100,000ths */

+   png_save_int_32(buf,      xy->whitex);

+   png_save_int_32(buf +  4, xy->whitey);

+

+   png_save_int_32(buf +  8, xy->redx);

+   png_save_int_32(buf + 12, xy->redy);

+

+   png_save_int_32(buf + 16, xy->greenx);

+   png_save_int_32(buf + 20, xy->greeny);

+

+   png_save_int_32(buf + 24, xy->bluex);

+   png_save_int_32(buf + 28, xy->bluey);

+

+   png_write_complete_chunk(png_ptr, png_cHRM, buf, 32);

+}

+#endif

+

+#ifdef PNG_WRITE_tRNS_SUPPORTED

+/* Write the tRNS chunk */

+void /* PRIVATE */

+png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,

+    png_const_color_16p tran, int num_trans, int color_type)

+{

+   png_byte buf[6];

+

+   png_debug(1, "in png_write_tRNS");

+

+   if (color_type == PNG_COLOR_TYPE_PALETTE)

+   {

+      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)

+      {

+         png_app_warning(png_ptr,

+             "Invalid number of transparent colors specified");

+         return;

+      }

+

+      /* Write the chunk out as it is */

+      png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,

+         (png_size_t)num_trans);

+   }

+

+   else if (color_type == PNG_COLOR_TYPE_GRAY)

+   {

+      /* One 16 bit value */

+      if (tran->gray >= (1 << png_ptr->bit_depth))

+      {

+         png_app_warning(png_ptr,

+             "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");

+

+         return;

+      }

+

+      png_save_uint_16(buf, tran->gray);

+      png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2);

+   }

+

+   else if (color_type == PNG_COLOR_TYPE_RGB)

+   {

+      /* Three 16 bit values */

+      png_save_uint_16(buf, tran->red);

+      png_save_uint_16(buf + 2, tran->green);

+      png_save_uint_16(buf + 4, tran->blue);

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))

+#else

+      if (buf[0] | buf[2] | buf[4])

+#endif

+      {

+         png_app_warning(png_ptr,

+           "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");

+         return;

+      }

+

+      png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6);

+   }

+

+   else

+   {

+      png_app_warning(png_ptr, "Can't write tRNS with an alpha channel");

+   }

+}

+#endif

+

+#ifdef PNG_WRITE_bKGD_SUPPORTED

+/* Write the background chunk */

+void /* PRIVATE */

+png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)

+{

+   png_byte buf[6];

+

+   png_debug(1, "in png_write_bKGD");

+

+   if (color_type == PNG_COLOR_TYPE_PALETTE)

+   {

+      if (

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+          (png_ptr->num_palette ||

+          (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&

+#endif

+         back->index >= png_ptr->num_palette)

+      {

+         png_warning(png_ptr, "Invalid background palette index");

+         return;

+      }

+

+      buf[0] = back->index;

+      png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);

+   }

+

+   else if (color_type & PNG_COLOR_MASK_COLOR)

+   {

+      png_save_uint_16(buf, back->red);

+      png_save_uint_16(buf + 2, back->green);

+      png_save_uint_16(buf + 4, back->blue);

+#ifdef PNG_WRITE_16BIT_SUPPORTED

+      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))

+#else

+      if (buf[0] | buf[2] | buf[4])

+#endif

+      {

+         png_warning(png_ptr,

+             "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");

+

+         return;

+      }

+

+      png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);

+   }

+

+   else

+   {

+      if (back->gray >= (1 << png_ptr->bit_depth))

+      {

+         png_warning(png_ptr,

+             "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");

+

+         return;

+      }

+

+      png_save_uint_16(buf, back->gray);

+      png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);

+   }

+}

+#endif

+

+#ifdef PNG_WRITE_hIST_SUPPORTED

+/* Write the histogram */

+void /* PRIVATE */

+png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist)

+{

+   int i;

+   png_byte buf[3];

+

+   png_debug(1, "in png_write_hIST");

+

+   if (num_hist > (int)png_ptr->num_palette)

+   {

+      png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,

+          png_ptr->num_palette);

+

+      png_warning(png_ptr, "Invalid number of histogram entries specified");

+      return;

+   }

+

+   png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2));

+

+   for (i = 0; i < num_hist; i++)

+   {

+      png_save_uint_16(buf, hist[i]);

+      png_write_chunk_data(png_ptr, buf, (png_size_t)2);

+   }

+

+   png_write_chunk_end(png_ptr);

+}

+#endif

+

+#ifdef PNG_WRITE_tEXt_SUPPORTED

+/* Write a tEXt chunk */

+void /* PRIVATE */

+png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,

+    png_size_t text_len)

+{

+   png_uint_32 key_len;

+   png_byte new_key[80];

+

+   png_debug(1, "in png_write_tEXt");

+

+   key_len = png_check_keyword(png_ptr, key, new_key);

+

+   if (key_len == 0)

+      png_error(png_ptr, "tEXt: invalid keyword");

+

+   if (text == NULL || *text == '\0')

+      text_len = 0;

+

+   else

+      text_len = strlen(text);

+

+   if (text_len > PNG_UINT_31_MAX - (key_len+1))

+      png_error(png_ptr, "tEXt: text too long");

+

+   /* Make sure we include the 0 after the key */

+   png_write_chunk_header(png_ptr, png_tEXt,

+       (png_uint_32)/*checked above*/(key_len + text_len + 1));

+   /*

+    * We leave it to the application to meet PNG-1.0 requirements on the

+    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of

+    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.

+    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.

+    */

+   png_write_chunk_data(png_ptr, new_key, key_len + 1);

+

+   if (text_len)

+      png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len);

+

+   png_write_chunk_end(png_ptr);

+}

+#endif

+

+#ifdef PNG_WRITE_zTXt_SUPPORTED

+/* Write a compressed text chunk */

+void /* PRIVATE */

+png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,

+    png_size_t text_len, int compression)

+{

+   png_uint_32 key_len;

+   png_byte new_key[81];

+   compression_state comp;

+

+   png_debug(1, "in png_write_zTXt");

+   PNG_UNUSED(text_len) /* Always use strlen */

+

+   if (compression == PNG_TEXT_COMPRESSION_NONE)

+   {

+      png_write_tEXt(png_ptr, key, text, 0);

+      return;

+   }

+

+   if (compression != PNG_TEXT_COMPRESSION_zTXt)

+      png_error(png_ptr, "zTXt: invalid compression type");

+

+   key_len = png_check_keyword(png_ptr, key, new_key);

+

+   if (key_len == 0)

+      png_error(png_ptr, "zTXt: invalid keyword");

+

+   /* Add the compression method and 1 for the keyword separator. */

+   new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;

+   ++key_len;

+

+   /* Compute the compressed data; do it now for the length */

+   png_text_compress_init(&comp, (png_const_bytep)text,

+      text == NULL ? 0 : strlen(text));

+

+   if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK)

+      png_error(png_ptr, png_ptr->zstream.msg);

+

+   /* Write start of chunk */

+   png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len);

+

+   /* Write key */

+   png_write_chunk_data(png_ptr, new_key, key_len);

+

+   /* Write the compressed data */

+   png_write_compressed_data_out(png_ptr, &comp);

+

+   /* Close the chunk */

+   png_write_chunk_end(png_ptr);

+}

+#endif

+

+#ifdef PNG_WRITE_iTXt_SUPPORTED

+/* Write an iTXt chunk */

+void /* PRIVATE */

+png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,

+    png_const_charp lang, png_const_charp lang_key, png_const_charp text)

+{

+   png_uint_32 key_len, prefix_len;

+   png_size_t lang_len, lang_key_len;

+   png_byte new_key[82];

+   compression_state comp;

+

+   png_debug(1, "in png_write_iTXt");

+

+   key_len = png_check_keyword(png_ptr, key, new_key);

+

+   if (key_len == 0)

+      png_error(png_ptr, "iTXt: invalid keyword");

+

+   /* Set the compression flag */

+   switch (compression)

+   {

+      case PNG_ITXT_COMPRESSION_NONE:

+      case PNG_TEXT_COMPRESSION_NONE:

+         compression = new_key[++key_len] = 0; /* no compression */

+         break;

+

+      case PNG_TEXT_COMPRESSION_zTXt:

+      case PNG_ITXT_COMPRESSION_zTXt:

+         compression = new_key[++key_len] = 1; /* compressed */

+         break;

+

+      default:

+         png_error(png_ptr, "iTXt: invalid compression");

+   }

+

+   new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;

+   ++key_len; /* for the keywod separator */

+

+   /* We leave it to the application to meet PNG-1.0 requirements on the

+    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of

+    * any non-Latin-1 characters except for NEWLINE.  ISO PNG, however,

+    * specifies that the text is UTF-8 and this really doesn't require any

+    * checking.

+    *

+    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.

+    *

+    * TODO: validate the language tag correctly (see the spec.)

+    */

+   if (lang == NULL) lang = ""; /* empty language is valid */

+   lang_len = strlen(lang)+1;

+   if (lang_key == NULL) lang_key = ""; /* may be empty */

+   lang_key_len = strlen(lang_key)+1;

+   if (text == NULL) text = ""; /* may be empty */

+

+   prefix_len = key_len;

+   if (lang_len > PNG_UINT_31_MAX-prefix_len)

+      prefix_len = PNG_UINT_31_MAX;

+   else

+      prefix_len = (png_uint_32)(prefix_len + lang_len);

+

+   if (lang_key_len > PNG_UINT_31_MAX-prefix_len)

+      prefix_len = PNG_UINT_31_MAX;

+   else

+      prefix_len = (png_uint_32)(prefix_len + lang_key_len);

+

+   png_text_compress_init(&comp, (png_const_bytep)text, strlen(text));

+

+   if (compression)

+   {

+      if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK)

+         png_error(png_ptr, png_ptr->zstream.msg);

+   }

+

+   else

+   {

+      if (comp.input_len > PNG_UINT_31_MAX-prefix_len)

+         png_error(png_ptr, "iTXt: uncompressed text too long");

+

+      /* So the string will fit in a chunk: */

+      comp.output_len = (png_uint_32)/*SAFE*/comp.input_len;

+   }

+

+   png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len);

+

+   png_write_chunk_data(png_ptr, new_key, key_len);

+

+   png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len);

+

+   png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len);

+

+   if (compression)

+      png_write_compressed_data_out(png_ptr, &comp);

+

+   else

+      png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_len);

+

+   png_write_chunk_end(png_ptr);

+}

+#endif

+

+#ifdef PNG_WRITE_oFFs_SUPPORTED

+/* Write the oFFs chunk */

+void /* PRIVATE */

+png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset,

+    int unit_type)

+{

+   png_byte buf[9];

+

+   png_debug(1, "in png_write_oFFs");

+

+   if (unit_type >= PNG_OFFSET_LAST)

+      png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");

+

+   png_save_int_32(buf, x_offset);

+   png_save_int_32(buf + 4, y_offset);

+   buf[8] = (png_byte)unit_type;

+

+   png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);

+}

+#endif

+#ifdef PNG_WRITE_pCAL_SUPPORTED

+/* Write the pCAL chunk (described in the PNG extensions document) */

+void /* PRIVATE */

+png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,

+    png_int_32 X1, int type, int nparams, png_const_charp units,

+    png_charpp params)

+{

+   png_uint_32 purpose_len;

+   png_size_t units_len, total_len;

+   png_size_tp params_len;

+   png_byte buf[10];

+   png_byte new_purpose[80];

+   int i;

+

+   png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);

+

+   if (type >= PNG_EQUATION_LAST)

+      png_error(png_ptr, "Unrecognized equation type for pCAL chunk");

+

+   purpose_len = png_check_keyword(png_ptr, purpose, new_purpose);

+

+   if (purpose_len == 0)

+      png_error(png_ptr, "pCAL: invalid keyword");

+

+   ++purpose_len; /* terminator */

+

+   png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);

+   units_len = strlen(units) + (nparams == 0 ? 0 : 1);

+   png_debug1(3, "pCAL units length = %d", (int)units_len);

+   total_len = purpose_len + units_len + 10;

+

+   params_len = (png_size_tp)png_malloc(png_ptr,

+       (png_alloc_size_t)(nparams * (sizeof (png_size_t))));

+

+   /* Find the length of each parameter, making sure we don't count the

+    * null terminator for the last parameter.

+    */

+   for (i = 0; i < nparams; i++)

+   {

+      params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);

+      png_debug2(3, "pCAL parameter %d length = %lu", i,

+          (unsigned long)params_len[i]);

+      total_len += params_len[i];

+   }

+

+   png_debug1(3, "pCAL total length = %d", (int)total_len);

+   png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len);

+   png_write_chunk_data(png_ptr, new_purpose, purpose_len);

+   png_save_int_32(buf, X0);

+   png_save_int_32(buf + 4, X1);

+   buf[8] = (png_byte)type;

+   buf[9] = (png_byte)nparams;

+   png_write_chunk_data(png_ptr, buf, (png_size_t)10);

+   png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len);

+

+   for (i = 0; i < nparams; i++)

+   {

+      png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]);

+   }

+

+   png_free(png_ptr, params_len);

+   png_write_chunk_end(png_ptr);

+}

+#endif

+

+#ifdef PNG_WRITE_sCAL_SUPPORTED

+/* Write the sCAL chunk */

+void /* PRIVATE */

+png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width,

+    png_const_charp height)

+{

+   png_byte buf[64];

+   png_size_t wlen, hlen, total_len;

+

+   png_debug(1, "in png_write_sCAL_s");

+

+   wlen = strlen(width);

+   hlen = strlen(height);

+   total_len = wlen + hlen + 2;

+

+   if (total_len > 64)

+   {

+      png_warning(png_ptr, "Can't write sCAL (buffer too small)");

+      return;

+   }

+

+   buf[0] = (png_byte)unit;

+   memcpy(buf + 1, width, wlen + 1);      /* Append the '\0' here */

+   memcpy(buf + wlen + 2, height, hlen);  /* Do NOT append the '\0' here */

+

+   png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);

+   png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len);

+}

+#endif

+

+#ifdef PNG_WRITE_pHYs_SUPPORTED

+/* Write the pHYs chunk */

+void /* PRIVATE */

+png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit,

+    png_uint_32 y_pixels_per_unit,

+    int unit_type)

+{

+   png_byte buf[9];

+

+   png_debug(1, "in png_write_pHYs");

+

+   if (unit_type >= PNG_RESOLUTION_LAST)

+      png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");

+

+   png_save_uint_32(buf, x_pixels_per_unit);

+   png_save_uint_32(buf + 4, y_pixels_per_unit);

+   buf[8] = (png_byte)unit_type;

+

+   png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);

+}

+#endif

+

+#ifdef PNG_WRITE_tIME_SUPPORTED

+/* Write the tIME chunk.  Use either png_convert_from_struct_tm()

+ * or png_convert_from_time_t(), or fill in the structure yourself.

+ */

+void /* PRIVATE */

+png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)

+{

+   png_byte buf[7];

+

+   png_debug(1, "in png_write_tIME");

+

+   if (mod_time->month  > 12 || mod_time->month  < 1 ||

+       mod_time->day    > 31 || mod_time->day    < 1 ||

+       mod_time->hour   > 23 || mod_time->second > 60)

+   {

+      png_warning(png_ptr, "Invalid time specified for tIME chunk");

+      return;

+   }

+

+   png_save_uint_16(buf, mod_time->year);

+   buf[2] = mod_time->month;

+   buf[3] = mod_time->day;

+   buf[4] = mod_time->hour;

+   buf[5] = mod_time->minute;

+   buf[6] = mod_time->second;

+

+   png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7);

+}

+#endif

+

+/* Initializes the row writing capability of libpng */

+void /* PRIVATE */

+png_write_start_row(png_structrp png_ptr)

+{

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */

+

+   /* Start of interlace block */

+   static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};

+

+   /* Offset to next interlace block */

+   static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};

+

+   /* Start of interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};

+

+   /* Offset to next interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};

+#endif

+

+   png_alloc_size_t buf_size;

+   int usr_pixel_depth;

+

+   png_debug(1, "in png_write_start_row");

+

+   usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth;

+   buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1;

+

+   /* 1.5.6: added to allow checking in the row write code. */

+   png_ptr->transformed_pixel_depth = png_ptr->pixel_depth;

+   png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth;

+

+   /* Set up row buffer */

+   png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);

+

+   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;

+

+#ifdef PNG_WRITE_FILTER_SUPPORTED

+   /* Set up filtering buffer, if using this filter */

+   if (png_ptr->do_filter & PNG_FILTER_SUB)

+   {

+      png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);

+

+      png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;

+   }

+

+   /* We only need to keep the previous row if we are using one of these. */

+   if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))

+   {

+      /* Set up previous row buffer */

+      png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size);

+

+      if (png_ptr->do_filter & PNG_FILTER_UP)

+      {

+         png_ptr->up_row = (png_bytep)png_malloc(png_ptr,

+            png_ptr->rowbytes + 1);

+

+         png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;

+      }

+

+      if (png_ptr->do_filter & PNG_FILTER_AVG)

+      {

+         png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,

+             png_ptr->rowbytes + 1);

+

+         png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;

+      }

+

+      if (png_ptr->do_filter & PNG_FILTER_PAETH)

+      {

+         png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,

+             png_ptr->rowbytes + 1);

+

+         png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;

+      }

+   }

+#endif /* PNG_WRITE_FILTER_SUPPORTED */

+

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+   /* If interlaced, we need to set up width and height of pass */

+   if (png_ptr->interlaced)

+   {

+      if (!(png_ptr->transformations & PNG_INTERLACE))

+      {

+         png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -

+             png_pass_ystart[0]) / png_pass_yinc[0];

+

+         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -

+             png_pass_start[0]) / png_pass_inc[0];

+      }

+

+      else

+      {

+         png_ptr->num_rows = png_ptr->height;

+         png_ptr->usr_width = png_ptr->width;

+      }

+   }

+

+   else

+#endif

+   {

+      png_ptr->num_rows = png_ptr->height;

+      png_ptr->usr_width = png_ptr->width;

+   }

+}

+

+/* Internal use only.  Called when finished processing a row of data. */

+void /* PRIVATE */

+png_write_finish_row(png_structrp png_ptr)

+{

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */

+

+   /* Start of interlace block */

+   static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};

+

+   /* Offset to next interlace block */

+   static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};

+

+   /* Start of interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};

+

+   /* Offset to next interlace block in the y direction */

+   static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};

+#endif

+

+   png_debug(1, "in png_write_finish_row");

+

+   /* Next row */

+   png_ptr->row_number++;

+

+   /* See if we are done */

+   if (png_ptr->row_number < png_ptr->num_rows)

+      return;

+

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+   /* If interlaced, go to next pass */

+   if (png_ptr->interlaced)

+   {

+      png_ptr->row_number = 0;

+      if (png_ptr->transformations & PNG_INTERLACE)

+      {

+         png_ptr->pass++;

+      }

+

+      else

+      {

+         /* Loop until we find a non-zero width or height pass */

+         do

+         {

+            png_ptr->pass++;

+

+            if (png_ptr->pass >= 7)

+               break;

+

+            png_ptr->usr_width = (png_ptr->width +

+                png_pass_inc[png_ptr->pass] - 1 -

+                png_pass_start[png_ptr->pass]) /

+                png_pass_inc[png_ptr->pass];

+

+            png_ptr->num_rows = (png_ptr->height +

+                png_pass_yinc[png_ptr->pass] - 1 -

+                png_pass_ystart[png_ptr->pass]) /

+                png_pass_yinc[png_ptr->pass];

+

+            if (png_ptr->transformations & PNG_INTERLACE)

+               break;

+

+         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);

+

+      }

+

+      /* Reset the row above the image for the next pass */

+      if (png_ptr->pass < 7)

+      {

+         if (png_ptr->prev_row != NULL)

+            memset(png_ptr->prev_row, 0,

+                (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*

+                png_ptr->usr_bit_depth, png_ptr->width)) + 1);

+

+         return;

+      }

+   }

+#endif

+

+   /* If we get here, we've just written the last row, so we need

+      to flush the compressor */

+   png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH);

+}

+

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+/* Pick out the correct pixels for the interlace pass.

+ * The basic idea here is to go through the row with a source

+ * pointer and a destination pointer (sp and dp), and copy the

+ * correct pixels for the pass.  As the row gets compacted,

+ * sp will always be >= dp, so we should never overwrite anything.

+ * See the default: case for the easiest code to understand.

+ */

+void /* PRIVATE */

+png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)

+{

+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */

+

+   /* Start of interlace block */

+   static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};

+

+   /* Offset to next interlace block */

+   static PNG_CONST png_byte  png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};

+

+   png_debug(1, "in png_do_write_interlace");

+

+   /* We don't have to do anything on the last pass (6) */

+   if (pass < 6)

+   {

+      /* Each pixel depth is handled separately */

+      switch (row_info->pixel_depth)

+      {

+         case 1:

+         {

+            png_bytep sp;

+            png_bytep dp;

+            int shift;

+            int d;

+            int value;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            dp = row;

+            d = 0;

+            shift = 7;

+

+            for (i = png_pass_start[pass]; i < row_width;

+               i += png_pass_inc[pass])

+            {

+               sp = row + (png_size_t)(i >> 3);

+               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;

+               d |= (value << shift);

+

+               if (shift == 0)

+               {

+                  shift = 7;

+                  *dp++ = (png_byte)d;

+                  d = 0;

+               }

+

+               else

+                  shift--;

+

+            }

+            if (shift != 7)

+               *dp = (png_byte)d;

+

+            break;

+         }

+

+         case 2:

+         {

+            png_bytep sp;

+            png_bytep dp;

+            int shift;

+            int d;

+            int value;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            dp = row;

+            shift = 6;

+            d = 0;

+

+            for (i = png_pass_start[pass]; i < row_width;

+               i += png_pass_inc[pass])

+            {

+               sp = row + (png_size_t)(i >> 2);

+               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;

+               d |= (value << shift);

+

+               if (shift == 0)

+               {

+                  shift = 6;

+                  *dp++ = (png_byte)d;

+                  d = 0;

+               }

+

+               else

+                  shift -= 2;

+            }

+            if (shift != 6)

+               *dp = (png_byte)d;

+

+            break;

+         }

+

+         case 4:

+         {

+            png_bytep sp;

+            png_bytep dp;

+            int shift;

+            int d;

+            int value;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+

+            dp = row;

+            shift = 4;

+            d = 0;

+            for (i = png_pass_start[pass]; i < row_width;

+                i += png_pass_inc[pass])

+            {

+               sp = row + (png_size_t)(i >> 1);

+               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;

+               d |= (value << shift);

+

+               if (shift == 0)

+               {

+                  shift = 4;

+                  *dp++ = (png_byte)d;

+                  d = 0;

+               }

+

+               else

+                  shift -= 4;

+            }

+            if (shift != 4)

+               *dp = (png_byte)d;

+

+            break;

+         }

+

+         default:

+         {

+            png_bytep sp;

+            png_bytep dp;

+            png_uint_32 i;

+            png_uint_32 row_width = row_info->width;

+            png_size_t pixel_bytes;

+

+            /* Start at the beginning */

+            dp = row;

+

+            /* Find out how many bytes each pixel takes up */

+            pixel_bytes = (row_info->pixel_depth >> 3);

+

+            /* Loop through the row, only looking at the pixels that matter */

+            for (i = png_pass_start[pass]; i < row_width;

+               i += png_pass_inc[pass])

+            {

+               /* Find out where the original pixel is */

+               sp = row + (png_size_t)i * pixel_bytes;

+

+               /* Move the pixel */

+               if (dp != sp)

+                  memcpy(dp, sp, pixel_bytes);

+

+               /* Next pixel */

+               dp += pixel_bytes;

+            }

+            break;

+         }

+      }

+      /* Set new row width */

+      row_info->width = (row_info->width +

+          png_pass_inc[pass] - 1 -

+          png_pass_start[pass]) /

+          png_pass_inc[pass];

+

+      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,

+          row_info->width);

+   }

+}

+#endif

+

+/* This filters the row, chooses which filter to use, if it has not already

+ * been specified by the application, and then writes the row out with the

+ * chosen filter.

+ */

+static void png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,

+   png_size_t row_bytes);

+

+#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)

+#define PNG_HISHIFT 10

+#define PNG_LOMASK ((png_uint_32)0xffffL)

+#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))

+void /* PRIVATE */

+png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)

+{

+   png_bytep best_row;

+#ifdef PNG_WRITE_FILTER_SUPPORTED

+   png_bytep prev_row, row_buf;

+   png_uint_32 mins, bpp;

+   png_byte filter_to_do = png_ptr->do_filter;

+   png_size_t row_bytes = row_info->rowbytes;

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+   int num_p_filters = png_ptr->num_prev_filters;

+#endif

+

+   png_debug(1, "in png_write_find_filter");

+

+#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+  if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS)

+  {

+     /* These will never be selected so we need not test them. */

+     filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH);

+  }

+#endif

+

+   /* Find out how many bytes offset each pixel is */

+   bpp = (row_info->pixel_depth + 7) >> 3;

+

+   prev_row = png_ptr->prev_row;

+#endif

+   best_row = png_ptr->row_buf;

+#ifdef PNG_WRITE_FILTER_SUPPORTED

+   row_buf = best_row;

+   mins = PNG_MAXSUM;

+

+   /* The prediction method we use is to find which method provides the

+    * smallest value when summing the absolute values of the distances

+    * from zero, using anything >= 128 as negative numbers.  This is known

+    * as the "minimum sum of absolute differences" heuristic.  Other

+    * heuristics are the "weighted minimum sum of absolute differences"

+    * (experimental and can in theory improve compression), and the "zlib

+    * predictive" method (not implemented yet), which does test compressions

+    * of lines using different filter methods, and then chooses the

+    * (series of) filter(s) that give minimum compressed data size (VERY

+    * computationally expensive).

+    *

+    * GRR 980525:  consider also

+    *

+    *   (1) minimum sum of absolute differences from running average (i.e.,

+    *       keep running sum of non-absolute differences & count of bytes)

+    *       [track dispersion, too?  restart average if dispersion too large?]

+    *

+    *  (1b) minimum sum of absolute differences from sliding average, probably

+    *       with window size <= deflate window (usually 32K)

+    *

+    *   (2) minimum sum of squared differences from zero or running average

+    *       (i.e., ~ root-mean-square approach)

+    */

+

+

+   /* We don't need to test the 'no filter' case if this is the only filter

+    * that has been chosen, as it doesn't actually do anything to the data.

+    */

+   if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE)

+   {

+      png_bytep rp;

+      png_uint_32 sum = 0;

+      png_size_t i;

+      int v;

+

+      for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)

+      {

+         v = *rp;

+         sum += (v < 128) ? v : 256 - v;

+      }

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         png_uint_32 sumhi, sumlo;

+         int j;

+         sumlo = sum & PNG_LOMASK;

+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */

+

+         /* Reduce the sum if we match any of the previous rows */

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)

+            {

+               sumlo = (sumlo * png_ptr->filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               sumhi = (sumhi * png_ptr->filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         /* Factor in the cost of this filter (this is here for completeness,

+          * but it makes no sense to have a "cost" for the NONE filter, as

+          * it has the minimum possible computational cost - none).

+          */

+         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>

+             PNG_COST_SHIFT;

+

+         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>

+             PNG_COST_SHIFT;

+

+         if (sumhi > PNG_HIMASK)

+            sum = PNG_MAXSUM;

+

+         else

+            sum = (sumhi << PNG_HISHIFT) + sumlo;

+      }

+#endif

+      mins = sum;

+   }

+

+   /* Sub filter */

+   if (filter_to_do == PNG_FILTER_SUB)

+   /* It's the only filter so no testing is needed */

+   {

+      png_bytep rp, lp, dp;

+      png_size_t i;

+

+      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;

+           i++, rp++, dp++)

+      {

+         *dp = *rp;

+      }

+

+      for (lp = row_buf + 1; i < row_bytes;

+         i++, rp++, lp++, dp++)

+      {

+         *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

+      }

+

+      best_row = png_ptr->sub_row;

+   }

+

+   else if (filter_to_do & PNG_FILTER_SUB)

+   {

+      png_bytep rp, dp, lp;

+      png_uint_32 sum = 0, lmins = mins;

+      png_size_t i;

+      int v;

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      /* We temporarily increase the "minimum sum" by the factor we

+       * would reduce the sum of this filter, so that we can do the

+       * early exit comparison without scaling the sum each time.

+       */

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         int j;

+         png_uint_32 lmhi, lmlo;

+         lmlo = lmins & PNG_LOMASK;

+         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

+

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)

+            {

+               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>

+             PNG_COST_SHIFT;

+

+         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>

+             PNG_COST_SHIFT;

+

+         if (lmhi > PNG_HIMASK)

+            lmins = PNG_MAXSUM;

+

+         else

+            lmins = (lmhi << PNG_HISHIFT) + lmlo;

+      }

+#endif

+

+      for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;

+           i++, rp++, dp++)

+      {

+         v = *dp = *rp;

+

+         sum += (v < 128) ? v : 256 - v;

+      }

+

+      for (lp = row_buf + 1; i < row_bytes;

+         i++, rp++, lp++, dp++)

+      {

+         v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);

+

+         sum += (v < 128) ? v : 256 - v;

+

+         if (sum > lmins)  /* We are already worse, don't continue. */

+            break;

+      }

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         int j;

+         png_uint_32 sumhi, sumlo;

+         sumlo = sum & PNG_LOMASK;

+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

+

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)

+            {

+               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>

+             PNG_COST_SHIFT;

+

+         sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>

+             PNG_COST_SHIFT;

+

+         if (sumhi > PNG_HIMASK)

+            sum = PNG_MAXSUM;

+

+         else

+            sum = (sumhi << PNG_HISHIFT) + sumlo;

+      }

+#endif

+

+      if (sum < mins)

+      {

+         mins = sum;

+         best_row = png_ptr->sub_row;

+      }

+   }

+

+   /* Up filter */

+   if (filter_to_do == PNG_FILTER_UP)

+   {

+      png_bytep rp, dp, pp;

+      png_size_t i;

+

+      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,

+          pp = prev_row + 1; i < row_bytes;

+          i++, rp++, pp++, dp++)

+      {

+         *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);

+      }

+

+      best_row = png_ptr->up_row;

+   }

+

+   else if (filter_to_do & PNG_FILTER_UP)

+   {

+      png_bytep rp, dp, pp;

+      png_uint_32 sum = 0, lmins = mins;

+      png_size_t i;

+      int v;

+

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         int j;

+         png_uint_32 lmhi, lmlo;

+         lmlo = lmins & PNG_LOMASK;

+         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

+

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)

+            {

+               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>

+             PNG_COST_SHIFT;

+

+         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>

+             PNG_COST_SHIFT;

+

+         if (lmhi > PNG_HIMASK)

+            lmins = PNG_MAXSUM;

+

+         else

+            lmins = (lmhi << PNG_HISHIFT) + lmlo;

+      }

+#endif

+

+      for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,

+          pp = prev_row + 1; i < row_bytes; i++)

+      {

+         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);

+

+         sum += (v < 128) ? v : 256 - v;

+

+         if (sum > lmins)  /* We are already worse, don't continue. */

+            break;

+      }

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         int j;

+         png_uint_32 sumhi, sumlo;

+         sumlo = sum & PNG_LOMASK;

+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

+

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)

+            {

+               sumlo = (sumlo * png_ptr->filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               sumhi = (sumhi * png_ptr->filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>

+             PNG_COST_SHIFT;

+

+         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>

+             PNG_COST_SHIFT;

+

+         if (sumhi > PNG_HIMASK)

+            sum = PNG_MAXSUM;

+

+         else

+            sum = (sumhi << PNG_HISHIFT) + sumlo;

+      }

+#endif

+

+      if (sum < mins)

+      {

+         mins = sum;

+         best_row = png_ptr->up_row;

+      }

+   }

+

+   /* Avg filter */

+   if (filter_to_do == PNG_FILTER_AVG)

+   {

+      png_bytep rp, dp, pp, lp;

+      png_uint_32 i;

+

+      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,

+           pp = prev_row + 1; i < bpp; i++)

+      {

+         *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);

+      }

+

+      for (lp = row_buf + 1; i < row_bytes; i++)

+      {

+         *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))

+                 & 0xff);

+      }

+      best_row = png_ptr->avg_row;

+   }

+

+   else if (filter_to_do & PNG_FILTER_AVG)

+   {

+      png_bytep rp, dp, pp, lp;

+      png_uint_32 sum = 0, lmins = mins;

+      png_size_t i;

+      int v;

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         int j;

+         png_uint_32 lmhi, lmlo;

+         lmlo = lmins & PNG_LOMASK;

+         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

+

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)

+            {

+               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>

+             PNG_COST_SHIFT;

+

+         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>

+             PNG_COST_SHIFT;

+

+         if (lmhi > PNG_HIMASK)

+            lmins = PNG_MAXSUM;

+

+         else

+            lmins = (lmhi << PNG_HISHIFT) + lmlo;

+      }

+#endif

+

+      for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,

+           pp = prev_row + 1; i < bpp; i++)

+      {

+         v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);

+

+         sum += (v < 128) ? v : 256 - v;

+      }

+

+      for (lp = row_buf + 1; i < row_bytes; i++)

+      {

+         v = *dp++ =

+             (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);

+

+         sum += (v < 128) ? v : 256 - v;

+

+         if (sum > lmins)  /* We are already worse, don't continue. */

+            break;

+      }

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         int j;

+         png_uint_32 sumhi, sumlo;

+         sumlo = sum & PNG_LOMASK;

+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

+

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)

+            {

+               sumlo = (sumlo * png_ptr->filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               sumhi = (sumhi * png_ptr->filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>

+             PNG_COST_SHIFT;

+

+         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>

+             PNG_COST_SHIFT;

+

+         if (sumhi > PNG_HIMASK)

+            sum = PNG_MAXSUM;

+

+         else

+            sum = (sumhi << PNG_HISHIFT) + sumlo;

+      }

+#endif

+

+      if (sum < mins)

+      {

+         mins = sum;

+         best_row = png_ptr->avg_row;

+      }

+   }

+

+   /* Paeth filter */

+   if (filter_to_do == PNG_FILTER_PAETH)

+   {

+      png_bytep rp, dp, pp, cp, lp;

+      png_size_t i;

+

+      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,

+          pp = prev_row + 1; i < bpp; i++)

+      {

+         *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);

+      }

+

+      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)

+      {

+         int a, b, c, pa, pb, pc, p;

+

+         b = *pp++;

+         c = *cp++;

+         a = *lp++;

+

+         p = b - c;

+         pc = a - c;

+

+#ifdef PNG_USE_ABS

+         pa = abs(p);

+         pb = abs(pc);

+         pc = abs(p + pc);

+#else

+         pa = p < 0 ? -p : p;

+         pb = pc < 0 ? -pc : pc;

+         pc = (p + pc) < 0 ? -(p + pc) : p + pc;

+#endif

+

+         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;

+

+         *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);

+      }

+      best_row = png_ptr->paeth_row;

+   }

+

+   else if (filter_to_do & PNG_FILTER_PAETH)

+   {

+      png_bytep rp, dp, pp, cp, lp;

+      png_uint_32 sum = 0, lmins = mins;

+      png_size_t i;

+      int v;

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         int j;

+         png_uint_32 lmhi, lmlo;

+         lmlo = lmins & PNG_LOMASK;

+         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;

+

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)

+            {

+               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>

+             PNG_COST_SHIFT;

+

+         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>

+             PNG_COST_SHIFT;

+

+         if (lmhi > PNG_HIMASK)

+            lmins = PNG_MAXSUM;

+

+         else

+            lmins = (lmhi << PNG_HISHIFT) + lmlo;

+      }

+#endif

+

+      for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,

+          pp = prev_row + 1; i < bpp; i++)

+      {

+         v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);

+

+         sum += (v < 128) ? v : 256 - v;

+      }

+

+      for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)

+      {

+         int a, b, c, pa, pb, pc, p;

+

+         b = *pp++;

+         c = *cp++;

+         a = *lp++;

+

+#ifndef PNG_SLOW_PAETH

+         p = b - c;

+         pc = a - c;

+#ifdef PNG_USE_ABS

+         pa = abs(p);

+         pb = abs(pc);

+         pc = abs(p + pc);

+#else

+         pa = p < 0 ? -p : p;

+         pb = pc < 0 ? -pc : pc;

+         pc = (p + pc) < 0 ? -(p + pc) : p + pc;

+#endif

+         p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;

+#else /* PNG_SLOW_PAETH */

+         p = a + b - c;

+         pa = abs(p - a);

+         pb = abs(p - b);

+         pc = abs(p - c);

+

+         if (pa <= pb && pa <= pc)

+            p = a;

+

+         else if (pb <= pc)

+            p = b;

+

+         else

+            p = c;

+#endif /* PNG_SLOW_PAETH */

+

+         v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);

+

+         sum += (v < 128) ? v : 256 - v;

+

+         if (sum > lmins)  /* We are already worse, don't continue. */

+            break;

+      }

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)

+      {

+         int j;

+         png_uint_32 sumhi, sumlo;

+         sumlo = sum & PNG_LOMASK;

+         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;

+

+         for (j = 0; j < num_p_filters; j++)

+         {

+            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)

+            {

+               sumlo = (sumlo * png_ptr->filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+

+               sumhi = (sumhi * png_ptr->filter_weights[j]) >>

+                   PNG_WEIGHT_SHIFT;

+            }

+         }

+

+         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>

+             PNG_COST_SHIFT;

+

+         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>

+             PNG_COST_SHIFT;

+

+         if (sumhi > PNG_HIMASK)

+            sum = PNG_MAXSUM;

+

+         else

+            sum = (sumhi << PNG_HISHIFT) + sumlo;

+      }

+#endif

+

+      if (sum < mins)

+      {

+         best_row = png_ptr->paeth_row;

+      }

+   }

+#endif /* PNG_WRITE_FILTER_SUPPORTED */

+

+   /* Do the actual writing of the filtered row data from the chosen filter. */

+   png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);

+

+#ifdef PNG_WRITE_FILTER_SUPPORTED

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+   /* Save the type of filter we picked this time for future calculations */

+   if (png_ptr->num_prev_filters > 0)

+   {

+      int j;

+

+      for (j = 1; j < num_p_filters; j++)

+      {

+         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];

+      }

+

+      png_ptr->prev_filters[j] = best_row[0];

+   }

+#endif

+#endif /* PNG_WRITE_FILTER_SUPPORTED */

+}

+

+

+/* Do the actual writing of a previously filtered row. */

+static void

+png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,

+   png_size_t full_row_length/*includes filter byte*/)

+{

+   png_debug(1, "in png_write_filtered_row");

+

+   png_debug1(2, "filter = %d", filtered_row[0]);

+

+   png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH);

+

+   /* Swap the current and previous rows */

+   if (png_ptr->prev_row != NULL)

+   {

+      png_bytep tptr;

+

+      tptr = png_ptr->prev_row;

+      png_ptr->prev_row = png_ptr->row_buf;

+      png_ptr->row_buf = tptr;

+   }

+

+   /* Finish row - updates counters and flushes zlib if last row */

+   png_write_finish_row(png_ptr);

+

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+   png_ptr->flush_rows++;

+

+   if (png_ptr->flush_dist > 0 &&

+       png_ptr->flush_rows >= png_ptr->flush_dist)

+   {

+      png_write_flush(png_ptr);

+   }

+#endif

+}

+#endif /* PNG_WRITE_SUPPORTED */

+#endif//_FPDFAPI_MINI_

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/png.h b/core/src/fxcodec/fx_lpng/lpng_v163/png.h
new file mode 100644
index 0000000..c3fb52d
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/png.h
@@ -0,0 +1,3563 @@
+
+/* png.h - header file for PNG reference library
+ *
+ * libpng version 1.6.3 - July 18, 2013
+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This code is released under the libpng license (See LICENSE, below)
+ *
+ * Authors and maintainers:
+ *   libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
+ *   libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
+ *   libpng versions 0.97, January 1998, through 1.6.3 - July 18, 2013: Glenn
+ *   See also "Contributing Authors", below.
+ *
+ * Note about libpng version numbers:
+ *
+ *   Due to various miscommunications, unforeseen code incompatibilities
+ *   and occasional factors outside the authors' control, version numbering
+ *   on the library has not always been consistent and straightforward.
+ *   The following table summarizes matters since version 0.89c, which was
+ *   the first widely used release:
+ *
+ *    source                 png.h  png.h  shared-lib
+ *    version                string   int  version
+ *    -------                ------ -----  ----------
+ *    0.89c "1.0 beta 3"     0.89      89  1.0.89
+ *    0.90  "1.0 beta 4"     0.90      90  0.90  [should have been 2.0.90]
+ *    0.95  "1.0 beta 5"     0.95      95  0.95  [should have been 2.0.95]
+ *    0.96  "1.0 beta 6"     0.96      96  0.96  [should have been 2.0.96]
+ *    0.97b "1.00.97 beta 7" 1.00.97   97  1.0.1 [should have been 2.0.97]
+ *    0.97c                  0.97      97  2.0.97
+ *    0.98                   0.98      98  2.0.98
+ *    0.99                   0.99      98  2.0.99
+ *    0.99a-m                0.99      99  2.0.99
+ *    1.00                   1.00     100  2.1.0 [100 should be 10000]
+ *    1.0.0      (from here on, the   100  2.1.0 [100 should be 10000]
+ *    1.0.1       png.h string is   10001  2.1.0
+ *    1.0.1a-e    identical to the  10002  from here on, the shared library
+ *    1.0.2       source version)   10002  is 2.V where V is the source code
+ *    1.0.2a-b                      10003  version, except as noted.
+ *    1.0.3                         10003
+ *    1.0.3a-d                      10004
+ *    1.0.4                         10004
+ *    1.0.4a-f                      10005
+ *    1.0.5 (+ 2 patches)           10005
+ *    1.0.5a-d                      10006
+ *    1.0.5e-r                      10100 (not source compatible)
+ *    1.0.5s-v                      10006 (not binary compatible)
+ *    1.0.6 (+ 3 patches)           10006 (still binary incompatible)
+ *    1.0.6d-f                      10007 (still binary incompatible)
+ *    1.0.6g                        10007
+ *    1.0.6h                        10007  10.6h (testing xy.z so-numbering)
+ *    1.0.6i                        10007  10.6i
+ *    1.0.6j                        10007  2.1.0.6j (incompatible with 1.0.0)
+ *    1.0.7beta11-14        DLLNUM  10007  2.1.0.7beta11-14 (binary compatible)
+ *    1.0.7beta15-18           1    10007  2.1.0.7beta15-18 (binary compatible)
+ *    1.0.7rc1-2               1    10007  2.1.0.7rc1-2 (binary compatible)
+ *    1.0.7                    1    10007  (still compatible)
+ *    1.0.8beta1-4             1    10008  2.1.0.8beta1-4
+ *    1.0.8rc1                 1    10008  2.1.0.8rc1
+ *    1.0.8                    1    10008  2.1.0.8
+ *    1.0.9beta1-6             1    10009  2.1.0.9beta1-6
+ *    1.0.9rc1                 1    10009  2.1.0.9rc1
+ *    1.0.9beta7-10            1    10009  2.1.0.9beta7-10
+ *    1.0.9rc2                 1    10009  2.1.0.9rc2
+ *    1.0.9                    1    10009  2.1.0.9
+ *    1.0.10beta1              1    10010  2.1.0.10beta1
+ *    1.0.10rc1                1    10010  2.1.0.10rc1
+ *    1.0.10                   1    10010  2.1.0.10
+ *    1.0.11beta1-3            1    10011  2.1.0.11beta1-3
+ *    1.0.11rc1                1    10011  2.1.0.11rc1
+ *    1.0.11                   1    10011  2.1.0.11
+ *    1.0.12beta1-2            2    10012  2.1.0.12beta1-2
+ *    1.0.12rc1                2    10012  2.1.0.12rc1
+ *    1.0.12                   2    10012  2.1.0.12
+ *    1.1.0a-f                 -    10100  2.1.1.0a-f (branch abandoned)
+ *    1.2.0beta1-2             2    10200  2.1.2.0beta1-2
+ *    1.2.0beta3-5             3    10200  3.1.2.0beta3-5
+ *    1.2.0rc1                 3    10200  3.1.2.0rc1
+ *    1.2.0                    3    10200  3.1.2.0
+ *    1.2.1beta1-4             3    10201  3.1.2.1beta1-4
+ *    1.2.1rc1-2               3    10201  3.1.2.1rc1-2
+ *    1.2.1                    3    10201  3.1.2.1
+ *    1.2.2beta1-6            12    10202  12.so.0.1.2.2beta1-6
+ *    1.0.13beta1             10    10013  10.so.0.1.0.13beta1
+ *    1.0.13rc1               10    10013  10.so.0.1.0.13rc1
+ *    1.2.2rc1                12    10202  12.so.0.1.2.2rc1
+ *    1.0.13                  10    10013  10.so.0.1.0.13
+ *    1.2.2                   12    10202  12.so.0.1.2.2
+ *    1.2.3rc1-6              12    10203  12.so.0.1.2.3rc1-6
+ *    1.2.3                   12    10203  12.so.0.1.2.3
+ *    1.2.4beta1-3            13    10204  12.so.0.1.2.4beta1-3
+ *    1.0.14rc1               13    10014  10.so.0.1.0.14rc1
+ *    1.2.4rc1                13    10204  12.so.0.1.2.4rc1
+ *    1.0.14                  10    10014  10.so.0.1.0.14
+ *    1.2.4                   13    10204  12.so.0.1.2.4
+ *    1.2.5beta1-2            13    10205  12.so.0.1.2.5beta1-2
+ *    1.0.15rc1-3             10    10015  10.so.0.1.0.15rc1-3
+ *    1.2.5rc1-3              13    10205  12.so.0.1.2.5rc1-3
+ *    1.0.15                  10    10015  10.so.0.1.0.15
+ *    1.2.5                   13    10205  12.so.0.1.2.5
+ *    1.2.6beta1-4            13    10206  12.so.0.1.2.6beta1-4
+ *    1.0.16                  10    10016  10.so.0.1.0.16
+ *    1.2.6                   13    10206  12.so.0.1.2.6
+ *    1.2.7beta1-2            13    10207  12.so.0.1.2.7beta1-2
+ *    1.0.17rc1               10    10017  12.so.0.1.0.17rc1
+ *    1.2.7rc1                13    10207  12.so.0.1.2.7rc1
+ *    1.0.17                  10    10017  12.so.0.1.0.17
+ *    1.2.7                   13    10207  12.so.0.1.2.7
+ *    1.2.8beta1-5            13    10208  12.so.0.1.2.8beta1-5
+ *    1.0.18rc1-5             10    10018  12.so.0.1.0.18rc1-5
+ *    1.2.8rc1-5              13    10208  12.so.0.1.2.8rc1-5
+ *    1.0.18                  10    10018  12.so.0.1.0.18
+ *    1.2.8                   13    10208  12.so.0.1.2.8
+ *    1.2.9beta1-3            13    10209  12.so.0.1.2.9beta1-3
+ *    1.2.9beta4-11           13    10209  12.so.0.9[.0]
+ *    1.2.9rc1                13    10209  12.so.0.9[.0]
+ *    1.2.9                   13    10209  12.so.0.9[.0]
+ *    1.2.10beta1-7           13    10210  12.so.0.10[.0]
+ *    1.2.10rc1-2             13    10210  12.so.0.10[.0]
+ *    1.2.10                  13    10210  12.so.0.10[.0]
+ *    1.4.0beta1-5            14    10400  14.so.0.0[.0]
+ *    1.2.11beta1-4           13    10211  12.so.0.11[.0]
+ *    1.4.0beta7-8            14    10400  14.so.0.0[.0]
+ *    1.2.11                  13    10211  12.so.0.11[.0]
+ *    1.2.12                  13    10212  12.so.0.12[.0]
+ *    1.4.0beta9-14           14    10400  14.so.0.0[.0]
+ *    1.2.13                  13    10213  12.so.0.13[.0]
+ *    1.4.0beta15-36          14    10400  14.so.0.0[.0]
+ *    1.4.0beta37-87          14    10400  14.so.14.0[.0]
+ *    1.4.0rc01               14    10400  14.so.14.0[.0]
+ *    1.4.0beta88-109         14    10400  14.so.14.0[.0]
+ *    1.4.0rc02-08            14    10400  14.so.14.0[.0]
+ *    1.4.0                   14    10400  14.so.14.0[.0]
+ *    1.4.1beta01-03          14    10401  14.so.14.1[.0]
+ *    1.4.1rc01               14    10401  14.so.14.1[.0]
+ *    1.4.1beta04-12          14    10401  14.so.14.1[.0]
+ *    1.4.1                   14    10401  14.so.14.1[.0]
+ *    1.4.2                   14    10402  14.so.14.2[.0]
+ *    1.4.3                   14    10403  14.so.14.3[.0]
+ *    1.4.4                   14    10404  14.so.14.4[.0]
+ *    1.5.0beta01-58          15    10500  15.so.15.0[.0]
+ *    1.5.0rc01-07            15    10500  15.so.15.0[.0]
+ *    1.5.0                   15    10500  15.so.15.0[.0]
+ *    1.5.1beta01-11          15    10501  15.so.15.1[.0]
+ *    1.5.1rc01-02            15    10501  15.so.15.1[.0]
+ *    1.5.1                   15    10501  15.so.15.1[.0]
+ *    1.5.2beta01-03          15    10502  15.so.15.2[.0]
+ *    1.5.2rc01-03            15    10502  15.so.15.2[.0]
+ *    1.5.2                   15    10502  15.so.15.2[.0]
+ *    1.5.3beta01-10          15    10503  15.so.15.3[.0]
+ *    1.5.3rc01-02            15    10503  15.so.15.3[.0]
+ *    1.5.3beta11             15    10503  15.so.15.3[.0]
+ *    1.5.3 [omitted]
+ *    1.5.4beta01-08          15    10504  15.so.15.4[.0]
+ *    1.5.4rc01               15    10504  15.so.15.4[.0]
+ *    1.5.4                   15    10504  15.so.15.4[.0]
+ *    1.5.5beta01-08          15    10505  15.so.15.5[.0]
+ *    1.5.5rc01               15    10505  15.so.15.5[.0]
+ *    1.5.5                   15    10505  15.so.15.5[.0]
+ *    1.5.6beta01-07          15    10506  15.so.15.6[.0]
+ *    1.5.6rc01-03            15    10506  15.so.15.6[.0]
+ *    1.5.6                   15    10506  15.so.15.6[.0]
+ *    1.5.7beta01-05          15    10507  15.so.15.7[.0]
+ *    1.5.7rc01-03            15    10507  15.so.15.7[.0]
+ *    1.5.7                   15    10507  15.so.15.7[.0]
+ *    1.6.0beta01-40          16    10600  16.so.16.0[.0]
+ *    1.6.0rc01-08            16    10600  16.so.16.0[.0]
+ *    1.6.0                   16    10600  16.so.16.0[.0]
+ *    1.6.1beta01-09          16    10601  16.so.16.1[.0]
+ *    1.6.1rc01               16    10601  16.so.16.1[.0]
+ *    1.6.1                   16    10601  16.so.16.1[.0]
+ *    1.6.2beta01             16    10602  16.so.16.2[.0]
+ *    1.6.2rc01-06            16    10602  16.so.16.2[.0]
+ *    1.6.2                   16    10602  16.so.16.2[.0]
+ *    1.6.3beta01-11          16    10603  16.so.16.3[.0]
+ *    1.6.3rc01               16    10603  16.so.16.3[.0]
+ *    1.6.3                   16    10603  16.so.16.3[.0]
+ *
+ *   Henceforth the source version will match the shared-library major
+ *   and minor numbers; the shared-library major version number will be
+ *   used for changes in backward compatibility, as it is intended.  The
+ *   PNG_LIBPNG_VER macro, which is not used within libpng but is available
+ *   for applications, is an unsigned integer of the form xyyzz corresponding
+ *   to the source version x.y.z (leading zeros in y and z).  Beta versions
+ *   were given the previous public release number plus a letter, until
+ *   version 1.0.6j; from then on they were given the upcoming public
+ *   release number plus "betaNN" or "rcNN".
+ *
+ *   Binary incompatibility exists only when applications make direct access
+ *   to the info_ptr or png_ptr members through png.h, and the compiled
+ *   application is loaded with a different version of the library.
+ *
+ *   DLLNUM will change each time there are forward or backward changes
+ *   in binary compatibility (e.g., when a new feature is added).
+ *
+ * See libpng-manual.txt or libpng.3 for more information.  The PNG
+ * specification is available as a W3C Recommendation and as an ISO
+ * Specification, <http://www.w3.org/TR/2003/REC-PNG-20031110/
+ */
+
+/*
+ * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+ *
+ * If you modify libpng you may insert additional notices immediately following
+ * this sentence.
+ *
+ * This code is released under the libpng license.
+ *
+ * libpng versions 1.2.6, August 15, 2004, through 1.6.3, July 18, 2013, are
+ * Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-1.2.5
+ * with the following individual added to the list of Contributing Authors:
+ *
+ *    Cosmin Truta
+ *
+ * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are
+ * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-1.0.6
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ *    Simon-Pierre Cadieux
+ *    Eric S. Raymond
+ *    Gilles Vollant
+ *
+ * and with the following additions to the disclaimer:
+ *
+ *    There is no warranty against interference with your enjoyment of the
+ *    library or against infringement.  There is no warranty that our
+ *    efforts or the library will fulfill any of your particular purposes
+ *    or needs.  This library is provided with all faults, and the entire
+ *    risk of satisfactory quality, performance, accuracy, and effort is with
+ *    the user.
+ *
+ * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+ * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-0.96,
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ *    Tom Lane
+ *    Glenn Randers-Pehrson
+ *    Willem van Schaik
+ *
+ * libpng versions 0.89, June 1996, through 0.96, May 1997, are
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Distributed according to the same disclaimer and license as libpng-0.88,
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ *    John Bowler
+ *    Kevin Bracey
+ *    Sam Bushell
+ *    Magnus Holmgren
+ *    Greg Roelofs
+ *    Tom Tanner
+ *
+ * libpng versions 0.5, May 1995, through 0.88, January 1996, are
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ *
+ * For the purposes of this copyright and license, "Contributing Authors"
+ * is defined as the following set of individuals:
+ *
+ *    Andreas Dilger
+ *    Dave Martindale
+ *    Guy Eric Schalnat
+ *    Paul Schmidt
+ *    Tim Wegner
+ *
+ * The PNG Reference Library is supplied "AS IS".  The Contributing Authors
+ * and Group 42, Inc. disclaim all warranties, expressed or implied,
+ * including, without limitation, the warranties of merchantability and of
+ * fitness for any purpose.  The Contributing Authors and Group 42, Inc.
+ * assume no liability for direct, indirect, incidental, special, exemplary,
+ * or consequential damages, which may result from the use of the PNG
+ * Reference Library, even if advised of the possibility of such damage.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * source code, or portions hereof, for any purpose, without fee, subject
+ * to the following restrictions:
+ *
+ *   1. The origin of this source code must not be misrepresented.
+ *
+ *   2. Altered versions must be plainly marked as such and must not
+ *      be misrepresented as being the original source.
+ *
+ *   3. This Copyright notice may not be removed or altered from
+ *      any source or altered source distribution.
+ *
+ * The Contributing Authors and Group 42, Inc. specifically permit, without
+ * fee, and encourage the use of this source code as a component to
+ * supporting the PNG file format in commercial products.  If you use this
+ * source code in a product, acknowledgment is not required but would be
+ * appreciated.
+ */
+
+/*
+ * A "png_get_copyright" function is available, for convenient use in "about"
+ * boxes and the like:
+ *
+ *     printf("%s", png_get_copyright(NULL));
+ *
+ * Also, the PNG logo (in PNG format, of course) is supplied in the
+ * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
+ */
+
+/*
+ * Libpng is OSI Certified Open Source Software.  OSI Certified is a
+ * certification mark of the Open Source Initiative.
+ */
+
+/*
+ * The contributing authors would like to thank all those who helped
+ * with testing, bug fixes, and patience.  This wouldn't have been
+ * possible without all of you.
+ *
+ * Thanks to Frank J. T. Wojcik for helping with the documentation.
+ */
+
+/*
+ * Y2K compliance in libpng:
+ * =========================
+ *
+ *    July 18, 2013
+ *
+ *    Since the PNG Development group is an ad-hoc body, we can't make
+ *    an official declaration.
+ *
+ *    This is your unofficial assurance that libpng from version 0.71 and
+ *    upward through 1.6.3 are Y2K compliant.  It is my belief that
+ *    earlier versions were also Y2K compliant.
+ *
+ *    Libpng only has two year fields.  One is a 2-byte unsigned integer
+ *    that will hold years up to 65535.  The other, which is deprecated,
+ *    holds the date in text format, and will hold years up to 9999.
+ *
+ *    The integer is
+ *        "png_uint_16 year" in png_time_struct.
+ *
+ *    The string is
+ *        "char time_buffer[29]" in png_struct.  This is no longer used
+ *    in libpng-1.6.x and will be removed from libpng-1.7.0.
+ *
+ *    There are seven time-related functions:
+ *        png.c: png_convert_to_rfc_1123_buffer() in png.c
+ *          (formerly png_convert_to_rfc_1123() prior to libpng-1.5.x and
+ *          png_convert_to_rfc_1152() in error prior to libpng-0.98)
+ *        png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ *        png_convert_from_time_t() in pngwrite.c
+ *        png_get_tIME() in pngget.c
+ *        png_handle_tIME() in pngrutil.c, called in pngread.c
+ *        png_set_tIME() in pngset.c
+ *        png_write_tIME() in pngwutil.c, called in pngwrite.c
+ *
+ *    All handle dates properly in a Y2K environment.  The
+ *    png_convert_from_time_t() function calls gmtime() to convert from system
+ *    clock time, which returns (year - 1900), which we properly convert to
+ *    the full 4-digit year.  There is a possibility that libpng applications
+ *    are not passing 4-digit years into the png_convert_to_rfc_1123_buffer()
+ *    function, or that they are incorrectly passing only a 2-digit year
+ *    instead of "year - 1900" into the png_convert_from_struct_tm() function,
+ *    but this is not under our control.  The libpng documentation has always
+ *    stated that it works with 4-digit years, and the APIs have been
+ *    documented as such.
+ *
+ *    The tIME chunk itself is also Y2K compliant.  It uses a 2-byte unsigned
+ *    integer to hold the year, and can hold years as large as 65535.
+ *
+ *    zlib, upon which libpng depends, is also Y2K compliant.  It contains
+ *    no date-related code.
+ *
+ *       Glenn Randers-Pehrson
+ *       libpng maintainer
+ *       PNG Development Group
+ */
+
+#ifndef PNG_H
+#define PNG_H
+
+/* This is not the place to learn how to use libpng. The file libpng-manual.txt
+ * describes how to use libpng, and the file example.c summarizes it
+ * with some code on which to build.  This file is useful for looking
+ * at the actual function definitions and structure components.
+ *
+ * If you just need to read a PNG file and don't want to read the documentation
+ * skip to the end of this file and read the section entitled 'simplified API'.
+ */
+
+/* Sunliang.liu add 20100319 for avoid name conflict. */
+#define png_set_sig_bytes FOXIT_png_set_sig_bytes
+#define png_sig_cmp FOXIT_png_sig_cmp
+#define png_create_info_struct FOXIT_png_create_info_struct
+#define png_destroy_info_struct FOXIT_png_destroy_info_struct
+#define png_info_init_3 FOXIT_png_info_init_3
+#define png_data_freer FOXIT_png_data_freer
+#define png_free_data FOXIT_png_free_data
+#define png_info_destroy FOXIT_png_info_destroy
+#define png_get_io_ptr FOXIT_png_get_io_ptr
+#define png_init_io FOXIT_png_init_io
+#define png_convert_to_rfc1123 FOXIT_png_convert_to_rfc1123
+#define png_get_copyright FOXIT_png_get_copyright
+#define png_get_libpng_ver FOXIT_png_get_libpng_ver
+#define png_get_header_ver FOXIT_png_get_header_ver
+#define png_get_header_version FOXIT_png_get_header_version
+#define png_handle_as_unknown FOXIT_png_handle_as_unknown
+#define png_reset_zstream FOXIT_png_reset_zstream
+#define png_access_version_number FOXIT_png_access_version_number
+#define png_mmx_support FOXIT_png_mmx_support
+#define png_create_read_struct FOXIT_png_create_read_struct
+#define png_create_read_struct_2 FOXIT_png_create_read_struct_2
+#define png_create_write_struct FOXIT_png_create_write_struct
+#define png_create_write_struct_2 FOXIT_png_create_write_struct_2
+#define png_get_compression_buffer_size FOXIT_png_get_compression_buffer_size
+#define png_set_compression_buffer_size FOXIT_png_set_compression_buffer_size
+#define png_set_longjmp_fn FOXIT_png_set_longjmp_fn
+#define png_longjmp FOXIT_png_longjmp
+#define png_write_sig FOXIT_png_write_sig
+#define png_write_chunk FOXIT_png_write_chunk
+#define png_write_chunk_start FOXIT_png_write_chunk_start
+#define png_write_chunk_data FOXIT_png_write_chunk_data
+#define png_write_chunk_end FOXIT_png_write_chunk_end
+#define png_write_info_before_PLTE FOXIT_png_write_info_before_PLTE
+#define png_write_info FOXIT_png_write_info
+#define png_read_info FOXIT_png_read_info
+#define png_convert_to_rfc1123_buffer FOXIT_png_convert_to_rfc1123_buffer
+#define png_convert_from_struct_tm FOXIT_png_convert_from_struct_tm
+#define png_convert_from_time_t FOXIT_png_convert_from_time_t
+#define png_set_expand FOXIT_png_set_expand
+#define png_set_expand_gray_1_2_4_to_8 FOXIT_png_set_expand_gray_1_2_4_to_8
+#define png_set_palette_to_rgb FOXIT_png_set_palette_to_rgb
+#define png_set_tRNS_to_alpha FOXIT_png_set_tRNS_to_alpha
+#define png_set_expand_16 FOXIT_png_set_expand_16
+#define png_set_bgr FOXIT_png_set_bgr
+#define png_set_gray_to_rgb FOXIT_png_set_gray_to_rgb
+#define png_set_rgb_to_gray FOXIT_png_set_rgb_to_gray
+#define png_set_rgb_to_gray_fixed FOXIT_png_set_rgb_to_gray_fixed
+#define png_get_rgb_to_gray_status FOXIT_png_get_rgb_to_gray_status
+#define png_build_grayscale_palette FOXIT_png_build_grayscale_palette
+#define png_set_alpha_mode FOXIT_png_set_alpha_mode
+#define png_set_alpha_mode_fixed FOXIT_png_set_alpha_mode_fixed
+#define png_set_strip_alpha FOXIT_png_set_strip_alpha
+#define png_set_swap_alpha FOXIT_png_set_swap_alpha
+#define png_set_invert_alpha FOXIT_png_set_invert_alpha
+#define png_set_filler FOXIT_png_set_filler
+#define png_set_add_alpha FOXIT_png_set_add_alpha
+#define png_set_swap FOXIT_png_set_swap
+#define png_set_packing FOXIT_png_set_packing
+#define png_set_packswap FOXIT_png_set_packswap
+#define png_set_shift FOXIT_png_set_shift
+#define png_set_interlace_handling FOXIT_png_set_interlace_handling
+#define png_set_invert_mono FOXIT_png_set_invert_mono
+#define png_set_background FOXIT_png_set_background
+#define png_set_background_fixed FOXIT_png_set_background_fixed
+#define png_set_scale_16 FOXIT_png_set_scale_16
+#define png_set_quantize FOXIT_png_set_quantize
+#define png_set_gamma FOXIT_png_set_gamma
+#define png_set_gamma_fixed FOXIT_png_set_gamma_fixed
+#define png_set_flush FOXIT_png_set_flush
+#define png_write_flush FOXIT_png_write_flush
+#define png_start_read_image FOXIT_png_start_read_image
+#define png_read_update_info FOXIT_png_read_update_info
+#define png_read_rows FOXIT_png_read_rows
+#define png_read_row FOXIT_png_read_row
+#define png_read_image FOXIT_png_read_image
+#define png_write_row FOXIT_png_write_row
+#define png_write_rows FOXIT_png_write_rows
+#define png_write_image FOXIT_png_write_image
+#define png_write_end FOXIT_png_write_end
+#define png_read_end FOXIT_png_read_end
+#define png_destroy_read_struct FOXIT_png_destroy_read_struct
+#define png_destroy_write_struct FOXIT_png_destroy_write_struct
+#define png_set_crc_action FOXIT_png_set_crc_action
+#define png_set_filter FOXIT_png_set_filter
+#define png_set_filter_heuristics FOXIT_png_set_filter_heuristics
+#define png_set_filter_heuristics_fixed FOXIT_png_set_filter_heuristics_fixed
+#define png_set_compression_level FOXIT_png_set_compression_level
+#define png_set_compression_mem_level FOXIT_png_set_compression_mem_level
+#define png_set_compression_strategy FOXIT_png_set_compression_strategy
+#define png_set_compression_window_bits FOXIT_png_set_compression_window_bits
+#define png_set_compression_method FOXIT_png_set_compression_method
+#define png_set_text_compression_level FOXIT_png_set_text_compression_level
+#define png_set_text_compression_mem_level FOXIT_png_set_text_compression_mem_level
+#define png_set_text_compression_strategy FOXIT_png_set_text_compression_strategy
+#define png_set_text_compression_window_bits FOXIT_png_set_text_compression_window_bits
+#define png_set_text_compression_method FOXIT_png_set_text_compression_method
+#define png_set_error_fn FOXIT_png_set_error_fn
+#define png_get_error_ptr FOXIT_png_get_error_ptr
+#define png_set_write_fn FOXIT_png_set_write_fn
+#define png_set_read_fn FOXIT_png_set_read_fn
+#define png_set_read_status_fn FOXIT_png_set_read_status_fn
+#define png_set_write_status_fn FOXIT_png_set_write_status_fn
+#define png_set_read_user_transform_fn FOXIT_png_set_read_user_transform_fn
+#define png_set_write_user_transform_fn FOXIT_png_set_write_user_transform_fn
+#define png_set_user_transform_info FOXIT_png_set_user_transform_info
+#define png_get_user_transform_ptr FOXIT_png_get_user_transform_ptr
+#define png_get_current_row_number FOXIT_png_get_current_row_number
+#define png_get_current_pass_number FOXIT_png_get_current_pass_number
+#define png_set_read_user_chunk_fn FOXIT_png_set_read_user_chunk_fn
+#define png_get_user_chunk_ptr FOXIT_png_get_user_chunk_ptr
+#define png_set_progressive_read_fn FOXIT_png_set_progressive_read_fn
+#define png_get_progressive_ptr FOXIT_png_get_progressive_ptr
+#define png_process_data FOXIT_png_process_data
+#define png_process_data_pause FOXIT_png_process_data_pause
+#define png_process_data_skip FOXIT_png_process_data_skip
+#define png_progressive_combine_row FOXIT_png_progressive_combine_row
+#define png_calloc FOXIT_png_calloc
+#define png_error FOXIT_png_error
+#define png_chunk_error FOXIT_png_chunk_error
+#define png_err FOXIT_png_err
+#define png_warning FOXIT_png_warning
+#define png_chunk_warning FOXIT_png_chunk_warning
+#define png_benign_error FOXIT_png_benign_error
+#define png_chunk_benign_error FOXIT_png_chunk_benign_error
+#define png_set_benign_errors FOXIT_png_set_benign_errors
+#define png_get_valid FOXIT_png_get_valid
+#define png_get_rowbytes FOXIT_png_get_rowbytes
+#define png_get_rows FOXIT_png_get_rows
+#define png_set_rows FOXIT_png_set_rows
+#define png_get_channels FOXIT_png_get_channels
+#define png_get_image_width FOXIT_png_get_image_width
+#define png_get_image_height FOXIT_png_get_image_height
+#define png_get_bit_depth FOXIT_png_get_bit_depth
+#define png_get_color_type FOXIT_png_get_color_type
+#define png_get_filter_type FOXIT_png_get_filter_type
+#define png_get_interlace_type FOXIT_png_get_interlace_type
+#define png_get_compression_type FOXIT_png_get_compression_type
+#define png_get_pixels_per_meter FOXIT_png_get_pixels_per_meter
+#define png_get_x_pixels_per_meter FOXIT_png_get_x_pixels_per_meter
+#define png_get_y_pixels_per_meter FOXIT_png_get_y_pixels_per_meter
+#define png_get_pixel_aspect_ratio FOXIT_png_get_pixel_aspect_ratio
+#define png_get_pixel_aspect_ratio_fixed FOXIT_png_get_pixel_aspect_ratio_fixed
+#define png_get_x_offset_pixels FOXIT_png_get_x_offset_pixels
+#define png_get_y_offset_pixels FOXIT_png_get_y_offset_pixels
+#define png_get_x_offset_microns FOXIT_png_get_x_offset_microns
+#define png_get_y_offset_microns FOXIT_png_get_y_offset_microns
+#define png_get_signature FOXIT_png_get_signature

+#define png_get_bKGD FOXIT_png_get_bKGD

+#define png_set_bKGD FOXIT_png_set_bKGD

+#define png_get_cHRM FOXIT_png_get_cHRM

+#define png_get_cHRM_XYZ FOXIT_png_get_cHRM_XYZ

+#define png_get_cHRM_fixed FOXIT_png_get_cHRM_fixed

+#define png_get_cHRM_XYZ_fixed FOXIT_png_get_cHRM_XYZ_fixed

+#define png_set_cHRM FOXIT_png_set_cHRM

+#define png_set_cHRM_XYZ FOXIT_png_set_cHRM_XYZ

+#define png_set_cHRM_fixed FOXIT_png_set_cHRM_fixed

+#define png_set_cHRM_XYZ_fixed FOXIT_png_set_cHRM_XYZ_fixed

+#define png_get_gAMA FOXIT_png_get_gAMA

+#define png_set_gAMA FOXIT_png_set_gAMA

+#define png_set_gAMA_fixed FOXIT_png_set_gAMA_fixed

+#define png_get_hIST FOXIT_png_get_hIST

+#define png_set_hIST FOXIT_png_set_hIST

+#define png_get_IHDR FOXIT_png_get_IHDR

+#define png_set_IHDR FOXIT_png_set_IHDR

+#define png_get_oFFs FOXIT_png_get_oFFs

+#define png_set_oFFs FOXIT_png_set_oFFs

+#define png_get_pCAL FOXIT_png_get_pCAL

+#define png_set_pCAL FOXIT_png_set_pCAL

+#define png_set_pHYs FOXIT_png_set_pHYs

+#define png_get_PLTE FOXIT_png_get_PLTE

+#define png_set_PLTE FOXIT_png_set_PLTE

+#define png_get_sBIT FOXIT_png_get_sBIT

+#define png_set_sBIT FOXIT_png_set_sBIT

+#define png_get_sRGB FOXIT_png_get_sRGB

+#define png_set_sRGB FOXIT_png_set_sRGB

+#define png_set_sRGB_gAMA_and_cHRM FOXIT_png_set_sRGB_gAMA_and_cHRM

+#define png_get_iCCP FOXIT_png_get_iCCP

+#define png_set_iCCP FOXIT_png_set_iCCP

+#define png_get_sPLT FOXIT_png_get_sPLT

+#define png_set_sPLT FOXIT_png_set_sPLT

+#define png_get_text FOXIT_png_get_text

+#define png_set_text FOXIT_png_set_text

+#define png_get_tIME FOXIT_png_get_tIME

+#define png_set_tIME FOXIT_png_set_tIME

+#define png_get_tRNS FOXIT_png_get_tRNS

+#define png_set_tRNS FOXIT_png_set_tRNS

+#define png_get_sCAL FOXIT_png_get_sCAL

+#define png_get_sCAL_fixed FOXIT_png_get_sCAL_fixed

+#define png_get_sCAL_s FOXIT_png_get_sCAL_s

+#define png_set_sCAL FOXIT_png_set_sCAL

+#define png_set_sCAL_s FOXIT_png_set_sCAL_s

+#define png_set_keep_unknown_chunks FOXIT_png_set_keep_unknown_chunks

+#define png_set_unknown_chunks FOXIT_png_set_unknown_chunks

+#define png_set_unknown_chunk_location FOXIT_png_set_unknown_chunk_location

+#define png_get_unknown_chunks FOXIT_png_get_unknown_chunks

+#define png_set_invalid FOXIT_png_set_invalid

+#define png_read_png FOXIT_png_read_png

+#define png_write_png FOXIT_png_write_png

+#define png_permit_mng_features FOXIT_png_permit_mng_features

+#define png_set_strip_error_numbers FOXIT_png_set_strip_error_numbers

+#define png_set_user_limits FOXIT_png_set_user_limits

+#define png_get_user_width_max FOXIT_png_get_user_width_max

+#define png_get_user_height_max FOXIT_png_get_user_height_max

+#define png_set_chunk_cache_max FOXIT_png_set_chunk_cache_max

+#define png_get_chunk_cache_max FOXIT_png_get_chunk_cache_max

+#define png_set_chunk_malloc_max FOXIT_png_set_chunk_malloc_max

+#define png_get_chunk_malloc_max FOXIT_png_get_chunk_malloc_max

+#define png_get_pixels_per_inch FOXIT_png_get_pixels_per_inch

+#define png_get_x_pixels_per_inch FOXIT_png_get_x_pixels_per_inch

+#define png_get_y_pixels_per_inch FOXIT_png_get_y_pixels_per_inch

+#define png_get_x_offset_inches FOXIT_png_get_x_offset_inches

+#define png_get_x_offset_inches_fixed FOXIT_png_get_x_offset_inches_fixed

+#define png_get_y_offset_inches FOXIT_png_get_y_offset_inches

+#define png_get_y_offset_inches_fixed FOXIT_png_get_y_offset_inches_fixed

+#define png_get_pHYs_dpi FOXIT_png_get_pHYs_dpi

+#define png_get_io_state FOXIT_png_get_io_state

+#define png_get_io_chunk_name FOXIT_png_get_io_chunk_name

+#define png_get_io_chunk_type FOXIT_png_get_io_chunk_type

+#define png_get_uint_31 FOXIT_png_get_uint_31

+#define png_save_uint_32 FOXIT_png_save_uint_32

+#define png_save_int_32 FOXIT_png_save_int_32

+#define png_save_uint_16 FOXIT_png_save_uint_16

+#define png_image_begin_read_from_file FOXIT_png_image_begin_read_from_file

+#define png_image_begin_read_from_stdio FOXIT_png_image_begin_read_from_stdio

+#define png_image_begin_read_from_memory FOXIT_png_image_begin_read_from_memory

+#define png_image_finish_read FOXIT_png_image_finish_read

+#define png_image_free FOXIT_png_image_free

+#define png_image_write_to_file FOXIT_png_image_write_to_file

+#define png_image_write_to_stdio FOXIT_png_image_write_to_stdio

+#define png_set_check_for_invalid_index FOXIT_png_set_check_for_invalid_index

+#define png_get_palette_max FOXIT_png_get_palette_max

+#define png_set_option FOXIT_png_set_option
+
+#define png_set_strip_16 FOXIT_png_set_strip_16
+#define png_64bit_product FOXIT_png_64bit_product
+#define png_check_cHRM_fixed FOXIT_png_check_cHRM_fixed
+#define png_free FOXIT_png_free
+#define png_free_default FOXIT_png_free_default
+#define png_get_mem_ptr FOXIT_png_get_mem_ptr
+#define png_malloc FOXIT_png_malloc
+#define png_malloc_default FOXIT_png_malloc_default
+#define png_malloc_warn FOXIT_png_malloc_warn
+#define png_memcpy_check FOXIT_png_memcpy_check
+#define png_memset_check FOXIT_png_memset_check
+#define png_pass_dsp_mask FOXIT_png_pass_dsp_mask
+#define png_pass_inc FOXIT_png_pass_inc
+#define png_pass_mask FOXIT_png_pass_mask
+#define png_pass_start FOXIT_png_pass_start
+#define png_pass_yinc FOXIT_png_pass_yinc
+#define png_pass_ystart FOXIT_png_pass_ystart
+#define png_set_mem_fn FOXIT_png_set_mem_fn
+
+/* Version information for png.h - this should match the version in png.c */
+#define PNG_LIBPNG_VER_STRING "1.6.3"
+#define PNG_HEADER_VERSION_STRING \
+     " libpng version 1.6.3 - July 18, 2013\n"
+
+#define PNG_LIBPNG_VER_SONUM   16
+#define PNG_LIBPNG_VER_DLLNUM  16
+
+/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
+#define PNG_LIBPNG_VER_MAJOR   1
+#define PNG_LIBPNG_VER_MINOR   6
+#define PNG_LIBPNG_VER_RELEASE 3
+
+/* This should match the numeric part of the final component of
+ * PNG_LIBPNG_VER_STRING, omitting any leading zero:
+ */
+
+#define PNG_LIBPNG_VER_BUILD  0
+
+/* Release Status */
+#define PNG_LIBPNG_BUILD_ALPHA    1
+#define PNG_LIBPNG_BUILD_BETA     2
+#define PNG_LIBPNG_BUILD_RC       3
+#define PNG_LIBPNG_BUILD_STABLE   4
+#define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7
+
+/* Release-Specific Flags */
+#define PNG_LIBPNG_BUILD_PATCH    8 /* Can be OR'ed with
+                                       PNG_LIBPNG_BUILD_STABLE only */
+#define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with
+                                       PNG_LIBPNG_BUILD_SPECIAL */
+#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with
+                                       PNG_LIBPNG_BUILD_PRIVATE */
+
+#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE
+
+/* Careful here.  At one time, Guy wanted to use 082, but that would be octal.
+ * We must not include leading zeros.
+ * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only
+ * version 1.0.0 was mis-numbered 100 instead of 10000).  From
+ * version 1.0.1 it's    xxyyzz, where x=major, y=minor, z=release
+ */
+#define PNG_LIBPNG_VER 10603 /* 1.6.3 */
+
+/* Library configuration: these options cannot be changed after
+ * the library has been built.
+ */
+#ifndef PNGLCONF_H
+    /* If pnglibconf.h is missing, you can
+     * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h
+     */
+#   include "pnglibconf.h"
+#endif
+
+#ifndef PNG_VERSION_INFO_ONLY
+   /* Machine specific configuration. */
+#  include "pngconf.h"
+#endif
+
+/*
+ * Added at libpng-1.2.8
+ *
+ * Ref MSDN: Private as priority over Special
+ * VS_FF_PRIVATEBUILD File *was not* built using standard release
+ * procedures. If this value is given, the StringFileInfo block must
+ * contain a PrivateBuild string.
+ *
+ * VS_FF_SPECIALBUILD File *was* built by the original company using
+ * standard release procedures but is a variation of the standard
+ * file of the same version number. If this value is given, the
+ * StringFileInfo block must contain a SpecialBuild string.
+ */
+
+#ifdef PNG_USER_PRIVATEBUILD /* From pnglibconf.h */
+#  define PNG_LIBPNG_BUILD_TYPE \
+       (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE)
+#else
+#  ifdef PNG_LIBPNG_SPECIALBUILD
+#    define PNG_LIBPNG_BUILD_TYPE \
+         (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL)
+#  else
+#    define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE)
+#  endif
+#endif
+
+#ifndef PNG_VERSION_INFO_ONLY
+
+/* Inhibit C++ name-mangling for libpng functions but not for system calls. */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Version information for C files, stored in png.c.  This had better match
+ * the version above.
+ */
+#define png_libpng_ver png_get_header_ver(NULL)
+
+/* This file is arranged in several sections:
+ *
+ * 1. Any configuration options that can be specified by for the application
+ *    code when it is built.  (Build time configuration is in pnglibconf.h)
+ * 2. Type definitions (base types are defined in pngconf.h), structure
+ *    definitions.
+ * 3. Exported library functions.
+ * 4. Simplified API.
+ *
+ * The library source code has additional files (principally pngpriv.h) that
+ * allow configuration of the library.
+ */
+/* Section 1: run time configuration
+ * See pnglibconf.h for build time configuration
+ *
+ * Run time configuration allows the application to choose between
+ * implementations of certain arithmetic APIs.  The default is set
+ * at build time and recorded in pnglibconf.h, but it is safe to
+ * override these (and only these) settings.  Note that this won't
+ * change what the library does, only application code, and the
+ * settings can (and probably should) be made on a per-file basis
+ * by setting the #defines before including png.h
+ *
+ * Use macros to read integers from PNG data or use the exported
+ * functions?
+ *   PNG_USE_READ_MACROS: use the macros (see below)  Note that
+ *     the macros evaluate their argument multiple times.
+ *   PNG_NO_USE_READ_MACROS: call the relevant library function.
+ *
+ * Use the alternative algorithm for compositing alpha samples that
+ * does not use division?
+ *   PNG_READ_COMPOSITE_NODIV_SUPPORTED: use the 'no division'
+ *      algorithm.
+ *   PNG_NO_READ_COMPOSITE_NODIV: use the 'division' algorithm.
+ *
+ * How to handle benign errors if PNG_ALLOW_BENIGN_ERRORS is
+ * false?
+ *   PNG_ALLOW_BENIGN_ERRORS: map calls to the benign error
+ *      APIs to png_warning.
+ * Otherwise the calls are mapped to png_error.
+ */
+
+/* Section 2: type definitions, including structures and compile time
+ * constants.
+ * See pngconf.h for base types that vary by machine/system
+ */
+
+/* This triggers a compiler error in png.c, if png.c and png.h
+ * do not agree upon the version number.
+ */
+typedef char* png_libpng_version_1_6_3;
+
+/* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
+ *
+ * png_struct is the cache of information used while reading or writing a single
+ * PNG file.  One of these is always required, although the simplified API
+ * (below) hides the creation and destruction of it.
+ */
+typedef struct png_struct_def png_struct;
+typedef const png_struct * png_const_structp;
+typedef png_struct * png_structp;
+typedef png_struct * * png_structpp;
+
+/* png_info contains information read from or to be written to a PNG file.  One
+ * or more of these must exist while reading or creating a PNG file.  The
+ * information is not used by libpng during read but is used to control what
+ * gets written when a PNG file is created.  "png_get_" function calls read
+ * information during read and "png_set_" functions calls write information
+ * when creating a PNG.
+ * been moved into a separate header file that is not accessible to
+ * applications.  Read libpng-manual.txt or libpng.3 for more info.
+ */
+typedef struct png_info_def png_info;
+typedef png_info * png_infop;
+typedef const png_info * png_const_infop;
+typedef png_info * * png_infopp;
+
+/* Types with names ending 'p' are pointer types.  The corresponding types with
+ * names ending 'rp' are identical pointer types except that the pointer is
+ * marked 'restrict', which means that it is the only pointer to the object
+ * passed to the function.  Applications should not use the 'restrict' types;
+ * it is always valid to pass 'p' to a pointer with a function argument of the
+ * corresponding 'rp' type.  Different compilers have different rules with
+ * regard to type matching in the presence of 'restrict'.  For backward
+ * compatibility libpng callbacks never have 'restrict' in their parameters and,
+ * consequentially, writing portable application code is extremely difficult if
+ * an attempt is made to use 'restrict'.
+ */
+typedef png_struct * PNG_RESTRICT png_structrp;
+typedef const png_struct * PNG_RESTRICT png_const_structrp;
+typedef png_info * PNG_RESTRICT png_inforp;
+typedef const png_info * PNG_RESTRICT png_const_inforp;
+
+/* Three color definitions.  The order of the red, green, and blue, (and the
+ * exact size) is not important, although the size of the fields need to
+ * be png_byte or png_uint_16 (as defined below).
+ */
+typedef struct png_color_struct
+{
+   png_byte red;
+   png_byte green;
+   png_byte blue;
+} png_color;
+typedef png_color * png_colorp;
+typedef const png_color * png_const_colorp;
+typedef png_color * * png_colorpp;
+
+typedef struct png_color_16_struct
+{
+   png_byte index;    /* used for palette files */
+   png_uint_16 red;   /* for use in red green blue files */
+   png_uint_16 green;
+   png_uint_16 blue;
+   png_uint_16 gray;  /* for use in grayscale files */
+} png_color_16;
+typedef png_color_16 * png_color_16p;
+typedef const png_color_16 * png_const_color_16p;
+typedef png_color_16 * * png_color_16pp;
+
+typedef struct png_color_8_struct
+{
+   png_byte red;   /* for use in red green blue files */
+   png_byte green;
+   png_byte blue;
+   png_byte gray;  /* for use in grayscale files */
+   png_byte alpha; /* for alpha channel files */
+} png_color_8;
+typedef png_color_8 * png_color_8p;
+typedef const png_color_8 * png_const_color_8p;
+typedef png_color_8 * * png_color_8pp;
+
+/*
+ * The following two structures are used for the in-core representation
+ * of sPLT chunks.
+ */
+typedef struct png_sPLT_entry_struct
+{
+   png_uint_16 red;
+   png_uint_16 green;
+   png_uint_16 blue;
+   png_uint_16 alpha;
+   png_uint_16 frequency;
+} png_sPLT_entry;
+typedef png_sPLT_entry * png_sPLT_entryp;
+typedef const png_sPLT_entry * png_const_sPLT_entryp;
+typedef png_sPLT_entry * * png_sPLT_entrypp;
+
+/*  When the depth of the sPLT palette is 8 bits, the color and alpha samples
+ *  occupy the LSB of their respective members, and the MSB of each member
+ *  is zero-filled.  The frequency member always occupies the full 16 bits.
+ */
+
+typedef struct png_sPLT_struct
+{
+   png_charp name;           /* palette name */
+   png_byte depth;           /* depth of palette samples */
+   png_sPLT_entryp entries;  /* palette entries */
+   png_int_32 nentries;      /* number of palette entries */
+} png_sPLT_t;
+typedef png_sPLT_t * png_sPLT_tp;
+typedef const png_sPLT_t * png_const_sPLT_tp;
+typedef png_sPLT_t * * png_sPLT_tpp;
+
+#ifdef PNG_TEXT_SUPPORTED
+/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file,
+ * and whether that contents is compressed or not.  The "key" field
+ * points to a regular zero-terminated C string.  The "text" fields can be a
+ * regular C string, an empty string, or a NULL pointer.
+ * However, the structure returned by png_get_text() will always contain
+ * the "text" field as a regular zero-terminated C string (possibly
+ * empty), never a NULL pointer, so it can be safely used in printf() and
+ * other string-handling functions.  Note that the "itxt_length", "lang", and
+ * "lang_key" members of the structure only exist when the library is built
+ * with iTXt chunk support.  Prior to libpng-1.4.0 the library was built by
+ * default without iTXt support. Also note that when iTXt *is* supported,
+ * the "lang" and "lang_key" fields contain NULL pointers when the
+ * "compression" field contains * PNG_TEXT_COMPRESSION_NONE or
+ * PNG_TEXT_COMPRESSION_zTXt. Note that the "compression value" is not the
+ * same as what appears in the PNG tEXt/zTXt/iTXt chunk's "compression flag"
+ * which is always 0 or 1, or its "compression method" which is always 0.
+ */
+typedef struct png_text_struct
+{
+   int  compression;       /* compression value:
+                             -1: tEXt, none
+                              0: zTXt, deflate
+                              1: iTXt, none
+                              2: iTXt, deflate  */
+   png_charp key;          /* keyword, 1-79 character description of "text" */
+   png_charp text;         /* comment, may be an empty string (ie "")
+                              or a NULL pointer */
+   png_size_t text_length; /* length of the text string */
+   png_size_t itxt_length; /* length of the itxt string */
+   png_charp lang;         /* language code, 0-79 characters
+                              or a NULL pointer */
+   png_charp lang_key;     /* keyword translated UTF-8 string, 0 or more
+                              chars or a NULL pointer */
+} png_text;
+typedef png_text * png_textp;
+typedef const png_text * png_const_textp;
+typedef png_text * * png_textpp;
+#endif
+
+/* Supported compression types for text in PNG files (tEXt, and zTXt).
+ * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */
+#define PNG_TEXT_COMPRESSION_NONE_WR -3
+#define PNG_TEXT_COMPRESSION_zTXt_WR -2
+#define PNG_TEXT_COMPRESSION_NONE    -1
+#define PNG_TEXT_COMPRESSION_zTXt     0
+#define PNG_ITXT_COMPRESSION_NONE     1
+#define PNG_ITXT_COMPRESSION_zTXt     2
+#define PNG_TEXT_COMPRESSION_LAST     3  /* Not a valid value */
+
+/* png_time is a way to hold the time in an machine independent way.
+ * Two conversions are provided, both from time_t and struct tm.  There
+ * is no portable way to convert to either of these structures, as far
+ * as I know.  If you know of a portable way, send it to me.  As a side
+ * note - PNG has always been Year 2000 compliant!
+ */
+typedef struct png_time_struct
+{
+   png_uint_16 year; /* full year, as in, 1995 */
+   png_byte month;   /* month of year, 1 - 12 */
+   png_byte day;     /* day of month, 1 - 31 */
+   png_byte hour;    /* hour of day, 0 - 23 */
+   png_byte minute;  /* minute of hour, 0 - 59 */
+   png_byte second;  /* second of minute, 0 - 60 (for leap seconds) */
+} png_time;
+typedef png_time * png_timep;
+typedef const png_time * png_const_timep;
+typedef png_time * * png_timepp;
+
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+/* png_unknown_chunk is a structure to hold queued chunks for which there is
+ * no specific support.  The idea is that we can use this to queue
+ * up private chunks for output even though the library doesn't actually
+ * know about their semantics.
+ *
+ * The data in the structure is set by libpng on read and used on write.
+ */
+typedef struct png_unknown_chunk_t
+{
+    png_byte name[5]; /* Textual chunk name with '\0' terminator */
+    png_byte *data;   /* Data, should not be modified on read! */
+    png_size_t size;
+
+    /* On write 'location' must be set using the flag values listed below.
+     * Notice that on read it is set by libpng however the values stored have
+     * more bits set than are listed below.  Always treat the value as a
+     * bitmask.  On write set only one bit - setting multiple bits may cause the
+     * chunk to be written in multiple places.
+     */
+    png_byte location; /* mode of operation at read time */
+}
+png_unknown_chunk;
+
+typedef png_unknown_chunk * png_unknown_chunkp;
+typedef const png_unknown_chunk * png_const_unknown_chunkp;
+typedef png_unknown_chunk * * png_unknown_chunkpp;
+#endif
+
+/* Flag values for the unknown chunk location byte. */
+#define PNG_HAVE_IHDR  0x01
+#define PNG_HAVE_PLTE  0x02
+#define PNG_AFTER_IDAT 0x08
+
+/* Maximum positive integer used in PNG is (2^31)-1 */
+#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL)
+#define PNG_UINT_32_MAX ((png_uint_32)(-1))
+#define PNG_SIZE_MAX ((png_size_t)(-1))
+
+/* These are constants for fixed point values encoded in the
+ * PNG specification manner (x100000)
+ */
+#define PNG_FP_1    100000
+#define PNG_FP_HALF  50000
+#define PNG_FP_MAX  ((png_fixed_point)0x7fffffffL)
+#define PNG_FP_MIN  (-PNG_FP_MAX)
+
+/* These describe the color_type field in png_info. */
+/* color type masks */
+#define PNG_COLOR_MASK_PALETTE    1
+#define PNG_COLOR_MASK_COLOR      2
+#define PNG_COLOR_MASK_ALPHA      4
+
+/* color types.  Note that not all combinations are legal */
+#define PNG_COLOR_TYPE_GRAY 0
+#define PNG_COLOR_TYPE_PALETTE  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
+#define PNG_COLOR_TYPE_RGB        (PNG_COLOR_MASK_COLOR)
+#define PNG_COLOR_TYPE_RGB_ALPHA  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
+#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
+/* aliases */
+#define PNG_COLOR_TYPE_RGBA  PNG_COLOR_TYPE_RGB_ALPHA
+#define PNG_COLOR_TYPE_GA  PNG_COLOR_TYPE_GRAY_ALPHA
+
+/* This is for compression type. PNG 1.0-1.2 only define the single type. */
+#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */
+#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE
+
+/* This is for filter type. PNG 1.0-1.2 only define the single type. */
+#define PNG_FILTER_TYPE_BASE      0 /* Single row per-byte filtering */
+#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */
+#define PNG_FILTER_TYPE_DEFAULT   PNG_FILTER_TYPE_BASE
+
+/* These are for the interlacing type.  These values should NOT be changed. */
+#define PNG_INTERLACE_NONE        0 /* Non-interlaced image */
+#define PNG_INTERLACE_ADAM7       1 /* Adam7 interlacing */
+#define PNG_INTERLACE_LAST        2 /* Not a valid value */
+
+/* These are for the oFFs chunk.  These values should NOT be changed. */
+#define PNG_OFFSET_PIXEL          0 /* Offset in pixels */
+#define PNG_OFFSET_MICROMETER     1 /* Offset in micrometers (1/10^6 meter) */
+#define PNG_OFFSET_LAST           2 /* Not a valid value */
+
+/* These are for the pCAL chunk.  These values should NOT be changed. */
+#define PNG_EQUATION_LINEAR       0 /* Linear transformation */
+#define PNG_EQUATION_BASE_E       1 /* Exponential base e transform */
+#define PNG_EQUATION_ARBITRARY    2 /* Arbitrary base exponential transform */
+#define PNG_EQUATION_HYPERBOLIC   3 /* Hyperbolic sine transformation */
+#define PNG_EQUATION_LAST         4 /* Not a valid value */
+
+/* These are for the sCAL chunk.  These values should NOT be changed. */
+#define PNG_SCALE_UNKNOWN         0 /* unknown unit (image scale) */
+#define PNG_SCALE_METER           1 /* meters per pixel */
+#define PNG_SCALE_RADIAN          2 /* radians per pixel */
+#define PNG_SCALE_LAST            3 /* Not a valid value */
+
+/* These are for the pHYs chunk.  These values should NOT be changed. */
+#define PNG_RESOLUTION_UNKNOWN    0 /* pixels/unknown unit (aspect ratio) */
+#define PNG_RESOLUTION_METER      1 /* pixels/meter */
+#define PNG_RESOLUTION_LAST       2 /* Not a valid value */
+
+/* These are for the sRGB chunk.  These values should NOT be changed. */
+#define PNG_sRGB_INTENT_PERCEPTUAL 0
+#define PNG_sRGB_INTENT_RELATIVE   1
+#define PNG_sRGB_INTENT_SATURATION 2
+#define PNG_sRGB_INTENT_ABSOLUTE   3
+#define PNG_sRGB_INTENT_LAST       4 /* Not a valid value */
+
+/* This is for text chunks */
+#define PNG_KEYWORD_MAX_LENGTH     79
+
+/* Maximum number of entries in PLTE/sPLT/tRNS arrays */
+#define PNG_MAX_PALETTE_LENGTH    256
+
+/* These determine if an ancillary chunk's data has been successfully read
+ * from the PNG header, or if the application has filled in the corresponding
+ * data in the info_struct to be written into the output file.  The values
+ * of the PNG_INFO_<chunk> defines should NOT be changed.
+ */
+#define PNG_INFO_gAMA 0x0001
+#define PNG_INFO_sBIT 0x0002
+#define PNG_INFO_cHRM 0x0004
+#define PNG_INFO_PLTE 0x0008
+#define PNG_INFO_tRNS 0x0010
+#define PNG_INFO_bKGD 0x0020
+#define PNG_INFO_hIST 0x0040
+#define PNG_INFO_pHYs 0x0080
+#define PNG_INFO_oFFs 0x0100
+#define PNG_INFO_tIME 0x0200
+#define PNG_INFO_pCAL 0x0400
+#define PNG_INFO_sRGB 0x0800   /* GR-P, 0.96a */
+#define PNG_INFO_iCCP 0x1000   /* ESR, 1.0.6 */
+#define PNG_INFO_sPLT 0x2000   /* ESR, 1.0.6 */
+#define PNG_INFO_sCAL 0x4000   /* ESR, 1.0.6 */
+#define PNG_INFO_IDAT 0x8000   /* ESR, 1.0.6 */
+
+/* This is used for the transformation routines, as some of them
+ * change these values for the row.  It also should enable using
+ * the routines for other purposes.
+ */
+typedef struct png_row_info_struct
+{
+   png_uint_32 width;    /* width of row */
+   png_size_t rowbytes;  /* number of bytes in row */
+   png_byte color_type;  /* color type of row */
+   png_byte bit_depth;   /* bit depth of row */
+   png_byte channels;    /* number of channels (1, 2, 3, or 4) */
+   png_byte pixel_depth; /* bits per pixel (depth * channels) */
+} png_row_info;
+
+typedef png_row_info * png_row_infop;
+typedef png_row_info * * png_row_infopp;
+
+/* These are the function types for the I/O functions and for the functions
+ * that allow the user to override the default I/O functions with his or her
+ * own.  The png_error_ptr type should match that of user-supplied warning
+ * and error functions, while the png_rw_ptr type should match that of the
+ * user read/write data functions.  Note that the 'write' function must not
+ * modify the buffer it is passed. The 'read' function, on the other hand, is
+ * expected to return the read data in the buffer.
+ */
+typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp));
+typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t));
+typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp));
+typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32,
+    int));
+typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
+    int));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
+
+/* The following callback receives png_uint_32 row_number, int pass for the
+ * png_bytep data of the row.  When transforming an interlaced image the
+ * row number is the row number within the sub-image of the interlace pass, so
+ * the value will increase to the height of the sub-image (not the full image)
+ * then reset to 0 for the next pass.
+ *
+ * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to
+ * find the output pixel (x,y) given an interlaced sub-image pixel
+ * (row,col,pass).  (See below for these macros.)
+ */
+typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep,
+    png_uint_32, int));
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop,
+    png_bytep));
+#endif
+
+#ifdef PNG_USER_CHUNKS_SUPPORTED
+typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp,
+    png_unknown_chunkp));
+#endif
+#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
+/* not used anywhere */
+/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+/* This must match the function definition in <setjmp.h>, and the application
+ * must include this before png.h to obtain the definition of jmp_buf.  The
+ * function is required to be PNG_NORETURN, but this is not checked.  If the
+ * function does return the application will crash via an abort() or similar
+ * system level call.
+ *
+ * If you get a warning here while building the library you may need to make
+ * changes to ensure that pnglibconf.h records the calling convention used by
+ * your compiler.  This may be very difficult - try using a different compiler
+ * to build the library!
+ */
+PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef);
+#endif
+
+/* Transform masks for the high-level interface */
+#define PNG_TRANSFORM_IDENTITY       0x0000    /* read and write */
+#define PNG_TRANSFORM_STRIP_16       0x0001    /* read only */
+#define PNG_TRANSFORM_STRIP_ALPHA    0x0002    /* read only */
+#define PNG_TRANSFORM_PACKING        0x0004    /* read and write */
+#define PNG_TRANSFORM_PACKSWAP       0x0008    /* read and write */
+#define PNG_TRANSFORM_EXPAND         0x0010    /* read only */
+#define PNG_TRANSFORM_INVERT_MONO    0x0020    /* read and write */
+#define PNG_TRANSFORM_SHIFT          0x0040    /* read and write */
+#define PNG_TRANSFORM_BGR            0x0080    /* read and write */
+#define PNG_TRANSFORM_SWAP_ALPHA     0x0100    /* read and write */
+#define PNG_TRANSFORM_SWAP_ENDIAN    0x0200    /* read and write */
+#define PNG_TRANSFORM_INVERT_ALPHA   0x0400    /* read and write */
+#define PNG_TRANSFORM_STRIP_FILLER   0x0800    /* write only */
+/* Added to libpng-1.2.34 */
+#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER
+#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */
+/* Added to libpng-1.4.0 */
+#define PNG_TRANSFORM_GRAY_TO_RGB   0x2000      /* read only */
+/* Added to libpng-1.5.4 */
+#define PNG_TRANSFORM_EXPAND_16     0x4000      /* read only */
+#define PNG_TRANSFORM_SCALE_16      0x8000      /* read only */
+
+/* Flags for MNG supported features */
+#define PNG_FLAG_MNG_EMPTY_PLTE     0x01
+#define PNG_FLAG_MNG_FILTER_64      0x04
+#define PNG_ALL_MNG_FEATURES        0x05
+
+/* NOTE: prior to 1.5 these functions had no 'API' style declaration,
+ * this allowed the zlib default functions to be used on Windows
+ * platforms.  In 1.5 the zlib default malloc (which just calls malloc and
+ * ignores the first argument) should be completely compatible with the
+ * following.
+ */
+typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp,
+    png_alloc_size_t));
+typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp));
+
+/* Section 3: exported functions
+ * Here are the function definitions most commonly used.  This is not
+ * the place to find out how to use libpng.  See libpng-manual.txt for the
+ * full explanation, see example.c for the summary.  This just provides
+ * a simple one line description of the use of each function.
+ *
+ * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in
+ * pngconf.h and in the *.dfn files in the scripts directory.
+ *
+ *   PNG_EXPORT(ordinal, type, name, (args));
+ *
+ *       ordinal:    ordinal that is used while building
+ *                   *.def files. The ordinal value is only
+ *                   relevant when preprocessing png.h with
+ *                   the *.dfn files for building symbol table
+ *                   entries, and are removed by pngconf.h.
+ *       type:       return type of the function
+ *       name:       function name
+ *       args:       function arguments, with types
+ *
+ * When we wish to append attributes to a function prototype we use
+ * the PNG_EXPORTA() macro instead.
+ *
+ *   PNG_EXPORTA(ordinal, type, name, (args), attributes);
+ *
+ *       ordinal, type, name, and args: same as in PNG_EXPORT().
+ *       attributes: function attributes
+ */
+
+/* Returns the version number of the library */
+PNG_EXPORT(1, png_uint_32, png_access_version_number, (void));
+
+/* Tell lib we have already handled the first <num_bytes> magic bytes.
+ * Handling more than 8 bytes from the beginning of the file is an error.
+ */
+PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes));
+
+/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
+ * PNG file.  Returns zero if the supplied bytes match the 8-byte PNG
+ * signature, and non-zero otherwise.  Having num_to_check == 0 or
+ * start > 7 will always fail (ie return non-zero).
+ */
+PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, png_size_t start,
+    png_size_t num_to_check));
+
+/* Simple signature checking function.  This is the same as calling
+ * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ */
+#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n))
+
+/* Allocate and initialize png_ptr struct for reading, and any other memory. */
+PNG_EXPORTA(4, png_structp, png_create_read_struct,
+    (png_const_charp user_png_ver, png_voidp error_ptr,
+    png_error_ptr error_fn, png_error_ptr warn_fn),
+    PNG_ALLOCATED);
+
+/* Allocate and initialize png_ptr struct for writing, and any other memory */
+PNG_EXPORTA(5, png_structp, png_create_write_struct,
+    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
+    png_error_ptr warn_fn),
+    PNG_ALLOCATED);
+
+PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size,
+    (png_const_structrp png_ptr));
+
+PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr,
+    png_size_t size));
+
+/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp
+ * match up.
+ */
+#ifdef PNG_SETJMP_SUPPORTED
+/* This function returns the jmp_buf built in to *png_ptr.  It must be
+ * supplied with an appropriate 'longjmp' function to use on that jmp_buf
+ * unless the default error function is overridden in which case NULL is
+ * acceptable.  The size of the jmp_buf is checked against the actual size
+ * allocated by the library - the call will return NULL on a mismatch
+ * indicating an ABI mismatch.
+ */
+PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr,
+    png_longjmp_ptr longjmp_fn, size_t jmp_buf_size));
+#  define png_jmpbuf(png_ptr) \
+      (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf))))
+#else
+#  define png_jmpbuf(png_ptr) \
+      (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP)
+#endif
+/* This function should be used by libpng applications in place of
+ * longjmp(png_ptr->jmpbuf, val).  If longjmp_fn() has been set, it
+ * will use it; otherwise it will call PNG_ABORT().  This function was
+ * added in libpng-1.5.0.
+ */
+PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val),
+    PNG_NORETURN);
+
+#ifdef PNG_READ_SUPPORTED
+/* Reset the compression stream */
+PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED);
+#endif
+
+/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */
+#ifdef PNG_USER_MEM_SUPPORTED
+PNG_EXPORTA(11, png_structp, png_create_read_struct_2,
+    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
+    png_error_ptr warn_fn,
+    png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),
+    PNG_ALLOCATED);
+PNG_EXPORTA(12, png_structp, png_create_write_struct_2,
+    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
+    png_error_ptr warn_fn,
+    png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),
+    PNG_ALLOCATED);
+#endif
+
+/* Write the PNG file signature. */
+PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr));
+
+/* Write a PNG chunk - size, type, (optional) data, CRC. */
+PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep
+    chunk_name, png_const_bytep data, png_size_t length));
+
+/* Write the start of a PNG chunk - length and chunk name. */
+PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr,
+    png_const_bytep chunk_name, png_uint_32 length));
+
+/* Write the data of a PNG chunk started with png_write_chunk_start(). */
+PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr,
+    png_const_bytep data, png_size_t length));
+
+/* Finish a chunk started with png_write_chunk_start() (includes CRC). */
+PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr));
+
+/* Allocate and initialize the info structure */
+PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr),
+    PNG_ALLOCATED);
+
+/* DEPRECATED: this function allowed init structures to be created using the
+ * default allocation method (typically malloc).  Use is deprecated in 1.6.0 and
+ * the API will be removed in the future.
+ */
+PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr,
+    png_size_t png_info_struct_size), PNG_DEPRECATED);
+
+/* Writes all the PNG information before the image. */
+PNG_EXPORT(20, void, png_write_info_before_PLTE,
+    (png_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(21, void, png_write_info,
+    (png_structrp png_ptr, png_const_inforp info_ptr));
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read the information before the actual image data. */
+PNG_EXPORT(22, void, png_read_info,
+    (png_structrp png_ptr, png_inforp info_ptr));
+#endif
+
+#ifdef PNG_TIME_RFC1123_SUPPORTED
+   /* Convert to a US string format: there is no localization support in this
+    * routine.  The original implementation used a 29 character buffer in
+    * png_struct, this will be removed in future versions.
+    */
+#if PNG_LIBPNG_VER < 10700
+/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */
+PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr,
+    png_const_timep ptime),PNG_DEPRECATED);
+#endif
+PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29],
+    png_const_timep ptime));
+#endif
+
+#ifdef PNG_CONVERT_tIME_SUPPORTED
+/* Convert from a struct tm to png_time */
+PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime,
+    const struct tm * ttime));
+
+/* Convert from time_t to png_time.  Uses gmtime() */
+PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime));
+#endif /* PNG_CONVERT_tIME_SUPPORTED */
+
+#ifdef PNG_READ_EXPAND_SUPPORTED
+/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */
+PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr));
+PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr));
+PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr));
+PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr));
+#endif
+
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion
+ * of a tRNS chunk if present.
+ */
+PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr));
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* Use blue, green, red order for pixels. */
+PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr));
+#endif
+
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+/* Expand the grayscale to 24-bit RGB if necessary. */
+PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr));
+#endif
+
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+/* Reduce RGB to grayscale. */
+#define PNG_ERROR_ACTION_NONE  1
+#define PNG_ERROR_ACTION_WARN  2
+#define PNG_ERROR_ACTION_ERROR 3
+#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/
+
+PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr,
+    int error_action, double red, double green))
+PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr,
+    int error_action, png_fixed_point red, png_fixed_point green))
+
+PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp
+    png_ptr));
+#endif
+
+#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
+PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth,
+    png_colorp palette));
+#endif
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+/* How the alpha channel is interpreted - this affects how the color channels of
+ * a PNG file are returned when an alpha channel, or tRNS chunk in a palette
+ * file, is present.
+ *
+ * This has no effect on the way pixels are written into a PNG output
+ * datastream. The color samples in a PNG datastream are never premultiplied
+ * with the alpha samples.
+ *
+ * The default is to return data according to the PNG specification: the alpha
+ * channel is a linear measure of the contribution of the pixel to the
+ * corresponding composited pixel.  The gamma encoded color channels must be
+ * scaled according to the contribution and to do this it is necessary to undo
+ * the encoding, scale the color values, perform the composition and reencode
+ * the values.  This is the 'PNG' mode.
+ *
+ * The alternative is to 'associate' the alpha with the color information by
+ * storing color channel values that have been scaled by the alpha.  The
+ * advantage is that the color channels can be resampled (the image can be
+ * scaled) in this form.  The disadvantage is that normal practice is to store
+ * linear, not (gamma) encoded, values and this requires 16-bit channels for
+ * still images rather than the 8-bit channels that are just about sufficient if
+ * gamma encoding is used.  In addition all non-transparent pixel values,
+ * including completely opaque ones, must be gamma encoded to produce the final
+ * image.  This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the
+ * latter being the two common names for associated alpha color channels.)
+ *
+ * Since it is not necessary to perform arithmetic on opaque color values so
+ * long as they are not to be resampled and are in the final color space it is
+ * possible to optimize the handling of alpha by storing the opaque pixels in
+ * the PNG format (adjusted for the output color space) while storing partially
+ * opaque pixels in the standard, linear, format.  The accuracy required for
+ * standard alpha composition is relatively low, because the pixels are
+ * isolated, therefore typically the accuracy loss in storing 8-bit linear
+ * values is acceptable.  (This is not true if the alpha channel is used to
+ * simulate transparency over large areas - use 16 bits or the PNG mode in
+ * this case!)  This is the 'OPTIMIZED' mode.  For this mode a pixel is
+ * treated as opaque only if the alpha value is equal to the maximum value.
+ *
+ * The final choice is to gamma encode the alpha channel as well.  This is
+ * broken because, in practice, no implementation that uses this choice
+ * correctly undoes the encoding before handling alpha composition.  Use this
+ * choice only if other serious errors in the software or hardware you use
+ * mandate it; the typical serious error is for dark halos to appear around
+ * opaque areas of the composited PNG image because of arithmetic overflow.
+ *
+ * The API function png_set_alpha_mode specifies which of these choices to use
+ * with an enumerated 'mode' value and the gamma of the required output:
+ */
+#define PNG_ALPHA_PNG           0 /* according to the PNG standard */
+#define PNG_ALPHA_STANDARD      1 /* according to Porter/Duff */
+#define PNG_ALPHA_ASSOCIATED    1 /* as above; this is the normal practice */
+#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */
+#define PNG_ALPHA_OPTIMIZED     2 /* 'PNG' for opaque pixels, else 'STANDARD' */
+#define PNG_ALPHA_BROKEN        3 /* the alpha channel is gamma encoded */
+
+PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode,
+    double output_gamma))
+PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr,
+    int mode, png_fixed_point output_gamma))
+#endif
+
+#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+/* The output_gamma value is a screen gamma in libpng terminology: it expresses
+ * how to decode the output values, not how they are encoded.  The values used
+ * correspond to the normal numbers used to describe the overall gamma of a
+ * computer display system; for example 2.2 for an sRGB conformant system.  The
+ * values are scaled by 100000 in the _fixed version of the API (so 220000 for
+ * sRGB.)
+ *
+ * The inverse of the value is always used to provide a default for the PNG file
+ * encoding if it has no gAMA chunk and if png_set_gamma() has not been called
+ * to override the PNG gamma information.
+ *
+ * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode
+ * opaque pixels however pixels with lower alpha values are not encoded,
+ * regardless of the output gamma setting.
+ *
+ * When the standard Porter Duff handling is requested with mode 1 the output
+ * encoding is set to be linear and the output_gamma value is only relevant
+ * as a default for input data that has no gamma information.  The linear output
+ * encoding will be overridden if png_set_gamma() is called - the results may be
+ * highly unexpected!
+ *
+ * The following numbers are derived from the sRGB standard and the research
+ * behind it.  sRGB is defined to be approximated by a PNG gAMA chunk value of
+ * 0.45455 (1/2.2) for PNG.  The value implicitly includes any viewing
+ * correction required to take account of any differences in the color
+ * environment of the original scene and the intended display environment; the
+ * value expresses how to *decode* the image for display, not how the original
+ * data was *encoded*.
+ *
+ * sRGB provides a peg for the PNG standard by defining a viewing environment.
+ * sRGB itself, and earlier TV standards, actually use a more complex transform
+ * (a linear portion then a gamma 2.4 power law) than PNG can express.  (PNG is
+ * limited to simple power laws.)  By saying that an image for direct display on
+ * an sRGB conformant system should be stored with a gAMA chunk value of 45455
+ * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification
+ * makes it possible to derive values for other display systems and
+ * environments.
+ *
+ * The Mac value is deduced from the sRGB based on an assumption that the actual
+ * extra viewing correction used in early Mac display systems was implemented as
+ * a power 1.45 lookup table.
+ *
+ * Any system where a programmable lookup table is used or where the behavior of
+ * the final display device characteristics can be changed requires system
+ * specific code to obtain the current characteristic.  However this can be
+ * difficult and most PNG gamma correction only requires an approximate value.
+ *
+ * By default, if png_set_alpha_mode() is not called, libpng assumes that all
+ * values are unencoded, linear, values and that the output device also has a
+ * linear characteristic.  This is only very rarely correct - it is invariably
+ * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the
+ * default if you don't know what the right answer is!
+ *
+ * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS
+ * 10.6) which used a correction table to implement a somewhat lower gamma on an
+ * otherwise sRGB system.
+ *
+ * Both these values are reserved (not simple gamma values) in order to allow
+ * more precise correction internally in the future.
+ *
+ * NOTE: the following values can be passed to either the fixed or floating
+ * point APIs, but the floating point API will also accept floating point
+ * values.
+ */
+#define PNG_DEFAULT_sRGB -1       /* sRGB gamma and color space */
+#define PNG_GAMMA_MAC_18 -2       /* Old Mac '1.8' gamma and color space */
+#define PNG_GAMMA_sRGB   220000   /* Television standards--matches sRGB gamma */
+#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */
+#endif
+
+/* The following are examples of calls to png_set_alpha_mode to achieve the
+ * required overall gamma correction and, where necessary, alpha
+ * premultiplication.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
+ *    This is the default libpng handling of the alpha channel - it is not
+ *    pre-multiplied into the color components.  In addition the call states
+ *    that the output is for a sRGB system and causes all PNG files without gAMA
+ *    chunks to be assumed to be encoded using sRGB.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);
+ *    In this case the output is assumed to be something like an sRGB conformant
+ *    display preceeded by a power-law lookup table of power 1.45.  This is how
+ *    early Mac systems behaved.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR);
+ *    This is the classic Jim Blinn approach and will work in academic
+ *    environments where everything is done by the book.  It has the shortcoming
+ *    of assuming that input PNG data with no gamma information is linear - this
+ *    is unlikely to be correct unless the PNG files where generated locally.
+ *    Most of the time the output precision will be so low as to show
+ *    significant banding in dark areas of the image.
+ *
+ * png_set_expand_16(pp);
+ * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB);
+ *    This is a somewhat more realistic Jim Blinn inspired approach.  PNG files
+ *    are assumed to have the sRGB encoding if not marked with a gamma value and
+ *    the output is always 16 bits per component.  This permits accurate scaling
+ *    and processing of the data.  If you know that your input PNG files were
+ *    generated locally you might need to replace PNG_DEFAULT_sRGB with the
+ *    correct value for your system.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB);
+ *    If you just need to composite the PNG image onto an existing background
+ *    and if you control the code that does this you can use the optimization
+ *    setting.  In this case you just copy completely opaque pixels to the
+ *    output.  For pixels that are not completely transparent (you just skip
+ *    those) you do the composition math using png_composite or png_composite_16
+ *    below then encode the resultant 8-bit or 16-bit values to match the output
+ *    encoding.
+ *
+ * Other cases
+ *    If neither the PNG nor the standard linear encoding work for you because
+ *    of the software or hardware you use then you have a big problem.  The PNG
+ *    case will probably result in halos around the image.  The linear encoding
+ *    will probably result in a washed out, too bright, image (it's actually too
+ *    contrasty.)  Try the ALPHA_OPTIMIZED mode above - this will probably
+ *    substantially reduce the halos.  Alternatively try:
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB);
+ *    This option will also reduce the halos, but there will be slight dark
+ *    halos round the opaque parts of the image where the background is light.
+ *    In the OPTIMIZED mode the halos will be light halos where the background
+ *    is dark.  Take your pick - the halos are unavoidable unless you can get
+ *    your hardware/software fixed!  (The OPTIMIZED approach is slightly
+ *    faster.)
+ *
+ * When the default gamma of PNG files doesn't match the output gamma.
+ *    If you have PNG files with no gamma information png_set_alpha_mode allows
+ *    you to provide a default gamma, but it also sets the ouput gamma to the
+ *    matching value.  If you know your PNG files have a gamma that doesn't
+ *    match the output you can take advantage of the fact that
+ *    png_set_alpha_mode always sets the output gamma but only sets the PNG
+ *    default if it is not already set:
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);
+ *    The first call sets both the default and the output gamma values, the
+ *    second call overrides the output gamma without changing the default.  This
+ *    is easier than achieving the same effect with png_set_gamma.  You must use
+ *    PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will
+ *    fire if more than one call to png_set_alpha_mode and png_set_background is
+ *    made in the same read operation, however multiple calls with PNG_ALPHA_PNG
+ *    are ignored.
+ */
+
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr));
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+    defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr));
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
+    defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr));
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */
+PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler,
+    int flags));
+/* The values of the PNG_FILLER_ defines should NOT be changed */
+#  define PNG_FILLER_BEFORE 0
+#  define PNG_FILLER_AFTER 1
+/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */
+PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr,
+    png_uint_32 filler, int flags));
+#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* Swap bytes in 16-bit depth files. */
+PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */
+PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr));
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \
+    defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* Swap packing order of pixels in bytes. */
+PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr));
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* Converts files to legal bit depths. */
+PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p
+    true_bits));
+#endif
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+    defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* Have the code handle the interlacing.  Returns the number of passes.
+ * MUST be called before png_read_update_info or png_start_read_image,
+ * otherwise it will not have the desired effect.  Note that it is still
+ * necessary to call png_read_row or png_read_rows png_get_image_height
+ * times for each pass.
+*/
+PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr));
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+/* Invert monochrome files */
+PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr));
+#endif
+
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+/* Handle alpha and tRNS by replacing with a background color.  Prior to
+ * libpng-1.5.4 this API must not be called before the PNG file header has been
+ * read.  Doing so will result in unexpected behavior and possible warnings or
+ * errors if the PNG file contains a bKGD chunk.
+ */
+PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr,
+    png_const_color_16p background_color, int background_gamma_code,
+    int need_expand, double background_gamma))
+PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr,
+    png_const_color_16p background_color, int background_gamma_code,
+    int need_expand, png_fixed_point background_gamma))
+#endif
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+#  define PNG_BACKGROUND_GAMMA_UNKNOWN 0
+#  define PNG_BACKGROUND_GAMMA_SCREEN  1
+#  define PNG_BACKGROUND_GAMMA_FILE    2
+#  define PNG_BACKGROUND_GAMMA_UNIQUE  3
+#endif
+
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+/* Scale a 16-bit depth file down to 8-bit, accurately. */
+PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr));
+#endif
+
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */
+/* Strip the second byte of information from a 16-bit depth file. */
+PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr));
+#endif
+
+#ifdef PNG_READ_QUANTIZE_SUPPORTED
+/* Turn on quantizing, and reduce the palette to the number of colors
+ * available.
+ */
+PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr,
+    png_colorp palette, int num_palette, int maximum_colors,
+    png_const_uint_16p histogram, int full_quantize));
+#endif
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+/* The threshold on gamma processing is configurable but hard-wired into the
+ * library.  The following is the floating point variant.
+ */
+#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001)
+
+/* Handle gamma correction. Screen_gamma=(display_exponent).
+ * NOTE: this API simply sets the screen and file gamma values. It will
+ * therefore override the value for gamma in a PNG file if it is called after
+ * the file header has been read - use with care  - call before reading the PNG
+ * file for best results!
+ *
+ * These routines accept the same gamma values as png_set_alpha_mode (described
+ * above).  The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either
+ * API (floating point or fixed.)  Notice, however, that the 'file_gamma' value
+ * is the inverse of a 'screen gamma' value.
+ */
+PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr,
+    double screen_gamma, double override_file_gamma))
+PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr,
+    png_fixed_point screen_gamma, png_fixed_point override_file_gamma))
+#endif
+
+#ifdef PNG_WRITE_FLUSH_SUPPORTED
+/* Set how many lines between output flushes - 0 for no flushing */
+PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows));
+/* Flush the current PNG output buffer */
+PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr));
+#endif
+
+/* Optional update palette with requested transformations */
+PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr));
+
+/* Optional call to update the users info structure */
+PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr,
+    png_inforp info_ptr));
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read one or more rows of image data. */
+PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row,
+    png_bytepp display_row, png_uint_32 num_rows));
+#endif
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read a row of data. */
+PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row,
+    png_bytep display_row));
+#endif
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read the whole image into memory at once. */
+PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image));
+#endif
+
+/* Write a row of image data */
+PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr,
+    png_const_bytep row));
+
+/* Write a few rows of image data: (*row) is not written; however, the type
+ * is declared as writeable to maintain compatibility with previous versions
+ * of libpng and to allow the 'display_row' array from read_rows to be passed
+ * unchanged to write_rows.
+ */
+PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row,
+    png_uint_32 num_rows));
+
+/* Write the image data */
+PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image));
+
+/* Write the end of the PNG file. */
+PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr,
+    png_inforp info_ptr));
+
+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
+/* Read the end of the PNG file. */
+PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr));
+#endif
+
+/* Free any memory associated with the png_info_struct */
+PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr,
+    png_infopp info_ptr_ptr));
+
+/* Free any memory associated with the png_struct and the png_info_structs */
+PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr,
+    png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
+
+/* Free any memory associated with the png_struct and the png_info_structs */
+PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr,
+    png_infopp info_ptr_ptr));
+
+/* Set the libpng method of handling chunk CRC errors */
+PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
+    int ancil_action));
+
+/* Values for png_set_crc_action() say how to handle CRC errors in
+ * ancillary and critical chunks, and whether to use the data contained
+ * therein.  Note that it is impossible to "discard" data in a critical
+ * chunk.  For versions prior to 0.90, the action was always error/quit,
+ * whereas in version 0.90 and later, the action for CRC errors in ancillary
+ * chunks is warn/discard.  These values should NOT be changed.
+ *
+ *      value                       action:critical     action:ancillary
+ */
+#define PNG_CRC_DEFAULT       0  /* error/quit          warn/discard data */
+#define PNG_CRC_ERROR_QUIT    1  /* error/quit          error/quit        */
+#define PNG_CRC_WARN_DISCARD  2  /* (INVALID)           warn/discard data */
+#define PNG_CRC_WARN_USE      3  /* warn/use data       warn/use data     */
+#define PNG_CRC_QUIET_USE     4  /* quiet/use data      quiet/use data    */
+#define PNG_CRC_NO_CHANGE     5  /* use current value   use current value */
+
+/* These functions give the user control over the scan-line filtering in
+ * libpng and the compression methods used by zlib.  These functions are
+ * mainly useful for testing, as the defaults should work with most users.
+ * Those users who are tight on memory or want faster performance at the
+ * expense of compression can modify them.  See the compression library
+ * header file (zlib.h) for an explination of the compression functions.
+ */
+
+/* Set the filtering method(s) used by libpng.  Currently, the only valid
+ * value for "method" is 0.
+ */
+PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
+    int filters));
+
+/* Flags for png_set_filter() to say which filters to use.  The flags
+ * are chosen so that they don't conflict with real filter types
+ * below, in case they are supplied instead of the #defined constants.
+ * These values should NOT be changed.
+ */
+#define PNG_NO_FILTERS     0x00
+#define PNG_FILTER_NONE    0x08
+#define PNG_FILTER_SUB     0x10
+#define PNG_FILTER_UP      0x20
+#define PNG_FILTER_AVG     0x40
+#define PNG_FILTER_PAETH   0x80
+#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
+                         PNG_FILTER_AVG | PNG_FILTER_PAETH)
+
+/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
+ * These defines should NOT be changed.
+ */
+#define PNG_FILTER_VALUE_NONE  0
+#define PNG_FILTER_VALUE_SUB   1
+#define PNG_FILTER_VALUE_UP    2
+#define PNG_FILTER_VALUE_AVG   3
+#define PNG_FILTER_VALUE_PAETH 4
+#define PNG_FILTER_VALUE_LAST  5
+
+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */
+/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
+ * defines, either the default (minimum-sum-of-absolute-differences), or
+ * the experimental method (weighted-minimum-sum-of-absolute-differences).
+ *
+ * Weights are factors >= 1.0, indicating how important it is to keep the
+ * filter type consistent between rows.  Larger numbers mean the current
+ * filter is that many times as likely to be the same as the "num_weights"
+ * previous filters.  This is cumulative for each previous row with a weight.
+ * There needs to be "num_weights" values in "filter_weights", or it can be
+ * NULL if the weights aren't being specified.  Weights have no influence on
+ * the selection of the first row filter.  Well chosen weights can (in theory)
+ * improve the compression for a given image.
+ *
+ * Costs are factors >= 1.0 indicating the relative decoding costs of a
+ * filter type.  Higher costs indicate more decoding expense, and are
+ * therefore less likely to be selected over a filter with lower computational
+ * costs.  There needs to be a value in "filter_costs" for each valid filter
+ * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
+ * setting the costs.  Costs try to improve the speed of decompression without
+ * unduly increasing the compressed image size.
+ *
+ * A negative weight or cost indicates the default value is to be used, and
+ * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
+ * The default values for both weights and costs are currently 1.0, but may
+ * change if good general weighting/cost heuristics can be found.  If both
+ * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
+ * to the UNWEIGHTED method, but with added encoding time/computation.
+ */
+PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr,
+    int heuristic_method, int num_weights, png_const_doublep filter_weights,
+    png_const_doublep filter_costs))
+PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
+    (png_structrp png_ptr, int heuristic_method, int num_weights,
+    png_const_fixed_point_p filter_weights,
+    png_const_fixed_point_p filter_costs))
+#endif /*  PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+/* Heuristic used for row filter selection.  These defines should NOT be
+ * changed.
+ */
+#define PNG_FILTER_HEURISTIC_DEFAULT    0  /* Currently "UNWEIGHTED" */
+#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1  /* Used by libpng < 0.95 */
+#define PNG_FILTER_HEURISTIC_WEIGHTED   2  /* Experimental feature */
+#define PNG_FILTER_HEURISTIC_LAST       3  /* Not a valid value */
+
+#ifdef PNG_WRITE_SUPPORTED
+/* Set the library compression level.  Currently, valid values range from
+ * 0 - 9, corresponding directly to the zlib compression levels 0 - 9
+ * (0 - no compression, 9 - "maximal" compression).  Note that tests have
+ * shown that zlib compression levels 3-6 usually perform as well as level 9
+ * for PNG images, and do considerably fewer caclulations.  In the future,
+ * these values may not correspond directly to the zlib compression levels.
+ */
+PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr,
+    int level));
+
+PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr,
+    int mem_level));
+
+PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr,
+    int strategy));
+
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
+PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr,
+    int window_bits));
+
+PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr,
+    int method));
+#endif
+
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+/* Also set zlib parameters for compressing non-IDAT chunks */
+PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr,
+    int level));
+
+PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr,
+    int mem_level));
+
+PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr,
+    int strategy));
+
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
+PNG_EXPORT(225, void, png_set_text_compression_window_bits,
+    (png_structrp png_ptr, int window_bits));
+
+PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
+    int method));
+#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
+
+/* These next functions are called for input/output, memory, and error
+ * handling.  They are in the file pngrio.c, pngwio.c, and pngerror.c,
+ * and call standard C I/O routines such as fread(), fwrite(), and
+ * fprintf().  These functions can be made to use other I/O routines
+ * at run time for those applications that need to handle I/O in a
+ * different manner by calling png_set_???_fn().  See libpng-manual.txt for
+ * more information.
+ */
+
+#ifdef PNG_STDIO_SUPPORTED
+/* Initialize the input/output for the PNG file to the default functions. */
+PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
+#endif
+
+/* Replace the (error and abort), and warning functions with user
+ * supplied functions.  If no messages are to be printed you must still
+ * write and use replacement functions. The replacement error_fn should
+ * still do a longjmp to the last setjmp location if you are using this
+ * method of error handling.  If error_fn or warning_fn is NULL, the
+ * default function will be used.
+ */
+
+PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr,
+    png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
+
+/* Return the user pointer associated with the error functions */
+PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr));
+
+/* Replace the default data output functions with a user supplied one(s).
+ * If buffered output is not used, then output_flush_fn can be set to NULL.
+ * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
+ * output_flush_fn will be ignored (and thus can be NULL).
+ * It is probably a mistake to use NULL for output_flush_fn if
+ * write_data_fn is not also NULL unless you have built libpng with
+ * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's
+ * default flush function, which uses the standard *FILE structure, will
+ * be used.
+ */
+PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr,
+    png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
+
+/* Replace the default data input function with a user supplied one. */
+PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr,
+    png_rw_ptr read_data_fn));
+
+/* Return the user pointer associated with the I/O functions */
+PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr));
+
+PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr,
+    png_read_status_ptr read_row_fn));
+
+PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr,
+    png_write_status_ptr write_row_fn));
+
+#ifdef PNG_USER_MEM_SUPPORTED
+/* Replace the default memory allocation functions with user supplied one(s). */
+PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr,
+    png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+/* Return the user pointer associated with the memory functions */
+PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr));
+#endif
+
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
+PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr,
+    png_user_transform_ptr read_user_transform_fn));
+#endif
+
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
+PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr,
+    png_user_transform_ptr write_user_transform_fn));
+#endif
+
+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
+PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr,
+    png_voidp user_transform_ptr, int user_transform_depth,
+    int user_transform_channels));
+/* Return the user pointer associated with the user transform functions */
+PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr,
+    (png_const_structrp png_ptr));
+#endif
+
+#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED
+/* Return information about the row currently being processed.  Note that these
+ * APIs do not fail but will return unexpected results if called outside a user
+ * transform callback.  Also note that when transforming an interlaced image the
+ * row number is the row number within the sub-image of the interlace pass, so
+ * the value will increase to the height of the sub-image (not the full image)
+ * then reset to 0 for the next pass.
+ *
+ * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to
+ * find the output pixel (x,y) given an interlaced sub-image pixel
+ * (row,col,pass).  (See below for these macros.)
+ */
+PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp));
+PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp));
+#endif
+
+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+/* This callback is called only for *unknown* chunks.  If
+ * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known
+ * chunks to be treated as unknown, however in this case the callback must do
+ * any processing required by the chunk (e.g. by calling the appropriate
+ * png_set_ APIs.)
+ *
+ * There is no write support - on write, by default, all the chunks in the
+ * 'unknown' list are written in the specified position.
+ *
+ * The integer return from the callback function is interpreted thus:
+ *
+ * negative: An error occured, png_chunk_error will be called.
+ *     zero: The chunk was not handled, the chunk will be saved. A critical
+ *           chunk will cause an error at this point unless it is to be saved.
+ * positive: The chunk was handled, libpng will ignore/discard it.
+ *
+ * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about
+ * how this behavior will change in libpng 1.7
+ */
+PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr,
+    png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn));
+#endif
+
+#ifdef PNG_USER_CHUNKS_SUPPORTED
+PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr));
+#endif
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+/* Sets the function callbacks for the push reader, and a pointer to a
+ * user-defined structure available to the callback functions.
+ */
+PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr,
+    png_voidp progressive_ptr, png_progressive_info_ptr info_fn,
+    png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn));
+
+/* Returns the user pointer associated with the push read functions */
+PNG_EXPORT(91, png_voidp, png_get_progressive_ptr,
+    (png_const_structrp png_ptr));
+
+/* Function to be called when data becomes available */
+PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr,
+    png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size));
+
+/* A function which may be called *only* within png_process_data to stop the
+ * processing of any more data.  The function returns the number of bytes
+ * remaining, excluding any that libpng has cached internally.  A subsequent
+ * call to png_process_data must supply these bytes again.  If the argument
+ * 'save' is set to true the routine will first save all the pending data and
+ * will always return 0.
+ */
+PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save));
+
+/* A function which may be called *only* outside (after) a call to
+ * png_process_data.  It returns the number of bytes of data to skip in the
+ * input.  Normally it will return 0, but if it returns a non-zero value the
+ * application must skip than number of bytes of input data and pass the
+ * following data to the next call to png_process_data.
+ */
+PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp));
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+/* Function that combines rows.  'new_row' is a flag that should come from
+ * the callback and be non-NULL if anything needs to be done; the library
+ * stores its own version of the new data internally and ignores the passed
+ * in value.
+ */
+PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr,
+    png_bytep old_row, png_const_bytep new_row));
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr,
+    png_alloc_size_t size), PNG_ALLOCATED);
+/* Added at libpng version 1.4.0 */
+PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr,
+    png_alloc_size_t size), PNG_ALLOCATED);
+
+/* Added at libpng version 1.2.4 */
+PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr,
+    png_alloc_size_t size), PNG_ALLOCATED);
+
+/* Frees a pointer allocated by png_malloc() */
+PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr));
+
+/* Free data that was allocated internally */
+PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_uint_32 free_me, int num));
+
+/* Reassign responsibility for freeing existing data, whether allocated
+ * by libpng or by the application; this works on the png_info structure passed
+ * in, it does not change the state for other png_info structures.
+ *
+ * It is unlikely that this function works correctly as of 1.6.0 and using it
+ * may result either in memory leaks or double free of allocated data.
+ */
+PNG_EXPORTA(99, void, png_data_freer, (png_const_structrp png_ptr,
+    png_inforp info_ptr, int freer, png_uint_32 mask), PNG_DEPRECATED);
+
+/* Assignments for png_data_freer */
+#define PNG_DESTROY_WILL_FREE_DATA 1
+#define PNG_SET_WILL_FREE_DATA 1
+#define PNG_USER_WILL_FREE_DATA 2
+/* Flags for png_ptr->free_me and info_ptr->free_me */
+#define PNG_FREE_HIST 0x0008
+#define PNG_FREE_ICCP 0x0010
+#define PNG_FREE_SPLT 0x0020
+#define PNG_FREE_ROWS 0x0040
+#define PNG_FREE_PCAL 0x0080
+#define PNG_FREE_SCAL 0x0100
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+#  define PNG_FREE_UNKN 0x0200
+#endif
+/*      PNG_FREE_LIST 0x0400    removed in 1.6.0 because it is ignored */
+#define PNG_FREE_PLTE 0x1000
+#define PNG_FREE_TRNS 0x2000
+#define PNG_FREE_TEXT 0x4000
+#define PNG_FREE_ALL  0x7fff
+#define PNG_FREE_MUL  0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */
+
+#ifdef PNG_USER_MEM_SUPPORTED
+PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr,
+    png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED);
+PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr,
+    png_voidp ptr), PNG_DEPRECATED);
+#endif
+
+#ifdef PNG_ERROR_TEXT_SUPPORTED
+/* Fatal error in PNG image of libpng - can't continue */
+PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr,
+    png_const_charp error_message), PNG_NORETURN);
+
+/* The same, but the chunk name is prepended to the error string. */
+PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr,
+    png_const_charp error_message), PNG_NORETURN);
+
+#else
+/* Fatal error in PNG image of libpng - can't continue */
+PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN);
+#endif
+
+#ifdef PNG_WARNINGS_SUPPORTED
+/* Non-fatal error in libpng.  Can continue, but may have a problem. */
+PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr,
+    png_const_charp warning_message));
+
+/* Non-fatal error in libpng, chunk name is prepended to message. */
+PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr,
+    png_const_charp warning_message));
+#endif
+
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
+/* Benign error in libpng.  Can continue, but may have a problem.
+ * User can choose whether to handle as a fatal error or as a warning. */
+PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr,
+    png_const_charp warning_message));
+
+#ifdef PNG_READ_SUPPORTED
+/* Same, chunk name is prepended to message (only during read) */
+PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr,
+    png_const_charp warning_message));
+#endif
+
+PNG_EXPORT(109, void, png_set_benign_errors,
+    (png_structrp png_ptr, int allowed));
+#else
+#  ifdef PNG_ALLOW_BENIGN_ERRORS
+#    define png_benign_error png_warning
+#    define png_chunk_benign_error png_chunk_warning
+#  else
+#    define png_benign_error png_error
+#    define png_chunk_benign_error png_chunk_error
+#  endif
+#endif
+
+/* The png_set_<chunk> functions are for storing values in the png_info_struct.
+ * Similarly, the png_get_<chunk> calls are used to read values from the
+ * png_info_struct, either storing the parameters in the passed variables, or
+ * setting pointers into the png_info_struct where the data is stored.  The
+ * png_get_<chunk> functions return a non-zero value if the data was available
+ * in info_ptr, or return zero and do not change any of the parameters if the
+ * data was not available.
+ *
+ * These functions should be used instead of directly accessing png_info
+ * to avoid problems with future changes in the size and internal layout of
+ * png_info_struct.
+ */
+/* Returns "flag" if chunk data is valid in info_ptr. */
+PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, png_uint_32 flag));
+
+/* Returns number of bytes needed to hold a transformed row. */
+PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+#ifdef PNG_INFO_IMAGE_SUPPORTED
+/* Returns row_pointers, which is an array of pointers to scanlines that was
+ * returned from png_read_png().
+ */
+PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+/* Set row_pointers, which is an array of pointers to scanlines for use
+ * by png_write_png().
+ */
+PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_bytepp row_pointers));
+#endif
+
+/* Returns number of color channels in image. */
+PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+/* Returns image width in pixels. */
+PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+/* Returns image height in pixels. */
+PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+/* Returns image bit_depth. */
+PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+/* Returns image color_type. */
+PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+/* Returns image filter_type. */
+PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+/* Returns image interlace_type. */
+PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+/* Returns image compression_type. */
+PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+
+/* Returns image resolution in pixels per meter, from pHYs chunk data. */
+PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+
+/* Returns pixel aspect ratio, computed from pHYs chunk data.  */
+PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+
+/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */
+PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(128, png_int_32, png_get_x_offset_microns,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+PNG_EXPORT(129, png_int_32, png_get_y_offset_microns,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+
+#endif /* PNG_EASY_ACCESS_SUPPORTED */
+
+#ifdef PNG_READ_SUPPORTED
+/* Returns pointer to signature string read from PNG header */
+PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr));
+#endif
+
+#ifdef PNG_bKGD_SUPPORTED
+PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_color_16p *background));
+#endif
+
+#ifdef PNG_bKGD_SUPPORTED
+PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_color_16p background));
+#endif
+
+#ifdef PNG_cHRM_SUPPORTED
+PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x,
+    double *red_y, double *green_x, double *green_y, double *blue_x,
+    double *blue_y))
+PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z,
+    double *green_X, double *green_Y, double *green_Z, double *blue_X,
+    double *blue_Y, double *blue_Z))
+PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_fixed_point *int_white_x, png_fixed_point *int_white_y,
+    png_fixed_point *int_red_x, png_fixed_point *int_red_y,
+    png_fixed_point *int_green_x, png_fixed_point *int_green_y,
+    png_fixed_point *int_blue_x, png_fixed_point *int_blue_y))
+PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_fixed_point *int_red_X, png_fixed_point *int_red_Y,
+    png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
+    png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
+    png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
+    png_fixed_point *int_blue_Z))
+#endif
+
+#ifdef PNG_cHRM_SUPPORTED
+PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr,
+    png_inforp info_ptr,
+    double white_x, double white_y, double red_x, double red_y, double green_x,
+    double green_y, double blue_x, double blue_y))
+PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr,
+    png_inforp info_ptr, double red_X, double red_Y, double red_Z,
+    double green_X, double green_Y, double green_Z, double blue_X,
+    double blue_Y, double blue_Z))
+PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_fixed_point int_white_x,
+    png_fixed_point int_white_y, png_fixed_point int_red_x,
+    png_fixed_point int_red_y, png_fixed_point int_green_x,
+    png_fixed_point int_green_y, png_fixed_point int_blue_x,
+    png_fixed_point int_blue_y))
+PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,
+    png_fixed_point int_red_Z, png_fixed_point int_green_X,
+    png_fixed_point int_green_Y, png_fixed_point int_green_Z,
+    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
+    png_fixed_point int_blue_Z))
+#endif
+
+#ifdef PNG_gAMA_SUPPORTED
+PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, double *file_gamma))
+PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr,
+    png_fixed_point *int_file_gamma))
+#endif
+
+#ifdef PNG_gAMA_SUPPORTED
+PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr,
+    png_inforp info_ptr, double file_gamma))
+PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_fixed_point int_file_gamma))
+#endif
+
+#ifdef PNG_hIST_SUPPORTED
+PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_uint_16p *hist));
+#endif
+
+#ifdef PNG_hIST_SUPPORTED
+PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_uint_16p hist));
+#endif
+
+PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height,
+    int *bit_depth, int *color_type, int *interlace_method,
+    int *compression_method, int *filter_method));
+
+PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
+    int color_type, int interlace_method, int compression_method,
+    int filter_method));
+
+#ifdef PNG_oFFs_SUPPORTED
+PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr,
+   png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,
+   int *unit_type));
+#endif
+
+#ifdef PNG_oFFs_SUPPORTED
+PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y,
+    int unit_type));
+#endif
+
+#ifdef PNG_pCAL_SUPPORTED
+PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_charp *purpose, png_int_32 *X0,
+    png_int_32 *X1, int *type, int *nparams, png_charp *units,
+    png_charpp *params));
+#endif
+
+#ifdef PNG_pCAL_SUPPORTED
+PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1,
+    int type, int nparams, png_const_charp units, png_charpp params));
+#endif
+
+#ifdef PNG_pHYs_SUPPORTED
+PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y,
+    int *unit_type));
+#endif
+
+#ifdef PNG_pHYs_SUPPORTED
+PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+#endif
+
+PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr,
+   png_inforp info_ptr, png_colorp *palette, int *num_palette));
+
+PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr,
+    png_inforp info_ptr, png_const_colorp palette, int num_palette));
+
+#ifdef PNG_sBIT_SUPPORTED
+PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_color_8p *sig_bit));
+#endif
+
+#ifdef PNG_sBIT_SUPPORTED
+PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_color_8p sig_bit));
+#endif
+
+#ifdef PNG_sRGB_SUPPORTED
+PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, int *file_srgb_intent));
+#endif
+
+#ifdef PNG_sRGB_SUPPORTED
+PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr,
+    png_inforp info_ptr, int srgb_intent));
+PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr,
+    png_inforp info_ptr, int srgb_intent));
+#endif
+
+#ifdef PNG_iCCP_SUPPORTED
+PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_charpp name, int *compression_type,
+    png_bytepp profile, png_uint_32 *proflen));
+#endif
+
+#ifdef PNG_iCCP_SUPPORTED
+PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_charp name, int compression_type,
+    png_const_bytep profile, png_uint_32 proflen));
+#endif
+
+#ifdef PNG_sPLT_SUPPORTED
+PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_sPLT_tpp entries));
+#endif
+
+#ifdef PNG_sPLT_SUPPORTED
+PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries));
+#endif
+
+#ifdef PNG_TEXT_SUPPORTED
+/* png_get_text also returns the number of text chunks in *num_text */
+PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_textp *text_ptr, int *num_text));
+#endif
+
+/* Note while png_set_text() will accept a structure whose text,
+ * language, and  translated keywords are NULL pointers, the structure
+ * returned by png_get_text will always contain regular
+ * zero-terminated C strings.  They might be empty strings but
+ * they will never be NULL pointers.
+ */
+
+#ifdef PNG_TEXT_SUPPORTED
+PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_textp text_ptr, int num_text));
+#endif
+
+#ifdef PNG_tIME_SUPPORTED
+PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_timep *mod_time));
+#endif
+
+#ifdef PNG_tIME_SUPPORTED
+PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_timep mod_time));
+#endif
+
+#ifdef PNG_tRNS_SUPPORTED
+PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans,
+    png_color_16p *trans_color));
+#endif
+
+#ifdef PNG_tRNS_SUPPORTED
+PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr,
+    png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans,
+    png_const_color_16p trans_color));
+#endif
+
+#ifdef PNG_sCAL_SUPPORTED
+PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, int *unit, double *width, double *height))
+#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \
+   defined(PNG_FLOATING_POINT_SUPPORTED)
+/* NOTE: this API is currently implemented using floating point arithmetic,
+ * consequently it can only be used on systems with floating point support.
+ * In any case the range of values supported by png_fixed_point is small and it
+ * is highly recommended that png_get_sCAL_s be used instead.
+ */
+PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit,
+    png_fixed_point *width, png_fixed_point *height))
+#endif
+PNG_EXPORT(169, png_uint_32, png_get_sCAL_s,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit,
+    png_charpp swidth, png_charpp sheight));
+
+PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr,
+    png_inforp info_ptr, int unit, double width, double height))
+PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr,
+   png_inforp info_ptr, int unit, png_fixed_point width,
+   png_fixed_point height))
+PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr,
+    png_inforp info_ptr, int unit,
+    png_const_charp swidth, png_const_charp sheight));
+#endif /* PNG_sCAL_SUPPORTED */
+
+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+/* Provide the default handling for all unknown chunks or, optionally, for
+ * specific unknown chunks.
+ *
+ * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was
+ * ignored and the default was used, the per-chunk setting only had an effect on
+ * write.  If you wish to have chunk-specific handling on read in code that must
+ * work on earlier versions you must use a user chunk callback to specify the
+ * desired handling (keep or discard.)
+ *
+ * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below.  The
+ * parameter is interpreted as follows:
+ *
+ * READ:
+ *    PNG_HANDLE_CHUNK_AS_DEFAULT:
+ *       Known chunks: do normal libpng processing, do not keep the chunk (but
+ *          see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED)
+ *       Unknown chunks: for a specific chunk use the global default, when used
+ *          as the default discard the chunk data.
+ *    PNG_HANDLE_CHUNK_NEVER:
+ *       Discard the chunk data.
+ *    PNG_HANDLE_CHUNK_IF_SAFE:
+ *       Keep the chunk data if the chunk is not critical else raise a chunk
+ *       error.
+ *    PNG_HANDLE_CHUNK_ALWAYS:
+ *       Keep the chunk data.
+ *
+ * If the chunk data is saved it can be retrieved using png_get_unknown_chunks,
+ * below.  Notice that specifying "AS_DEFAULT" as a global default is equivalent
+ * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks
+ * it simply resets the behavior to the libpng default.
+ *
+ * INTERACTION WTIH USER CHUNK CALLBACKS:
+ * The per-chunk handling is always used when there is a png_user_chunk_ptr
+ * callback and the callback returns 0; the chunk is then always stored *unless*
+ * it is critical and the per-chunk setting is other than ALWAYS.  Notice that
+ * the global default is *not* used in this case.  (In effect the per-chunk
+ * value is incremented to at least IF_SAFE.)
+ *
+ * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and
+ * per-chunk defaults will be honored.  If you want to preserve the current
+ * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE
+ * as the default - if you don't do this libpng 1.6 will issue a warning.
+ *
+ * If you want unhandled unknown chunks to be discarded in libpng 1.6 and
+ * earlier simply return '1' (handled).
+ *
+ * PNG_HANDLE_AS_UNKNOWN_SUPPORTED:
+ *    If this is *not* set known chunks will always be handled by libpng and
+ *    will never be stored in the unknown chunk list.  Known chunks listed to
+ *    png_set_keep_unknown_chunks will have no effect.  If it is set then known
+ *    chunks listed with a keep other than AS_DEFAULT will *never* be processed
+ *    by libpng, in addition critical chunks must either be processed by the
+ *    callback or saved.
+ *
+ *    The IHDR and IEND chunks must not be listed.  Because this turns off the
+ *    default handling for chunks that would otherwise be recognized the
+ *    behavior of libpng transformations may well become incorrect!
+ *
+ * WRITE:
+ *    When writing chunks the options only apply to the chunks specified by
+ *    png_set_unknown_chunks (below), libpng will *always* write known chunks
+ *    required by png_set_ calls and will always write the core critical chunks
+ *    (as required for PLTE).
+ *
+ *    Each chunk in the png_set_unknown_chunks list is looked up in the
+ *    png_set_keep_unknown_chunks list to find the keep setting, this is then
+ *    interpreted as follows:
+ *
+ *    PNG_HANDLE_CHUNK_AS_DEFAULT:
+ *       Write safe-to-copy chunks and write other chunks if the global
+ *       default is set to _ALWAYS, otherwise don't write this chunk.
+ *    PNG_HANDLE_CHUNK_NEVER:
+ *       Do not write the chunk.
+ *    PNG_HANDLE_CHUNK_IF_SAFE:
+ *       Write the chunk if it is safe-to-copy, otherwise do not write it.
+ *    PNG_HANDLE_CHUNK_ALWAYS:
+ *       Write the chunk.
+ *
+ * Note that the default behavior is effectively the opposite of the read case -
+ * in read unknown chunks are not stored by default, in write they are written
+ * by default.  Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different
+ * - on write the safe-to-copy bit is checked, on read the critical bit is
+ * checked and on read if the chunk is critical an error will be raised.
+ *
+ * num_chunks:
+ * ===========
+ *    If num_chunks is positive, then the "keep" parameter specifies the manner
+ *    for handling only those chunks appearing in the chunk_list array,
+ *    otherwise the chunk list array is ignored.
+ *
+ *    If num_chunks is 0 the "keep" parameter specifies the default behavior for
+ *    unknown chunks, as described above.
+ *
+ *    If num_chunks is negative, then the "keep" parameter specifies the manner
+ *    for handling all unknown chunks plus all chunks recognized by libpng
+ *    except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to
+ *    be processed by libpng.
+ */
+PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr,
+    int keep, png_const_bytep chunk_list, int num_chunks));
+
+/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned;
+ * the result is therefore true (non-zero) if special handling is required,
+ * false for the default handling.
+ */
+PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr,
+    png_const_bytep chunk_name));
+#endif
+
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_const_unknown_chunkp unknowns,
+    int num_unknowns));
+   /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added
+    * unknowns to the location currently stored in the png_struct.  This is
+    * invariably the wrong value on write.  To fix this call the following API
+    * for each chunk in the list with the correct location.  If you know your
+    * code won't be compiled on earlier versions you can rely on
+    * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing
+    * the correct thing.
+    */
+
+PNG_EXPORT(175, void, png_set_unknown_chunk_location,
+    (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location));
+
+PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr,
+    png_inforp info_ptr, png_unknown_chunkpp entries));
+#endif
+
+/* Png_free_data() will turn off the "valid" flag for anything it frees.
+ * If you need to turn it off for a chunk that your application has freed,
+ * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK);
+ */
+PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr,
+    png_inforp info_ptr, int mask));
+
+#ifdef PNG_INFO_IMAGE_SUPPORTED
+/* The "params" pointer is currently not used and is for future expansion. */
+PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr,
+    int transforms, png_voidp params));
+PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr,
+    int transforms, png_voidp params));
+#endif
+
+PNG_EXPORT(180, png_const_charp, png_get_copyright,
+    (png_const_structrp png_ptr));
+PNG_EXPORT(181, png_const_charp, png_get_header_ver,
+    (png_const_structrp png_ptr));
+PNG_EXPORT(182, png_const_charp, png_get_header_version,
+    (png_const_structrp png_ptr));
+PNG_EXPORT(183, png_const_charp, png_get_libpng_ver,
+    (png_const_structrp png_ptr));
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr,
+    png_uint_32 mng_features_permitted));
+#endif
+
+/* For use in png_set_keep_unknown, added to version 1.2.6 */
+#define PNG_HANDLE_CHUNK_AS_DEFAULT   0
+#define PNG_HANDLE_CHUNK_NEVER        1
+#define PNG_HANDLE_CHUNK_IF_SAFE      2
+#define PNG_HANDLE_CHUNK_ALWAYS       3
+#define PNG_HANDLE_CHUNK_LAST         4
+
+/* Strip the prepended error numbers ("#nnn ") from error and warning
+ * messages before passing them to the error or warning handler.
+ */
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr,
+    png_uint_32 strip_mode));
+#endif
+
+/* Added in libpng-1.2.6 */
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr,
+    png_uint_32 user_width_max, png_uint_32 user_height_max));
+PNG_EXPORT(187, png_uint_32, png_get_user_width_max,
+    (png_const_structrp png_ptr));
+PNG_EXPORT(188, png_uint_32, png_get_user_height_max,
+    (png_const_structrp png_ptr));
+/* Added in libpng-1.4.0 */
+PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr,
+    png_uint_32 user_chunk_cache_max));
+PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max,
+    (png_const_structrp png_ptr));
+/* Added in libpng-1.4.1 */
+PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr,
+    png_alloc_size_t user_chunk_cache_max));
+PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max,
+    (png_const_structrp png_ptr));
+#endif
+
+#if defined(PNG_INCH_CONVERSIONS_SUPPORTED)
+PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+
+PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+
+PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr));
+
+PNG_FP_EXPORT(196, float, png_get_x_offset_inches,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
+PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+#endif
+
+PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr))
+#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
+PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed,
+    (png_const_structrp png_ptr, png_const_inforp info_ptr))
+#endif
+
+#  ifdef PNG_pHYs_SUPPORTED
+PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr,
+    png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y,
+    int *unit_type));
+#  endif /* PNG_pHYs_SUPPORTED */
+#endif  /* PNG_INCH_CONVERSIONS_SUPPORTED */
+
+/* Added in libpng-1.4.0 */
+#ifdef PNG_IO_STATE_SUPPORTED
+PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr));
+
+/* Removed from libpng 1.6; use png_get_io_chunk_type. */
+PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr),
+    PNG_DEPRECATED)
+
+PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type,
+    (png_const_structrp png_ptr));
+
+/* The flags returned by png_get_io_state() are the following: */
+#  define PNG_IO_NONE        0x0000   /* no I/O at this moment */
+#  define PNG_IO_READING     0x0001   /* currently reading */
+#  define PNG_IO_WRITING     0x0002   /* currently writing */
+#  define PNG_IO_SIGNATURE   0x0010   /* currently at the file signature */
+#  define PNG_IO_CHUNK_HDR   0x0020   /* currently at the chunk header */
+#  define PNG_IO_CHUNK_DATA  0x0040   /* currently at the chunk data */
+#  define PNG_IO_CHUNK_CRC   0x0080   /* currently at the chunk crc */
+#  define PNG_IO_MASK_OP     0x000f   /* current operation: reading/writing */
+#  define PNG_IO_MASK_LOC    0x00f0   /* current location: sig/hdr/data/crc */
+#endif /* ?PNG_IO_STATE_SUPPORTED */
+
+/* Interlace support.  The following macros are always defined so that if
+ * libpng interlace handling is turned off the macros may be used to handle
+ * interlaced images within the application.
+ */
+#define PNG_INTERLACE_ADAM7_PASSES 7
+
+/* Two macros to return the first row and first column of the original,
+ * full, image which appears in a given pass.  'pass' is in the range 0
+ * to 6 and the result is in the range 0 to 7.
+ */
+#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7)
+#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7)
+
+/* A macro to return the offset between pixels in the output row for a pair of
+ * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that
+ * follows.  Note that ROW_OFFSET is the offset from one row to the next whereas
+ * COL_OFFSET is from one column to the next, within a row.
+ */
+#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8)
+#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1))
+
+/* Two macros to help evaluate the number of rows or columns in each
+ * pass.  This is expressed as a shift - effectively log2 of the number or
+ * rows or columns in each 8x8 tile of the original image.
+ */
+#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3)
+#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3)
+
+/* Hence two macros to determine the number of rows or columns in a given
+ * pass of an image given its height or width.  In fact these macros may
+ * return non-zero even though the sub-image is empty, because the other
+ * dimension may be empty for a small image.
+ */
+#define PNG_PASS_ROWS(height, pass) (((height)+(((1<<PNG_PASS_ROW_SHIFT(pass))\
+   -1)-PNG_PASS_START_ROW(pass)))>>PNG_PASS_ROW_SHIFT(pass))
+#define PNG_PASS_COLS(width, pass) (((width)+(((1<<PNG_PASS_COL_SHIFT(pass))\
+   -1)-PNG_PASS_START_COL(pass)))>>PNG_PASS_COL_SHIFT(pass))
+
+/* For the reader row callbacks (both progressive and sequential) it is
+ * necessary to find the row in the output image given a row in an interlaced
+ * image, so two more macros:
+ */
+#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \
+   (((y_in)<<PNG_PASS_ROW_SHIFT(pass))+PNG_PASS_START_ROW(pass))
+#define PNG_COL_FROM_PASS_COL(x_in, pass) \
+   (((x_in)<<PNG_PASS_COL_SHIFT(pass))+PNG_PASS_START_COL(pass))
+
+/* Two macros which return a boolean (0 or 1) saying whether the given row
+ * or column is in a particular pass.  These use a common utility macro that
+ * returns a mask for a given pass - the offset 'off' selects the row or
+ * column version.  The mask has the appropriate bit set for each column in
+ * the tile.
+ */
+#define PNG_PASS_MASK(pass,off) ( \
+   ((0x110145AF>>(((7-(off))-(pass))<<2)) & 0xF) | \
+   ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0))
+
+#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \
+   ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1)
+#define PNG_COL_IN_INTERLACE_PASS(x, pass) \
+   ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1)
+
+#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED
+/* With these routines we avoid an integer divide, which will be slower on
+ * most machines.  However, it does take more operations than the corresponding
+ * divide method, so it may be slower on a few RISC systems.  There are two
+ * shifts (by 8 or 16 bits) and an addition, versus a single integer divide.
+ *
+ * Note that the rounding factors are NOT supposed to be the same!  128 and
+ * 32768 are correct for the NODIV code; 127 and 32767 are correct for the
+ * standard method.
+ *
+ * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ]
+ */
+
+ /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */
+
+#  define png_composite(composite, fg, alpha, bg)         \
+     { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \
+           * (png_uint_16)(alpha)                         \
+           + (png_uint_16)(bg)*(png_uint_16)(255          \
+           - (png_uint_16)(alpha)) + 128);                \
+       (composite) = (png_byte)((temp + (temp >> 8)) >> 8); }
+
+#  define png_composite_16(composite, fg, alpha, bg)       \
+     { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg)  \
+           * (png_uint_32)(alpha)                          \
+           + (png_uint_32)(bg)*(65535                      \
+           - (png_uint_32)(alpha)) + 32768);               \
+       (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); }
+
+#else  /* Standard method using integer division */
+
+#  define png_composite(composite, fg, alpha, bg)                          \
+     (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) +  \
+     (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) +       \
+     127) / 255)
+
+#  define png_composite_16(composite, fg, alpha, bg)                         \
+     (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \
+     (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) +         \
+     32767) / 65535)
+#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */
+
+#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
+PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf));
+PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf));
+PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf));
+#endif
+
+PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr,
+    png_const_bytep buf));
+/* No png_get_int_16 -- may be added if there's a real need for it. */
+
+/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */
+#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
+PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i));
+#endif
+#ifdef PNG_SAVE_INT_32_SUPPORTED
+PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i));
+#endif
+
+/* Place a 16-bit number into a buffer in PNG byte order.
+ * The parameter is declared unsigned int, not png_uint_16,
+ * just to avoid potential problems on pre-ANSI C compilers.
+ */
+#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
+PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
+/* No png_save_int_16 -- may be added if there's a real need for it. */
+#endif
+
+#ifdef PNG_USE_READ_MACROS
+/* Inline macros to do direct reads of bytes from the input buffer.
+ * The png_get_int_32() routine assumes we are using two's complement
+ * format for negative values, which is almost certainly true.
+ */
+#  define PNG_get_uint_32(buf) \
+     (((png_uint_32)(*(buf)) << 24) + \
+      ((png_uint_32)(*((buf) + 1)) << 16) + \
+      ((png_uint_32)(*((buf) + 2)) << 8) + \
+      ((png_uint_32)(*((buf) + 3))))
+
+   /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the
+    * function) incorrectly returned a value of type png_uint_32.
+    */
+#  define PNG_get_uint_16(buf) \
+     ((png_uint_16) \
+      (((unsigned int)(*(buf)) << 8) + \
+       ((unsigned int)(*((buf) + 1)))))
+
+#  define PNG_get_int_32(buf) \
+     ((png_int_32)((*(buf) & 0x80) \
+      ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \
+      : (png_int_32)png_get_uint_32(buf)))
+
+   /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h,
+    * but defining a macro name prefixed with PNG_PREFIX.
+    */
+#  ifndef PNG_PREFIX
+#     define png_get_uint_32(buf) PNG_get_uint_32(buf)
+#     define png_get_uint_16(buf) PNG_get_uint_16(buf)
+#     define png_get_int_32(buf)  PNG_get_int_32(buf)
+#  endif
+#else
+#  ifdef PNG_PREFIX
+      /* No macros; revert to the (redefined) function */
+#     define PNG_get_uint_32 (png_get_uint_32)
+#     define PNG_get_uint_16 (png_get_uint_16)
+#     define PNG_get_int_32  (png_get_int_32)
+#  endif
+#endif
+
+/*******************************************************************************
+ *  SIMPLIFIED API
+ *******************************************************************************
+ *
+ * Please read the documentation in libpng-manual.txt (TODO: write said
+ * documentation) if you don't understand what follows.
+ *
+ * The simplified API hides the details of both libpng and the PNG file format
+ * itself.  It allows PNG files to be read into a very limited number of
+ * in-memory bitmap formats or to be written from the same formats.  If these
+ * formats do not accomodate your needs then you can, and should, use the more
+ * sophisticated APIs above - these support a wide variety of in-memory formats
+ * and a wide variety of sophisticated transformations to those formats as well
+ * as a wide variety of APIs to manipulate ancillary information.
+ *
+ * To read a PNG file using the simplified API:
+ *
+ * 1) Declare a 'png_image' structure (see below) on the stack and set the
+ *    version field to PNG_IMAGE_VERSION.
+ * 2) Call the appropriate png_image_begin_read... function.
+ * 3) Set the png_image 'format' member to the required sample format.
+ * 4) Allocate a buffer for the image and, if required, the color-map.
+ * 5) Call png_image_finish_read to read the image and, if required, the
+ *    color-map into your buffers.
+ *
+ * There are no restrictions on the format of the PNG input itself; all valid
+ * color types, bit depths, and interlace methods are acceptable, and the
+ * input image is transformed as necessary to the requested in-memory format
+ * during the png_image_finish_read() step.  The only caveat is that if you
+ * request a color-mapped image from a PNG that is full-color or makes
+ * complex use of an alpha channel the transformation is extremely lossy and the
+ * result may look terrible.
+ *
+ * To write a PNG file using the simplified API:
+ *
+ * 1) Declare a 'png_image' structure on the stack and memset() it to all zero.
+ * 2) Initialize the members of the structure that describe the image, setting
+ *    the 'format' member to the format of the image samples.
+ * 3) Call the appropriate png_image_write... function with a pointer to the
+ *    image and, if necessary, the color-map to write the PNG data.
+ *
+ * png_image is a structure that describes the in-memory format of an image
+ * when it is being read or defines the in-memory format of an image that you
+ * need to write:
+ */
+#define PNG_IMAGE_VERSION 1
+
+typedef struct png_control *png_controlp;
+typedef struct
+{
+   png_controlp opaque;    /* Initialize to NULL, free with png_image_free */
+   png_uint_32  version;   /* Set to PNG_IMAGE_VERSION */
+   png_uint_32  width;     /* Image width in pixels (columns) */
+   png_uint_32  height;    /* Image height in pixels (rows) */
+   png_uint_32  format;    /* Image format as defined below */
+   png_uint_32  flags;     /* A bit mask containing informational flags */
+   png_uint_32  colormap_entries;
+                           /* Number of entries in the color-map */
+
+   /* In the event of an error or warning the following field will be set to a
+    * non-zero value and the 'message' field will contain a '\0' terminated
+    * string with the libpng error or warning message.  If both warnings and
+    * an error were encountered, only the error is recorded.  If there
+    * are multiple warnings, only the first one is recorded.
+    *
+    * The upper 30 bits of this value are reserved, the low two bits contain
+    * a value as follows:
+    */
+#  define PNG_IMAGE_WARNING 1
+#  define PNG_IMAGE_ERROR 2
+   /*
+    * The result is a two bit code such that a value more than 1 indicates
+    * a failure in the API just called:
+    *
+    *    0 - no warning or error
+    *    1 - warning
+    *    2 - error
+    *    3 - error preceded by warning
+    */
+#  define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1)
+
+   png_uint_32  warning_or_error;
+
+   char         message[64];
+} png_image, *png_imagep;
+
+/* The samples of the image have one to four channels whose components have
+ * original values in the range 0 to 1.0:
+ *
+ * 1: A single gray or luminance channel (G).
+ * 2: A gray/luminance channel and an alpha channel (GA).
+ * 3: Three red, green, blue color channels (RGB).
+ * 4: Three color channels and an alpha channel (RGBA).
+ *
+ * The components are encoded in one of two ways:
+ *
+ * a) As a small integer, value 0..255, contained in a single byte.  For the
+ * alpha channel the original value is simply value/255.  For the color or
+ * luminance channels the value is encoded according to the sRGB specification
+ * and matches the 8-bit format expected by typical display devices.
+ *
+ * The color/gray channels are not scaled (pre-multiplied) by the alpha
+ * channel and are suitable for passing to color management software.
+ *
+ * b) As a value in the range 0..65535, contained in a 2-byte integer.  All
+ * channels can be converted to the original value by dividing by 65535; all
+ * channels are linear.  Color channels use the RGB encoding (RGB end-points) of
+ * the sRGB specification.  This encoding is identified by the
+ * PNG_FORMAT_FLAG_LINEAR flag below.
+ *
+ * When the simplified API needs to convert between sRGB and linear colorspaces,
+ * the actual sRGB transfer curve defined in the sRGB specification (see the
+ * article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2
+ * approximation used elsewhere in libpng.
+ *
+ * When an alpha channel is present it is expected to denote pixel coverage
+ * of the color or luminance channels and is returned as an associated alpha
+ * channel: the color/gray channels are scaled (pre-multiplied) by the alpha
+ * value.
+ *
+ * The samples are either contained directly in the image data, between 1 and 8
+ * bytes per pixel according to the encoding, or are held in a color-map indexed
+ * by bytes in the image data.  In the case of a color-map the color-map entries
+ * are individual samples, encoded as above, and the image data has one byte per
+ * pixel to select the relevant sample from the color-map.
+ */
+
+/* PNG_FORMAT_*
+ *
+ * #defines to be used in png_image::format.  Each #define identifies a
+ * particular layout of sample data and, if present, alpha values.  There are
+ * separate defines for each of the two component encodings.
+ *
+ * A format is built up using single bit flag values.  All combinations are
+ * valid.  Formats can be built up from the flag values or you can use one of
+ * the predefined values below.  When testing formats always use the FORMAT_FLAG
+ * macros to test for individual features - future versions of the library may
+ * add new flags.
+ *
+ * When reading or writing color-mapped images the format should be set to the
+ * format of the entries in the color-map then png_image_{read,write}_colormap
+ * called to read or write the color-map and set the format correctly for the
+ * image data.  Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly!
+ *
+ * NOTE: libpng can be built with particular features disabled, if you see
+ * compiler errors because the definition of one of the following flags has been
+ * compiled out it is because libpng does not have the required support.  It is
+ * possible, however, for the libpng configuration to enable the format on just
+ * read or just write; in that case you may see an error at run time.  You can
+ * guard against this by checking for the definition of the appropriate
+ * "_SUPPORTED" macro, one of:
+ *
+ *    PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED
+ */
+#define PNG_FORMAT_FLAG_ALPHA    0x01U /* format with an alpha channel */
+#define PNG_FORMAT_FLAG_COLOR    0x02U /* color format: otherwise grayscale */
+#define PNG_FORMAT_FLAG_LINEAR   0x04U /* 2 byte channels else 1 byte */
+#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */
+
+#ifdef PNG_FORMAT_BGR_SUPPORTED
+#  define PNG_FORMAT_FLAG_BGR    0x10U /* BGR colors, else order is RGB */
+#endif
+
+#ifdef PNG_FORMAT_AFIRST_SUPPORTED
+#  define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */
+#endif
+
+/* Commonly used formats have predefined macros.
+ *
+ * First the single byte (sRGB) formats:
+ */
+#define PNG_FORMAT_GRAY 0
+#define PNG_FORMAT_GA   PNG_FORMAT_FLAG_ALPHA
+#define PNG_FORMAT_AG   (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST)
+#define PNG_FORMAT_RGB  PNG_FORMAT_FLAG_COLOR
+#define PNG_FORMAT_BGR  (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR)
+#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA)
+#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST)
+#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA)
+#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST)
+
+/* Then the linear 2-byte formats.  When naming these "Y" is used to
+ * indicate a luminance (gray) channel.
+ */
+#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR
+#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA)
+#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR)
+#define PNG_FORMAT_LINEAR_RGB_ALPHA \
+   (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA)
+
+/* With color-mapped formats the image data is one byte for each pixel, the byte
+ * is an index into the color-map which is formatted as above.  To obtain a
+ * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP
+ * to one of the above definitions, or you can use one of the definitions below.
+ */
+#define PNG_FORMAT_RGB_COLORMAP  (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_BGR_COLORMAP  (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP)
+#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP)
+
+/* PNG_IMAGE macros
+ *
+ * These are convenience macros to derive information from a png_image
+ * structure.  The PNG_IMAGE_SAMPLE_ macros return values appropriate to the
+ * actual image sample values - either the entries in the color-map or the
+ * pixels in the image.  The PNG_IMAGE_PIXEL_ macros return corresponding values
+ * for the pixels and will always return 1 for color-mapped formats.  The
+ * remaining macros return information about the rows in the image and the
+ * complete image.
+ *
+ * NOTE: All the macros that take a png_image::format parameter are compile time
+ * constants if the format parameter is, itself, a constant.  Therefore these
+ * macros can be used in array declarations and case labels where required.
+ * Similarly the macros are also pre-processor constants (sizeof is not used) so
+ * they can be used in #if tests.
+ *
+ * First the information about the samples.
+ */
+#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\
+   (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1)
+   /* Return the total number of channels in a given format: 1..4 */
+
+#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\
+   ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1)
+   /* Return the size in bytes of a single component of a pixel or color-map
+    * entry (as appropriate) in the image: 1 or 2.
+    */
+
+#define PNG_IMAGE_SAMPLE_SIZE(fmt)\
+   (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt))
+   /* This is the size of the sample data for one sample.  If the image is
+    * color-mapped it is the size of one color-map entry (and image pixels are
+    * one byte in size), otherwise it is the size of one image pixel.
+    */
+
+#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\
+   (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256)
+   /* The maximum size of the color-map required by the format expressed in a
+    * count of components.  This can be used to compile-time allocate a
+    * color-map:
+    *
+    * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)];
+    *
+    * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)];
+    *
+    * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the
+    * information from one of the png_image_begin_read_ APIs and dynamically
+    * allocate the required memory.
+    */
+
+/* Corresponding information about the pixels */
+#define PNG_IMAGE_PIXEL_(test,fmt)\
+   (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt))
+
+#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\
+   PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt)
+   /* The number of separate channels (components) in a pixel; 1 for a
+    * color-mapped image.
+    */
+
+#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\
+   PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt)
+   /* The size, in bytes, of each component in a pixel; 1 for a color-mapped
+    * image.
+    */
+
+#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt)
+   /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */
+
+/* Information about the whole row, or whole image */
+#define PNG_IMAGE_ROW_STRIDE(image)\
+   (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width)
+   /* Return the total number of components in a single row of the image; this
+    * is the minimum 'row stride', the minimum count of components between each
+    * row.  For a color-mapped image this is the minimum number of bytes in a
+    * row.
+    */
+
+#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\
+   (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride))
+   /* Return the size, in bytes, of an image buffer given a png_image and a row
+    * stride - the number of components to leave space for in each row.
+    */
+
+#define PNG_IMAGE_SIZE(image)\
+   PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image))
+   /* Return the size, in bytes, of the image in memory given just a png_image;
+    * the row stride is the minimum stride required for the image.
+    */
+
+#define PNG_IMAGE_COLORMAP_SIZE(image)\
+   (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries)
+   /* Return the size, in bytes, of the color-map of this image.  If the image
+    * format is not a color-map format this will return a size sufficient for
+    * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if
+    * you don't want to allocate a color-map in this case.
+    */
+
+/* PNG_IMAGE_FLAG_*
+ *
+ * Flags containing additional information about the image are held in the
+ * 'flags' field of png_image.
+ */
+#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01
+   /* This indicates the the RGB values of the in-memory bitmap do not
+    * correspond to the red, green and blue end-points defined by sRGB.
+    */
+
+#define PNG_IMAGE_FLAG_FAST 0x02
+   /* On write emphasise speed over compression; the resultant PNG file will be
+    * larger but will be produced significantly faster, particular for large
+    * images.  Do not use this option for images which will be distributed, only
+    * used it when producing intermediate files that will be read back in
+    * repeatedly.  For a typical 24-bit image the option will double the read
+    * speed at the cost of increasing the image size by 25%, however for many
+    * more compressible images the PNG file can be 10 times larger with only a
+    * slight speed gain.
+    */
+
+#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04
+   /* On read if the image is a 16-bit per component image and there is no gAMA
+    * or sRGB chunk assume that the components are sRGB encoded.  Notice that
+    * images output by the simplified API always have gamma information; setting
+    * this flag only affects the interpretation of 16-bit images from an
+    * external source.  It is recommended that the application expose this flag
+    * to the user; the user can normally easily recognize the difference between
+    * linear and sRGB encoding.  This flag has no effect on write - the data
+    * passed to the write APIs must have the correct encoding (as defined
+    * above.)
+    *
+    * If the flag is not set (the default) input 16-bit per component data is
+    * assumed to be linear.
+    *
+    * NOTE: the flag can only be set after the png_image_begin_read_ call,
+    * because that call initializes the 'flags' field.
+    */
+
+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
+/* READ APIs
+ * ---------
+ *
+ * The png_image passed to the read APIs must have been initialized by setting
+ * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.)
+ */
+#ifdef PNG_STDIO_SUPPORTED
+PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
+   const char *file_name));
+   /* The named file is opened for read and the image header is filled in
+    * from the PNG header in the file.
+    */
+
+PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,
+   FILE* file));
+   /* The PNG header is read from the stdio FILE object. */
+#endif /* PNG_STDIO_SUPPORTED */
+
+PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image,
+   png_const_voidp memory, png_size_t size));
+   /* The PNG header is read from the given memory buffer. */
+
+PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image,
+   png_const_colorp background, void *buffer, png_int_32 row_stride,
+   void *colormap));
+   /* Finish reading the image into the supplied buffer and clean up the
+    * png_image structure.
+    *
+    * row_stride is the step, in byte or 2-byte units as appropriate,
+    * between adjacent rows.  A positive stride indicates that the top-most row
+    * is first in the buffer - the normal top-down arrangement.  A negative
+    * stride indicates that the bottom-most row is first in the buffer.
+    *
+    * background need only be supplied if an alpha channel must be removed from
+    * a png_byte format and the removal is to be done by compositing on a solid
+    * color; otherwise it may be NULL and any composition will be done directly
+    * onto the buffer.  The value is an sRGB color to use for the background,
+    * for grayscale output the green channel is used.
+    *
+    * background must be supplied when an alpha channel must be removed from a
+    * single byte color-mapped output format, in other words if:
+    *
+    * 1) The original format from png_image_begin_read_from_* had
+    *    PNG_FORMAT_FLAG_ALPHA set.
+    * 2) The format set by the application does not.
+    * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and
+    *    PNG_FORMAT_FLAG_LINEAR *not* set.
+    *
+    * For linear output removing the alpha channel is always done by compositing
+    * on black and background is ignored.
+    *
+    * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set.  It must
+    * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE.
+    * image->colormap_entries will be updated to the actual number of entries
+    * written to the colormap; this may be less than the original value.
+    */
+
+PNG_EXPORT(238, void, png_image_free, (png_imagep image));
+   /* Free any data allocated by libpng in image->opaque, setting the pointer to
+    * NULL.  May be called at any time after the structure is initialized.
+    */
+#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */
+
+#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+#ifdef PNG_STDIO_SUPPORTED
+/* WRITE APIS
+ * ----------
+ * For write you must initialize a png_image structure to describe the image to
+ * be written.  To do this use memset to set the whole structure to 0 then
+ * initialize fields describing your image.
+ *
+ * version: must be set to PNG_IMAGE_VERSION
+ * opaque: must be initialized to NULL
+ * width: image width in pixels
+ * height: image height in rows
+ * format: the format of the data (image and color-map) you wish to write
+ * flags: set to 0 unless one of the defined flags applies; set
+ *    PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB
+ *    values do not correspond to the colors in sRGB.
+ * colormap_entries: set to the number of entries in the color-map (0 to 256)
+ */
+PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
+   const char *file, int convert_to_8bit, const void *buffer,
+   png_int_32 row_stride, const void *colormap));
+   /* Write the image to the named file. */
+
+PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
+   int convert_to_8_bit, const void *buffer, png_int_32 row_stride,
+   const void *colormap));
+   /* Write the image to the given (FILE*). */
+
+/* With both write APIs if image is in one of the linear formats with 16-bit
+ * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG
+ * gamma encoded according to the sRGB specification, otherwise a 16-bit linear
+ * encoded PNG file is written.
+ *
+ * With color-mapped data formats the colormap parameter point to a color-map
+ * with at least image->colormap_entries encoded in the specified format.  If
+ * the format is linear the written PNG color-map will be converted to sRGB
+ * regardless of the convert_to_8_bit flag.
+ *
+ * With all APIs row_stride is handled as in the read APIs - it is the spacing
+ * from one row to the next in component sized units (1 or 2 bytes) and if
+ * negative indicates a bottom-up row layout in the buffer.
+ *
+ * Note that the write API does not support interlacing or sub-8-bit pixels.
+ */
+#endif /* PNG_STDIO_SUPPORTED */
+#endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */
+/*******************************************************************************
+ *  END OF SIMPLIFIED API
+ ******************************************************************************/
+
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+PNG_EXPORT(242, void, png_set_check_for_invalid_index,
+    (png_structrp png_ptr, int allowed));
+#  ifdef PNG_GET_PALETTE_MAX_SUPPORTED
+PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr,
+    png_const_infop info_ptr));
+#  endif
+#endif /* CHECK_FOR_INVALID_INDEX */
+
+/*******************************************************************************
+ *  IMPLEMENTATION OPTIONS
+ *******************************************************************************
+ *
+ * Support for arbitrary implementation-specific optimizations.  The API allows
+ * particular options to be turned on or off.  'Option' is the number of the
+ * option and 'onoff' is 0 (off) or non-0 (on).  The value returned is given
+ * by the PNG_OPTION_ defines below.
+ *
+ * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions,
+ *           are detected at run time, however sometimes it may be impossible
+ *           to do this in user mode, in which case it is necessary to discover
+ *           the capabilities in an OS specific way.  Such capabilities are
+ *           listed here when libpng has support for them and must be turned
+ *           ON by the application if present.
+ *
+ * SOFTWARE: sometimes software optimizations actually result in performance
+ *           decrease on some architectures or systems, or with some sets of
+ *           PNG images.  'Software' options allow such optimizations to be
+ *           selected at run time.
+ */
+#ifdef PNG_SET_OPTION_SUPPORTED
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+#  define PNG_ARM_NEON   0 /* HARDWARE: ARM Neon SIMD instructions supported */
+#endif
+#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
+#define PNG_OPTION_NEXT  4 /* Next option - numbers must be even */
+
+/* Return values: NOTE: there are four values and 'off' is *not* zero */
+#define PNG_OPTION_UNSET   0 /* Unset - defaults to off */
+#define PNG_OPTION_INVALID 1 /* Option number out of range */
+#define PNG_OPTION_OFF     2
+#define PNG_OPTION_ON      3
+
+PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
+   int onoff));
+#endif
+
+/*******************************************************************************
+ *  END OF HARDWARE OPTIONS
+ ******************************************************************************/
+
+/* Maintainer: Put new public prototypes here ^, in libpng.3, and project
+ * defs, scripts/pnglibconf.h, and scripts/pnglibconf.h.prebuilt
+ */
+
+/* The last ordinal number (this is the *last* one already used; the next
+ * one to use is one more than this.)  Maintainer, remember to add an entry to
+ * scripts/symbols.def as well.
+ */
+#ifdef PNG_EXPORT_LAST_ORDINAL
+  PNG_EXPORT_LAST_ORDINAL(244);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PNG_VERSION_INFO_ONLY */
+/* Do not put anything past this line */
+#endif /* PNG_H */
diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pngconf.h b/core/src/fxcodec/fx_lpng/lpng_v163/pngconf.h
new file mode 100644
index 0000000..02f74e2
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/pngconf.h
@@ -0,0 +1,617 @@
+

+/* pngconf.h - machine configurable file for libpng

+ *

+ * libpng version 1.6.3 - July 18, 2013

+ *

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ *

+ */

+

+/* Any machine specific code is near the front of this file, so if you

+ * are configuring libpng for a machine, you may want to read the section

+ * starting here down to where it starts to typedef png_color, png_text,

+ * and png_info.

+ */

+

+#ifndef PNGCONF_H

+#define PNGCONF_H

+

+/* To do: Do all of this in scripts/pnglibconf.dfa */

+#ifdef PNG_SAFE_LIMITS_SUPPORTED

+#  ifdef PNG_USER_WIDTH_MAX

+#    undef PNG_USER_WIDTH_MAX

+#    define PNG_USER_WIDTH_MAX 1000000L

+#  endif

+#  ifdef PNG_USER_HEIGHT_MAX

+#    undef PNG_USER_HEIGHT_MAX

+#    define PNG_USER_HEIGHT_MAX 1000000L

+#  endif

+#  ifdef PNG_USER_CHUNK_MALLOC_MAX

+#    undef PNG_USER_CHUNK_MALLOC_MAX

+#    define PNG_USER_CHUNK_MALLOC_MAX 4000000L

+#  endif

+#  ifdef PNG_USER_CHUNK_CACHE_MAX

+#    undef PNG_USER_CHUNK_CACHE_MAX

+#    define PNG_USER_CHUNK_CACHE_MAX 128

+#  endif

+#endif

+

+#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */

+

+/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C

+ * compiler for correct compilation.  The following header files are required by

+ * the standard.  If your compiler doesn't provide these header files, or they

+ * do not match the standard, you will need to provide/improve them.

+ */

+#include <limits.h>

+#include <stddef.h>

+

+/* Library header files.  These header files are all defined by ISOC90; libpng

+ * expects conformant implementations, however, an ISOC90 conformant system need

+ * not provide these header files if the functionality cannot be implemented.

+ * In this case it will be necessary to disable the relevant parts of libpng in

+ * the build of pnglibconf.h.

+ *

+ * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not

+ * include this unnecessary header file.

+ */

+

+#ifdef PNG_STDIO_SUPPORTED

+   /* Required for the definition of FILE: */

+#  include <stdio.h>

+#endif

+

+#ifdef PNG_SETJMP_SUPPORTED

+   /* Required for the definition of jmp_buf and the declaration of longjmp: */

+#  include <setjmp.h>

+#endif

+

+#ifdef PNG_CONVERT_tIME_SUPPORTED

+   /* Required for struct tm: */

+#  include <time.h>

+#endif

+

+#endif /* PNG_BUILDING_SYMBOL_TABLE */

+

+/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using

+ * PNG_NO_CONST; this is no longer supported except for data declarations which

+ * apparently still cause problems in 2011 on some compilers.

+ */

+#define PNG_CONST const /* backward compatibility only */

+

+/* This controls optimization of the reading of 16 and 32 bit values

+ * from PNG files.  It can be set on a per-app-file basis - it

+ * just changes whether a macro is used when the function is called.

+ * The library builder sets the default; if read functions are not

+ * built into the library the macro implementation is forced on.

+ */

+#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED

+#  define PNG_USE_READ_MACROS

+#endif

+#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS)

+#  if PNG_DEFAULT_READ_MACROS

+#    define PNG_USE_READ_MACROS

+#  endif

+#endif

+

+/* COMPILER SPECIFIC OPTIONS.

+ *

+ * These options are provided so that a variety of difficult compilers

+ * can be used.  Some are fixed at build time (e.g. PNG_API_RULE

+ * below) but still have compiler specific implementations, others

+ * may be changed on a per-file basis when compiling against libpng.

+ */

+

+/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect

+ * against legacy (pre ISOC90) compilers that did not understand function

+ * prototypes.  It is not required for modern C compilers.

+ */

+#ifndef PNGARG

+#  define PNGARG(arglist) arglist

+#endif

+

+/* Function calling conventions.

+ * =============================

+ * Normally it is not necessary to specify to the compiler how to call

+ * a function - it just does it - however on x86 systems derived from

+ * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems

+ * and some others) there are multiple ways to call a function and the

+ * default can be changed on the compiler command line.  For this reason

+ * libpng specifies the calling convention of every exported function and

+ * every function called via a user supplied function pointer.  This is

+ * done in this file by defining the following macros:

+ *

+ * PNGAPI    Calling convention for exported functions.

+ * PNGCBAPI  Calling convention for user provided (callback) functions.

+ * PNGCAPI   Calling convention used by the ANSI-C library (required

+ *           for longjmp callbacks and sometimes used internally to

+ *           specify the calling convention for zlib).

+ *

+ * These macros should never be overridden.  If it is necessary to

+ * change calling convention in a private build this can be done

+ * by setting PNG_API_RULE (which defaults to 0) to one of the values

+ * below to select the correct 'API' variants.

+ *

+ * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout.

+ *                This is correct in every known environment.

+ * PNG_API_RULE=1 Use the operating system convention for PNGAPI and

+ *                the 'C' calling convention (from PNGCAPI) for

+ *                callbacks (PNGCBAPI).  This is no longer required

+ *                in any known environment - if it has to be used

+ *                please post an explanation of the problem to the

+ *                libpng mailing list.

+ *

+ * These cases only differ if the operating system does not use the C

+ * calling convention, at present this just means the above cases

+ * (x86 DOS/Windows sytems) and, even then, this does not apply to

+ * Cygwin running on those systems.

+ *

+ * Note that the value must be defined in pnglibconf.h so that what

+ * the application uses to call the library matches the conventions

+ * set when building the library.

+ */

+

+/* Symbol export

+ * =============

+ * When building a shared library it is almost always necessary to tell

+ * the compiler which symbols to export.  The png.h macro 'PNG_EXPORT'

+ * is used to mark the symbols.  On some systems these symbols can be

+ * extracted at link time and need no special processing by the compiler,

+ * on other systems the symbols are flagged by the compiler and just

+ * the declaration requires a special tag applied (unfortunately) in a

+ * compiler dependent way.  Some systems can do either.

+ *

+ * A small number of older systems also require a symbol from a DLL to

+ * be flagged to the program that calls it.  This is a problem because

+ * we do not know in the header file included by application code that

+ * the symbol will come from a shared library, as opposed to a statically

+ * linked one.  For this reason the application must tell us by setting

+ * the magic flag PNG_USE_DLL to turn on the special processing before

+ * it includes png.h.

+ *

+ * Four additional macros are used to make this happen:

+ *

+ * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from

+ *            the build or imported if PNG_USE_DLL is set - compiler

+ *            and system specific.

+ *

+ * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to

+ *                       'type', compiler specific.

+ *

+ * PNG_DLL_EXPORT Set to the magic to use during a libpng build to

+ *                make a symbol exported from the DLL.  Not used in the

+ *                public header files; see pngpriv.h for how it is used

+ *                in the libpng build.

+ *

+ * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come

+ *                from a DLL - used to define PNG_IMPEXP when

+ *                PNG_USE_DLL is set.

+ */

+

+/* System specific discovery.

+ * ==========================

+ * This code is used at build time to find PNG_IMPEXP, the API settings

+ * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL

+ * import processing is possible.  On Windows systems it also sets

+ * compiler-specific macros to the values required to change the calling

+ * conventions of the various functions.

+ */

+#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\

+    defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)

+  /* Windows system (DOS doesn't support DLLs).  Includes builds under Cygwin or

+   * MinGW on any architecture currently supported by Windows.  Also includes

+   * Watcom builds but these need special treatment because they are not

+   * compatible with GCC or Visual C because of different calling conventions.

+   */

+#  if PNG_API_RULE == 2

+    /* If this line results in an error, either because __watcall is not

+     * understood or because of a redefine just below you cannot use *this*

+     * build of the library with the compiler you are using.  *This* build was

+     * build using Watcom and applications must also be built using Watcom!

+     */

+#    define PNGCAPI __watcall

+#  endif

+

+#  if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800))

+#    define PNGCAPI __cdecl

+#    if PNG_API_RULE == 1

+       /* If this line results in an error __stdcall is not understood and

+        * PNG_API_RULE should not have been set to '1'.

+        */

+#      define PNGAPI __stdcall

+#    endif

+#  else

+    /* An older compiler, or one not detected (erroneously) above,

+     * if necessary override on the command line to get the correct

+     * variants for the compiler.

+     */

+#    ifndef PNGCAPI

+#      define PNGCAPI _cdecl

+#    endif

+#    if PNG_API_RULE == 1 && !defined(PNGAPI)

+#      define PNGAPI _stdcall

+#    endif

+#  endif /* compiler/api */

+

+  /* NOTE: PNGCBAPI always defaults to PNGCAPI. */

+

+#  if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)

+#     error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed"

+#  endif

+

+#  if (defined(_MSC_VER) && _MSC_VER < 800) ||\

+      (defined(__BORLANDC__) && __BORLANDC__ < 0x500)

+    /* older Borland and MSC

+     * compilers used '__export' and required this to be after

+     * the type.

+     */

+#    ifndef PNG_EXPORT_TYPE

+#      define PNG_EXPORT_TYPE(type) type PNG_IMPEXP

+#    endif

+#    define PNG_DLL_EXPORT __export

+#  else /* newer compiler */

+#    define PNG_DLL_EXPORT __declspec(dllexport)

+#    ifndef PNG_DLL_IMPORT

+#      define PNG_DLL_IMPORT __declspec(dllimport)

+#    endif

+#  endif /* compiler */

+

+#else /* !Windows */

+#  if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)

+#    define PNGAPI _System

+#  else /* !Windows/x86 && !OS/2 */

+    /* Use the defaults, or define PNG*API on the command line (but

+     * this will have to be done for every compile!)

+     */

+#  endif /* other system, !OS/2 */

+#endif /* !Windows/x86 */

+

+/* Now do all the defaulting . */

+#ifndef PNGCAPI

+#  define PNGCAPI

+#endif

+#ifndef PNGCBAPI

+#  define PNGCBAPI PNGCAPI

+#endif

+#ifndef PNGAPI

+#  define PNGAPI PNGCAPI

+#endif

+

+/* PNG_IMPEXP may be set on the compilation system command line or (if not set)

+ * then in an internal header file when building the library, otherwise (when

+ * using the library) it is set here.

+ */

+#ifndef PNG_IMPEXP

+#  if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT)

+     /* This forces use of a DLL, disallowing static linking */

+#    define PNG_IMPEXP PNG_DLL_IMPORT

+#  endif

+

+#  ifndef PNG_IMPEXP

+#    define PNG_IMPEXP

+#  endif

+#endif

+

+/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat

+ * 'attributes' as a storage class - the attributes go at the start of the

+ * function definition, and attributes are always appended regardless of the

+ * compiler.  This considerably simplifies these macros but may cause problems

+ * if any compilers both need function attributes and fail to handle them as

+ * a storage class (this is unlikely.)

+ */

+#ifndef PNG_FUNCTION

+#  define PNG_FUNCTION(type, name, args, attributes) attributes type name args

+#endif

+

+#ifndef PNG_EXPORT_TYPE

+#  define PNG_EXPORT_TYPE(type) PNG_IMPEXP type

+#endif

+

+   /* The ordinal value is only relevant when preprocessing png.h for symbol

+    * table entries, so we discard it here.  See the .dfn files in the

+    * scripts directory.

+    */

+#ifndef PNG_EXPORTA

+

+#  define PNG_EXPORTA(ordinal, type, name, args, attributes)\

+      PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \

+        extern attributes)

+#endif

+

+/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument,

+ * so make something non-empty to satisfy the requirement:

+ */

+#define PNG_EMPTY /*empty list*/

+

+#define PNG_EXPORT(ordinal, type, name, args)\

+   PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY)

+

+/* Use PNG_REMOVED to comment out a removed interface. */

+#ifndef PNG_REMOVED

+#  define PNG_REMOVED(ordinal, type, name, args, attributes)

+#endif

+

+#ifndef PNG_CALLBACK

+#  define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args)

+#endif

+

+/* Support for compiler specific function attributes.  These are used

+ * so that where compiler support is available incorrect use of API

+ * functions in png.h will generate compiler warnings.

+ *

+ * Added at libpng-1.2.41.

+ */

+

+#ifndef PNG_NO_PEDANTIC_WARNINGS

+#  ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED

+#    define PNG_PEDANTIC_WARNINGS_SUPPORTED

+#  endif

+#endif

+

+#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED

+  /* Support for compiler specific function attributes.  These are used

+   * so that where compiler support is available, incorrect use of API

+   * functions in png.h will generate compiler warnings.  Added at libpng

+   * version 1.2.41.  Disabling these removes the warnings but may also produce

+   * less efficient code.

+   */

+#  if defined(__GNUC__)

+#    ifndef PNG_USE_RESULT

+#      define PNG_USE_RESULT __attribute__((__warn_unused_result__))

+#    endif

+#    ifndef PNG_NORETURN

+#      define PNG_NORETURN   __attribute__((__noreturn__))

+#    endif

+#    if __GNUC__ >= 3

+#      ifndef PNG_ALLOCATED

+#        define PNG_ALLOCATED  __attribute__((__malloc__))

+#      endif

+#      ifndef PNG_DEPRECATED

+#        define PNG_DEPRECATED __attribute__((__deprecated__))

+#      endif

+#      ifndef PNG_PRIVATE

+#        if 0 /* Doesn't work so we use deprecated instead*/

+#          define PNG_PRIVATE \

+            __attribute__((warning("This function is not exported by libpng.")))

+#        else

+#          define PNG_PRIVATE \

+            __attribute__((__deprecated__))

+#        endif

+#      endif

+#      if ((__GNUC__ != 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1))

+#        ifndef PNG_RESTRICT

+#          define PNG_RESTRICT __restrict

+#        endif

+#      endif /*  __GNUC__ == 3.0 */

+#    endif /*  __GNUC__ >= 3 */

+

+#  elif defined(_MSC_VER)  && (_MSC_VER >= 1300)

+#    ifndef PNG_USE_RESULT

+#      define PNG_USE_RESULT /* not supported */

+#    endif

+#    ifndef PNG_NORETURN

+#      define PNG_NORETURN   __declspec(noreturn)

+#    endif

+#    ifndef PNG_ALLOCATED

+#      if (_MSC_VER >= 1400)

+#        define PNG_ALLOCATED __declspec(restrict)

+#      endif

+#    endif

+#    ifndef PNG_DEPRECATED

+#      define PNG_DEPRECATED __declspec(deprecated)

+#    endif

+#    ifndef PNG_PRIVATE

+#      define PNG_PRIVATE __declspec(deprecated)

+#    endif

+#    ifndef PNG_RESTRICT

+#      if (_MSC_VER >= 1400)

+#        define PNG_RESTRICT __restrict

+#      endif

+#    endif

+

+#  elif defined(__WATCOMC__)

+#    ifndef PNG_RESTRICT

+#      define PNG_RESTRICT __restrict

+#    endif

+#  endif /* _MSC_VER */

+#endif /* PNG_PEDANTIC_WARNINGS */

+

+#ifndef PNG_DEPRECATED

+#  define PNG_DEPRECATED  /* Use of this function is deprecated */

+#endif

+#ifndef PNG_USE_RESULT

+#  define PNG_USE_RESULT  /* The result of this function must be checked */

+#endif

+#ifndef PNG_NORETURN

+#  define PNG_NORETURN    /* This function does not return */

+#endif

+#ifndef PNG_ALLOCATED

+#  define PNG_ALLOCATED   /* The result of the function is new memory */

+#endif

+#ifndef PNG_PRIVATE

+#  define PNG_PRIVATE     /* This is a private libpng function */

+#endif

+#ifndef PNG_RESTRICT

+#  define PNG_RESTRICT    /* The C99 "restrict" feature */

+#endif

+#ifndef PNG_FP_EXPORT     /* A floating point API. */

+#  ifdef PNG_FLOATING_POINT_SUPPORTED

+#     define PNG_FP_EXPORT(ordinal, type, name, args)\

+         PNG_EXPORT(ordinal, type, name, args);

+#  else                   /* No floating point APIs */

+#     define PNG_FP_EXPORT(ordinal, type, name, args)

+#  endif

+#endif

+#ifndef PNG_FIXED_EXPORT  /* A fixed point API. */

+#  ifdef PNG_FIXED_POINT_SUPPORTED

+#     define PNG_FIXED_EXPORT(ordinal, type, name, args)\

+         PNG_EXPORT(ordinal, type, name, args);

+#  else                   /* No fixed point APIs */

+#     define PNG_FIXED_EXPORT(ordinal, type, name, args)

+#  endif

+#endif

+

+#ifndef PNG_BUILDING_SYMBOL_TABLE

+/* Some typedefs to get us started.  These should be safe on most of the common

+ * platforms.

+ *

+ * png_uint_32 and png_int_32 may, currently, be larger than required to hold a

+ * 32-bit value however this is not normally advisable.

+ *

+ * png_uint_16 and png_int_16 should always be two bytes in size - this is

+ * verified at library build time.

+ *

+ * png_byte must always be one byte in size.

+ *

+ * The checks below use constants from limits.h, as defined by the ISOC90

+ * standard.

+ */

+#if CHAR_BIT == 8 && UCHAR_MAX == 255

+   typedef unsigned char png_byte;

+#else

+#  error "libpng requires 8 bit bytes"

+#endif

+

+#if INT_MIN == -32768 && INT_MAX == 32767

+   typedef int png_int_16;

+#elif SHRT_MIN == -32768 && SHRT_MAX == 32767

+   typedef short png_int_16;

+#else

+#  error "libpng requires a signed 16 bit type"

+#endif

+

+#if UINT_MAX == 65535

+   typedef unsigned int png_uint_16;

+#elif USHRT_MAX == 65535

+   typedef unsigned short png_uint_16;

+#else

+#  error "libpng requires an unsigned 16 bit type"

+#endif

+

+#if INT_MIN < -2147483646 && INT_MAX > 2147483646

+   typedef int png_int_32;

+#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646

+   typedef long int png_int_32;

+#else

+#  error "libpng requires a signed 32 bit (or more) type"

+#endif

+

+#if UINT_MAX > 4294967294

+   typedef unsigned int png_uint_32;

+#elif ULONG_MAX > 4294967294

+   typedef unsigned long int png_uint_32;

+#else

+#  error "libpng requires an unsigned 32 bit (or more) type"

+#endif

+

+/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however,

+ * requires an ISOC90 compiler and relies on consistent behavior of sizeof.

+ */

+typedef size_t png_size_t;

+typedef ptrdiff_t png_ptrdiff_t;

+

+/* libpng needs to know the maximum value of 'size_t' and this controls the

+ * definition of png_alloc_size_t, below.  This maximum value of size_t limits

+ * but does not control the maximum allocations the library makes - there is

+ * direct application control of this through png_set_user_limits().

+ */

+#ifndef PNG_SMALL_SIZE_T

+   /* Compiler specific tests for systems where size_t is known to be less than

+    * 32 bits (some of these systems may no longer work because of the lack of

+    * 'far' support; see above.)

+    */

+#  if (defined(__TURBOC__) && !defined(__FLAT__)) ||\

+   (defined(_MSC_VER) && defined(MAXSEG_64K))

+#     define PNG_SMALL_SIZE_T

+#  endif

+#endif

+

+/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no

+ * smaller than png_uint_32.  Casts from png_size_t or png_uint_32 to

+ * png_alloc_size_t are not necessary; in fact, it is recommended not to use

+ * them at all so that the compiler can complain when something turns out to be

+ * problematic.

+ *

+ * Casts in the other direction (from png_alloc_size_t to png_size_t or

+ * png_uint_32) should be explicitly applied; however, we do not expect to

+ * encounter practical situations that require such conversions.

+ *

+ * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than

+ * 4294967295 - i.e. less than the maximum value of png_uint_32.

+ */

+#ifdef PNG_SMALL_SIZE_T

+   typedef png_uint_32 png_alloc_size_t;

+#else

+   typedef png_size_t png_alloc_size_t;

+#endif

+

+/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler

+ * implementations of Intel CPU specific support of user-mode segmented address

+ * spaces, where 16-bit pointers address more than 65536 bytes of memory using

+ * separate 'segment' registers.  The implementation requires two different

+ * types of pointer (only one of which includes the segment value.)

+ *

+ * If required this support is available in version 1.2 of libpng and may be

+ * available in versions through 1.5, although the correctness of the code has

+ * not been verified recently.

+ */

+

+/* Typedef for floating-point numbers that are converted to fixed-point with a

+ * multiple of 100,000, e.g., gamma

+ */

+typedef png_int_32 png_fixed_point;

+

+/* Add typedefs for pointers */

+typedef void                  * png_voidp;

+typedef const void            * png_const_voidp;

+typedef png_byte              * png_bytep;

+typedef const png_byte        * png_const_bytep;

+typedef png_uint_32           * png_uint_32p;

+typedef const png_uint_32     * png_const_uint_32p;

+typedef png_int_32            * png_int_32p;

+typedef const png_int_32      * png_const_int_32p;

+typedef png_uint_16           * png_uint_16p;

+typedef const png_uint_16     * png_const_uint_16p;

+typedef png_int_16            * png_int_16p;

+typedef const png_int_16      * png_const_int_16p;

+typedef char                  * png_charp;

+typedef const char            * png_const_charp;

+typedef png_fixed_point       * png_fixed_point_p;

+typedef const png_fixed_point * png_const_fixed_point_p;

+typedef png_size_t            * png_size_tp;

+typedef const png_size_t      * png_const_size_tp;

+

+#ifdef PNG_STDIO_SUPPORTED

+typedef FILE            * png_FILE_p;

+#endif

+

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+typedef double       * png_doublep;

+typedef const double * png_const_doublep;

+#endif

+

+/* Pointers to pointers; i.e. arrays */

+typedef png_byte        * * png_bytepp;

+typedef png_uint_32     * * png_uint_32pp;

+typedef png_int_32      * * png_int_32pp;

+typedef png_uint_16     * * png_uint_16pp;

+typedef png_int_16      * * png_int_16pp;

+typedef const char      * * png_const_charpp;

+typedef char            * * png_charpp;

+typedef png_fixed_point * * png_fixed_point_pp;

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+typedef double          * * png_doublepp;

+#endif

+

+/* Pointers to pointers to pointers; i.e., pointer to array */

+typedef char            * * * png_charppp;

+

+#endif /* PNG_BUILDING_SYMBOL_TABLE */

+

+#endif /* PNGCONF_H */

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pngdebug.h b/core/src/fxcodec/fx_lpng/lpng_v163/pngdebug.h
new file mode 100644
index 0000000..96c1ea4
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/pngdebug.h
@@ -0,0 +1,157 @@
+

+/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c

+ *

+ * Copyright (c) 1998-2011 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * Last changed in libpng 1.5.0 [January 6, 2011]

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+

+/* Define PNG_DEBUG at compile time for debugging information.  Higher

+ * numbers for PNG_DEBUG mean more debugging information.  This has

+ * only been added since version 0.95 so it is not implemented throughout

+ * libpng yet, but more support will be added as needed.

+ *

+ * png_debug[1-2]?(level, message ,arg{0-2})

+ *   Expands to a statement (either a simple expression or a compound

+ *   do..while(0) statement) that outputs a message with parameter

+ *   substitution if PNG_DEBUG is defined to 2 or more.  If PNG_DEBUG

+ *   is undefined, 0 or 1 every png_debug expands to a simple expression

+ *   (actually ((void)0)).

+ *

+ *   level: level of detail of message, starting at 0.  A level 'n'

+ *          message is preceded by 'n' tab characters (not implemented

+ *          on Microsoft compilers unless PNG_DEBUG_FILE is also

+ *          defined, to allow debug DLL compilation with no standard IO).

+ *   message: a printf(3) style text string.  A trailing '\n' is added

+ *            to the message.

+ *   arg: 0 to 2 arguments for printf(3) style substitution in message.

+ */

+#ifndef PNGDEBUG_H

+#define PNGDEBUG_H

+/* These settings control the formatting of messages in png.c and pngerror.c */

+/* Moved to pngdebug.h at 1.5.0 */

+#  ifndef PNG_LITERAL_SHARP

+#    define PNG_LITERAL_SHARP 0x23

+#  endif

+#  ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET

+#    define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b

+#  endif

+#  ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET

+#    define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d

+#  endif

+#  ifndef PNG_STRING_NEWLINE

+#    define PNG_STRING_NEWLINE "\n"

+#  endif

+

+#ifdef PNG_DEBUG

+#  if (PNG_DEBUG > 0)

+#    if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER)

+#      include <crtdbg.h>

+#      if (PNG_DEBUG > 1)

+#        ifndef _DEBUG

+#          define _DEBUG

+#        endif

+#        ifndef png_debug

+#          define png_debug(l,m)  _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE)

+#        endif

+#        ifndef png_debug1

+#          define png_debug1(l,m,p1)  _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1)

+#        endif

+#        ifndef png_debug2

+#          define png_debug2(l,m,p1,p2) \

+             _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2)

+#        endif

+#      endif

+#    else /* PNG_DEBUG_FILE || !_MSC_VER */

+#      ifndef PNG_STDIO_SUPPORTED

+#        include <stdio.h> /* not included yet */

+#      endif

+#      ifndef PNG_DEBUG_FILE

+#        define PNG_DEBUG_FILE stderr

+#      endif /* PNG_DEBUG_FILE */

+

+#      if (PNG_DEBUG > 1)

+/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on

+ * non-ISO compilers

+ */

+#        ifdef __STDC__

+#          ifndef png_debug

+#            define png_debug(l,m) \

+       do { \

+       int num_tabs=l; \

+       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \

+         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \

+       } while (0)

+#          endif

+#          ifndef png_debug1

+#            define png_debug1(l,m,p1) \

+       do { \

+       int num_tabs=l; \

+       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \

+         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \

+       } while (0)

+#          endif

+#          ifndef png_debug2

+#            define png_debug2(l,m,p1,p2) \

+       do { \

+       int num_tabs=l; \

+       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \

+         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \

+       } while (0)

+#          endif

+#        else /* __STDC __ */

+#          ifndef png_debug

+#            define png_debug(l,m) \

+       do { \

+       int num_tabs=l; \

+       char format[256]; \

+       snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \

+         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \

+         m,PNG_STRING_NEWLINE); \

+       fprintf(PNG_DEBUG_FILE,format); \

+       } while (0)

+#          endif

+#          ifndef png_debug1

+#            define png_debug1(l,m,p1) \

+       do { \

+       int num_tabs=l; \

+       char format[256]; \

+       snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \

+         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \

+         m,PNG_STRING_NEWLINE); \

+       fprintf(PNG_DEBUG_FILE,format,p1); \

+       } while (0)

+#          endif

+#          ifndef png_debug2

+#            define png_debug2(l,m,p1,p2) \

+       do { \

+       int num_tabs=l; \

+       char format[256]; \

+       snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \

+         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \

+         m,PNG_STRING_NEWLINE); \

+       fprintf(PNG_DEBUG_FILE,format,p1,p2); \

+       } while (0)

+#          endif

+#        endif /* __STDC __ */

+#      endif /* (PNG_DEBUG > 1) */

+

+#    endif /* _MSC_VER */

+#  endif /* (PNG_DEBUG > 0) */

+#endif /* PNG_DEBUG */

+#ifndef png_debug

+#  define png_debug(l, m) ((void)0)

+#endif

+#ifndef png_debug1

+#  define png_debug1(l, m, p1) ((void)0)

+#endif

+#ifndef png_debug2

+#  define png_debug2(l, m, p1, p2) ((void)0)

+#endif

+#endif /* PNGDEBUG_H */

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pnginfo.h b/core/src/fxcodec/fx_lpng/lpng_v163/pnginfo.h
new file mode 100644
index 0000000..683b7ea
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/pnginfo.h
@@ -0,0 +1,260 @@
+

+/* pnginfo.h - header file for PNG reference library

+ *

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * Last changed in libpng 1.6.1 [March 28, 2013]

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+

+ /* png_info is a structure that holds the information in a PNG file so

+ * that the application can find out the characteristics of the image.

+ * If you are reading the file, this structure will tell you what is

+ * in the PNG file.  If you are writing the file, fill in the information

+ * you want to put into the PNG file, using png_set_*() functions, then

+ * call png_write_info().

+ *

+ * The names chosen should be very close to the PNG specification, so

+ * consult that document for information about the meaning of each field.

+ *

+ * With libpng < 0.95, it was only possible to directly set and read the

+ * the values in the png_info_struct, which meant that the contents and

+ * order of the values had to remain fixed.  With libpng 0.95 and later,

+ * however, there are now functions that abstract the contents of

+ * png_info_struct from the application, so this makes it easier to use

+ * libpng with dynamic libraries, and even makes it possible to use

+ * libraries that don't have all of the libpng ancillary chunk-handing

+ * functionality.  In libpng-1.5.0 this was moved into a separate private

+ * file that is not visible to applications.

+ *

+ * The following members may have allocated storage attached that should be

+ * cleaned up before the structure is discarded: palette, trans, text,

+ * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,

+ * splt_palettes, scal_unit, row_pointers, and unknowns.   By default, these

+ * are automatically freed when the info structure is deallocated, if they were

+ * allocated internally by libpng.  This behavior can be changed by means

+ * of the png_data_freer() function.

+ *

+ * More allocation details: all the chunk-reading functions that

+ * change these members go through the corresponding png_set_*

+ * functions.  A function to clear these members is available: see

+ * png_free_data().  The png_set_* functions do not depend on being

+ * able to point info structure members to any of the storage they are

+ * passed (they make their own copies), EXCEPT that the png_set_text

+ * functions use the same storage passed to them in the text_ptr or

+ * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns

+ * functions do not make their own copies.

+ */

+#ifndef PNGINFO_H

+#define PNGINFO_H

+

+struct png_info_def

+{

+   /* The following are necessary for every PNG file */

+   png_uint_32 width;  /* width of image in pixels (from IHDR) */

+   png_uint_32 height; /* height of image in pixels (from IHDR) */

+   png_uint_32 valid;  /* valid chunk data (see PNG_INFO_ below) */

+   png_size_t rowbytes; /* bytes needed to hold an untransformed row */

+   png_colorp palette;      /* array of color values (valid & PNG_INFO_PLTE) */

+   png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */

+   png_uint_16 num_trans;   /* number of transparent palette color (tRNS) */

+   png_byte bit_depth;      /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */

+   png_byte color_type;     /* see PNG_COLOR_TYPE_ below (from IHDR) */

+   /* The following three should have been named *_method not *_type */

+   png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */

+   png_byte filter_type;    /* must be PNG_FILTER_TYPE_BASE (from IHDR) */

+   png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */

+

+   /* The following are set by png_set_IHDR, called from the application on

+    * write, but the are never actually used by the write code.

+    */

+   png_byte channels;       /* number of data channels per pixel (1, 2, 3, 4) */

+   png_byte pixel_depth;    /* number of bits per pixel */

+   png_byte spare_byte;     /* to align the data, and for future use */

+

+#ifdef PNG_READ_SUPPORTED

+   /* This is never set during write */

+   png_byte signature[8];   /* magic bytes read by libpng from start of file */

+#endif

+

+   /* The rest of the data is optional.  If you are reading, check the

+    * valid field to see if the information in these are valid.  If you

+    * are writing, set the valid field to those chunks you want written,

+    * and initialize the appropriate fields below.

+    */

+

+#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)

+   /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are

+    * defined.  When COLORSPACE is switched on all the colorspace-defining

+    * chunks should be enabled, when GAMMA is switched on all the gamma-defining

+    * chunks should be enabled.  If this is not done it becomes possible to read

+    * inconsistent PNG files and assign a probably incorrect interpretation to

+    * the information.  (In other words, by carefully choosing which chunks to

+    * recognize the system configuration can select an interpretation for PNG

+    * files containing ambiguous data and this will result in inconsistent

+    * behavior between different libpng builds!)

+    */

+   png_colorspace colorspace;

+#endif

+

+#ifdef PNG_iCCP_SUPPORTED

+   /* iCCP chunk data. */

+   png_charp iccp_name;     /* profile name */

+   png_bytep iccp_profile;  /* International Color Consortium profile data */

+   png_uint_32 iccp_proflen;  /* ICC profile data length */

+#endif

+

+#ifdef PNG_TEXT_SUPPORTED

+   /* The tEXt, and zTXt chunks contain human-readable textual data in

+    * uncompressed, compressed, and optionally compressed forms, respectively.

+    * The data in "text" is an array of pointers to uncompressed,

+    * null-terminated C strings. Each chunk has a keyword that describes the

+    * textual data contained in that chunk.  Keywords are not required to be

+    * unique, and the text string may be empty.  Any number of text chunks may

+    * be in an image.

+    */

+   int num_text; /* number of comments read or comments to write */

+   int max_text; /* current size of text array */

+   png_textp text; /* array of comments read or comments to write */

+#endif /* PNG_TEXT_SUPPORTED */

+

+#ifdef PNG_tIME_SUPPORTED

+   /* The tIME chunk holds the last time the displayed image data was

+    * modified.  See the png_time struct for the contents of this struct.

+    */

+   png_time mod_time;

+#endif

+

+#ifdef PNG_sBIT_SUPPORTED

+   /* The sBIT chunk specifies the number of significant high-order bits

+    * in the pixel data.  Values are in the range [1, bit_depth], and are

+    * only specified for the channels in the pixel data.  The contents of

+    * the low-order bits is not specified.  Data is valid if

+    * (valid & PNG_INFO_sBIT) is non-zero.

+    */

+   png_color_8 sig_bit; /* significant bits in color channels */

+#endif

+

+#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \

+defined(PNG_READ_BACKGROUND_SUPPORTED)

+   /* The tRNS chunk supplies transparency data for paletted images and

+    * other image types that don't need a full alpha channel.  There are

+    * "num_trans" transparency values for a paletted image, stored in the

+    * same order as the palette colors, starting from index 0.  Values

+    * for the data are in the range [0, 255], ranging from fully transparent

+    * to fully opaque, respectively.  For non-paletted images, there is a

+    * single color specified that should be treated as fully transparent.

+    * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.

+    */

+   png_bytep trans_alpha;    /* alpha values for paletted image */

+   png_color_16 trans_color; /* transparent color for non-palette image */

+#endif

+

+#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)

+   /* The bKGD chunk gives the suggested image background color if the

+    * display program does not have its own background color and the image

+    * is needs to composited onto a background before display.  The colors

+    * in "background" are normally in the same color space/depth as the

+    * pixel data.  Data is valid if (valid & PNG_INFO_bKGD) is non-zero.

+    */

+   png_color_16 background;

+#endif

+

+#ifdef PNG_oFFs_SUPPORTED

+   /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards

+    * and downwards from the top-left corner of the display, page, or other

+    * application-specific co-ordinate space.  See the PNG_OFFSET_ defines

+    * below for the unit types.  Valid if (valid & PNG_INFO_oFFs) non-zero.

+    */

+   png_int_32 x_offset; /* x offset on page */

+   png_int_32 y_offset; /* y offset on page */

+   png_byte offset_unit_type; /* offset units type */

+#endif

+

+#ifdef PNG_pHYs_SUPPORTED

+   /* The pHYs chunk gives the physical pixel density of the image for

+    * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_

+    * defines below).  Data is valid if (valid & PNG_INFO_pHYs) is non-zero.

+    */

+   png_uint_32 x_pixels_per_unit; /* horizontal pixel density */

+   png_uint_32 y_pixels_per_unit; /* vertical pixel density */

+   png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */

+#endif

+

+#ifdef PNG_hIST_SUPPORTED

+   /* The hIST chunk contains the relative frequency or importance of the

+    * various palette entries, so that a viewer can intelligently select a

+    * reduced-color palette, if required.  Data is an array of "num_palette"

+    * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)

+    * is non-zero.

+    */

+   png_uint_16p hist;

+#endif

+

+#ifdef PNG_pCAL_SUPPORTED

+   /* The pCAL chunk describes a transformation between the stored pixel

+    * values and original physical data values used to create the image.

+    * The integer range [0, 2^bit_depth - 1] maps to the floating-point

+    * range given by [pcal_X0, pcal_X1], and are further transformed by a

+    * (possibly non-linear) transformation function given by "pcal_type"

+    * and "pcal_params" into "pcal_units".  Please see the PNG_EQUATION_

+    * defines below, and the PNG-Group's PNG extensions document for a

+    * complete description of the transformations and how they should be

+    * implemented, and for a description of the ASCII parameter strings.

+    * Data values are valid if (valid & PNG_INFO_pCAL) non-zero.

+    */

+   png_charp pcal_purpose;  /* pCAL chunk description string */

+   png_int_32 pcal_X0;      /* minimum value */

+   png_int_32 pcal_X1;      /* maximum value */

+   png_charp pcal_units;    /* Latin-1 string giving physical units */

+   png_charpp pcal_params;  /* ASCII strings containing parameter values */

+   png_byte pcal_type;      /* equation type (see PNG_EQUATION_ below) */

+   png_byte pcal_nparams;   /* number of parameters given in pcal_params */

+#endif

+

+/* New members added in libpng-1.0.6 */

+   png_uint_32 free_me;     /* flags items libpng is responsible for freeing */

+

+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED

+   /* Storage for unknown chunks that the library doesn't recognize. */

+   png_unknown_chunkp unknown_chunks;

+

+   /* The type of this field is limited by the type of 

+    * png_struct::user_chunk_cache_max, else overflow can occur.

+    */

+   int                unknown_chunks_num;

+#endif

+

+#ifdef PNG_sPLT_SUPPORTED

+   /* Data on sPLT chunks (there may be more than one). */

+   png_sPLT_tp splt_palettes;

+   int         splt_palettes_num; /* Match type returned by png_get API */

+#endif

+

+#ifdef PNG_sCAL_SUPPORTED

+   /* The sCAL chunk describes the actual physical dimensions of the

+    * subject matter of the graphic.  The chunk contains a unit specification

+    * a byte value, and two ASCII strings representing floating-point

+    * values.  The values are width and height corresponsing to one pixel

+    * in the image.  Data values are valid if (valid & PNG_INFO_sCAL) is

+    * non-zero.

+    */

+   png_byte scal_unit;         /* unit of physical scale */

+   png_charp scal_s_width;     /* string containing height */

+   png_charp scal_s_height;    /* string containing width */

+#endif

+

+#ifdef PNG_INFO_IMAGE_SUPPORTED

+   /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS)

+      non-zero */

+   /* Data valid if (valid & PNG_INFO_IDAT) non-zero */

+   png_bytepp row_pointers;        /* the image bits */

+#endif

+

+};

+#endif /* PNGINFO_H */

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pnglibconf.h b/core/src/fxcodec/fx_lpng/lpng_v163/pnglibconf.h
new file mode 100644
index 0000000..ececc38
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/pnglibconf.h
@@ -0,0 +1,211 @@
+/* libpng 1.6.3 STANDARD API DEFINITION */

+

+/* pnglibconf.h - library build configuration */

+

+/* Libpng version 1.6.3 - July 18, 2013 */

+

+/* Copyright (c) 1998-2013 Glenn Randers-Pehrson */

+

+/* This code is released under the libpng license. */

+/* For conditions of distribution and use, see the disclaimer */

+/* and license in png.h */

+

+/* pnglibconf.h */

+/* Machine generated file: DO NOT EDIT */

+/* Derived from: scripts/pnglibconf.dfa */

+#ifndef PNGLCONF_H

+#define PNGLCONF_H

+/* options */

+#define PNG_16BIT_SUPPORTED

+#define PNG_ALIGNED_MEMORY_SUPPORTED

+/*#undef PNG_ARM_NEON_API_SUPPORTED*/

+/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/

+#define PNG_BENIGN_ERRORS_SUPPORTED

+#define PNG_BENIGN_READ_ERRORS_SUPPORTED

+/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/

+#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED

+#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED

+#define PNG_COLORSPACE_SUPPORTED

+#define PNG_CONSOLE_IO_SUPPORTED

+#define PNG_CONVERT_tIME_SUPPORTED

+#define PNG_EASY_ACCESS_SUPPORTED

+/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/

+#define PNG_ERROR_TEXT_SUPPORTED

+#define PNG_FIXED_POINT_SUPPORTED

+#define PNG_FLOATING_ARITHMETIC_SUPPORTED

+#define PNG_FLOATING_POINT_SUPPORTED

+#define PNG_FORMAT_AFIRST_SUPPORTED

+#define PNG_FORMAT_BGR_SUPPORTED

+#define PNG_GAMMA_SUPPORTED

+#define PNG_GET_PALETTE_MAX_SUPPORTED

+#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED

+#define PNG_INCH_CONVERSIONS_SUPPORTED

+#define PNG_INFO_IMAGE_SUPPORTED

+#define PNG_IO_STATE_SUPPORTED

+#define PNG_MNG_FEATURES_SUPPORTED

+#define PNG_POINTER_INDEXING_SUPPORTED

+#define PNG_PROGRESSIVE_READ_SUPPORTED

+#define PNG_READ_16BIT_SUPPORTED

+#define PNG_READ_ALPHA_MODE_SUPPORTED

+#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED

+#define PNG_READ_BACKGROUND_SUPPORTED

+#define PNG_READ_BGR_SUPPORTED

+#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED

+#define PNG_READ_COMPOSITE_NODIV_SUPPORTED

+#define PNG_READ_COMPRESSED_TEXT_SUPPORTED

+#define PNG_READ_EXPAND_16_SUPPORTED

+#define PNG_READ_EXPAND_SUPPORTED

+#define PNG_READ_FILLER_SUPPORTED

+#define PNG_READ_GAMMA_SUPPORTED

+#define PNG_READ_GET_PALETTE_MAX_SUPPORTED

+#define PNG_READ_GRAY_TO_RGB_SUPPORTED

+#define PNG_READ_INTERLACING_SUPPORTED

+#define PNG_READ_INT_FUNCTIONS_SUPPORTED

+#define PNG_READ_INVERT_ALPHA_SUPPORTED

+#define PNG_READ_INVERT_SUPPORTED

+#define PNG_READ_OPT_PLTE_SUPPORTED

+#define PNG_READ_PACKSWAP_SUPPORTED

+#define PNG_READ_PACK_SUPPORTED

+#define PNG_READ_QUANTIZE_SUPPORTED

+#define PNG_READ_RGB_TO_GRAY_SUPPORTED

+#define PNG_READ_SCALE_16_TO_8_SUPPORTED

+#define PNG_READ_SHIFT_SUPPORTED

+#define PNG_READ_STRIP_16_TO_8_SUPPORTED

+#define PNG_READ_STRIP_ALPHA_SUPPORTED

+#define PNG_READ_SUPPORTED

+#define PNG_READ_SWAP_ALPHA_SUPPORTED

+#define PNG_READ_SWAP_SUPPORTED

+#define PNG_READ_TEXT_SUPPORTED

+#define PNG_READ_TRANSFORMS_SUPPORTED

+#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED

+#define PNG_READ_USER_CHUNKS_SUPPORTED

+#define PNG_READ_USER_TRANSFORM_SUPPORTED

+#define PNG_READ_bKGD_SUPPORTED

+#define PNG_READ_cHRM_SUPPORTED

+#define PNG_READ_gAMA_SUPPORTED

+#define PNG_READ_hIST_SUPPORTED

+#define PNG_READ_iCCP_SUPPORTED

+#define PNG_READ_iTXt_SUPPORTED

+#define PNG_READ_oFFs_SUPPORTED

+#define PNG_READ_pCAL_SUPPORTED

+#define PNG_READ_pHYs_SUPPORTED

+#define PNG_READ_sBIT_SUPPORTED

+#define PNG_READ_sCAL_SUPPORTED

+#define PNG_READ_sPLT_SUPPORTED

+#define PNG_READ_sRGB_SUPPORTED

+#define PNG_READ_tEXt_SUPPORTED

+#define PNG_READ_tIME_SUPPORTED

+#define PNG_READ_tRNS_SUPPORTED

+#define PNG_READ_zTXt_SUPPORTED

+/*#undef PNG_SAFE_LIMITS_SUPPORTED*/

+#define PNG_SAVE_INT_32_SUPPORTED

+#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED

+#define PNG_SEQUENTIAL_READ_SUPPORTED

+#define PNG_SETJMP_SUPPORTED

+#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED

+#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED

+#define PNG_SET_OPTION_SUPPORTED

+#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+#define PNG_SET_USER_LIMITS_SUPPORTED

+#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED

+#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED

+#define PNG_SIMPLIFIED_READ_SUPPORTED

+#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED

+#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED

+#define PNG_SIMPLIFIED_WRITE_SUPPORTED

+#define PNG_STDIO_SUPPORTED

+#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED

+#define PNG_TEXT_SUPPORTED

+#define PNG_TIME_RFC1123_SUPPORTED

+#define PNG_UNKNOWN_CHUNKS_SUPPORTED

+#define PNG_USER_CHUNKS_SUPPORTED

+#define PNG_USER_LIMITS_SUPPORTED

+#define PNG_USER_MEM_SUPPORTED

+#define PNG_USER_TRANSFORM_INFO_SUPPORTED

+#define PNG_USER_TRANSFORM_PTR_SUPPORTED

+#define PNG_WARNINGS_SUPPORTED

+#define PNG_WRITE_16BIT_SUPPORTED

+#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED

+#define PNG_WRITE_BGR_SUPPORTED

+#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED

+#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED

+#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED

+#define PNG_WRITE_FILLER_SUPPORTED

+#define PNG_WRITE_FILTER_SUPPORTED

+#define PNG_WRITE_FLUSH_SUPPORTED

+#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED

+#define PNG_WRITE_INTERLACING_SUPPORTED

+#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED

+#define PNG_WRITE_INVERT_ALPHA_SUPPORTED

+#define PNG_WRITE_INVERT_SUPPORTED

+#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED

+#define PNG_WRITE_PACKSWAP_SUPPORTED

+#define PNG_WRITE_PACK_SUPPORTED

+#define PNG_WRITE_SHIFT_SUPPORTED

+#define PNG_WRITE_SUPPORTED

+#define PNG_WRITE_SWAP_ALPHA_SUPPORTED

+#define PNG_WRITE_SWAP_SUPPORTED

+#define PNG_WRITE_TEXT_SUPPORTED

+#define PNG_WRITE_TRANSFORMS_SUPPORTED

+#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED

+#define PNG_WRITE_USER_TRANSFORM_SUPPORTED

+#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+#define PNG_WRITE_bKGD_SUPPORTED

+#define PNG_WRITE_cHRM_SUPPORTED

+#define PNG_WRITE_gAMA_SUPPORTED

+#define PNG_WRITE_hIST_SUPPORTED

+#define PNG_WRITE_iCCP_SUPPORTED

+#define PNG_WRITE_iTXt_SUPPORTED

+#define PNG_WRITE_oFFs_SUPPORTED

+#define PNG_WRITE_pCAL_SUPPORTED

+#define PNG_WRITE_pHYs_SUPPORTED

+#define PNG_WRITE_sBIT_SUPPORTED

+#define PNG_WRITE_sCAL_SUPPORTED

+#define PNG_WRITE_sPLT_SUPPORTED

+#define PNG_WRITE_sRGB_SUPPORTED

+#define PNG_WRITE_tEXt_SUPPORTED

+#define PNG_WRITE_tIME_SUPPORTED

+#define PNG_WRITE_tRNS_SUPPORTED

+#define PNG_WRITE_zTXt_SUPPORTED

+#define PNG_bKGD_SUPPORTED

+#define PNG_cHRM_SUPPORTED

+#define PNG_gAMA_SUPPORTED

+#define PNG_hIST_SUPPORTED

+#define PNG_iCCP_SUPPORTED

+#define PNG_iTXt_SUPPORTED

+#define PNG_oFFs_SUPPORTED

+#define PNG_pCAL_SUPPORTED

+#define PNG_pHYs_SUPPORTED

+#define PNG_sBIT_SUPPORTED

+#define PNG_sCAL_SUPPORTED

+#define PNG_sPLT_SUPPORTED

+#define PNG_sRGB_SUPPORTED

+#define PNG_tEXt_SUPPORTED

+#define PNG_tIME_SUPPORTED

+#define PNG_tRNS_SUPPORTED

+#define PNG_zTXt_SUPPORTED

+/* end of options */

+/* settings */

+#define PNG_API_RULE 0

+#define PNG_CALLOC_SUPPORTED

+#define PNG_COST_SHIFT 3

+#define PNG_DEFAULT_READ_MACROS 1

+#define PNG_GAMMA_THRESHOLD_FIXED 5000

+#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE

+#define PNG_INFLATE_BUF_SIZE 1024

+#define PNG_MAX_GAMMA_8 11

+#define PNG_QUANTIZE_BLUE_BITS 5

+#define PNG_QUANTIZE_GREEN_BITS 5

+#define PNG_QUANTIZE_RED_BITS 5

+#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)

+#define PNG_TEXT_Z_DEFAULT_STRATEGY 0

+#define PNG_WEIGHT_SHIFT 8

+#define PNG_ZBUF_SIZE 8192

+#define PNG_ZLIB_VERNUM 0 /* unknown */

+#define PNG_Z_DEFAULT_COMPRESSION (-1)

+#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0

+#define PNG_Z_DEFAULT_STRATEGY 1

+#define PNG_sCAL_PRECISION 5

+#define PNG_sRGB_PROFILE_CHECKS 2

+/* end of settings */

+#endif /* PNGLCONF_H */

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pngpriv.h b/core/src/fxcodec/fx_lpng/lpng_v163/pngpriv.h
new file mode 100644
index 0000000..7fa3d60
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/pngpriv.h
@@ -0,0 +1,2006 @@
+

+/* pngpriv.h - private declarations for use inside libpng

+ *

+ * For conditions of distribution and use, see copyright notice in png.h

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * Last changed in libpng 1.6.3 [July 18, 2013]

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+

+/* The symbols declared in this file (including the functions declared

+ * as extern) are PRIVATE.  They are not part of the libpng public

+ * interface, and are not recommended for use by regular applications.

+ * Some of them may become public in the future; others may stay private,

+ * change in an incompatible way, or even disappear.

+ * Although the libpng users are not forbidden to include this header,

+ * they should be well aware of the issues that may arise from doing so.

+ */

+

+#ifndef PNGPRIV_H

+#define PNGPRIV_H

+

+/* Feature Test Macros.  The following are defined here to ensure that correctly

+ * implemented libraries reveal the APIs libpng needs to build and hide those

+ * that are not needed and potentially damaging to the compilation.

+ *

+ * Feature Test Macros must be defined before any system header is included (see

+ * POSIX 1003.1 2.8.2 "POSIX Symbols."

+ *

+ * These macros only have an effect if the operating system supports either

+ * POSIX 1003.1 or C99, or both.  On other operating systems (particularly

+ * Windows/Visual Studio) there is no effect; the OS specific tests below are

+ * still required (as of 2011-05-02.)

+ */

+#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */

+

+#ifndef PNG_VERSION_INFO_ONLY

+/* Standard library headers not required by png.h: */

+#  include <stdlib.h>

+#  include <string.h>

+#endif

+

+#define PNGLIB_BUILD /*libpng is being built, not used*/

+

+/* If HAVE_CONFIG_H is defined during the build then the build system must

+ * provide an appropriate "config.h" file on the include path.  The header file

+ * must provide definitions as required below (search for "HAVE_CONFIG_H");

+ * see configure.ac for more details of the requirements.  The macro

+ * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on

+ * 'configure'; define this macro to prevent the configure build including the

+ * configure generated config.h.  Libpng is expected to compile without *any*

+ * special build system support on a reasonably ANSI-C compliant system.

+ */

+#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)

+#  include <config.h>

+

+   /* Pick up the definition of 'restrict' from config.h if it was read: */

+#  define PNG_RESTRICT restrict

+#endif

+

+/* To support symbol prefixing it is necessary to know *before* including png.h

+ * whether the fixed point (and maybe other) APIs are exported, because if they

+ * are not internal definitions may be required.  This is handled below just

+ * before png.h is included, but load the configuration now if it is available.

+ */

+#ifndef PNGLCONF_H

+#  include "pnglibconf.h"

+#endif

+

+/* Local renames may change non-exported API functions from png.h */

+#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H)

+#  include "pngprefix.h"

+#endif

+

+#ifdef PNG_USER_CONFIG

+#  include "pngusr.h"

+   /* These should have been defined in pngusr.h */

+#  ifndef PNG_USER_PRIVATEBUILD

+#    define PNG_USER_PRIVATEBUILD "Custom libpng build"

+#  endif

+#  ifndef PNG_USER_DLLFNAME_POSTFIX

+#    define PNG_USER_DLLFNAME_POSTFIX "Cb"

+#  endif

+#endif

+

+/* Compile time options.

+ * =====================

+ * In a multi-arch build the compiler may compile the code several times for the

+ * same object module, producing different binaries for different architectures.

+ * When this happens configure-time setting of the target host options cannot be

+ * done and this interferes with the handling of the ARM NEON optimizations, and

+ * possibly other similar optimizations.  Put additional tests here; in general

+ * this is needed when the same option can be changed at both compile time and

+ * run time depending on the target OS (i.e. iOS vs Android.)

+ *

+ * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because

+ * this is not possible with certain compilers (Oracle SUN OS CC), as a result

+ * it is necessary to ensure that all extern functions that *might* be used

+ * regardless of $(CFLAGS) get declared in this file.  The test on __ARM_NEON__

+ * below is one example of this behavior because it is controlled by the

+ * presence or not of -mfpu=neon on the GCC command line, it is possible to do

+ * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely

+ * do this.

+ */

+#ifndef PNG_ARM_NEON_OPT

+   /* ARM NEON optimizations are being controlled by the compiler settings,

+    * typically the target FPU.  If the FPU has been set to NEON (-mfpu=neon

+    * with GCC) then the compiler will define __ARM_NEON__ and we can rely

+    * unconditionally on NEON instructions not crashing, otherwise we must

+    * disable use of NEON instructions:

+    */

+#  ifdef __ARM_NEON__

+#     define PNG_ARM_NEON_OPT 2

+#  else

+#     define PNG_ARM_NEON_OPT 0

+#  endif

+#endif

+

+#if PNG_ARM_NEON_OPT > 0

+   /* NEON optimizations are to be at least considered by libpng, so enable the

+    * callbacks to do this.

+    */

+#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon

+#endif

+

+/* Is this a build of a DLL where compilation of the object modules requires

+ * different preprocessor settings to those required for a simple library?  If

+ * so PNG_BUILD_DLL must be set.

+ *

+ * If libpng is used inside a DLL but that DLL does not export the libpng APIs

+ * PNG_BUILD_DLL must not be set.  To avoid the code below kicking in build a

+ * static library of libpng then link the DLL against that.

+ */

+#ifndef PNG_BUILD_DLL

+#  ifdef DLL_EXPORT

+      /* This is set by libtool when files are compiled for a DLL; libtool

+       * always compiles twice, even on systems where it isn't necessary.  Set

+       * PNG_BUILD_DLL in case it is necessary:

+       */

+#     define PNG_BUILD_DLL

+#  else

+#     ifdef _WINDLL

+         /* This is set by the Microsoft Visual Studio IDE in projects that

+          * build a DLL.  It can't easily be removed from those projects (it

+          * isn't visible in the Visual Studio UI) so it is a fairly reliable

+          * indication that PNG_IMPEXP needs to be set to the DLL export

+          * attributes.

+          */

+#        define PNG_BUILD_DLL

+#     else

+#        ifdef __DLL__

+            /* This is set by the Borland C system when compiling for a DLL

+             * (as above.)

+             */

+#           define PNG_BUILD_DLL

+#        else

+            /* Add additional compiler cases here. */

+#        endif

+#     endif

+#  endif

+#endif /* Setting PNG_BUILD_DLL if required */

+

+/* See pngconf.h for more details: the builder of the library may set this on

+ * the command line to the right thing for the specific compilation system or it

+ * may be automagically set above (at present we know of no system where it does

+ * need to be set on the command line.)

+ *

+ * PNG_IMPEXP must be set here when building the library to prevent pngconf.h

+ * setting it to the "import" setting for a DLL build.

+ */

+#ifndef PNG_IMPEXP

+#  ifdef PNG_BUILD_DLL

+#     define PNG_IMPEXP PNG_DLL_EXPORT

+#  else

+      /* Not building a DLL, or the DLL doesn't require specific export

+       * definitions.

+       */

+#     define PNG_IMPEXP

+#  endif

+#endif

+

+/* No warnings for private or deprecated functions in the build: */

+#ifndef PNG_DEPRECATED

+#  define PNG_DEPRECATED

+#endif

+#ifndef PNG_PRIVATE

+#  define PNG_PRIVATE

+#endif

+

+/* Symbol preprocessing support.

+ *

+ * To enable listing global, but internal, symbols the following macros should

+ * always be used to declare an extern data or function object in this file.

+ */

+#ifndef PNG_INTERNAL_DATA

+#  define PNG_INTERNAL_DATA(type, name, array) extern type name array

+#endif

+

+#ifndef PNG_INTERNAL_FUNCTION

+#  define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\

+      extern PNG_FUNCTION(type, name, args, PNG_EMPTY attributes)

+#endif

+

+/* If floating or fixed point APIs are disabled they may still be compiled

+ * internally.  To handle this make sure they are declared as the appropriate

+ * internal extern function (otherwise the symbol prefixing stuff won't work and

+ * the functions will be used without definitions.)

+ *

+ * NOTE: although all the API functions are declared here they are not all

+ * actually built!  Because the declarations are still made it is necessary to

+ * fake out types that they depend on.

+ */

+#ifndef PNG_FP_EXPORT

+#  ifndef PNG_FLOATING_POINT_SUPPORTED

+#     define PNG_FP_EXPORT(ordinal, type, name, args)\

+         PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY);

+#     ifndef PNG_VERSION_INFO_ONLY

+         typedef struct png_incomplete png_double;

+         typedef png_double*           png_doublep;

+         typedef const png_double*     png_const_doublep;

+         typedef png_double**          png_doublepp;

+#     endif

+#  endif

+#endif

+#ifndef PNG_FIXED_EXPORT

+#  ifndef PNG_FIXED_POINT_SUPPORTED

+#     define PNG_FIXED_EXPORT(ordinal, type, name, args)\

+         PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY);

+#  endif

+#endif

+

+#include "png.h"

+

+/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */

+#ifndef PNG_DLL_EXPORT

+#  define PNG_DLL_EXPORT

+#endif

+

+/* SECURITY and SAFETY:

+ *

+ * By default libpng is built without any internal limits on image size,

+ * individual heap (png_malloc) allocations or the total amount of memory used.

+ * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used

+ * (unless individually overridden).  These limits are believed to be fairly

+ * safe, but builders of secure systems should verify the values against the

+ * real system capabilities.

+ */

+#ifdef PNG_SAFE_LIMITS_SUPPORTED

+   /* 'safe' limits */

+#  ifndef PNG_USER_WIDTH_MAX

+#     define PNG_USER_WIDTH_MAX 1000000

+#  endif

+#  ifndef PNG_USER_HEIGHT_MAX

+#     define PNG_USER_HEIGHT_MAX 1000000

+#  endif

+#  ifndef PNG_USER_CHUNK_CACHE_MAX

+#     define PNG_USER_CHUNK_CACHE_MAX 128

+#  endif

+#  ifndef PNG_USER_CHUNK_MALLOC_MAX

+#     define PNG_USER_CHUNK_MALLOC_MAX 8000000

+#  endif

+#else

+   /* values for no limits */

+#  ifndef PNG_USER_WIDTH_MAX

+#     define PNG_USER_WIDTH_MAX 0x7fffffff

+#  endif

+#  ifndef PNG_USER_HEIGHT_MAX

+#     define PNG_USER_HEIGHT_MAX 0x7fffffff

+#  endif

+#  ifndef PNG_USER_CHUNK_CACHE_MAX

+#     define PNG_USER_CHUNK_CACHE_MAX 0

+#  endif

+#  ifndef PNG_USER_CHUNK_MALLOC_MAX

+#     define PNG_USER_CHUNK_MALLOC_MAX 0

+#  endif

+#endif

+

+/* Moved to pngpriv.h at libpng-1.5.0 */

+/* NOTE: some of these may have been used in external applications as

+ * these definitions were exposed in pngconf.h prior to 1.5.

+ */

+

+/* If you are running on a machine where you cannot allocate more

+ * than 64K of memory at once, uncomment this.  While libpng will not

+ * normally need that much memory in a chunk (unless you load up a very

+ * large file), zlib needs to know how big of a chunk it can use, and

+ * libpng thus makes sure to check any memory allocation to verify it

+ * will fit into memory.

+ *

+ * zlib provides 'MAXSEG_64K' which, if defined, indicates the

+ * same limit and pngconf.h (already included) sets the limit

+ * if certain operating systems are detected.

+ */

+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)

+#  define PNG_MAX_MALLOC_64K

+#endif

+

+#ifndef PNG_UNUSED

+/* Unused formal parameter warnings are silenced using the following macro

+ * which is expected to have no bad effects on performance (optimizing

+ * compilers will probably remove it entirely).  Note that if you replace

+ * it with something other than whitespace, you must include the terminating

+ * semicolon.

+ */

+#  define PNG_UNUSED(param) (void)param;

+#endif

+

+/* Just a little check that someone hasn't tried to define something

+ * contradictory.

+ */

+#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K)

+#  undef PNG_ZBUF_SIZE

+#  define PNG_ZBUF_SIZE 65536L

+#endif

+

+/* If warnings or errors are turned off the code is disabled or redirected here.

+ * From 1.5.4 functions have been added to allow very limited formatting of

+ * error and warning messages - this code will also be disabled here.

+ */

+#ifdef PNG_WARNINGS_SUPPORTED

+#  define PNG_WARNING_PARAMETERS(p) png_warning_parameters p;

+#else

+#  define png_warning(s1,s2) ((void)(s1))

+#  define png_chunk_warning(s1,s2) ((void)(s1))

+#  define png_warning_parameter(p,number,string) ((void)0)

+#  define png_warning_parameter_unsigned(p,number,format,value) ((void)0)

+#  define png_warning_parameter_signed(p,number,format,value) ((void)0)

+#  define png_formatted_warning(pp,p,message) ((void)(pp))

+#  define PNG_WARNING_PARAMETERS(p)

+#endif

+#ifndef PNG_ERROR_TEXT_SUPPORTED

+#  define png_error(s1,s2) png_err(s1)

+#  define png_chunk_error(s1,s2) png_err(s1)

+#  define png_fixed_error(s1,s2) png_err(s1)

+#endif

+

+/* C allows up-casts from (void*) to any pointer and (const void*) to any

+ * pointer to a const object.  C++ regards this as a type error and requires an

+ * explicit, static, cast and provides the static_cast<> rune to ensure that

+ * const is not cast away.

+ */

+#ifdef __cplusplus

+#  define png_voidcast(type, value) static_cast<type>(value)

+#  define png_constcast(type, value) const_cast<type>(value)

+#  define png_aligncast(type, value) \

+   static_cast<type>(static_cast<void*>(value))

+#  define png_aligncastconst(type, value) \

+   static_cast<type>(static_cast<const void*>(value))

+#else

+#  define png_voidcast(type, value) (value)

+#  define png_constcast(type, value) ((type)(value))

+#  define png_aligncast(type, value) ((void*)(value))

+#  define png_aligncastconst(type, value) ((const void*)(value))

+#endif /* __cplusplus */

+

+/* Some fixed point APIs are still required even if not exported because

+ * they get used by the corresponding floating point APIs.  This magic

+ * deals with this:

+ */

+#ifdef PNG_FIXED_POINT_SUPPORTED

+#  define PNGFAPI PNGAPI

+#else

+#  define PNGFAPI /* PRIVATE */

+#endif

+

+#ifndef PNG_VERSION_INFO_ONLY

+/* Other defines specific to compilers can go here.  Try to keep

+ * them inside an appropriate ifdef/endif pair for portability.

+ */

+#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\

+    defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)

+   /* png.c requires the following ANSI-C constants if the conversion of

+    * floating point to ASCII is implemented therein:

+    *

+    *  DBL_DIG  Maximum number of decimal digits (can be set to any constant)

+    *  DBL_MIN  Smallest normalized fp number (can be set to an arbitrary value)

+    *  DBL_MAX  Maximum floating point number (can be set to an arbitrary value)

+    */

+#  include <float.h>

+

+#  if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \

+    defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC)

+     /* We need to check that <math.h> hasn't already been included earlier

+      * as it seems it doesn't agree with <fp.h>, yet we should really use

+      * <fp.h> if possible.

+      */

+#    if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)

+#      include <fp.h>

+#    endif

+#  else

+#    include <math.h>

+#  endif

+#  if defined(_AMIGA) && defined(__SASC) && defined(_M68881)

+     /* Amiga SAS/C: We must include builtin FPU functions when compiling using

+      * MATH=68881

+      */

+#    include <m68881.h>

+#  endif

+#endif

+

+/* This provides the non-ANSI (far) memory allocation routines. */

+#if defined(__TURBOC__) && defined(__MSDOS__)

+#  include <mem.h>

+#  include <alloc.h>

+#endif

+

+#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \

+    defined(_WIN32) || defined(__WIN32__)

+#  include <windows.h>  /* defines _WINDOWS_ macro */

+#endif

+#endif /* PNG_VERSION_INFO_ONLY */

+

+/* Moved here around 1.5.0beta36 from pngconf.h */

+/* Users may want to use these so they are not private.  Any library

+ * functions that are passed far data must be model-independent.

+ */

+

+/* Memory model/platform independent fns */

+#ifndef PNG_ABORT

+#  ifdef _WINDOWS_

+#    define PNG_ABORT() ExitProcess(0)

+#  else

+#    define PNG_ABORT() abort()

+#  endif

+#endif

+

+/* These macros may need to be architecture dependent. */

+#define PNG_ALIGN_NONE   0 /* do not use data alignment */

+#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */

+#ifdef offsetof

+#  define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */

+#else

+#  define PNG_ALIGN_OFFSET -1 /* prevent the use of this */

+#endif

+#define PNG_ALIGN_SIZE   3 /* use sizeof to determine alignment */

+

+#ifndef PNG_ALIGN_TYPE

+   /* Default to using aligned access optimizations and requiring alignment to a

+    * multiple of the data type size.  Override in a compiler specific fashion

+    * if necessary by inserting tests here:

+    */

+#  define PNG_ALIGN_TYPE PNG_ALIGN_SIZE

+#endif

+

+#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE

+   /* This is used because in some compiler implementations non-aligned

+    * structure members are supported, so the offsetof approach below fails.

+    * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access

+    * is good for performance.  Do not do this unless you have tested the result

+    * and understand it.

+    */

+#  define png_alignof(type) (sizeof (type))

+#else

+#  if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET

+#     define png_alignof(type) offsetof(struct{char c; type t;}, t)

+#  else

+#     if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS

+#        define png_alignof(type) (1)

+#     endif

+      /* Else leave png_alignof undefined to prevent use thereof */

+#  endif

+#endif

+

+/* This implicitly assumes alignment is always to a power of 2. */

+#ifdef png_alignof

+#  define png_isaligned(ptr, type)\

+   ((((const char*)ptr-(const char*)0) & (png_alignof(type)-1)) == 0)

+#else

+#  define png_isaligned(ptr, type) 0

+#endif

+

+/* End of memory model/platform independent support */

+/* End of 1.5.0beta36 move from pngconf.h */

+

+/* CONSTANTS and UTILITY MACROS

+ * These are used internally by libpng and not exposed in the API

+ */

+

+/* Various modes of operation.  Note that after an init, mode is set to

+ * zero automatically when the structure is created.  Three of these

+ * are defined in png.h because they need to be visible to applications

+ * that call png_set_unknown_chunk().

+ */

+/* #define PNG_HAVE_IHDR            0x01 (defined in png.h) */

+/* #define PNG_HAVE_PLTE            0x02 (defined in png.h) */

+#define PNG_HAVE_IDAT               0x04

+/* #define PNG_AFTER_IDAT           0x08 (defined in png.h) */

+#define PNG_HAVE_IEND               0x10

+                   /*               0x20 (unused) */

+                   /*               0x40 (unused) */

+                   /*               0x80 (unused) */

+#define PNG_HAVE_CHUNK_HEADER      0x100

+#define PNG_WROTE_tIME             0x200

+#define PNG_WROTE_INFO_BEFORE_PLTE 0x400

+#define PNG_BACKGROUND_IS_GRAY     0x800

+#define PNG_HAVE_PNG_SIGNATURE    0x1000

+#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */

+                   /*             0x4000 (unused) */

+#define PNG_IS_READ_STRUCT        0x8000 /* Else is a write struct */

+

+/* Flags for the transformations the PNG library does on the image data */

+#define PNG_BGR                 0x0001

+#define PNG_INTERLACE           0x0002

+#define PNG_PACK                0x0004

+#define PNG_SHIFT               0x0008

+#define PNG_SWAP_BYTES          0x0010

+#define PNG_INVERT_MONO         0x0020

+#define PNG_QUANTIZE            0x0040

+#define PNG_COMPOSE             0x0080     /* Was PNG_BACKGROUND */

+#define PNG_BACKGROUND_EXPAND   0x0100

+#define PNG_EXPAND_16           0x0200     /* Added to libpng 1.5.2 */

+#define PNG_16_TO_8             0x0400     /* Becomes 'chop' in 1.5.4 */

+#define PNG_RGBA                0x0800

+#define PNG_EXPAND              0x1000

+#define PNG_GAMMA               0x2000

+#define PNG_GRAY_TO_RGB         0x4000

+#define PNG_FILLER              0x8000

+#define PNG_PACKSWAP           0x10000

+#define PNG_SWAP_ALPHA         0x20000

+#define PNG_STRIP_ALPHA        0x40000

+#define PNG_INVERT_ALPHA       0x80000

+#define PNG_USER_TRANSFORM    0x100000

+#define PNG_RGB_TO_GRAY_ERR   0x200000

+#define PNG_RGB_TO_GRAY_WARN  0x400000

+#define PNG_RGB_TO_GRAY       0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */

+#define PNG_ENCODE_ALPHA      0x800000 /* Added to libpng-1.5.4 */

+#define PNG_ADD_ALPHA         0x1000000 /* Added to libpng-1.2.7 */

+#define PNG_EXPAND_tRNS       0x2000000 /* Added to libpng-1.2.9 */

+#define PNG_SCALE_16_TO_8     0x4000000 /* Added to libpng-1.5.4 */

+                       /*   0x8000000 unused */

+                       /*  0x10000000 unused */

+                       /*  0x20000000 unused */

+                       /*  0x40000000 unused */

+/* Flags for png_create_struct */

+#define PNG_STRUCT_PNG   0x0001

+#define PNG_STRUCT_INFO  0x0002

+

+/* Scaling factor for filter heuristic weighting calculations */

+#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))

+#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))

+

+/* Flags for the png_ptr->flags rather than declaring a byte for each one */

+#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY     0x0001

+#define PNG_FLAG_ZSTREAM_INITIALIZED      0x0002 /* Added to libpng-1.6.0 */

+                                  /*      0x0004    unused */

+#define PNG_FLAG_ZSTREAM_ENDED            0x0008 /* Added to libpng-1.6.0 */

+                                  /*      0x0010    unused */

+                                  /*      0x0020    unused */

+#define PNG_FLAG_ROW_INIT                 0x0040

+#define PNG_FLAG_FILLER_AFTER             0x0080

+#define PNG_FLAG_CRC_ANCILLARY_USE        0x0100

+#define PNG_FLAG_CRC_ANCILLARY_NOWARN     0x0200

+#define PNG_FLAG_CRC_CRITICAL_USE         0x0400

+#define PNG_FLAG_CRC_CRITICAL_IGNORE      0x0800

+#define PNG_FLAG_ASSUME_sRGB              0x1000 /* Added to libpng-1.5.4 */

+#define PNG_FLAG_OPTIMIZE_ALPHA           0x2000 /* Added to libpng-1.5.4 */

+#define PNG_FLAG_DETECT_UNINITIALIZED     0x4000 /* Added to libpng-1.5.4 */

+/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000 */

+/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS      0x10000 */

+#define PNG_FLAG_LIBRARY_MISMATCH        0x20000

+#define PNG_FLAG_STRIP_ERROR_NUMBERS     0x40000

+#define PNG_FLAG_STRIP_ERROR_TEXT        0x80000

+#define PNG_FLAG_BENIGN_ERRORS_WARN     0x100000 /* Added to libpng-1.4.0 */

+#define PNG_FLAG_APP_WARNINGS_WARN      0x200000 /* Added to libpng-1.6.0 */

+#define PNG_FLAG_APP_ERRORS_WARN        0x400000 /* Added to libpng-1.6.0 */

+                                  /*    0x800000    unused */

+                                  /*   0x1000000    unused */

+                                  /*   0x2000000    unused */

+                                  /*   0x4000000    unused */

+                                  /*   0x8000000    unused */

+                                  /*  0x10000000    unused */

+                                  /*  0x20000000    unused */

+                                  /*  0x40000000    unused */

+

+#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \

+                                     PNG_FLAG_CRC_ANCILLARY_NOWARN)

+

+#define PNG_FLAG_CRC_CRITICAL_MASK  (PNG_FLAG_CRC_CRITICAL_USE | \

+                                     PNG_FLAG_CRC_CRITICAL_IGNORE)

+

+#define PNG_FLAG_CRC_MASK           (PNG_FLAG_CRC_ANCILLARY_MASK | \

+                                     PNG_FLAG_CRC_CRITICAL_MASK)

+

+/* Save typing and make code easier to understand */

+

+#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \

+   abs((int)((c1).green) - (int)((c2).green)) + \

+   abs((int)((c1).blue) - (int)((c2).blue)))

+

+/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255

+ * by dividing by 257 *with rounding*.  This macro is exact for the given range.

+ * See the discourse in pngrtran.c png_do_scale_16_to_8.  The values in the

+ * macro were established by experiment (modifying the added value).  The macro

+ * has a second variant that takes a value already scaled by 255 and divides by

+ * 65535 - this has a maximum error of .502.  Over the range 0..65535*65535 it

+ * only gives off-by-one errors and only for 0.5% (1 in 200) of the values.

+ */

+#define PNG_DIV65535(v24) (((v24) + 32895) >> 16)

+#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255)

+

+/* Added to libpng-1.2.6 JB */

+#define PNG_ROWBYTES(pixel_bits, width) \

+    ((pixel_bits) >= 8 ? \

+    ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \

+    (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) )

+

+/* PNG_OUT_OF_RANGE returns true if value is outside the range

+ * ideal-delta..ideal+delta.  Each argument is evaluated twice.

+ * "ideal" and "delta" should be constants, normally simple

+ * integers, "value" a variable. Added to libpng-1.2.6 JB

+ */

+#define PNG_OUT_OF_RANGE(value, ideal, delta) \

+   ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) )

+

+/* Conversions between fixed and floating point, only defined if

+ * required (to make sure the code doesn't accidentally use float

+ * when it is supposedly disabled.)

+ */

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+/* The floating point conversion can't overflow, though it can and

+ * does lose accuracy relative to the original fixed point value.

+ * In practice this doesn't matter because png_fixed_point only

+ * stores numbers with very low precision.  The png_ptr and s

+ * arguments are unused by default but are there in case error

+ * checking becomes a requirement.

+ */

+#define png_float(png_ptr, fixed, s) (.00001 * (fixed))

+

+/* The fixed point conversion performs range checking and evaluates

+ * its argument multiple times, so must be used with care.  The

+ * range checking uses the PNG specification values for a signed

+ * 32 bit fixed point value except that the values are deliberately

+ * rounded-to-zero to an integral value - 21474 (21474.83 is roughly

+ * (2^31-1) * 100000). 's' is a string that describes the value being

+ * converted.

+ *

+ * NOTE: this macro will raise a png_error if the range check fails,

+ * therefore it is normally only appropriate to use this on values

+ * that come from API calls or other sources where an out of range

+ * error indicates a programming error, not a data error!

+ *

+ * NOTE: by default this is off - the macro is not used - because the

+ * function call saves a lot of code.

+ */

+#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED

+#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\

+    ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0))

+#endif

+/* else the corresponding function is defined below, inside the scope of the

+ * cplusplus test.

+ */

+#endif

+

+/* Constants for known chunk types.  If you need to add a chunk, define the name

+ * here.  For historical reasons these constants have the form png_<name>; i.e.

+ * the prefix is lower case.  Please use decimal values as the parameters to

+ * match the ISO PNG specification and to avoid relying on the C locale

+ * interpretation of character values.

+ *

+ * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values

+ * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string

+ * to be generated if required.

+ *

+ * PNG_32b correctly produces a value shifted by up to 24 bits, even on

+ * architectures where (int) is only 16 bits.

+ */

+#define PNG_32b(b,s) ((png_uint_32)(b) << (s))

+#define PNG_U32(b1,b2,b3,b4) \

+   (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0))

+

+/* Constants for known chunk types.

+ *

+ * MAINTAINERS: If you need to add a chunk, define the name here.

+ * For historical reasons these constants have the form png_<name>; i.e.

+ * the prefix is lower case.  Please use decimal values as the parameters to

+ * match the ISO PNG specification and to avoid relying on the C locale

+ * interpretation of character values.  Please keep the list sorted.

+ *

+ * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk

+ * type.  In fact the specification does not express chunk types this way,

+ * however using a 32-bit value means that the chunk type can be read from the

+ * stream using exactly the same code as used for a 32-bit unsigned value and

+ * can be examined far more efficiently (using one arithmetic compare).

+ *

+ * Prior to 1.5.6 the chunk type constants were expressed as C strings.  The

+ * libpng API still uses strings for 'unknown' chunks and a macro,

+ * PNG_STRING_FROM_CHUNK, allows a string to be generated if required.  Notice

+ * that for portable code numeric values must still be used; the string "IHDR"

+ * is not portable and neither is PNG_U32('I', 'H', 'D', 'R').

+ *

+ * In 1.7.0 the definitions will be made public in png.h to avoid having to

+ * duplicate the same definitions in application code.

+ */

+#define png_IDAT PNG_U32( 73,  68,  65,  84)

+#define png_IEND PNG_U32( 73,  69,  78,  68)

+#define png_IHDR PNG_U32( 73,  72,  68,  82)

+#define png_PLTE PNG_U32( 80,  76,  84,  69)

+#define png_bKGD PNG_U32( 98,  75,  71,  68)

+#define png_cHRM PNG_U32( 99,  72,  82,  77)

+#define png_fRAc PNG_U32(102,  82,  65,  99) /* registered, not defined */

+#define png_gAMA PNG_U32(103,  65,  77,  65)

+#define png_gIFg PNG_U32(103,  73,  70, 103)

+#define png_gIFt PNG_U32(103,  73,  70, 116) /* deprecated */

+#define png_gIFx PNG_U32(103,  73,  70, 120)

+#define png_hIST PNG_U32(104,  73,  83,  84)

+#define png_iCCP PNG_U32(105,  67,  67,  80)

+#define png_iTXt PNG_U32(105,  84,  88, 116)

+#define png_oFFs PNG_U32(111,  70,  70, 115)

+#define png_pCAL PNG_U32(112,  67,  65,  76)

+#define png_pHYs PNG_U32(112,  72,  89, 115)

+#define png_sBIT PNG_U32(115,  66,  73,  84)

+#define png_sCAL PNG_U32(115,  67,  65,  76)

+#define png_sPLT PNG_U32(115,  80,  76,  84)

+#define png_sRGB PNG_U32(115,  82,  71,  66)

+#define png_sTER PNG_U32(115,  84,  69,  82)

+#define png_tEXt PNG_U32(116,  69,  88, 116)

+#define png_tIME PNG_U32(116,  73,  77,  69)

+#define png_tRNS PNG_U32(116,  82,  78,  83)

+#define png_zTXt PNG_U32(122,  84,  88, 116)

+

+/* The following will work on (signed char*) strings, whereas the get_uint_32

+ * macro will fail on top-bit-set values because of the sign extension.

+ */

+#define PNG_CHUNK_FROM_STRING(s)\

+   PNG_U32(0xff&(s)[0], 0xff&(s)[1], 0xff&(s)[2], 0xff&(s)[3])

+

+/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is

+ * signed and the argument is a (char[])  This macro will fail miserably on

+ * systems where (char) is more than 8 bits.

+ */

+#define PNG_STRING_FROM_CHUNK(s,c)\

+   (void)(((char*)(s))[0]=(char)((c)>>24), ((char*)(s))[1]=(char)((c)>>16),\

+   ((char*)(s))[2]=(char)((c)>>8), ((char*)(s))[3]=(char)((c)))

+

+/* Do the same but terminate with a null character. */

+#define PNG_CSTRING_FROM_CHUNK(s,c)\

+   (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0)

+

+/* Test on flag values as defined in the spec (section 5.4): */

+#define PNG_CHUNK_ANCILLARY(c)   (1 & ((c) >> 29))

+#define PNG_CHUNK_CRITICAL(c)     (!PNG_CHUNK_ANCILLARY(c))

+#define PNG_CHUNK_PRIVATE(c)      (1 & ((c) >> 21))

+#define PNG_CHUNK_RESERVED(c)     (1 & ((c) >> 13))

+#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >>  5))

+

+/* Gamma values (new at libpng-1.5.4): */

+#define PNG_GAMMA_MAC_OLD 151724  /* Assume '1.8' is really 2.2/1.45! */

+#define PNG_GAMMA_MAC_INVERSE 65909

+#define PNG_GAMMA_sRGB_INVERSE 45455

+

+/* Almost everything below is C specific; the #defines above can be used in

+ * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot.

+ */

+#ifndef PNG_VERSION_INFO_ONLY

+

+#include "pngstruct.h"

+#include "pnginfo.h"

+

+/* Validate the include paths - the include path used to generate pnglibconf.h

+ * must match that used in the build, or we must be using pnglibconf.h.prebuilt:

+ */

+#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM

+#  error ZLIB_VERNUM != PNG_ZLIB_VERNUM \

+      "-I (include path) error: see the notes in pngpriv.h"

+   /* This means that when pnglibconf.h was built the copy of zlib.h that it

+    * used is not the same as the one being used here.  Because the build of

+    * libpng makes decisions to use inflateInit2 and inflateReset2 based on the

+    * zlib version number and because this affects handling of certain broken

+    * PNG files the -I directives must match.

+    *

+    * The most likely explanation is that you passed a -I in CFLAGS, this will

+    * not work; all the preprocessor directories and in particular all the -I

+    * directives must be in CPPFLAGS.

+    */

+#endif

+

+/* This is used for 16 bit gamma tables -- only the top level pointers are

+ * const; this could be changed:

+ */

+typedef const png_uint_16p * png_const_uint_16pp;

+

+/* Added to libpng-1.5.7: sRGB conversion tables */

+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\

+   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)

+#ifdef PNG_SIMPLIFIED_READ_SUPPORTED

+PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]);

+   /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value,

+    * 0..65535.  This table gives the closest 16-bit answers (no errors).

+    */

+#endif

+

+PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]);

+PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]);

+

+#define PNG_sRGB_FROM_LINEAR(linear) ((png_byte)((png_sRGB_base[(linear)>>15] +\

+   ((((linear)&0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8))

+   /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB

+    * encoded value with maximum error 0.646365.  Note that the input is not a

+    * 16-bit value; it has been multiplied by 255! */

+#endif /* PNG_SIMPLIFIED_READ/WRITE */

+

+

+/* Inhibit C++ name-mangling for libpng functions but not for system calls. */

+#ifdef __cplusplus

+extern "C" {

+#endif /* __cplusplus */

+

+/* Internal functions; these are not exported from a DLL however because they

+ * are used within several of the C source files they have to be C extern.

+ *

+ * All of these functions must be declared with PNG_INTERNAL_FUNCTION.

+ */

+

+/* Zlib support */

+#define PNG_UNEXPECTED_ZLIB_RETURN (-7)

+PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret),

+   PNG_EMPTY);

+   /* Used by the zlib handling functions to ensure that z_stream::msg is always

+    * set before they return.

+    */

+

+#ifdef PNG_WRITE_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,

+   png_compression_bufferp *list),PNG_EMPTY);

+   /* Free the buffer list used by the compressed write code. */

+#endif

+

+#if defined(PNG_FLOATING_POINT_SUPPORTED) && \

+   !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \

+   (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \

+   defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \

+   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \

+   (defined(PNG_sCAL_SUPPORTED) && \

+   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))

+PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr,

+   double fp, png_const_charp text),PNG_EMPTY);

+#endif

+

+/* Check the user version string for compatibility, returns false if the version

+ * numbers aren't compatible.

+ */

+PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr,

+   png_const_charp user_png_ver),PNG_EMPTY);

+

+/* Internal base allocator - no messages, NULL on failure to allocate.  This

+ * does, however, call the application provided allocator and that could call

+ * png_error (although that would be a bug in the application implementation.)

+ */

+PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr,

+   png_alloc_size_t size),PNG_ALLOCATED);

+

+#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\

+   defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED)

+/* Internal array allocator, outputs no error or warning messages on failure,

+ * just returns NULL.  

+ */

+PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr,

+   int nelements, size_t element_size),PNG_ALLOCATED);

+

+/* The same but an existing array is extended by add_elements.  This function

+ * also memsets the new elements to 0 and copies the old elements.  The old

+ * array is not freed or altered.

+ */

+PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr,

+   png_const_voidp array, int old_elements, int add_elements,

+   size_t element_size),PNG_ALLOCATED);

+#endif /* text, sPLT or unknown chunks */

+

+/* Magic to create a struct when there is no struct to call the user supplied

+ * memory allocators.  Because error handling has not been set up the memory

+ * handlers can't safely call png_error, but this is an obscure and undocumented

+ * restriction so libpng has to assume that the 'free' handler, at least, might

+ * call png_error.

+ */

+PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct,

+   (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,

+    png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn,

+    png_free_ptr free_fn),PNG_ALLOCATED);

+

+/* Free memory from internal libpng struct */

+PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr),

+   PNG_EMPTY);

+

+/* Free an allocated jmp_buf (always succeeds) */

+PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY);

+

+/* Function to allocate memory for zlib.  PNGAPI is disallowed. */

+PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size),

+   PNG_ALLOCATED);

+

+/* Function to free memory for zlib.  PNGAPI is disallowed. */

+PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY);

+

+/* Next four functions are used internally as callbacks.  PNGCBAPI is required

+ * but not PNG_EXPORT.  PNGAPI added at libpng version 1.2.3, changed to

+ * PNGCBAPI at 1.5.0

+ */

+

+PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr,

+    png_bytep data, png_size_t length),PNG_EMPTY);

+

+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED

+PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr,

+    png_bytep buffer, png_size_t length),PNG_EMPTY);

+#endif

+

+PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr,

+    png_bytep data, png_size_t length),PNG_EMPTY);

+

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+#  ifdef PNG_STDIO_SUPPORTED

+PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr),

+   PNG_EMPTY);

+#  endif

+#endif

+

+/* Reset the CRC variable */

+PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY);

+

+/* Write the "data" buffer to whatever output you are using */

+PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr,

+    png_const_bytep data, png_size_t length),PNG_EMPTY);

+

+/* Read and check the PNG file signature */

+PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr,

+   png_inforp info_ptr),PNG_EMPTY);

+

+/* Read the chunk header (length + type name) */

+PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr),

+   PNG_EMPTY);

+

+/* Read data from whatever input you are using into the "data" buffer */

+PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data,

+    png_size_t length),PNG_EMPTY);

+

+/* Read bytes into buf, and update png_ptr->crc */

+PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf,

+    png_uint_32 length),PNG_EMPTY);

+

+/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */

+PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr,

+   png_uint_32 skip),PNG_EMPTY);

+

+/* Read the CRC from the file and compare it to the libpng calculated CRC */

+PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY);

+

+/* Calculate the CRC over a section of data.  Note that we are only

+ * passing a maximum of 64K on systems that have this as a memory limit,

+ * since this is the maximum buffer size we can specify.

+ */

+PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr,

+   png_const_bytep ptr, png_size_t length),PNG_EMPTY);

+

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY);

+#endif

+

+/* Write various chunks */

+

+/* Write the IHDR chunk, and update the png_struct with the necessary

+ * information.

+ */

+PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr,

+   png_uint_32 width, png_uint_32 height, int bit_depth, int color_type,

+   int compression_method, int filter_method, int interlace_method),PNG_EMPTY);

+

+PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr,

+   png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY);

+

+PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr,

+   png_const_bytep row_data, png_alloc_size_t row_data_length, int flush),

+   PNG_EMPTY);

+

+PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY);

+

+#ifdef PNG_WRITE_gAMA_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr,

+    png_fixed_point file_gamma),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_sBIT_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr,

+    png_const_color_8p sbit, int color_type),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_cHRM_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr,

+    const png_xy *xy), PNG_EMPTY);

+    /* The xy value must have been previously validated */

+#endif

+

+#ifdef PNG_WRITE_sRGB_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr,

+    int intent),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_iCCP_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr,

+   png_const_charp name, png_const_bytep profile), PNG_EMPTY);

+   /* The profile must have been previously validated for correctness, the

+    * length comes from the first four bytes.  Only the base, deflate,

+    * compression is supported.

+    */

+#endif

+

+#ifdef PNG_WRITE_sPLT_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr,

+    png_const_sPLT_tp palette),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_tRNS_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr,

+    png_const_bytep trans, png_const_color_16p values, int number,

+    int color_type),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_bKGD_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr,

+    png_const_color_16p values, int color_type),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_hIST_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr,

+    png_const_uint_16p hist, int num_hist),PNG_EMPTY);

+#endif

+

+/* Chunks that have keywords */

+#ifdef PNG_WRITE_tEXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr,

+   png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_zTXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp

+    key, png_const_charp text, png_size_t text_len, int compression),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_iTXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr,

+    int compression, png_const_charp key, png_const_charp lang,

+    png_const_charp lang_key, png_const_charp text),PNG_EMPTY);

+#endif

+

+#ifdef PNG_TEXT_SUPPORTED  /* Added at version 1.0.14 and 1.2.4 */

+PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr,

+    png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_oFFs_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr,

+    png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_pCAL_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr,

+    png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,

+    png_const_charp units, png_charpp params),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_pHYs_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr,

+    png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,

+    int unit_type),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_tIME_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr,

+    png_const_timep mod_time),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_sCAL_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr,

+    int unit, png_const_charp width, png_const_charp height),PNG_EMPTY);

+#endif

+

+/* Called when finished processing a row of data */

+PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr),

+    PNG_EMPTY);

+

+/* Internal use only.   Called before first row of data */

+PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr),

+    PNG_EMPTY);

+

+/* Combine a row of data, dealing with alpha, etc. if requested.  'row' is an

+ * array of png_ptr->width pixels.  If the image is not interlaced or this

+ * is the final pass this just does a memcpy, otherwise the "display" flag

+ * is used to determine whether to copy pixels that are not in the current pass.

+ *

+ * Because 'png_do_read_interlace' (below) replicates pixels this allows this

+ * function to achieve the documented 'blocky' appearance during interlaced read

+ * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row'

+ * are not changed if they are not in the current pass, when display is 0.

+ *

+ * 'display' must be 0 or 1, otherwise the memcpy will be done regardless.

+ *

+ * The API always reads from the png_struct row buffer and always assumes that

+ * it is full width (png_do_read_interlace has already been called.)

+ *

+ * This function is only ever used to write to row buffers provided by the

+ * caller of the relevant libpng API and the row must have already been

+ * transformed by the read transformations.

+ *

+ * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed

+ * bitmasks for use within the code, otherwise runtime generated masks are used.

+ * The default is compile time masks.

+ */

+#ifndef PNG_USE_COMPILE_TIME_MASKS

+#  define PNG_USE_COMPILE_TIME_MASKS 1

+#endif

+PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr,

+    png_bytep row, int display),PNG_EMPTY);

+

+#ifdef PNG_READ_INTERLACING_SUPPORTED

+/* Expand an interlaced row: the 'row_info' describes the pass data that has

+ * been read in and must correspond to the pixels in 'row', the pixels are

+ * expanded (moved apart) in 'row' to match the final layout, when doing this

+ * the pixels are *replicated* to the intervening space.  This is essential for

+ * the correct operation of png_combine_row, above.

+ */

+PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info,

+    png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY);

+#endif

+

+/* GRR TO DO (2.0 or whenever):  simplify other internal calling interfaces */

+

+#ifdef PNG_WRITE_INTERLACING_SUPPORTED

+/* Grab pixels out of a row for an interlaced pass */

+PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info,

+    png_bytep row, int pass),PNG_EMPTY);

+#endif

+

+/* Unfilter a row: check the filter value before calling this, there is no point

+ * calling it for PNG_FILTER_VALUE_NONE.

+ */

+PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop

+    row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY);

+

+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info,

+    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop

+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop

+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop

+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop

+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop

+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop

+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);

+

+/* Choose the best filter to use and filter the row data */

+PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,

+    png_row_infop row_info),PNG_EMPTY);

+

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr,

+   png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY);

+   /* Read 'avail_out' bytes of data from the IDAT stream.  If the output buffer

+    * is NULL the function checks, instead, for the end of the stream.  In this

+    * case a benign error will be issued if the stream end is not found or if

+    * extra data has to be consumed.

+    */

+PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr),

+   PNG_EMPTY);

+   /* This cleans up when the IDAT LZ stream does not end when the last image

+    * byte is read; there is still some pending input.

+    */

+

+PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr),

+   PNG_EMPTY);

+   /* Finish a row while reading, dealing with interlacing passes, etc. */

+#endif

+

+/* Initialize the row buffers, etc. */

+PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY);

+

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+/* Optional call to update the users info structure */

+PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr,

+    png_inforp info_ptr),PNG_EMPTY);

+#endif

+

+/* These are the functions that do the transformations */

+#ifdef PNG_READ_FILLER_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_read_filler,(png_row_infop row_info,

+    png_bytep row, png_uint_32 filler, png_uint_32 flags),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_read_swap_alpha,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_write_swap_alpha,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_read_invert_alpha,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_write_invert_alpha,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \

+    defined(PNG_READ_STRIP_ALPHA_SUPPORTED)

+PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info,

+    png_bytep row, int at_start),PNG_EMPTY);

+#endif

+

+#ifdef PNG_16BIT_SUPPORTED

+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)

+PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+#endif

+

+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \

+    defined(PNG_WRITE_PACKSWAP_SUPPORTED)

+PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+PNG_INTERNAL_FUNCTION(int,png_do_rgb_to_gray,(png_structrp png_ptr,

+    png_row_infop row_info, png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_gray_to_rgb,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_PACK_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_unpack,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_SHIFT_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_unshift,(png_row_infop row_info,

+    png_bytep row, png_const_color_8p sig_bits),PNG_EMPTY);

+#endif

+

+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)

+PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_scale_16_to_8,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_chop,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_QUANTIZE_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_quantize,(png_row_infop row_info,

+    png_bytep row, png_const_bytep palette_lookup,

+    png_const_bytep quantize_lookup),PNG_EMPTY);

+

+#  ifdef PNG_CORRECT_PALETTE_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_correct_palette,(png_structrp png_ptr,

+    png_colorp palette, int num_palette),PNG_EMPTY);

+#  endif

+#endif

+

+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)

+PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_PACK_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_pack,(png_row_infop row_info,

+   png_bytep row, png_uint_32 bit_depth),PNG_EMPTY);

+#endif

+

+#ifdef PNG_WRITE_SHIFT_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_shift,(png_row_infop row_info,

+    png_bytep row, png_const_color_8p bit_depth),PNG_EMPTY);

+#endif

+

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\

+    defined(PNG_READ_ALPHA_MODE_SUPPORTED)

+PNG_INTERNAL_FUNCTION(void,png_do_compose,(png_row_infop row_info,

+    png_bytep row, png_structrp png_ptr),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_gamma,(png_row_infop row_info,

+    png_bytep row, png_structrp png_ptr),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_encode_alpha,(png_row_infop row_info,

+   png_bytep row, png_structrp png_ptr),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_EXPAND_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_expand_palette,(png_row_infop row_info,

+    png_bytep row, png_const_colorp palette, png_const_bytep trans,

+    int num_trans),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_do_expand,(png_row_infop row_info,

+    png_bytep row, png_const_color_16p trans_color),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_EXPAND_16_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_expand_16,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+/* The following decodes the appropriate chunks, and does error correction,

+ * then calls the appropriate callback for the chunk if it is valid.

+ */

+

+/* Decode the IHDR chunk */

+PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+

+#ifdef PNG_READ_bKGD_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_cHRM_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_gAMA_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_hIST_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_iCCP_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif /* PNG_READ_iCCP_SUPPORTED */

+

+#ifdef PNG_READ_iTXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_oFFs_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_pCAL_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_pHYs_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_sBIT_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_sCAL_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_sPLT_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif /* PNG_READ_sPLT_SUPPORTED */

+

+#ifdef PNG_READ_sRGB_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_tEXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_tIME_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_tRNS_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_zTXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+#endif

+

+PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr,

+    png_uint_32 chunk_name),PNG_EMPTY);

+

+#ifdef PNG_READ_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY);

+   /* This is the function that gets called for unknown chunks.  The 'keep'

+    * argument is either non-zero for a known chunk that has been set to be

+    * handled as unknown or zero for an unknown chunk.  By default the function

+    * just skips the chunk or errors out if it is critical.

+    */

+

+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED

+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling,

+    (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY);

+   /* Exactly as the API png_handle_as_unknown() except that the argument is a

+    * 32-bit chunk name, not a string.

+    */

+#endif

+#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */

+#endif /* PNG_READ_SUPPORTED */

+

+/* Handle the transformations for reading and writing */

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr,

+   png_row_infop row_info),PNG_EMPTY);

+#endif

+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr,

+   png_row_infop row_info),PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_TRANSFORMS_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr),

+    PNG_EMPTY);

+#endif

+

+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr,

+    png_inforp info_ptr),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr,

+    png_inforp info_ptr),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_crc_skip,(png_structrp png_ptr,

+    png_uint_32 length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_crc_finish,(png_structrp png_ptr),

+    PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr),

+    PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr,

+    png_bytep buffer, png_size_t buffer_length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr,

+    png_bytep buffer, png_size_t buffer_length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr),

+    PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr,

+   png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr,

+   png_inforp info_ptr),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr,

+   png_inforp info_ptr),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr,

+     png_bytep row),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr,

+    png_inforp info_ptr),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr,

+    png_inforp info_ptr),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr),

+    PNG_EMPTY);

+#  ifdef PNG_READ_tEXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr,

+    png_inforp info_ptr),PNG_EMPTY);

+#  endif

+#  ifdef PNG_READ_zTXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr,

+    png_inforp info_ptr),PNG_EMPTY);

+#  endif

+#  ifdef PNG_READ_iTXt_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr,

+    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr,

+    png_inforp info_ptr),PNG_EMPTY);

+#  endif

+

+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */

+

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_do_read_intrapixel,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_do_write_intrapixel,(png_row_infop row_info,

+    png_bytep row),PNG_EMPTY);

+#endif

+

+/* Added at libpng version 1.6.0 */

+#ifdef PNG_GAMMA_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr,

+    png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY);

+   /* Set the colorspace gamma with a value provided by the application or by

+    * the gAMA chunk on read.  The value will override anything set by an ICC

+    * profile.

+    */

+

+PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr,

+    png_inforp info_ptr), PNG_EMPTY);

+    /* Synchronize the info 'valid' flags with the colorspace */

+

+PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr,

+    png_inforp info_ptr), PNG_EMPTY);

+    /* Copy the png_struct colorspace to the info_struct and call the above to

+     * synchronize the flags.  Checks for NULL info_ptr and does nothing.

+     */

+#endif

+

+/* Added at libpng version 1.4.0 */

+#ifdef PNG_COLORSPACE_SUPPORTED

+/* These internal functions are for maintaining the colorspace structure within

+ * a png_info or png_struct (or, indeed, both).

+ */

+PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities,

+   (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy,

+    int preferred), PNG_EMPTY);

+

+PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints,

+   (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ,

+    int preferred), PNG_EMPTY);

+

+#ifdef PNG_sRGB_SUPPORTED

+PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, int intent), PNG_EMPTY);

+   /* This does set the colorspace gAMA and cHRM values too, but doesn't set the

+    * flags to write them, if it returns false there was a problem and an error

+    * message has already been output (but the colorspace may still need to be

+    * synced to record the invalid flag).

+    */

+#endif /* sRGB */

+

+#ifdef PNG_iCCP_SUPPORTED

+PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, png_const_charp name,

+   png_uint_32 profile_length, png_const_bytep profile, int color_type),

+   PNG_EMPTY);

+   /* The 'name' is used for information only */

+

+/* Routines for checking parts of an ICC profile. */

+PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, png_const_charp name,

+   png_uint_32 profile_length), PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, png_const_charp name,

+   png_uint_32 profile_length,

+   png_const_bytep profile /* first 132 bytes only */, int color_type),

+   PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr,

+   png_colorspacerp colorspace, png_const_charp name,

+   png_uint_32 profile_length,

+   png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY);

+#ifdef PNG_sRGB_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,(

+   png_const_structrp png_ptr, png_colorspacerp colorspace,

+   png_const_bytep profile, uLong adler), PNG_EMPTY);

+   /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may

+    * be zero to indicate that it is not available.  It is used, if provided,

+    * as a fast check on the profile when checking to see if it is sRGB.

+    */

+#endif

+#endif /* iCCP */

+

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients,

+   (png_structrp png_ptr), PNG_EMPTY);

+   /* Set the rgb_to_gray coefficients from the colorspace Y values */

+#endif /* READ_RGB_TO_GRAY */

+#endif /* COLORSPACE */

+

+/* Added at libpng version 1.4.0 */

+PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr,

+    png_uint_32 width, png_uint_32 height, int bit_depth,

+    int color_type, int interlace_type, int compression_type,

+    int filter_type),PNG_EMPTY);

+

+/* Added at libpng version 1.5.10 */

+#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \

+    defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)

+PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes,

+   (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY);

+#endif

+

+#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)

+PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr,

+   png_const_charp name),PNG_NORETURN);

+#endif

+

+/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite

+ * the end.  Always leaves the buffer nul terminated.  Never errors out (and

+ * there is no error code.)

+ */

+PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize,

+   size_t pos, png_const_charp string),PNG_EMPTY);

+

+/* Various internal functions to handle formatted warning messages, currently

+ * only implemented for warnings.

+ */

+#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)

+/* Utility to dump an unsigned value into a buffer, given a start pointer and

+ * and end pointer (which should point just *beyond* the end of the buffer!)

+ * Returns the pointer to the start of the formatted string.  This utility only

+ * does unsigned values.

+ */

+PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start,

+   png_charp end, int format, png_alloc_size_t number),PNG_EMPTY);

+

+/* Convenience macro that takes an array: */

+#define PNG_FORMAT_NUMBER(buffer,format,number) \

+   png_format_number(buffer, buffer + (sizeof buffer), format, number)

+

+/* Suggested size for a number buffer (enough for 64 bits and a sign!) */

+#define PNG_NUMBER_BUFFER_SIZE 24

+

+/* These are the integer formats currently supported, the name is formed from

+ * the standard printf(3) format string.

+ */

+#define PNG_NUMBER_FORMAT_u     1 /* chose unsigned API! */

+#define PNG_NUMBER_FORMAT_02u   2

+#define PNG_NUMBER_FORMAT_d     1 /* chose signed API! */

+#define PNG_NUMBER_FORMAT_02d   2

+#define PNG_NUMBER_FORMAT_x     3

+#define PNG_NUMBER_FORMAT_02x   4

+#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */

+#endif

+

+#ifdef PNG_WARNINGS_SUPPORTED

+/* New defines and members adding in libpng-1.5.4 */

+#  define PNG_WARNING_PARAMETER_SIZE 32

+#  define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */

+

+/* An l-value of this type has to be passed to the APIs below to cache the

+ * values of the parameters to a formatted warning message.

+ */

+typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][

+   PNG_WARNING_PARAMETER_SIZE];

+

+PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p,

+   int number, png_const_charp string),PNG_EMPTY);

+   /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters,

+    * including the trailing '\0'.

+    */

+PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned,

+   (png_warning_parameters p, int number, int format, png_alloc_size_t value),

+   PNG_EMPTY);

+   /* Use png_alloc_size_t because it is an unsigned type as big as any we

+    * need to output.  Use the following for a signed value.

+    */

+PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed,

+   (png_warning_parameters p, int number, int format, png_int_32 value),

+   PNG_EMPTY);

+

+PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr,

+   png_warning_parameters p, png_const_charp message),PNG_EMPTY);

+   /* 'message' follows the X/Open approach of using @1, @2 to insert

+    * parameters previously supplied using the above functions.  Errors in

+    * specifying the parameters will simply result in garbage substitutions.

+    */

+#endif

+

+#ifdef PNG_BENIGN_ERRORS_SUPPORTED

+/* Application errors (new in 1.6); use these functions (declared below) for

+ * errors in the parameters or order of API function calls on read.  The

+ * 'warning' should be used for an error that can be handled completely; the

+ * 'error' for one which can be handled safely but which may lose application

+ * information or settings.

+ *

+ * By default these both result in a png_error call prior to release, while in a

+ * released version the 'warning' is just a warning.  However if the application

+ * explicitly disables benign errors (explicitly permitting the code to lose

+ * information) they both turn into warnings.

+ *

+ * If benign errors aren't supported they end up as the corresponding base call

+ * (png_warning or png_error.)

+ */

+PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr,

+   png_const_charp message),PNG_EMPTY);

+   /* The application provided invalid parameters to an API function or called

+    * an API function at the wrong time, libpng can completely recover.

+    */

+

+PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr,

+   png_const_charp message),PNG_EMPTY);

+   /* As above but libpng will ignore the call, or attempt some other partial

+    * recovery from the error.

+    */

+#else

+#  define png_app_warning(pp,s) png_warning(pp,s)

+#  define png_app_error(pp,s) png_error(pp,s)

+#endif

+

+PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr,

+   png_const_charp message, int error),PNG_EMPTY);

+   /* Report a recoverable issue in chunk data.  On read this is used to report

+    * a problem found while reading a particular chunk and the

+    * png_chunk_benign_error or png_chunk_warning function is used as

+    * appropriate.  On write this is used to report an error that comes from

+    * data set via an application call to a png_set_ API and png_app_error or

+    * png_app_warning is used as appropriate.

+    *

+    * The 'error' parameter must have one of the following values:

+    */

+#define PNG_CHUNK_WARNING     0 /* never an error */

+#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */

+#define PNG_CHUNK_ERROR       2 /* always an error */

+

+/* ASCII to FP interfaces, currently only implemented if sCAL

+ * support is required.

+ */

+#if defined(PNG_sCAL_SUPPORTED)

+/* MAX_DIGITS is actually the maximum number of characters in an sCAL

+ * width or height, derived from the precision (number of significant

+ * digits - a build time settable option) and assumptions about the

+ * maximum ridiculous exponent.

+ */

+#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/)

+

+#ifdef PNG_FLOATING_POINT_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr,

+   png_charp ascii, png_size_t size, double fp, unsigned int precision),

+   PNG_EMPTY);

+#endif /* FLOATING_POINT */

+

+#ifdef PNG_FIXED_POINT_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,

+   png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY);

+#endif /* FIXED_POINT */

+#endif /* sCAL */

+

+#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)

+/* An internal API to validate the format of a floating point number.

+ * The result is the index of the next character.  If the number is

+ * not valid it will be the index of a character in the supposed number.

+ *

+ * The format of a number is defined in the PNG extensions specification

+ * and this API is strictly conformant to that spec, not anyone elses!

+ *

+ * The format as a regular expression is:

+ *

+ * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)?

+ *

+ * or:

+ *

+ * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)?

+ *

+ * The complexity is that either integer or fraction must be present and the

+ * fraction is permitted to have no digits only if the integer is present.

+ *

+ * NOTE: The dangling E problem.

+ *   There is a PNG valid floating point number in the following:

+ *

+ *       PNG floating point numbers are not greedy.

+ *

+ *   Working this out requires *TWO* character lookahead (because of the

+ *   sign), the parser does not do this - it will fail at the 'r' - this

+ *   doesn't matter for PNG sCAL chunk values, but it requires more care

+ *   if the value were ever to be embedded in something more complex.  Use

+ *   ANSI-C strtod if you need the lookahead.

+ */

+/* State table for the parser. */

+#define PNG_FP_INTEGER    0  /* before or in integer */

+#define PNG_FP_FRACTION   1  /* before or in fraction */

+#define PNG_FP_EXPONENT   2  /* before or in exponent */

+#define PNG_FP_STATE      3  /* mask for the above */

+#define PNG_FP_SAW_SIGN   4  /* Saw +/- in current state */

+#define PNG_FP_SAW_DIGIT  8  /* Saw a digit in current state */

+#define PNG_FP_SAW_DOT   16  /* Saw a dot in current state */

+#define PNG_FP_SAW_E     32  /* Saw an E (or e) in current state */

+#define PNG_FP_SAW_ANY   60  /* Saw any of the above 4 */

+

+/* These three values don't affect the parser.  They are set but not used.

+ */

+#define PNG_FP_WAS_VALID 64  /* Preceding substring is a valid fp number */

+#define PNG_FP_NEGATIVE 128  /* A negative number, including "-0" */

+#define PNG_FP_NONZERO  256  /* A non-zero value */

+#define PNG_FP_STICKY   448  /* The above three flags */

+

+/* This is available for the caller to store in 'state' if required.  Do not

+ * call the parser after setting it (the parser sometimes clears it.)

+ */

+#define PNG_FP_INVALID  512  /* Available for callers as a distinct value */

+

+/* Result codes for the parser (boolean - true meants ok, false means

+ * not ok yet.)

+ */

+#define PNG_FP_MAYBE      0  /* The number may be valid in the future */

+#define PNG_FP_OK         1  /* The number is valid */

+

+/* Tests on the sticky non-zero and negative flags.  To pass these checks

+ * the state must also indicate that the whole number is valid - this is

+ * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this

+ * is equivalent to PNG_FP_OK above.)

+ */

+#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO)

+   /* NZ_MASK: the string is valid and a non-zero negative value */

+#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO)

+   /* Z MASK: the string is valid and a non-zero value. */

+   /* PNG_FP_SAW_DIGIT: the string is valid. */

+#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT)

+#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK)

+#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK)

+

+/* The actual parser.  This can be called repeatedly. It updates

+ * the index into the string and the state variable (which must

+ * be initialized to 0).  It returns a result code, as above.  There

+ * is no point calling the parser any more if it fails to advance to

+ * the end of the string - it is stuck on an invalid character (or

+ * terminated by '\0').

+ *

+ * Note that the pointer will consume an E or even an E+ and then leave

+ * a 'maybe' state even though a preceding integer.fraction is valid.

+ * The PNG_FP_WAS_VALID flag indicates that a preceding substring was

+ * a valid number.  It's possible to recover from this by calling

+ * the parser again (from the start, with state 0) but with a string

+ * that omits the last character (i.e. set the size to the index of

+ * the problem character.)  This has not been tested within libpng.

+ */

+PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string,

+   png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY);

+

+/* This is the same but it checks a complete string and returns true

+ * only if it just contains a floating point number.  As of 1.5.4 this

+ * function also returns the state at the end of parsing the number if

+ * it was valid (otherwise it returns 0.)  This can be used for testing

+ * for negative or zero values using the sticky flag.

+ */

+PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string,

+   png_size_t size),PNG_EMPTY);

+#endif /* pCAL || sCAL */

+

+#if defined(PNG_READ_GAMMA_SUPPORTED) ||\

+    defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)

+/* Added at libpng version 1.5.0 */

+/* This is a utility to provide a*times/div (rounded) and indicate

+ * if there is an overflow.  The result is a boolean - false (0)

+ * for overflow, true (1) if no overflow, in which case *res

+ * holds the result.

+ */

+PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a,

+   png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY);

+#endif

+

+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)

+/* Same deal, but issue a warning on overflow and return 0. */

+PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn,

+   (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by,

+   png_int_32 divided_by),PNG_EMPTY);

+#endif

+

+#ifdef PNG_GAMMA_SUPPORTED

+/* Calculate a reciprocal - used for gamma values.  This returns

+ * 0 if the argument is 0 in order to maintain an undefined value;

+ * there are no warnings.

+ */

+PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a),

+   PNG_EMPTY);

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+/* The same but gives a reciprocal of the product of two fixed point

+ * values.  Accuracy is suitable for gamma calculations but this is

+ * not exact - use png_muldiv for that.  Only required at present on read.

+ */

+PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a,

+   png_fixed_point b),PNG_EMPTY);

+#endif

+

+/* Return true if the gamma value is significantly different from 1.0 */

+PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value),

+   PNG_EMPTY);

+#endif

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+/* Internal fixed point gamma correction.  These APIs are called as

+ * required to convert single values - they don't need to be fast,

+ * they are not used when processing image pixel values.

+ *

+ * While the input is an 'unsigned' value it must actually be the

+ * correct bit value - 0..255 or 0..65535 as required.

+ */

+PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr,

+   unsigned int value, png_fixed_point gamma_value),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value,

+   png_fixed_point gamma_value),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value,

+   png_fixed_point gamma_value),PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr),

+   PNG_EMPTY);

+PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr,

+   int bit_depth),PNG_EMPTY);

+#endif

+

+/* SIMPLIFIED READ/WRITE SUPPORT */

+#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\

+   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)

+/* The internal structure that png_image::opaque points to. */

+typedef struct png_control

+{

+   png_structp png_ptr;

+   png_infop   info_ptr;

+   png_voidp   error_buf;           /* Always a jmp_buf at present. */

+

+   png_const_bytep memory;          /* Memory buffer. */

+   png_size_t      size;            /* Size of the memory buffer. */

+

+   unsigned int for_write       :1; /* Otherwise it is a read structure */

+   unsigned int owned_file      :1; /* We own the file in io_ptr */

+} png_control;

+

+/* Return the pointer to the jmp_buf from a png_control: necessary because C

+ * does not reveal the type of the elements of jmp_buf.

+ */

+#ifdef __cplusplus

+#  define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0])

+#else

+#  define png_control_jmp_buf(pc) ((pc)->error_buf)

+#endif

+

+/* Utility to safely execute a piece of libpng code catching and logging any

+ * errors that might occur.  Returns true on success, false on failure (either

+ * of the function or as a result of a png_error.)

+ */

+PNG_INTERNAL_FUNCTION(void,png_safe_error,(png_structp png_ptr,

+   png_const_charp error_message),PNG_NORETURN);

+

+#ifdef PNG_WARNINGS_SUPPORTED

+PNG_INTERNAL_FUNCTION(void,png_safe_warning,(png_structp png_ptr,

+   png_const_charp warning_message),PNG_EMPTY);

+#else

+#  define png_safe_warning 0/*dummy argument*/

+#endif

+

+PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image,

+   int (*function)(png_voidp), png_voidp arg),PNG_EMPTY);

+

+/* Utility to log an error; this also cleans up the png_image; the function

+ * always returns 0 (false).

+ */

+PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image,

+   png_const_charp error_message),PNG_EMPTY);

+

+#ifndef PNG_SIMPLIFIED_READ_SUPPORTED

+/* png_image_free is used by the write code but not exported */

+PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY);

+#endif /* !SIMPLIFIED_READ */

+

+#endif /* SIMPLIFIED READ/WRITE */

+

+/* These are initialization functions for hardware specific PNG filter

+ * optimizations; list these here then select the appropriate one at compile

+ * time using the macro PNG_FILTER_OPTIMIZATIONS.  If the macro is not defined

+ * the generic code is used.

+ */

+#ifdef PNG_FILTER_OPTIMIZATIONS

+PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr,

+   unsigned int bpp), PNG_EMPTY);

+   /* Just declare the optimization that will be used */

+#else

+   /* List *all* the possible optimizations here - this branch is required if

+    * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in

+    * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing.

+    */

+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon,

+   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);

+#endif

+

+/* Maintainer: Put new private prototypes here ^ */

+

+#include "pngdebug.h"

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif /* PNG_VERSION_INFO_ONLY */

+#endif /* PNGPRIV_H */

diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pngstruct.h b/core/src/fxcodec/fx_lpng/lpng_v163/pngstruct.h
new file mode 100644
index 0000000..2694705
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/lpng_v163/pngstruct.h
@@ -0,0 +1,489 @@
+

+/* pngstruct.h - header file for PNG reference library

+ *

+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson

+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)

+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)

+ *

+ * Last changed in libpng 1.6.1 [March 28, 2013]

+ *

+ * This code is released under the libpng license.

+ * For conditions of distribution and use, see the disclaimer

+ * and license in png.h

+ */

+

+/* The structure that holds the information to read and write PNG files.

+ * The only people who need to care about what is inside of this are the

+ * people who will be modifying the library for their own special needs.

+ * It should NOT be accessed directly by an application.

+ */

+

+#ifndef PNGSTRUCT_H

+#define PNGSTRUCT_H

+/* zlib.h defines the structure z_stream, an instance of which is included

+ * in this structure and is required for decompressing the LZ compressed

+ * data in PNG files.

+ */

+#ifndef ZLIB_CONST

+   /* We must ensure that zlib uses 'const' in declarations. */

+#  define ZLIB_CONST

+#endif

+#include "../../fx_zlib/include/fx_zlib.h"

+#ifdef const

+   /* zlib.h sometimes #defines const to nothing, undo this. */

+#  undef const

+#endif

+

+/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility

+ * with older builds.

+ */

+#if ZLIB_VERNUM < 0x1260

+#  define PNGZ_MSG_CAST(s) png_constcast(char*,s)

+#  define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b)

+#else

+#  define PNGZ_MSG_CAST(s) (s)

+#  define PNGZ_INPUT_CAST(b) (b)

+#endif

+

+/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib

+ * can handle at once.  This type need be no larger than 16 bits (so maximum of

+ * 65535), this define allows us to discover how big it is, but limited by the

+ * maximuum for png_size_t.  The value can be overriden in a library build

+ * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably

+ * lower value (e.g. 255 works).  A lower value may help memory usage (slightly)

+ * and may even improve performance on some systems (and degrade it on others.)

+ */

+#ifndef ZLIB_IO_MAX

+#  define ZLIB_IO_MAX ((uInt)-1)

+#endif

+

+#ifdef PNG_WRITE_SUPPORTED

+/* The type of a compression buffer list used by the write code. */

+typedef struct png_compression_buffer

+{

+   struct png_compression_buffer *next;

+   png_byte                       output[1]; /* actually zbuf_size */

+} png_compression_buffer, *png_compression_bufferp;

+

+#define PNG_COMPRESSION_BUFFER_SIZE(pp)\

+   (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size)

+#endif

+

+/* Colorspace support; structures used in png_struct, png_info and in internal

+ * functions to hold and communicate information about the color space.

+ *

+ * PNG_COLORSPACE_SUPPORTED is only required if the application will perform

+ * colorspace corrections, otherwise all the colorspace information can be

+ * skipped and the size of libpng can be reduced (significantly) by compiling

+ * out the colorspace support.

+ */

+#ifdef PNG_COLORSPACE_SUPPORTED

+/* The chromaticities of the red, green and blue colorants and the chromaticity

+ * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)).

+ */

+typedef struct png_xy

+{

+   png_fixed_point redx, redy;

+   png_fixed_point greenx, greeny;

+   png_fixed_point bluex, bluey;

+   png_fixed_point whitex, whitey;

+} png_xy;

+

+/* The same data as above but encoded as CIE XYZ values.  When this data comes

+ * from chromaticities the sum of the Y values is assumed to be 1.0

+ */

+typedef struct png_XYZ

+{

+   png_fixed_point red_X, red_Y, red_Z;

+   png_fixed_point green_X, green_Y, green_Z;

+   png_fixed_point blue_X, blue_Y, blue_Z;

+} png_XYZ;

+#endif /* COLORSPACE */

+

+#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)

+/* A colorspace is all the above plus, potentially, profile information,

+ * however at present libpng does not use the profile internally so it is only

+ * stored in the png_info struct (if iCCP is supported.)  The rendering intent

+ * is retained here and is checked.

+ *

+ * The file gamma encoding information is also stored here and gamma correction

+ * is done by libpng, whereas color correction must currently be done by the

+ * application.

+ */

+typedef struct png_colorspace

+{

+#ifdef PNG_GAMMA_SUPPORTED

+   png_fixed_point gamma;        /* File gamma */

+#endif

+

+#ifdef PNG_COLORSPACE_SUPPORTED

+   png_xy      end_points_xy;    /* End points as chromaticities */

+   png_XYZ     end_points_XYZ;   /* End points as CIE XYZ colorant values */

+   png_uint_16 rendering_intent; /* Rendering intent of a profile */

+#endif

+

+   /* Flags are always defined to simplify the code. */

+   png_uint_16 flags;            /* As defined below */

+} png_colorspace, * PNG_RESTRICT png_colorspacerp;

+

+typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp;

+

+/* General flags for the 'flags' field */

+#define PNG_COLORSPACE_HAVE_GAMMA           0x0001

+#define PNG_COLORSPACE_HAVE_ENDPOINTS       0x0002

+#define PNG_COLORSPACE_HAVE_INTENT          0x0004

+#define PNG_COLORSPACE_FROM_gAMA            0x0008

+#define PNG_COLORSPACE_FROM_cHRM            0x0010

+#define PNG_COLORSPACE_FROM_sRGB            0x0020

+#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040

+#define PNG_COLORSPACE_MATCHES_sRGB         0x0080 /* exact match on profile */

+#define PNG_COLORSPACE_INVALID              0x8000

+#define PNG_COLORSPACE_CANCEL(flags)        (0xffff ^ (flags))

+#endif /* COLORSPACE || GAMMA */

+

+struct png_struct_def

+{

+#ifdef PNG_SETJMP_SUPPORTED

+   jmp_buf jmp_buf_local;     /* New name in 1.6.0 for jmp_buf in png_struct */

+   png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */

+   jmp_buf *jmp_buf_ptr;      /* passed to longjmp_fn */

+   size_t jmp_buf_size;       /* size of the above, if allocated */

+#endif

+   png_error_ptr error_fn;    /* function for printing errors and aborting */

+#ifdef PNG_WARNINGS_SUPPORTED

+   png_error_ptr warning_fn;  /* function for printing warnings */

+#endif

+   png_voidp error_ptr;       /* user supplied struct for error functions */

+   png_rw_ptr write_data_fn;  /* function for writing output data */

+   png_rw_ptr read_data_fn;   /* function for reading input data */

+   png_voidp io_ptr;          /* ptr to application struct for I/O functions */

+

+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED

+   png_user_transform_ptr read_user_transform_fn; /* user read transform */

+#endif

+

+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED

+   png_user_transform_ptr write_user_transform_fn; /* user write transform */

+#endif

+

+/* These were added in libpng-1.0.2 */

+#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED

+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \

+    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)

+   png_voidp user_transform_ptr; /* user supplied struct for user transform */

+   png_byte user_transform_depth;    /* bit depth of user transformed pixels */

+   png_byte user_transform_channels; /* channels in user transformed pixels */

+#endif

+#endif

+

+   png_uint_32 mode;          /* tells us where we are in the PNG file */

+   png_uint_32 flags;         /* flags indicating various things to libpng */

+   png_uint_32 transformations; /* which transformations to perform */

+

+   png_uint_32 zowner;        /* ID (chunk type) of zstream owner, 0 if none */

+   z_stream    zstream;       /* decompression structure */

+

+#ifdef PNG_WRITE_SUPPORTED

+   png_compression_bufferp zbuffer_list; /* Created on demand during write */

+   uInt                    zbuffer_size; /* size of the actual buffer */

+

+   int zlib_level;            /* holds zlib compression level */

+   int zlib_method;           /* holds zlib compression method */

+   int zlib_window_bits;      /* holds zlib compression window bits */

+   int zlib_mem_level;        /* holds zlib compression memory level */

+   int zlib_strategy;         /* holds zlib compression strategy */

+#endif

+/* Added at libpng 1.5.4 */

+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED

+   int zlib_text_level;            /* holds zlib compression level */

+   int zlib_text_method;           /* holds zlib compression method */

+   int zlib_text_window_bits;      /* holds zlib compression window bits */

+   int zlib_text_mem_level;        /* holds zlib compression memory level */

+   int zlib_text_strategy;         /* holds zlib compression strategy */

+#endif

+/* End of material added at libpng 1.5.4 */

+/* Added at libpng 1.6.0 */

+#ifdef PNG_WRITE_SUPPORTED

+   int zlib_set_level;        /* Actual values set into the zstream on write */

+   int zlib_set_method;

+   int zlib_set_window_bits;

+   int zlib_set_mem_level;

+   int zlib_set_strategy;

+#endif

+

+   png_uint_32 width;         /* width of image in pixels */

+   png_uint_32 height;        /* height of image in pixels */

+   png_uint_32 num_rows;      /* number of rows in current pass */

+   png_uint_32 usr_width;     /* width of row at start of write */

+   png_size_t rowbytes;       /* size of row in bytes */

+   png_uint_32 iwidth;        /* width of current interlaced row in pixels */

+   png_uint_32 row_number;    /* current row in interlace pass */

+   png_uint_32 chunk_name;    /* PNG_CHUNK() id of current chunk */

+   png_bytep prev_row;        /* buffer to save previous (unfiltered) row.

+                               * This is a pointer into big_prev_row

+                               */

+   png_bytep row_buf;         /* buffer to save current (unfiltered) row.

+                               * This is a pointer into big_row_buf

+                               */

+#ifdef PNG_WRITE_SUPPORTED

+   png_bytep sub_row;         /* buffer to save "sub" row when filtering */

+   png_bytep up_row;          /* buffer to save "up" row when filtering */

+   png_bytep avg_row;         /* buffer to save "avg" row when filtering */

+   png_bytep paeth_row;       /* buffer to save "Paeth" row when filtering */

+#endif

+   png_size_t info_rowbytes;  /* Added in 1.5.4: cache of updated row bytes */

+

+   png_uint_32 idat_size;     /* current IDAT size for read */

+   png_uint_32 crc;           /* current chunk CRC value */

+   png_colorp palette;        /* palette from the input file */

+   png_uint_16 num_palette;   /* number of color entries in palette */

+

+/* Added at libpng-1.5.10 */

+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED

+   int num_palette_max;       /* maximum palette index found in IDAT */

+#endif

+

+   png_uint_16 num_trans;     /* number of transparency values */

+   png_byte compression;      /* file compression type (always 0) */

+   png_byte filter;           /* file filter type (always 0) */

+   png_byte interlaced;       /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */

+   png_byte pass;             /* current interlace pass (0 - 6) */

+   png_byte do_filter;        /* row filter flags (see PNG_FILTER_ below ) */

+   png_byte color_type;       /* color type of file */

+   png_byte bit_depth;        /* bit depth of file */

+   png_byte usr_bit_depth;    /* bit depth of users row: write only */

+   png_byte pixel_depth;      /* number of bits per pixel */

+   png_byte channels;         /* number of channels in file */

+#ifdef PNG_WRITE_SUPPORTED

+   png_byte usr_channels;     /* channels at start of write: write only */

+#endif

+   png_byte sig_bytes;        /* magic bytes read/written from start of file */

+   png_byte maximum_pixel_depth;

+                              /* pixel depth used for the row buffers */

+   png_byte transformed_pixel_depth;

+                              /* pixel depth after read/write transforms */

+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)

+   png_uint_16 filler;           /* filler bytes for pixel expansion */

+#endif

+

+#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)

+   png_byte background_gamma_type;

+   png_fixed_point background_gamma;

+   png_color_16 background;   /* background color in screen gamma space */

+#ifdef PNG_READ_GAMMA_SUPPORTED

+   png_color_16 background_1; /* background normalized to gamma 1.0 */

+#endif

+#endif /* PNG_bKGD_SUPPORTED */

+

+#ifdef PNG_WRITE_FLUSH_SUPPORTED

+   png_flush_ptr output_flush_fn; /* Function for flushing output */

+   png_uint_32 flush_dist;    /* how many rows apart to flush, 0 - no flush */

+   png_uint_32 flush_rows;    /* number of rows written since last flush */

+#endif

+

+#ifdef PNG_READ_GAMMA_SUPPORTED

+   int gamma_shift;      /* number of "insignificant" bits in 16-bit gamma */

+   png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */

+

+   png_bytep gamma_table;     /* gamma table for 8-bit depth files */

+   png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */

+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \

+   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \

+   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)

+   png_bytep gamma_from_1;    /* converts from 1.0 to screen */

+   png_bytep gamma_to_1;      /* converts from file to 1.0 */

+   png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */

+   png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */

+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */

+#endif

+

+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)

+   png_color_8 sig_bit;       /* significant bits in each available channel */

+#endif

+

+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)

+   png_color_8 shift;         /* shift for significant bit tranformation */

+#endif

+

+#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \

+ || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)

+   png_bytep trans_alpha;           /* alpha values for paletted files */

+   png_color_16 trans_color;  /* transparent color for non-paletted files */

+#endif

+

+   png_read_status_ptr read_row_fn;   /* called after each row is decoded */

+   png_write_status_ptr write_row_fn; /* called after each row is encoded */

+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED

+   png_progressive_info_ptr info_fn; /* called after header data fully read */

+   png_progressive_row_ptr row_fn;   /* called after a prog. row is decoded */

+   png_progressive_end_ptr end_fn;   /* called after image is complete */

+   png_bytep save_buffer_ptr;        /* current location in save_buffer */

+   png_bytep save_buffer;            /* buffer for previously read data */

+   png_bytep current_buffer_ptr;     /* current location in current_buffer */

+   png_bytep current_buffer;         /* buffer for recently used data */

+   png_uint_32 push_length;          /* size of current input chunk */

+   png_uint_32 skip_length;          /* bytes to skip in input data */

+   png_size_t save_buffer_size;      /* amount of data now in save_buffer */

+   png_size_t save_buffer_max;       /* total size of save_buffer */

+   png_size_t buffer_size;           /* total amount of available input data */

+   png_size_t current_buffer_size;   /* amount of data now in current_buffer */

+   int process_mode;                 /* what push library is currently doing */

+   int cur_palette;                  /* current push library palette index */

+

+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */

+

+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)

+/* For the Borland special 64K segment handler */

+   png_bytepp offset_table_ptr;

+   png_bytep offset_table;

+   png_uint_16 offset_table_number;

+   png_uint_16 offset_table_count;

+   png_uint_16 offset_table_count_free;

+#endif

+

+#ifdef PNG_READ_QUANTIZE_SUPPORTED

+   png_bytep palette_lookup; /* lookup table for quantizing */

+   png_bytep quantize_index; /* index translation for palette files */

+#endif

+

+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED

+   png_byte heuristic_method;        /* heuristic for row filter selection */

+   png_byte num_prev_filters;        /* number of weights for previous rows */

+   png_bytep prev_filters;           /* filter type(s) of previous row(s) */

+   png_uint_16p filter_weights;      /* weight(s) for previous line(s) */

+   png_uint_16p inv_filter_weights;  /* 1/weight(s) for previous line(s) */

+   png_uint_16p filter_costs;        /* relative filter calculation cost */

+   png_uint_16p inv_filter_costs;    /* 1/relative filter calculation cost */

+#endif

+

+   /* Options */

+#ifdef PNG_SET_OPTION_SUPPORTED

+   png_byte options;           /* On/off state (up to 4 options) */

+#endif

+

+#if PNG_LIBPNG_VER < 10700

+/* To do: remove this from libpng-1.7 */

+#ifdef PNG_TIME_RFC1123_SUPPORTED

+   char time_buffer[29]; /* String to hold RFC 1123 time text */

+#endif

+#endif

+

+/* New members added in libpng-1.0.6 */

+

+   png_uint_32 free_me;    /* flags items libpng is responsible for freeing */

+

+#ifdef PNG_USER_CHUNKS_SUPPORTED

+   png_voidp user_chunk_ptr;

+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED

+   png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */

+#endif

+#endif

+

+#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED

+   int          unknown_default; /* As PNG_HANDLE_* */

+   unsigned int num_chunk_list;  /* Number of entries in the list */

+   png_bytep    chunk_list;      /* List of png_byte[5]; the textual chunk name

+                                  * followed by a PNG_HANDLE_* byte */

+#endif

+

+/* New members added in libpng-1.0.3 */

+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED

+   png_byte rgb_to_gray_status;

+   /* Added in libpng 1.5.5 to record setting of coefficients: */

+   png_byte rgb_to_gray_coefficients_set;

+   /* These were changed from png_byte in libpng-1.0.6 */

+   png_uint_16 rgb_to_gray_red_coeff;

+   png_uint_16 rgb_to_gray_green_coeff;

+   /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */

+#endif

+

+/* New member added in libpng-1.0.4 (renamed in 1.0.9) */

+#if defined(PNG_MNG_FEATURES_SUPPORTED)

+/* Changed from png_byte to png_uint_32 at version 1.2.0 */

+   png_uint_32 mng_features_permitted;

+#endif

+

+/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */

+#ifdef PNG_MNG_FEATURES_SUPPORTED

+   png_byte filter_type;

+#endif

+

+/* New members added in libpng-1.2.0 */

+

+/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */

+#ifdef PNG_USER_MEM_SUPPORTED

+   png_voidp mem_ptr;             /* user supplied struct for mem functions */

+   png_malloc_ptr malloc_fn;      /* function for allocating memory */

+   png_free_ptr free_fn;          /* function for freeing memory */

+#endif

+

+/* New member added in libpng-1.0.13 and 1.2.0 */

+   png_bytep big_row_buf;         /* buffer to save current (unfiltered) row */

+

+#ifdef PNG_READ_QUANTIZE_SUPPORTED

+/* The following three members were added at version 1.0.14 and 1.2.4 */

+   png_bytep quantize_sort;          /* working sort array */

+   png_bytep index_to_palette;       /* where the original index currently is

+                                        in the palette */

+   png_bytep palette_to_index;       /* which original index points to this

+                                         palette color */

+#endif

+

+/* New members added in libpng-1.0.16 and 1.2.6 */

+   png_byte compression_type;

+

+#ifdef PNG_USER_LIMITS_SUPPORTED

+   png_uint_32 user_width_max;

+   png_uint_32 user_height_max;

+

+   /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown

+    * chunks that can be stored (0 means unlimited).

+    */

+   png_uint_32 user_chunk_cache_max;

+

+   /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk

+    * can occupy when decompressed.  0 means unlimited.

+    */

+   png_alloc_size_t user_chunk_malloc_max;

+#endif

+

+/* New member added in libpng-1.0.25 and 1.2.17 */

+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED

+   /* Temporary storage for unknown chunk that the library doesn't recognize,

+    * used while reading the chunk.

+    */

+   png_unknown_chunk unknown_chunk;

+#endif

+

+/* New member added in libpng-1.2.26 */

+  png_size_t old_big_row_buf_size;

+

+#ifdef PNG_READ_SUPPORTED

+/* New member added in libpng-1.2.30 */

+  png_bytep        read_buffer;      /* buffer for reading chunk data */

+  png_alloc_size_t read_buffer_size; /* current size of the buffer */

+#endif

+#ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+  uInt             IDAT_read_size;   /* limit on read buffer size for IDAT */

+#endif

+

+#ifdef PNG_IO_STATE_SUPPORTED

+/* New member added in libpng-1.4.0 */

+   png_uint_32 io_state;

+#endif

+

+/* New member added in libpng-1.5.6 */

+   png_bytep big_prev_row;

+

+/* New member added in libpng-1.5.7 */

+   void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info,

+      png_bytep row, png_const_bytep prev_row);

+

+#ifdef PNG_READ_SUPPORTED

+#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)

+   png_colorspace   colorspace;

+#endif

+#endif

+};

+#endif /* PNGSTRUCT_H */

diff --git a/core/src/fxcodec/fx_lpng/src/fx_png.c b/core/src/fxcodec/fx_lpng/src/fx_png.c
new file mode 100644
index 0000000..7b65826
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_png.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_png.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngerror.c b/core/src/fxcodec/fx_lpng/src/fx_pngerror.c
new file mode 100644
index 0000000..7581b99
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngerror.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngerror.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngget.c b/core/src/fxcodec/fx_lpng/src/fx_pngget.c
new file mode 100644
index 0000000..cc8dc4e
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngget.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngget.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngmem.c b/core/src/fxcodec/fx_lpng/src/fx_pngmem.c
new file mode 100644
index 0000000..9892408
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngmem.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngmem.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngpread.c b/core/src/fxcodec/fx_lpng/src/fx_pngpread.c
new file mode 100644
index 0000000..8d53be2
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngpread.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngpread.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngread.c b/core/src/fxcodec/fx_lpng/src/fx_pngread.c
new file mode 100644
index 0000000..c612bd5
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngread.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngread.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngrio.c b/core/src/fxcodec/fx_lpng/src/fx_pngrio.c
new file mode 100644
index 0000000..d324a8e
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngrio.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngrio.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngrtran.c b/core/src/fxcodec/fx_lpng/src/fx_pngrtran.c
new file mode 100644
index 0000000..bec380d
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngrtran.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngrtran.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngrutil.c b/core/src/fxcodec/fx_lpng/src/fx_pngrutil.c
new file mode 100644
index 0000000..a3da355
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngrutil.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngrutil.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngset.c b/core/src/fxcodec/fx_lpng/src/fx_pngset.c
new file mode 100644
index 0000000..76a72223
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngset.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngset.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngtrans.c b/core/src/fxcodec/fx_lpng/src/fx_pngtrans.c
new file mode 100644
index 0000000..eac49bf
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngtrans.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngtrans.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngwio.c b/core/src/fxcodec/fx_lpng/src/fx_pngwio.c
new file mode 100644
index 0000000..3fb21e5
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngwio.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngwio.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngwrite.c b/core/src/fxcodec/fx_lpng/src/fx_pngwrite.c
new file mode 100644
index 0000000..4434fd0
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngwrite.c
@@ -0,0 +1,10 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#ifdef _MSC_VER

+#define _CRT_SECURE_NO_WARNINGS

+#endif

+#include "../lpng_v163/fx_pngwrite.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngwtran.c b/core/src/fxcodec/fx_lpng/src/fx_pngwtran.c
new file mode 100644
index 0000000..8a095d3
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngwtran.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngwtran.c"

diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngwutil.c b/core/src/fxcodec/fx_lpng/src/fx_pngwutil.c
new file mode 100644
index 0000000..b07fb40
--- /dev/null
+++ b/core/src/fxcodec/fx_lpng/src/fx_pngwutil.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../lpng_v163/fx_pngwutil.c"

diff --git a/core/src/fxcodec/fx_tiff/include/fx_tiffiop.h b/core/src/fxcodec/fx_tiff/include/fx_tiffiop.h
new file mode 100644
index 0000000..8c78903
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/include/fx_tiffiop.h
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tiffiop.h"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_aux.c b/core/src/fxcodec/fx_tiff/src/fx_tif_aux.c
new file mode 100644
index 0000000..55d4f65
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_aux.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_aux.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_close.c b/core/src/fxcodec/fx_tiff/src/fx_tif_close.c
new file mode 100644
index 0000000..3645bd2
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_close.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_close.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_codec.c b/core/src/fxcodec/fx_tiff/src/fx_tif_codec.c
new file mode 100644
index 0000000..183622f
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_codec.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_codec.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_color.c b/core/src/fxcodec/fx_tiff/src/fx_tif_color.c
new file mode 100644
index 0000000..ce0f6fb
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_color.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_color.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_compress.c b/core/src/fxcodec/fx_tiff/src/fx_tif_compress.c
new file mode 100644
index 0000000..cdbf26c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_compress.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_compress.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dir.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dir.c
new file mode 100644
index 0000000..2dc94bb
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dir.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_dir.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dirinfo.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dirinfo.c
new file mode 100644
index 0000000..5481733
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dirinfo.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_dirinfo.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dirread.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dirread.c
new file mode 100644
index 0000000..ef57dfd
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dirread.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_dirread.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dirwrite.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dirwrite.c
new file mode 100644
index 0000000..daee77b
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dirwrite.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_dirwrite.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dumpmode.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dumpmode.c
new file mode 100644
index 0000000..1ece3b8
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dumpmode.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_dumpmode.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_error.c b/core/src/fxcodec/fx_tiff/src/fx_tif_error.c
new file mode 100644
index 0000000..8693e9d
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_error.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_error.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_extension.c b/core/src/fxcodec/fx_tiff/src/fx_tif_extension.c
new file mode 100644
index 0000000..3b92492
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_extension.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_extension.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_fax3.c b/core/src/fxcodec/fx_tiff/src/fx_tif_fax3.c
new file mode 100644
index 0000000..68d26de
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_fax3.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_fax3.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_fax3sm.c b/core/src/fxcodec/fx_tiff/src/fx_tif_fax3sm.c
new file mode 100644
index 0000000..aa633e7
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_fax3sm.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_fax3sm.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_flush.c b/core/src/fxcodec/fx_tiff/src/fx_tif_flush.c
new file mode 100644
index 0000000..40884c8
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_flush.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_flush.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_getimage.c b/core/src/fxcodec/fx_tiff/src/fx_tif_getimage.c
new file mode 100644
index 0000000..15c8ee4
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_getimage.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_getimage.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_jpeg.c b/core/src/fxcodec/fx_tiff/src/fx_tif_jpeg.c
new file mode 100644
index 0000000..03ee51f
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_jpeg.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_jpeg.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_luv.c b/core/src/fxcodec/fx_tiff/src/fx_tif_luv.c
new file mode 100644
index 0000000..08768e7
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_luv.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_luv.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_lzw.c b/core/src/fxcodec/fx_tiff/src/fx_tif_lzw.c
new file mode 100644
index 0000000..8323113
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_lzw.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_lzw.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_next.c b/core/src/fxcodec/fx_tiff/src/fx_tif_next.c
new file mode 100644
index 0000000..a13df45
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_next.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_next.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_ojpeg.c b/core/src/fxcodec/fx_tiff/src/fx_tif_ojpeg.c
new file mode 100644
index 0000000..fed1911
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_ojpeg.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_ojpeg.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_open.c b/core/src/fxcodec/fx_tiff/src/fx_tif_open.c
new file mode 100644
index 0000000..682ffe6
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_open.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_open.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_packbits.c b/core/src/fxcodec/fx_tiff/src/fx_tif_packbits.c
new file mode 100644
index 0000000..349930f
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_packbits.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_packbits.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_pixarlog.c b/core/src/fxcodec/fx_tiff/src/fx_tif_pixarlog.c
new file mode 100644
index 0000000..2812901
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_pixarlog.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_pixarlog.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_predict.c b/core/src/fxcodec/fx_tiff/src/fx_tif_predict.c
new file mode 100644
index 0000000..eab405a
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_predict.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_predict.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_print.c b/core/src/fxcodec/fx_tiff/src/fx_tif_print.c
new file mode 100644
index 0000000..9a16a92
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_print.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_print.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_read.c b/core/src/fxcodec/fx_tiff/src/fx_tif_read.c
new file mode 100644
index 0000000..64289bb
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_read.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_read.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_strip.c b/core/src/fxcodec/fx_tiff/src/fx_tif_strip.c
new file mode 100644
index 0000000..e642a4e
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_strip.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_strip.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_swab.c b/core/src/fxcodec/fx_tiff/src/fx_tif_swab.c
new file mode 100644
index 0000000..e9c6b10
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_swab.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_swab.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_thunder.c b/core/src/fxcodec/fx_tiff/src/fx_tif_thunder.c
new file mode 100644
index 0000000..80f523c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_thunder.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_thunder.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_tile.c b/core/src/fxcodec/fx_tiff/src/fx_tif_tile.c
new file mode 100644
index 0000000..49cd404
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_tile.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_tile.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_version.c b/core/src/fxcodec/fx_tiff/src/fx_tif_version.c
new file mode 100644
index 0000000..6d62e3c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_version.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_version.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_warning.c b/core/src/fxcodec/fx_tiff/src/fx_tif_warning.c
new file mode 100644
index 0000000..cb1921d
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_warning.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_warning.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_write.c b/core/src/fxcodec/fx_tiff/src/fx_tif_write.c
new file mode 100644
index 0000000..9ab43fa
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_write.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_write.c"

diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_zip.c b/core/src/fxcodec/fx_tiff/src/fx_tif_zip.c
new file mode 100644
index 0000000..8460a3f
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/src/fx_tif_zip.c
@@ -0,0 +1,7 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "../tiff_v403/tif_zip.c"

diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/t4.h b/core/src/fxcodec/fx_tiff/tiff_v403/t4.h
new file mode 100644
index 0000000..b908f54
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/t4.h
@@ -0,0 +1,292 @@
+/* $Id: t4.h,v 1.3 2010-03-10 18:56:48 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _T4_
+#define	_T4_
+/*
+ * CCITT T.4 1D Huffman runlength codes and
+ * related definitions.  Given the small sizes
+ * of these tables it does not seem
+ * worthwhile to make code & length 8 bits.
+ */
+typedef struct tableentry {
+    unsigned short length;  /* bit length of g3 code */
+    unsigned short code;    /* g3 code */
+    short runlen;           /* run length in bits */
+} tableentry;
+
+#define EOL	0x001	/* EOL code value - 0000 0000 0000 1 */
+
+/* status values returned instead of a run length */
+#define G3CODE_EOL	-1	/* NB: ACT_EOL - ACT_WRUNT */
+#define G3CODE_INVALID	-2	/* NB: ACT_INVALID - ACT_WRUNT */
+#define G3CODE_EOF	-3	/* end of input data */
+#define G3CODE_INCOMP	-4	/* incomplete run code */
+
+/*
+ * Note that these tables are ordered such that the
+ * index into the table is known to be either the
+ * run length, or (run length / 64) + a fixed offset.
+ *
+ * NB: The G3CODE_INVALID entries are only used
+ *     during state generation (see mkg3states.c).
+ */
+#ifdef G3CODES
+const tableentry TIFFFaxWhiteCodes[] = {
+    { 8, 0x35, 0 },	/* 0011 0101 */
+    { 6, 0x7, 1 },	/* 0001 11 */
+    { 4, 0x7, 2 },	/* 0111 */
+    { 4, 0x8, 3 },	/* 1000 */
+    { 4, 0xB, 4 },	/* 1011 */
+    { 4, 0xC, 5 },	/* 1100 */
+    { 4, 0xE, 6 },	/* 1110 */
+    { 4, 0xF, 7 },	/* 1111 */
+    { 5, 0x13, 8 },	/* 1001 1 */
+    { 5, 0x14, 9 },	/* 1010 0 */
+    { 5, 0x7, 10 },	/* 0011 1 */
+    { 5, 0x8, 11 },	/* 0100 0 */
+    { 6, 0x8, 12 },	/* 0010 00 */
+    { 6, 0x3, 13 },	/* 0000 11 */
+    { 6, 0x34, 14 },	/* 1101 00 */
+    { 6, 0x35, 15 },	/* 1101 01 */
+    { 6, 0x2A, 16 },	/* 1010 10 */
+    { 6, 0x2B, 17 },	/* 1010 11 */
+    { 7, 0x27, 18 },	/* 0100 111 */
+    { 7, 0xC, 19 },	/* 0001 100 */
+    { 7, 0x8, 20 },	/* 0001 000 */
+    { 7, 0x17, 21 },	/* 0010 111 */
+    { 7, 0x3, 22 },	/* 0000 011 */
+    { 7, 0x4, 23 },	/* 0000 100 */
+    { 7, 0x28, 24 },	/* 0101 000 */
+    { 7, 0x2B, 25 },	/* 0101 011 */
+    { 7, 0x13, 26 },	/* 0010 011 */
+    { 7, 0x24, 27 },	/* 0100 100 */
+    { 7, 0x18, 28 },	/* 0011 000 */
+    { 8, 0x2, 29 },	/* 0000 0010 */
+    { 8, 0x3, 30 },	/* 0000 0011 */
+    { 8, 0x1A, 31 },	/* 0001 1010 */
+    { 8, 0x1B, 32 },	/* 0001 1011 */
+    { 8, 0x12, 33 },	/* 0001 0010 */
+    { 8, 0x13, 34 },	/* 0001 0011 */
+    { 8, 0x14, 35 },	/* 0001 0100 */
+    { 8, 0x15, 36 },	/* 0001 0101 */
+    { 8, 0x16, 37 },	/* 0001 0110 */
+    { 8, 0x17, 38 },	/* 0001 0111 */
+    { 8, 0x28, 39 },	/* 0010 1000 */
+    { 8, 0x29, 40 },	/* 0010 1001 */
+    { 8, 0x2A, 41 },	/* 0010 1010 */
+    { 8, 0x2B, 42 },	/* 0010 1011 */
+    { 8, 0x2C, 43 },	/* 0010 1100 */
+    { 8, 0x2D, 44 },	/* 0010 1101 */
+    { 8, 0x4, 45 },	/* 0000 0100 */
+    { 8, 0x5, 46 },	/* 0000 0101 */
+    { 8, 0xA, 47 },	/* 0000 1010 */
+    { 8, 0xB, 48 },	/* 0000 1011 */
+    { 8, 0x52, 49 },	/* 0101 0010 */
+    { 8, 0x53, 50 },	/* 0101 0011 */
+    { 8, 0x54, 51 },	/* 0101 0100 */
+    { 8, 0x55, 52 },	/* 0101 0101 */
+    { 8, 0x24, 53 },	/* 0010 0100 */
+    { 8, 0x25, 54 },	/* 0010 0101 */
+    { 8, 0x58, 55 },	/* 0101 1000 */
+    { 8, 0x59, 56 },	/* 0101 1001 */
+    { 8, 0x5A, 57 },	/* 0101 1010 */
+    { 8, 0x5B, 58 },	/* 0101 1011 */
+    { 8, 0x4A, 59 },	/* 0100 1010 */
+    { 8, 0x4B, 60 },	/* 0100 1011 */
+    { 8, 0x32, 61 },	/* 0011 0010 */
+    { 8, 0x33, 62 },	/* 0011 0011 */
+    { 8, 0x34, 63 },	/* 0011 0100 */
+    { 5, 0x1B, 64 },	/* 1101 1 */
+    { 5, 0x12, 128 },	/* 1001 0 */
+    { 6, 0x17, 192 },	/* 0101 11 */
+    { 7, 0x37, 256 },	/* 0110 111 */
+    { 8, 0x36, 320 },	/* 0011 0110 */
+    { 8, 0x37, 384 },	/* 0011 0111 */
+    { 8, 0x64, 448 },	/* 0110 0100 */
+    { 8, 0x65, 512 },	/* 0110 0101 */
+    { 8, 0x68, 576 },	/* 0110 1000 */
+    { 8, 0x67, 640 },	/* 0110 0111 */
+    { 9, 0xCC, 704 },	/* 0110 0110 0 */
+    { 9, 0xCD, 768 },	/* 0110 0110 1 */
+    { 9, 0xD2, 832 },	/* 0110 1001 0 */
+    { 9, 0xD3, 896 },	/* 0110 1001 1 */
+    { 9, 0xD4, 960 },	/* 0110 1010 0 */
+    { 9, 0xD5, 1024 },	/* 0110 1010 1 */
+    { 9, 0xD6, 1088 },	/* 0110 1011 0 */
+    { 9, 0xD7, 1152 },	/* 0110 1011 1 */
+    { 9, 0xD8, 1216 },	/* 0110 1100 0 */
+    { 9, 0xD9, 1280 },	/* 0110 1100 1 */
+    { 9, 0xDA, 1344 },	/* 0110 1101 0 */
+    { 9, 0xDB, 1408 },	/* 0110 1101 1 */
+    { 9, 0x98, 1472 },	/* 0100 1100 0 */
+    { 9, 0x99, 1536 },	/* 0100 1100 1 */
+    { 9, 0x9A, 1600 },	/* 0100 1101 0 */
+    { 6, 0x18, 1664 },	/* 0110 00 */
+    { 9, 0x9B, 1728 },	/* 0100 1101 1 */
+    { 11, 0x8, 1792 },	/* 0000 0001 000 */
+    { 11, 0xC, 1856 },	/* 0000 0001 100 */
+    { 11, 0xD, 1920 },	/* 0000 0001 101 */
+    { 12, 0x12, 1984 },	/* 0000 0001 0010 */
+    { 12, 0x13, 2048 },	/* 0000 0001 0011 */
+    { 12, 0x14, 2112 },	/* 0000 0001 0100 */
+    { 12, 0x15, 2176 },	/* 0000 0001 0101 */
+    { 12, 0x16, 2240 },	/* 0000 0001 0110 */
+    { 12, 0x17, 2304 },	/* 0000 0001 0111 */
+    { 12, 0x1C, 2368 },	/* 0000 0001 1100 */
+    { 12, 0x1D, 2432 },	/* 0000 0001 1101 */
+    { 12, 0x1E, 2496 },	/* 0000 0001 1110 */
+    { 12, 0x1F, 2560 },	/* 0000 0001 1111 */
+    { 12, 0x1, G3CODE_EOL },	/* 0000 0000 0001 */
+    { 9, 0x1, G3CODE_INVALID },	/* 0000 0000 1 */
+    { 10, 0x1, G3CODE_INVALID },	/* 0000 0000 01 */
+    { 11, 0x1, G3CODE_INVALID },	/* 0000 0000 001 */
+    { 12, 0x0, G3CODE_INVALID },	/* 0000 0000 0000 */
+};
+
+const tableentry TIFFFaxBlackCodes[] = {
+    { 10, 0x37, 0 },	/* 0000 1101 11 */
+    { 3, 0x2, 1 },	/* 010 */
+    { 2, 0x3, 2 },	/* 11 */
+    { 2, 0x2, 3 },	/* 10 */
+    { 3, 0x3, 4 },	/* 011 */
+    { 4, 0x3, 5 },	/* 0011 */
+    { 4, 0x2, 6 },	/* 0010 */
+    { 5, 0x3, 7 },	/* 0001 1 */
+    { 6, 0x5, 8 },	/* 0001 01 */
+    { 6, 0x4, 9 },	/* 0001 00 */
+    { 7, 0x4, 10 },	/* 0000 100 */
+    { 7, 0x5, 11 },	/* 0000 101 */
+    { 7, 0x7, 12 },	/* 0000 111 */
+    { 8, 0x4, 13 },	/* 0000 0100 */
+    { 8, 0x7, 14 },	/* 0000 0111 */
+    { 9, 0x18, 15 },	/* 0000 1100 0 */
+    { 10, 0x17, 16 },	/* 0000 0101 11 */
+    { 10, 0x18, 17 },	/* 0000 0110 00 */
+    { 10, 0x8, 18 },	/* 0000 0010 00 */
+    { 11, 0x67, 19 },	/* 0000 1100 111 */
+    { 11, 0x68, 20 },	/* 0000 1101 000 */
+    { 11, 0x6C, 21 },	/* 0000 1101 100 */
+    { 11, 0x37, 22 },	/* 0000 0110 111 */
+    { 11, 0x28, 23 },	/* 0000 0101 000 */
+    { 11, 0x17, 24 },	/* 0000 0010 111 */
+    { 11, 0x18, 25 },	/* 0000 0011 000 */
+    { 12, 0xCA, 26 },	/* 0000 1100 1010 */
+    { 12, 0xCB, 27 },	/* 0000 1100 1011 */
+    { 12, 0xCC, 28 },	/* 0000 1100 1100 */
+    { 12, 0xCD, 29 },	/* 0000 1100 1101 */
+    { 12, 0x68, 30 },	/* 0000 0110 1000 */
+    { 12, 0x69, 31 },	/* 0000 0110 1001 */
+    { 12, 0x6A, 32 },	/* 0000 0110 1010 */
+    { 12, 0x6B, 33 },	/* 0000 0110 1011 */
+    { 12, 0xD2, 34 },	/* 0000 1101 0010 */
+    { 12, 0xD3, 35 },	/* 0000 1101 0011 */
+    { 12, 0xD4, 36 },	/* 0000 1101 0100 */
+    { 12, 0xD5, 37 },	/* 0000 1101 0101 */
+    { 12, 0xD6, 38 },	/* 0000 1101 0110 */
+    { 12, 0xD7, 39 },	/* 0000 1101 0111 */
+    { 12, 0x6C, 40 },	/* 0000 0110 1100 */
+    { 12, 0x6D, 41 },	/* 0000 0110 1101 */
+    { 12, 0xDA, 42 },	/* 0000 1101 1010 */
+    { 12, 0xDB, 43 },	/* 0000 1101 1011 */
+    { 12, 0x54, 44 },	/* 0000 0101 0100 */
+    { 12, 0x55, 45 },	/* 0000 0101 0101 */
+    { 12, 0x56, 46 },	/* 0000 0101 0110 */
+    { 12, 0x57, 47 },	/* 0000 0101 0111 */
+    { 12, 0x64, 48 },	/* 0000 0110 0100 */
+    { 12, 0x65, 49 },	/* 0000 0110 0101 */
+    { 12, 0x52, 50 },	/* 0000 0101 0010 */
+    { 12, 0x53, 51 },	/* 0000 0101 0011 */
+    { 12, 0x24, 52 },	/* 0000 0010 0100 */
+    { 12, 0x37, 53 },	/* 0000 0011 0111 */
+    { 12, 0x38, 54 },	/* 0000 0011 1000 */
+    { 12, 0x27, 55 },	/* 0000 0010 0111 */
+    { 12, 0x28, 56 },	/* 0000 0010 1000 */
+    { 12, 0x58, 57 },	/* 0000 0101 1000 */
+    { 12, 0x59, 58 },	/* 0000 0101 1001 */
+    { 12, 0x2B, 59 },	/* 0000 0010 1011 */
+    { 12, 0x2C, 60 },	/* 0000 0010 1100 */
+    { 12, 0x5A, 61 },	/* 0000 0101 1010 */
+    { 12, 0x66, 62 },	/* 0000 0110 0110 */
+    { 12, 0x67, 63 },	/* 0000 0110 0111 */
+    { 10, 0xF, 64 },	/* 0000 0011 11 */
+    { 12, 0xC8, 128 },	/* 0000 1100 1000 */
+    { 12, 0xC9, 192 },	/* 0000 1100 1001 */
+    { 12, 0x5B, 256 },	/* 0000 0101 1011 */
+    { 12, 0x33, 320 },	/* 0000 0011 0011 */
+    { 12, 0x34, 384 },	/* 0000 0011 0100 */
+    { 12, 0x35, 448 },	/* 0000 0011 0101 */
+    { 13, 0x6C, 512 },	/* 0000 0011 0110 0 */
+    { 13, 0x6D, 576 },	/* 0000 0011 0110 1 */
+    { 13, 0x4A, 640 },	/* 0000 0010 0101 0 */
+    { 13, 0x4B, 704 },	/* 0000 0010 0101 1 */
+    { 13, 0x4C, 768 },	/* 0000 0010 0110 0 */
+    { 13, 0x4D, 832 },	/* 0000 0010 0110 1 */
+    { 13, 0x72, 896 },	/* 0000 0011 1001 0 */
+    { 13, 0x73, 960 },	/* 0000 0011 1001 1 */
+    { 13, 0x74, 1024 },	/* 0000 0011 1010 0 */
+    { 13, 0x75, 1088 },	/* 0000 0011 1010 1 */
+    { 13, 0x76, 1152 },	/* 0000 0011 1011 0 */
+    { 13, 0x77, 1216 },	/* 0000 0011 1011 1 */
+    { 13, 0x52, 1280 },	/* 0000 0010 1001 0 */
+    { 13, 0x53, 1344 },	/* 0000 0010 1001 1 */
+    { 13, 0x54, 1408 },	/* 0000 0010 1010 0 */
+    { 13, 0x55, 1472 },	/* 0000 0010 1010 1 */
+    { 13, 0x5A, 1536 },	/* 0000 0010 1101 0 */
+    { 13, 0x5B, 1600 },	/* 0000 0010 1101 1 */
+    { 13, 0x64, 1664 },	/* 0000 0011 0010 0 */
+    { 13, 0x65, 1728 },	/* 0000 0011 0010 1 */
+    { 11, 0x8, 1792 },	/* 0000 0001 000 */
+    { 11, 0xC, 1856 },	/* 0000 0001 100 */
+    { 11, 0xD, 1920 },	/* 0000 0001 101 */
+    { 12, 0x12, 1984 },	/* 0000 0001 0010 */
+    { 12, 0x13, 2048 },	/* 0000 0001 0011 */
+    { 12, 0x14, 2112 },	/* 0000 0001 0100 */
+    { 12, 0x15, 2176 },	/* 0000 0001 0101 */
+    { 12, 0x16, 2240 },	/* 0000 0001 0110 */
+    { 12, 0x17, 2304 },	/* 0000 0001 0111 */
+    { 12, 0x1C, 2368 },	/* 0000 0001 1100 */
+    { 12, 0x1D, 2432 },	/* 0000 0001 1101 */
+    { 12, 0x1E, 2496 },	/* 0000 0001 1110 */
+    { 12, 0x1F, 2560 },	/* 0000 0001 1111 */
+    { 12, 0x1, G3CODE_EOL },	/* 0000 0000 0001 */
+    { 9, 0x1, G3CODE_INVALID },	/* 0000 0000 1 */
+    { 10, 0x1, G3CODE_INVALID },	/* 0000 0000 01 */
+    { 11, 0x1, G3CODE_INVALID },	/* 0000 0000 001 */
+    { 12, 0x0, G3CODE_INVALID },	/* 0000 0000 0000 */
+};
+#else
+extern const tableentry TIFFFaxWhiteCodes[];
+extern const tableentry TIFFFaxBlackCodes[];
+#endif
+#endif /* _T4_ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_aux.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_aux.c
new file mode 100644
index 0000000..752e8d6
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_aux.c
@@ -0,0 +1,360 @@
+/* $Id: tif_aux.c,v 1.26 2010-07-01 15:33:28 dron Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Auxiliary Support Routines.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include "tif_predict.h"
+#include <math.h>
+
+uint32
+_TIFFMultiply32(TIFF* tif, uint32 first, uint32 second, const char* where)
+{
+	uint32 bytes = first * second;
+
+	if (second && bytes / second != first) {
+		TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where);
+		bytes = 0;
+	}
+
+	return bytes;
+}
+
+uint64
+_TIFFMultiply64(TIFF* tif, uint64 first, uint64 second, const char* where)
+{
+	uint64 bytes = first * second;
+
+	if (second && bytes / second != first) {
+		TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where);
+		bytes = 0;
+	}
+
+	return bytes;
+}
+
+void*
+_TIFFCheckRealloc(TIFF* tif, void* buffer,
+		  tmsize_t nmemb, tmsize_t elem_size, const char* what)
+{
+	void* cp = NULL;
+	tmsize_t bytes = nmemb * elem_size;
+
+	/*
+	 * XXX: Check for integer overflow.
+	 */
+	if (nmemb && elem_size && bytes / elem_size == nmemb)
+		cp = _TIFFrealloc(buffer, bytes);
+
+	if (cp == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "Failed to allocate memory for %s "
+			     "(%ld elements of %ld bytes each)",
+			     what,(long) nmemb, (long) elem_size);
+	}
+
+	return cp;
+}
+
+void*
+_TIFFCheckMalloc(TIFF* tif, tmsize_t nmemb, tmsize_t elem_size, const char* what)
+{
+	return _TIFFCheckRealloc(tif, NULL, nmemb, elem_size, what);  
+}
+
+static int
+TIFFDefaultTransferFunction(TIFFDirectory* td)
+{
+	uint16 **tf = td->td_transferfunction;
+	tmsize_t i, n, nbytes;
+
+	tf[0] = tf[1] = tf[2] = 0;
+	if (td->td_bitspersample >= sizeof(tmsize_t) * 8 - 2)
+		return 0;
+
+	n = ((tmsize_t)1)<<td->td_bitspersample;
+	nbytes = n * sizeof (uint16);
+	if (!(tf[0] = (uint16 *)_TIFFmalloc(nbytes)))
+		return 0;
+	tf[0][0] = 0;
+	for (i = 1; i < n; i++) {
+		double t = (double)i/((double) n-1.);
+		tf[0][i] = (uint16)floor(65535.*pow(t, 2.2) + .5);
+	}
+
+	if (td->td_samplesperpixel - td->td_extrasamples > 1) {
+		if (!(tf[1] = (uint16 *)_TIFFmalloc(nbytes)))
+			goto bad;
+		_TIFFmemcpy(tf[1], tf[0], nbytes);
+		if (!(tf[2] = (uint16 *)_TIFFmalloc(nbytes)))
+			goto bad;
+		_TIFFmemcpy(tf[2], tf[0], nbytes);
+	}
+	return 1;
+
+bad:
+	if (tf[0])
+		_TIFFfree(tf[0]);
+	if (tf[1])
+		_TIFFfree(tf[1]);
+	if (tf[2])
+		_TIFFfree(tf[2]);
+	tf[0] = tf[1] = tf[2] = 0;
+	return 0;
+}
+
+static int
+TIFFDefaultRefBlackWhite(TIFFDirectory* td)
+{
+	int i;
+
+	if (!(td->td_refblackwhite = (float *)_TIFFmalloc(6*sizeof (float))))
+		return 0;
+        if (td->td_photometric == PHOTOMETRIC_YCBCR) {
+		/*
+		 * YCbCr (Class Y) images must have the ReferenceBlackWhite
+		 * tag set. Fix the broken images, which lacks that tag.
+		 */
+		td->td_refblackwhite[0] = 0.0F;
+		td->td_refblackwhite[1] = td->td_refblackwhite[3] =
+			td->td_refblackwhite[5] = 255.0F;
+		td->td_refblackwhite[2] = td->td_refblackwhite[4] = 128.0F;
+	} else {
+		/*
+		 * Assume RGB (Class R)
+		 */
+		for (i = 0; i < 3; i++) {
+		    td->td_refblackwhite[2*i+0] = 0;
+		    td->td_refblackwhite[2*i+1] =
+			    (float)((1L<<td->td_bitspersample)-1L);
+		}
+	}
+	return 1;
+}
+
+/*
+ * Like TIFFGetField, but return any default
+ * value if the tag is not present in the directory.
+ *
+ * NB:	We use the value in the directory, rather than
+ *	explcit values so that defaults exist only one
+ *	place in the library -- in TIFFDefaultDirectory.
+ */
+int
+TIFFVGetFieldDefaulted(TIFF* tif, uint32 tag, va_list ap)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+	if (TIFFVGetField(tif, tag, ap))
+		return (1);
+	switch (tag) {
+	case TIFFTAG_SUBFILETYPE:
+		*va_arg(ap, uint32 *) = td->td_subfiletype;
+		return (1);
+	case TIFFTAG_BITSPERSAMPLE:
+		*va_arg(ap, uint16 *) = td->td_bitspersample;
+		return (1);
+	case TIFFTAG_THRESHHOLDING:
+		*va_arg(ap, uint16 *) = td->td_threshholding;
+		return (1);
+	case TIFFTAG_FILLORDER:
+		*va_arg(ap, uint16 *) = td->td_fillorder;
+		return (1);
+	case TIFFTAG_ORIENTATION:
+		*va_arg(ap, uint16 *) = td->td_orientation;
+		return (1);
+	case TIFFTAG_SAMPLESPERPIXEL:
+		*va_arg(ap, uint16 *) = td->td_samplesperpixel;
+		return (1);
+	case TIFFTAG_ROWSPERSTRIP:
+		*va_arg(ap, uint32 *) = td->td_rowsperstrip;
+		return (1);
+	case TIFFTAG_MINSAMPLEVALUE:
+		*va_arg(ap, uint16 *) = td->td_minsamplevalue;
+		return (1);
+	case TIFFTAG_MAXSAMPLEVALUE:
+		*va_arg(ap, uint16 *) = td->td_maxsamplevalue;
+		return (1);
+	case TIFFTAG_PLANARCONFIG:
+		*va_arg(ap, uint16 *) = td->td_planarconfig;
+		return (1);
+	case TIFFTAG_RESOLUTIONUNIT:
+		*va_arg(ap, uint16 *) = td->td_resolutionunit;
+		return (1);
+	case TIFFTAG_PREDICTOR:
+                {
+			TIFFPredictorState* sp = (TIFFPredictorState*) tif->tif_data;
+			*va_arg(ap, uint16*) = (uint16) sp->predictor;
+			return 1;
+                }
+	case TIFFTAG_DOTRANGE:
+		*va_arg(ap, uint16 *) = 0;
+		*va_arg(ap, uint16 *) = (1<<td->td_bitspersample)-1;
+		return (1);
+	case TIFFTAG_INKSET:
+		*va_arg(ap, uint16 *) = INKSET_CMYK;
+		return 1;
+	case TIFFTAG_NUMBEROFINKS:
+		*va_arg(ap, uint16 *) = 4;
+		return (1);
+	case TIFFTAG_EXTRASAMPLES:
+		*va_arg(ap, uint16 *) = td->td_extrasamples;
+		*va_arg(ap, uint16 **) = td->td_sampleinfo;
+		return (1);
+	case TIFFTAG_MATTEING:
+		*va_arg(ap, uint16 *) =
+		    (td->td_extrasamples == 1 &&
+		     td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA);
+		return (1);
+	case TIFFTAG_TILEDEPTH:
+		*va_arg(ap, uint32 *) = td->td_tiledepth;
+		return (1);
+	case TIFFTAG_DATATYPE:
+		*va_arg(ap, uint16 *) = td->td_sampleformat-1;
+		return (1);
+	case TIFFTAG_SAMPLEFORMAT:
+		*va_arg(ap, uint16 *) = td->td_sampleformat;
+                return(1);
+	case TIFFTAG_IMAGEDEPTH:
+		*va_arg(ap, uint32 *) = td->td_imagedepth;
+		return (1);
+	case TIFFTAG_YCBCRCOEFFICIENTS:
+		{
+			/* defaults are from CCIR Recommendation 601-1 */
+			static float ycbcrcoeffs[] = { 0.299f, 0.587f, 0.114f };
+			*va_arg(ap, float **) = ycbcrcoeffs;
+			return 1;
+		}
+	case TIFFTAG_YCBCRSUBSAMPLING:
+		*va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[0];
+		*va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[1];
+		return (1);
+	case TIFFTAG_YCBCRPOSITIONING:
+		*va_arg(ap, uint16 *) = td->td_ycbcrpositioning;
+		return (1);
+	case TIFFTAG_WHITEPOINT:
+		{
+			static float whitepoint[2];
+
+			/* TIFF 6.0 specification tells that it is no default
+			   value for the WhitePoint, but AdobePhotoshop TIFF
+			   Technical Note tells that it should be CIE D50. */
+			whitepoint[0] =	D50_X0 / (D50_X0 + D50_Y0 + D50_Z0);
+			whitepoint[1] =	D50_Y0 / (D50_X0 + D50_Y0 + D50_Z0);
+			*va_arg(ap, float **) = whitepoint;
+			return 1;
+		}
+	case TIFFTAG_TRANSFERFUNCTION:
+		if (!td->td_transferfunction[0] &&
+		    !TIFFDefaultTransferFunction(td)) {
+			TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "No space for \"TransferFunction\" tag");
+			return (0);
+		}
+		*va_arg(ap, uint16 **) = td->td_transferfunction[0];
+		if (td->td_samplesperpixel - td->td_extrasamples > 1) {
+			*va_arg(ap, uint16 **) = td->td_transferfunction[1];
+			*va_arg(ap, uint16 **) = td->td_transferfunction[2];
+		}
+		return (1);
+	case TIFFTAG_REFERENCEBLACKWHITE:
+		if (!td->td_refblackwhite && !TIFFDefaultRefBlackWhite(td))
+			return (0);
+		*va_arg(ap, float **) = td->td_refblackwhite;
+		return (1);
+	}
+	return 0;
+}
+
+/*
+ * Like TIFFGetField, but return any default
+ * value if the tag is not present in the directory.
+ */
+int
+TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...)
+{
+	int ok;
+	va_list ap;
+
+	va_start(ap, tag);
+	ok =  TIFFVGetFieldDefaulted(tif, tag, ap);
+	va_end(ap);
+	return (ok);
+}
+
+struct _Int64Parts {
+	int32 low, high;
+};
+
+typedef union {
+	struct _Int64Parts part;
+	int64 value;
+} _Int64;
+
+float
+_TIFFUInt64ToFloat(uint64 ui64)
+{
+	_Int64 i;
+
+	i.value = ui64;
+	if (i.part.high >= 0) {
+		return (float)i.value;
+	} else {
+		long double df;
+		df = (long double)i.value;
+		df += 18446744073709551616.0; /* adding 2**64 */
+		return (float)df;
+	}
+}
+
+double
+_TIFFUInt64ToDouble(uint64 ui64)
+{
+	_Int64 i;
+
+	i.value = ui64;
+	if (i.part.high >= 0) {
+		return (double)i.value;
+	} else {
+		long double df;
+		df = (long double)i.value;
+		df += 18446744073709551616.0; /* adding 2**64 */
+		return (double)df;
+	}
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+ #endif
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_close.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_close.c
new file mode 100644
index 0000000..eebb30a
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_close.c
@@ -0,0 +1,143 @@
+/* $Id: tif_close.c,v 1.19 2010-03-10 18:56:48 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include <string.h>
+
+/************************************************************************/
+/*                            TIFFCleanup()                             */
+/************************************************************************/
+
+/**
+ * Auxiliary function to free the TIFF structure. Given structure will be
+ * completetly freed, so you should save opened file handle and pointer
+ * to the close procedure in external variables before calling
+ * _TIFFCleanup(), if you will need these ones to close the file.
+ * 
+ * @param tif A TIFF pointer.
+ */
+
+void
+TIFFCleanup(TIFF* tif)
+{
+	/*
+         * Flush buffered data and directory (if dirty).
+         */
+	if (tif->tif_mode != O_RDONLY)
+		TIFFFlush(tif);
+	(*tif->tif_cleanup)(tif);
+	TIFFFreeDirectory(tif);
+
+	if (tif->tif_dirlist)
+		_TIFFfree(tif->tif_dirlist);
+
+	/*
+         * Clean up client info links.
+         */
+	while( tif->tif_clientinfo )
+	{
+		TIFFClientInfoLink *link = tif->tif_clientinfo;
+
+		tif->tif_clientinfo = link->next;
+		_TIFFfree( link->name );
+		_TIFFfree( link );
+	}
+
+	if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER))
+		_TIFFfree(tif->tif_rawdata);
+	if (isMapped(tif))
+		TIFFUnmapFileContents(tif, tif->tif_base, (toff_t)tif->tif_size);
+
+	/*
+         * Clean up custom fields.
+         */
+	if (tif->tif_fields && tif->tif_nfields > 0) {
+		uint32 i;
+
+		for (i = 0; i < tif->tif_nfields; i++) {
+			TIFFField *fld = tif->tif_fields[i];
+			if (fld->field_bit == FIELD_CUSTOM &&
+			    strncmp("Tag ", fld->field_name, 4) == 0) {
+				_TIFFfree(fld->field_name);
+				_TIFFfree(fld);
+			}
+		}
+
+		_TIFFfree(tif->tif_fields);
+	}
+
+        if (tif->tif_nfieldscompat > 0) {
+                uint32 i;
+
+                for (i = 0; i < tif->tif_nfieldscompat; i++) {
+                        if (tif->tif_fieldscompat[i].allocated_size)
+                                _TIFFfree(tif->tif_fieldscompat[i].fields);
+                }
+                _TIFFfree(tif->tif_fieldscompat);
+        }
+
+	_TIFFfree(tif);
+}
+
+/************************************************************************/
+/*                            TIFFClose()                               */
+/************************************************************************/
+
+/**
+ * Close a previously opened TIFF file.
+ *
+ * TIFFClose closes a file that was previously opened with TIFFOpen().
+ * Any buffered data are flushed to the file, including the contents of
+ * the current directory (if modified); and all resources are reclaimed.
+ * 
+ * @param tif A TIFF pointer.
+ */
+
+void
+TIFFClose(TIFF* tif)
+{
+	TIFFCloseProc closeproc = tif->tif_closeproc;
+	thandle_t fd = tif->tif_clientdata;
+
+	TIFFCleanup(tif);
+	(void) (*closeproc)(fd);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_codec.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_codec.c
new file mode 100644
index 0000000..16d237f
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_codec.c
@@ -0,0 +1,168 @@
+/* $Id: tif_codec.c,v 1.15 2010-12-14 12:53:00 dron Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Builtin Compression Scheme Configuration Support.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+static int NotConfigured(TIFF*, int);
+
+#ifndef LZW_SUPPORT
+#define TIFFInitLZW NotConfigured
+#endif
+#ifndef PACKBITS_SUPPORT
+#define TIFFInitPackBits NotConfigured
+#endif
+#ifndef THUNDER_SUPPORT
+#define TIFFInitThunderScan NotConfigured
+#endif
+#ifndef NEXT_SUPPORT
+#define TIFFInitNeXT NotConfigured
+#endif
+#ifndef JPEG_SUPPORT
+#define TIFFInitJPEG NotConfigured
+#endif
+#ifndef OJPEG_SUPPORT
+#define TIFFInitOJPEG NotConfigured
+#endif
+#ifndef CCITT_SUPPORT
+#define TIFFInitCCITTRLE NotConfigured
+#define TIFFInitCCITTRLEW NotConfigured
+#define TIFFInitCCITTFax3 NotConfigured
+#define TIFFInitCCITTFax4 NotConfigured
+#endif
+#ifndef JBIG_SUPPORT
+#define TIFFInitJBIG NotConfigured
+#endif
+#ifndef ZIP_SUPPORT
+#define TIFFInitZIP NotConfigured
+#endif
+#ifndef PIXARLOG_SUPPORT
+#define TIFFInitPixarLog NotConfigured
+#endif
+#ifndef LOGLUV_SUPPORT
+#define TIFFInitSGILog NotConfigured
+#endif
+#ifndef LZMA_SUPPORT
+#define TIFFInitLZMA NotConfigured
+#endif
+
+/*
+ * Compression schemes statically built into the library.
+ */
+#ifdef VMS
+const TIFFCodec _TIFFBuiltinCODECS[] = {
+#else
+TIFFCodec _TIFFBuiltinCODECS[] = {
+#endif
+    { "None",		COMPRESSION_NONE,	TIFFInitDumpMode },
+    { "LZW",		COMPRESSION_LZW,	TIFFInitLZW },
+    { "PackBits",	COMPRESSION_PACKBITS,	TIFFInitPackBits },
+    { "ThunderScan",	COMPRESSION_THUNDERSCAN,TIFFInitThunderScan },
+    { "NeXT",		COMPRESSION_NEXT,	TIFFInitNeXT },
+    { "JPEG",		COMPRESSION_JPEG,	TIFFInitJPEG },
+    { "Old-style JPEG",	COMPRESSION_OJPEG,	TIFFInitOJPEG },
+    { "CCITT RLE",	COMPRESSION_CCITTRLE,	TIFFInitCCITTRLE },
+    { "CCITT RLE/W",	COMPRESSION_CCITTRLEW,	TIFFInitCCITTRLEW },
+    { "CCITT Group 3",	COMPRESSION_CCITTFAX3,	TIFFInitCCITTFax3 },
+    { "CCITT Group 4",	COMPRESSION_CCITTFAX4,	TIFFInitCCITTFax4 },
+    { "ISO JBIG",	COMPRESSION_JBIG,	TIFFInitJBIG },
+    { "Deflate",	COMPRESSION_DEFLATE,	TIFFInitZIP },
+    { "AdobeDeflate",   COMPRESSION_ADOBE_DEFLATE , TIFFInitZIP }, 
+    { "PixarLog",	COMPRESSION_PIXARLOG,	TIFFInitPixarLog },
+    { "SGILog",		COMPRESSION_SGILOG,	TIFFInitSGILog },
+    { "SGILog24",	COMPRESSION_SGILOG24,	TIFFInitSGILog },
+    { "LZMA",		COMPRESSION_LZMA,	TIFFInitLZMA },
+    { NULL,             0,                      NULL }
+};
+
+static int
+_notConfigured(TIFF* tif)
+{
+	const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
+        char compression_code[20];
+        
+        sprintf( compression_code, "%d", tif->tif_dir.td_compression );
+	TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+                     "%s compression support is not configured", 
+                     c ? c->name : compression_code );
+	return (0);
+}
+
+static int
+NotConfigured(TIFF* tif, int scheme)
+{
+	(void) scheme;
+
+	tif->tif_fixuptags = _notConfigured;
+	tif->tif_decodestatus = FALSE;
+	tif->tif_setupdecode = _notConfigured;
+	tif->tif_encodestatus = FALSE;
+	tif->tif_setupencode = _notConfigured;
+	return (1);
+}
+
+/************************************************************************/
+/*                       TIFFIsCODECConfigured()                        */
+/************************************************************************/
+
+/**
+ * Check whether we have working codec for the specific coding scheme.
+ *
+ * @return returns 1 if the codec is configured and working. Otherwise
+ * 0 will be returned.
+ */
+
+int
+TIFFIsCODECConfigured(uint16 scheme)
+{
+	const TIFFCodec* codec = TIFFFindCODEC(scheme);
+
+	if(codec == NULL) {
+		return 0;
+	}
+	if(codec->init == NULL) {
+		return 0;
+	}
+	if(codec->init != NotConfigured){
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_color.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_color.c
new file mode 100644
index 0000000..71effbc
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_color.c
@@ -0,0 +1,289 @@
+/* $Id: tif_color.c,v 1.19 2010-12-14 02:22:42 faxguy Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken
+ * from the VIPS library (http://www.vips.ecs.soton.ac.uk) with
+ * the permission of John Cupitt, the VIPS author.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Color space conversion routines.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include <math.h>
+
+/*
+ * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ.
+ */
+void
+TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b,
+		float *X, float *Y, float *Z)
+{
+	float L = (float)l * 100.0F / 255.0F;
+	float cby, tmp;
+
+	if( L < 8.856F ) {
+		*Y = (L * cielab->Y0) / 903.292F;
+		cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F;
+	} else {
+		cby = (L + 16.0F) / 116.0F;
+		*Y = cielab->Y0 * cby * cby * cby;
+	}
+
+	tmp = (float)a / 500.0F + cby;
+	if( tmp < 0.2069F )
+		*X = cielab->X0 * (tmp - 0.13793F) / 7.787F;
+	else    
+		*X = cielab->X0 * tmp * tmp * tmp;
+
+	tmp = cby - (float)b / 200.0F;
+	if( tmp < 0.2069F )
+		*Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F;
+	else    
+		*Z = cielab->Z0 * tmp * tmp * tmp;
+}
+
+#define RINT(R) ((uint32)((R)>0?((R)+0.5):((R)-0.5)))
+/*
+ * Convert color value from the XYZ space to RGB.
+ */
+void
+TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
+	     uint32 *r, uint32 *g, uint32 *b)
+{
+	int i;
+	float Yr, Yg, Yb;
+	float *matrix = &cielab->display.d_mat[0][0];
+
+	/* Multiply through the matrix to get luminosity values. */
+	Yr =  matrix[0] * X + matrix[1] * Y + matrix[2] * Z;
+	Yg =  matrix[3] * X + matrix[4] * Y + matrix[5] * Z;
+	Yb =  matrix[6] * X + matrix[7] * Y + matrix[8] * Z;
+
+	/* Clip input */
+	Yr = TIFFmax(Yr, cielab->display.d_Y0R);
+	Yg = TIFFmax(Yg, cielab->display.d_Y0G);
+	Yb = TIFFmax(Yb, cielab->display.d_Y0B);
+
+	/* Avoid overflow in case of wrong input values */
+	Yr = TIFFmin(Yr, cielab->display.d_YCR);
+	Yg = TIFFmin(Yg, cielab->display.d_YCG);
+	Yb = TIFFmin(Yb, cielab->display.d_YCB);
+
+	/* Turn luminosity to colour value. */
+	i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep);
+	i = TIFFmin(cielab->range, i);
+	*r = RINT(cielab->Yr2r[i]);
+
+	i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep);
+	i = TIFFmin(cielab->range, i);
+	*g = RINT(cielab->Yg2g[i]);
+
+	i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep);
+	i = TIFFmin(cielab->range, i);
+	*b = RINT(cielab->Yb2b[i]);
+
+	/* Clip output. */
+	*r = TIFFmin(*r, cielab->display.d_Vrwr);
+	*g = TIFFmin(*g, cielab->display.d_Vrwg);
+	*b = TIFFmin(*b, cielab->display.d_Vrwb);
+}
+#undef RINT
+
+/* 
+ * Allocate conversion state structures and make look_up tables for
+ * the Yr,Yb,Yg <=> r,g,b conversions.
+ */
+int
+TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab,
+		    const TIFFDisplay *display, float *refWhite)
+{
+	int i;
+	double gamma;
+
+	cielab->range = CIELABTORGB_TABLE_RANGE;
+
+	_TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay));
+
+	/* Red */
+	gamma = 1.0 / cielab->display.d_gammaR ;
+	cielab->rstep =
+		(cielab->display.d_YCR - cielab->display.d_Y0R)	/ cielab->range;
+	for(i = 0; i <= cielab->range; i++) {
+		cielab->Yr2r[i] = cielab->display.d_Vrwr
+		    * ((float)pow((double)i / cielab->range, gamma));
+	}
+
+	/* Green */
+	gamma = 1.0 / cielab->display.d_gammaG ;
+	cielab->gstep =
+	    (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
+	for(i = 0; i <= cielab->range; i++) {
+		cielab->Yg2g[i] = cielab->display.d_Vrwg
+		    * ((float)pow((double)i / cielab->range, gamma));
+	}
+
+	/* Blue */
+	gamma = 1.0 / cielab->display.d_gammaB ;
+	cielab->bstep =
+	    (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
+	for(i = 0; i <= cielab->range; i++) {
+		cielab->Yb2b[i] = cielab->display.d_Vrwb
+		    * ((float)pow((double)i / cielab->range, gamma));
+	}
+
+	/* Init reference white point */
+	cielab->X0 = refWhite[0];
+	cielab->Y0 = refWhite[1];
+	cielab->Z0 = refWhite[2];
+
+	return 0;
+}
+
+/* 
+ * Convert color value from the YCbCr space to CIE XYZ.
+ * The colorspace conversion algorithm comes from the IJG v5a code;
+ * see below for more information on how it works.
+ */
+#define	SHIFT			16
+#define	FIX(x)			((int32)((x) * (1L<<SHIFT) + 0.5))
+#define	ONE_HALF		((int32)(1<<(SHIFT-1)))
+#define	Code2V(c, RB, RW, CR)	((((c)-(int32)(RB))*(float)(CR))/(float)(((RW)-(RB)) ? ((RW)-(RB)) : 1))
+#define	CLAMP(f,min,max)	((f)<(min)?(min):(f)>(max)?(max):(f))
+#define HICLAMP(f,max)		((f)>(max)?(max):(f))
+
+void
+TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr,
+	       uint32 *r, uint32 *g, uint32 *b)
+{
+	int32 i;
+
+	/* XXX: Only 8-bit YCbCr input supported for now */
+	Y = HICLAMP(Y, 255), Cb = CLAMP(Cb, 0, 255), Cr = CLAMP(Cr, 0, 255);
+
+	i = ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr];
+	*r = CLAMP(i, 0, 255);
+	i = ycbcr->Y_tab[Y]
+	    + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT);
+	*g = CLAMP(i, 0, 255);
+	i = ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb];
+	*b = CLAMP(i, 0, 255);
+}
+
+/*
+ * Initialize the YCbCr->RGB conversion tables.  The conversion
+ * is done according to the 6.0 spec:
+ *
+ *    R = Y + Cr*(2 - 2*LumaRed)
+ *    B = Y + Cb*(2 - 2*LumaBlue)
+ *    G =   Y
+ *        - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
+ *        - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
+ *
+ * To avoid floating point arithmetic the fractional constants that
+ * come out of the equations are represented as fixed point values
+ * in the range 0...2^16.  We also eliminate multiplications by
+ * pre-calculating possible values indexed by Cb and Cr (this code
+ * assumes conversion is being done for 8-bit samples).
+ */
+int
+TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, float *luma, float *refBlackWhite)
+{
+    TIFFRGBValue* clamptab;
+    int i;
+    
+#define LumaRed	    luma[0]
+#define LumaGreen   luma[1]
+#define LumaBlue    luma[2]
+
+    clamptab = (TIFFRGBValue*)(
+	(uint8*) ycbcr+TIFFroundup_32(sizeof (TIFFYCbCrToRGB), sizeof (long)));  
+    _TIFFmemset(clamptab, 0, 256);		/* v < 0 => 0 */
+    ycbcr->clamptab = (clamptab += 256);
+    for (i = 0; i < 256; i++)
+	clamptab[i] = (TIFFRGBValue) i;
+    _TIFFmemset(clamptab+256, 255, 2*256);	/* v > 255 => 255 */
+    ycbcr->Cr_r_tab = (int*) (clamptab + 3*256);
+    ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
+    ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256);
+    ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
+    ycbcr->Y_tab = ycbcr->Cb_g_tab + 256;
+
+    { float f1 = 2-2*LumaRed;		int32 D1 = FIX(f1);
+      float f2 = LumaRed*f1/LumaGreen;	int32 D2 = -FIX(f2);
+      float f3 = 2-2*LumaBlue;		int32 D3 = FIX(f3);
+      float f4 = LumaBlue*f3/LumaGreen;	int32 D4 = -FIX(f4);
+      int x;
+
+#undef LumaBlue
+#undef LumaGreen
+#undef LumaRed
+      
+      /*
+       * i is the actual input pixel value in the range 0..255
+       * Cb and Cr values are in the range -128..127 (actually
+       * they are in a range defined by the ReferenceBlackWhite
+       * tag) so there is some range shifting to do here when
+       * constructing tables indexed by the raw pixel data.
+       */
+      for (i = 0, x = -128; i < 256; i++, x++) {
+	    int32 Cr = (int32)Code2V(x, refBlackWhite[4] - 128.0F,
+			    refBlackWhite[5] - 128.0F, 127);
+	    int32 Cb = (int32)Code2V(x, refBlackWhite[2] - 128.0F,
+			    refBlackWhite[3] - 128.0F, 127);
+
+	    ycbcr->Cr_r_tab[i] = (int32)((D1*Cr + ONE_HALF)>>SHIFT);
+	    ycbcr->Cb_b_tab[i] = (int32)((D3*Cb + ONE_HALF)>>SHIFT);
+	    ycbcr->Cr_g_tab[i] = D2*Cr;
+	    ycbcr->Cb_g_tab[i] = D4*Cb + ONE_HALF;
+	    ycbcr->Y_tab[i] =
+		    (int32)Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255);
+      }
+    }
+
+    return 0;
+}
+#undef	HICLAMP
+#undef	CLAMP
+#undef	Code2V
+#undef	SHIFT
+#undef	ONE_HALF
+#undef	FIX
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_compress.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_compress.c
new file mode 100644
index 0000000..5b2b4d5
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_compress.c
@@ -0,0 +1,307 @@
+/* $Id: tif_compress.c,v 1.22 2010-03-10 18:56:48 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Compression Scheme Configuration Support.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+static int
+TIFFNoEncode(TIFF* tif, const char* method)
+{
+	const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
+
+	if (c) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%s %s encoding is not implemented",
+			     c->name, method);
+	} else {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			"Compression scheme %u %s encoding is not implemented",
+			     tif->tif_dir.td_compression, method);
+	}
+	return (-1);
+}
+
+int
+_TIFFNoRowEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoEncode(tif, "scanline"));
+}
+
+int
+_TIFFNoStripEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoEncode(tif, "strip"));
+}
+
+int
+_TIFFNoTileEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoEncode(tif, "tile"));
+}
+
+static int
+TIFFNoDecode(TIFF* tif, const char* method)
+{
+	const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
+
+	if (c)
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%s %s decoding is not implemented",
+			     c->name, method);
+	else
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "Compression scheme %u %s decoding is not implemented",
+			     tif->tif_dir.td_compression, method);
+	return (-1);
+}
+
+int
+_TIFFNoFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+int
+_TIFFNoRowDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoDecode(tif, "scanline"));
+}
+
+int
+_TIFFNoStripDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoDecode(tif, "strip"));
+}
+
+int
+_TIFFNoTileDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoDecode(tif, "tile"));
+}
+
+int
+_TIFFNoSeek(TIFF* tif, uint32 off)
+{
+	(void) off;
+	TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		     "Compression algorithm does not support random access");
+	return (0);
+}
+
+int
+_TIFFNoPreCode(TIFF* tif, uint16 s)
+{
+	(void) tif; (void) s;
+	return (1);
+}
+
+static int _TIFFtrue(TIFF* tif) { (void) tif; return (1); }
+static void _TIFFvoid(TIFF* tif) { (void) tif; }
+
+void
+_TIFFSetDefaultCompressionState(TIFF* tif)
+{
+	tif->tif_fixuptags = _TIFFNoFixupTags; 
+	tif->tif_decodestatus = TRUE;
+	tif->tif_setupdecode = _TIFFtrue;
+	tif->tif_predecode = _TIFFNoPreCode;
+	tif->tif_decoderow = _TIFFNoRowDecode;  
+	tif->tif_decodestrip = _TIFFNoStripDecode;
+	tif->tif_decodetile = _TIFFNoTileDecode;  
+	tif->tif_encodestatus = TRUE;
+	tif->tif_setupencode = _TIFFtrue;
+	tif->tif_preencode = _TIFFNoPreCode;
+	tif->tif_postencode = _TIFFtrue;
+	tif->tif_encoderow = _TIFFNoRowEncode;
+	tif->tif_encodestrip = _TIFFNoStripEncode;  
+	tif->tif_encodetile = _TIFFNoTileEncode;  
+	tif->tif_close = _TIFFvoid;
+	tif->tif_seek = _TIFFNoSeek;
+	tif->tif_cleanup = _TIFFvoid;
+	tif->tif_defstripsize = _TIFFDefaultStripSize;
+	tif->tif_deftilesize = _TIFFDefaultTileSize;
+	tif->tif_flags &= ~(TIFF_NOBITREV|TIFF_NOREADRAW);
+}
+
+int
+TIFFSetCompressionScheme(TIFF* tif, int scheme)
+{
+	const TIFFCodec *c = TIFFFindCODEC((uint16) scheme);
+
+	_TIFFSetDefaultCompressionState(tif);
+	/*
+	 * Don't treat an unknown compression scheme as an error.
+	 * This permits applications to open files with data that
+	 * the library does not have builtin support for, but which
+	 * may still be meaningful.
+	 */
+	return (c ? (*c->init)(tif, scheme) : 1);
+}
+
+/*
+ * Other compression schemes may be registered.  Registered
+ * schemes can also override the builtin versions provided
+ * by this library.
+ */
+typedef struct _codec {
+	struct _codec* next;
+	TIFFCodec* info;
+} codec_t;
+static codec_t* registeredCODECS = NULL;
+
+const TIFFCodec*
+TIFFFindCODEC(uint16 scheme)
+{
+	const TIFFCodec* c;
+	codec_t* cd;
+
+	for (cd = registeredCODECS; cd; cd = cd->next)
+		if (cd->info->scheme == scheme)
+			return ((const TIFFCodec*) cd->info);
+	for (c = _TIFFBuiltinCODECS; c->name; c++)
+		if (c->scheme == scheme)
+			return (c);
+	return ((const TIFFCodec*) 0);
+}
+
+TIFFCodec*
+TIFFRegisterCODEC(uint16 scheme, const char* name, TIFFInitMethod init)
+{
+	codec_t* cd = (codec_t*)
+	    _TIFFmalloc((tmsize_t)(sizeof (codec_t) + sizeof (TIFFCodec) + strlen(name)+1));
+
+	if (cd != NULL) {
+		cd->info = (TIFFCodec*) ((uint8*) cd + sizeof (codec_t));
+		cd->info->name = (char*)
+		    ((uint8*) cd->info + sizeof (TIFFCodec));
+		strcpy(cd->info->name, name);
+		cd->info->scheme = scheme;
+		cd->info->init = init;
+		cd->next = registeredCODECS;
+		registeredCODECS = cd;
+	} else {
+		TIFFErrorExt(0, "TIFFRegisterCODEC",
+		    "No space to register compression scheme %s", name);
+		return NULL;
+	}
+	return (cd->info);
+}
+
+void
+TIFFUnRegisterCODEC(TIFFCodec* c)
+{
+	codec_t* cd;
+	codec_t** pcd;
+
+	for (pcd = &registeredCODECS; (cd = *pcd); pcd = &cd->next)
+		if (cd->info == c) {
+			*pcd = cd->next;
+			_TIFFfree(cd);
+			return;
+		}
+	TIFFErrorExt(0, "TIFFUnRegisterCODEC",
+	    "Cannot remove compression scheme %s; not registered", c->name);
+}
+
+/************************************************************************/
+/*                       TIFFGetConfisuredCODECs()                      */
+/************************************************************************/
+
+/**
+ * Get list of configured codecs, both built-in and registered by user.
+ * Caller is responsible to free this structure.
+ * 
+ * @return returns array of TIFFCodec records (the last record should be NULL)
+ * or NULL if function failed.
+ */
+
+TIFFCodec*
+TIFFGetConfiguredCODECs()
+{
+	int i = 1;
+	codec_t *cd;
+	const TIFFCodec* c;
+	TIFFCodec* codecs = NULL;
+	TIFFCodec* new_codecs;
+
+	for (cd = registeredCODECS; cd; cd = cd->next) {
+		new_codecs = (TIFFCodec *)
+			_TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+		if (!new_codecs) {
+			_TIFFfree (codecs);
+			return NULL;
+		}
+		codecs = new_codecs;
+		_TIFFmemcpy(codecs + i - 1, cd, sizeof(TIFFCodec));
+		i++;
+	}
+	for (c = _TIFFBuiltinCODECS; c->name; c++) {
+		if (TIFFIsCODECConfigured(c->scheme)) {
+			new_codecs = (TIFFCodec *)
+				_TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+			if (!new_codecs) {
+				_TIFFfree (codecs);
+				return NULL;
+			}
+			codecs = new_codecs;
+			_TIFFmemcpy(codecs + i - 1, (const void*)c, sizeof(TIFFCodec));
+			i++;
+		}
+	}
+
+	new_codecs = (TIFFCodec *) _TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+	if (!new_codecs) {
+		_TIFFfree (codecs);
+		return NULL;
+	}
+	codecs = new_codecs;
+	_TIFFmemset(codecs + i - 1, 0, sizeof(TIFFCodec));
+
+	return codecs;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.c
new file mode 100644
index 0000000..076d9b4
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.c
@@ -0,0 +1,1662 @@
+/* $Id: tif_dir.c,v 1.113 2012-06-14 20:32:53 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Tag Get & Set Routines.
+ * (and also some miscellaneous stuff)
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+/*
+ * These are used in the backwards compatibility code...
+ */
+#define DATATYPE_VOID		0       /* !untyped data */
+#define DATATYPE_INT		1       /* !signed integer data */
+#define DATATYPE_UINT		2       /* !unsigned integer data */
+#define DATATYPE_IEEEFP		3       /* !IEEE floating point data */
+
+static void
+setByteArray(void** vpp, void* vp, size_t nmemb, size_t elem_size)
+{
+	if (*vpp)
+		_TIFFfree(*vpp), *vpp = 0;
+	if (vp) {
+		tmsize_t bytes = (tmsize_t)(nmemb * elem_size);
+		if (elem_size && bytes / elem_size == nmemb)
+			*vpp = (void*) _TIFFmalloc(bytes);
+		if (*vpp)
+			_TIFFmemcpy(*vpp, vp, bytes);
+	}
+}
+void _TIFFsetByteArray(void** vpp, void* vp, uint32 n)
+    { setByteArray(vpp, vp, n, 1); }
+void _TIFFsetString(char** cpp, char* cp)
+    { setByteArray((void**) cpp, (void*) cp, strlen(cp)+1, 1); }
+void _TIFFsetNString(char** cpp, char* cp, uint32 n)
+    { setByteArray((void**) cpp, (void*) cp, n, 1); }
+void _TIFFsetShortArray(uint16** wpp, uint16* wp, uint32 n)
+    { setByteArray((void**) wpp, (void*) wp, n, sizeof (uint16)); }
+void _TIFFsetLongArray(uint32** lpp, uint32* lp, uint32 n)
+    { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint32)); }
+void _TIFFsetLong8Array(uint64** lpp, uint64* lp, uint32 n)
+    { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint64)); }
+void _TIFFsetFloatArray(float** fpp, float* fp, uint32 n)
+    { setByteArray((void**) fpp, (void*) fp, n, sizeof (float)); }
+void _TIFFsetDoubleArray(double** dpp, double* dp, uint32 n)
+    { setByteArray((void**) dpp, (void*) dp, n, sizeof (double)); }
+
+static void
+setDoubleArrayOneValue(double** vpp, double value, size_t nmemb)
+{
+	if (*vpp)
+		_TIFFfree(*vpp);
+	*vpp = _TIFFmalloc(nmemb*sizeof(double));
+	if (*vpp)
+	{
+		while (nmemb--)
+			((double*)*vpp)[nmemb] = value;
+	}
+}
+
+/*
+ * Install extra samples information.
+ */
+static int
+setExtraSamples(TIFFDirectory* td, va_list ap, uint32* v)
+{
+/* XXX: Unassociated alpha data == 999 is a known Corel Draw bug, see below */
+#define EXTRASAMPLE_COREL_UNASSALPHA 999 
+
+	uint16* va;
+	uint32 i;
+
+	*v = (uint16) va_arg(ap, uint16_vap);
+	if ((uint16) *v > td->td_samplesperpixel)
+		return 0;
+	va = va_arg(ap, uint16*);
+	if (*v > 0 && va == NULL)		/* typically missing param */
+		return 0;
+	for (i = 0; i < *v; i++) {
+		if (va[i] > EXTRASAMPLE_UNASSALPHA) {
+			/*
+			 * XXX: Corel Draw is known to produce incorrect
+			 * ExtraSamples tags which must be patched here if we
+			 * want to be able to open some of the damaged TIFF
+			 * files: 
+			 */
+			if (va[i] == EXTRASAMPLE_COREL_UNASSALPHA)
+				va[i] = EXTRASAMPLE_UNASSALPHA;
+			else
+				return 0;
+		}
+	}
+	td->td_extrasamples = (uint16) *v;
+	_TIFFsetShortArray(&td->td_sampleinfo, va, td->td_extrasamples);
+	return 1;
+
+#undef EXTRASAMPLE_COREL_UNASSALPHA
+}
+
+/*
+ * Confirm we have "samplesperpixel" ink names separated by \0.  Returns 
+ * zero if the ink names are not as expected.
+ */
+static uint32
+checkInkNamesString(TIFF* tif, uint32 slen, const char* s)
+{
+	TIFFDirectory* td = &tif->tif_dir;
+	uint16 i = td->td_samplesperpixel;
+
+	if (slen > 0) {
+		const char* ep = s+slen;
+		const char* cp = s;
+		for (; i > 0; i--) {
+			for (; cp < ep && *cp != '\0'; cp++) {}
+			if (cp >= ep)
+				goto bad;
+			cp++;				/* skip \0 */
+		}
+		return ((uint32)(cp-s));
+	}
+bad:
+	TIFFErrorExt(tif->tif_clientdata, "TIFFSetField",
+	    "%s: Invalid InkNames value; expecting %d names, found %d",
+	    tif->tif_name,
+	    td->td_samplesperpixel,
+	    td->td_samplesperpixel-i);
+	return (0);
+}
+
+static int
+_TIFFVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	static const char module[] = "_TIFFVSetField";
+
+	TIFFDirectory* td = &tif->tif_dir;
+	int status = 1;
+	uint32 v32, i, v;
+	char* s;
+	const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY);
+	uint32 standard_tag = tag;
+
+	/*
+	 * We want to force the custom code to be used for custom
+	 * fields even if the tag happens to match a well known 
+	 * one - important for reinterpreted handling of standard
+	 * tag values in custom directories (ie. EXIF) 
+	 */
+	if (fip->field_bit == FIELD_CUSTOM) {
+		standard_tag = 0;
+	}
+
+	switch (standard_tag) {
+	case TIFFTAG_SUBFILETYPE:
+		td->td_subfiletype = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_IMAGEWIDTH:
+		td->td_imagewidth = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_IMAGELENGTH:
+		td->td_imagelength = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_BITSPERSAMPLE:
+		td->td_bitspersample = (uint16) va_arg(ap, uint16_vap);
+		/*
+		 * If the data require post-decoding processing to byte-swap
+		 * samples, set it up here.  Note that since tags are required
+		 * to be ordered, compression code can override this behaviour
+		 * in the setup method if it wants to roll the post decoding
+		 * work in with its normal work.
+		 */
+		if (tif->tif_flags & TIFF_SWAB) {
+			if (td->td_bitspersample == 8)
+				tif->tif_postdecode = _TIFFNoPostDecode;
+			else if (td->td_bitspersample == 16)
+				tif->tif_postdecode = _TIFFSwab16BitData;
+			else if (td->td_bitspersample == 24)
+				tif->tif_postdecode = _TIFFSwab24BitData;
+			else if (td->td_bitspersample == 32)
+				tif->tif_postdecode = _TIFFSwab32BitData;
+			else if (td->td_bitspersample == 64)
+				tif->tif_postdecode = _TIFFSwab64BitData;
+			else if (td->td_bitspersample == 128) /* two 64's */
+				tif->tif_postdecode = _TIFFSwab64BitData;
+		}
+		break;
+	case TIFFTAG_COMPRESSION:
+		v = (uint16) va_arg(ap, uint16_vap);
+		/*
+		 * If we're changing the compression scheme, the notify the
+		 * previous module so that it can cleanup any state it's
+		 * setup.
+		 */
+		if (TIFFFieldSet(tif, FIELD_COMPRESSION)) {
+			if ((uint32)td->td_compression == v)
+				break;
+			(*tif->tif_cleanup)(tif);
+			tif->tif_flags &= ~TIFF_CODERSETUP;
+		}
+		/*
+		 * Setup new compression routine state.
+		 */
+		if( (status = TIFFSetCompressionScheme(tif, v)) != 0 )
+		    td->td_compression = (uint16) v;
+		else
+		    status = 0;
+		break;
+	case TIFFTAG_PHOTOMETRIC:
+		td->td_photometric = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_THRESHHOLDING:
+		td->td_threshholding = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_FILLORDER:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB)
+			goto badvalue;
+		td->td_fillorder = (uint16) v;
+		break;
+	case TIFFTAG_ORIENTATION:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v)
+			goto badvalue;
+		else
+			td->td_orientation = (uint16) v;
+		break;
+	case TIFFTAG_SAMPLESPERPIXEL:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v == 0)
+			goto badvalue;
+		td->td_samplesperpixel = (uint16) v;
+		break;
+	case TIFFTAG_ROWSPERSTRIP:
+		v32 = (uint32) va_arg(ap, uint32);
+		if (v32 == 0)
+			goto badvalue32;
+		td->td_rowsperstrip = v32;
+		if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
+			td->td_tilelength = v32;
+			td->td_tilewidth = td->td_imagewidth;
+		}
+		break;
+	case TIFFTAG_MINSAMPLEVALUE:
+		td->td_minsamplevalue = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_MAXSAMPLEVALUE:
+		td->td_maxsamplevalue = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_SMINSAMPLEVALUE:
+		if (tif->tif_flags & TIFF_PERSAMPLE)
+			_TIFFsetDoubleArray(&td->td_sminsamplevalue, va_arg(ap, double*), td->td_samplesperpixel);
+		else
+			setDoubleArrayOneValue(&td->td_sminsamplevalue, va_arg(ap, double), td->td_samplesperpixel);
+		break;
+	case TIFFTAG_SMAXSAMPLEVALUE:
+		if (tif->tif_flags & TIFF_PERSAMPLE)
+			_TIFFsetDoubleArray(&td->td_smaxsamplevalue, va_arg(ap, double*), td->td_samplesperpixel);
+		else
+			setDoubleArrayOneValue(&td->td_smaxsamplevalue, va_arg(ap, double), td->td_samplesperpixel);
+		break;
+	case TIFFTAG_XRESOLUTION:
+		td->td_xresolution = (float) va_arg(ap, double);
+		break;
+	case TIFFTAG_YRESOLUTION:
+		td->td_yresolution = (float) va_arg(ap, double);
+		break;
+	case TIFFTAG_PLANARCONFIG:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE)
+			goto badvalue;
+		td->td_planarconfig = (uint16) v;
+		break;
+	case TIFFTAG_XPOSITION:
+		td->td_xposition = (float) va_arg(ap, double);
+		break;
+	case TIFFTAG_YPOSITION:
+		td->td_yposition = (float) va_arg(ap, double);
+		break;
+	case TIFFTAG_RESOLUTIONUNIT:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v)
+			goto badvalue;
+		td->td_resolutionunit = (uint16) v;
+		break;
+	case TIFFTAG_PAGENUMBER:
+		td->td_pagenumber[0] = (uint16) va_arg(ap, uint16_vap);
+		td->td_pagenumber[1] = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_HALFTONEHINTS:
+		td->td_halftonehints[0] = (uint16) va_arg(ap, uint16_vap);
+		td->td_halftonehints[1] = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_COLORMAP:
+		v32 = (uint32)(1L<<td->td_bitspersample);
+		_TIFFsetShortArray(&td->td_colormap[0], va_arg(ap, uint16*), v32);
+		_TIFFsetShortArray(&td->td_colormap[1], va_arg(ap, uint16*), v32);
+		_TIFFsetShortArray(&td->td_colormap[2], va_arg(ap, uint16*), v32);
+		break;
+	case TIFFTAG_EXTRASAMPLES:
+		if (!setExtraSamples(td, ap, &v))
+			goto badvalue;
+		break;
+	case TIFFTAG_MATTEING:
+		td->td_extrasamples =  (((uint16) va_arg(ap, uint16_vap)) != 0);
+		if (td->td_extrasamples) {
+			uint16 sv = EXTRASAMPLE_ASSOCALPHA;
+			_TIFFsetShortArray(&td->td_sampleinfo, &sv, 1);
+		}
+		break;
+	case TIFFTAG_TILEWIDTH:
+		v32 = (uint32) va_arg(ap, uint32);
+		if (v32 % 16) {
+			if (tif->tif_mode != O_RDONLY)
+				goto badvalue32;
+			TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+				"Nonstandard tile width %d, convert file", v32);
+		}
+		td->td_tilewidth = v32;
+		tif->tif_flags |= TIFF_ISTILED;
+		break;
+	case TIFFTAG_TILELENGTH:
+		v32 = (uint32) va_arg(ap, uint32);
+		if (v32 % 16) {
+			if (tif->tif_mode != O_RDONLY)
+				goto badvalue32;
+			TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+			    "Nonstandard tile length %d, convert file", v32);
+		}
+		td->td_tilelength = v32;
+		tif->tif_flags |= TIFF_ISTILED;
+		break;
+	case TIFFTAG_TILEDEPTH:
+		v32 = (uint32) va_arg(ap, uint32);
+		if (v32 == 0)
+			goto badvalue32;
+		td->td_tiledepth = v32;
+		break;
+	case TIFFTAG_DATATYPE:
+		v = (uint16) va_arg(ap, uint16_vap);
+		switch (v) {
+		case DATATYPE_VOID:	v = SAMPLEFORMAT_VOID;	break;
+		case DATATYPE_INT:	v = SAMPLEFORMAT_INT;	break;
+		case DATATYPE_UINT:	v = SAMPLEFORMAT_UINT;	break;
+		case DATATYPE_IEEEFP:	v = SAMPLEFORMAT_IEEEFP;break;
+		default:		goto badvalue;
+		}
+		td->td_sampleformat = (uint16) v;
+		break;
+	case TIFFTAG_SAMPLEFORMAT:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_COMPLEXIEEEFP < v)
+			goto badvalue;
+		td->td_sampleformat = (uint16) v;
+
+		/*  Try to fix up the SWAB function for complex data. */
+		if( td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT
+		    && td->td_bitspersample == 32
+		    && tif->tif_postdecode == _TIFFSwab32BitData )
+		    tif->tif_postdecode = _TIFFSwab16BitData;
+		else if( (td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT
+			  || td->td_sampleformat == SAMPLEFORMAT_COMPLEXIEEEFP)
+			 && td->td_bitspersample == 64
+			 && tif->tif_postdecode == _TIFFSwab64BitData )
+		    tif->tif_postdecode = _TIFFSwab32BitData;
+		break;
+	case TIFFTAG_IMAGEDEPTH:
+		td->td_imagedepth = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_SUBIFD:
+		if ((tif->tif_flags & TIFF_INSUBIFD) == 0) {
+			td->td_nsubifd = (uint16) va_arg(ap, uint16_vap);
+			_TIFFsetLong8Array(&td->td_subifd, (uint64*) va_arg(ap, uint64*),
+			    (long) td->td_nsubifd);
+		} else {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				     "%s: Sorry, cannot nest SubIFDs",
+				     tif->tif_name);
+			status = 0;
+		}
+		break;
+	case TIFFTAG_YCBCRPOSITIONING:
+		td->td_ycbcrpositioning = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_YCBCRSUBSAMPLING:
+		td->td_ycbcrsubsampling[0] = (uint16) va_arg(ap, uint16_vap);
+		td->td_ycbcrsubsampling[1] = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_TRANSFERFUNCTION:
+		v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1;
+		for (i = 0; i < v; i++)
+			_TIFFsetShortArray(&td->td_transferfunction[i],
+			    va_arg(ap, uint16*), 1L<<td->td_bitspersample);
+		break;
+	case TIFFTAG_REFERENCEBLACKWHITE:
+		/* XXX should check for null range */
+		_TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6);
+		break;
+	case TIFFTAG_INKNAMES:
+		v = (uint16) va_arg(ap, uint16_vap);
+		s = va_arg(ap, char*);
+		v = checkInkNamesString(tif, v, s);
+		status = v > 0;
+		if( v > 0 ) {
+			_TIFFsetNString(&td->td_inknames, s, v);
+			td->td_inknameslen = v;
+		}
+		break;
+	case TIFFTAG_PERSAMPLE:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if( v == PERSAMPLE_MULTI )
+			tif->tif_flags |= TIFF_PERSAMPLE;
+		else
+			tif->tif_flags &= ~TIFF_PERSAMPLE;
+		break;
+	default: {
+		TIFFTagValue *tv;
+		int tv_size, iCustom;
+
+		/*
+		 * This can happen if multiple images are open with different
+		 * codecs which have private tags.  The global tag information
+		 * table may then have tags that are valid for one file but not
+		 * the other. If the client tries to set a tag that is not valid
+		 * for the image's codec then we'll arrive here.  This
+		 * happens, for example, when tiffcp is used to convert between
+		 * compression schemes and codec-specific tags are blindly copied.
+		 */
+		if(fip == NULL || fip->field_bit != FIELD_CUSTOM) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "%s: Invalid %stag \"%s\" (not supported by codec)",
+			    tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "",
+			    fip ? fip->field_name : "Unknown");
+			status = 0;
+			break;
+		}
+
+		/*
+		 * Find the existing entry for this custom value.
+		 */
+		tv = NULL;
+		for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++) {
+			if (td->td_customValues[iCustom].info->field_tag == tag) {
+				tv = td->td_customValues + iCustom;
+				if (tv->value != NULL) {
+					_TIFFfree(tv->value);
+					tv->value = NULL;
+				}
+				break;
+			}
+		}
+
+		/*
+		 * Grow the custom list if the entry was not found.
+		 */
+		if(tv == NULL) {
+			TIFFTagValue *new_customValues;
+
+			td->td_customValueCount++;
+			new_customValues = (TIFFTagValue *)
+			    _TIFFrealloc(td->td_customValues,
+			    sizeof(TIFFTagValue) * td->td_customValueCount);
+			if (!new_customValues) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "%s: Failed to allocate space for list of custom values",
+				    tif->tif_name);
+				status = 0;
+				goto end;
+			}
+
+			td->td_customValues = new_customValues;
+
+			tv = td->td_customValues + (td->td_customValueCount - 1);
+			tv->info = fip;
+			tv->value = NULL;
+			tv->count = 0;
+		}
+
+		/*
+		 * Set custom value ... save a copy of the custom tag value.
+		 */
+		tv_size = _TIFFDataSize(fip->field_type);
+		if (tv_size == 0) {
+			status = 0;
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "%s: Bad field type %d for \"%s\"",
+			    tif->tif_name, fip->field_type,
+			    fip->field_name);
+			goto end;
+		}
+
+		if (fip->field_type == TIFF_ASCII)
+		{
+			uint32 ma;
+			char* mb;
+			if (fip->field_passcount)
+			{
+				assert(fip->field_writecount==TIFF_VARIABLE2);
+				ma=(uint32)va_arg(ap,uint32);
+				mb=(char*)va_arg(ap,char*);
+			}
+			else
+			{
+				mb=(char*)va_arg(ap,char*);
+				ma=(uint32)(strlen(mb)+1);
+			}
+			tv->count=ma;
+			setByteArray(&tv->value,mb,ma,1);
+		}
+		else
+		{
+			if (fip->field_passcount) {
+				if (fip->field_writecount == TIFF_VARIABLE2)
+					tv->count = (uint32) va_arg(ap, uint32);
+				else
+					tv->count = (int) va_arg(ap, int);
+			} else if (fip->field_writecount == TIFF_VARIABLE
+			   || fip->field_writecount == TIFF_VARIABLE2)
+				tv->count = 1;
+			else if (fip->field_writecount == TIFF_SPP)
+				tv->count = td->td_samplesperpixel;
+			else
+				tv->count = fip->field_writecount;
+
+			if (tv->count == 0) {
+				status = 0;
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "%s: Null count for \"%s\" (type "
+					     "%d, writecount %d, passcount %d)",
+					     tif->tif_name,
+					     fip->field_name,
+					     fip->field_type,
+					     fip->field_writecount,
+					     fip->field_passcount);
+				goto end;
+			}
+
+			tv->value = _TIFFCheckMalloc(tif, tv->count, tv_size,
+			    "custom tag binary object");
+			if (!tv->value) {
+				status = 0;
+				goto end;
+			}
+
+			if (fip->field_tag == TIFFTAG_DOTRANGE 
+			    && strcmp(fip->field_name,"DotRange") == 0) {
+				/* TODO: This is an evil exception and should not have been
+				   handled this way ... likely best if we move it into
+				   the directory structure with an explicit field in 
+				   libtiff 4.1 and assign it a FIELD_ value */
+				uint16 v[2];
+				v[0] = (uint16)va_arg(ap, int);
+				v[1] = (uint16)va_arg(ap, int);
+				_TIFFmemcpy(tv->value, &v, 4);
+			}
+
+			else if (fip->field_passcount
+				  || fip->field_writecount == TIFF_VARIABLE
+				  || fip->field_writecount == TIFF_VARIABLE2
+				  || fip->field_writecount == TIFF_SPP
+				  || tv->count > 1) {
+				_TIFFmemcpy(tv->value, va_arg(ap, void *),
+				    tv->count * tv_size);
+			} else {
+				char *val = (char *)tv->value;
+				assert( tv->count == 1 );
+
+				switch (fip->field_type) {
+				case TIFF_BYTE:
+				case TIFF_UNDEFINED:
+					{
+						uint8 v = (uint8)va_arg(ap, int);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_SBYTE:
+					{
+						int8 v = (int8)va_arg(ap, int);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_SHORT:
+					{
+						uint16 v = (uint16)va_arg(ap, int);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_SSHORT:
+					{
+						int16 v = (int16)va_arg(ap, int);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_LONG:
+				case TIFF_IFD:
+					{
+						uint32 v = va_arg(ap, uint32);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_SLONG:
+					{
+						int32 v = va_arg(ap, int32);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_LONG8:
+				case TIFF_IFD8:
+					{
+						uint64 v = va_arg(ap, uint64);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_SLONG8:
+					{
+						int64 v = va_arg(ap, int64);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_RATIONAL:
+				case TIFF_SRATIONAL:
+				case TIFF_FLOAT:
+					{
+						float v = (float)va_arg(ap, double);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_DOUBLE:
+					{
+						double v = va_arg(ap, double);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				default:
+					_TIFFmemset(val, 0, tv_size);
+					status = 0;
+					break;
+				}
+			}
+		}
+	}
+	}
+	if (status) {
+		const TIFFField* fip=TIFFFieldWithTag(tif,tag);
+		if (fip)                
+			TIFFSetFieldBit(tif, fip->field_bit);
+		tif->tif_flags |= TIFF_DIRTYDIRECT;
+	}
+
+end:
+	va_end(ap);
+	return (status);
+badvalue:
+        {
+		const TIFFField* fip=TIFFFieldWithTag(tif,tag);
+		TIFFErrorExt(tif->tif_clientdata, module,
+		     "%s: Bad value %u for \"%s\" tag",
+		     tif->tif_name, v,
+		     fip ? fip->field_name : "Unknown");
+		va_end(ap);
+        }
+	return (0);
+badvalue32:
+        {
+		const TIFFField* fip=TIFFFieldWithTag(tif,tag);
+		TIFFErrorExt(tif->tif_clientdata, module,
+		     "%s: Bad value %u for \"%s\" tag",
+		     tif->tif_name, v32,
+		     fip ? fip->field_name : "Unknown");
+		va_end(ap);
+        }
+	return (0);
+}
+
+/*
+ * Return 1/0 according to whether or not
+ * it is permissible to set the tag's value.
+ * Note that we allow ImageLength to be changed
+ * so that we can append and extend to images.
+ * Any other tag may not be altered once writing
+ * has commenced, unless its value has no effect
+ * on the format of the data that is written.
+ */
+static int
+OkToChangeTag(TIFF* tif, uint32 tag)
+{
+	const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY);
+	if (!fip) {			/* unknown tag */
+		TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", "%s: Unknown %stag %u",
+		    tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", tag);
+		return (0);
+	}
+	if (tag != TIFFTAG_IMAGELENGTH && (tif->tif_flags & TIFF_BEENWRITING) &&
+	    !fip->field_oktochange) {
+		/*
+		 * Consult info table to see if tag can be changed
+		 * after we've started writing.  We only allow changes
+		 * to those tags that don't/shouldn't affect the
+		 * compression and/or format of the data.
+		 */
+		TIFFErrorExt(tif->tif_clientdata, "TIFFSetField",
+		    "%s: Cannot modify tag \"%s\" while writing",
+		    tif->tif_name, fip->field_name);
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Record the value of a field in the
+ * internal directory structure.  The
+ * field will be written to the file
+ * when/if the directory structure is
+ * updated.
+ */
+int
+TIFFSetField(TIFF* tif, uint32 tag, ...)
+{
+	va_list ap;
+	int status;
+
+	va_start(ap, tag);
+	status = TIFFVSetField(tif, tag, ap);
+	va_end(ap);
+	return (status);
+}
+
+/*
+ * Clear the contents of the field in the internal structure.
+ */
+int
+TIFFUnsetField(TIFF* tif, uint32 tag)
+{
+    const TIFFField *fip =  TIFFFieldWithTag(tif, tag);
+    TIFFDirectory* td = &tif->tif_dir;
+
+    if( !fip )
+        return 0;
+
+    if( fip->field_bit != FIELD_CUSTOM )
+        TIFFClrFieldBit(tif, fip->field_bit);
+    else
+    {
+        TIFFTagValue *tv = NULL;
+        int i;
+
+        for (i = 0; i < td->td_customValueCount; i++) {
+                
+            tv = td->td_customValues + i;
+            if( tv->info->field_tag == tag )
+                break;
+        }
+
+        if( i < td->td_customValueCount )
+        {
+            _TIFFfree(tv->value);
+            for( ; i < td->td_customValueCount-1; i++) {
+                td->td_customValues[i] = td->td_customValues[i+1];
+            }
+            td->td_customValueCount--;
+        }
+    }
+        
+    tif->tif_flags |= TIFF_DIRTYDIRECT;
+
+    return (1);
+}
+
+/*
+ * Like TIFFSetField, but taking a varargs
+ * parameter list.  This routine is useful
+ * for building higher-level interfaces on
+ * top of the library.
+ */
+int
+TIFFVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	return OkToChangeTag(tif, tag) ?
+	    (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0;
+}
+
+static int
+_TIFFVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	TIFFDirectory* td = &tif->tif_dir;
+	int ret_val = 1;
+	uint32 standard_tag = tag;
+	const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY);
+	
+	/*
+	 * We want to force the custom code to be used for custom
+	 * fields even if the tag happens to match a well known 
+	 * one - important for reinterpreted handling of standard
+	 * tag values in custom directories (ie. EXIF) 
+	 */
+	if (fip->field_bit == FIELD_CUSTOM) {
+		standard_tag = 0;
+	}
+
+	switch (standard_tag) {
+		case TIFFTAG_SUBFILETYPE:
+			*va_arg(ap, uint32*) = td->td_subfiletype;
+			break;
+		case TIFFTAG_IMAGEWIDTH:
+			*va_arg(ap, uint32*) = td->td_imagewidth;
+			break;
+		case TIFFTAG_IMAGELENGTH:
+			*va_arg(ap, uint32*) = td->td_imagelength;
+			break;
+		case TIFFTAG_BITSPERSAMPLE:
+			*va_arg(ap, uint16*) = td->td_bitspersample;
+			break;
+		case TIFFTAG_COMPRESSION:
+			*va_arg(ap, uint16*) = td->td_compression;
+			break;
+		case TIFFTAG_PHOTOMETRIC:
+			*va_arg(ap, uint16*) = td->td_photometric;
+			break;
+		case TIFFTAG_THRESHHOLDING:
+			*va_arg(ap, uint16*) = td->td_threshholding;
+			break;
+		case TIFFTAG_FILLORDER:
+			*va_arg(ap, uint16*) = td->td_fillorder;
+			break;
+		case TIFFTAG_ORIENTATION:
+			*va_arg(ap, uint16*) = td->td_orientation;
+			break;
+		case TIFFTAG_SAMPLESPERPIXEL:
+			*va_arg(ap, uint16*) = td->td_samplesperpixel;
+			break;
+		case TIFFTAG_ROWSPERSTRIP:
+			*va_arg(ap, uint32*) = td->td_rowsperstrip;
+			break;
+		case TIFFTAG_MINSAMPLEVALUE:
+			*va_arg(ap, uint16*) = td->td_minsamplevalue;
+			break;
+		case TIFFTAG_MAXSAMPLEVALUE:
+			*va_arg(ap, uint16*) = td->td_maxsamplevalue;
+			break;
+		case TIFFTAG_SMINSAMPLEVALUE:
+			if (tif->tif_flags & TIFF_PERSAMPLE)
+				*va_arg(ap, double**) = td->td_sminsamplevalue;
+			else
+			{
+				/* libtiff historially treats this as a single value. */
+				uint16 i;
+				double v = td->td_sminsamplevalue[0];
+				for (i=1; i < td->td_samplesperpixel; ++i)
+					if( td->td_sminsamplevalue[i] < v )
+						v = td->td_sminsamplevalue[i];
+				*va_arg(ap, double*) = v;
+			}
+			break;
+		case TIFFTAG_SMAXSAMPLEVALUE:
+			if (tif->tif_flags & TIFF_PERSAMPLE)
+				*va_arg(ap, double**) = td->td_smaxsamplevalue;
+			else
+			{
+				/* libtiff historially treats this as a single value. */
+				uint16 i;
+				double v = td->td_smaxsamplevalue[0];
+				for (i=1; i < td->td_samplesperpixel; ++i)
+					if( td->td_smaxsamplevalue[i] > v )
+						v = td->td_smaxsamplevalue[i];
+				*va_arg(ap, double*) = v;
+			}
+			break;
+		case TIFFTAG_XRESOLUTION:
+			*va_arg(ap, float*) = td->td_xresolution;
+			break;
+		case TIFFTAG_YRESOLUTION:
+			*va_arg(ap, float*) = td->td_yresolution;
+			break;
+		case TIFFTAG_PLANARCONFIG:
+			*va_arg(ap, uint16*) = td->td_planarconfig;
+			break;
+		case TIFFTAG_XPOSITION:
+			*va_arg(ap, float*) = td->td_xposition;
+			break;
+		case TIFFTAG_YPOSITION:
+			*va_arg(ap, float*) = td->td_yposition;
+			break;
+		case TIFFTAG_RESOLUTIONUNIT:
+			*va_arg(ap, uint16*) = td->td_resolutionunit;
+			break;
+		case TIFFTAG_PAGENUMBER:
+			*va_arg(ap, uint16*) = td->td_pagenumber[0];
+			*va_arg(ap, uint16*) = td->td_pagenumber[1];
+			break;
+		case TIFFTAG_HALFTONEHINTS:
+			*va_arg(ap, uint16*) = td->td_halftonehints[0];
+			*va_arg(ap, uint16*) = td->td_halftonehints[1];
+			break;
+		case TIFFTAG_COLORMAP:
+			*va_arg(ap, uint16**) = td->td_colormap[0];
+			*va_arg(ap, uint16**) = td->td_colormap[1];
+			*va_arg(ap, uint16**) = td->td_colormap[2];
+			break;
+		case TIFFTAG_STRIPOFFSETS:
+		case TIFFTAG_TILEOFFSETS:
+			_TIFFFillStriles( tif );
+			*va_arg(ap, uint64**) = td->td_stripoffset;
+			break;
+		case TIFFTAG_STRIPBYTECOUNTS:
+		case TIFFTAG_TILEBYTECOUNTS:
+			_TIFFFillStriles( tif );
+			*va_arg(ap, uint64**) = td->td_stripbytecount;
+			break;
+		case TIFFTAG_MATTEING:
+			*va_arg(ap, uint16*) =
+			    (td->td_extrasamples == 1 &&
+			    td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA);
+			break;
+		case TIFFTAG_EXTRASAMPLES:
+			*va_arg(ap, uint16*) = td->td_extrasamples;
+			*va_arg(ap, uint16**) = td->td_sampleinfo;
+			break;
+		case TIFFTAG_TILEWIDTH:
+			*va_arg(ap, uint32*) = td->td_tilewidth;
+			break;
+		case TIFFTAG_TILELENGTH:
+			*va_arg(ap, uint32*) = td->td_tilelength;
+			break;
+		case TIFFTAG_TILEDEPTH:
+			*va_arg(ap, uint32*) = td->td_tiledepth;
+			break;
+		case TIFFTAG_DATATYPE:
+			switch (td->td_sampleformat) {
+				case SAMPLEFORMAT_UINT:
+					*va_arg(ap, uint16*) = DATATYPE_UINT;
+					break;
+				case SAMPLEFORMAT_INT:
+					*va_arg(ap, uint16*) = DATATYPE_INT;
+					break;
+				case SAMPLEFORMAT_IEEEFP:
+					*va_arg(ap, uint16*) = DATATYPE_IEEEFP;
+					break;
+				case SAMPLEFORMAT_VOID:
+					*va_arg(ap, uint16*) = DATATYPE_VOID;
+					break;
+			}
+			break;
+		case TIFFTAG_SAMPLEFORMAT:
+			*va_arg(ap, uint16*) = td->td_sampleformat;
+			break;
+		case TIFFTAG_IMAGEDEPTH:
+			*va_arg(ap, uint32*) = td->td_imagedepth;
+			break;
+		case TIFFTAG_SUBIFD:
+			*va_arg(ap, uint16*) = td->td_nsubifd;
+			*va_arg(ap, uint64**) = td->td_subifd;
+			break;
+		case TIFFTAG_YCBCRPOSITIONING:
+			*va_arg(ap, uint16*) = td->td_ycbcrpositioning;
+			break;
+		case TIFFTAG_YCBCRSUBSAMPLING:
+			*va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0];
+			*va_arg(ap, uint16*) = td->td_ycbcrsubsampling[1];
+			break;
+		case TIFFTAG_TRANSFERFUNCTION:
+			*va_arg(ap, uint16**) = td->td_transferfunction[0];
+			if (td->td_samplesperpixel - td->td_extrasamples > 1) {
+				*va_arg(ap, uint16**) = td->td_transferfunction[1];
+				*va_arg(ap, uint16**) = td->td_transferfunction[2];
+			}
+			break;
+		case TIFFTAG_REFERENCEBLACKWHITE:
+			*va_arg(ap, float**) = td->td_refblackwhite;
+			break;
+		case TIFFTAG_INKNAMES:
+			*va_arg(ap, char**) = td->td_inknames;
+			break;
+		default:
+			{
+				int i;
+
+				/*
+				 * This can happen if multiple images are open
+				 * with different codecs which have private
+				 * tags.  The global tag information table may
+				 * then have tags that are valid for one file
+				 * but not the other. If the client tries to
+				 * get a tag that is not valid for the image's
+				 * codec then we'll arrive here.
+				 */
+				if( fip == NULL || fip->field_bit != FIELD_CUSTOM )
+				{
+					TIFFErrorExt(tif->tif_clientdata, "_TIFFVGetField",
+					    "%s: Invalid %stag \"%s\" "
+					    "(not supported by codec)",
+					    tif->tif_name,
+					    isPseudoTag(tag) ? "pseudo-" : "",
+					    fip ? fip->field_name : "Unknown");
+					ret_val = 0;
+					break;
+				}
+
+				/*
+				 * Do we have a custom value?
+				 */
+				ret_val = 0;
+				for (i = 0; i < td->td_customValueCount; i++) {
+					TIFFTagValue *tv = td->td_customValues + i;
+
+					if (tv->info->field_tag != tag)
+						continue;
+
+					if (fip->field_passcount) {
+						if (fip->field_readcount == TIFF_VARIABLE2)
+							*va_arg(ap, uint32*) = (uint32)tv->count;
+						else  /* Assume TIFF_VARIABLE */
+							*va_arg(ap, uint16*) = (uint16)tv->count;
+						*va_arg(ap, void **) = tv->value;
+						ret_val = 1;
+					} else if (fip->field_tag == TIFFTAG_DOTRANGE
+						   && strcmp(fip->field_name,"DotRange") == 0) {
+						/* TODO: This is an evil exception and should not have been
+						   handled this way ... likely best if we move it into
+						   the directory structure with an explicit field in 
+						   libtiff 4.1 and assign it a FIELD_ value */
+						*va_arg(ap, uint16*) = ((uint16 *)tv->value)[0];
+						*va_arg(ap, uint16*) = ((uint16 *)tv->value)[1];
+						ret_val = 1;
+					} else {
+						if (fip->field_type == TIFF_ASCII
+						    || fip->field_readcount == TIFF_VARIABLE
+						    || fip->field_readcount == TIFF_VARIABLE2
+						    || fip->field_readcount == TIFF_SPP
+						    || tv->count > 1) {
+							*va_arg(ap, void **) = tv->value;
+							ret_val = 1;
+						} else {
+							char *val = (char *)tv->value;
+							assert( tv->count == 1 );
+							switch (fip->field_type) {
+							case TIFF_BYTE:
+							case TIFF_UNDEFINED:
+								*va_arg(ap, uint8*) =
+									*(uint8 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_SBYTE:
+								*va_arg(ap, int8*) =
+									*(int8 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_SHORT:
+								*va_arg(ap, uint16*) =
+									*(uint16 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_SSHORT:
+								*va_arg(ap, int16*) =
+									*(int16 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_LONG:
+							case TIFF_IFD:
+								*va_arg(ap, uint32*) =
+									*(uint32 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_SLONG:
+								*va_arg(ap, int32*) =
+									*(int32 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_LONG8:
+							case TIFF_IFD8:
+								*va_arg(ap, uint64*) =
+									*(uint64 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_SLONG8:
+								*va_arg(ap, int64*) =
+									*(int64 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_RATIONAL:
+							case TIFF_SRATIONAL:
+							case TIFF_FLOAT:
+								*va_arg(ap, float*) =
+									*(float *)val;
+								ret_val = 1;
+								break;
+							case TIFF_DOUBLE:
+								*va_arg(ap, double*) =
+									*(double *)val;
+								ret_val = 1;
+								break;
+							default:
+								ret_val = 0;
+								break;
+							}
+						}
+					}
+					break;
+				}
+			}
+	}
+	return(ret_val);
+}
+
+/*
+ * Return the value of a field in the
+ * internal directory structure.
+ */
+int
+TIFFGetField(TIFF* tif, uint32 tag, ...)
+{
+	int status;
+	va_list ap;
+
+	va_start(ap, tag);
+	status = TIFFVGetField(tif, tag, ap);
+	va_end(ap);
+	return (status);
+}
+
+/*
+ * Like TIFFGetField, but taking a varargs
+ * parameter list.  This routine is useful
+ * for building higher-level interfaces on
+ * top of the library.
+ */
+int
+TIFFVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY);
+	return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit)) ?
+	    (*tif->tif_tagmethods.vgetfield)(tif, tag, ap) : 0);
+}
+
+#define	CleanupField(member) {		\
+    if (td->member) {			\
+	_TIFFfree(td->member);		\
+	td->member = 0;			\
+    }					\
+}
+
+/*
+ * Release storage associated with a directory.
+ */
+void
+TIFFFreeDirectory(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	int            i;
+
+	_TIFFmemset(td->td_fieldsset, 0, FIELD_SETLONGS);
+	CleanupField(td_sminsamplevalue);
+	CleanupField(td_smaxsamplevalue);
+	CleanupField(td_colormap[0]);
+	CleanupField(td_colormap[1]);
+	CleanupField(td_colormap[2]);
+	CleanupField(td_sampleinfo);
+	CleanupField(td_subifd);
+	CleanupField(td_inknames);
+	CleanupField(td_refblackwhite);
+	CleanupField(td_transferfunction[0]);
+	CleanupField(td_transferfunction[1]);
+	CleanupField(td_transferfunction[2]);
+	CleanupField(td_stripoffset);
+	CleanupField(td_stripbytecount);
+	TIFFClrFieldBit(tif, FIELD_YCBCRSUBSAMPLING);
+	TIFFClrFieldBit(tif, FIELD_YCBCRPOSITIONING);
+
+	/* Cleanup custom tag values */
+	for( i = 0; i < td->td_customValueCount; i++ ) {
+		if (td->td_customValues[i].value)
+			_TIFFfree(td->td_customValues[i].value);
+	}
+
+	td->td_customValueCount = 0;
+	CleanupField(td_customValues);
+
+#if defined(DEFER_STRILE_LOAD)
+        _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
+        _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
+#endif        
+}
+#undef CleanupField
+
+/*
+ * Client Tag extension support (from Niles Ritter).
+ */
+static TIFFExtendProc _TIFFextender = (TIFFExtendProc) NULL;
+
+TIFFExtendProc
+TIFFSetTagExtender(TIFFExtendProc extender)
+{
+	TIFFExtendProc prev = _TIFFextender;
+	_TIFFextender = extender;
+	return (prev);
+}
+
+/*
+ * Setup for a new directory.  Should we automatically call
+ * TIFFWriteDirectory() if the current one is dirty?
+ *
+ * The newly created directory will not exist on the file till
+ * TIFFWriteDirectory(), TIFFFlush() or TIFFClose() is called.
+ */
+int
+TIFFCreateDirectory(TIFF* tif)
+{
+	TIFFDefaultDirectory(tif);
+	tif->tif_diroff = 0;
+	tif->tif_nextdiroff = 0;
+	tif->tif_curoff = 0;
+	tif->tif_row = (uint32) -1;
+	tif->tif_curstrip = (uint32) -1;
+
+	return 0;
+}
+
+int
+TIFFCreateCustomDirectory(TIFF* tif, const TIFFFieldArray* infoarray)
+{
+	TIFFDefaultDirectory(tif);
+
+	/*
+	 * Reset the field definitions to match the application provided list. 
+	 * Hopefully TIFFDefaultDirectory() won't have done anything irreversable
+	 * based on it's assumption this is an image directory.
+	 */
+	_TIFFSetupFields(tif, infoarray);
+
+	tif->tif_diroff = 0;
+	tif->tif_nextdiroff = 0;
+	tif->tif_curoff = 0;
+	tif->tif_row = (uint32) -1;
+	tif->tif_curstrip = (uint32) -1;
+
+	return 0;
+}
+
+int
+TIFFCreateEXIFDirectory(TIFF* tif)
+{
+	const TIFFFieldArray* exifFieldArray;
+	exifFieldArray = _TIFFGetExifFields();
+	return TIFFCreateCustomDirectory(tif, exifFieldArray);
+}
+
+/*
+ * Setup a default directory structure.
+ */
+int
+TIFFDefaultDirectory(TIFF* tif)
+{
+	register TIFFDirectory* td = &tif->tif_dir;
+	const TIFFFieldArray* tiffFieldArray;
+
+	tiffFieldArray = _TIFFGetFields();
+	_TIFFSetupFields(tif, tiffFieldArray);   
+
+	_TIFFmemset(td, 0, sizeof (*td));
+	td->td_fillorder = FILLORDER_MSB2LSB;
+	td->td_bitspersample = 1;
+	td->td_threshholding = THRESHHOLD_BILEVEL;
+	td->td_orientation = ORIENTATION_TOPLEFT;
+	td->td_samplesperpixel = 1;
+	td->td_rowsperstrip = (uint32) -1;
+	td->td_tilewidth = 0;
+	td->td_tilelength = 0;
+	td->td_tiledepth = 1;
+	td->td_stripbytecountsorted = 1; /* Our own arrays always sorted. */  
+	td->td_resolutionunit = RESUNIT_INCH;
+	td->td_sampleformat = SAMPLEFORMAT_UINT;
+	td->td_imagedepth = 1;
+	td->td_ycbcrsubsampling[0] = 2;
+	td->td_ycbcrsubsampling[1] = 2;
+	td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED;
+	tif->tif_postdecode = _TIFFNoPostDecode;  
+	tif->tif_foundfield = NULL;
+	tif->tif_tagmethods.vsetfield = _TIFFVSetField;  
+	tif->tif_tagmethods.vgetfield = _TIFFVGetField;
+	tif->tif_tagmethods.printdir = NULL;
+	/*
+	 *  Give client code a chance to install their own
+	 *  tag extensions & methods, prior to compression overloads.
+	 */
+	if (_TIFFextender)
+		(*_TIFFextender)(tif);
+	(void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+	/*
+	 * NB: The directory is marked dirty as a result of setting
+	 * up the default compression scheme.  However, this really
+	 * isn't correct -- we want TIFF_DIRTYDIRECT to be set only
+	 * if the user does something.  We could just do the setup
+	 * by hand, but it seems better to use the normal mechanism
+	 * (i.e. TIFFSetField).
+	 */
+	tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+
+	/*
+	 * As per http://bugzilla.remotesensing.org/show_bug.cgi?id=19
+	 * we clear the ISTILED flag when setting up a new directory.
+	 * Should we also be clearing stuff like INSUBIFD?
+	 */
+	tif->tif_flags &= ~TIFF_ISTILED;
+
+	return (1);
+}
+
+static int
+TIFFAdvanceDirectory(TIFF* tif, uint64* nextdir, uint64* off)
+{
+	static const char module[] = "TIFFAdvanceDirectory";
+	if (isMapped(tif))
+	{
+		uint64 poff=*nextdir;
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			tmsize_t poffa,poffb,poffc,poffd;
+			uint16 dircount;
+			uint32 nextdir32;
+			poffa=(tmsize_t)poff;
+			poffb=poffa+sizeof(uint16);
+			if (((uint64)poffa!=poff)||(poffb<poffa)||(poffb<(tmsize_t)sizeof(uint16))||(poffb>tif->tif_size))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count");
+				return(0);
+			}
+			_TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16));
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort(&dircount);
+			poffc=poffb+dircount*12;
+			poffd=poffc+sizeof(uint32);
+			if ((poffc<poffb)||(poffc<dircount*12)||(poffd<poffc)||(poffd<(tmsize_t)sizeof(uint32))||(poffd>tif->tif_size))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory link");
+				return(0);
+			}
+			if (off!=NULL)
+				*off=(uint64)poffc;
+			_TIFFmemcpy(&nextdir32,tif->tif_base+poffc,sizeof(uint32));
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong(&nextdir32);
+			*nextdir=nextdir32;
+		}
+		else
+		{
+			tmsize_t poffa,poffb,poffc,poffd;
+			uint64 dircount64;
+			uint16 dircount16;
+			poffa=(tmsize_t)poff;
+			poffb=poffa+sizeof(uint64);
+			if (((uint64)poffa!=poff)||(poffb<poffa)||(poffb<(tmsize_t)sizeof(uint64))||(poffb>tif->tif_size))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count");
+				return(0);
+			}
+			_TIFFmemcpy(&dircount64,tif->tif_base+poffa,sizeof(uint64));
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>0xFFFF)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Sanity check on directory count failed");
+				return(0);
+			}
+			dircount16=(uint16)dircount64;
+			poffc=poffb+dircount16*20;
+			poffd=poffc+sizeof(uint64);
+			if ((poffc<poffb)||(poffc<dircount16*20)||(poffd<poffc)||(poffd<(tmsize_t)sizeof(uint64))||(poffd>tif->tif_size))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory link");
+				return(0);
+			}
+			if (off!=NULL)
+				*off=(uint64)poffc;
+			_TIFFmemcpy(nextdir,tif->tif_base+poffc,sizeof(uint64));
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8(nextdir);
+		}
+		return(1);
+	}
+	else
+	{
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			uint16 dircount;
+			uint32 nextdir32;
+			if (!SeekOK(tif, *nextdir) ||
+			    !ReadOK(tif, &dircount, sizeof (uint16))) {
+				TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
+				    tif->tif_name);
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&dircount);
+			if (off != NULL)
+				*off = TIFFSeekFile(tif,
+				    dircount*12, SEEK_CUR);
+			else
+				(void) TIFFSeekFile(tif,
+				    dircount*12, SEEK_CUR);
+			if (!ReadOK(tif, &nextdir32, sizeof (uint32))) {
+				TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link",
+				    tif->tif_name);
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong(&nextdir32);
+			*nextdir=nextdir32;
+		}
+		else
+		{
+			uint64 dircount64;
+			uint16 dircount16;
+			if (!SeekOK(tif, *nextdir) ||
+			    !ReadOK(tif, &dircount64, sizeof (uint64))) {
+				TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
+				    tif->tif_name);
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>0xFFFF)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory count");
+				return(0);
+			}
+			dircount16 = (uint16)dircount64;
+			if (off != NULL)
+				*off = TIFFSeekFile(tif,
+				    dircount16*20, SEEK_CUR);
+			else
+				(void) TIFFSeekFile(tif,
+				    dircount16*20, SEEK_CUR);
+			if (!ReadOK(tif, nextdir, sizeof (uint64))) {
+				TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link",
+				    tif->tif_name);
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(nextdir);
+		}
+		return (1);
+	}
+}
+
+/*
+ * Count the number of directories in a file.
+ */
+uint16
+TIFFNumberOfDirectories(TIFF* tif)
+{
+	uint64 nextdir;
+	uint16 n;
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+		nextdir = tif->tif_header.classic.tiff_diroff;
+	else
+		nextdir = tif->tif_header.big.tiff_diroff;
+	n = 0;
+	while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL))
+		n++;
+	return (n);
+}
+
+/*
+ * Set the n-th directory as the current directory.
+ * NB: Directories are numbered starting at 0.
+ */
+int
+TIFFSetDirectory(TIFF* tif, uint16 dirn)
+{
+	uint64 nextdir;
+	uint16 n;
+
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+		nextdir = tif->tif_header.classic.tiff_diroff;
+	else
+		nextdir = tif->tif_header.big.tiff_diroff;
+	for (n = dirn; n > 0 && nextdir != 0; n--)
+		if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
+			return (0);
+	tif->tif_nextdiroff = nextdir;
+	/*
+	 * Set curdir to the actual directory index.  The
+	 * -1 is because TIFFReadDirectory will increment
+	 * tif_curdir after successfully reading the directory.
+	 */
+	tif->tif_curdir = (dirn - n) - 1;
+	/*
+	 * Reset tif_dirnumber counter and start new list of seen directories.
+	 * We need this to prevent IFD loops.
+	 */
+	tif->tif_dirnumber = 0;
+	return (TIFFReadDirectory(tif));
+}
+
+/*
+ * Set the current directory to be the directory
+ * located at the specified file offset.  This interface
+ * is used mainly to access directories linked with
+ * the SubIFD tag (e.g. thumbnail images).
+ */
+int
+TIFFSetSubDirectory(TIFF* tif, uint64 diroff)
+{
+	tif->tif_nextdiroff = diroff;
+	/*
+	 * Reset tif_dirnumber counter and start new list of seen directories.
+	 * We need this to prevent IFD loops.
+	 */
+	tif->tif_dirnumber = 0;
+	return (TIFFReadDirectory(tif));
+}
+
+/*
+ * Return file offset of the current directory.
+ */
+uint64
+TIFFCurrentDirOffset(TIFF* tif)
+{
+	return (tif->tif_diroff);
+}
+
+/*
+ * Return an indication of whether or not we are
+ * at the last directory in the file.
+ */
+int
+TIFFLastDirectory(TIFF* tif)
+{
+	return (tif->tif_nextdiroff == 0);
+}
+
+/*
+ * Unlink the specified directory from the directory chain.
+ */
+int
+TIFFUnlinkDirectory(TIFF* tif, uint16 dirn)
+{
+	static const char module[] = "TIFFUnlinkDirectory";
+	uint64 nextdir;
+	uint64 off;
+	uint16 n;
+
+	if (tif->tif_mode == O_RDONLY) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+                             "Can not unlink directory in read-only file");
+		return (0);
+	}
+	/*
+	 * Go to the directory before the one we want
+	 * to unlink and nab the offset of the link
+	 * field we'll need to patch.
+	 */
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		nextdir = tif->tif_header.classic.tiff_diroff;
+		off = 4;
+	}
+	else
+	{
+		nextdir = tif->tif_header.big.tiff_diroff;
+		off = 8;
+	}
+	for (n = dirn-1; n > 0; n--) {
+		if (nextdir == 0) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Directory %d does not exist", dirn);
+			return (0);
+		}
+		if (!TIFFAdvanceDirectory(tif, &nextdir, &off))
+			return (0);
+	}
+	/*
+	 * Advance to the directory to be unlinked and fetch
+	 * the offset of the directory that follows.
+	 */
+	if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
+		return (0);
+	/*
+	 * Go back and patch the link field of the preceding
+	 * directory to point to the offset of the directory
+	 * that follows.
+	 */
+	(void) TIFFSeekFile(tif, off, SEEK_SET);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		uint32 nextdir32;
+		nextdir32=(uint32)nextdir;
+		assert((uint64)nextdir32==nextdir);
+		if (tif->tif_flags & TIFF_SWAB)
+			TIFFSwabLong(&nextdir32);
+		if (!WriteOK(tif, &nextdir32, sizeof (uint32))) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link");
+			return (0);
+		}
+	}
+	else
+	{
+		if (tif->tif_flags & TIFF_SWAB)
+			TIFFSwabLong8(&nextdir);
+		if (!WriteOK(tif, &nextdir, sizeof (uint64))) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link");
+			return (0);
+		}
+	}
+	/*
+	 * Leave directory state setup safely.  We don't have
+	 * facilities for doing inserting and removing directories,
+	 * so it's safest to just invalidate everything.  This
+	 * means that the caller can only append to the directory
+	 * chain.
+	 */
+	(*tif->tif_cleanup)(tif);
+	if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+		_TIFFfree(tif->tif_rawdata);
+		tif->tif_rawdata = NULL;
+		tif->tif_rawcc = 0;
+                tif->tif_rawdataoff = 0;
+                tif->tif_rawdataloaded = 0;
+	}
+	tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP|TIFF_POSTENCODE|TIFF_BUF4WRITE);
+	TIFFFreeDirectory(tif);
+	TIFFDefaultDirectory(tif);
+	tif->tif_diroff = 0;			/* force link on next write */
+	tif->tif_nextdiroff = 0;		/* next write must be at end */
+	tif->tif_curoff = 0;
+	tif->tif_row = (uint32) -1;
+	tif->tif_curstrip = (uint32) -1;
+	return (1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.h b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.h
new file mode 100644
index 0000000..6af5f3d
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.h
@@ -0,0 +1,308 @@
+/* $Id: tif_dir.h,v 1.54 2011-02-18 20:53:05 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFDIR_
+#define	_TIFFDIR_
+/*
+ * ``Library-private'' Directory-related Definitions.
+ */
+
+typedef struct {
+	const TIFFField *info;
+	int             count;
+	void           *value;
+} TIFFTagValue;
+
+/*
+ * TIFF Image File Directories are comprised of a table of field
+ * descriptors of the form shown below.  The table is sorted in
+ * ascending order by tag.  The values associated with each entry are
+ * disjoint and may appear anywhere in the file (so long as they are
+ * placed on a word boundary).
+ *
+ * If the value is 4 bytes or less, in ClassicTIFF, or 8 bytes or less in
+ * BigTIFF, then it is placed in the offset field to save space. If so,
+ * it is left-justified in the offset field.
+ */
+typedef struct {
+	uint16 tdir_tag;        /* see below */
+	uint16 tdir_type;       /* data type; see below */
+	uint64 tdir_count;      /* number of items; length in spec */
+	union {
+		uint16 toff_short;
+		uint32 toff_long;
+		uint64 toff_long8;
+	} tdir_offset;		/* either offset or the data itself if fits */
+} TIFFDirEntry;
+
+/*
+ * Internal format of a TIFF directory entry.
+ */
+typedef struct {
+#define FIELD_SETLONGS 4
+	/* bit vector of fields that are set */
+	unsigned long td_fieldsset[FIELD_SETLONGS];
+
+	uint32  td_imagewidth, td_imagelength, td_imagedepth;
+	uint32  td_tilewidth, td_tilelength, td_tiledepth;
+	uint32  td_subfiletype;
+	uint16  td_bitspersample;
+	uint16  td_sampleformat;
+	uint16  td_compression;
+	uint16  td_photometric;
+	uint16  td_threshholding;
+	uint16  td_fillorder;
+	uint16  td_orientation;
+	uint16  td_samplesperpixel;
+	uint32  td_rowsperstrip;
+	uint16  td_minsamplevalue, td_maxsamplevalue;
+	double* td_sminsamplevalue;
+	double* td_smaxsamplevalue;
+	float   td_xresolution, td_yresolution;
+	uint16  td_resolutionunit;
+	uint16  td_planarconfig;
+	float   td_xposition, td_yposition;
+	uint16  td_pagenumber[2];
+	uint16* td_colormap[3];
+	uint16  td_halftonehints[2];
+	uint16  td_extrasamples;
+	uint16* td_sampleinfo;
+	/* even though the name is misleading, td_stripsperimage is the number
+	 * of striles (=strips or tiles) per plane, and td_nstrips the total
+	 * number of striles */
+	uint32  td_stripsperimage;  
+	uint32  td_nstrips;              /* size of offset & bytecount arrays */
+	uint64* td_stripoffset;
+	uint64* td_stripbytecount;
+	int     td_stripbytecountsorted; /* is the bytecount array sorted ascending? */
+#if defined(DEFER_STRILE_LOAD)
+        TIFFDirEntry td_stripoffset_entry;    /* for deferred loading */
+        TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */
+#endif
+	uint16  td_nsubifd;
+	uint64* td_subifd;
+	/* YCbCr parameters */
+	uint16  td_ycbcrsubsampling[2];
+	uint16  td_ycbcrpositioning;
+	/* Colorimetry parameters */
+	uint16* td_transferfunction[3];
+	float*	td_refblackwhite;
+	/* CMYK parameters */
+	int     td_inknameslen;
+	char*   td_inknames;
+
+	int     td_customValueCount;
+        TIFFTagValue *td_customValues;
+} TIFFDirectory;
+
+/*
+ * Field flags used to indicate fields that have been set in a directory, and
+ * to reference fields when manipulating a directory.
+ */
+
+/*
+ * FIELD_IGNORE is used to signify tags that are to be processed but otherwise
+ * ignored.  This permits antiquated tags to be quietly read and discarded.
+ * Note that a bit *is* allocated for ignored tags; this is understood by the
+ * directory reading logic which uses this fact to avoid special-case handling
+ */
+#define FIELD_IGNORE                   0
+
+/* multi-item fields */
+#define FIELD_IMAGEDIMENSIONS          1
+#define FIELD_TILEDIMENSIONS           2
+#define FIELD_RESOLUTION               3
+#define FIELD_POSITION                 4
+
+/* single-item fields */
+#define FIELD_SUBFILETYPE              5
+#define FIELD_BITSPERSAMPLE            6
+#define FIELD_COMPRESSION              7
+#define FIELD_PHOTOMETRIC              8
+#define FIELD_THRESHHOLDING            9
+#define FIELD_FILLORDER                10
+#define FIELD_ORIENTATION              15
+#define FIELD_SAMPLESPERPIXEL          16
+#define FIELD_ROWSPERSTRIP             17
+#define FIELD_MINSAMPLEVALUE           18
+#define FIELD_MAXSAMPLEVALUE           19
+#define FIELD_PLANARCONFIG             20
+#define FIELD_RESOLUTIONUNIT           22
+#define FIELD_PAGENUMBER               23
+#define FIELD_STRIPBYTECOUNTS          24
+#define FIELD_STRIPOFFSETS             25
+#define FIELD_COLORMAP                 26
+#define FIELD_EXTRASAMPLES             31
+#define FIELD_SAMPLEFORMAT             32
+#define FIELD_SMINSAMPLEVALUE          33
+#define FIELD_SMAXSAMPLEVALUE          34
+#define FIELD_IMAGEDEPTH               35
+#define FIELD_TILEDEPTH                36
+#define FIELD_HALFTONEHINTS            37
+#define FIELD_YCBCRSUBSAMPLING         39
+#define FIELD_YCBCRPOSITIONING         40
+#define	FIELD_REFBLACKWHITE            41
+#define FIELD_TRANSFERFUNCTION         44
+#define FIELD_INKNAMES                 46
+#define FIELD_SUBIFD                   49
+/*      FIELD_CUSTOM (see tiffio.h)    65 */
+/* end of support for well-known tags; codec-private tags follow */
+#define FIELD_CODEC                    66  /* base of codec-private tags */
+
+
+/*
+ * Pseudo-tags don't normally need field bits since they are not written to an
+ * output file (by definition). The library also has express logic to always
+ * query a codec for a pseudo-tag so allocating a field bit for one is a
+ * waste.   If codec wants to promote the notion of a pseudo-tag being ``set''
+ * or ``unset'' then it can do using internal state flags without polluting
+ * the field bit space defined for real tags.
+ */
+#define FIELD_PSEUDO			0
+
+#define FIELD_LAST			(32*FIELD_SETLONGS-1)
+
+#define BITn(n)				(((unsigned long)1L)<<((n)&0x1f))
+#define BITFIELDn(tif, n)		((tif)->tif_dir.td_fieldsset[(n)/32])
+#define TIFFFieldSet(tif, field)	(BITFIELDn(tif, field) & BITn(field))
+#define TIFFSetFieldBit(tif, field)	(BITFIELDn(tif, field) |= BITn(field))
+#define TIFFClrFieldBit(tif, field)	(BITFIELDn(tif, field) &= ~BITn(field))
+
+#define FieldSet(fields, f)		(fields[(f)/32] & BITn(f))
+#define ResetFieldBit(fields, f)	(fields[(f)/32] &= ~BITn(f))
+
+typedef enum {
+	TIFF_SETGET_UNDEFINED = 0,
+	TIFF_SETGET_ASCII = 1,
+	TIFF_SETGET_UINT8 = 2,
+	TIFF_SETGET_SINT8 = 3,
+	TIFF_SETGET_UINT16 = 4,
+	TIFF_SETGET_SINT16 = 5,
+	TIFF_SETGET_UINT32 = 6,
+	TIFF_SETGET_SINT32 = 7,
+	TIFF_SETGET_UINT64 = 8,
+	TIFF_SETGET_SINT64 = 9,
+	TIFF_SETGET_FLOAT = 10,
+	TIFF_SETGET_DOUBLE = 11,
+	TIFF_SETGET_IFD8 = 12,
+	TIFF_SETGET_INT = 13,
+	TIFF_SETGET_UINT16_PAIR = 14,
+	TIFF_SETGET_C0_ASCII = 15,
+	TIFF_SETGET_C0_UINT8 = 16,
+	TIFF_SETGET_C0_SINT8 = 17,
+	TIFF_SETGET_C0_UINT16 = 18,
+	TIFF_SETGET_C0_SINT16 = 19,
+	TIFF_SETGET_C0_UINT32 = 20,
+	TIFF_SETGET_C0_SINT32 = 21,
+	TIFF_SETGET_C0_UINT64 = 22,
+	TIFF_SETGET_C0_SINT64 = 23,
+	TIFF_SETGET_C0_FLOAT = 24,
+	TIFF_SETGET_C0_DOUBLE = 25,
+	TIFF_SETGET_C0_IFD8 = 26,
+	TIFF_SETGET_C16_ASCII = 27,
+	TIFF_SETGET_C16_UINT8 = 28,
+	TIFF_SETGET_C16_SINT8 = 29,
+	TIFF_SETGET_C16_UINT16 = 30,
+	TIFF_SETGET_C16_SINT16 = 31,
+	TIFF_SETGET_C16_UINT32 = 32,
+	TIFF_SETGET_C16_SINT32 = 33,
+	TIFF_SETGET_C16_UINT64 = 34,
+	TIFF_SETGET_C16_SINT64 = 35,
+	TIFF_SETGET_C16_FLOAT = 36,
+	TIFF_SETGET_C16_DOUBLE = 37,
+	TIFF_SETGET_C16_IFD8 = 38,
+	TIFF_SETGET_C32_ASCII = 39,
+	TIFF_SETGET_C32_UINT8 = 40,
+	TIFF_SETGET_C32_SINT8 = 41,
+	TIFF_SETGET_C32_UINT16 = 42,
+	TIFF_SETGET_C32_SINT16 = 43,
+	TIFF_SETGET_C32_UINT32 = 44,
+	TIFF_SETGET_C32_SINT32 = 45,
+	TIFF_SETGET_C32_UINT64 = 46,
+	TIFF_SETGET_C32_SINT64 = 47,
+	TIFF_SETGET_C32_FLOAT = 48,
+	TIFF_SETGET_C32_DOUBLE = 49,
+	TIFF_SETGET_C32_IFD8 = 50,
+	TIFF_SETGET_OTHER = 51
+} TIFFSetGetFieldType;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern const TIFFFieldArray* _TIFFGetFields(void);
+extern const TIFFFieldArray* _TIFFGetExifFields(void);
+extern void _TIFFSetupFields(TIFF* tif, const TIFFFieldArray* infoarray);
+extern void _TIFFPrintFieldInfo(TIFF*, FILE*);
+
+extern int _TIFFFillStriles(TIFF*);        
+
+typedef enum {
+	tfiatImage,
+	tfiatExif,
+	tfiatOther
+} TIFFFieldArrayType;
+
+struct _TIFFFieldArray {
+	TIFFFieldArrayType type;    /* array type, will be used to determine if IFD is image and such */
+	uint32 allocated_size;      /* 0 if array is constant, other if modified by future definition extension support */
+	uint32 count;               /* number of elements in fields array */
+	TIFFField* fields;          /* actual field info */
+};
+
+struct _TIFFField {
+	uint32 field_tag;                       /* field's tag */
+	short field_readcount;                  /* read count/TIFF_VARIABLE/TIFF_SPP */
+	short field_writecount;                 /* write count/TIFF_VARIABLE */
+	TIFFDataType field_type;                /* type of associated data */
+	uint32 reserved;                        /* reserved for future extension */
+	TIFFSetGetFieldType set_field_type;     /* type to be passed to TIFFSetField */
+	TIFFSetGetFieldType get_field_type;     /* type to be passed to TIFFGetField */
+	unsigned short field_bit;               /* bit in fieldsset bit vector */
+	unsigned char field_oktochange;         /* if true, can change while writing */
+	unsigned char field_passcount;          /* if true, pass dir count on set */
+	char* field_name;                       /* ASCII name */
+	TIFFFieldArray* field_subfields;        /* if field points to child ifds, child ifd field definition array */
+};
+
+extern int _TIFFMergeFields(TIFF*, const TIFFField[], uint32);
+extern const TIFFField* _TIFFFindOrRegisterField(TIFF *, uint32, TIFFDataType);
+extern  TIFFField* _TIFFCreateAnonField(TIFF *, uint32, TIFFDataType);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* _TIFFDIR_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirinfo.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirinfo.c
new file mode 100644
index 0000000..5f28d23
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirinfo.c
@@ -0,0 +1,978 @@
+/* $Id: tif_dirinfo.c,v 1.117 2012-08-19 16:56:34 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Core Directory Tag Support.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include <stdlib.h>
+
+/*
+ * NOTE: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG.
+ *
+ * NOTE: The second field (field_readcount) and third field (field_writecount)
+ *       sometimes use the values TIFF_VARIABLE (-1), TIFF_VARIABLE2 (-3)
+ *       and TIFF_SPP (-2). The macros should be used but would throw off
+ *       the formatting of the code, so please interprete the -1, -2 and -3
+ *       values accordingly.
+ */
+
+static TIFFFieldArray tiffFieldArray;
+static TIFFFieldArray exifFieldArray;
+
+static TIFFField
+tiffFields[] = {
+	{ TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "SubfileType", NULL },
+	{ TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "OldSubfileType", NULL },
+	{ TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 0, 0, "ImageWidth", NULL },
+	{ TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 1, 0, "ImageLength", NULL },
+	{ TIFFTAG_BITSPERSAMPLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_BITSPERSAMPLE, 0, 0, "BitsPerSample", NULL },
+	{ TIFFTAG_COMPRESSION, -1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_COMPRESSION, 0, 0, "Compression", NULL },
+	{ TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PHOTOMETRIC, 0, 0, "PhotometricInterpretation", NULL },
+	{ TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_THRESHHOLDING, 1, 0, "Threshholding", NULL },
+	{ TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "CellWidth", NULL },
+	{ TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "CellLength", NULL },
+	{ TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_FILLORDER, 0, 0, "FillOrder", NULL },
+	{ TIFFTAG_DOCUMENTNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DocumentName", NULL },
+	{ TIFFTAG_IMAGEDESCRIPTION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageDescription", NULL },
+	{ TIFFTAG_MAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Make", NULL },
+	{ TIFFTAG_MODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Model", NULL },
+	{ TIFFTAG_STRIPOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "StripOffsets", NULL },
+	{ TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_ORIENTATION, 0, 0, "Orientation", NULL },
+	{ TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLESPERPIXEL, 0, 0, "SamplesPerPixel", NULL },
+	{ TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_ROWSPERSTRIP, 0, 0, "RowsPerStrip", NULL },
+	{ TIFFTAG_STRIPBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "StripByteCounts", NULL },
+	{ TIFFTAG_MINSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MINSAMPLEVALUE, 1, 0, "MinSampleValue", NULL },
+	{ TIFFTAG_MAXSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MAXSAMPLEVALUE, 1, 0, "MaxSampleValue", NULL },
+	{ TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "XResolution", NULL },
+	{ TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "YResolution", NULL },
+	{ TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PLANARCONFIG, 0, 0, "PlanarConfiguration", NULL },
+	{ TIFFTAG_PAGENAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PageName", NULL },
+	{ TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "XPosition", NULL },
+	{ TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "YPosition", NULL },
+	{ TIFFTAG_FREEOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeOffsets", NULL },
+	{ TIFFTAG_FREEBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeByteCounts", NULL },
+	{ TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseUnit", NULL },
+	{ TIFFTAG_GRAYRESPONSECURVE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseCurve", NULL },
+	{ TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTIONUNIT, 1, 0, "ResolutionUnit", NULL },
+	{ TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_PAGENUMBER, 1, 0, "PageNumber", NULL },
+	{ TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "ColorResponseUnit", NULL },
+	{ TIFFTAG_TRANSFERFUNCTION, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_TRANSFERFUNCTION, 1, 0, "TransferFunction", NULL },
+	{ TIFFTAG_SOFTWARE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Software", NULL },
+	{ TIFFTAG_DATETIME, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTime", NULL },
+	{ TIFFTAG_ARTIST, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Artist", NULL },
+	{ TIFFTAG_HOSTCOMPUTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "HostComputer", NULL },
+	{ TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WhitePoint", NULL },
+	{ TIFFTAG_PRIMARYCHROMATICITIES, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PrimaryChromaticities", NULL },
+	{ TIFFTAG_COLORMAP, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_COLORMAP, 1, 0, "ColorMap", NULL },
+	{ TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_HALFTONEHINTS, 1, 0, "HalftoneHints", NULL },
+	{ TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDIMENSIONS, 0, 0, "TileWidth", NULL },
+	{ TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDIMENSIONS, 0, 0, "TileLength", NULL },
+	{ TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "TileOffsets", NULL },
+	{ TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "TileByteCounts", NULL },
+	{ TIFFTAG_SUBIFD, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_SUBIFD, 1, 1, "SubIFD", &tiffFieldArray },
+	{ TIFFTAG_INKSET, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InkSet", NULL },
+	{ TIFFTAG_INKNAMES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_C16_ASCII, TIFF_SETGET_UNDEFINED, FIELD_INKNAMES, 1, 1, "InkNames", NULL },
+	{ TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NumberOfInks", NULL },
+	{ TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DotRange", NULL },
+	{ TIFFTAG_TARGETPRINTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TargetPrinter", NULL },
+	{ TIFFTAG_EXTRASAMPLES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 1, "ExtraSamples", NULL },
+	{ TIFFTAG_SAMPLEFORMAT, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "SampleFormat", NULL },
+	{ TIFFTAG_SMINSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMINSAMPLEVALUE, 1, 0, "SMinSampleValue", NULL },
+	{ TIFFTAG_SMAXSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMAXSAMPLEVALUE, 1, 0, "SMaxSampleValue", NULL },
+	{ TIFFTAG_CLIPPATH, -1, -3, TIFF_BYTE, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ClipPath", NULL },
+	{ TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SLONG, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL },
+	{ TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SBYTE, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL },
+	{ TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SLONG, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YClipPathUnits", NULL },
+	{ TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YCbCrCoefficients", NULL },
+	{ TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_YCBCRSUBSAMPLING, 0, 0, "YCbCrSubsampling", NULL },
+	{ TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_YCBCRPOSITIONING, 0, 0, "YCbCrPositioning", NULL },
+	{ TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_REFBLACKWHITE, 1, 0, "ReferenceBlackWhite", NULL },
+	{ TIFFTAG_XMLPACKET, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "XMLPacket", NULL },
+	/* begin SGI tags */
+	{ TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 0, "Matteing", NULL },
+	{ TIFFTAG_DATATYPE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "DataType", NULL },
+	{ TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDEPTH, 0, 0, "ImageDepth", NULL },
+	{ TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDEPTH, 0, 0, "TileDepth", NULL },
+	/* end SGI tags */
+	/* begin Pixar tags */
+	{ TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullWidth", NULL },
+	{ TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullLength", NULL },
+	{ TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureFormat", NULL },
+	{ TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureWrapModes", NULL },
+	{ TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FieldOfViewCotangent", NULL },
+	{ TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen", NULL },
+	{ TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera", NULL },
+	{ TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Copyright", NULL },
+	/* end Pixar tags */
+	{ TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_LONG, 0, TIFF_SETGET_C32_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "RichTIFFIPTC", NULL },
+	{ TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Photoshop", NULL },
+	{ TIFFTAG_EXIFIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "EXIFIFDOffset", &exifFieldArray },
+	{ TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ICC Profile", NULL },
+	{ TIFFTAG_GPSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "GPSIFDOffset", NULL },
+	{ TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvParams", NULL },
+	{ TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxSubAddress", NULL },
+	{ TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvTime", NULL },
+	{ TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxDcs", NULL },
+	{ TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "StoNits", NULL },
+	{ TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InteroperabilityIFDOffset", NULL },
+	/* begin DNG tags */
+	{ TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DNGVersion", NULL },
+	{ TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DNGBackwardVersion", NULL },
+	{ TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "UniqueCameraModel", NULL },
+	{ TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LocalizedCameraModel", NULL },
+	{ TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CFAPlaneColor", NULL },
+	{ TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CFALayout", NULL },
+	{ TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "LinearizationTable", NULL },
+	{ TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BlackLevelRepeatDim", NULL },
+	{ TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevel", NULL },
+	{ TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevelDeltaH", NULL },
+	{ TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevelDeltaV", NULL },
+	{ TIFFTAG_WHITELEVEL, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "WhiteLevel", NULL },
+	{ TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultScale", NULL },
+	{ TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BestQualityScale", NULL },
+	{ TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultCropOrigin", NULL },
+	{ TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultCropSize", NULL },
+	{ TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ColorMatrix1", NULL },
+	{ TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ColorMatrix2", NULL },
+	{ TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CameraCalibration1", NULL },
+	{ TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CameraCalibration2", NULL },
+	{ TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ReductionMatrix1", NULL },
+	{ TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ReductionMatrix2", NULL },
+	{ TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AnalogBalance", NULL },
+	{ TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotNeutral", NULL },
+	{ TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "AsShotWhiteXY", NULL },
+	{ TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineExposure", NULL },
+	{ TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineNoise", NULL },
+	{ TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineSharpness", NULL },
+	{ TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BayerGreenSplit", NULL },
+	{ TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "LinearResponseLimit", NULL },
+	{ TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraSerialNumber", NULL },
+	{ TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "LensInfo", NULL },
+	{ TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ChromaBlurRadius", NULL },
+	{ TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "AntiAliasStrength", NULL },
+	{ TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ShadowScale", NULL },
+	{ TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "DNGPrivateData", NULL },
+	{ TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "MakerNoteSafety", NULL },
+	{ TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CalibrationIlluminant1", NULL },
+	{ TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CalibrationIlluminant2", NULL },
+	{ TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "RawDataUniqueID", NULL },
+	{ TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OriginalRawFileName", NULL },
+	{ TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "OriginalRawFileData", NULL },
+	{ TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ActiveArea", NULL },
+	{ TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "MaskedAreas", NULL },
+	{ TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotICCProfile", NULL },
+	{ TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotPreProfileMatrix", NULL },
+	{ TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentICCProfile", NULL },
+	{ TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentPreProfileMatrix", NULL },
+	{ TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL},
+	/* end DNG tags */
+	/* begin TIFF/FX tags */
+    { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "Indexed" },
+    { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "GlobalParametersIFD", NULL },
+    { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ProfileType", NULL },
+    { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "FaxProfile", NULL },
+    { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CodingMethods", NULL },
+    { TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "VersionYear", NULL },
+    { TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ModeNumber", NULL },
+    { TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Decode", NULL },
+    { TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ImageBaseColor", NULL },
+    { TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "T82Options", NULL },
+    { TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "StripRowCounts", NULL },
+    { TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ImageLayer", NULL },
+	/* end DNG tags */
+	/* begin pseudo tags */
+};
+
+static TIFFField
+exifFields[] = {
+	{ EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureTime", NULL },
+	{ EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FNumber", NULL },
+	{ EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureProgram", NULL },
+	{ EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SpectralSensitivity", NULL },
+	{ EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ISOSpeedRatings", NULL },
+	{ EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OptoelectricConversionFactor", NULL },
+	{ EXIFTAG_EXIFVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExifVersion", NULL },
+	{ EXIFTAG_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTimeOriginal", NULL },
+	{ EXIFTAG_DATETIMEDIGITIZED, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTimeDigitized", NULL },
+	{ EXIFTAG_COMPONENTSCONFIGURATION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ComponentsConfiguration", NULL },
+	{ EXIFTAG_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CompressedBitsPerPixel", NULL },
+	{ EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ShutterSpeedValue", NULL },
+	{ EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ApertureValue", NULL },
+	{ EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL },
+	{ EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL },
+	{ EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL },
+	{ EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL },
+	{ EXIFTAG_METERINGMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MeteringMode", NULL },
+	{ EXIFTAG_LIGHTSOURCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LightSource", NULL },
+	{ EXIFTAG_FLASH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Flash", NULL },
+	{ EXIFTAG_FOCALLENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalLength", NULL },
+	{ EXIFTAG_SUBJECTAREA, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SubjectArea", NULL },
+	{ EXIFTAG_MAKERNOTE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "MakerNote", NULL },
+	{ EXIFTAG_USERCOMMENT, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "UserComment", NULL },
+	{ EXIFTAG_SUBSECTIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTime", NULL },
+	{ EXIFTAG_SUBSECTIMEORIGINAL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTimeOriginal", NULL },
+	{ EXIFTAG_SUBSECTIMEDIGITIZED, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTimeDigitized", NULL },
+	{ EXIFTAG_FLASHPIXVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FlashpixVersion", NULL },
+	{ EXIFTAG_COLORSPACE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorSpace", NULL },
+	{ EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PixelXDimension", NULL },
+	{ EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PixelYDimension", NULL },
+	{ EXIFTAG_RELATEDSOUNDFILE, 13, 13, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RelatedSoundFile", NULL },
+	{ EXIFTAG_FLASHENERGY, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FlashEnergy", NULL },
+	{ EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SpatialFrequencyResponse", NULL },
+	{ EXIFTAG_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneXResolution", NULL },
+	{ EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneYResolution", NULL },
+	{ EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneResolutionUnit", NULL },
+	{ EXIFTAG_SUBJECTLOCATION, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectLocation", NULL },
+	{ EXIFTAG_EXPOSUREINDEX, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureIndex", NULL },
+	{ EXIFTAG_SENSINGMETHOD, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SensingMethod", NULL },
+	{ EXIFTAG_FILESOURCE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FileSource", NULL },
+	{ EXIFTAG_SCENETYPE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SceneType", NULL },
+	{ EXIFTAG_CFAPATTERN, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CFAPattern", NULL },
+	{ EXIFTAG_CUSTOMRENDERED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CustomRendered", NULL },
+	{ EXIFTAG_EXPOSUREMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureMode", NULL },
+	{ EXIFTAG_WHITEBALANCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WhiteBalance", NULL },
+	{ EXIFTAG_DIGITALZOOMRATIO, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DigitalZoomRatio", NULL },
+	{ EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalLengthIn35mmFilm", NULL },
+	{ EXIFTAG_SCENECAPTURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SceneCaptureType", NULL },
+	{ EXIFTAG_GAINCONTROL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "GainControl", NULL },
+	{ EXIFTAG_CONTRAST, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Contrast", NULL },
+	{ EXIFTAG_SATURATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Saturation", NULL },
+	{ EXIFTAG_SHARPNESS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Sharpness", NULL },
+	{ EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "DeviceSettingDescription", NULL },
+	{ EXIFTAG_SUBJECTDISTANCERANGE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistanceRange", NULL },
+	{ EXIFTAG_IMAGEUNIQUEID, 33, 33, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageUniqueID", NULL }
+};
+
+static TIFFFieldArray
+tiffFieldArray = { tfiatImage, 0, TIFFArrayCount(tiffFields), tiffFields };
+static TIFFFieldArray
+exifFieldArray = { tfiatExif, 0, TIFFArrayCount(exifFields), exifFields };
+
+/*
+ *  We have our own local lfind() equivelent to avoid subtle differences
+ *  in types passed to lfind() on different systems. 
+ */
+
+static void *
+td_lfind(const void *key, const void *base, size_t *nmemb, size_t size,
+         int(*compar)(const void *, const void *))
+{
+    char *element, *end;
+
+    end = (char *)base + *nmemb * size;
+    for (element = (char *)base; element < end; element += size)
+        if (!compar(key, element))		/* key found */
+            return element;
+
+    return NULL;
+}
+
+const TIFFFieldArray*
+_TIFFGetFields(void)
+{
+	return(&tiffFieldArray);
+}
+
+const TIFFFieldArray*
+_TIFFGetExifFields(void)
+{
+	return(&exifFieldArray);
+}
+
+void
+_TIFFSetupFields(TIFF* tif, const TIFFFieldArray* fieldarray)
+{
+	if (tif->tif_fields && tif->tif_nfields > 0) {
+		uint32 i;
+
+		for (i = 0; i < tif->tif_nfields; i++) {
+			TIFFField *fld = tif->tif_fields[i];
+			if (fld->field_bit == FIELD_CUSTOM &&
+				strncmp("Tag ", fld->field_name, 4) == 0) {
+					_TIFFfree(fld->field_name);
+					_TIFFfree(fld);
+				}
+		}
+
+		_TIFFfree(tif->tif_fields);
+		tif->tif_fields = NULL;
+		tif->tif_nfields = 0;
+	}
+	if (!_TIFFMergeFields(tif, fieldarray->fields, fieldarray->count)) {
+		TIFFErrorExt(tif->tif_clientdata, "_TIFFSetupFields",
+			     "Setting up field info failed");
+	}
+}
+
+static int
+tagCompare(const void* a, const void* b)
+{
+	const TIFFField* ta = *(const TIFFField**) a;
+	const TIFFField* tb = *(const TIFFField**) b;
+	/* NB: be careful of return values for 16-bit platforms */
+	if (ta->field_tag != tb->field_tag)
+		return (int)ta->field_tag - (int)tb->field_tag;
+	else
+		return (ta->field_type == TIFF_ANY) ?
+			0 : ((int)tb->field_type - (int)ta->field_type);
+}
+
+static int
+tagNameCompare(const void* a, const void* b)
+{
+	const TIFFField* ta = *(const TIFFField**) a;
+	const TIFFField* tb = *(const TIFFField**) b;
+	int ret = strcmp(ta->field_name, tb->field_name);
+
+	if (ret)
+		return ret;
+	else
+		return (ta->field_type == TIFF_ANY) ?
+			0 : ((int)tb->field_type - (int)ta->field_type);
+}
+
+int
+_TIFFMergeFields(TIFF* tif, const TIFFField info[], uint32 n)
+{
+	static const char module[] = "_TIFFMergeFields";
+	static const char reason[] = "for fields array";
+	/* TIFFField** tp; */
+	uint32 i;
+
+        tif->tif_foundfield = NULL;
+
+	if (tif->tif_fields && tif->tif_nfields > 0) {
+		tif->tif_fields = (TIFFField**)
+			_TIFFCheckRealloc(tif, tif->tif_fields,
+					  (tif->tif_nfields + n),
+					  sizeof(TIFFField *), reason);
+	} else {
+		tif->tif_fields = (TIFFField **)
+			_TIFFCheckMalloc(tif, n, sizeof(TIFFField *),
+					 reason);
+	}
+	if (!tif->tif_fields) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Failed to allocate fields array");
+		return 0;
+	}
+
+	/* tp = tif->tif_fields + tif->tif_nfields; */
+	for (i = 0; i < n; i++) {
+		const TIFFField *fip =
+			TIFFFindField(tif, info[i].field_tag, TIFF_ANY);
+
+                /* only add definitions that aren't already present */
+		if (!fip) {
+                        tif->tif_fields[tif->tif_nfields] = (TIFFField *) (info+i);
+                        tif->tif_nfields++;
+                }
+	}
+
+        /* Sort the field info by tag number */
+	qsort(tif->tif_fields, tif->tif_nfields,
+	      sizeof(TIFFField *), tagCompare);
+
+	return n;
+}
+
+void
+_TIFFPrintFieldInfo(TIFF* tif, FILE* fd)
+{
+	uint32 i;
+
+	fprintf(fd, "%s: \n", tif->tif_name);
+	for (i = 0; i < tif->tif_nfields; i++) {
+		const TIFFField* fip = tif->tif_fields[i];
+		fprintf(fd, "field[%2d] %5lu, %2d, %2d, %d, %2d, %5s, %5s, %s\n"
+			, (int)i
+			, (unsigned long) fip->field_tag
+			, fip->field_readcount, fip->field_writecount
+			, fip->field_type
+			, fip->field_bit
+			, fip->field_oktochange ? "TRUE" : "FALSE"
+			, fip->field_passcount ? "TRUE" : "FALSE"
+			, fip->field_name
+		);
+	}
+}
+
+/*
+ * Return size of TIFFDataType in bytes
+ */
+int
+TIFFDataWidth(TIFFDataType type)
+{
+	switch(type)
+	{
+		case 0:  /* nothing */
+		case TIFF_BYTE:
+		case TIFF_ASCII:
+		case TIFF_SBYTE:
+		case TIFF_UNDEFINED:
+			return 1;
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+			return 2;
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_FLOAT:
+		case TIFF_IFD:
+			return 4;
+		case TIFF_RATIONAL:
+		case TIFF_SRATIONAL:
+		case TIFF_DOUBLE:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+		case TIFF_IFD8:
+			return 8;
+		default:
+			return 0; /* will return 0 for unknown types */
+	}
+}
+
+/*
+ * Return size of TIFFDataType in bytes.
+ *
+ * XXX: We need a separate function to determine the space needed
+ * to store the value. For TIFF_RATIONAL values TIFFDataWidth() returns 8,
+ * but we use 4-byte float to represent rationals.
+ */
+int
+_TIFFDataSize(TIFFDataType type)
+{
+	switch (type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_ASCII:
+		case TIFF_UNDEFINED:
+		    return 1;
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		    return 2;
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_FLOAT:
+		case TIFF_IFD:
+		case TIFF_RATIONAL:
+		case TIFF_SRATIONAL:
+		    return 4;
+		case TIFF_DOUBLE:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+		case TIFF_IFD8:
+		    return 8;
+		default:
+		    return 0;
+	}
+}
+
+/* Sync from 3.8.2's modified*/
+#ifdef _WIN32_WCE
+void* wceex_bsearch(const void *key, const void *base, size_t nmemb, size_t size,
+						int (*compar)(const void *, const void *));
+#define bsearch wceex_bsearch
+#endif
+
+const TIFFField*
+TIFFFindField(TIFF* tif, uint32 tag, TIFFDataType dt)
+{
+	TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL};
+	TIFFField* pkey = &key;
+	const TIFFField **ret;
+	if (tif->tif_foundfield && tif->tif_foundfield->field_tag == tag &&
+	    (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type))
+		return tif->tif_foundfield;
+
+	/* If we are invoked with no field information, then just return. */
+	if (!tif->tif_fields)
+		return NULL;
+
+	/* NB: use sorted search (e.g. binary search) */
+
+	key.field_tag = tag;
+	key.field_type = dt;
+
+	ret = (const TIFFField **) bsearch(&pkey, tif->tif_fields,
+					   tif->tif_nfields,
+					   sizeof(TIFFField *), tagCompare);
+	return tif->tif_foundfield = (ret ? *ret : NULL);
+}
+
+const TIFFField*
+_TIFFFindFieldByName(TIFF* tif, const char *field_name, TIFFDataType dt)
+{
+	TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL};
+	TIFFField* pkey = &key;
+	const TIFFField **ret;
+	if (tif->tif_foundfield
+	    && streq(tif->tif_foundfield->field_name, field_name)
+	    && (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type))
+		return (tif->tif_foundfield);
+
+	/* If we are invoked with no field information, then just return. */
+	if (!tif->tif_fields)
+		return NULL;
+
+	/* NB: use linear search since list is sorted by key#, not name */
+
+	key.field_name = (char *)field_name;
+	key.field_type = dt;
+
+#if 1
+	ret = (const TIFFField **) 
+            td_lfind(&pkey, tif->tif_fields, &tif->tif_nfields,
+                     sizeof(TIFFField *), tagNameCompare);
+#else
+	// from old svn version
+	/*ret = (const TIFFFieldInfo **) lfind(&pkey,
+											tif->tif_fieldinfo, 
+											&tif->tif_nfields,
+											sizeof(TIFFFieldInfo *),
+											tagNameCompare);
+	*/
+	/*modify by Sunliang.Liu 20090827 for some platform not support lfind*/
+	ret = NULL;
+#endif
+	return tif->tif_foundfield = (ret ? *ret : NULL);
+}
+
+const TIFFField*
+TIFFFieldWithTag(TIFF* tif, uint32 tag)
+{
+	const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY);
+	if (!fip) {
+		TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithTag",
+			     "Internal error, unknown tag 0x%x",
+			     (unsigned int) tag);
+	}
+	return (fip);
+}
+
+const TIFFField*
+TIFFFieldWithName(TIFF* tif, const char *field_name)
+{
+	const TIFFField* fip =
+		_TIFFFindFieldByName(tif, field_name, TIFF_ANY);
+	if (!fip) {
+		TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithName",
+			     "Internal error, unknown tag %s", field_name);
+	}
+	return (fip);
+}
+
+uint32
+TIFFFieldTag(const TIFFField* fip)
+{
+	return fip->field_tag;
+}
+
+const char *
+TIFFFieldName(const TIFFField* fip)
+{
+	return fip->field_name;
+}
+
+TIFFDataType
+TIFFFieldDataType(const TIFFField* fip)
+{
+	return fip->field_type;
+}
+
+int
+TIFFFieldPassCount(const TIFFField* fip)
+{
+	return fip->field_passcount;
+}
+
+int
+TIFFFieldReadCount(const TIFFField* fip)
+{
+	return fip->field_readcount;
+}
+
+int
+TIFFFieldWriteCount(const TIFFField* fip)
+{
+	return fip->field_writecount;
+}
+
+const TIFFField*
+_TIFFFindOrRegisterField(TIFF *tif, uint32 tag, TIFFDataType dt)
+
+{
+	const TIFFField *fld;
+
+	fld = TIFFFindField(tif, tag, dt);
+	if (fld == NULL) {
+		fld = _TIFFCreateAnonField(tif, tag, dt);
+		if (!_TIFFMergeFields(tif, fld, 1))
+			return NULL;
+	}
+
+	return fld;
+}
+
+TIFFField*
+_TIFFCreateAnonField(TIFF *tif, uint32 tag, TIFFDataType field_type)
+{
+	TIFFField *fld;
+	(void) tif;
+
+	fld = (TIFFField *) _TIFFmalloc(sizeof (TIFFField));
+	if (fld == NULL)
+	    return NULL;
+	_TIFFmemset(fld, 0, sizeof(TIFFField));
+
+	fld->field_tag = tag;
+	fld->field_readcount = TIFF_VARIABLE2;
+	fld->field_writecount = TIFF_VARIABLE2;
+	fld->field_type = field_type;
+	fld->reserved = 0;
+	switch (field_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_UNDEFINED:
+			fld->set_field_type = TIFF_SETGET_C32_UINT8;
+			fld->get_field_type = TIFF_SETGET_C32_UINT8;
+			break;
+		case TIFF_ASCII:
+			fld->set_field_type = TIFF_SETGET_C32_ASCII;
+			fld->get_field_type = TIFF_SETGET_C32_ASCII;
+			break;
+		case TIFF_SHORT:
+			fld->set_field_type = TIFF_SETGET_C32_UINT16;
+			fld->get_field_type = TIFF_SETGET_C32_UINT16;
+			break;
+		case TIFF_LONG:
+			fld->set_field_type = TIFF_SETGET_C32_UINT32;
+			fld->get_field_type = TIFF_SETGET_C32_UINT32;
+			break;
+		case TIFF_RATIONAL:
+		case TIFF_SRATIONAL:
+		case TIFF_FLOAT:
+			fld->set_field_type = TIFF_SETGET_C32_FLOAT;
+			fld->get_field_type = TIFF_SETGET_C32_FLOAT;
+			break;
+		case TIFF_SBYTE:
+			fld->set_field_type = TIFF_SETGET_C32_SINT8;
+			fld->get_field_type = TIFF_SETGET_C32_SINT8;
+			break;
+		case TIFF_SSHORT:
+			fld->set_field_type = TIFF_SETGET_C32_SINT16;
+			fld->get_field_type = TIFF_SETGET_C32_SINT16;
+			break;
+		case TIFF_SLONG:
+			fld->set_field_type = TIFF_SETGET_C32_SINT32;
+			fld->get_field_type = TIFF_SETGET_C32_SINT32;
+			break;
+		case TIFF_DOUBLE:
+			fld->set_field_type = TIFF_SETGET_C32_DOUBLE;
+			fld->get_field_type = TIFF_SETGET_C32_DOUBLE;
+			break;
+		case TIFF_IFD:
+		case TIFF_IFD8:
+			fld->set_field_type = TIFF_SETGET_C32_IFD8;
+			fld->get_field_type = TIFF_SETGET_C32_IFD8;
+			break;
+		case TIFF_LONG8:
+			fld->set_field_type = TIFF_SETGET_C32_UINT64;
+			fld->get_field_type = TIFF_SETGET_C32_UINT64;
+			break;
+		case TIFF_SLONG8:
+			fld->set_field_type = TIFF_SETGET_C32_SINT64;
+			fld->get_field_type = TIFF_SETGET_C32_SINT64;
+			break;
+		default:
+			fld->set_field_type = TIFF_SETGET_UNDEFINED;
+			fld->get_field_type = TIFF_SETGET_UNDEFINED;
+			break;
+	}
+	fld->field_bit = FIELD_CUSTOM;
+	fld->field_oktochange = TRUE;
+	fld->field_passcount = TRUE;
+	fld->field_name = (char *) _TIFFmalloc(32);
+	if (fld->field_name == NULL) {
+	    _TIFFfree(fld);
+	    return NULL;
+	}
+	fld->field_subfields = NULL;
+
+	/* 
+	 * note that this name is a special sign to TIFFClose() and
+	 * _TIFFSetupFields() to free the field
+	 */
+	sprintf(fld->field_name, "Tag %d", (int) tag);
+
+	return fld;    
+}
+
+/****************************************************************************
+ *               O B S O L E T E D    I N T E R F A C E S
+ *
+ * Don't use this stuff in your applications, it may be removed in the future
+ * libtiff versions.
+ ****************************************************************************/
+
+static TIFFSetGetFieldType
+_TIFFSetGetType(TIFFDataType type, short count, unsigned char passcount)
+{
+	if (type == TIFF_ASCII && count == TIFF_VARIABLE && passcount == 0)
+		return TIFF_SETGET_ASCII;
+
+	else if (count == 1 && passcount == 0) {
+		switch (type)
+		{
+			case TIFF_BYTE:
+			case TIFF_UNDEFINED:
+				return TIFF_SETGET_UINT8;
+			case TIFF_ASCII:
+				return TIFF_SETGET_ASCII;
+			case TIFF_SHORT:
+				return TIFF_SETGET_UINT16;
+			case TIFF_LONG:
+				return TIFF_SETGET_UINT32;
+			case TIFF_RATIONAL:
+			case TIFF_SRATIONAL:
+			case TIFF_FLOAT:
+				return TIFF_SETGET_FLOAT;
+			case TIFF_SBYTE:
+				return TIFF_SETGET_SINT8;
+			case TIFF_SSHORT:
+				return TIFF_SETGET_SINT16;
+			case TIFF_SLONG:
+				return TIFF_SETGET_SINT32;
+			case TIFF_DOUBLE:
+				return TIFF_SETGET_DOUBLE;
+			case TIFF_IFD:
+			case TIFF_IFD8:
+				return TIFF_SETGET_IFD8;
+			case TIFF_LONG8:
+				return TIFF_SETGET_UINT64;
+			case TIFF_SLONG8:
+				return TIFF_SETGET_SINT64;
+			default:
+				return TIFF_SETGET_UNDEFINED;
+		}
+	}
+
+	else if (count >= 1 && passcount == 0) {
+		switch (type)
+		{
+			case TIFF_BYTE:
+			case TIFF_UNDEFINED:
+				return TIFF_SETGET_C0_UINT8;
+			case TIFF_ASCII:
+				return TIFF_SETGET_C0_ASCII;
+			case TIFF_SHORT:
+				return TIFF_SETGET_C0_UINT16;
+			case TIFF_LONG:
+				return TIFF_SETGET_C0_UINT32;
+			case TIFF_RATIONAL:
+			case TIFF_SRATIONAL:
+			case TIFF_FLOAT:
+				return TIFF_SETGET_C0_FLOAT;
+			case TIFF_SBYTE:
+				return TIFF_SETGET_C0_SINT8;
+			case TIFF_SSHORT:
+				return TIFF_SETGET_C0_SINT16;
+			case TIFF_SLONG:
+				return TIFF_SETGET_C0_SINT32;
+			case TIFF_DOUBLE:
+				return TIFF_SETGET_C0_DOUBLE;
+			case TIFF_IFD:
+			case TIFF_IFD8:
+				return TIFF_SETGET_C0_IFD8;
+			case TIFF_LONG8:
+				return TIFF_SETGET_C0_UINT64;
+			case TIFF_SLONG8:
+				return TIFF_SETGET_C0_SINT64;
+			default:
+				return TIFF_SETGET_UNDEFINED;
+		}
+	}
+
+	else if (count == TIFF_VARIABLE && passcount == 1) {
+		switch (type)
+		{
+			case TIFF_BYTE:
+			case TIFF_UNDEFINED:
+				return TIFF_SETGET_C16_UINT8;
+			case TIFF_ASCII:
+				return TIFF_SETGET_C16_ASCII;
+			case TIFF_SHORT:
+				return TIFF_SETGET_C16_UINT16;
+			case TIFF_LONG:
+				return TIFF_SETGET_C16_UINT32;
+			case TIFF_RATIONAL:
+			case TIFF_SRATIONAL:
+			case TIFF_FLOAT:
+				return TIFF_SETGET_C16_FLOAT;
+			case TIFF_SBYTE:
+				return TIFF_SETGET_C16_SINT8;
+			case TIFF_SSHORT:
+				return TIFF_SETGET_C16_SINT16;
+			case TIFF_SLONG:
+				return TIFF_SETGET_C16_SINT32;
+			case TIFF_DOUBLE:
+				return TIFF_SETGET_C16_DOUBLE;
+			case TIFF_IFD:
+			case TIFF_IFD8:
+				return TIFF_SETGET_C16_IFD8;
+			case TIFF_LONG8:
+				return TIFF_SETGET_C16_UINT64;
+			case TIFF_SLONG8:
+				return TIFF_SETGET_C16_SINT64;
+			default:
+				return TIFF_SETGET_UNDEFINED;
+		}
+	}
+
+	else if (count == TIFF_VARIABLE2 && passcount == 1) {
+		switch (type)
+		{
+			case TIFF_BYTE:
+			case TIFF_UNDEFINED:
+				return TIFF_SETGET_C32_UINT8;
+			case TIFF_ASCII:
+				return TIFF_SETGET_C32_ASCII;
+			case TIFF_SHORT:
+				return TIFF_SETGET_C32_UINT16;
+			case TIFF_LONG:
+				return TIFF_SETGET_C32_UINT32;
+			case TIFF_RATIONAL:
+			case TIFF_SRATIONAL:
+			case TIFF_FLOAT:
+				return TIFF_SETGET_C32_FLOAT;
+			case TIFF_SBYTE:
+				return TIFF_SETGET_C32_SINT8;
+			case TIFF_SSHORT:
+				return TIFF_SETGET_C32_SINT16;
+			case TIFF_SLONG:
+				return TIFF_SETGET_C32_SINT32;
+			case TIFF_DOUBLE:
+				return TIFF_SETGET_C32_DOUBLE;
+			case TIFF_IFD:
+			case TIFF_IFD8:
+				return TIFF_SETGET_C32_IFD8;
+			case TIFF_LONG8:
+				return TIFF_SETGET_C32_UINT64;
+			case TIFF_SLONG8:
+				return TIFF_SETGET_C32_SINT64;
+			default:
+				return TIFF_SETGET_UNDEFINED;
+		}
+	}
+
+	return TIFF_SETGET_UNDEFINED;
+}
+
+int
+TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], uint32 n)
+{
+	static const char module[] = "TIFFMergeFieldInfo";
+	static const char reason[] = "for fields array";
+	TIFFField *tp;
+	size_t nfields;
+	uint32 i;
+
+	if (tif->tif_nfieldscompat > 0) {
+		tif->tif_fieldscompat = (TIFFFieldArray *)
+			_TIFFCheckRealloc(tif, tif->tif_fieldscompat,
+					  tif->tif_nfieldscompat + 1,
+					  sizeof(TIFFFieldArray), reason);
+	} else {
+		tif->tif_fieldscompat = (TIFFFieldArray *)
+			_TIFFCheckMalloc(tif, 1, sizeof(TIFFFieldArray),
+					 reason);
+	}
+	if (!tif->tif_fieldscompat) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Failed to allocate fields array");
+		return -1;
+	}
+	nfields = tif->tif_nfieldscompat++;
+
+	tif->tif_fieldscompat[nfields].type = tfiatOther;
+	tif->tif_fieldscompat[nfields].allocated_size = n;
+	tif->tif_fieldscompat[nfields].count = n;
+	tif->tif_fieldscompat[nfields].fields =
+		(TIFFField *)_TIFFCheckMalloc(tif, n, sizeof(TIFFField),
+					      reason);
+	if (!tif->tif_fieldscompat[nfields].fields) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Failed to allocate fields array");
+		return -1;
+	}
+
+	tp = tif->tif_fieldscompat[nfields].fields;
+	for (i = 0; i < n; i++) {
+		tp->field_tag = info[i].field_tag;
+		tp->field_readcount = info[i].field_readcount;
+		tp->field_writecount = info[i].field_writecount;
+		tp->field_type = info[i].field_type;
+		tp->reserved = 0;
+		tp->set_field_type =
+		     _TIFFSetGetType(info[i].field_type,
+				info[i].field_readcount,
+				info[i].field_passcount);
+		tp->get_field_type =
+		     _TIFFSetGetType(info[i].field_type,
+				info[i].field_readcount,
+				info[i].field_passcount);
+		tp->field_bit = info[i].field_bit;
+		tp->field_oktochange = info[i].field_oktochange;
+		tp->field_passcount = info[i].field_passcount;
+		tp->field_name = info[i].field_name;
+		tp->field_subfields = NULL;
+		tp++;
+	}
+
+	if (!_TIFFMergeFields(tif, tif->tif_fieldscompat[nfields].fields, n)) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Setting up field info failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirread.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirread.c
new file mode 100644
index 0000000..bd28d69
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirread.c
@@ -0,0 +1,5616 @@
+/* $Id: tif_dirread.c,v 1.178 2012-08-19 16:56:34 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Read Support Routines.
+ */
+
+/* Suggested pending improvements:
+ * - add a field 'ignore' to the TIFFDirEntry structure, to flag status,
+ *   eliminating current use of the IGNORE value, and therefore eliminating
+ *   current irrational behaviour on tags with tag id code 0
+ * - add a field 'field_info' to the TIFFDirEntry structure, and set that with
+ *   the pointer to the appropriate TIFFField structure early on in
+ *   TIFFReadDirectory, so as to eliminate current possibly repetitive lookup.
+ */
+ 
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+#define IGNORE 0          /* tag placeholder used below */
+#define FAILED_FII    ((uint32) -1)
+
+#ifdef HAVE_IEEEFP
+# define TIFFCvtIEEEFloatToNative(tif, n, fp)
+# define TIFFCvtIEEEDoubleToNative(tif, n, dp)
+#else
+extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*);
+extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*);
+#endif
+
+enum TIFFReadDirEntryErr {
+	TIFFReadDirEntryErrOk = 0,
+	TIFFReadDirEntryErrCount = 1,
+	TIFFReadDirEntryErrType = 2,
+	TIFFReadDirEntryErrIo = 3,
+	TIFFReadDirEntryErrRange = 4,
+	TIFFReadDirEntryErrPsdif = 5,
+	TIFFReadDirEntryErrSizesan = 6,
+	TIFFReadDirEntryErrAlloc = 7,
+};
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64* value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
+#if 0
+static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
+#endif
+
+static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value);
+static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value);
+static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
+static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value);
+static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value);
+static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value);
+static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF* tif, uint64 offset, tmsize_t size, void* dest);
+static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover);
+
+static void TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16 dircount);
+static TIFFDirEntry* TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16 dircount, uint16 tagid);
+static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16 tagid, uint32* fii);
+
+static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount);
+static void MissingRequired(TIFF*, const char*);
+static int TIFFCheckDirOffset(TIFF* tif, uint64 diroff);
+static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32);
+static uint16 TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir, uint64* nextdiroff);
+static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover);
+static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp);
+static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*);
+static void ChopUpSingleUncompressedStrip(TIFF*);
+static uint64 TIFFReadUInt64(const uint8 *value);
+
+typedef union _UInt64Aligned_t
+{
+        double d;
+	uint64 l;
+	uint32 i[2];
+	uint16 s[4];
+	uint8  c[8];
+} UInt64Aligned_t;
+
+/*
+  Unaligned safe copy of a uint64 value from an octet array.
+*/
+static uint64 TIFFReadUInt64(const uint8 *value)
+{
+	UInt64Aligned_t result;
+
+	result.c[0]=value[0];
+	result.c[1]=value[1];
+	result.c[2]=value[2];
+	result.c[3]=value[3];
+	result.c[4]=value[4];
+	result.c[5]=value[5];
+	result.c[6]=value[6];
+	result.c[7]=value[7];
+
+	return result.l;
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			TIFFReadDirEntryCheckedByte(tif,direntry,value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteSbyte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteShort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteSshort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteLong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteSlong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 m;
+				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeByteLong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeByteSlong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeShortSbyte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			TIFFReadDirEntryCheckedShort(tif,direntry,value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeShortSshort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeShortLong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeShortSlong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 m;
+				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeShortLong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeShortSlong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLongSbyte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLongSshort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			TIFFReadDirEntryCheckedLong(tif,direntry,value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLongSlong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 m;
+				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeLongLong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeLongSlong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLong8Sbyte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLong8Sshort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLong8Slong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			err=TIFFReadDirEntryCheckedLong8(tif,direntry,value);
+			return(err);
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeLong8Slong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 m;
+				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+#if defined(__WIN32__) && (_MSC_VER < 1500)
+				/*
+				 * XXX: MSVC 6.0 does not support conversion
+				 * of 64-bit integers into floating point
+				 * values.
+				 */
+				*value = _TIFFUInt64ToFloat(m);
+#else
+				*value=(float)m;
+#endif
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_RATIONAL:
+			{
+				double m;
+				err=TIFFReadDirEntryCheckedRational(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SRATIONAL:
+			{
+				double m;
+				err=TIFFReadDirEntryCheckedSrational(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_FLOAT:
+			TIFFReadDirEntryCheckedFloat(tif,direntry,value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_DOUBLE:
+			{
+				double m;
+				err=TIFFReadDirEntryCheckedDouble(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 m;
+				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+#if defined(__WIN32__) && (_MSC_VER < 1500)
+				/*
+				 * XXX: MSVC 6.0 does not support conversion
+				 * of 64-bit integers into floating point
+				 * values.
+				 */
+				*value = _TIFFUInt64ToDouble(m);
+#else
+				*value = (double)m;
+#endif
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_RATIONAL:
+			err=TIFFReadDirEntryCheckedRational(tif,direntry,value);
+			return(err);
+		case TIFF_SRATIONAL:
+			err=TIFFReadDirEntryCheckedSrational(tif,direntry,value);
+			return(err);
+		case TIFF_FLOAT:
+			{
+				float m;
+				TIFFReadDirEntryCheckedFloat(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_DOUBLE:
+			err=TIFFReadDirEntryCheckedDouble(tif,direntry,value);
+			return(err);
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG:
+		case TIFF_IFD:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+		case TIFF_IFD8:
+			err=TIFFReadDirEntryCheckedLong8(tif,direntry,value);
+			return(err);
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value)
+{
+	int typesize;
+	uint32 datasize;
+	void* data;
+	typesize=TIFFDataWidth(direntry->tdir_type);
+	if ((direntry->tdir_count==0)||(typesize==0))
+	{
+		*value=0;
+		return(TIFFReadDirEntryErrOk);
+	}
+        (void) desttypesize;
+
+        /* 
+         * As a sanity check, make sure we have no more than a 2GB tag array 
+         * in either the current data type or the dest data type.  This also
+         * avoids problems with overflow of tmsize_t on 32bit systems.
+         */
+	if ((uint64)(2147483647/typesize)<direntry->tdir_count)
+		return(TIFFReadDirEntryErrSizesan);
+	if ((uint64)(2147483647/desttypesize)<direntry->tdir_count)
+		return(TIFFReadDirEntryErrSizesan);
+
+	*count=(uint32)direntry->tdir_count;
+	datasize=(*count)*typesize;
+	assert((tmsize_t)datasize>0);
+	data=_TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray");
+	if (data==0)
+		return(TIFFReadDirEntryErrAlloc);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		if (datasize<=4)
+			_TIFFmemcpy(data,&direntry->tdir_offset,datasize);
+		else
+		{
+			enum TIFFReadDirEntryErr err;
+			uint32 offset = direntry->tdir_offset.toff_long;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong(&offset);
+			err=TIFFReadDirEntryData(tif,(uint64)offset,(tmsize_t)datasize,data);
+			if (err!=TIFFReadDirEntryErrOk)
+			{
+				_TIFFfree(data);
+				return(err);
+			}
+		}
+	}
+	else
+	{
+		if (datasize<=8)
+			_TIFFmemcpy(data,&direntry->tdir_offset,datasize);
+		else
+		{
+			enum TIFFReadDirEntryErr err;
+			uint64 offset = direntry->tdir_offset.toff_long8;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8(&offset);
+			err=TIFFReadDirEntryData(tif,offset,(tmsize_t)datasize,data);
+			if (err!=TIFFReadDirEntryErrOk)
+			{
+				_TIFFfree(data);
+				return(err);
+			}
+		}
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint8* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_ASCII:
+		case TIFF_UNDEFINED:
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,1,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_ASCII:
+		case TIFF_UNDEFINED:
+		case TIFF_BYTE:
+			*value=(uint8*)origdata;
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SBYTE:
+			{
+				int8* m;
+				uint32 n;
+				m=(int8*)origdata;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeByteSbyte(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(uint8*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+	}
+	data=(uint8*)_TIFFmalloc(count);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					err=TIFFReadDirEntryCheckRangeByteShort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					err=TIFFReadDirEntryCheckRangeByteSshort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					err=TIFFReadDirEntryCheckRangeByteLong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeByteSlong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(uint64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(ma);
+					err=TIFFReadDirEntryCheckRangeByteLong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeByteSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	int8* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_UNDEFINED:
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,1,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_UNDEFINED:
+		case TIFF_BYTE:
+			{
+				uint8* m;
+				uint32 n;
+				m=(uint8*)origdata;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeSbyteByte(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(int8*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			*value=(int8*)origdata;
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(int8*)_TIFFmalloc(count);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				int8* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					err=TIFFReadDirEntryCheckRangeSbyteShort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				int8* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					err=TIFFReadDirEntryCheckRangeSbyteSshort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				int8* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					err=TIFFReadDirEntryCheckRangeSbyteLong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				int8* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeSbyteSlong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				int8* mb;
+				uint32 n;
+				ma=(uint64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(ma);
+					err=TIFFReadDirEntryCheckRangeSbyteLong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				int8* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeSbyteSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint16* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,2,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_SHORT:
+			*value=(uint16*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfShort(*value,count);  
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SSHORT:
+			{
+				int16* m;
+				uint32 n;
+				m=(int16*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)m);
+					err=TIFFReadDirEntryCheckRangeShortSshort(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(uint16*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+	}
+	data=(uint16*)_TIFFmalloc(count*2);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(uint16)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeShortSbyte(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					err=TIFFReadDirEntryCheckRangeShortLong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeShortSlong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(uint64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(ma);
+					err=TIFFReadDirEntryCheckRangeShortLong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeShortSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint16)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	int16* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,2,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_SHORT:
+			{
+				uint16* m;
+				uint32 n;
+				m=(uint16*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(m);
+					err=TIFFReadDirEntryCheckRangeSshortShort(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(int16*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			*value=(int16*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfShort((uint16*)(*value),count);
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(int16*)_TIFFmalloc(count*2);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				int16* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int16)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				int16* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int16)(*ma++);
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				int16* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					err=TIFFReadDirEntryCheckRangeSshortLong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				int16* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeSshortSlong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				int16* mb;
+				uint32 n;
+				ma=(uint64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(ma);
+					err=TIFFReadDirEntryCheckRangeSshortLong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				int16* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeSshortSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int16)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint32* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG:
+			*value=(uint32*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong(*value,count);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SLONG:
+			{
+				int32* m;
+				uint32 n;
+				m=(int32*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)m);
+					err=TIFFReadDirEntryCheckRangeLongSlong(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(uint32*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+	}
+	data=(uint32*)_TIFFmalloc(count*4);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(uint32)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeLongSbyte(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					err=TIFFReadDirEntryCheckRangeLongSshort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(uint64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(ma);
+					err=TIFFReadDirEntryCheckRangeLongLong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeLongSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	int32* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG:
+			{
+				uint32* m;
+				uint32 n;
+				m=(uint32*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)m);
+					err=TIFFReadDirEntryCheckRangeSlongLong(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(int32*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			*value=(int32*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong((uint32*)(*value),count);
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(int32*)_TIFFmalloc(count*4);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				int32* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int32)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				int32* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int32)(*ma++);
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				int32* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(int32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				int32* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					*mb++=(int32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				int32* mb;
+				uint32 n;
+				ma=(uint64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(ma);
+					err=TIFFReadDirEntryCheckRangeSlongLong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				int32* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeSlongSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int32)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint64* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG8:
+			*value=(uint64*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong8(*value,count);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SLONG8:
+			{
+				int64* m;
+				uint32 n;
+				m=(int64*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)m);
+					err=TIFFReadDirEntryCheckRangeLong8Slong8(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(uint64*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+	}
+	data=(uint64*)_TIFFmalloc(count*8);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(uint64)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeLong8Sbyte(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					err=TIFFReadDirEntryCheckRangeLong8Sshort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeLong8Slong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	int64* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG8:
+			{
+				uint64* m;
+				uint32 n;
+				m=(uint64*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(m);
+					err=TIFFReadDirEntryCheckRangeSlong8Long8(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(int64*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			*value=(int64*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong8((uint64*)(*value),count);
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(int64*)_TIFFmalloc(count*8);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				int64* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int64)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				int64* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int64)(*ma++);
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				int64* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(int64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				int64* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					*mb++=(int64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				int64* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					*mb++=(int64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				int64* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					*mb++=(int64)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	float* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+		case TIFF_RATIONAL:
+		case TIFF_SRATIONAL:
+		case TIFF_FLOAT:
+		case TIFF_DOUBLE:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_FLOAT:
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong((uint32*)origdata,count);  
+			TIFFCvtIEEEDoubleToNative(tif,count,(float*)origdata);
+			*value=(float*)origdata;
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(float*)_TIFFmalloc(count*sizeof(float));
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				float* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(float)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				float* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(float)(*ma++);
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				float* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(float)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				float* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					*mb++=(float)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				float* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					*mb++=(float)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				float* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					*mb++=(float)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				float* mb;
+				uint32 n;
+				ma=(uint64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(ma);
+#if defined(__WIN32__) && (_MSC_VER < 1500)
+					/*
+					 * XXX: MSVC 6.0 does not support
+					 * conversion of 64-bit integers into
+					 * floating point values.
+					 */
+					*mb++ = _TIFFUInt64ToFloat(*ma++);
+#else
+					*mb++ = (float)(*ma++);
+#endif
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				float* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					*mb++=(float)(*ma++);
+				}
+			}
+			break;
+		case TIFF_RATIONAL:
+			{
+				uint32* ma;
+				uint32 maa;
+				uint32 mab;
+				float* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					maa=*ma++;
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					mab=*ma++;
+					if (mab==0)
+						*mb++=0.0;
+					else
+						*mb++=(float)maa/(float)mab;
+				}
+			}
+			break;
+		case TIFF_SRATIONAL:
+			{
+				uint32* ma;
+				int32 maa;
+				uint32 mab;
+				float* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					maa=*(int32*)ma;
+					ma++;
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					mab=*ma++;
+					if (mab==0)
+						*mb++=0.0;
+					else
+						*mb++=(float)maa/(float)mab;
+				}
+			}
+			break;
+		case TIFF_DOUBLE:
+			{
+				double* ma;
+				float* mb;
+				uint32 n;
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabArrayOfLong8((uint64*)origdata,count);
+				TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata);
+				ma=(double*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(float)(*ma++);
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	double* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+		case TIFF_RATIONAL:
+		case TIFF_SRATIONAL:
+		case TIFF_FLOAT:
+		case TIFF_DOUBLE:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_DOUBLE:
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong8((uint64*)origdata,count);
+			TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata);
+			*value=(double*)origdata;
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(double*)_TIFFmalloc(count*sizeof(double));
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				double* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(double)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				double* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(double)(*ma++);
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				double* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(double)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				double* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					*mb++=(double)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				double* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					*mb++=(double)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				double* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					*mb++=(double)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				double* mb;
+				uint32 n;
+				ma=(uint64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(ma);
+#if defined(__WIN32__) && (_MSC_VER < 1500)
+					/*
+					 * XXX: MSVC 6.0 does not support
+					 * conversion of 64-bit integers into
+					 * floating point values.
+					 */
+					*mb++ = _TIFFUInt64ToDouble(*ma++);
+#else
+					*mb++ = (double)(*ma++);
+#endif
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				double* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					*mb++=(double)(*ma++);
+				}
+			}
+			break;
+		case TIFF_RATIONAL:
+			{
+				uint32* ma;
+				uint32 maa;
+				uint32 mab;
+				double* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					maa=*ma++;
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					mab=*ma++;
+					if (mab==0)
+						*mb++=0.0;
+					else
+						*mb++=(double)maa/(double)mab;
+				}
+			}
+			break;
+		case TIFF_SRATIONAL:
+			{
+				uint32* ma;
+				int32 maa;
+				uint32 mab;
+				double* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					maa=*(int32*)ma;
+					ma++;
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					mab=*ma++;
+					if (mab==0)
+						*mb++=0.0;
+					else
+						*mb++=(double)maa/(double)mab;
+				}
+			}
+			break;
+		case TIFF_FLOAT:
+			{
+				float* ma;
+				double* mb;
+				uint32 n;
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabArrayOfLong((uint32*)origdata,count);  
+				TIFFCvtIEEEFloatToNative(tif,count,(float*)origdata);
+				ma=(float*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(double)(*ma++);
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint64* data;
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG:
+		case TIFF_LONG8:
+		case TIFF_IFD:
+		case TIFF_IFD8:
+			break;
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+	err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata);
+	if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
+	{
+		*value=0;
+		return(err);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG8:
+		case TIFF_IFD8:
+			*value=(uint64*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong8(*value,count);
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(uint64*)_TIFFmalloc(count*8);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG:
+		case TIFF_IFD:
+			{
+				uint32* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint16* m;
+	uint16* na;
+	uint16 nb;
+	if (direntry->tdir_count<(uint64)tif->tif_dir.td_samplesperpixel)
+		return(TIFFReadDirEntryErrCount);
+	err=TIFFReadDirEntryShortArray(tif,direntry,&m);
+	if (err!=TIFFReadDirEntryErrOk)
+		return(err);
+	na=m;
+	nb=tif->tif_dir.td_samplesperpixel;
+	*value=*na++;
+	nb--;
+	while (nb>0)
+	{
+		if (*na++!=*value)
+		{
+			err=TIFFReadDirEntryErrPsdif;
+			break;
+		}
+		nb--;
+	}
+	_TIFFfree(m);
+	return(err);
+}
+
+#if 0
+static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	enum TIFFReadDirEntryErr err;
+	double* m;
+	double* na;
+	uint16 nb;
+	if (direntry->tdir_count<(uint64)tif->tif_dir.td_samplesperpixel)
+		return(TIFFReadDirEntryErrCount);
+	err=TIFFReadDirEntryDoubleArray(tif,direntry,&m);
+	if (err!=TIFFReadDirEntryErrOk)
+		return(err);
+	na=m;
+	nb=tif->tif_dir.td_samplesperpixel;
+	*value=*na++;
+	nb--;
+	while (nb>0)
+	{
+		if (*na++!=*value)
+		{
+			err=TIFFReadDirEntryErrPsdif;
+			break;
+		}
+		nb--;
+	}
+	_TIFFfree(m);
+	return(err);
+}
+#endif
+
+static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value)
+{
+	(void) tif;
+	*value=*(uint8*)(&direntry->tdir_offset);
+}
+
+static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value)
+{
+	(void) tif;
+	*value=*(int8*)(&direntry->tdir_offset);
+}
+
+static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
+{
+	*value = direntry->tdir_offset.toff_short;
+	/* *value=*(uint16*)(&direntry->tdir_offset); */
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabShort(value);
+}
+
+static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value)
+{
+	*value=*(int16*)(&direntry->tdir_offset);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabShort((uint16*)value);
+}
+
+static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value)
+{
+	*value=*(uint32*)(&direntry->tdir_offset);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong(value);
+}
+
+static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value)
+{
+	*value=*(int32*)(&direntry->tdir_offset);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong((uint32*)value);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value)
+{
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 offset = direntry->tdir_offset.toff_long;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong(&offset);
+		err=TIFFReadDirEntryData(tif,offset,8,value);
+		if (err!=TIFFReadDirEntryErrOk)
+			return(err);
+	}
+	else
+		*value = direntry->tdir_offset.toff_long8;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong8(value);
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64* value)
+{
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 offset = direntry->tdir_offset.toff_long;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong(&offset);
+		err=TIFFReadDirEntryData(tif,offset,8,value);
+		if (err!=TIFFReadDirEntryErrOk)
+			return(err);
+	}
+	else
+		*value=*(int64*)(&direntry->tdir_offset);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong8((uint64*)value);
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	UInt64Aligned_t m;
+
+	assert(sizeof(double)==8);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(uint32)==4);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 offset = direntry->tdir_offset.toff_long;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong(&offset);
+		err=TIFFReadDirEntryData(tif,offset,8,m.i);
+		if (err!=TIFFReadDirEntryErrOk)
+			return(err);
+	}
+	else
+		m.l = direntry->tdir_offset.toff_long8;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong(m.i,2);
+	if (m.i[0]==0)
+		*value=0.0;
+	else
+		*value=(double)m.i[0]/(double)m.i[1];
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	UInt64Aligned_t m;
+	assert(sizeof(double)==8);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(int32)==4);
+	assert(sizeof(uint32)==4);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 offset = direntry->tdir_offset.toff_long;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong(&offset);
+		err=TIFFReadDirEntryData(tif,offset,8,m.i);
+		if (err!=TIFFReadDirEntryErrOk)
+			return(err);
+	}
+	else
+		m.l=direntry->tdir_offset.toff_long8;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong(m.i,2);
+	if ((int32)m.i[0]==0)
+		*value=0.0;
+	else
+		*value=(double)((int32)m.i[0])/(double)m.i[1];
+	return(TIFFReadDirEntryErrOk);
+}
+
+static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value)
+{
+         union
+	 {
+	   float  f;
+	   uint32 i;
+	 } float_union;
+	assert(sizeof(float)==4);
+	assert(sizeof(uint32)==4);
+	assert(sizeof(float_union)==4);
+	float_union.i=*(uint32*)(&direntry->tdir_offset);
+	*value=float_union.f;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong((uint32*)value);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	assert(sizeof(double)==8);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(UInt64Aligned_t)==8);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 offset = direntry->tdir_offset.toff_long;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong(&offset);
+		err=TIFFReadDirEntryData(tif,offset,8,value);
+		if (err!=TIFFReadDirEntryErrOk)
+			return(err);
+	}
+	else
+	{
+	       UInt64Aligned_t uint64_union;
+	       uint64_union.l=direntry->tdir_offset.toff_long8;
+	       *value=uint64_union.d;
+	}
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong8((uint64*)value);
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value)
+{
+	if (value>0xFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value)
+{
+	if ((value<0)||(value>0xFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value)
+{
+	if (value>0xFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value)
+{
+	if ((value<0)||(value>0xFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value)
+{
+	if (value>0xFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value)
+{
+	if ((value<0)||(value>0xFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value)
+{
+	if (value>0x7F)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value)
+{
+	if (value>0x7F)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value)
+{
+	if ((value<-0x80)||(value>0x7F))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value)
+{
+	if (value>0x7F)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value)
+{
+	if ((value<-0x80)||(value>0x7F))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value)
+{
+	if (value>0x7F)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value)
+{
+	if ((value<-0x80)||(value>0x7F))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value)
+{
+	if (value>0xFFFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value)
+{
+	if ((value<0)||(value>0xFFFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value)
+{
+	if (value>0xFFFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value)
+{
+	if ((value<0)||(value>0xFFFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value)
+{
+	if (value>0x7FFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value)
+{
+	if (value>0x7FFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value)
+{
+	if ((value<-0x8000)||(value>0x7FFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value)
+{
+	if (value>0x7FFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value)
+{
+	if ((value<-0x8000)||(value>0x7FFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+/*
+ * Largest 32-bit unsigned integer value.
+ */
+#if defined(__WIN32__) && defined(_MSC_VER)
+# define TIFF_UINT32_MAX 0xFFFFFFFFI64
+#else
+# define TIFF_UINT32_MAX 0xFFFFFFFFLL
+#endif
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLongLong8(uint64 value)
+{
+	if (value > TIFF_UINT32_MAX)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLongSlong8(int64 value)
+{
+	if ((value<0) || (value > TIFF_UINT32_MAX))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+#undef TIFF_UINT32_MAX
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeSlongLong(uint32 value)
+{
+	if (value > 0x7FFFFFFFUL)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeSlongLong8(uint64 value)
+{
+	if (value > 0x7FFFFFFFUL)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeSlongSlong8(int64 value)
+{
+	if ((value < 0L-0x80000000L) || (value > 0x7FFFFFFFL))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value)
+{
+	if (value < 0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLong8Sshort(int16 value)
+{
+	if (value < 0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLong8Slong(int32 value)
+{
+	if (value < 0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLong8Slong8(int64 value)
+{
+	if (value < 0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+/*
+ * Largest 64-bit signed integer value.
+ */
+#if defined(__WIN32__) && defined(_MSC_VER)
+# define TIFF_INT64_MAX 0x7FFFFFFFFFFFFFFFI64
+#else
+# define TIFF_INT64_MAX 0x7FFFFFFFFFFFFFFFLL
+#endif
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value)
+{
+	if (value > TIFF_INT64_MAX)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+#undef TIFF_INT64_MAX
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryData(TIFF* tif, uint64 offset, tmsize_t size, void* dest)
+{
+	assert(size>0);
+	if (!isMapped(tif)) {
+		if (!SeekOK(tif,offset))
+			return(TIFFReadDirEntryErrIo);
+		if (!ReadOK(tif,dest,size))
+			return(TIFFReadDirEntryErrIo);
+	} else {
+		size_t ma,mb;
+		ma=(size_t)offset;
+		mb=ma+size;
+		if (((uint64)ma!=offset)
+		    || (mb < ma)
+		    || (mb - ma != (size_t) size)
+		    || (mb < (size_t)size)
+		    || (mb > (size_t)tif->tif_size)
+		    )
+			return(TIFFReadDirEntryErrIo);
+		_TIFFmemcpy(dest,tif->tif_base+ma,size);
+	}
+	return(TIFFReadDirEntryErrOk);
+}
+
+static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover)
+{
+	if (!recover) {
+		switch (err) {
+			case TIFFReadDirEntryErrCount:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Incorrect count for \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrType:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Incompatible type for \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrIo:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "IO error during reading of \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrRange:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Incorrect value for \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrPsdif:
+				TIFFErrorExt(tif->tif_clientdata, module,
+			"Cannot handle different values per sample for \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrSizesan:
+				TIFFErrorExt(tif->tif_clientdata, module,
+				"Sanity check on size of \"%s\" value failed",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrAlloc:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Out of memory reading of \"%s\"",
+					     tagname);
+				break;
+			default:
+				assert(0);   /* we should never get here */
+				break;
+		}
+	} else {
+		switch (err) {
+			case TIFFReadDirEntryErrCount:
+				TIFFErrorExt(tif->tif_clientdata, module,
+				"Incorrect count for \"%s\"; tag ignored",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrType:
+				TIFFWarningExt(tif->tif_clientdata, module,
+				"Incompatible type for \"%s\"; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrIo:
+				TIFFWarningExt(tif->tif_clientdata, module,
+			"IO error during reading of \"%s\"; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrRange:
+				TIFFWarningExt(tif->tif_clientdata, module,
+				"Incorrect value for \"%s\"; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrPsdif:
+				TIFFWarningExt(tif->tif_clientdata, module,
+	"Cannot handle different values per sample for \"%s\"; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrSizesan:
+				TIFFWarningExt(tif->tif_clientdata, module,
+		"Sanity check on size of \"%s\" value failed; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrAlloc:
+				TIFFWarningExt(tif->tif_clientdata, module,
+				"Out of memory reading of \"%s\"; tag ignored",
+					       tagname);
+				break;
+			default:
+				assert(0);   /* we should never get here */
+				break;
+		}
+	}
+}
+
+/*
+ * Read the next TIFF directory from a file and convert it to the internal
+ * format. We read directories sequentially.
+ */
+int
+TIFFReadDirectory(TIFF* tif)
+{
+	static const char module[] = "TIFFReadDirectory";
+	TIFFDirEntry* dir;
+	uint16 dircount;
+	TIFFDirEntry* dp;
+	uint16 di;
+	const TIFFField* fip;
+	uint32 fii=FAILED_FII;
+        toff_t nextdiroff;
+	tif->tif_diroff=tif->tif_nextdiroff;
+	if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff))
+		return 0;           /* last offset or bad offset (IFD looping) */
+	(*tif->tif_cleanup)(tif);   /* cleanup any previous compression state */
+	tif->tif_curdir++;
+        nextdiroff = tif->tif_nextdiroff;
+	dircount=TIFFFetchDirectory(tif,nextdiroff,&dir,&tif->tif_nextdiroff);
+	if (!dircount)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,
+		    "Failed to read directory at offset " TIFF_UINT64_FORMAT,nextdiroff);
+		return 0;
+	}
+	TIFFReadDirectoryCheckOrder(tif,dir,dircount);
+
+        /*
+         * Mark duplicates of any tag to be ignored (bugzilla 1994)
+         * to avoid certain pathological problems.
+         */
+	{
+		TIFFDirEntry* ma;
+		uint16 mb;
+		for (ma=dir, mb=0; mb<dircount; ma++, mb++)
+		{
+			TIFFDirEntry* na;
+			uint16 nb;
+			for (na=ma+1, nb=mb+1; nb<dircount; na++, nb++)
+			{
+				if (ma->tdir_tag==na->tdir_tag)
+					na->tdir_tag=IGNORE;
+			}
+		}
+	}
+        
+	tif->tif_flags &= ~TIFF_BEENWRITING;    /* reset before new dir */
+	tif->tif_flags &= ~TIFF_BUF4WRITE;      /* reset before new dir */
+	/* free any old stuff and reinit */
+	TIFFFreeDirectory(tif);
+	TIFFDefaultDirectory(tif);
+	/*
+	 * Electronic Arts writes gray-scale TIFF files
+	 * without a PlanarConfiguration directory entry.
+	 * Thus we setup a default value here, even though
+	 * the TIFF spec says there is no default value.
+	 */
+	TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
+	/*
+	 * Setup default value and then make a pass over
+	 * the fields to check type and tag information,
+	 * and to extract info required to size data
+	 * structures.  A second pass is made afterwards
+	 * to read in everthing not taken in the first pass.
+	 * But we must process the Compression tag first
+	 * in order to merge in codec-private tag definitions (otherwise
+	 * we may get complaints about unknown tags).  However, the
+	 * Compression tag may be dependent on the SamplesPerPixel
+	 * tag value because older TIFF specs permited Compression
+	 * to be written as a SamplesPerPixel-count tag entry.
+	 * Thus if we don't first figure out the correct SamplesPerPixel
+	 * tag value then we may end up ignoring the Compression tag
+	 * value because it has an incorrect count value (if the
+	 * true value of SamplesPerPixel is not 1).
+	 */
+	dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_SAMPLESPERPIXEL);
+	if (dp)
+	{
+		if (!TIFFFetchNormalTag(tif,dp,0))
+			goto bad;
+		dp->tdir_tag=IGNORE;
+	}
+	dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_COMPRESSION);
+	if (dp)
+	{
+		/*
+		 * The 5.0 spec says the Compression tag has one value, while
+		 * earlier specs say it has one value per sample.  Because of
+		 * this, we accept the tag if one value is supplied with either
+		 * count.
+		 */
+		uint16 value;
+		enum TIFFReadDirEntryErr err;
+		err=TIFFReadDirEntryShort(tif,dp,&value);
+		if (err==TIFFReadDirEntryErrCount)
+			err=TIFFReadDirEntryPersampleShort(tif,dp,&value);
+		if (err!=TIFFReadDirEntryErrOk)
+		{
+			TIFFReadDirEntryOutputErr(tif,err,module,"Compression",0);
+			goto bad;
+		}
+		if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,value))
+			goto bad;
+		dp->tdir_tag=IGNORE;
+	}
+	else
+	{
+		if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,COMPRESSION_NONE))
+			goto bad;
+	}
+	/*
+	 * First real pass over the directory.
+	 */
+	for (di=0, dp=dir; di<dircount; di++, dp++)
+	{
+		if (dp->tdir_tag!=IGNORE)
+		{
+			TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+			if (fii == FAILED_FII)
+			{
+				TIFFWarningExt(tif->tif_clientdata, module,
+				    "Unknown field with tag %d (0x%x) encountered",
+				    dp->tdir_tag,dp->tdir_tag);
+                                /* the following knowingly leaks the 
+                                   anonymous field structure */
+				if (!_TIFFMergeFields(tif,
+					_TIFFCreateAnonField(tif,
+						dp->tdir_tag,
+						(TIFFDataType) dp->tdir_type),
+					1)) {
+					TIFFWarningExt(tif->tif_clientdata,
+					    module,
+					    "Registering anonymous field with tag %d (0x%x) failed",
+					    dp->tdir_tag,
+					    dp->tdir_tag);
+					dp->tdir_tag=IGNORE;
+				} else {
+					TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+					assert(fii != FAILED_FII);
+				}
+			}
+		}
+		if (dp->tdir_tag!=IGNORE)
+		{
+			fip=tif->tif_fields[fii];
+			if (fip->field_bit==FIELD_IGNORE)
+				dp->tdir_tag=IGNORE;
+			else
+			{
+				switch (dp->tdir_tag)
+				{
+					case TIFFTAG_STRIPOFFSETS:
+					case TIFFTAG_STRIPBYTECOUNTS:
+					case TIFFTAG_TILEOFFSETS:
+					case TIFFTAG_TILEBYTECOUNTS:
+						TIFFSetFieldBit(tif,fip->field_bit);
+						break;
+					case TIFFTAG_IMAGEWIDTH:
+					case TIFFTAG_IMAGELENGTH:
+					case TIFFTAG_IMAGEDEPTH:
+					case TIFFTAG_TILELENGTH:
+					case TIFFTAG_TILEWIDTH:
+					case TIFFTAG_TILEDEPTH:
+					case TIFFTAG_PLANARCONFIG:
+					case TIFFTAG_ROWSPERSTRIP:
+					case TIFFTAG_EXTRASAMPLES:
+						if (!TIFFFetchNormalTag(tif,dp,0))
+							goto bad;
+						dp->tdir_tag=IGNORE;
+						break;
+				}
+			}
+		}
+	}
+	/*
+	 * XXX: OJPEG hack.
+	 * If a) compression is OJPEG, b) planarconfig tag says it's separate,
+	 * c) strip offsets/bytecounts tag are both present and
+	 * d) both contain exactly one value, then we consistently find
+	 * that the buggy implementation of the buggy compression scheme
+	 * matches contig planarconfig best. So we 'fix-up' the tag here
+	 */
+	if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG)&&
+	    (tif->tif_dir.td_planarconfig==PLANARCONFIG_SEPARATE))
+	{
+        if (!_TIFFFillStriles(tif))
+            goto bad;
+		dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_STRIPOFFSETS);
+		if ((dp!=0)&&(dp->tdir_count==1))
+		{
+			dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,
+			    TIFFTAG_STRIPBYTECOUNTS);
+			if ((dp!=0)&&(dp->tdir_count==1))
+			{
+				tif->tif_dir.td_planarconfig=PLANARCONFIG_CONTIG;
+				TIFFWarningExt(tif->tif_clientdata,module,
+				    "Planarconfig tag value assumed incorrect, "
+				    "assuming data is contig instead of chunky");
+			}
+		}
+	}
+	/*
+	 * Allocate directory structure and setup defaults.
+	 */
+	if (!TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS))
+	{
+		MissingRequired(tif,"ImageLength");
+		goto bad;
+	}
+	/*
+	 * Setup appropriate structures (by strip or by tile)
+	 */
+	if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
+		tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);  
+		tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
+		tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
+		tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
+		tif->tif_flags &= ~TIFF_ISTILED;
+	} else {
+		tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
+		tif->tif_flags |= TIFF_ISTILED;
+	}
+	if (!tif->tif_dir.td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Cannot handle zero number of %s",
+		    isTiled(tif) ? "tiles" : "strips");
+		goto bad;
+	}
+	tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
+	if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
+		tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
+	if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
+		if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) &&
+		    (isTiled(tif)==0) &&
+		    (tif->tif_dir.td_nstrips==1)) {
+			/*
+			 * XXX: OJPEG hack.
+			 * If a) compression is OJPEG, b) it's not a tiled TIFF,
+			 * and c) the number of strips is 1,
+			 * then we tolerate the absence of stripoffsets tag,
+			 * because, presumably, all required data is in the
+			 * JpegInterchangeFormat stream.
+			 */
+			TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
+		} else {
+			MissingRequired(tif,
+				isTiled(tif) ? "TileOffsets" : "StripOffsets");
+			goto bad;
+		}
+	}
+	/*
+	 * Second pass: extract other information.
+	 */
+	for (di=0, dp=dir; di<dircount; di++, dp++)
+	{
+		switch (dp->tdir_tag)
+		{
+			case IGNORE:
+				break;
+			case TIFFTAG_MINSAMPLEVALUE:
+			case TIFFTAG_MAXSAMPLEVALUE:
+			case TIFFTAG_BITSPERSAMPLE:
+			case TIFFTAG_DATATYPE:
+			case TIFFTAG_SAMPLEFORMAT:
+				/*
+				 * The MinSampleValue, MaxSampleValue, BitsPerSample
+				 * DataType and SampleFormat tags are supposed to be
+				 * written as one value/sample, but some vendors
+				 * incorrectly write one value only -- so we accept
+				 * that as well (yech). Other vendors write correct
+				 * value for NumberOfSamples, but incorrect one for
+				 * BitsPerSample and friends, and we will read this
+				 * too.
+				 */
+				{
+					uint16 value;
+					enum TIFFReadDirEntryErr err;
+					err=TIFFReadDirEntryShort(tif,dp,&value);
+					if (err==TIFFReadDirEntryErrCount)
+						err=TIFFReadDirEntryPersampleShort(tif,dp,&value);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+						TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
+						goto bad;
+					}
+					if (!TIFFSetField(tif,dp->tdir_tag,value))
+						goto bad;
+				}
+				break;
+			case TIFFTAG_SMINSAMPLEVALUE:
+			case TIFFTAG_SMAXSAMPLEVALUE:
+				{
+
+					double *data;
+					enum TIFFReadDirEntryErr err;
+					uint32 saved_flags;
+					int m;
+					if (dp->tdir_count != (uint64)tif->tif_dir.td_samplesperpixel)
+						err = TIFFReadDirEntryErrCount;
+					else
+						err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+						TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
+						goto bad;
+					}
+					saved_flags = tif->tif_flags;
+					tif->tif_flags |= TIFF_PERSAMPLE;
+					m = TIFFSetField(tif,dp->tdir_tag,data);
+					tif->tif_flags = saved_flags;
+					_TIFFfree(data);
+					if (!m)
+						goto bad;
+				}
+				break;
+			case TIFFTAG_STRIPOFFSETS:
+			case TIFFTAG_TILEOFFSETS:
+#if defined(DEFER_STRILE_LOAD)
+                                _TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry),
+                                             dp, sizeof(TIFFDirEntry) );
+#else                          
+				if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripoffset))  
+					goto bad;
+#endif                                
+				break;
+			case TIFFTAG_STRIPBYTECOUNTS:
+			case TIFFTAG_TILEBYTECOUNTS:
+#if defined(DEFER_STRILE_LOAD)
+                                _TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry),
+                                             dp, sizeof(TIFFDirEntry) );
+#else                          
+				if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripbytecount))  
+					goto bad;
+#endif                                
+				break;
+			case TIFFTAG_COLORMAP:
+			case TIFFTAG_TRANSFERFUNCTION:
+				{
+					enum TIFFReadDirEntryErr err;
+					uint32 countpersample;
+					uint32 countrequired;
+					uint32 incrementpersample;
+					uint16* value=NULL;
+					countpersample=(1L<<tif->tif_dir.td_bitspersample);
+					if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample))
+					{
+						countrequired=countpersample;
+						incrementpersample=0;
+					}
+					else
+					{
+						countrequired=3*countpersample;
+						incrementpersample=countpersample;
+					}
+					if (dp->tdir_count!=(uint64)countrequired)
+						err=TIFFReadDirEntryErrCount;
+					else
+						err=TIFFReadDirEntryShortArray(tif,dp,&value);
+					if (err!=TIFFReadDirEntryErrOk)
+                    {
+						fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+						TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",1);
+                    }
+					else
+					{
+						TIFFSetField(tif,dp->tdir_tag,value,value+incrementpersample,value+2*incrementpersample);
+						_TIFFfree(value);
+					}
+				}
+				break;
+/* BEGIN REV 4.0 COMPATIBILITY */
+			case TIFFTAG_OSUBFILETYPE:
+				{
+					uint16 valueo;
+					uint32 value;
+					if (TIFFReadDirEntryShort(tif,dp,&valueo)==TIFFReadDirEntryErrOk)
+					{
+						switch (valueo)
+						{
+							case OFILETYPE_REDUCEDIMAGE: value=FILETYPE_REDUCEDIMAGE; break;
+							case OFILETYPE_PAGE: value=FILETYPE_PAGE; break;
+							default: value=0; break;
+						}
+						if (value!=0)
+							TIFFSetField(tif,TIFFTAG_SUBFILETYPE,value);
+					}
+				}
+				break;
+/* END REV 4.0 COMPATIBILITY */
+			default:
+				(void) TIFFFetchNormalTag(tif, dp, TRUE);
+				break;
+		}
+	}
+	/*
+	 * OJPEG hack:
+	 * - If a) compression is OJPEG, and b) photometric tag is missing,
+	 * then we consistently find that photometric should be YCbCr
+	 * - If a) compression is OJPEG, and b) photometric tag says it's RGB,
+	 * then we consistently find that the buggy implementation of the
+	 * buggy compression scheme matches photometric YCbCr instead.
+	 * - If a) compression is OJPEG, and b) bitspersample tag is missing,
+	 * then we consistently find bitspersample should be 8.
+	 * - If a) compression is OJPEG, b) samplesperpixel tag is missing,
+	 * and c) photometric is RGB or YCbCr, then we consistently find
+	 * samplesperpixel should be 3
+	 * - If a) compression is OJPEG, b) samplesperpixel tag is missing,
+	 * and c) photometric is MINISWHITE or MINISBLACK, then we consistently
+	 * find samplesperpixel should be 3
+	 */
+	if (tif->tif_dir.td_compression==COMPRESSION_OJPEG)
+	{
+		if (!TIFFFieldSet(tif,FIELD_PHOTOMETRIC))
+		{
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Photometric tag is missing, assuming data is YCbCr");
+			if (!TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_YCBCR))
+				goto bad;
+		}
+		else if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB)
+		{
+			tif->tif_dir.td_photometric=PHOTOMETRIC_YCBCR;
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Photometric tag value assumed incorrect, "
+			    "assuming data is YCbCr instead of RGB");
+		}
+		if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
+		{
+			TIFFWarningExt(tif->tif_clientdata,module,
+			    "BitsPerSample tag is missing, assuming 8 bits per sample");
+			if (!TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8))
+				goto bad;
+		}
+		if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
+		{
+			if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB)
+			{
+				TIFFWarningExt(tif->tif_clientdata,module,
+				    "SamplesPerPixel tag is missing, "
+				    "assuming correct SamplesPerPixel value is 3");
+				if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3))
+					goto bad;
+			}
+			if (tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR)
+			{
+				TIFFWarningExt(tif->tif_clientdata,module,
+				    "SamplesPerPixel tag is missing, "
+				    "applying correct SamplesPerPixel value of 3");
+				if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3))
+					goto bad;
+			}
+			else if ((tif->tif_dir.td_photometric==PHOTOMETRIC_MINISWHITE)
+				 || (tif->tif_dir.td_photometric==PHOTOMETRIC_MINISBLACK))
+			{
+				/*
+				 * SamplesPerPixel tag is missing, but is not required
+				 * by spec.  Assume correct SamplesPerPixel value of 1.
+				 */
+				if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1))
+					goto bad;
+			}
+		}
+	}
+	/*
+	 * Verify Palette image has a Colormap.
+	 */
+	if (tif->tif_dir.td_photometric == PHOTOMETRIC_PALETTE &&
+	    !TIFFFieldSet(tif, FIELD_COLORMAP)) {
+		if ( tif->tif_dir.td_bitspersample>=8 && tif->tif_dir.td_samplesperpixel==3)
+			tif->tif_dir.td_photometric = PHOTOMETRIC_RGB;
+		else if (tif->tif_dir.td_bitspersample>=8)
+			tif->tif_dir.td_photometric = PHOTOMETRIC_MINISBLACK;
+		else {
+			MissingRequired(tif, "Colormap");
+			goto bad;
+		}
+	}
+	/*
+	 * OJPEG hack:
+	 * We do no further messing with strip/tile offsets/bytecounts in OJPEG
+	 * TIFFs
+	 */
+	if (tif->tif_dir.td_compression!=COMPRESSION_OJPEG)
+	{
+		/*
+		 * Attempt to deal with a missing StripByteCounts tag.
+		 */
+		if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) {
+			/*
+			 * Some manufacturers violate the spec by not giving
+			 * the size of the strips.  In this case, assume there
+			 * is one uncompressed strip of data.
+			 */
+			if ((tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG &&
+			    tif->tif_dir.td_nstrips > 1) ||
+			    (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE &&
+			     tif->tif_dir.td_nstrips != (uint32)tif->tif_dir.td_samplesperpixel)) {
+			    MissingRequired(tif, "StripByteCounts");
+			    goto bad;
+			}
+			TIFFWarningExt(tif->tif_clientdata, module,
+				"TIFF directory is missing required "
+				"\"StripByteCounts\" field, calculating from imagelength");
+			if (EstimateStripByteCounts(tif, dir, dircount) < 0)
+			    goto bad;
+		/*
+		 * Assume we have wrong StripByteCount value (in case
+		 * of single strip) in following cases:
+		 *   - it is equal to zero along with StripOffset;
+		 *   - it is larger than file itself (in case of uncompressed
+		 *     image);
+		 *   - it is smaller than the size of the bytes per row
+		 *     multiplied on the number of rows.  The last case should
+		 *     not be checked in the case of writing new image,
+		 *     because we may do not know the exact strip size
+		 *     until the whole image will be written and directory
+		 *     dumped out.
+		 */
+		#define	BYTECOUNTLOOKSBAD \
+		    ( (tif->tif_dir.td_stripbytecount[0] == 0 && tif->tif_dir.td_stripoffset[0] != 0) || \
+		      (tif->tif_dir.td_compression == COMPRESSION_NONE && \
+		       tif->tif_dir.td_stripbytecount[0] > TIFFGetFileSize(tif) - tif->tif_dir.td_stripoffset[0]) || \
+		      (tif->tif_mode == O_RDONLY && \
+		       tif->tif_dir.td_compression == COMPRESSION_NONE && \
+		       tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) )
+
+		} else if (tif->tif_dir.td_nstrips == 1
+                           && _TIFFFillStriles(tif)
+			   && tif->tif_dir.td_stripoffset[0] != 0
+			   && BYTECOUNTLOOKSBAD) {
+			/*
+			 * XXX: Plexus (and others) sometimes give a value of
+			 * zero for a tag when they don't know what the
+			 * correct value is!  Try and handle the simple case
+			 * of estimating the size of a one strip image.
+			 */
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Bogus \"StripByteCounts\" field, ignoring and calculating from imagelength");
+			if(EstimateStripByteCounts(tif, dir, dircount) < 0)
+			    goto bad;
+
+#if !defined(DEFER_STRILE_LOAD)
+		} else if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG
+			   && tif->tif_dir.td_nstrips > 2
+			   && tif->tif_dir.td_compression == COMPRESSION_NONE
+			   && tif->tif_dir.td_stripbytecount[0] != tif->tif_dir.td_stripbytecount[1]
+			   && tif->tif_dir.td_stripbytecount[0] != 0
+			   && tif->tif_dir.td_stripbytecount[1] != 0 ) {
+			/*
+			 * XXX: Some vendors fill StripByteCount array with
+			 * absolutely wrong values (it can be equal to
+			 * StripOffset array, for example). Catch this case
+			 * here.
+                         *
+                         * We avoid this check if deferring strile loading
+                         * as it would always force us to load the strip/tile
+                         * information.
+			 */
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Wrong \"StripByteCounts\" field, ignoring and calculating from imagelength");
+			if (EstimateStripByteCounts(tif, dir, dircount) < 0)
+			    goto bad;
+#endif /* !defined(DEFER_STRILE_LOAD) */                        
+		}
+	}
+	if (dir)
+	{
+		_TIFFfree(dir);
+		dir=NULL;
+	}
+	if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE))
+	{
+		if (tif->tif_dir.td_bitspersample>=16)
+			tif->tif_dir.td_maxsamplevalue=0xFFFF;
+		else
+			tif->tif_dir.td_maxsamplevalue = (uint16)((1L<<tif->tif_dir.td_bitspersample)-1);
+	}
+	/*
+	 * XXX: We can optimize checking for the strip bounds using the sorted
+	 * bytecounts array. See also comments for TIFFAppendToStrip()
+	 * function in tif_write.c.
+	 */
+#if !defined(DEFER_STRILE_LOAD)        
+	if (tif->tif_dir.td_nstrips > 1) {
+		uint32 strip;
+
+		tif->tif_dir.td_stripbytecountsorted = 1;
+		for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
+			if (tif->tif_dir.td_stripoffset[strip - 1] >
+			    tif->tif_dir.td_stripoffset[strip]) {
+				tif->tif_dir.td_stripbytecountsorted = 0;
+				break;
+			}
+		}
+	}
+#endif /* !defined(DEFER_STRILE_LOAD) */
+        
+	/*
+	 * An opportunity for compression mode dependent tag fixup
+	 */
+	(*tif->tif_fixuptags)(tif);
+
+	/*
+	 * Some manufacturers make life difficult by writing
+	 * large amounts of uncompressed data as a single strip.
+	 * This is contrary to the recommendations of the spec.
+	 * The following makes an attempt at breaking such images
+	 * into strips closer to the recommended 8k bytes.  A
+	 * side effect, however, is that the RowsPerStrip tag
+	 * value may be changed.
+	 */
+	if ((tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&&
+	    (tif->tif_dir.td_nstrips==1)&&
+	    (tif->tif_dir.td_compression==COMPRESSION_NONE)&&  
+	    ((tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED))==TIFF_STRIPCHOP))
+    {
+        if ( !_TIFFFillStriles(tif) || !tif->tif_dir.td_stripbytecount )
+            return 0;
+		ChopUpSingleUncompressedStrip(tif);
+    }
+
+        /*
+         * Clear the dirty directory flag. 
+         */
+	tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+	tif->tif_flags &= ~TIFF_DIRTYSTRIP;
+
+	/*
+	 * Reinitialize i/o since we are starting on a new directory.
+	 */
+	tif->tif_row = (uint32) -1;
+	tif->tif_curstrip = (uint32) -1;
+	tif->tif_col = (uint32) -1;
+	tif->tif_curtile = (uint32) -1;
+	tif->tif_tilesize = (tmsize_t) -1;
+
+	tif->tif_scanlinesize = TIFFScanlineSize(tif);
+	if (!tif->tif_scanlinesize) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Cannot handle zero scanline size");
+		return (0);
+	}
+
+	if (isTiled(tif)) {
+		tif->tif_tilesize = TIFFTileSize(tif);
+		if (!tif->tif_tilesize) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			     "Cannot handle zero tile size");
+			return (0);
+		}
+	} else {
+		if (!TIFFStripSize(tif)) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Cannot handle zero strip size");
+			return (0);
+		}
+	}
+	return (1);
+bad:
+	if (dir)
+		_TIFFfree(dir);
+	return (0);
+}
+
+static void
+TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
+{
+	static const char module[] = "TIFFReadDirectoryCheckOrder";
+	uint16 m;
+	uint16 n;
+	TIFFDirEntry* o;
+	m=0;
+	for (n=0, o=dir; n<dircount; n++, o++)
+	{
+		if (o->tdir_tag<m)
+		{
+			TIFFWarningExt(tif->tif_clientdata,module,
+			    "Invalid TIFF directory; tags are not sorted in ascending order");
+			break;
+		}
+		m=o->tdir_tag+1;
+	}
+}
+
+static TIFFDirEntry*
+TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16 dircount, uint16 tagid)
+{
+	TIFFDirEntry* m;
+	uint16 n;
+	(void) tif;
+	for (m=dir, n=0; n<dircount; m++, n++)
+	{
+		if (m->tdir_tag==tagid)
+			return(m);
+	}
+	return(0);
+}
+
+static void
+TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16 tagid, uint32* fii)
+{
+	int32 ma,mb,mc;
+	ma=-1;
+	mc=(int32)tif->tif_nfields;
+	while (1)
+	{
+		if (ma+1==mc)
+		{
+			*fii = FAILED_FII;
+			return;
+		}
+		mb=(ma+mc)/2;
+		if (tif->tif_fields[mb]->field_tag==(uint32)tagid)
+			break;
+		if (tif->tif_fields[mb]->field_tag<(uint32)tagid)
+			ma=mb;
+		else
+			mc=mb;
+	}
+	while (1)
+	{
+		if (mb==0)
+			break;
+		if (tif->tif_fields[mb-1]->field_tag!=(uint32)tagid)
+			break;
+		mb--;
+	}
+	*fii=mb;
+}
+
+/*
+ * Read custom directory from the arbitarry offset.
+ * The code is very similar to TIFFReadDirectory().
+ */
+int
+TIFFReadCustomDirectory(TIFF* tif, toff_t diroff,
+			const TIFFFieldArray* infoarray)
+{
+	static const char module[] = "TIFFReadCustomDirectory";
+	TIFFDirEntry* dir;
+	uint16 dircount;
+	TIFFDirEntry* dp;
+	uint16 di;
+	const TIFFField* fip;
+	uint32 fii;
+	_TIFFSetupFields(tif, infoarray);
+	dircount=TIFFFetchDirectory(tif,diroff,&dir,NULL);
+	if (!dircount)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,
+		    "Failed to read custom directory at offset " TIFF_UINT64_FORMAT,diroff);
+		return 0;
+	}
+	TIFFFreeDirectory(tif);
+	_TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory));
+	TIFFReadDirectoryCheckOrder(tif,dir,dircount);
+	for (di=0, dp=dir; di<dircount; di++, dp++)
+	{
+		TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+		if (fii == FAILED_FII)
+		{
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Unknown field with tag %d (0x%x) encountered",
+			    dp->tdir_tag, dp->tdir_tag);
+			if (!_TIFFMergeFields(tif, _TIFFCreateAnonField(tif,
+						dp->tdir_tag,
+						(TIFFDataType) dp->tdir_type),
+					     1)) {
+				TIFFWarningExt(tif->tif_clientdata, module,
+				    "Registering anonymous field with tag %d (0x%x) failed",
+				    dp->tdir_tag, dp->tdir_tag);
+				dp->tdir_tag=IGNORE;
+			} else {
+				TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+				assert( fii != FAILED_FII );
+			}
+		}
+		if (dp->tdir_tag!=IGNORE)
+		{
+			fip=tif->tif_fields[fii];
+			if (fip->field_bit==FIELD_IGNORE)
+				dp->tdir_tag=IGNORE;
+			else
+			{
+				/* check data type */
+				while ((fip->field_type!=TIFF_ANY)&&(fip->field_type!=dp->tdir_type))
+				{
+					fii++;
+					if ((fii==tif->tif_nfields)||
+					    (tif->tif_fields[fii]->field_tag!=(uint32)dp->tdir_tag))
+					{
+						fii=0xFFFF;
+						break;
+					}
+					fip=tif->tif_fields[fii];
+				}
+				if (fii==0xFFFF)
+				{
+					TIFFWarningExt(tif->tif_clientdata, module,
+					    "Wrong data type %d for \"%s\"; tag ignored",
+					    dp->tdir_type,fip->field_name);
+					dp->tdir_tag=IGNORE;
+				}
+				else
+				{
+					/* check count if known in advance */
+					if ((fip->field_readcount!=TIFF_VARIABLE)&&
+					    (fip->field_readcount!=TIFF_VARIABLE2))
+					{
+						uint32 expected;
+						if (fip->field_readcount==TIFF_SPP)
+							expected=(uint32)tif->tif_dir.td_samplesperpixel;
+						else
+							expected=(uint32)fip->field_readcount;
+						if (!CheckDirCount(tif,dp,expected))
+							dp->tdir_tag=IGNORE;
+					}
+				}
+			}
+			switch (dp->tdir_tag)
+			{
+				case IGNORE:
+					break;
+				case EXIFTAG_SUBJECTDISTANCE:
+					(void) TIFFFetchSubjectDistance(tif,dp);
+					break;
+				default:
+					(void) TIFFFetchNormalTag(tif, dp, TRUE);
+					break;
+			}
+		}
+	}
+	if (dir)
+		_TIFFfree(dir);
+	return 1;
+}
+
+/*
+ * EXIF is important special case of custom IFD, so we have a special
+ * function to read it.
+ */
+int
+TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff)
+{
+	const TIFFFieldArray* exifFieldArray;
+	exifFieldArray = _TIFFGetExifFields();
+	return TIFFReadCustomDirectory(tif, diroff, exifFieldArray);  
+}
+
+static int
+EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
+{
+	static const char module[] = "EstimateStripByteCounts";
+
+	TIFFDirEntry *dp;
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 strip;
+
+    _TIFFFillStriles( tif );
+
+	if (td->td_stripbytecount)
+		_TIFFfree(td->td_stripbytecount);
+	td->td_stripbytecount = (uint64*)
+	    _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64),
+		"for \"StripByteCounts\" array");
+        if( td->td_stripbytecount == NULL )
+            return -1;
+
+	if (td->td_compression != COMPRESSION_NONE) {
+		uint64 space;
+		uint64 filesize;
+		uint16 n;
+		filesize = TIFFGetFileSize(tif);
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+			space=sizeof(TIFFHeaderClassic)+2+dircount*12+4;
+		else
+			space=sizeof(TIFFHeaderBig)+8+dircount*20+8;
+		/* calculate amount of space used by indirect values */
+		for (dp = dir, n = dircount; n > 0; n--, dp++)
+		{
+			uint32 typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type);
+			uint64 datasize;
+			typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type);
+			if (typewidth == 0) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Cannot determine size of unknown tag type %d",
+				    dp->tdir_type);
+				return -1;
+			}
+			datasize=(uint64)typewidth*dp->tdir_count;
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+			{
+				if (datasize<=4)
+					datasize=0;
+			}
+			else
+			{
+				if (datasize<=8)
+					datasize=0;
+			}
+			space+=datasize;
+		}
+		space = filesize - space;
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+			space /= td->td_samplesperpixel;
+		for (strip = 0; strip < td->td_nstrips; strip++)
+			td->td_stripbytecount[strip] = space;
+		/*
+		 * This gross hack handles the case were the offset to
+		 * the last strip is past the place where we think the strip
+		 * should begin.  Since a strip of data must be contiguous,
+		 * it's safe to assume that we've overestimated the amount
+		 * of data in the strip and trim this number back accordingly.
+		 */
+		strip--;
+		if (td->td_stripoffset[strip]+td->td_stripbytecount[strip] > filesize)
+			td->td_stripbytecount[strip] = filesize - td->td_stripoffset[strip];
+	} else if (isTiled(tif)) {
+		uint64 bytespertile = TIFFTileSize64(tif);
+
+		for (strip = 0; strip < td->td_nstrips; strip++)
+		    td->td_stripbytecount[strip] = bytespertile;
+	} else {
+		uint64 rowbytes = TIFFScanlineSize64(tif);
+		uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage;
+		for (strip = 0; strip < td->td_nstrips; strip++)
+			td->td_stripbytecount[strip] = rowbytes * rowsperstrip;
+	}
+	TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
+	if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
+		td->td_rowsperstrip = td->td_imagelength;
+	return 1;
+}
+
+static void
+MissingRequired(TIFF* tif, const char* tagname)
+{
+	static const char module[] = "MissingRequired";
+
+	TIFFErrorExt(tif->tif_clientdata, module,
+	    "TIFF directory is missing required \"%s\" field",
+	    tagname);
+}
+
+/*
+ * Check the directory offset against the list of already seen directory
+ * offsets. This is a trick to prevent IFD looping. The one can create TIFF
+ * file with looped directory pointers. We will maintain a list of already
+ * seen directories and check every IFD offset against that list.
+ */
+static int
+TIFFCheckDirOffset(TIFF* tif, uint64 diroff)
+{
+	uint16 n;
+
+	if (diroff == 0)			/* no more directories */
+		return 0;
+
+	for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) {
+		if (tif->tif_dirlist[n] == diroff)
+			return 0;
+	}
+
+	tif->tif_dirnumber++;
+
+	if (tif->tif_dirnumber > tif->tif_dirlistsize) {
+		uint64* new_dirlist;
+
+		/*
+		 * XXX: Reduce memory allocation granularity of the dirlist
+		 * array.
+		 */
+		new_dirlist = (uint64*)_TIFFCheckRealloc(tif, tif->tif_dirlist,
+		    tif->tif_dirnumber, 2 * sizeof(uint64), "for IFD list");
+		if (!new_dirlist)
+			return 0;
+		tif->tif_dirlistsize = 2 * tif->tif_dirnumber;
+		tif->tif_dirlist = new_dirlist;
+	}
+
+	tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff;
+
+	return 1;
+}
+
+/*
+ * Check the count field of a directory entry against a known value.  The
+ * caller is expected to skip/ignore the tag if there is a mismatch.
+ */
+static int
+CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count)
+{
+	if ((uint64)count > dir->tdir_count) {
+		const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag);
+		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+	"incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); tag ignored",
+		    fip ? fip->field_name : "unknown tagname",
+		    dir->tdir_count, count);
+		return (0);
+	} else if ((uint64)count < dir->tdir_count) {
+		const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag);
+		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+	"incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); tag trimmed",
+		    fip ? fip->field_name : "unknown tagname",
+		    dir->tdir_count, count);
+		dir->tdir_count = count;
+		return (1);
+	}
+	return (1);
+}
+
+/*
+ * Read IFD structure from the specified offset. If the pointer to
+ * nextdiroff variable has been specified, read it too. Function returns a
+ * number of fields in the directory or 0 if failed.
+ */
+static uint16
+TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir,
+                   uint64 *nextdiroff)
+{
+	static const char module[] = "TIFFFetchDirectory";
+
+	void* origdir;
+	uint16 dircount16;
+	uint32 dirsize;
+	TIFFDirEntry* dir;
+	uint8* ma;
+	TIFFDirEntry* mb;
+	uint16 n;
+
+	assert(pdir);
+
+	tif->tif_diroff = diroff;
+	if (nextdiroff)
+		*nextdiroff = 0;
+	if (!isMapped(tif)) {
+		if (!SeekOK(tif, tif->tif_diroff)) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%s: Seek error accessing TIFF directory",
+				tif->tif_name);
+			return 0;
+		}
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			if (!ReadOK(tif, &dircount16, sizeof (uint16))) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "%s: Can not read TIFF directory count",
+				    tif->tif_name);
+				return 0;
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&dircount16);
+			if (dircount16>4096)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Sanity check on directory count failed, this is probably not a valid IFD offset");
+				return 0;
+			}
+			dirsize = 12;
+		} else {
+			uint64 dircount64;
+			if (!ReadOK(tif, &dircount64, sizeof (uint64))) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					"%s: Can not read TIFF directory count",
+					tif->tif_name);
+				return 0;
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>4096)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Sanity check on directory count failed, this is probably not a valid IFD offset");
+				return 0;
+			}
+			dircount16 = (uint16)dircount64;
+			dirsize = 20;
+		}
+		origdir = _TIFFCheckMalloc(tif, dircount16,
+		    dirsize, "to read TIFF directory");
+		if (origdir == NULL)
+			return 0;
+		if (!ReadOK(tif, origdir, (tmsize_t)(dircount16*dirsize))) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%.100s: Can not read TIFF directory",
+				tif->tif_name);
+			_TIFFfree(origdir);
+			return 0;
+		}
+		/*
+		 * Read offset to next directory for sequential scans if
+		 * needed.
+		 */
+		if (nextdiroff)
+		{
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+			{
+				uint32 nextdiroff32;
+				if (!ReadOK(tif, &nextdiroff32, sizeof(uint32)))
+					nextdiroff32 = 0;
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabLong(&nextdiroff32);
+				*nextdiroff=nextdiroff32;
+			} else {
+				if (!ReadOK(tif, nextdiroff, sizeof(uint64)))
+					*nextdiroff = 0;
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabLong8(nextdiroff);
+			}
+		}
+	} else {
+		tmsize_t m;
+		tmsize_t off = (tmsize_t) tif->tif_diroff;
+		if ((uint64)off!=tif->tif_diroff)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count");
+			return(0);
+		}
+
+		/*
+		 * Check for integer overflow when validating the dir_off,
+		 * otherwise a very high offset may cause an OOB read and
+		 * crash the client. Make two comparisons instead of
+		 *
+		 *  off + sizeof(uint16) > tif->tif_size
+		 *
+		 * to avoid overflow.
+		 */
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			m=off+sizeof(uint16);
+			if ((m<off)||(m<(tmsize_t)sizeof(uint16))||(m>tif->tif_size)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					"Can not read TIFF directory count");
+				return 0;
+			} else {
+				_TIFFmemcpy(&dircount16, tif->tif_base + off,
+					    sizeof(uint16));
+			}
+			off += sizeof (uint16);
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&dircount16);
+			if (dircount16>4096)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Sanity check on directory count failed, this is probably not a valid IFD offset");
+				return 0;
+			}
+			dirsize = 12;
+		}
+		else
+		{
+			tmsize_t m;
+			uint64 dircount64;
+			m=off+sizeof(uint64);
+			if ((m<off)||(m<(tmsize_t)sizeof(uint64))||(m>tif->tif_size)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					"Can not read TIFF directory count");
+				return 0;
+			} else {
+				_TIFFmemcpy(&dircount64, tif->tif_base + off,
+					    sizeof(uint64));
+			}
+			off += sizeof (uint64);
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>4096)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Sanity check on directory count failed, this is probably not a valid IFD offset");
+				return 0;
+			}
+			dircount16 = (uint16)dircount64;
+			dirsize = 20;
+		}
+		if (dircount16 == 0 )
+		{
+			TIFFErrorExt(tif->tif_clientdata, module,
+			             "Sanity check on directory count failed, zero tag directories not supported");
+			return 0;
+		}
+		origdir = _TIFFCheckMalloc(tif, dircount16,
+						dirsize,
+						"to read TIFF directory");
+		if (origdir == NULL)
+			return 0;
+		m=off+dircount16*dirsize;
+		if ((m<off)||(m<(tmsize_t)(dircount16*dirsize))||(m>tif->tif_size)) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				     "Can not read TIFF directory");
+			_TIFFfree(origdir);
+			return 0;
+		} else {
+			_TIFFmemcpy(origdir, tif->tif_base + off,
+				    dircount16 * dirsize);
+		}
+		if (nextdiroff) {
+			off += dircount16 * dirsize;
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+			{
+				uint32 nextdiroff32;
+				m=off+sizeof(uint32);
+				if ((m<off)||(m<(tmsize_t)sizeof(uint32))||(m>tif->tif_size))
+					nextdiroff32 = 0;
+				else
+					_TIFFmemcpy(&nextdiroff32, tif->tif_base + off,
+						    sizeof (uint32));
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabLong(&nextdiroff32);
+				*nextdiroff = nextdiroff32;
+			}
+			else
+			{
+				m=off+sizeof(uint64);
+				if ((m<off)||(m<(tmsize_t)sizeof(uint64))||(m>tif->tif_size))
+					*nextdiroff = 0;
+				else
+					_TIFFmemcpy(nextdiroff, tif->tif_base + off,
+						    sizeof (uint64));
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabLong8(nextdiroff);
+			}
+		}
+	}
+	dir = (TIFFDirEntry*)_TIFFCheckMalloc(tif, dircount16,
+						sizeof(TIFFDirEntry),
+						"to read TIFF directory");
+	if (dir==0)
+	{
+		_TIFFfree(origdir);
+		return 0;
+	}
+	ma=(uint8*)origdir;
+	mb=dir;
+	for (n=0; n<dircount16; n++)
+	{
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabShort((uint16*)ma);
+		mb->tdir_tag=*(uint16*)ma;
+		ma+=sizeof(uint16);
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabShort((uint16*)ma);
+		mb->tdir_type=*(uint16*)ma;
+		ma+=sizeof(uint16);
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong((uint32*)ma);
+			mb->tdir_count=(uint64)(*(uint32*)ma);
+			ma+=sizeof(uint32);
+			*(uint32*)(&mb->tdir_offset)=*(uint32*)ma;
+			ma+=sizeof(uint32);
+		}
+		else
+		{
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8((uint64*)ma);
+                        mb->tdir_count=TIFFReadUInt64(ma);
+			ma+=sizeof(uint64);
+			mb->tdir_offset.toff_long8=TIFFReadUInt64(ma);
+			ma+=sizeof(uint64);
+		}
+		mb++;
+	}
+	_TIFFfree(origdir);
+	*pdir = dir;
+	return dircount16;
+}
+
+/*
+ * Fetch a tag that is not handled by special case code.
+ */
+static int
+TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
+{
+	static const char module[] = "TIFFFetchNormalTag";
+	enum TIFFReadDirEntryErr err;
+	uint32 fii;
+	const TIFFField* fip = NULL;
+	TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+        if( fii == FAILED_FII )
+        {
+            TIFFErrorExt(tif->tif_clientdata, "TIFFFetchNormalTag",
+                         "No definition found for tag %d",
+                         dp->tdir_tag);
+            return 0;
+        }
+	fip=tif->tif_fields[fii];
+	assert(fip->set_field_type!=TIFF_SETGET_OTHER);  /* if so, we shouldn't arrive here but deal with this in specialized code */
+	assert(fip->set_field_type!=TIFF_SETGET_INT);    /* if so, we shouldn't arrive here as this is only the case for pseudo-tags */
+	err=TIFFReadDirEntryErrOk;
+	switch (fip->set_field_type)
+	{
+		case TIFF_SETGET_UNDEFINED:
+			break;
+		case TIFF_SETGET_ASCII:
+			{
+				uint8* data;
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryByteArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					uint8* ma;
+					uint32 mb;
+					int n;
+					ma=data;
+					mb=0;
+					while (mb<(uint32)dp->tdir_count)
+					{
+						if (*ma==0)
+							break;
+						ma++;
+						mb++;
+					}
+					if (mb+1<(uint32)dp->tdir_count)
+						TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" contains null byte in value; value incorrectly truncated during reading due to implementation limitations",fip->field_name);
+					else if (mb+1>(uint32)dp->tdir_count)
+					{
+						uint8* o;
+						TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte",fip->field_name);
+						if ((uint32)dp->tdir_count+1!=dp->tdir_count+1)
+							o=NULL;
+						else
+							o=_TIFFmalloc((uint32)dp->tdir_count+1);
+						if (o==NULL)
+						{
+							if (data!=NULL)
+								_TIFFfree(data);
+							return(0);
+						}
+						_TIFFmemcpy(o,data,(uint32)dp->tdir_count);
+						o[(uint32)dp->tdir_count]=0;
+						if (data!=0)
+							_TIFFfree(data);
+						data=o;
+					}
+					n=TIFFSetField(tif,dp->tdir_tag,data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!n)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT8:
+			{
+				uint8 data=0;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryByte(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT16:
+			{
+				uint16 data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryShort(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT32:
+			{
+				uint32 data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryLong(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT64:
+			{
+				uint64 data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryLong8(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_FLOAT:
+			{
+				float data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryFloat(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_DOUBLE:
+			{
+				double data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryDouble(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_IFD8:
+			{
+				uint64 data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryIfd8(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT16_PAIR:
+			{
+				uint16* data;
+				assert(fip->field_readcount==2);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=2) {
+					TIFFWarningExt(tif->tif_clientdata,module,
+						       "incorrect count for field \"%s\", expected 2, got %d",
+						       fip->field_name,(int)dp->tdir_count);
+					return(0);
+				}
+				err=TIFFReadDirEntryShortArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,data[0],data[1]);
+					_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_UINT8:
+			{
+				uint8* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata,module,
+						       "incorrect count for field \"%s\", expected %d, got %d",
+						       fip->field_name,(int) fip->field_readcount, (int)dp->tdir_count);
+					return 0;
+				}
+				else
+				{
+					err=TIFFReadDirEntryByteArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_UINT16:
+			{
+				uint16* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64)fip->field_readcount)
+                                    /* corrupt file */;
+				else
+				{
+					err=TIFFReadDirEntryShortArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_UINT32:
+			{
+				uint32* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64)fip->field_readcount)
+                                    /* corrupt file */;
+				else
+				{
+					err=TIFFReadDirEntryLongArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_FLOAT:
+			{
+				float* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64)fip->field_readcount)
+                                    /* corrupt file */;
+				else
+				{
+					err=TIFFReadDirEntryFloatArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_ASCII:
+			{
+				uint8* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryByteArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_UINT8:
+			{
+				uint8* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryByteArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_UINT16:
+			{
+				uint16* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryShortArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_UINT32:
+			{
+				uint32* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryLongArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_UINT64:
+			{
+				uint64* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryLong8Array(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_FLOAT:
+			{
+				float* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryFloatArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_DOUBLE:
+			{
+				double* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryDoubleArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_IFD8:
+			{
+				uint64* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryIfd8Array(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_ASCII:
+			{
+				uint8* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryByteArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_UINT8:
+			{
+				uint8* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryByteArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_SINT8:
+			{
+				int8* data = NULL;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntrySbyteArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_UINT16:
+			{
+				uint16* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryShortArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_SINT16:
+			{
+				int16* data = NULL;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntrySshortArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_UINT32:
+			{
+				uint32* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryLongArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_SINT32:
+			{
+				int32* data = NULL;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntrySlongArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_UINT64:
+			{
+				uint64* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryLong8Array(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_SINT64:
+			{
+				int64* data = NULL;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntrySlong8Array(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_FLOAT:
+			{
+				float* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryFloatArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_DOUBLE:
+			{
+				double* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryDoubleArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_IFD8:
+			{
+				uint64* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryIfd8Array(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		default:
+			assert(0);    /* we should never get here */
+			break;
+	}
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",recover);
+		return(0);
+	}
+	return(1);
+}
+
+/*
+ * Fetch a set of offsets or lengths.
+ * While this routine says "strips", in fact it's also used for tiles.
+ */
+static int
+TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp)
+{
+	static const char module[] = "TIFFFetchStripThing";
+	enum TIFFReadDirEntryErr err;
+	uint64* data;
+	err=TIFFReadDirEntryLong8Array(tif,dir,&data);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag); 
+		TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
+		return(0);
+	}
+	if (dir->tdir_count!=(uint64)nstrips)
+	{
+		uint64* resizeddata;
+		resizeddata=(uint64*)_TIFFCheckMalloc(tif,nstrips,sizeof(uint64),"for strip array");
+		if (resizeddata==0) {
+			_TIFFfree(data);
+			return(0);
+		}
+		if (dir->tdir_count<(uint64)nstrips)
+		{
+			_TIFFmemcpy(resizeddata,data,(uint32)dir->tdir_count*sizeof(uint64));
+			_TIFFmemset(resizeddata+(uint32)dir->tdir_count,0,(nstrips-(uint32)dir->tdir_count)*sizeof(uint64));
+		}
+		else
+			_TIFFmemcpy(resizeddata,data,nstrips*sizeof(uint64));
+		_TIFFfree(data);
+		data=resizeddata;
+	}
+	*lpp=data;
+	return(1);
+}
+
+/*
+ * Fetch and set the SubjectDistance EXIF tag.
+ */
+static int
+TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir)
+{
+	static const char module[] = "TIFFFetchSubjectDistance";
+	enum TIFFReadDirEntryErr err;
+	UInt64Aligned_t m;
+    m.l=0;
+	assert(sizeof(double)==8);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(uint32)==4);
+	if (dir->tdir_count!=1)
+		err=TIFFReadDirEntryErrCount;
+	else if (dir->tdir_type!=TIFF_RATIONAL)
+		err=TIFFReadDirEntryErrType;
+	else
+	{
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			uint32 offset;
+			offset=*(uint32*)(&dir->tdir_offset);
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong(&offset);
+			err=TIFFReadDirEntryData(tif,offset,8,m.i);
+		}
+		else
+		{
+			m.l=dir->tdir_offset.toff_long8;
+			err=TIFFReadDirEntryErrOk;
+		}
+	}
+	if (err==TIFFReadDirEntryErrOk)
+	{
+		double n;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabArrayOfLong(m.i,2);
+		if (m.i[0]==0)
+			n=0.0;
+		else if (m.i[0]==0xFFFFFFFF)
+			/*
+			 * XXX: Numerator 0xFFFFFFFF means that we have infinite
+			 * distance. Indicate that with a negative floating point
+			 * SubjectDistance value.
+			 */
+			n=-1.0;
+		else
+			n=(double)m.i[0]/(double)m.i[1];
+		return(TIFFSetField(tif,dir->tdir_tag,n));
+	}
+	else
+	{
+		TIFFReadDirEntryOutputErr(tif,err,module,"SubjectDistance",TRUE);
+		return(0);
+	}
+}
+
+/*
+ * Replace a single strip (tile) of uncompressed data by multiple strips
+ * (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for
+ * dealing with large images or for dealing with machines with a limited
+ * amount memory.
+ */
+static void
+ChopUpSingleUncompressedStrip(TIFF* tif)
+{
+	register TIFFDirectory *td = &tif->tif_dir;
+	uint64 bytecount;
+	uint64 offset;
+	uint32 rowblock;
+	uint64 rowblockbytes;
+	uint64 stripbytes;
+	uint32 strip;
+	uint64 nstrips64;
+	uint32 nstrips32;
+	uint32 rowsperstrip;
+	uint64* newcounts;
+	uint64* newoffsets;
+
+	bytecount = td->td_stripbytecount[0];
+	offset = td->td_stripoffset[0];
+	assert(td->td_planarconfig == PLANARCONFIG_CONTIG);
+	if ((td->td_photometric == PHOTOMETRIC_YCBCR)&&
+	    (!isUpSampled(tif)))
+		rowblock = td->td_ycbcrsubsampling[1];
+	else
+		rowblock = 1;
+	rowblockbytes = TIFFVTileSize64(tif, rowblock);
+	/*
+	 * Make the rows hold at least one scanline, but fill specified amount
+	 * of data if possible.
+	 */
+	if (rowblockbytes > STRIP_SIZE_DEFAULT) {
+		stripbytes = rowblockbytes;
+		rowsperstrip = rowblock;
+	} else if (rowblockbytes > 0 ) {
+		uint32 rowblocksperstrip;
+		rowblocksperstrip = (uint32) (STRIP_SIZE_DEFAULT / rowblockbytes);
+		rowsperstrip = rowblocksperstrip * rowblock;
+		stripbytes = rowblocksperstrip * rowblockbytes;
+	}
+	else
+	    return;
+
+	/*
+	 * never increase the number of strips in an image
+	 */
+	if (rowsperstrip >= td->td_rowsperstrip)
+		return;
+	nstrips64 = TIFFhowmany_64(bytecount, stripbytes);
+	if ((nstrips64==0)||(nstrips64>0xFFFFFFFF)) /* something is wonky, do nothing. */
+	    return;
+	nstrips32 = (uint32)nstrips64;
+
+	newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64),
+				"for chopped \"StripByteCounts\" array");
+	newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64),
+				"for chopped \"StripOffsets\" array");
+	if (newcounts == NULL || newoffsets == NULL) {
+		/*
+		 * Unable to allocate new strip information, give up and use
+		 * the original one strip information.
+		 */
+		if (newcounts != NULL)
+			_TIFFfree(newcounts);
+		if (newoffsets != NULL)
+			_TIFFfree(newoffsets);
+		return;
+	}
+	/*
+	 * Fill the strip information arrays with new bytecounts and offsets
+	 * that reflect the broken-up format.
+	 */
+	for (strip = 0; strip < nstrips32; strip++) {
+		if (stripbytes > bytecount)
+			stripbytes = bytecount;
+		newcounts[strip] = stripbytes;
+		newoffsets[strip] = offset;
+		offset += stripbytes;
+		bytecount -= stripbytes;
+	}
+	/*
+	 * Replace old single strip info with multi-strip info.
+	 */
+	td->td_stripsperimage = td->td_nstrips = nstrips32;
+	TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+	_TIFFfree(td->td_stripbytecount);
+	_TIFFfree(td->td_stripoffset);
+	td->td_stripbytecount = newcounts;
+	td->td_stripoffset = newoffsets;
+	td->td_stripbytecountsorted = 1;
+}
+
+int _TIFFFillStriles( TIFF *tif )
+{
+#if defined(DEFER_STRILE_LOAD)
+        register TIFFDirectory *td = &tif->tif_dir;
+        int return_value = 1;
+
+        if( td->td_stripoffset != NULL )
+                return 1;
+
+        if( td->td_stripoffset_entry.tdir_count == 0 )
+                return 0;
+
+        if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry),
+                                 td->td_nstrips,&td->td_stripoffset))
+        {
+                return_value = 0;
+        }
+
+        if (!TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry),
+                                 td->td_nstrips,&td->td_stripbytecount))
+        {
+                return_value = 0;
+        }
+
+        _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
+        _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
+
+	if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) {
+		uint32 strip;
+
+		tif->tif_dir.td_stripbytecountsorted = 1;
+		for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
+			if (tif->tif_dir.td_stripoffset[strip - 1] >
+			    tif->tif_dir.td_stripoffset[strip]) {
+				tif->tif_dir.td_stripbytecountsorted = 0;
+				break;
+			}
+		}
+	}
+
+        return return_value;
+#else /* !defined(DEFER_STRILE_LOAD) */
+        (void) tif;
+        return 1;
+#endif 
+}
+
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+ #endif
+ 
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirwrite.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirwrite.c
new file mode 100644
index 0000000..ac13cd4
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirwrite.c
@@ -0,0 +1,2912 @@
+/* $Id: tif_dirwrite.c,v 1.77 2012-07-06 19:18:31 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Write Support Routines.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+#ifdef HAVE_IEEEFP
+#define TIFFCvtNativeToIEEEFloat(tif, n, fp)
+#define TIFFCvtNativeToIEEEDouble(tif, n, dp)
+#else
+extern void TIFFCvtNativeToIEEEFloat(TIFF* tif, uint32 n, float* fp);
+extern void TIFFCvtNativeToIEEEDouble(TIFF* tif, uint32 n, double* dp);
+#endif
+
+static int TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff);
+
+static int TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
+#if 0
+static int TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+#endif
+
+static int TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value);
+static int TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
+#endif
+static int TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
+#if 0
+static int TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
+#endif
+#ifdef notdef
+static int TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
+#endif
+static int TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value);
+#if 0
+static int TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
+#endif
+static int TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
+static int TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value);
+static int TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
+#endif
+static int TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value);
+#if 0
+static int TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
+#endif
+static int TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
+static int TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
+#if 0
+static int TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
+#endif
+#ifdef notdef
+static int TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
+#endif
+static int TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value);
+#if 0
+static int TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
+#endif
+#ifdef notdef
+static int TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value);
+#endif
+static int TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value);
+#endif
+static int TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value);
+static int TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+static int TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+static int TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
+#endif
+static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+#if 0
+static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
+#endif
+#ifdef notdef
+static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+#endif
+static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
+#if 0
+static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+#endif
+static int TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#endif
+static int TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
+static int TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#endif
+static int TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);
+static int TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);
+static int TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);
+
+static int TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value);
+static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value);
+static int TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
+static int TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value);
+static int TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
+static int TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value);
+static int TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
+#endif
+static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+#endif
+static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
+static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
+static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+
+static int TIFFWriteDirectoryTagData(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data);
+
+static int TIFFLinkDirectory(TIFF*);
+
+/*
+ * Write the contents of the current directory
+ * to the specified file.  This routine doesn't
+ * handle overwriting a directory with auxiliary
+ * storage that's been changed.
+ */
+int
+TIFFWriteDirectory(TIFF* tif)
+{
+	return TIFFWriteDirectorySec(tif,TRUE,TRUE,NULL);
+}
+
+/*
+ * Similar to TIFFWriteDirectory(), writes the directory out
+ * but leaves all data structures in memory so that it can be
+ * written again.  This will make a partially written TIFF file
+ * readable before it is successfully completed/closed.
+ */
+int
+TIFFCheckpointDirectory(TIFF* tif)
+{
+	int rc;
+	/* Setup the strips arrays, if they haven't already been. */
+	if (tif->tif_dir.td_stripoffset == NULL)
+	    (void) TIFFSetupStrips(tif);
+	rc = TIFFWriteDirectorySec(tif,TRUE,FALSE,NULL);
+	(void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END));
+	return rc;
+}
+
+int
+TIFFWriteCustomDirectory(TIFF* tif, uint64* pdiroff)
+{
+	return TIFFWriteDirectorySec(tif,FALSE,FALSE,pdiroff);
+}
+
+/*
+ * Similar to TIFFWriteDirectory(), but if the directory has already
+ * been written once, it is relocated to the end of the file, in case it
+ * has changed in size.  Note that this will result in the loss of the
+ * previously used directory space. 
+ */ 
+int
+TIFFRewriteDirectory( TIFF *tif )
+{
+	static const char module[] = "TIFFRewriteDirectory";
+
+	/* We don't need to do anything special if it hasn't been written. */
+	if( tif->tif_diroff == 0 )
+		return TIFFWriteDirectory( tif );
+
+	/*
+	 * Find and zero the pointer to this directory, so that TIFFLinkDirectory
+	 * will cause it to be added after this directories current pre-link.
+	 */
+
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		if (tif->tif_header.classic.tiff_diroff == tif->tif_diroff)
+		{
+			tif->tif_header.classic.tiff_diroff = 0;
+			tif->tif_diroff = 0;
+
+			TIFFSeekFile(tif,4,SEEK_SET);
+			if (!WriteOK(tif, &(tif->tif_header.classic.tiff_diroff),4))
+			{
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+				    "Error updating TIFF header");
+				return (0);
+			}
+		}
+		else
+		{
+			uint32 nextdir;
+			nextdir = tif->tif_header.classic.tiff_diroff;
+			while(1) {
+				uint16 dircount;
+				uint32 nextnextdir;
+
+				if (!SeekOK(tif, nextdir) ||
+				    !ReadOK(tif, &dircount, 2)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory count");
+					return (0);
+				}
+				if (tif->tif_flags & TIFF_SWAB)
+					TIFFSwabShort(&dircount);
+				(void) TIFFSeekFile(tif,
+				    nextdir+2+dircount*12, SEEK_SET);
+				if (!ReadOK(tif, &nextnextdir, 4)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory link");
+					return (0);
+				}
+				if (tif->tif_flags & TIFF_SWAB)
+					TIFFSwabLong(&nextnextdir);
+				if (nextnextdir==tif->tif_diroff)
+				{
+					uint32 m;
+					m=0;
+					(void) TIFFSeekFile(tif,
+					    nextdir+2+dircount*12, SEEK_SET);
+					if (!WriteOK(tif, &m, 4)) {
+						TIFFErrorExt(tif->tif_clientdata, module,
+						     "Error writing directory link");
+						return (0);
+					}
+					tif->tif_diroff=0;
+					break;
+				}
+				nextdir=nextnextdir;
+			}
+		}
+	}
+	else
+	{
+		if (tif->tif_header.big.tiff_diroff == tif->tif_diroff)
+		{
+			tif->tif_header.big.tiff_diroff = 0;
+			tif->tif_diroff = 0;
+
+			TIFFSeekFile(tif,8,SEEK_SET);
+			if (!WriteOK(tif, &(tif->tif_header.big.tiff_diroff),8))
+			{
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+				    "Error updating TIFF header");
+				return (0);
+			}
+		}
+		else
+		{
+			uint64 nextdir;
+			nextdir = tif->tif_header.big.tiff_diroff;
+			while(1) {
+				uint64 dircount64;
+				uint16 dircount;
+				uint64 nextnextdir;
+
+				if (!SeekOK(tif, nextdir) ||
+				    !ReadOK(tif, &dircount64, 8)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory count");
+					return (0);
+				}
+				if (tif->tif_flags & TIFF_SWAB)
+					TIFFSwabLong8(&dircount64);
+				if (dircount64>0xFFFF)
+				{
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Sanity check on tag count failed, likely corrupt TIFF");
+					return (0);
+				}
+				dircount=(uint16)dircount64;
+				(void) TIFFSeekFile(tif,
+				    nextdir+8+dircount*20, SEEK_SET);
+				if (!ReadOK(tif, &nextnextdir, 8)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory link");
+					return (0);
+				}
+				if (tif->tif_flags & TIFF_SWAB)
+					TIFFSwabLong8(&nextnextdir);
+				if (nextnextdir==tif->tif_diroff)
+				{
+					uint64 m;
+					m=0;
+					(void) TIFFSeekFile(tif,
+					    nextdir+8+dircount*20, SEEK_SET);
+					if (!WriteOK(tif, &m, 8)) {
+						TIFFErrorExt(tif->tif_clientdata, module,
+						     "Error writing directory link");
+						return (0);
+					}
+					tif->tif_diroff=0;
+					break;
+				}
+				nextdir=nextnextdir;
+			}
+		}
+	}
+
+	/*
+	 * Now use TIFFWriteDirectory() normally.
+	 */
+
+	return TIFFWriteDirectory( tif );
+}
+
+static int
+TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff)
+{
+	static const char module[] = "TIFFWriteDirectorySec";
+	uint32 ndir;
+	TIFFDirEntry* dir;
+	uint32 dirsize;
+	void* dirmem;
+	uint32 m;
+	if (tif->tif_mode == O_RDONLY)
+		return (1);
+
+        _TIFFFillStriles( tif );
+        
+	/*
+	 * Clear write state so that subsequent images with
+	 * different characteristics get the right buffers
+	 * setup for them.
+	 */
+	if (imagedone)
+	{
+		if (tif->tif_flags & TIFF_POSTENCODE)
+		{
+			tif->tif_flags &= ~TIFF_POSTENCODE;
+			if (!(*tif->tif_postencode)(tif))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,
+				    "Error post-encoding before directory write");
+				return (0);
+			}
+		}
+		(*tif->tif_close)(tif);       /* shutdown encoder */
+		/*
+		 * Flush any data that might have been written
+		 * by the compression close+cleanup routines.  But
+                 * be careful not to write stuff if we didn't add data
+                 * in the previous steps as the "rawcc" data may well be
+                 * a previously read tile/strip in mixed read/write mode.
+		 */
+		if (tif->tif_rawcc > 0 
+		    && (tif->tif_flags & TIFF_BEENWRITING) != 0 )
+		{
+		    if( !TIFFFlushData1(tif) )
+                    {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Error flushing data before directory write");
+			return (0);
+                    }
+		}
+		if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
+		{
+			_TIFFfree(tif->tif_rawdata);
+			tif->tif_rawdata = NULL;
+			tif->tif_rawcc = 0;
+			tif->tif_rawdatasize = 0;
+                        tif->tif_rawdataoff = 0;
+                        tif->tif_rawdataloaded = 0;
+		}
+		tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);
+	}
+	dir=NULL;
+	dirmem=NULL;
+	dirsize=0;
+	while (1)
+	{
+		ndir=0;
+		if (isimage)
+		{
+			if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS))
+			{
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGEWIDTH,tif->tif_dir.td_imagewidth))
+					goto bad;
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGELENGTH,tif->tif_dir.td_imagelength))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS))
+			{
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILEWIDTH,tif->tif_dir.td_tilewidth))
+					goto bad;
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILELENGTH,tif->tif_dir.td_tilelength))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_RESOLUTION))
+			{
+				if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XRESOLUTION,tif->tif_dir.td_xresolution))
+					goto bad;
+				if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YRESOLUTION,tif->tif_dir.td_yresolution))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_POSITION))
+			{
+				if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XPOSITION,tif->tif_dir.td_xposition))
+					goto bad;
+				if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YPOSITION,tif->tif_dir.td_yposition))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SUBFILETYPE))
+			{
+				if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_SUBFILETYPE,tif->tif_dir.td_subfiletype))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
+			{
+				if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_BITSPERSAMPLE,tif->tif_dir.td_bitspersample))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_COMPRESSION))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_COMPRESSION,tif->tif_dir.td_compression))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PHOTOMETRIC,tif->tif_dir.td_photometric))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_THRESHHOLDING))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_THRESHHOLDING,tif->tif_dir.td_threshholding))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_FILLORDER))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_FILLORDER,tif->tif_dir.td_fillorder))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_ORIENTATION))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_ORIENTATION,tif->tif_dir.td_orientation))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_SAMPLESPERPIXEL,tif->tif_dir.td_samplesperpixel))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP))
+			{
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_ROWSPERSTRIP,tif->tif_dir.td_rowsperstrip))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE))
+			{
+				if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MINSAMPLEVALUE,tif->tif_dir.td_minsamplevalue))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE))
+			{
+				if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MAXSAMPLEVALUE,tif->tif_dir.td_maxsamplevalue))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_PLANARCONFIG))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PLANARCONFIG,tif->tif_dir.td_planarconfig))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_RESOLUTIONUNIT,tif->tif_dir.td_resolutionunit))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_PAGENUMBER))
+			{
+				if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_PAGENUMBER,2,&tif->tif_dir.td_pagenumber[0]))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_STRIPBYTECOUNTS))
+			{
+				if (!isTiled(tif))
+				{
+					if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount))
+						goto bad;
+				}
+				else
+				{
+					if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount))
+						goto bad;
+				}
+			}
+			if (TIFFFieldSet(tif,FIELD_STRIPOFFSETS))
+			{
+				if (!isTiled(tif))
+				{
+					if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset))
+						goto bad;
+				}
+				else
+				{
+					if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset))
+						goto bad;
+				}
+			}
+			if (TIFFFieldSet(tif,FIELD_COLORMAP))
+			{
+				if (!TIFFWriteDirectoryTagColormap(tif,&ndir,dir))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES))
+			{
+				if (tif->tif_dir.td_extrasamples)
+				{
+					uint16 na;
+					uint16* nb;
+					TIFFGetFieldDefaulted(tif,TIFFTAG_EXTRASAMPLES,&na,&nb);
+					if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_EXTRASAMPLES,na,nb))
+						goto bad;
+				}
+			}
+			if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT))
+			{
+				if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_SAMPLEFORMAT,tif->tif_dir.td_sampleformat))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE))
+			{
+				if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMINSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_sminsamplevalue))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE))
+			{
+				if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMAXSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_smaxsamplevalue))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH))
+			{
+				if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_IMAGEDEPTH,tif->tif_dir.td_imagedepth))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_TILEDEPTH))
+			{
+				if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_TILEDEPTH,tif->tif_dir.td_tiledepth))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS))
+			{
+				if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_HALFTONEHINTS,2,&tif->tif_dir.td_halftonehints[0]))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING))
+			{
+				if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_YCBCRSUBSAMPLING,2,&tif->tif_dir.td_ycbcrsubsampling[0]))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_YCBCRPOSITIONING,tif->tif_dir.td_ycbcrpositioning))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_REFBLACKWHITE))
+			{
+				if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,TIFFTAG_REFERENCEBLACKWHITE,6,tif->tif_dir.td_refblackwhite))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION))
+			{
+				if (!TIFFWriteDirectoryTagTransferfunction(tif,&ndir,dir))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_INKNAMES))
+			{
+				if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,TIFFTAG_INKNAMES,tif->tif_dir.td_inknameslen,tif->tif_dir.td_inknames))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SUBIFD))
+			{
+				if (!TIFFWriteDirectoryTagSubifd(tif,&ndir,dir))
+					goto bad;
+			}
+			{
+				uint32 n;
+				for (n=0; n<tif->tif_nfields; n++) {
+					const TIFFField* o;
+					o = tif->tif_fields[n];
+					if ((o->field_bit>=FIELD_CODEC)&&(TIFFFieldSet(tif,o->field_bit)))
+					{
+						switch (o->get_field_type)
+						{
+							case TIFF_SETGET_ASCII:
+								{
+									uint32 pa;
+									char* pb;
+									assert(o->field_type==TIFF_ASCII);
+									assert(o->field_readcount==TIFF_VARIABLE);
+									assert(o->field_passcount==0);
+									TIFFGetField(tif,o->field_tag,&pb);
+									pa=(uint32)(strlen(pb));
+									if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,o->field_tag,pa,pb))
+										goto bad;
+								}
+								break;
+							case TIFF_SETGET_UINT16:
+								{
+									uint16 p;
+									assert(o->field_type==TIFF_SHORT);
+									assert(o->field_readcount==1);
+									assert(o->field_passcount==0);
+									TIFFGetField(tif,o->field_tag,&p);
+									if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,o->field_tag,p))
+										goto bad;
+								}
+								break;
+							case TIFF_SETGET_UINT32:
+								{
+									uint32 p;
+									assert(o->field_type==TIFF_LONG);
+									assert(o->field_readcount==1);
+									assert(o->field_passcount==0);
+									TIFFGetField(tif,o->field_tag,&p);
+									if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,o->field_tag,p))
+										goto bad;
+								}
+								break;
+							case TIFF_SETGET_C32_UINT8:
+								{
+									uint32 pa;
+									void* pb;
+									assert(o->field_type==TIFF_UNDEFINED);
+									assert(o->field_readcount==TIFF_VARIABLE2);
+									assert(o->field_passcount==1);
+									TIFFGetField(tif,o->field_tag,&pa,&pb);
+									if (!TIFFWriteDirectoryTagUndefinedArray(tif,&ndir,dir,o->field_tag,pa,pb))
+										goto bad;
+								}
+								break;
+							default:
+								assert(0);   /* we should never get here */
+								break;
+						}
+					}
+				}
+			}
+		}
+		for (m=0; m<(uint32)(tif->tif_dir.td_customValueCount); m++)
+		{
+			switch (tif->tif_dir.td_customValues[m].info->field_type)
+			{
+				case TIFF_ASCII:
+					if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_UNDEFINED:
+					if (!TIFFWriteDirectoryTagUndefinedArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_BYTE:
+					if (!TIFFWriteDirectoryTagByteArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SBYTE:
+					if (!TIFFWriteDirectoryTagSbyteArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SHORT:
+					if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SSHORT:
+					if (!TIFFWriteDirectoryTagSshortArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_LONG:
+					if (!TIFFWriteDirectoryTagLongArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SLONG:
+					if (!TIFFWriteDirectoryTagSlongArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_LONG8:
+					if (!TIFFWriteDirectoryTagLong8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SLONG8:
+					if (!TIFFWriteDirectoryTagSlong8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_RATIONAL:
+					if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SRATIONAL:
+					if (!TIFFWriteDirectoryTagSrationalArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_FLOAT:
+					if (!TIFFWriteDirectoryTagFloatArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_DOUBLE:
+					if (!TIFFWriteDirectoryTagDoubleArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_IFD:
+					if (!TIFFWriteDirectoryTagIfdArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_IFD8:
+					if (!TIFFWriteDirectoryTagIfdIfd8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				default:
+					assert(0);   /* we should never get here */
+					break;
+			}
+		}
+		if (dir!=NULL)
+			break;
+		dir=_TIFFmalloc(ndir*sizeof(TIFFDirEntry));
+		if (dir==NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			goto bad;
+		}
+		if (isimage)
+		{
+			if ((tif->tif_diroff==0)&&(!TIFFLinkDirectory(tif)))
+				goto bad;
+		}
+		else
+			tif->tif_diroff=(TIFFSeekFile(tif,0,SEEK_END)+1)&(~1);
+		if (pdiroff!=NULL)
+			*pdiroff=tif->tif_diroff;
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+			dirsize=2+ndir*12+4;
+		else
+			dirsize=8+ndir*20+8;
+		tif->tif_dataoff=tif->tif_diroff+dirsize;
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+			tif->tif_dataoff=(uint32)tif->tif_dataoff;
+		if ((tif->tif_dataoff<tif->tif_diroff)||(tif->tif_dataoff<(uint64)dirsize))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded");
+			goto bad;
+		}
+		if (tif->tif_dataoff&1)
+			tif->tif_dataoff++;
+		if (isimage)
+			tif->tif_curdir++;
+	}
+	if (isimage)
+	{
+		if (TIFFFieldSet(tif,FIELD_SUBIFD)&&(tif->tif_subifdoff==0))
+		{
+			uint32 na;
+			TIFFDirEntry* nb;
+			for (na=0, nb=dir; ; na++, nb++)
+			{
+				assert(na<ndir);
+				if (nb->tdir_tag==TIFFTAG_SUBIFD)
+					break;
+			}
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+				tif->tif_subifdoff=tif->tif_diroff+2+na*12+8;
+			else
+				tif->tif_subifdoff=tif->tif_diroff+8+na*20+12;
+		}
+	}
+	dirmem=_TIFFmalloc(dirsize);
+	if (dirmem==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		goto bad;
+	}
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		uint8* n;
+		uint32 nTmp;
+		TIFFDirEntry* o;
+		n=dirmem;
+		*(uint16*)n=ndir;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabShort((uint16*)n);
+		n+=2;
+		o=dir;
+		for (m=0; m<ndir; m++)
+		{
+			*(uint16*)n=o->tdir_tag;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort((uint16*)n);
+			n+=2;
+			*(uint16*)n=o->tdir_type;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort((uint16*)n);
+			n+=2;
+			nTmp = (uint32)o->tdir_count;
+			_TIFFmemcpy(n,&nTmp,4);
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong((uint32*)n);
+			n+=4;
+			/* This is correct. The data has been */
+			/* swabbed previously in TIFFWriteDirectoryTagData */
+			_TIFFmemcpy(n,&o->tdir_offset,4);
+			n+=4;
+			o++;
+		}
+		nTmp = (uint32)tif->tif_nextdiroff;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong(&nTmp);
+		_TIFFmemcpy(n,&nTmp,4);
+	}
+	else
+	{
+		uint8* n;
+		TIFFDirEntry* o;
+		n=dirmem;
+		*(uint64*)n=ndir;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong8((uint64*)n);
+		n+=8;
+		o=dir;
+		for (m=0; m<ndir; m++)
+		{
+			*(uint16*)n=o->tdir_tag;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort((uint16*)n);
+			n+=2;
+			*(uint16*)n=o->tdir_type;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort((uint16*)n);
+			n+=2;
+			_TIFFmemcpy(n,&o->tdir_count,8);
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8((uint64*)n);
+			n+=8;
+			_TIFFmemcpy(n,&o->tdir_offset,8);
+			n+=8;
+			o++;
+		}
+		_TIFFmemcpy(n,&tif->tif_nextdiroff,8);
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong8((uint64*)n);
+	}
+	_TIFFfree(dir);
+	dir=NULL;
+	if (!SeekOK(tif,tif->tif_diroff))
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory");
+		goto bad;
+	}
+	if (!WriteOK(tif,dirmem,(tmsize_t)dirsize))
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory");
+		goto bad;
+	}
+	_TIFFfree(dirmem);
+	if (imagedone)
+	{
+		TIFFFreeDirectory(tif);
+		tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+		tif->tif_flags &= ~TIFF_DIRTYSTRIP;
+		(*tif->tif_cleanup)(tif);
+		/*
+		* Reset directory-related state for subsequent
+		* directories.
+		*/
+		TIFFCreateDirectory(tif);
+	}
+	return(1);
+bad:
+	if (dir!=NULL)
+		_TIFFfree(dir);
+	if (dirmem!=NULL)
+		_TIFFfree(dirmem);
+	return(0);
+}
+
+static int
+TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSampleformatArray";
+	void* conv;
+	uint32 i;
+	int ok;
+	conv = _TIFFmalloc(count*sizeof(double));
+	if (conv == NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Out of memory");
+		return (0);
+	}
+
+	switch (tif->tif_dir.td_sampleformat)
+	{
+		case SAMPLEFORMAT_IEEEFP:
+			if (tif->tif_dir.td_bitspersample<=32)
+			{
+				for (i = 0; i < count; ++i)
+					((float*)conv)[i] = (float)value[i];
+				ok = TIFFWriteDirectoryTagFloatArray(tif,ndir,dir,tag,count,(float*)conv);
+			}
+			else
+			{
+				ok = TIFFWriteDirectoryTagDoubleArray(tif,ndir,dir,tag,count,value);
+			}
+			break;
+		case SAMPLEFORMAT_INT:
+			if (tif->tif_dir.td_bitspersample<=8)
+			{
+				for (i = 0; i < count; ++i)
+					((int8*)conv)[i] = (int8)value[i];
+				ok = TIFFWriteDirectoryTagSbyteArray(tif,ndir,dir,tag,count,(int8*)conv);
+			}
+			else if (tif->tif_dir.td_bitspersample<=16)
+			{
+				for (i = 0; i < count; ++i)
+					((int16*)conv)[i] = (int16)value[i];
+				ok = TIFFWriteDirectoryTagSshortArray(tif,ndir,dir,tag,count,(int16*)conv);
+			}
+			else
+			{
+				for (i = 0; i < count; ++i)
+					((int32*)conv)[i] = (int32)value[i];
+				ok = TIFFWriteDirectoryTagSlongArray(tif,ndir,dir,tag,count,(int32*)conv);
+			}
+			break;
+		case SAMPLEFORMAT_UINT:
+			if (tif->tif_dir.td_bitspersample<=8)
+			{
+				for (i = 0; i < count; ++i)
+					((uint8*)conv)[i] = (uint8)value[i];
+				ok = TIFFWriteDirectoryTagByteArray(tif,ndir,dir,tag,count,(uint8*)conv);
+			}
+			else if (tif->tif_dir.td_bitspersample<=16)
+			{
+				for (i = 0; i < count; ++i)
+					((uint16*)conv)[i] = (uint16)value[i];
+				ok = TIFFWriteDirectoryTagShortArray(tif,ndir,dir,tag,count,(uint16*)conv);
+			}
+			else
+			{
+				for (i = 0; i < count; ++i)
+					((uint32*)conv)[i] = (uint32)value[i];
+				ok = TIFFWriteDirectoryTagLongArray(tif,ndir,dir,tag,count,(uint32*)conv);
+			}
+			break;
+		default:
+			ok = 0;
+	}
+
+	_TIFFfree(conv);
+	return (ok);
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	switch (tif->tif_dir.td_sampleformat)
+	{
+		case SAMPLEFORMAT_IEEEFP:
+			if (tif->tif_dir.td_bitspersample<=32)
+				return(TIFFWriteDirectoryTagFloatPerSample(tif,ndir,dir,tag,(float)value));
+			else
+				return(TIFFWriteDirectoryTagDoublePerSample(tif,ndir,dir,tag,value));
+		case SAMPLEFORMAT_INT:
+			if (tif->tif_dir.td_bitspersample<=8)
+				return(TIFFWriteDirectoryTagSbytePerSample(tif,ndir,dir,tag,(int8)value));
+			else if (tif->tif_dir.td_bitspersample<=16)
+				return(TIFFWriteDirectoryTagSshortPerSample(tif,ndir,dir,tag,(int16)value));
+			else
+				return(TIFFWriteDirectoryTagSlongPerSample(tif,ndir,dir,tag,(int32)value));
+		case SAMPLEFORMAT_UINT:
+			if (tif->tif_dir.td_bitspersample<=8)
+				return(TIFFWriteDirectoryTagBytePerSample(tif,ndir,dir,tag,(uint8)value));
+			else if (tif->tif_dir.td_bitspersample<=16)
+				return(TIFFWriteDirectoryTagShortPerSample(tif,ndir,dir,tag,(uint16)value));
+			else
+				return(TIFFWriteDirectoryTagLongPerSample(tif,ndir,dir,tag,(uint32)value));
+		default:
+			return(1);
+	}
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedAscii(tif,ndir,dir,tag,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedUndefinedArray(tif,ndir,dir,tag,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedByte(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagBytePerSample";
+	uint8* m;
+	uint8* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint8));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSbyte(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSbytePerSample";
+	int8* m;
+	int8* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int8));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,value));
+}
+
+static int
+TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagShortPerSample";
+	uint16* m;
+	uint16* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint16));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSshort(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSshortPerSample";
+	int16* m;
+	int16* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int16));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value));
+}
+
+static int
+TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagLongPerSample";
+	uint32* m;
+	uint32* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint32));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSlong(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSlongPerSample";
+	int32* m;
+	int32* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int32));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedLong8(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSlong8(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSlong8Array(tif,ndir,dir,tag,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedRational(tif,ndir,dir,tag,value));
+}
+
+static int
+TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedRationalArray(tif,ndir,dir,tag,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSrationalArray(tif,ndir,dir,tag,count,value));
+}
+
+#ifdef notdef
+static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedFloat(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagFloatPerSample";
+	float* m;
+	float* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(float));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+#ifdef notdef
+static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedDouble(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagDoublePerSample";
+	double* m;
+	double* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(double));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,tag,count,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	if (value<=0xFFFF)
+		return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,(uint16)value));
+	else
+		return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value));
+}
+
+/************************************************************************/
+/*                TIFFWriteDirectoryTagLongLong8Array()                 */
+/*                                                                      */
+/*      Write out LONG8 array as LONG8 for BigTIFF or LONG for          */
+/*      Classic TIFF with some checking.                                */
+/************************************************************************/
+
+static int
+TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+    static const char module[] = "TIFFWriteDirectoryTagLongLong8Array";
+    uint64* ma;
+    uint32 mb;
+    uint32* p;
+    uint32* q;
+    int o;
+
+    /* is this just a counting pass? */
+    if (dir==NULL)
+    {
+        (*ndir)++;
+        return(1);
+    }
+
+    /* We always write LONG8 for BigTIFF, no checking needed. */
+    if( tif->tif_flags&TIFF_BIGTIFF )
+        return TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,
+                                                      tag,count,value);
+
+    /*
+    ** For classic tiff we want to verify everything is in range for LONG
+    ** and convert to long format.
+    */
+
+    p = _TIFFmalloc(count*sizeof(uint32));
+    if (p==NULL)
+    {
+        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+        return(0);
+    }
+
+    for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
+    {
+        if (*ma>0xFFFFFFFF)
+        {
+            TIFFErrorExt(tif->tif_clientdata,module,
+                         "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file.");
+            _TIFFfree(p);
+            return(0);
+        }
+        *q= (uint32)(*ma);
+    }
+
+    o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p);
+    _TIFFfree(p);
+
+    return(o);
+}
+
+/************************************************************************/
+/*                 TIFFWriteDirectoryTagIfdIfd8Array()                  */
+/*                                                                      */
+/*      Write either IFD8 or IFD array depending on file type.          */
+/************************************************************************/
+
+static int
+TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+    static const char module[] = "TIFFWriteDirectoryTagIfdIfd8Array";
+    uint64* ma;
+    uint32 mb;
+    uint32* p;
+    uint32* q;
+    int o;
+
+    /* is this just a counting pass? */
+    if (dir==NULL)
+    {
+        (*ndir)++;
+        return(1);
+    }
+
+    /* We always write IFD8 for BigTIFF, no checking needed. */
+    if( tif->tif_flags&TIFF_BIGTIFF )
+        return TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,
+                                                     tag,count,value);
+
+    /*
+    ** For classic tiff we want to verify everything is in range for IFD
+    ** and convert to long format.
+    */
+
+    p = _TIFFmalloc(count*sizeof(uint32));
+    if (p==NULL)
+    {
+        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+        return(0);
+    }
+
+    for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
+    {
+        if (*ma>0xFFFFFFFF)
+        {
+            TIFFErrorExt(tif->tif_clientdata,module,
+                         "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file.");
+            _TIFFfree(p);
+            return(0);
+        }
+        *q= (uint32)(*ma);
+    }
+
+    o=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,p);
+    _TIFFfree(p);
+
+    return(o);
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagShortLongLong8Array";
+	uint64* ma;
+	uint32 mb;
+	uint8 n;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	n=0;
+	for (ma=value, mb=0; mb<count; ma++, mb++)
+	{
+		if ((n==0)&&(*ma>0xFFFF))
+			n=1;
+		if ((n==1)&&(*ma>0xFFFFFFFF))
+		{
+			n=2;
+			break;
+		}
+	}
+	if (n==0)
+	{
+		uint16* p;
+		uint16* q;
+		p=_TIFFmalloc(count*sizeof(uint16));
+		if (p==NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			return(0);
+		}
+		for (ma=value, mb=0, q=p; mb<count; ma++, mb++, q++)
+			*q=(uint16)(*ma);
+		o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,p);
+		_TIFFfree(p);
+	}
+	else if (n==1)
+	{
+		uint32* p;
+		uint32* q;
+		p=_TIFFmalloc(count*sizeof(uint32));
+		if (p==NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			return(0);
+		}
+		for (ma=value, mb=0, q=p; mb<count; ma++, mb++, q++)
+			*q=(uint32)(*ma);
+		o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p);
+		_TIFFfree(p);
+	}
+	else
+	{
+		assert(n==2);
+		o=TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value);
+	}
+	return(o);
+}
+#endif
+static int
+TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
+{
+	static const char module[] = "TIFFWriteDirectoryTagColormap";
+	uint32 m;
+	uint16* n;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=(1<<tif->tif_dir.td_bitspersample);
+	n=_TIFFmalloc(3*m*sizeof(uint16));
+	if (n==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	_TIFFmemcpy(&n[0],tif->tif_dir.td_colormap[0],m*sizeof(uint16));
+	_TIFFmemcpy(&n[m],tif->tif_dir.td_colormap[1],m*sizeof(uint16));
+	_TIFFmemcpy(&n[2*m],tif->tif_dir.td_colormap[2],m*sizeof(uint16));
+	o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_COLORMAP,3*m,n);
+	_TIFFfree(n);
+	return(o);
+}
+
+static int
+TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
+{
+	static const char module[] = "TIFFWriteDirectoryTagTransferfunction";
+	uint32 m;
+	uint16 n;
+	uint16* o;
+	int p;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=(1<<tif->tif_dir.td_bitspersample);
+	n=tif->tif_dir.td_samplesperpixel-tif->tif_dir.td_extrasamples;
+	/*
+	 * Check if the table can be written as a single column,
+	 * or if it must be written as 3 columns.  Note that we
+	 * write a 3-column tag if there are 2 samples/pixel and
+	 * a single column of data won't suffice--hmm.
+	 */
+	if (n>3)
+		n=3;
+	if (n==3)
+	{
+		if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16)))
+			n=2;
+	}
+	if (n==2)
+	{
+		if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16)))
+			n=1;
+	}
+	if (n==0)
+		n=1;
+	o=_TIFFmalloc(n*m*sizeof(uint16));
+	if (o==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	_TIFFmemcpy(&o[0],tif->tif_dir.td_transferfunction[0],m*sizeof(uint16));
+	if (n>1)
+		_TIFFmemcpy(&o[m],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16));
+	if (n>2)
+		_TIFFmemcpy(&o[2*m],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16));
+	p=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_TRANSFERFUNCTION,n*m,o);
+	_TIFFfree(o);
+	return(p);
+}
+
+static int
+TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSubifd";
+	uint64 m;
+	int n;
+	if (tif->tif_dir.td_nsubifd==0)
+		return(1);
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=tif->tif_dataoff;
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		uint32* o;
+		uint64* pa;
+		uint32* pb;
+		uint16 p;
+		o=_TIFFmalloc(tif->tif_dir.td_nsubifd*sizeof(uint32));
+		if (o==NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			return(0);
+		}
+		pa=tif->tif_dir.td_subifd;
+		pb=o;
+		for (p=0; p < tif->tif_dir.td_nsubifd; p++)
+		{
+                        assert(pa != 0);
+			assert(*pa <= 0xFFFFFFFFUL);
+			*pb++=(uint32)(*pa++);
+		}
+		n=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,o);
+		_TIFFfree(o);
+	}
+	else
+		n=TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,tif->tif_dir.td_subifd);
+	if (!n)
+		return(0);
+	/*
+	 * Total hack: if this directory includes a SubIFD
+	 * tag then force the next <n> directories to be
+	 * written as ``sub directories'' of this one.  This
+	 * is used to write things like thumbnails and
+	 * image masks that one wants to keep out of the
+	 * normal directory linkage access mechanism.
+	 */
+	tif->tif_flags|=TIFF_INSUBIFD;
+	tif->tif_nsubifd=tif->tif_dir.td_nsubifd;
+	if (tif->tif_dir.td_nsubifd==1)
+		tif->tif_subifdoff=0;
+	else
+		tif->tif_subifdoff=m;
+	return(1);
+}
+
+static int
+TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value)
+{
+	assert(sizeof(char)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_ASCII,count,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
+{
+	assert(sizeof(uint8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_UNDEFINED,count,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
+{
+	assert(sizeof(uint8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,1,1,&value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
+{
+	assert(sizeof(uint8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,count,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
+{
+	assert(sizeof(int8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,1,1,&value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value)
+{
+	assert(sizeof(int8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,count,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
+{
+	uint16 m;
+	assert(sizeof(uint16)==2);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabShort(&m);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,1,2,&m));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value)
+{
+	assert(count<0x80000000);
+	assert(sizeof(uint16)==2);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfShort(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,count,count*2,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
+{
+	int16 m;
+	assert(sizeof(int16)==2);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabShort((uint16*)(&m));
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,1,2,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value)
+{
+	assert(count<0x80000000);
+	assert(sizeof(int16)==2);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfShort((uint16*)value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,count,count*2,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
+{
+	uint32 m;
+	assert(sizeof(uint32)==4);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong(&m);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,1,4,&m));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
+{
+	assert(count<0x40000000);
+	assert(sizeof(uint32)==4);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,count,count*4,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
+{
+	int32 m;
+	assert(sizeof(int32)==4);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong((uint32*)(&m));
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,1,4,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value)
+{
+	assert(count<0x40000000);
+	assert(sizeof(int32)==4);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong((uint32*)value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,count,count*4,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value)
+{
+	uint64 m;
+	assert(sizeof(uint64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong8(&m);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,1,8,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	assert(count<0x20000000);
+	assert(sizeof(uint64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong8(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,count,count*8,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value)
+{
+	int64 m;
+	assert(sizeof(int64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong8((uint64*)(&m));
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,1,8,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value)
+{
+	assert(count<0x20000000);
+	assert(sizeof(int64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong8((uint64*)value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,count,count*8,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	uint32 m[2];
+	assert(value>=0.0);
+	assert(sizeof(uint32)==4);
+	if (value<=0.0)
+	{
+		m[0]=0;
+		m[1]=1;
+	}
+	else if (value==(double)(uint32)value)
+	{
+		m[0]=(uint32)value;
+		m[1]=1;
+	}
+	else if (value<1.0)
+	{
+		m[0]=(uint32)(value*0xFFFFFFFF);
+		m[1]=0xFFFFFFFF;
+	}
+	else
+	{
+		m[0]=0xFFFFFFFF;
+		m[1]=(uint32)(0xFFFFFFFF/value);
+	}
+	if (tif->tif_flags&TIFF_SWAB)
+	{
+		TIFFSwabLong(&m[0]);
+		TIFFSwabLong(&m[1]);
+	}
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,1,8,&m[0]));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagCheckedRationalArray";
+	uint32* m;
+	float* na;
+	uint32* nb;
+	uint32 nc;
+	int o;
+	assert(sizeof(uint32)==4);
+	m=_TIFFmalloc(count*2*sizeof(uint32));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=value, nb=m, nc=0; nc<count; na++, nb+=2, nc++)
+	{
+		if (*na<=0.0)
+		{
+			nb[0]=0;
+			nb[1]=1;
+		}
+		else if (*na==(float)(uint32)(*na))
+		{
+			nb[0]=(uint32)(*na);
+			nb[1]=1;
+		}
+		else if (*na<1.0)
+		{
+			nb[0]=(uint32)((*na)*0xFFFFFFFF);
+			nb[1]=0xFFFFFFFF;
+		}
+		else
+		{
+			nb[0]=0xFFFFFFFF;
+			nb[1]=(uint32)(0xFFFFFFFF/(*na));
+		}
+	}
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong(m,count*2);
+	o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,count,count*8,&m[0]);
+	_TIFFfree(m);
+	return(o);
+}
+
+static int
+TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalArray";
+	int32* m;
+	float* na;
+	int32* nb;
+	uint32 nc;
+	int o;
+	assert(sizeof(int32)==4);
+	m=_TIFFmalloc(count*2*sizeof(int32));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=value, nb=m, nc=0; nc<count; na++, nb+=2, nc++)
+	{
+		if (*na<0.0)
+		{
+			if (*na==(int32)(*na))
+			{
+				nb[0]=(int32)(*na);
+				nb[1]=1;
+			}
+			else if (*na>-1.0)
+			{
+				nb[0]=-(int32)((-*na)*0x7FFFFFFF);
+				nb[1]=0x7FFFFFFF;
+			}
+			else
+			{
+				nb[0]=-0x7FFFFFFF;
+				nb[1]=(int32)(0x7FFFFFFF/(-*na));
+			}
+		}
+		else
+		{
+			if (*na==(int32)(*na))
+			{
+				nb[0]=(int32)(*na);
+				nb[1]=1;
+			}
+			else if (*na<1.0)
+			{
+				nb[0]=(int32)((*na)*0x7FFFFFFF);
+				nb[1]=0x7FFFFFFF;
+			}
+			else
+			{
+				nb[0]=0x7FFFFFFF;
+				nb[1]=(int32)(0x7FFFFFFF/(*na));
+			}
+		}
+	}
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong((uint32*)m,count*2);
+	o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SRATIONAL,count,count*8,&m[0]);
+	_TIFFfree(m);
+	return(o);
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
+{
+	float m;
+	assert(sizeof(float)==4);
+	m=value;
+	TIFFCvtNativeToIEEEFloat(tif,1,&m);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabFloat(&m);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,1,4,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	assert(count<0x40000000);
+	assert(sizeof(float)==4);
+	TIFFCvtNativeToIEEEFloat(tif,count,&value);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfFloat(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,count,count*4,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	double m;
+	assert(sizeof(double)==8);
+	m=value;
+	TIFFCvtNativeToIEEEDouble(tif,1,&m);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabDouble(&m);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,1,8,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value)
+{
+	assert(count<0x20000000);
+	assert(sizeof(double)==8);
+	TIFFCvtNativeToIEEEDouble(tif,count,&value);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfDouble(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,count,count*8,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
+{
+	assert(count<0x40000000);
+	assert(sizeof(uint32)==4);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_IFD,count,count*4,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	assert(count<0x20000000);
+	assert(sizeof(uint64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong8(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_IFD8,count,count*8,value));
+}
+
+static int
+TIFFWriteDirectoryTagData(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data)
+{
+	static const char module[] = "TIFFWriteDirectoryTagData";
+	uint32 m;
+	m=0;
+	while (m<(*ndir))
+	{
+		assert(dir[m].tdir_tag!=tag);
+		if (dir[m].tdir_tag>tag)
+			break;
+		m++;
+	}
+	if (m<(*ndir))
+	{
+		uint32 n;
+		for (n=*ndir; n>m; n--)
+			dir[n]=dir[n-1];
+	}
+	dir[m].tdir_tag=tag;
+	dir[m].tdir_type=datatype;
+	dir[m].tdir_count=count;
+	dir[m].tdir_offset.toff_long8 = 0;
+	if (datalength<=((tif->tif_flags&TIFF_BIGTIFF)?0x8U:0x4U))
+		_TIFFmemcpy(&dir[m].tdir_offset,data,datalength);
+	else
+	{
+		uint64 na,nb;
+		na=tif->tif_dataoff;
+		nb=na+datalength;
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+			nb=(uint32)nb;
+		if ((nb<na)||(nb<datalength))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded");
+			return(0);
+		}
+		if (!SeekOK(tif,na))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data");
+			return(0);
+		}
+		assert(datalength<0x80000000UL);
+		if (!WriteOK(tif,data,(tmsize_t)datalength))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data");
+			return(0);
+		}
+		tif->tif_dataoff=nb;
+		if (tif->tif_dataoff&1)
+			tif->tif_dataoff++;
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			uint32 o;
+			o=(uint32)na;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong(&o);
+			_TIFFmemcpy(&dir[m].tdir_offset,&o,4);
+		}
+		else
+		{
+			dir[m].tdir_offset.toff_long8 = na;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8(&dir[m].tdir_offset.toff_long8);
+		}
+	}
+	(*ndir)++;
+	return(1);
+}
+
+/*
+ * Link the current directory into the directory chain for the file.
+ */
+static int
+TIFFLinkDirectory(TIFF* tif)
+{
+	static const char module[] = "TIFFLinkDirectory";
+
+	tif->tif_diroff = (TIFFSeekFile(tif,0,SEEK_END)+1) &~ 1;
+
+	/*
+	 * Handle SubIFDs
+	 */
+	if (tif->tif_flags & TIFF_INSUBIFD)
+	{
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			uint32 m;
+			m = (uint32)tif->tif_diroff;
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong(&m);
+			(void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
+			if (!WriteOK(tif, &m, 4)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				     "Error writing SubIFD directory link");
+				return (0);
+			}
+			/*
+			 * Advance to the next SubIFD or, if this is
+			 * the last one configured, revert back to the
+			 * normal directory linkage.
+			 */
+			if (--tif->tif_nsubifd)
+				tif->tif_subifdoff += 4;
+			else
+				tif->tif_flags &= ~TIFF_INSUBIFD;
+			return (1);
+		}
+		else
+		{
+			uint64 m;
+			m = tif->tif_diroff;
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&m);
+			(void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
+			if (!WriteOK(tif, &m, 8)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				     "Error writing SubIFD directory link");
+				return (0);
+			}
+			/*
+			 * Advance to the next SubIFD or, if this is
+			 * the last one configured, revert back to the
+			 * normal directory linkage.
+			 */
+			if (--tif->tif_nsubifd)
+				tif->tif_subifdoff += 8;
+			else
+				tif->tif_flags &= ~TIFF_INSUBIFD;
+			return (1);
+		}
+	}
+
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		uint32 m;
+		uint32 nextdir;
+		m = (uint32)(tif->tif_diroff);
+		if (tif->tif_flags & TIFF_SWAB)
+			TIFFSwabLong(&m);
+		if (tif->tif_header.classic.tiff_diroff == 0) {
+			/*
+			 * First directory, overwrite offset in header.
+			 */
+			tif->tif_header.classic.tiff_diroff = (uint32) tif->tif_diroff;
+			(void) TIFFSeekFile(tif,4, SEEK_SET);
+			if (!WriteOK(tif, &m, 4)) {
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+					     "Error writing TIFF header");
+				return (0);
+			}
+			return (1);
+		}
+		/*
+		 * Not the first directory, search to the last and append.
+		 */
+		nextdir = tif->tif_header.classic.tiff_diroff;
+		while(1) {
+			uint16 dircount;
+			uint32 nextnextdir;
+
+			if (!SeekOK(tif, nextdir) ||
+			    !ReadOK(tif, &dircount, 2)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory count");
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&dircount);
+			(void) TIFFSeekFile(tif,
+			    nextdir+2+dircount*12, SEEK_SET);
+			if (!ReadOK(tif, &nextnextdir, 4)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory link");
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong(&nextnextdir);
+			if (nextnextdir==0)
+			{
+				(void) TIFFSeekFile(tif,
+				    nextdir+2+dircount*12, SEEK_SET);
+				if (!WriteOK(tif, &m, 4)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error writing directory link");
+					return (0);
+				}
+				break;
+			}
+			nextdir=nextnextdir;
+		}
+	}
+	else
+	{
+		uint64 m;
+		uint64 nextdir;
+		m = tif->tif_diroff;
+		if (tif->tif_flags & TIFF_SWAB)
+			TIFFSwabLong8(&m);
+		if (tif->tif_header.big.tiff_diroff == 0) {
+			/*
+			 * First directory, overwrite offset in header.
+			 */
+			tif->tif_header.big.tiff_diroff = tif->tif_diroff;
+			(void) TIFFSeekFile(tif,8, SEEK_SET);
+			if (!WriteOK(tif, &m, 8)) {
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+					     "Error writing TIFF header");
+				return (0);
+			}
+			return (1);
+		}
+		/*
+		 * Not the first directory, search to the last and append.
+		 */
+		nextdir = tif->tif_header.big.tiff_diroff;
+		while(1) {
+			uint64 dircount64;
+			uint16 dircount;
+			uint64 nextnextdir;
+
+			if (!SeekOK(tif, nextdir) ||
+			    !ReadOK(tif, &dircount64, 8)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory count");
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>0xFFFF)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Sanity check on tag count failed, likely corrupt TIFF");
+				return (0);
+			}
+			dircount=(uint16)dircount64;
+			(void) TIFFSeekFile(tif,
+			    nextdir+8+dircount*20, SEEK_SET);
+			if (!ReadOK(tif, &nextnextdir, 8)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory link");
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&nextnextdir);
+			if (nextnextdir==0)
+			{
+				(void) TIFFSeekFile(tif,
+				    nextdir+8+dircount*20, SEEK_SET);
+				if (!WriteOK(tif, &m, 8)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error writing directory link");
+					return (0);
+				}
+				break;
+			}
+			nextdir=nextnextdir;
+		}
+	}
+	return (1);
+}
+
+/************************************************************************/
+/*                          TIFFRewriteField()                          */
+/*                                                                      */
+/*      Rewrite a field in the directory on disk without regard to      */
+/*      updating the TIFF directory structure in memory.  Currently     */
+/*      only supported for field that already exist in the on-disk      */
+/*      directory.  Mainly used for updating stripoffset /              */
+/*      stripbytecount values after the directory is already on         */
+/*      disk.                                                           */
+/*                                                                      */
+/*      Returns zero on failure, and one on success.                    */
+/************************************************************************/
+
+int
+_TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype, 
+                  tmsize_t count, void* data)
+{
+    static const char module[] = "TIFFResetField";
+    /* const TIFFField* fip = NULL; */
+    uint16 dircount;
+    tmsize_t dirsize;
+    uint8 direntry_raw[20];
+    uint16 entry_tag = 0;
+    uint16 entry_type = 0;
+    uint64 entry_count = 0;
+    uint64 entry_offset = 0;
+    int    value_in_entry = 0;
+    uint64 read_offset;
+    uint8 *buf_to_write = NULL;
+    TIFFDataType datatype;
+
+/* -------------------------------------------------------------------- */
+/*      Find field definition.                                          */
+/* -------------------------------------------------------------------- */
+    /*fip =*/ TIFFFindField(tif, tag, TIFF_ANY);
+
+/* -------------------------------------------------------------------- */
+/*      Do some checking this is a straight forward case.               */
+/* -------------------------------------------------------------------- */
+    if( isMapped(tif) )
+    {
+        TIFFErrorExt( tif->tif_clientdata, module, 
+                      "Memory mapped files not currently supported for this operation." );
+        return 0;
+    }
+
+    if( tif->tif_diroff == 0 )
+    {
+        TIFFErrorExt( tif->tif_clientdata, module, 
+                      "Attempt to reset field on directory not already on disk." );
+        return 0;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Read the directory entry count.                                 */
+/* -------------------------------------------------------------------- */
+    if (!SeekOK(tif, tif->tif_diroff)) {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                     "%s: Seek error accessing TIFF directory",
+                     tif->tif_name);
+        return 0;
+    }
+
+    read_offset = tif->tif_diroff;
+
+    if (!(tif->tif_flags&TIFF_BIGTIFF))
+    {
+        if (!ReadOK(tif, &dircount, sizeof (uint16))) {
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "%s: Can not read TIFF directory count",
+                         tif->tif_name);
+            return 0;
+        }
+        if (tif->tif_flags & TIFF_SWAB)
+            TIFFSwabShort(&dircount);
+        dirsize = 12;
+        read_offset += 2;
+    } else {
+        uint64 dircount64;
+        if (!ReadOK(tif, &dircount64, sizeof (uint64))) {
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "%s: Can not read TIFF directory count",
+                         tif->tif_name);
+            return 0;
+        }
+        if (tif->tif_flags & TIFF_SWAB)
+            TIFFSwabLong8(&dircount64);
+        dircount = (uint16)dircount64;
+        dirsize = 20;
+        read_offset += 8;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Read through directory to find target tag.                      */
+/* -------------------------------------------------------------------- */
+    while( dircount > 0 )
+    {
+        if (!ReadOK(tif, direntry_raw, dirsize)) {
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "%s: Can not read TIFF directory entry.",
+                         tif->tif_name);
+            return 0;
+        }
+
+        memcpy( &entry_tag, direntry_raw + 0, sizeof(uint16) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabShort( &entry_tag );
+
+        if( entry_tag == tag )
+            break;
+
+        read_offset += dirsize;
+    }
+
+    if( entry_tag != tag )
+    {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                     "%s: Could not find tag %d.",
+                     tif->tif_name, tag );
+        return 0;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Extract the type, count and offset for this entry.              */
+/* -------------------------------------------------------------------- */
+    memcpy( &entry_type, direntry_raw + 2, sizeof(uint16) );
+    if (tif->tif_flags&TIFF_SWAB)
+        TIFFSwabShort( &entry_type );
+
+    if (!(tif->tif_flags&TIFF_BIGTIFF))
+    {
+        uint32 value;
+        
+        memcpy( &value, direntry_raw + 4, sizeof(uint32) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong( &value );
+        entry_count = value;
+
+        memcpy( &value, direntry_raw + 8, sizeof(uint32) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong( &value );
+        entry_offset = value;
+    }
+    else
+    {
+        memcpy( &entry_count, direntry_raw + 4, sizeof(uint64) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong8( &entry_count );
+
+        memcpy( &entry_offset, direntry_raw + 12, sizeof(uint64) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong8( &entry_offset );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      What data type do we want to write this as?                     */
+/* -------------------------------------------------------------------- */
+    if( TIFFDataWidth(in_datatype) == 8 && !(tif->tif_flags&TIFF_BIGTIFF) )
+    {
+        if( in_datatype == TIFF_LONG8 )
+            datatype = TIFF_LONG;
+        else if( in_datatype == TIFF_SLONG8 )
+            datatype = TIFF_SLONG;
+        else if( in_datatype == TIFF_IFD8 )
+            datatype = TIFF_IFD;
+        else
+            datatype = in_datatype;
+    }
+    else 
+        datatype = in_datatype;
+
+/* -------------------------------------------------------------------- */
+/*      Prepare buffer of actual data to write.  This includes          */
+/*      swabbing as needed.                                             */
+/* -------------------------------------------------------------------- */
+    buf_to_write =
+	    (uint8 *)_TIFFCheckMalloc(tif, count, TIFFDataWidth(datatype),
+				      "for field buffer.");
+    if (!buf_to_write)
+        return 0;
+
+    if( datatype == in_datatype )
+        memcpy( buf_to_write, data, count * TIFFDataWidth(datatype) );
+    else if( datatype == TIFF_SLONG && in_datatype == TIFF_SLONG8 )
+    {
+	tmsize_t i;
+
+        for( i = 0; i < count; i++ )
+        {
+            ((int32 *) buf_to_write)[i] = 
+                (int32) ((int64 *) data)[i];
+            if( (int64) ((int32 *) buf_to_write)[i] != ((int64 *) data)[i] )
+            {
+                _TIFFfree( buf_to_write );
+                TIFFErrorExt( tif->tif_clientdata, module, 
+                              "Value exceeds 32bit range of output type." );
+                return 0;
+            }
+        }
+    }
+    else if( (datatype == TIFF_LONG && in_datatype == TIFF_LONG8)
+             || (datatype == TIFF_IFD && in_datatype == TIFF_IFD8) )
+    {
+	tmsize_t i;
+
+        for( i = 0; i < count; i++ )
+        {
+            ((uint32 *) buf_to_write)[i] = 
+                (uint32) ((uint64 *) data)[i];
+            if( (uint64) ((uint32 *) buf_to_write)[i] != ((uint64 *) data)[i] )
+            {
+                _TIFFfree( buf_to_write );
+                TIFFErrorExt( tif->tif_clientdata, module, 
+                              "Value exceeds 32bit range of output type." );
+                return 0;
+            }
+        }
+    }
+
+    if( TIFFDataWidth(datatype) > 1 && (tif->tif_flags&TIFF_SWAB) )
+    {
+        if( TIFFDataWidth(datatype) == 2 )
+            TIFFSwabArrayOfShort( (uint16 *) buf_to_write, count );
+        else if( TIFFDataWidth(datatype) == 4 )
+            TIFFSwabArrayOfLong( (uint32 *) buf_to_write, count );
+        else if( TIFFDataWidth(datatype) == 8 )
+            TIFFSwabArrayOfLong8( (uint64 *) buf_to_write, count );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Is this a value that fits into the directory entry?             */
+/* -------------------------------------------------------------------- */
+    if (!(tif->tif_flags&TIFF_BIGTIFF))
+    {
+        if( TIFFDataWidth(datatype) * count <= 4 )
+        {
+            entry_offset = read_offset + 8;
+            value_in_entry = 1;
+        }
+    }
+    else
+    {
+        if( TIFFDataWidth(datatype) * count <= 8 )
+        {
+            entry_offset = read_offset + 12;
+            value_in_entry = 1;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If the tag type, and count match, then we just write it out     */
+/*      over the old values without altering the directory entry at     */
+/*      all.                                                            */
+/* -------------------------------------------------------------------- */
+    if( entry_count == (uint64)count && entry_type == (uint16) datatype )
+    {
+        if (!SeekOK(tif, entry_offset)) {
+            _TIFFfree( buf_to_write );
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "%s: Seek error accessing TIFF directory",
+                         tif->tif_name);
+            return 0;
+        }
+        if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) {
+            _TIFFfree( buf_to_write );
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "Error writing directory link");
+            return (0);
+        }
+
+        _TIFFfree( buf_to_write );
+        return 1;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Otherwise, we write the new tag data at the end of the file.    */
+/* -------------------------------------------------------------------- */
+    if( !value_in_entry )
+    {
+        entry_offset = TIFFSeekFile(tif,0,SEEK_END);
+        
+        if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) {
+            _TIFFfree( buf_to_write );
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "Error writing directory link");
+            return (0);
+        }
+        
+        _TIFFfree( buf_to_write );
+    }
+    else
+    {
+        memcpy( &entry_offset, buf_to_write, count*TIFFDataWidth(datatype));
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Adjust the directory entry.                                     */
+/* -------------------------------------------------------------------- */
+    entry_type = datatype;
+    memcpy( direntry_raw + 2, &entry_type, sizeof(uint16) );
+    if (tif->tif_flags&TIFF_SWAB)
+        TIFFSwabShort( (uint16 *) (direntry_raw + 2) );
+
+    if (!(tif->tif_flags&TIFF_BIGTIFF))
+    {
+        uint32 value;
+
+        value = (uint32) entry_count;
+        memcpy( direntry_raw + 4, &value, sizeof(uint32) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong( (uint32 *) (direntry_raw + 4) );
+
+        value = (uint32) entry_offset;
+        memcpy( direntry_raw + 8, &value, sizeof(uint32) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong( (uint32 *) (direntry_raw + 8) );
+    }
+    else
+    {
+        memcpy( direntry_raw + 4, &entry_count, sizeof(uint64) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong8( (uint64 *) (direntry_raw + 4) );
+
+        memcpy( direntry_raw + 12, &entry_offset, sizeof(uint64) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong8( (uint64 *) (direntry_raw + 12) );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Write the directory entry out to disk.                          */
+/* -------------------------------------------------------------------- */
+    if (!SeekOK(tif, read_offset )) {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                     "%s: Seek error accessing TIFF directory",
+                     tif->tif_name);
+        return 0;
+    }
+
+    if (!WriteOK(tif, direntry_raw,dirsize))
+    {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                     "%s: Can not write TIFF directory entry.",
+                     tif->tif_name);
+        return 0;
+    }
+    
+    return 1;
+}
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dumpmode.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dumpmode.c
new file mode 100644
index 0000000..78ab03f
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dumpmode.c
@@ -0,0 +1,146 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_dumpmode.c,v 1.14 2011-04-02 20:54:09 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * "Null" Compression Algorithm Support.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+static int
+DumpFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+/*
+ * Encode a hunk of pixels.
+ */
+static int
+DumpModeEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) s;
+	while (cc > 0) {
+		tmsize_t n;
+
+		n = cc;
+		if (tif->tif_rawcc + n > tif->tif_rawdatasize)
+			n = tif->tif_rawdatasize - tif->tif_rawcc;
+
+		assert( n > 0 );
+
+		/*
+		 * Avoid copy if client has setup raw
+		 * data buffer to avoid extra copy.
+		 */
+		if (tif->tif_rawcp != pp)
+			_TIFFmemcpy(tif->tif_rawcp, pp, n);
+		tif->tif_rawcp += n;
+		tif->tif_rawcc += n;
+		pp += n;
+		cc -= n;
+		if (tif->tif_rawcc >= tif->tif_rawdatasize &&
+		    !TIFFFlushData1(tif))
+			return (-1);
+	}
+	return (1);
+}
+
+/*
+ * Decode a hunk of pixels.
+ */
+static int
+DumpModeDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "DumpModeDecode";
+	(void) s;
+	if (tif->tif_rawcc < cc) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+"Not enough data for scanline %lu, expected a request for at most %I64d bytes, got a request for %I64d bytes",
+		             (unsigned long) tif->tif_row,
+		             (signed __int64) tif->tif_rawcc,
+		             (signed __int64) cc);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+"Not enough data for scanline %lu, expected a request for at most %lld bytes, got a request for %lld bytes",
+		             (unsigned long) tif->tif_row,
+		             (signed long long) tif->tif_rawcc,
+		             (signed long long) cc);
+#endif
+		return (0);
+	}
+	/*
+	 * Avoid copy if client has setup raw
+	 * data buffer to avoid extra copy.
+	 */
+	if (tif->tif_rawcp != buf)
+		_TIFFmemcpy(buf, tif->tif_rawcp, cc);
+	tif->tif_rawcp += cc;
+	tif->tif_rawcc -= cc;  
+	return (1);
+}
+
+/*
+ * Seek forwards nrows in the current strip.
+ */
+static int
+DumpModeSeek(TIFF* tif, uint32 nrows)
+{
+	tif->tif_rawcp += nrows * tif->tif_scanlinesize;
+	tif->tif_rawcc -= nrows * tif->tif_scanlinesize;
+	return (1);
+}
+
+/*
+ * Initialize dump mode.
+ */
+int
+TIFFInitDumpMode(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	tif->tif_fixuptags = DumpFixupTags;  
+	tif->tif_decoderow = DumpModeDecode;
+	tif->tif_decodestrip = DumpModeDecode;
+	tif->tif_decodetile = DumpModeDecode;
+	tif->tif_encoderow = DumpModeEncode;
+	tif->tif_encodestrip = DumpModeEncode;
+	tif->tif_encodetile = DumpModeEncode; 
+	tif->tif_seek = DumpModeSeek;
+	return (1);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_error.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_error.c
new file mode 100644
index 0000000..3a478c3
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_error.c
@@ -0,0 +1,85 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_error.c,v 1.5 2010-03-10 18:56:48 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+/*TIFFErrorHandlerExt _TIFFerrorHandlerExt = NULL;*/
+/* Modify here for use _TIFFerrorHandlerExt by Sunliang.Liu 20090715 */
+TIFFErrorHandler _TIFFerrorHandler = NULL;
+
+TIFFErrorHandler
+TIFFSetErrorHandler(TIFFErrorHandler handler)
+{
+	TIFFErrorHandler prev = _TIFFerrorHandler;
+	_TIFFerrorHandler = handler;
+	return (prev);
+}
+
+TIFFErrorHandlerExt
+TIFFSetErrorHandlerExt(TIFFErrorHandlerExt handler)
+{
+	TIFFErrorHandlerExt prev = _TIFFerrorHandlerExt;
+	_TIFFerrorHandlerExt = handler;
+	return (prev);
+}
+
+void
+TIFFError(const char* module, const char* fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	if (_TIFFerrorHandler)
+		(*_TIFFerrorHandler)(module, fmt, ap);
+	if (_TIFFerrorHandlerExt)
+		(*_TIFFerrorHandlerExt)(0, module, fmt, ap);
+	va_end(ap);
+}
+
+void
+TIFFErrorExt(thandle_t fd, const char* module, const char* fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	if (_TIFFerrorHandler)
+		(*_TIFFerrorHandler)(module, fmt, ap);
+	if (_TIFFerrorHandlerExt)
+		(*_TIFFerrorHandlerExt)(fd, module, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_extension.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_extension.c
new file mode 100644
index 0000000..474cd79
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_extension.c
@@ -0,0 +1,120 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_extension.c,v 1.7 2010-03-10 18:56:48 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Various routines support external extension of the tag set, and other
+ * application extension capabilities. 
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+int TIFFGetTagListCount( TIFF *tif )
+
+{
+    TIFFDirectory* td = &tif->tif_dir;
+    
+    return td->td_customValueCount;
+}
+
+uint32 TIFFGetTagListEntry( TIFF *tif, int tag_index )
+
+{
+    TIFFDirectory* td = &tif->tif_dir;
+
+    if( tag_index < 0 || tag_index >= td->td_customValueCount )
+        return (uint32)(-1);
+    else
+        return td->td_customValues[tag_index].info->field_tag;
+}
+
+/*
+** This provides read/write access to the TIFFTagMethods within the TIFF
+** structure to application code without giving access to the private
+** TIFF structure.
+*/
+TIFFTagMethods *TIFFAccessTagMethods( TIFF *tif )
+
+{
+    return &(tif->tif_tagmethods);
+}
+
+void *TIFFGetClientInfo( TIFF *tif, const char *name )
+
+{
+    TIFFClientInfoLink *link = tif->tif_clientinfo;
+
+    while( link != NULL && strcmp(link->name,name) != 0 )
+        link = link->next;
+
+    if( link != NULL )
+        return link->data;
+    else
+        return NULL;
+}
+
+void TIFFSetClientInfo( TIFF *tif, void *data, const char *name )
+
+{
+    TIFFClientInfoLink *link = tif->tif_clientinfo;
+
+    /*
+    ** Do we have an existing link with this name?  If so, just
+    ** set it.
+    */
+    while( link != NULL && strcmp(link->name,name) != 0 )
+        link = link->next;
+
+    if( link != NULL )
+    {
+        link->data = data;
+        return;
+    }
+
+    /*
+    ** Create a new link.
+    */
+
+    link = (TIFFClientInfoLink *) _TIFFmalloc(sizeof(TIFFClientInfoLink));
+    assert (link != NULL);
+    link->next = tif->tif_clientinfo;
+    link->name = (char *) _TIFFmalloc((tmsize_t)(strlen(name)+1));
+    assert (link->name != NULL);
+    strcpy(link->name, name);
+    link->data = data;
+
+    tif->tif_clientinfo = link;
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.c
new file mode 100644
index 0000000..986a3f4
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.c
@@ -0,0 +1,1625 @@
+/* $Id: tif_fax3.c,v 1.74 2012-06-21 02:01:31 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#ifdef CCITT_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * CCITT Group 3 (T.4) and Group 4 (T.6) Compression Support.
+ *
+ * This file contains support for decoding and encoding TIFF
+ * compression algorithms 2, 3, 4, and 32771.
+ *
+ * Decoder support is derived, with permission, from the code
+ * in Frank Cringle's viewfax program;
+ *      Copyright (C) 1990, 1995  Frank D. Cringle.
+ */
+#include "tif_fax3.h"
+#define	G3CODES
+#include "t4.h"
+#include <stdio.h>
+
+/*
+ * Compression+decompression state blocks are
+ * derived from this ``base state'' block.
+ */
+typedef struct {
+	int      rw_mode;                /* O_RDONLY for decode, else encode */
+	int      mode;                   /* operating mode */
+	tmsize_t rowbytes;               /* bytes in a decoded scanline */
+	uint32   rowpixels;              /* pixels in a scanline */
+
+	uint16   cleanfaxdata;           /* CleanFaxData tag */
+	uint32   badfaxrun;              /* BadFaxRun tag */
+	uint32   badfaxlines;            /* BadFaxLines tag */
+	uint32   groupoptions;           /* Group 3/4 options tag */
+
+	TIFFVGetMethod  vgetparent;      /* super-class method */
+	TIFFVSetMethod  vsetparent;      /* super-class method */
+	TIFFPrintMethod printdir;        /* super-class method */
+} Fax3BaseState;
+#define	Fax3State(tif)		((Fax3BaseState*) (tif)->tif_data)
+
+typedef enum { G3_1D, G3_2D } Ttag;
+typedef struct {
+	Fax3BaseState b;
+
+	/* Decoder state info */
+	const unsigned char* bitmap;	/* bit reversal table */
+	uint32	data;			/* current i/o byte/word */
+	int	bit;			/* current i/o bit in byte */
+	int	EOLcnt;			/* count of EOL codes recognized */
+	TIFFFaxFillFunc fill;		/* fill routine */
+	uint32*	runs;			/* b&w runs for current/previous row */
+	uint32*	refruns;		/* runs for reference line */
+	uint32*	curruns;		/* runs for current line */
+
+	/* Encoder state info */
+	Ttag    tag;			/* encoding state */
+	unsigned char*	refline;	/* reference line for 2d decoding */
+	int	k;			/* #rows left that can be 2d encoded */
+	int	maxk;			/* max #rows that can be 2d encoded */
+
+	int line;
+} Fax3CodecState;
+#define DecoderState(tif) ((Fax3CodecState*) Fax3State(tif))
+#define EncoderState(tif) ((Fax3CodecState*) Fax3State(tif))
+
+#define is2DEncoding(sp) (sp->b.groupoptions & GROUP3OPT_2DENCODING)
+#define isAligned(p,t) ((((size_t)(p)) & (sizeof (t)-1)) == 0)
+
+/*
+ * Group 3 and Group 4 Decoding.
+ */
+
+/*
+ * These macros glue the TIFF library state to
+ * the state expected by Frank's decoder.
+ */
+#define	DECLARE_STATE(tif, sp, mod)					\
+    static const char module[] = mod;					\
+    Fax3CodecState* sp = DecoderState(tif);				\
+    int a0;				/* reference element */		\
+    int lastx = sp->b.rowpixels;	/* last element in row */	\
+    uint32 BitAcc;			/* bit accumulator */		\
+    int BitsAvail;			/* # valid bits in BitAcc */	\
+    int RunLength;			/* length of current run */	\
+    unsigned char* cp;			/* next byte of input data */	\
+    unsigned char* ep;			/* end of input data */		\
+    uint32* pa;				/* place to stuff next run */	\
+    uint32* thisrun;			/* current row's run array */	\
+    int EOLcnt;				/* # EOL codes recognized */	\
+    const unsigned char* bitmap = sp->bitmap;	/* input data bit reverser */	\
+    const TIFFFaxTabEnt* TabEnt
+#define	DECLARE_STATE_2D(tif, sp, mod)					\
+    DECLARE_STATE(tif, sp, mod);					\
+    int b1;				/* next change on prev line */	\
+    uint32* pb				/* next run in reference line */\
+/*
+ * Load any state that may be changed during decoding.
+ */
+#define	CACHE_STATE(tif, sp) do {					\
+    BitAcc = sp->data;							\
+    BitsAvail = sp->bit;						\
+    EOLcnt = sp->EOLcnt;						\
+    cp = (unsigned char*) tif->tif_rawcp;				\
+    ep = cp + tif->tif_rawcc;						\
+} while (0)
+/*
+ * Save state possibly changed during decoding.
+ */
+#define	UNCACHE_STATE(tif, sp) do {					\
+    sp->bit = BitsAvail;						\
+    sp->data = BitAcc;							\
+    sp->EOLcnt = EOLcnt;						\
+    tif->tif_rawcc -= (tmsize_t)((uint8*) cp - tif->tif_rawcp);		\
+    tif->tif_rawcp = (uint8*) cp;					\
+} while (0)
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+Fax3PreDecode(TIFF* tif, uint16 s)
+{
+	Fax3CodecState* sp = DecoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	sp->bit = 0;			/* force initial read */
+	sp->data = 0;
+	sp->EOLcnt = 0;			/* force initial scan for EOL */
+	/*
+	 * Decoder assumes lsb-to-msb bit order.  Note that we select
+	 * this here rather than in Fax3SetupState so that viewers can
+	 * hold the image open, fiddle with the FillOrder tag value,
+	 * and then re-decode the image.  Otherwise they'd need to close
+	 * and open the image to get the state reset.
+	 */
+	sp->bitmap =
+	    TIFFGetBitRevTable(tif->tif_dir.td_fillorder != FILLORDER_LSB2MSB);
+	if (sp->refruns) {		/* init reference line to white */
+		sp->refruns[0] = (uint32) sp->b.rowpixels;
+		sp->refruns[1] = 0;
+	}
+	sp->line = 0;
+	return (1);
+}
+
+/*
+ * Routine for handling various errors/conditions.
+ * Note how they are "glued into the decoder" by
+ * overriding the definitions used by the decoder.
+ */
+
+static void
+Fax3Unexpected(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+	TIFFErrorExt(tif->tif_clientdata, module, "Bad code word at line %u of %s %u (x %u)",
+	    line, isTiled(tif) ? "tile" : "strip",
+	    (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+	    a0);
+}
+#define	unexpected(table, a0)	Fax3Unexpected(module, tif, sp->line, a0)
+
+static void
+Fax3Extension(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+	TIFFErrorExt(tif->tif_clientdata, module,
+	    "Uncompressed data (not supported) at line %u of %s %u (x %u)",
+	    line, isTiled(tif) ? "tile" : "strip",
+	    (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+	    a0);
+}
+#define	extension(a0)	Fax3Extension(module, tif, sp->line, a0)
+
+static void
+Fax3BadLength(const char* module, TIFF* tif, uint32 line, uint32 a0, uint32 lastx)
+{
+	TIFFWarningExt(tif->tif_clientdata, module, "%s at line %u of %s %u (got %u, expected %u)",
+	    a0 < lastx ? "Premature EOL" : "Line length mismatch",
+	    line, isTiled(tif) ? "tile" : "strip",
+	    (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+	    a0, lastx);
+}
+#define	badlength(a0,lastx)	Fax3BadLength(module, tif, sp->line, a0, lastx)
+
+static void
+Fax3PrematureEOF(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+	TIFFWarningExt(tif->tif_clientdata, module, "Premature EOF at line %u of %s %u (x %u)",
+	    line, isTiled(tif) ? "tile" : "strip",
+	    (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+	    a0);
+}
+#define	prematureEOF(a0)	Fax3PrematureEOF(module, tif, sp->line, a0)
+
+#define	Nop
+
+/*
+ * Decode the requested amount of G3 1D-encoded data.
+ */
+static int
+Fax3Decode1D(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	DECLARE_STATE(tif, sp, "Fax3Decode1D");
+	(void) s;
+	if (occ % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (-1);
+	}
+	CACHE_STATE(tif, sp);
+	thisrun = sp->curruns;
+	while (occ > 0) {
+		a0 = 0;
+		RunLength = 0;
+		pa = thisrun;
+#ifdef FAX3_DEBUG
+		printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail);
+		printf("-------------------- %d\n", tif->tif_row);
+		fflush(stdout);
+#endif
+		SYNC_EOL(EOF1D);
+		EXPAND1D(EOF1Da);
+		(*sp->fill)(buf, thisrun, pa, lastx);
+		buf += sp->b.rowbytes;
+		occ -= sp->b.rowbytes;
+		sp->line++;
+		continue;
+	EOF1D:				/* premature EOF */
+		CLEANUP_RUNS();
+	EOF1Da:				/* premature EOF */
+		(*sp->fill)(buf, thisrun, pa, lastx);
+		UNCACHE_STATE(tif, sp);
+		return (-1);
+	}
+	UNCACHE_STATE(tif, sp);
+	return (1);
+}
+
+#define	SWAP(t,a,b)	{ t x; x = (a); (a) = (b); (b) = x; }
+/*
+ * Decode the requested amount of G3 2D-encoded data.
+ */
+static int
+Fax3Decode2D(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	DECLARE_STATE_2D(tif, sp, "Fax3Decode2D");
+	int is1D;			/* current line is 1d/2d-encoded */
+	(void) s;
+	if (occ % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (-1);
+	}
+	CACHE_STATE(tif, sp);
+	while (occ > 0) {
+		a0 = 0;
+		RunLength = 0;
+		pa = thisrun = sp->curruns;
+#ifdef FAX3_DEBUG
+		printf("\nBitAcc=%08X, BitsAvail = %d EOLcnt = %d",
+		    BitAcc, BitsAvail, EOLcnt);
+#endif
+		SYNC_EOL(EOF2D);
+		NeedBits8(1, EOF2D);
+		is1D = GetBits(1);	/* 1D/2D-encoding tag bit */
+		ClrBits(1);
+#ifdef FAX3_DEBUG
+		printf(" %s\n-------------------- %d\n",
+		    is1D ? "1D" : "2D", tif->tif_row);
+		fflush(stdout);
+#endif
+		pb = sp->refruns;
+		b1 = *pb++;
+		if (is1D)
+			EXPAND1D(EOF2Da);
+		else
+			EXPAND2D(EOF2Da);
+		(*sp->fill)(buf, thisrun, pa, lastx);
+		SETVALUE(0);		/* imaginary change for reference */
+		SWAP(uint32*, sp->curruns, sp->refruns);
+		buf += sp->b.rowbytes;
+		occ -= sp->b.rowbytes;
+		sp->line++;
+		continue;
+	EOF2D:				/* premature EOF */
+		CLEANUP_RUNS();
+	EOF2Da:				/* premature EOF */
+		(*sp->fill)(buf, thisrun, pa, lastx);
+		UNCACHE_STATE(tif, sp);
+		return (-1);
+	}
+	UNCACHE_STATE(tif, sp);
+	return (1);
+}
+#undef SWAP
+
+/*
+ * The ZERO & FILL macros must handle spans < 2*sizeof(long) bytes.
+ * For machines with 64-bit longs this is <16 bytes; otherwise
+ * this is <8 bytes.  We optimize the code here to reflect the
+ * machine characteristics.
+ */
+#if SIZEOF_UNSIGNED_LONG == 8
+# define FILL(n, cp)							    \
+    switch (n) {							    \
+    case 15:(cp)[14] = 0xff; case 14:(cp)[13] = 0xff; case 13: (cp)[12] = 0xff;\
+    case 12:(cp)[11] = 0xff; case 11:(cp)[10] = 0xff; case 10: (cp)[9] = 0xff;\
+    case  9: (cp)[8] = 0xff; case  8: (cp)[7] = 0xff; case  7: (cp)[6] = 0xff;\
+    case  6: (cp)[5] = 0xff; case  5: (cp)[4] = 0xff; case  4: (cp)[3] = 0xff;\
+    case  3: (cp)[2] = 0xff; case  2: (cp)[1] = 0xff;			      \
+    case  1: (cp)[0] = 0xff; (cp) += (n); case 0:  ;			      \
+    }
+# define ZERO(n, cp)							\
+    switch (n) {							\
+    case 15:(cp)[14] = 0; case 14:(cp)[13] = 0; case 13: (cp)[12] = 0;	\
+    case 12:(cp)[11] = 0; case 11:(cp)[10] = 0; case 10: (cp)[9] = 0;	\
+    case  9: (cp)[8] = 0; case  8: (cp)[7] = 0; case  7: (cp)[6] = 0;	\
+    case  6: (cp)[5] = 0; case  5: (cp)[4] = 0; case  4: (cp)[3] = 0;	\
+    case  3: (cp)[2] = 0; case  2: (cp)[1] = 0;				\
+    case  1: (cp)[0] = 0; (cp) += (n); case 0:  ;			\
+    }
+#else
+# define FILL(n, cp)							    \
+    switch (n) {							    \
+    case 7: (cp)[6] = 0xff; case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; \
+    case 4: (cp)[3] = 0xff; case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \
+    case 1: (cp)[0] = 0xff; (cp) += (n); case 0:  ;			    \
+    }
+# define ZERO(n, cp)							\
+    switch (n) {							\
+    case 7: (cp)[6] = 0; case 6: (cp)[5] = 0; case 5: (cp)[4] = 0;	\
+    case 4: (cp)[3] = 0; case 3: (cp)[2] = 0; case 2: (cp)[1] = 0;	\
+    case 1: (cp)[0] = 0; (cp) += (n); case 0:  ;			\
+    }
+#endif
+
+/*
+ * Bit-fill a row according to the white/black
+ * runs generated during G3/G4 decoding.
+ */
+void
+_TIFFFax3fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
+{
+	static const unsigned char _fillmasks[] =
+	    { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+	unsigned char* cp;
+	uint32 x, bx, run,bx_;/* add bx_ = 8-bx for avoid ms evc compiler bug*/
+	int32 n, nw;
+	long* lp;
+
+	if ((erun-runs)&1)
+	    *erun++ = 0;
+	x = 0;
+	for (; runs < erun; runs += 2) {
+	    run = runs[0];
+	    if (x+run > lastx || run > lastx )
+		run = runs[0] = (uint32) (lastx - x);
+	    if (run) {
+		cp = buf + (x>>3);
+		bx = x&7;
+// 		if (run > 8-bx) {
+// 			if (bx) {			/* align to byte boundary */
+// 				*cp++ &= 0xff << (8-bx);
+// 				run -= 8-bx;
+// 		    }
+//Modify by Sunliang.Liu 20090804
+//Detail: For avoid ms evc compiler bug in WCE ARMV4(I) Release
+		bx_ = 8-bx;
+		if (run > bx_) {
+		    if (bx) {			/* align to byte boundary */
+			*cp++ &= 0xff << bx_;
+			run -= bx_;
+		    }
+		    if( (n = run >> 3) != 0 ) {	/* multiple bytes to fill */
+			if ((n/sizeof (long)) > 1) {
+			    /*
+			     * Align to longword boundary and fill.
+			     */
+			    for (; n && !isAligned(cp, long); n--)
+				    *cp++ = 0x00;
+			    lp = (long*) cp;
+			    nw = (int32)(n / sizeof (long));
+			    n -= nw * sizeof (long);
+			    do {
+				    *lp++ = 0L;
+			    } while (--nw);
+			    cp = (unsigned char*) lp;
+			}
+#ifdef FAX3_DEBUG
+			printf("_TIFFFax3fillruns ZERO: %d\n",n);
+#endif
+			ZERO(n, cp);
+			run &= 7;
+		    }
+		    if (run)
+			cp[0] &= 0xff >> run;
+		} else
+		    cp[0] &= ~(_fillmasks[run]>>bx);
+		x += runs[0];
+	    }
+	    run = runs[1];
+	    if (x+run > lastx || run > lastx )
+		run = runs[1] = lastx - x;
+	    if (run) {
+		cp = buf + (x>>3);
+		bx = x&7;
+		if (run > 8-bx) {
+		    if (bx) {			/* align to byte boundary */
+			*cp++ |= 0xff >> bx;
+			run -= 8-bx;
+		    }
+		    if( (n = run>>3) != 0 ) {	/* multiple bytes to fill */
+			if ((n/sizeof (long)) > 1) {
+			    /*
+			     * Align to longword boundary and fill.
+			     */
+			    for (; n && !isAligned(cp, long); n--)
+				*cp++ = 0xff;
+			    lp = (long*) cp;
+			    nw = (int32)(n / sizeof (long));
+			    n -= nw * sizeof (long);
+			    do {
+				*lp++ = -1L;
+			    } while (--nw);
+			    cp = (unsigned char*) lp;
+			}
+#ifdef FAX3_DEBUG
+			printf("_TIFFFax3fillruns FILL: %d\n",n);
+#endif
+			FILL(n, cp);
+			run &= 7;
+		    }
+		    if (run)
+			cp[0] |= 0xff00 >> run;
+		} else
+		    cp[0] |= _fillmasks[run]>>bx;
+		x += runs[1];
+	    }
+	}
+	assert(x == lastx);
+}
+#undef	ZERO
+#undef	FILL
+
+static int
+Fax3FixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+/*
+ * Setup G3/G4-related compression/decompression state
+ * before data is processed.  This routine is called once
+ * per image -- it sets up different state based on whether
+ * or not decoding or encoding is being done and whether
+ * 1D- or 2D-encoded data is involved.
+ */
+static int
+Fax3SetupState(TIFF* tif)
+{
+	static const char module[] = "Fax3SetupState";
+	TIFFDirectory* td = &tif->tif_dir;
+	Fax3BaseState* sp = Fax3State(tif);
+	int needsRefLine;
+	Fax3CodecState* dsp = (Fax3CodecState*) Fax3State(tif);
+	tmsize_t rowbytes;
+	uint32 rowpixels, nruns;
+
+	if (td->td_bitspersample != 1) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Bits/sample must be 1 for Group 3/4 encoding/decoding");
+		return (0);
+	}
+	/*
+	 * Calculate the scanline/tile widths.
+	 */
+	if (isTiled(tif)) {
+		rowbytes = TIFFTileRowSize(tif);
+		rowpixels = td->td_tilewidth;
+	} else {
+		rowbytes = TIFFScanlineSize(tif);
+		rowpixels = td->td_imagewidth;
+	}
+	sp->rowbytes = rowbytes;
+	sp->rowpixels = rowpixels;
+	/*
+	 * Allocate any additional space required for decoding/encoding.
+	 */
+	needsRefLine = (
+	    (sp->groupoptions & GROUP3OPT_2DENCODING) ||
+	    td->td_compression == COMPRESSION_CCITTFAX4
+	);
+
+	/*
+	  Assure that allocation computations do not overflow.
+	  
+	  TIFFroundup and TIFFSafeMultiply return zero on integer overflow
+	*/
+	dsp->runs=(uint32*) NULL;
+	nruns = TIFFroundup_32(rowpixels,32);
+	if (needsRefLine) {
+		nruns = TIFFSafeMultiply(uint32,nruns,2);
+	}
+	if ((nruns == 0) || (TIFFSafeMultiply(uint32,nruns,2) == 0)) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "Row pixels integer overflow (rowpixels %u)",
+			     rowpixels);
+		return (0);
+	}
+	dsp->runs = (uint32*) _TIFFCheckMalloc(tif,
+					       TIFFSafeMultiply(uint32,nruns,2),
+					       sizeof (uint32),
+					       "for Group 3/4 run arrays");
+	if (dsp->runs == NULL)
+		return (0);
+	memset( dsp->runs, 0, TIFFSafeMultiply(uint32,nruns,2)*sizeof(uint32));
+	dsp->curruns = dsp->runs;
+	if (needsRefLine)
+		dsp->refruns = dsp->runs + nruns;
+	else
+		dsp->refruns = NULL;
+	if (td->td_compression == COMPRESSION_CCITTFAX3
+	    && is2DEncoding(dsp)) {	/* NB: default is 1D routine */
+		tif->tif_decoderow = Fax3Decode2D;
+		tif->tif_decodestrip = Fax3Decode2D;
+		tif->tif_decodetile = Fax3Decode2D;
+	}
+
+	if (needsRefLine) {		/* 2d encoding */
+		Fax3CodecState* esp = EncoderState(tif);
+		/*
+		 * 2d encoding requires a scanline
+		 * buffer for the ``reference line''; the
+		 * scanline against which delta encoding
+		 * is referenced.  The reference line must
+		 * be initialized to be ``white'' (done elsewhere).
+		 */
+		esp->refline = (unsigned char*) _TIFFmalloc(rowbytes);
+		if (esp->refline == NULL) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "No space for Group 3/4 reference line");
+			return (0);
+		}
+	} else					/* 1d encoding */
+		EncoderState(tif)->refline = NULL;
+
+	return (1);
+}
+
+/*
+ * CCITT Group 3 FAX Encoding.
+ */
+
+#define	Fax3FlushBits(tif, sp) {				\
+	if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize)		\
+		(void) TIFFFlushData1(tif);			\
+	*(tif)->tif_rawcp++ = (uint8) (sp)->data;		\
+	(tif)->tif_rawcc++;					\
+	(sp)->data = 0, (sp)->bit = 8;				\
+}
+#define	_FlushBits(tif) {					\
+	if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize)		\
+		(void) TIFFFlushData1(tif);			\
+	*(tif)->tif_rawcp++ = (uint8) data;		\
+	(tif)->tif_rawcc++;					\
+	data = 0, bit = 8;					\
+}
+static const int _msbmask[9] =
+    { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+#define	_PutBits(tif, bits, length) {				\
+	while (length > bit) {					\
+		data |= bits >> (length - bit);			\
+		length -= bit;					\
+		_FlushBits(tif);				\
+	}							\
+        assert( length < 9 );                                   \
+	data |= (bits & _msbmask[length]) << (bit - length);	\
+	bit -= length;						\
+	if (bit == 0)						\
+		_FlushBits(tif);				\
+}
+	
+/*
+ * Write a variable-length bit-value to
+ * the output stream.  Values are
+ * assumed to be at most 16 bits.
+ */
+static void
+Fax3PutBits(TIFF* tif, unsigned int bits, unsigned int length)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+	unsigned int bit = sp->bit;
+	int data = sp->data;
+
+	_PutBits(tif, bits, length);
+
+	sp->data = data;
+	sp->bit = bit;
+}
+
+/*
+ * Write a code to the output stream.
+ */
+#define putcode(tif, te)	Fax3PutBits(tif, (te)->code, (te)->length)
+
+#ifdef FAX3_DEBUG
+#define	DEBUG_COLOR(w) (tab == TIFFFaxWhiteCodes ? w "W" : w "B")
+#define	DEBUG_PRINT(what,len) {						\
+    int t;								\
+    printf("%08X/%-2d: %s%5d\t", data, bit, DEBUG_COLOR(what), len);	\
+    for (t = length-1; t >= 0; t--)					\
+	putchar(code & (1<<t) ? '1' : '0');				\
+    putchar('\n');							\
+}
+#endif
+
+/*
+ * Write the sequence of codes that describes
+ * the specified span of zero's or one's.  The
+ * appropriate table that holds the make-up and
+ * terminating codes is supplied.
+ */
+static void
+putspan(TIFF* tif, int32 span, const tableentry* tab)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+	unsigned int bit = sp->bit;
+	int data = sp->data;
+	unsigned int code, length;
+
+	while (span >= 2624) {
+		const tableentry* te = &tab[63 + (2560>>6)];
+		code = te->code, length = te->length;
+#ifdef FAX3_DEBUG
+		DEBUG_PRINT("MakeUp", te->runlen);
+#endif
+		_PutBits(tif, code, length);
+		span -= te->runlen;
+	}
+	if (span >= 64) {
+		const tableentry* te = &tab[63 + (span>>6)];
+		assert(te->runlen == 64*(span>>6));
+		code = te->code, length = te->length;
+#ifdef FAX3_DEBUG
+		DEBUG_PRINT("MakeUp", te->runlen);
+#endif
+		_PutBits(tif, code, length);
+		span -= te->runlen;
+	}
+	code = tab[span].code, length = tab[span].length;
+#ifdef FAX3_DEBUG
+	DEBUG_PRINT("  Term", tab[span].runlen);
+#endif
+	_PutBits(tif, code, length);
+
+	sp->data = data;
+	sp->bit = bit;
+}
+
+/*
+ * Write an EOL code to the output stream.  The zero-fill
+ * logic for byte-aligning encoded scanlines is handled
+ * here.  We also handle writing the tag bit for the next
+ * scanline when doing 2d encoding.
+ */
+static void
+Fax3PutEOL(TIFF* tif)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+	unsigned int bit = sp->bit;
+	int data = sp->data;
+	unsigned int code, length, tparm;
+
+	if (sp->b.groupoptions & GROUP3OPT_FILLBITS) {
+		/*
+		 * Force bit alignment so EOL will terminate on
+		 * a byte boundary.  That is, force the bit alignment
+		 * to 16-12 = 4 before putting out the EOL code.
+		 */
+		int align = 8 - 4;
+		if (align != sp->bit) {
+			if (align > sp->bit)
+				align = sp->bit + (8 - align);
+			else
+				align = sp->bit - align;
+			code = 0;
+			tparm=align; 
+			_PutBits(tif, 0, tparm);
+		}
+	}
+	code = EOL, length = 12;
+	if (is2DEncoding(sp))
+		code = (code<<1) | (sp->tag == G3_1D), length++;
+	_PutBits(tif, code, length);
+
+	sp->data = data;
+	sp->bit = bit;
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+Fax3PreEncode(TIFF* tif, uint16 s)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	sp->bit = 8;
+	sp->data = 0;
+	sp->tag = G3_1D;
+	/*
+	 * This is necessary for Group 4; otherwise it isn't
+	 * needed because the first scanline of each strip ends
+	 * up being copied into the refline.
+	 */
+	if (sp->refline)
+		_TIFFmemset(sp->refline, 0x00, sp->b.rowbytes);
+	if (is2DEncoding(sp)) {
+		float res = tif->tif_dir.td_yresolution;
+		/*
+		 * The CCITT spec says that when doing 2d encoding, you
+		 * should only do it on K consecutive scanlines, where K
+		 * depends on the resolution of the image being encoded
+		 * (2 for <= 200 lpi, 4 for > 200 lpi).  Since the directory
+		 * code initializes td_yresolution to 0, this code will
+		 * select a K of 2 unless the YResolution tag is set
+		 * appropriately.  (Note also that we fudge a little here
+		 * and use 150 lpi to avoid problems with units conversion.)
+		 */
+		if (tif->tif_dir.td_resolutionunit == RESUNIT_CENTIMETER)
+			res *= 2.54f;		/* convert to inches */
+		sp->maxk = (res > 150 ? 4 : 2);
+		sp->k = sp->maxk-1;
+	} else
+		sp->k = sp->maxk = 0;
+	sp->line = 0;
+	return (1);
+}
+
+static const unsigned char zeroruns[256] = {
+    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,	/* 0x00 - 0x0f */
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	/* 0x10 - 0x1f */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0x20 - 0x2f */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0x30 - 0x3f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x40 - 0x4f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x50 - 0x5f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x60 - 0x6f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x70 - 0x7f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x80 - 0x8f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x90 - 0x9f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xa0 - 0xaf */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xb0 - 0xbf */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xc0 - 0xcf */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xd0 - 0xdf */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xe0 - 0xef */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xf0 - 0xff */
+};
+static const unsigned char oneruns[256] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x00 - 0x0f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x10 - 0x1f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x20 - 0x2f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x30 - 0x3f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x40 - 0x4f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x50 - 0x5f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x60 - 0x6f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x70 - 0x7f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x80 - 0x8f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x90 - 0x9f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0xa0 - 0xaf */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0xb0 - 0xbf */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0xc0 - 0xcf */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0xd0 - 0xdf */
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	/* 0xe0 - 0xef */
+    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,	/* 0xf0 - 0xff */
+};
+
+/*
+ * On certain systems it pays to inline
+ * the routines that find pixel spans.
+ */
+#ifdef VAXC
+static	int32 find0span(unsigned char*, int32, int32);
+static	int32 find1span(unsigned char*, int32, int32);
+#pragma inline(find0span,find1span)
+#endif
+
+/*
+ * Find a span of ones or zeros using the supplied
+ * table.  The ``base'' of the bit string is supplied
+ * along with the start+end bit indices.
+ */
+inline static int32
+find0span(unsigned char* bp, int32 bs, int32 be)
+{
+	int32 bits = be - bs;
+	int32 n, span;
+
+	bp += bs>>3;
+	/*
+	 * Check partial byte on lhs.
+	 */
+	if (bits > 0 && (n = (bs & 7))) {
+		span = zeroruns[(*bp << n) & 0xff];
+		if (span > 8-n)		/* table value too generous */
+			span = 8-n;
+		if (span > bits)	/* constrain span to bit range */
+			span = bits;
+		if (n+span < 8)		/* doesn't extend to edge of byte */
+			return (span);
+		bits -= span;
+		bp++;
+	} else
+		span = 0;
+	if (bits >= (int32)(2 * 8 * sizeof(long))) {
+		long* lp;
+		/*
+		 * Align to longword boundary and check longwords.
+		 */
+		while (!isAligned(bp, long)) {
+			if (*bp != 0x00)
+				return (span + zeroruns[*bp]);
+			span += 8, bits -= 8;
+			bp++;
+		}
+		lp = (long*) bp;
+		while ((bits >= (int32)(8 * sizeof(long))) && (0 == *lp)) {
+			span += 8*sizeof (long), bits -= 8*sizeof (long);
+			lp++;
+		}
+		bp = (unsigned char*) lp;
+	}
+	/*
+	 * Scan full bytes for all 0's.
+	 */
+	while (bits >= 8) {
+		if (*bp != 0x00)	/* end of run */
+			return (span + zeroruns[*bp]);
+		span += 8, bits -= 8;
+		bp++;
+	}
+	/*
+	 * Check partial byte on rhs.
+	 */
+	if (bits > 0) {
+		n = zeroruns[*bp];
+		span += (n > bits ? bits : n);
+	}
+	return (span);
+}
+
+inline static int32
+find1span(unsigned char* bp, int32 bs, int32 be)
+{
+	int32 bits = be - bs;
+	int32 n, span;
+
+	bp += bs>>3;
+	/*
+	 * Check partial byte on lhs.
+	 */
+	if (bits > 0 && (n = (bs & 7))) {
+		span = oneruns[(*bp << n) & 0xff];
+		if (span > 8-n)		/* table value too generous */
+			span = 8-n;
+		if (span > bits)	/* constrain span to bit range */
+			span = bits;
+		if (n+span < 8)		/* doesn't extend to edge of byte */
+			return (span);
+		bits -= span;
+		bp++;
+	} else
+		span = 0;
+	if (bits >= (int32)(2 * 8 * sizeof(long))) {
+		long* lp;
+		/*
+		 * Align to longword boundary and check longwords.
+		 */
+		while (!isAligned(bp, long)) {
+			if (*bp != 0xff)
+				return (span + oneruns[*bp]);
+			span += 8, bits -= 8;
+			bp++;
+		}
+		lp = (long*) bp;
+		while ((bits >= (int32)(8 * sizeof(long))) && (~0 == *lp)) {
+			span += 8*sizeof (long), bits -= 8*sizeof (long);
+			lp++;
+		}
+		bp = (unsigned char*) lp;
+	}
+	/*
+	 * Scan full bytes for all 1's.
+	 */
+	while (bits >= 8) {
+		if (*bp != 0xff)	/* end of run */
+			return (span + oneruns[*bp]);
+		span += 8, bits -= 8;
+		bp++;
+	}
+	/*
+	 * Check partial byte on rhs.
+	 */
+	if (bits > 0) {
+		n = oneruns[*bp];
+		span += (n > bits ? bits : n);
+	}
+	return (span);
+}
+
+/*
+ * Return the offset of the next bit in the range
+ * [bs..be] that is different from the specified
+ * color.  The end, be, is returned if no such bit
+ * exists.
+ */
+#define	finddiff(_cp, _bs, _be, _color)	\
+	(_bs + (_color ? find1span(_cp,_bs,_be) : find0span(_cp,_bs,_be)))
+/*
+ * Like finddiff, but also check the starting bit
+ * against the end in case start > end.
+ */
+#define	finddiff2(_cp, _bs, _be, _color) \
+	(_bs < _be ? finddiff(_cp,_bs,_be,_color) : _be)
+
+/*
+ * 1d-encode a row of pixels.  The encoding is
+ * a sequence of all-white or all-black spans
+ * of pixels encoded with Huffman codes.
+ */
+static int
+Fax3Encode1DRow(TIFF* tif, unsigned char* bp, uint32 bits)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+	int32 span;
+        uint32 bs = 0;
+
+	for (;;) {
+		span = find0span(bp, bs, bits);		/* white span */
+		putspan(tif, span, TIFFFaxWhiteCodes);
+		bs += span;
+		if (bs >= bits)
+			break;
+		span = find1span(bp, bs, bits);		/* black span */
+		putspan(tif, span, TIFFFaxBlackCodes);
+		bs += span;
+		if (bs >= bits)
+			break;
+	}
+	if (sp->b.mode & (FAXMODE_BYTEALIGN|FAXMODE_WORDALIGN)) {
+		if (sp->bit != 8)			/* byte-align */
+			Fax3FlushBits(tif, sp);
+		if ((sp->b.mode&FAXMODE_WORDALIGN) &&
+		    !isAligned(tif->tif_rawcp, uint16))
+			Fax3FlushBits(tif, sp);
+	}
+	return (1);
+}
+
+static const tableentry horizcode =
+    { 3, 0x1, 0 };	/* 001 */
+static const tableentry passcode =
+    { 4, 0x1, 0 };	/* 0001 */
+static const tableentry vcodes[7] = {
+    { 7, 0x03, 0 },	/* 0000 011 */
+    { 6, 0x03, 0 },	/* 0000 11 */
+    { 3, 0x03, 0 },	/* 011 */
+    { 1, 0x1, 0 },	/* 1 */
+    { 3, 0x2, 0 },	/* 010 */
+    { 6, 0x02, 0 },	/* 0000 10 */
+    { 7, 0x02, 0 }	/* 0000 010 */
+};
+
+/*
+ * 2d-encode a row of pixels.  Consult the CCITT
+ * documentation for the algorithm.
+ */
+static int
+Fax3Encode2DRow(TIFF* tif, unsigned char* bp, unsigned char* rp, uint32 bits)
+{
+#define	PIXEL(buf,ix)	((((buf)[(ix)>>3]) >> (7-((ix)&7))) & 1)
+        uint32 a0 = 0;
+	uint32 a1 = (PIXEL(bp, 0) != 0 ? 0 : finddiff(bp, 0, bits, 0));
+	uint32 b1 = (PIXEL(rp, 0) != 0 ? 0 : finddiff(rp, 0, bits, 0));
+	uint32 a2, b2;
+
+	for (;;) {
+		b2 = finddiff2(rp, b1, bits, PIXEL(rp,b1));
+		if (b2 >= a1) {
+			int32 d = b1 - a1;
+			if (!(-3 <= d && d <= 3)) {	/* horizontal mode */
+				a2 = finddiff2(bp, a1, bits, PIXEL(bp,a1));
+				putcode(tif, &horizcode);
+				if (a0+a1 == 0 || PIXEL(bp, a0) == 0) {
+					putspan(tif, a1-a0, TIFFFaxWhiteCodes);
+					putspan(tif, a2-a1, TIFFFaxBlackCodes);
+				} else {
+					putspan(tif, a1-a0, TIFFFaxBlackCodes);
+					putspan(tif, a2-a1, TIFFFaxWhiteCodes);
+				}
+				a0 = a2;
+			} else {			/* vertical mode */
+				putcode(tif, &vcodes[d+3]);
+				a0 = a1;
+			}
+		} else {				/* pass mode */
+			putcode(tif, &passcode);
+			a0 = b2;
+		}
+		if (a0 >= bits)
+			break;
+		a1 = finddiff(bp, a0, bits, PIXEL(bp,a0));
+		b1 = finddiff(rp, a0, bits, !PIXEL(bp,a0));
+		b1 = finddiff(rp, b1, bits, PIXEL(bp,a0));
+	}
+	return (1);
+#undef PIXEL
+}
+
+/*
+ * Encode a buffer of pixels.
+ */
+static int
+Fax3Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "Fax3Encode";
+	Fax3CodecState* sp = EncoderState(tif);
+	(void) s;
+	if (cc % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be written");
+		return (0);
+	}
+	while (cc > 0) {
+		if ((sp->b.mode & FAXMODE_NOEOL) == 0)
+			Fax3PutEOL(tif);
+		if (is2DEncoding(sp)) {
+			if (sp->tag == G3_1D) {
+				if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels))
+					return (0);
+				sp->tag = G3_2D;
+			} else {
+				if (!Fax3Encode2DRow(tif, bp, sp->refline,
+				    sp->b.rowpixels))
+					return (0);
+				sp->k--;
+			}
+			if (sp->k == 0) {
+				sp->tag = G3_1D;
+				sp->k = sp->maxk-1;
+			} else
+				_TIFFmemcpy(sp->refline, bp, sp->b.rowbytes);
+		} else {
+			if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels))
+				return (0);
+		}
+		bp += sp->b.rowbytes;
+		cc -= sp->b.rowbytes;
+	}
+	return (1);
+}
+
+static int
+Fax3PostEncode(TIFF* tif)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+
+	if (sp->bit != 8)
+		Fax3FlushBits(tif, sp);
+	return (1);
+}
+
+static void
+Fax3Close(TIFF* tif)
+{
+	if ((Fax3State(tif)->mode & FAXMODE_NORTC) == 0) {
+		Fax3CodecState* sp = EncoderState(tif);
+		unsigned int code = EOL;
+		unsigned int length = 12;
+		int i;
+
+		if (is2DEncoding(sp))
+			code = (code<<1) | (sp->tag == G3_1D), length++;
+		for (i = 0; i < 6; i++)
+			Fax3PutBits(tif, code, length);
+		Fax3FlushBits(tif, sp);
+	}
+}
+
+static void
+Fax3Cleanup(TIFF* tif)
+{
+	Fax3CodecState* sp = DecoderState(tif);
+	
+	assert(sp != 0);
+
+	tif->tif_tagmethods.vgetfield = sp->b.vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->b.vsetparent;
+	tif->tif_tagmethods.printdir = sp->b.printdir;
+
+	if (sp->runs)
+		_TIFFfree(sp->runs);
+	if (sp->refline)
+		_TIFFfree(sp->refline);
+
+	_TIFFfree(tif->tif_data);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+#define	FIELD_BADFAXLINES	(FIELD_CODEC+0)
+#define	FIELD_CLEANFAXDATA	(FIELD_CODEC+1)
+#define	FIELD_BADFAXRUN		(FIELD_CODEC+2)
+
+#define	FIELD_OPTIONS		(FIELD_CODEC+7)
+
+static const TIFFField faxFields[] = {
+    { TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxMode", NULL },
+    { TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxFillFunc", NULL },
+    { TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_BADFAXLINES, TRUE, FALSE, "BadFaxLines", NULL },
+    { TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UINT16, FIELD_CLEANFAXDATA, TRUE, FALSE, "CleanFaxData", NULL },
+    { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_BADFAXRUN, TRUE, FALSE, "ConsecutiveBadFaxLines", NULL }};
+static const TIFFField fax3Fields[] = {
+    { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group3Options", NULL },
+};
+static const TIFFField fax4Fields[] = {
+    { TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group4Options", NULL },
+};
+
+static int
+Fax3VSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	Fax3BaseState* sp = Fax3State(tif);
+	const TIFFField* fip;
+
+	assert(sp != 0);
+	assert(sp->vsetparent != 0);
+
+	switch (tag) {
+	case TIFFTAG_FAXMODE:
+		sp->mode = (int) va_arg(ap, int);
+		return 1;			/* NB: pseudo tag */
+	case TIFFTAG_FAXFILLFUNC:
+		DecoderState(tif)->fill = va_arg(ap, TIFFFaxFillFunc);
+		return 1;			/* NB: pseudo tag */
+	case TIFFTAG_GROUP3OPTIONS:
+		/* XXX: avoid reading options if compression mismatches. */
+		if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX3)
+			sp->groupoptions = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_GROUP4OPTIONS:
+		/* XXX: avoid reading options if compression mismatches. */
+		if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4)
+			sp->groupoptions = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_BADFAXLINES:
+		sp->badfaxlines = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_CLEANFAXDATA:
+		sp->cleanfaxdata = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_CONSECUTIVEBADFAXLINES:
+		sp->badfaxrun = (uint32) va_arg(ap, uint32);
+		break;
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+	
+	if ((fip = TIFFFieldWithTag(tif, tag)))
+		TIFFSetFieldBit(tif, fip->field_bit);
+	else
+		return 0;
+
+	tif->tif_flags |= TIFF_DIRTYDIRECT;
+	return 1;
+}
+
+static int
+Fax3VGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	Fax3BaseState* sp = Fax3State(tif);
+
+	assert(sp != 0);
+
+	switch (tag) {
+	case TIFFTAG_FAXMODE:
+		*va_arg(ap, int*) = sp->mode;
+		break;
+	case TIFFTAG_FAXFILLFUNC:
+		*va_arg(ap, TIFFFaxFillFunc*) = DecoderState(tif)->fill;
+		break;
+	case TIFFTAG_GROUP3OPTIONS:
+	case TIFFTAG_GROUP4OPTIONS:
+		*va_arg(ap, uint32*) = sp->groupoptions;
+		break;
+	case TIFFTAG_BADFAXLINES:
+		*va_arg(ap, uint32*) = sp->badfaxlines;
+		break;
+	case TIFFTAG_CLEANFAXDATA:
+		*va_arg(ap, uint16*) = sp->cleanfaxdata;
+		break;
+	case TIFFTAG_CONSECUTIVEBADFAXLINES:
+		*va_arg(ap, uint32*) = sp->badfaxrun;
+		break;
+	default:
+		return (*sp->vgetparent)(tif, tag, ap);
+	}
+	return (1);
+}
+
+static void
+Fax3PrintDir(TIFF* tif, FILE* fd, long flags)
+{
+	Fax3BaseState* sp = Fax3State(tif);
+
+	assert(sp != 0);
+
+	(void) flags;
+	if (TIFFFieldSet(tif,FIELD_OPTIONS)) {
+		const char* sep = " ";
+		if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) {
+			fprintf(fd, "  Group 4 Options:");
+			if (sp->groupoptions & GROUP4OPT_UNCOMPRESSED)
+				fprintf(fd, "%suncompressed data", sep);
+		} else {
+
+			fprintf(fd, "  Group 3 Options:");
+			if (sp->groupoptions & GROUP3OPT_2DENCODING)
+				fprintf(fd, "%s2-d encoding", sep), sep = "+";
+			if (sp->groupoptions & GROUP3OPT_FILLBITS)
+				fprintf(fd, "%sEOL padding", sep), sep = "+";
+			if (sp->groupoptions & GROUP3OPT_UNCOMPRESSED)
+				fprintf(fd, "%suncompressed data", sep);
+		}
+		fprintf(fd, " (%lu = 0x%lx)\n",
+                        (unsigned long) sp->groupoptions,
+                        (unsigned long) sp->groupoptions);
+	}
+	if (TIFFFieldSet(tif,FIELD_CLEANFAXDATA)) {
+		fprintf(fd, "  Fax Data:");
+		switch (sp->cleanfaxdata) {
+		case CLEANFAXDATA_CLEAN:
+			fprintf(fd, " clean");
+			break;
+		case CLEANFAXDATA_REGENERATED:
+			fprintf(fd, " receiver regenerated");
+			break;
+		case CLEANFAXDATA_UNCLEAN:
+			fprintf(fd, " uncorrected errors");
+			break;
+		}
+		fprintf(fd, " (%u = 0x%x)\n",
+		    sp->cleanfaxdata, sp->cleanfaxdata);
+	}
+	if (TIFFFieldSet(tif,FIELD_BADFAXLINES))
+		fprintf(fd, "  Bad Fax Lines: %lu\n",
+                        (unsigned long) sp->badfaxlines);
+	if (TIFFFieldSet(tif,FIELD_BADFAXRUN))
+		fprintf(fd, "  Consecutive Bad Fax Lines: %lu\n",
+		    (unsigned long) sp->badfaxrun);
+	if (sp->printdir)
+		(*sp->printdir)(tif, fd, flags);
+}
+
+static int
+InitCCITTFax3(TIFF* tif)
+{
+	static const char module[] = "InitCCITTFax3";
+	Fax3BaseState* sp;
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, faxFields, TIFFArrayCount(faxFields))) {
+		TIFFErrorExt(tif->tif_clientdata, "InitCCITTFax3",
+			"Merging common CCITT Fax codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*)
+		_TIFFmalloc(sizeof (Fax3CodecState));
+
+	if (tif->tif_data == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "No space for state block");
+		return (0);
+	}
+
+	sp = Fax3State(tif);
+        sp->rw_mode = tif->tif_mode;
+
+	/*
+	 * Override parent get/set field methods.
+	 */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield = Fax3VGetField; /* hook for codec tags */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield = Fax3VSetField; /* hook for codec tags */
+	sp->printdir = tif->tif_tagmethods.printdir;
+	tif->tif_tagmethods.printdir = Fax3PrintDir;   /* hook for codec tags */
+	sp->groupoptions = 0;	
+
+	if (sp->rw_mode == O_RDONLY) /* FIXME: improve for in place update */
+		tif->tif_flags |= TIFF_NOBITREV; /* decoder does bit reversal */
+	DecoderState(tif)->runs = NULL;
+	TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, _TIFFFax3fillruns);
+	EncoderState(tif)->refline = NULL;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = Fax3FixupTags;
+	tif->tif_setupdecode = Fax3SetupState;
+	tif->tif_predecode = Fax3PreDecode;
+	tif->tif_decoderow = Fax3Decode1D;
+	tif->tif_decodestrip = Fax3Decode1D;
+	tif->tif_decodetile = Fax3Decode1D;
+	tif->tif_setupencode = Fax3SetupState;
+	tif->tif_preencode = Fax3PreEncode;
+	tif->tif_postencode = Fax3PostEncode;
+	tif->tif_encoderow = Fax3Encode;
+	tif->tif_encodestrip = Fax3Encode;
+	tif->tif_encodetile = Fax3Encode;
+	tif->tif_close = Fax3Close;
+	tif->tif_cleanup = Fax3Cleanup;
+
+	return (1);
+}
+
+int
+TIFFInitCCITTFax3(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	if (InitCCITTFax3(tif)) {
+		/*
+		 * Merge codec-specific tag information.
+		 */
+		if (!_TIFFMergeFields(tif, fax3Fields,
+				      TIFFArrayCount(fax3Fields))) {
+			TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3",
+			"Merging CCITT Fax 3 codec-specific tags failed");
+			return 0;
+		}
+
+		/*
+		 * The default format is Class/F-style w/o RTC.
+		 */
+		return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_CLASSF);
+	} else
+		return 01;
+}
+
+/*
+ * CCITT Group 4 (T.6) Facsimile-compatible
+ * Compression Scheme Support.
+ */
+
+#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; }
+/*
+ * Decode the requested amount of G4-encoded data.
+ */
+static int
+Fax4Decode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+#ifdef FAX3_DEBUG
+	FILE* file;
+#endif
+	DECLARE_STATE_2D(tif, sp, "Fax4Decode");
+
+	(void) s;
+	if (occ % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (-1);
+	}
+	CACHE_STATE(tif, sp);
+	while (occ > 0) {
+		a0 = 0;
+		RunLength = 0;
+		pa = thisrun = sp->curruns;
+		pb = sp->refruns;
+		b1 = *pb++;
+#ifdef FAX3_DEBUG
+		printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail);
+		printf("-------------------- %d\n", tif->tif_row);
+		fflush(stdout);
+#endif
+		EXPAND2D(EOFG4);
+                if (EOLcnt)
+                    goto EOFG4;
+		(*sp->fill)(buf, thisrun, pa, lastx);
+#ifdef FAX3_DEBUG
+		file = fopen("fillbuf.txt", "a");
+		fwrite(buf, sp->b.rowbytes, 1, file);
+		fclose(file);
+#endif
+		SETVALUE(0);		/* imaginary change for reference */
+		SWAP(uint32*, sp->curruns, sp->refruns);
+		buf += sp->b.rowbytes;
+		occ -= sp->b.rowbytes;
+		sp->line++;
+		continue;
+	EOFG4:
+                NeedBits16( 13, BADG4 );
+        BADG4:
+#ifdef FAX3_DEBUG
+                if( GetBits(13) != 0x1001 )
+                    fputs( "Bad EOFB\n", stderr );
+#endif                
+                ClrBits( 13 );
+		(*sp->fill)(buf, thisrun, pa, lastx);
+#ifdef FAX3_DEBUG
+		file = fopen("fillbuf.txt", "a");
+		fwrite(buf, sp->b.rowbytes, 1, file);
+		fclose(file);
+#endif
+		UNCACHE_STATE(tif, sp);
+		return ( sp->line ? 1 : -1);	/* don't error on badly-terminated strips */
+	}
+	UNCACHE_STATE(tif, sp);
+	return (1);
+}
+#undef	SWAP
+
+/*
+ * Encode the requested amount of data.
+ */
+static int
+Fax4Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "Fax4Encode";
+	Fax3CodecState *sp = EncoderState(tif);
+	(void) s;
+	if (cc % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be written");
+		return (0);
+	}
+	while (cc > 0) {
+		if (!Fax3Encode2DRow(tif, bp, sp->refline, sp->b.rowpixels))
+			return (0);
+		_TIFFmemcpy(sp->refline, bp, sp->b.rowbytes);
+		bp += sp->b.rowbytes;
+		cc -= sp->b.rowbytes;
+	}
+	return (1);
+}
+
+static int
+Fax4PostEncode(TIFF* tif)
+{
+	Fax3CodecState *sp = EncoderState(tif);
+
+	/* terminate strip w/ EOFB */
+	Fax3PutBits(tif, EOL, 12);
+	Fax3PutBits(tif, EOL, 12);
+	if (sp->bit != 8)
+		Fax3FlushBits(tif, sp);
+	return (1);
+}
+
+int
+TIFFInitCCITTFax4(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	if (InitCCITTFax3(tif)) {		/* reuse G3 support */
+		/*
+		 * Merge codec-specific tag information.
+		 */
+		if (!_TIFFMergeFields(tif, fax4Fields,
+				      TIFFArrayCount(fax4Fields))) {
+			TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax4",
+			"Merging CCITT Fax 4 codec-specific tags failed");
+			return 0;
+		}
+
+		tif->tif_decoderow = Fax4Decode;
+		tif->tif_decodestrip = Fax4Decode;
+		tif->tif_decodetile = Fax4Decode;
+		tif->tif_encoderow = Fax4Encode;
+		tif->tif_encodestrip = Fax4Encode;
+		tif->tif_encodetile = Fax4Encode;
+		tif->tif_postencode = Fax4PostEncode;
+		/*
+		 * Suppress RTC at the end of each strip.
+		 */
+		return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_NORTC);
+	} else
+		return (0);
+}
+
+/*
+ * CCITT Group 3 1-D Modified Huffman RLE Compression Support.
+ * (Compression algorithms 2 and 32771)
+ */
+
+/*
+ * Decode the requested amount of RLE-encoded data.
+ */
+static int
+Fax3DecodeRLE(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	DECLARE_STATE(tif, sp, "Fax3DecodeRLE");
+	int mode = sp->b.mode;
+	(void) s;
+	if (occ % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (-1);
+	}
+	CACHE_STATE(tif, sp);
+	thisrun = sp->curruns;
+	while (occ > 0) {
+		a0 = 0;
+		RunLength = 0;
+		pa = thisrun;
+#ifdef FAX3_DEBUG
+		printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail);
+		printf("-------------------- %d\n", tif->tif_row);
+		fflush(stdout);
+#endif
+		EXPAND1D(EOFRLE);
+		(*sp->fill)(buf, thisrun, pa, lastx);
+		/*
+		 * Cleanup at the end of the row.
+		 */
+		if (mode & FAXMODE_BYTEALIGN) {
+			int n = BitsAvail - (BitsAvail &~ 7);
+			ClrBits(n);
+		} else if (mode & FAXMODE_WORDALIGN) {
+			int n = BitsAvail - (BitsAvail &~ 15);
+			ClrBits(n);
+			if (BitsAvail == 0 && !isAligned(cp, uint16))
+			    cp++;
+		}
+		buf += sp->b.rowbytes;
+		occ -= sp->b.rowbytes;
+		sp->line++;
+		continue;
+	EOFRLE:				/* premature EOF */
+		(*sp->fill)(buf, thisrun, pa, lastx);
+		UNCACHE_STATE(tif, sp);
+		return (-1);
+	}
+	UNCACHE_STATE(tif, sp);
+	return (1);
+}
+
+int
+TIFFInitCCITTRLE(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	if (InitCCITTFax3(tif)) {		/* reuse G3 support */
+		tif->tif_decoderow = Fax3DecodeRLE;
+		tif->tif_decodestrip = Fax3DecodeRLE;
+		tif->tif_decodetile = Fax3DecodeRLE;
+		/*
+		 * Suppress RTC+EOLs when encoding and byte-align data.
+		 */
+		return TIFFSetField(tif, TIFFTAG_FAXMODE,
+		    FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_BYTEALIGN);
+	} else
+		return (0);
+}
+
+int
+TIFFInitCCITTRLEW(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	if (InitCCITTFax3(tif)) {		/* reuse G3 support */
+		tif->tif_decoderow = Fax3DecodeRLE;
+		tif->tif_decodestrip = Fax3DecodeRLE;
+		tif->tif_decodetile = Fax3DecodeRLE;  
+		/*
+		 * Suppress RTC+EOLs when encoding and word-align data.
+		 */
+		return TIFFSetField(tif, TIFFTAG_FAXMODE,
+		    FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_WORDALIGN);
+	} else
+		return (0);
+}
+#endif /* CCITT_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.h b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.h
new file mode 100644
index 0000000..b0f46c9
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.h
@@ -0,0 +1,538 @@
+/* $Id: tif_fax3.h,v 1.9 2011-03-10 20:23:07 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _FAX3_
+#define	_FAX3_
+/*
+ * TIFF Library.
+ *
+ * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support.
+ *
+ * Decoder support is derived, with permission, from the code
+ * in Frank Cringle's viewfax program;
+ *      Copyright (C) 1990, 1995  Frank D. Cringle.
+ */
+#include "tiff.h"
+
+/*
+ * To override the default routine used to image decoded
+ * spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC.
+ * The routine must have the type signature given below;
+ * for example:
+ *
+ * fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
+ *
+ * where buf is place to set the bits, runs is the array of b&w run
+ * lengths (white then black), erun is the last run in the array, and
+ * lastx is the width of the row in pixels.  Fill routines can assume
+ * the run array has room for at least lastx runs and can overwrite
+ * data in the run array as needed (e.g. to append zero runs to bring
+ * the count up to a nice multiple).
+ */
+typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32);
+
+/*
+ * The default run filler; made external for other decoders.
+ */
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32);
+#if defined(__cplusplus)
+}
+#endif
+
+
+/* finite state machine codes */
+#define S_Null     0
+#define S_Pass     1
+#define S_Horiz    2
+#define S_V0       3
+#define S_VR       4
+#define S_VL       5
+#define S_Ext      6
+#define S_TermW    7
+#define S_TermB    8
+#define S_MakeUpW  9
+#define S_MakeUpB  10
+#define S_MakeUp   11
+#define S_EOL      12
+
+typedef struct {                /* state table entry */
+	unsigned char State;    /* see above */
+	unsigned char Width;    /* width of code in bits */
+	uint32 Param;           /* unsigned 32-bit run length in bits */
+} TIFFFaxTabEnt;
+
+extern const TIFFFaxTabEnt TIFFFaxMainTable[];
+extern const TIFFFaxTabEnt TIFFFaxWhiteTable[];
+extern const TIFFFaxTabEnt TIFFFaxBlackTable[];
+
+/*
+ * The following macros define the majority of the G3/G4 decoder
+ * algorithm using the state tables defined elsewhere.  To build
+ * a decoder you need some setup code and some glue code. Note
+ * that you may also need/want to change the way the NeedBits*
+ * macros get input data if, for example, you know the data to be
+ * decoded is properly aligned and oriented (doing so before running
+ * the decoder can be a big performance win).
+ *
+ * Consult the decoder in the TIFF library for an idea of what you
+ * need to define and setup to make use of these definitions.
+ *
+ * NB: to enable a debugging version of these macros define FAX3_DEBUG
+ *     before including this file.  Trace output goes to stdout.
+ */
+
+#ifndef EndOfData
+#define EndOfData()	(cp >= ep)
+#endif
+/*
+ * Need <=8 or <=16 bits of input data.  Unlike viewfax we
+ * cannot use/assume a word-aligned, properly bit swizzled
+ * input data set because data may come from an arbitrarily
+ * aligned, read-only source such as a memory-mapped file.
+ * Note also that the viewfax decoder does not check for
+ * running off the end of the input data buffer.  This is
+ * possible for G3-encoded data because it prescans the input
+ * data to count EOL markers, but can cause problems for G4
+ * data.  In any event, we don't prescan and must watch for
+ * running out of data since we can't permit the library to
+ * scan past the end of the input data buffer.
+ *
+ * Finally, note that we must handle remaindered data at the end
+ * of a strip specially.  The coder asks for a fixed number of
+ * bits when scanning for the next code.  This may be more bits
+ * than are actually present in the data stream.  If we appear
+ * to run out of data but still have some number of valid bits
+ * remaining then we makeup the requested amount with zeros and
+ * return successfully.  If the returned data is incorrect then
+ * we should be called again and get a premature EOF error;
+ * otherwise we should get the right answer.
+ */
+#ifndef NeedBits8
+#define NeedBits8(n,eoflab) do {					\
+    if (BitsAvail < (n)) {						\
+	if (EndOfData()) {						\
+	    if (BitsAvail == 0)			/* no valid bits */	\
+		goto eoflab;						\
+	    BitsAvail = (n);			/* pad with zeros */	\
+	} else {							\
+	    BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail;		\
+	    BitsAvail += 8;						\
+	}								\
+    }									\
+} while (0)
+#endif
+#ifndef NeedBits16
+#define NeedBits16(n,eoflab) do {					\
+    if (BitsAvail < (n)) {						\
+	if (EndOfData()) {						\
+	    if (BitsAvail == 0)			/* no valid bits */	\
+		goto eoflab;						\
+	    BitsAvail = (n);			/* pad with zeros */	\
+	} else {							\
+	    BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail;		\
+	    if ((BitsAvail += 8) < (n)) {				\
+		if (EndOfData()) {					\
+		    /* NB: we know BitsAvail is non-zero here */	\
+		    BitsAvail = (n);		/* pad with zeros */	\
+		} else {						\
+		    BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail;	\
+		    BitsAvail += 8;					\
+		}							\
+	    }								\
+	}								\
+    }									\
+} while (0)
+#endif
+#define GetBits(n)	(BitAcc & ((1<<(n))-1))
+#define ClrBits(n) do {							\
+    BitsAvail -= (n);							\
+    BitAcc >>= (n);							\
+} while (0)
+
+#ifdef FAX3_DEBUG
+static const char* StateNames[] = {
+    "Null   ",
+    "Pass   ",
+    "Horiz  ",
+    "V0     ",
+    "VR     ",
+    "VL     ",
+    "Ext    ",
+    "TermW  ",
+    "TermB  ",
+    "MakeUpW",
+    "MakeUpB",
+    "MakeUp ",
+    "EOL    ",
+};
+#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
+#define LOOKUP8(wid,tab,eoflab) do {					\
+    int t;								\
+    NeedBits8(wid,eoflab);						\
+    TabEnt = tab + GetBits(wid);					\
+    printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail,		\
+	   StateNames[TabEnt->State], TabEnt->Param);			\
+    for (t = 0; t < TabEnt->Width; t++)					\
+	DEBUG_SHOW;							\
+    putchar('\n');							\
+    fflush(stdout);							\
+    ClrBits(TabEnt->Width);						\
+} while (0)
+#define LOOKUP16(wid,tab,eoflab) do {					\
+    int t;								\
+    NeedBits16(wid,eoflab);						\
+    TabEnt = tab + GetBits(wid);					\
+    printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail,		\
+	   StateNames[TabEnt->State], TabEnt->Param);			\
+    for (t = 0; t < TabEnt->Width; t++)					\
+	DEBUG_SHOW;							\
+    putchar('\n');							\
+    fflush(stdout);							\
+    ClrBits(TabEnt->Width);						\
+} while (0)
+
+#define SETVALUE(x) do {							\
+    *pa++ = RunLength + (x);						\
+    printf("SETVALUE: %d\t%d\n", RunLength + (x), a0);			\
+    a0 += x;								\
+    RunLength = 0;							\
+} while (0)
+#else
+#define LOOKUP8(wid,tab,eoflab) do {					\
+    NeedBits8(wid,eoflab);						\
+    TabEnt = tab + GetBits(wid);					\
+    ClrBits(TabEnt->Width);						\
+} while (0)
+#define LOOKUP16(wid,tab,eoflab) do {					\
+    NeedBits16(wid,eoflab);						\
+    TabEnt = tab + GetBits(wid);					\
+    ClrBits(TabEnt->Width);						\
+} while (0)
+
+/*
+ * Append a run to the run length array for the
+ * current row and reset decoding state.
+ */
+#define SETVALUE(x) do {							\
+    *pa++ = RunLength + (x);						\
+    a0 += (x);								\
+    RunLength = 0;							\
+} while (0)
+#endif
+
+/*
+ * Synchronize input decoding at the start of each
+ * row by scanning for an EOL (if appropriate) and
+ * skipping any trash data that might be present
+ * after a decoding error.  Note that the decoding
+ * done elsewhere that recognizes an EOL only consumes
+ * 11 consecutive zero bits.  This means that if EOLcnt
+ * is non-zero then we still need to scan for the final flag
+ * bit that is part of the EOL code.
+ */
+#define	SYNC_EOL(eoflab) do {						\
+    if (EOLcnt == 0) {							\
+	for (;;) {							\
+	    NeedBits16(11,eoflab);					\
+	    if (GetBits(11) == 0)					\
+		break;							\
+	    ClrBits(1);							\
+	}								\
+    }									\
+    for (;;) {								\
+	NeedBits8(8,eoflab);						\
+	if (GetBits(8))							\
+	    break;							\
+	ClrBits(8);							\
+    }									\
+    while (GetBits(1) == 0)						\
+	ClrBits(1);							\
+    ClrBits(1);				/* EOL bit */			\
+    EOLcnt = 0;				/* reset EOL counter/flag */	\
+} while (0)
+
+/*
+ * Cleanup the array of runs after decoding a row.
+ * We adjust final runs to insure the user buffer is not
+ * overwritten and/or undecoded area is white filled.
+ */
+#define	CLEANUP_RUNS() do {						\
+    if (RunLength)							\
+	SETVALUE(0);							\
+    if (a0 != lastx) {							\
+	badlength(a0, lastx);						\
+	while (a0 > lastx && pa > thisrun)				\
+	    a0 -= *--pa;						\
+	if (a0 < lastx) {						\
+	    if (a0 < 0)							\
+		a0 = 0;							\
+	    if ((pa-thisrun)&1)						\
+		SETVALUE(0);						\
+	    SETVALUE(lastx - a0);						\
+	} else if (a0 > lastx) {					\
+	    SETVALUE(lastx);						\
+	    SETVALUE(0);							\
+	}								\
+    }									\
+} while (0)
+
+/*
+ * Decode a line of 1D-encoded data.
+ *
+ * The line expanders are written as macros so that they can be reused
+ * but still have direct access to the local variables of the "calling"
+ * function.
+ *
+ * Note that unlike the original version we have to explicitly test for
+ * a0 >= lastx after each black/white run is decoded.  This is because
+ * the original code depended on the input data being zero-padded to
+ * insure the decoder recognized an EOL before running out of data.
+ */
+#define EXPAND1D(eoflab) do {						\
+    for (;;) {								\
+	for (;;) {							\
+	    LOOKUP16(12, TIFFFaxWhiteTable, eof1d);			\
+	    switch (TabEnt->State) {					\
+	    case S_EOL:							\
+		EOLcnt = 1;						\
+		goto done1d;						\
+	    case S_TermW:						\
+		SETVALUE(TabEnt->Param);					\
+		goto doneWhite1d;					\
+	    case S_MakeUpW:						\
+	    case S_MakeUp:						\
+		a0 += TabEnt->Param;					\
+		RunLength += TabEnt->Param;				\
+		break;							\
+	    default:							\
+		unexpected("WhiteTable", a0);				\
+		goto done1d;						\
+	    }								\
+	}								\
+    doneWhite1d:							\
+	if (a0 >= lastx)						\
+	    goto done1d;						\
+	for (;;) {							\
+	    LOOKUP16(13, TIFFFaxBlackTable, eof1d);			\
+	    switch (TabEnt->State) {					\
+	    case S_EOL:							\
+		EOLcnt = 1;						\
+		goto done1d;						\
+	    case S_TermB:						\
+		SETVALUE(TabEnt->Param);					\
+		goto doneBlack1d;					\
+	    case S_MakeUpB:						\
+	    case S_MakeUp:						\
+		a0 += TabEnt->Param;					\
+		RunLength += TabEnt->Param;				\
+		break;							\
+	    default:							\
+		unexpected("BlackTable", a0);				\
+		goto done1d;						\
+	    }								\
+	}								\
+    doneBlack1d:							\
+	if (a0 >= lastx)						\
+	    goto done1d;						\
+        if( *(pa-1) == 0 && *(pa-2) == 0 )				\
+            pa -= 2;                                                    \
+    }									\
+eof1d:									\
+    prematureEOF(a0);							\
+    CLEANUP_RUNS();							\
+    goto eoflab;							\
+done1d:									\
+    CLEANUP_RUNS();							\
+} while (0)
+
+/*
+ * Update the value of b1 using the array
+ * of runs for the reference line.
+ */
+#define CHECK_b1 do {							\
+    if (pa != thisrun) while (b1 <= a0 && b1 < lastx) {			\
+	b1 += pb[0] + pb[1];						\
+	pb += 2;							\
+    }									\
+} while (0)
+
+/*
+ * Expand a row of 2D-encoded data.
+ */
+#define EXPAND2D(eoflab) do {						\
+    while (a0 < lastx) {						\
+	LOOKUP8(7, TIFFFaxMainTable, eof2d);				\
+	switch (TabEnt->State) {					\
+	case S_Pass:							\
+	    CHECK_b1;							\
+	    b1 += *pb++;						\
+	    RunLength += b1 - a0;					\
+	    a0 = b1;							\
+	    b1 += *pb++;						\
+	    break;							\
+	case S_Horiz:							\
+	    if ((pa-thisrun)&1) {					\
+		for (;;) {	/* black first */			\
+		    LOOKUP16(13, TIFFFaxBlackTable, eof2d);		\
+		    switch (TabEnt->State) {				\
+		    case S_TermB:					\
+			SETVALUE(TabEnt->Param);				\
+			goto doneWhite2da;				\
+		    case S_MakeUpB:					\
+		    case S_MakeUp:					\
+			a0 += TabEnt->Param;				\
+			RunLength += TabEnt->Param;			\
+			break;						\
+		    default:						\
+			goto badBlack2d;				\
+		    }							\
+		}							\
+	    doneWhite2da:;						\
+		for (;;) {	/* then white */			\
+		    LOOKUP16(12, TIFFFaxWhiteTable, eof2d);		\
+		    switch (TabEnt->State) {				\
+		    case S_TermW:					\
+			SETVALUE(TabEnt->Param);				\
+			goto doneBlack2da;				\
+		    case S_MakeUpW:					\
+		    case S_MakeUp:					\
+			a0 += TabEnt->Param;				\
+			RunLength += TabEnt->Param;			\
+			break;						\
+		    default:						\
+			goto badWhite2d;				\
+		    }							\
+		}							\
+	    doneBlack2da:;						\
+	    } else {							\
+		for (;;) {	/* white first */			\
+		    LOOKUP16(12, TIFFFaxWhiteTable, eof2d);		\
+		    switch (TabEnt->State) {				\
+		    case S_TermW:					\
+			SETVALUE(TabEnt->Param);				\
+			goto doneWhite2db;				\
+		    case S_MakeUpW:					\
+		    case S_MakeUp:					\
+			a0 += TabEnt->Param;				\
+			RunLength += TabEnt->Param;			\
+			break;						\
+		    default:						\
+			goto badWhite2d;				\
+		    }							\
+		}							\
+	    doneWhite2db:;						\
+		for (;;) {	/* then black */			\
+		    LOOKUP16(13, TIFFFaxBlackTable, eof2d);		\
+		    switch (TabEnt->State) {				\
+		    case S_TermB:					\
+			SETVALUE(TabEnt->Param);				\
+			goto doneBlack2db;				\
+		    case S_MakeUpB:					\
+		    case S_MakeUp:					\
+			a0 += TabEnt->Param;				\
+			RunLength += TabEnt->Param;			\
+			break;						\
+		    default:						\
+			goto badBlack2d;				\
+		    }							\
+		}							\
+	    doneBlack2db:;						\
+	    }								\
+	    CHECK_b1;							\
+	    break;							\
+	case S_V0:							\
+	    CHECK_b1;							\
+	    SETVALUE(b1 - a0);						\
+	    b1 += *pb++;						\
+	    break;							\
+	case S_VR:							\
+	    CHECK_b1;							\
+	    SETVALUE(b1 - a0 + TabEnt->Param);				\
+	    b1 += *pb++;						\
+	    break;							\
+	case S_VL:							\
+	    CHECK_b1;							\
+	    if (b1 <= (int) (a0 + TabEnt->Param)) {			\
+		if (b1 < (int) (a0 + TabEnt->Param) || pa != thisrun) {	\
+		    unexpected("VL", a0);				\
+		    goto eol2d;						\
+		}							\
+	    }								\
+	    SETVALUE(b1 - a0 - TabEnt->Param);				\
+	    b1 -= *--pb;						\
+	    break;							\
+	case S_Ext:							\
+	    *pa++ = lastx - a0;						\
+	    extension(a0);						\
+	    goto eol2d;							\
+	case S_EOL:							\
+	    *pa++ = lastx - a0;						\
+	    NeedBits8(4,eof2d);						\
+	    if (GetBits(4))						\
+		unexpected("EOL", a0);					\
+            ClrBits(4);                                                 \
+	    EOLcnt = 1;							\
+	    goto eol2d;							\
+	default:							\
+	badMain2d:							\
+	    unexpected("MainTable", a0);				\
+	    goto eol2d;							\
+	badBlack2d:							\
+	    unexpected("BlackTable", a0);				\
+	    goto eol2d;							\
+	badWhite2d:							\
+	    unexpected("WhiteTable", a0);				\
+	    goto eol2d;							\
+	eof2d:								\
+	    prematureEOF(a0);						\
+	    CLEANUP_RUNS();						\
+	    goto eoflab;						\
+	}								\
+    }									\
+    if (RunLength) {							\
+	if (RunLength + a0 < lastx) {					\
+	    /* expect a final V0 */					\
+	    NeedBits8(1,eof2d);						\
+	    if (!GetBits(1))						\
+		goto badMain2d;						\
+	    ClrBits(1);							\
+	}								\
+	SETVALUE(0);							\
+    }									\
+eol2d:									\
+    CLEANUP_RUNS();							\
+} while (0)
+#endif /* _FAX3_ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3sm.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3sm.c
new file mode 100644
index 0000000..47a532c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3sm.c
@@ -0,0 +1,1263 @@
+/* WARNING, this file was automatically generated by the
+    mkg3states program */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiff.h"
+#include "tif_fax3.h"
+ const TIFFFaxTabEnt TIFFFaxMainTable[128] = {
+{12,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},
+{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{5,6,2},{3,1,0},{5,3,1},{3,1,0},
+{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},
+{4,3,1},{3,1,0},{5,7,3},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},
+{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,6,2},{3,1,0},
+{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},
+{2,3,0},{3,1,0},{4,3,1},{3,1,0},{6,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},
+{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},
+{5,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},
+{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,7,3},{3,1,0},{5,3,1},{3,1,0},
+{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},
+{4,3,1},{3,1,0},{4,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},
+{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}
+};
+ const TIFFFaxTabEnt TIFFFaxWhiteTable[4096] = {
+{12,11,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},
+{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},
+{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},
+{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},
+{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},
+{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},
+{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},
+{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},
+{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},
+{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},
+{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},
+{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},
+{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},
+{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},
+{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},
+{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},
+{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},
+{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},
+{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},
+{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},
+{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},
+{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},
+{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},
+{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{11,12,2112},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},
+{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},
+{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},
+{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},
+{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},
+{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},
+{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},
+{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2368},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},
+{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},
+{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},
+{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},
+{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},
+{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},
+{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},
+{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},
+{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},
+{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},
+{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},
+{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},
+{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{11,12,1984},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},
+{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},
+{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},
+{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},
+{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},
+{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},
+{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},
+{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},
+{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},
+{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},
+{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},
+{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},
+{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},
+{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},
+{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},
+{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},
+{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},
+{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},
+{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2240},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},
+{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},
+{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},
+{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},
+{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},
+{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},
+{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},
+{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},
+{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},
+{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{11,12,2496},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},
+{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},
+{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},
+{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{12,11,0},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},
+{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},
+{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},
+{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},
+{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},
+{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},
+{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},
+{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},
+{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},
+{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},
+{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},
+{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},
+{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},
+{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},
+{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},
+{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},
+{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},
+{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},
+{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},
+{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},
+{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},
+{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},
+{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},
+{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2176},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},
+{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},
+{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},
+{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},
+{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},
+{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},
+{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},
+{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},
+{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},
+{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},
+{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},
+{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2432},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},
+{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},
+{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},
+{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},
+{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},
+{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},
+{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},
+{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},
+{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},
+{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{11,12,2048},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},
+{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},
+{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},
+{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},
+{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},
+{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},
+{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},
+{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},
+{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},
+{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},
+{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},
+{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},
+{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},
+{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},
+{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},
+{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},
+{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},
+{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},
+{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},
+{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{11,12,2304},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},
+{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},
+{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},
+{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},
+{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},
+{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},
+{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},
+{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2560},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},
+{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},
+{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},
+{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},
+{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}
+};
+ const TIFFFaxTabEnt TIFFFaxBlackTable[8192] = {
+{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,56},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,30},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2112},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,44},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,60},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,12,1984},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,34},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1664},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1408},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,61},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,13,1024},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,768},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,62},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,38},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,512},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2496},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,12,192},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1280},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,31},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,896},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,640},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,45},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,12,448},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,1536},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,41},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2048},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,51},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,59},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,1152},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,63},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,12,2304},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,39},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,56},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,30},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2112},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,44},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,60},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,1984},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,34},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,13,1728},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,1472},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,61},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1088},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,832},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,62},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,38},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,576},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2496},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,192},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1344},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,31},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,13,960},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,704},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,45},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,448},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1600},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,41},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2048},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,51},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,59},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1216},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,63},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2304},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,39},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2}
+};
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_flush.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_flush.c
new file mode 100644
index 0000000..075b3bc
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_flush.c
@@ -0,0 +1,121 @@
+/* $Id: tif_flush.c,v 1.9 2010-03-31 06:40:10 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+int
+TIFFFlush(TIFF* tif)
+{
+    if( tif->tif_mode == O_RDONLY )
+        return 1;
+
+    if (!TIFFFlushData(tif))
+        return (0);
+                
+    /* In update (r+) mode we try to detect the case where 
+       only the strip/tile map has been altered, and we try to 
+       rewrite only that portion of the directory without 
+       making any other changes */
+                
+    if( (tif->tif_flags & TIFF_DIRTYSTRIP)
+        && !(tif->tif_flags & TIFF_DIRTYDIRECT) 
+        && tif->tif_mode == O_RDWR )
+    {
+        uint64  *offsets=NULL, *sizes=NULL;
+
+        if( TIFFIsTiled(tif) )
+        {
+            if( TIFFGetField( tif, TIFFTAG_TILEOFFSETS, &offsets ) 
+                && TIFFGetField( tif, TIFFTAG_TILEBYTECOUNTS, &sizes ) 
+                && _TIFFRewriteField( tif, TIFFTAG_TILEOFFSETS, TIFF_LONG8, 
+                                      tif->tif_dir.td_nstrips, offsets )
+                && _TIFFRewriteField( tif, TIFFTAG_TILEBYTECOUNTS, TIFF_LONG8, 
+                                      tif->tif_dir.td_nstrips, sizes ) )
+            {
+                tif->tif_flags &= ~TIFF_DIRTYSTRIP;
+                tif->tif_flags &= ~TIFF_BEENWRITING;
+                return 1;
+            }
+        }
+        else
+        {
+            if( TIFFGetField( tif, TIFFTAG_STRIPOFFSETS, &offsets ) 
+                && TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &sizes ) 
+                && _TIFFRewriteField( tif, TIFFTAG_STRIPOFFSETS, TIFF_LONG8, 
+                                      tif->tif_dir.td_nstrips, offsets )
+                && _TIFFRewriteField( tif, TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG8, 
+                                      tif->tif_dir.td_nstrips, sizes ) )
+            {
+                tif->tif_flags &= ~TIFF_DIRTYSTRIP;
+                tif->tif_flags &= ~TIFF_BEENWRITING;
+                return 1;
+            }
+        }
+    }
+
+    if ((tif->tif_flags & (TIFF_DIRTYDIRECT|TIFF_DIRTYSTRIP)) 
+        && !TIFFRewriteDirectory(tif))
+        return (0);
+
+    return (1);
+}
+
+/*
+ * Flush buffered data to the file.
+ *
+ * Frank Warmerdam'2000: I modified this to return 1 if TIFF_BEENWRITING
+ * is not set, so that TIFFFlush() will proceed to write out the directory.
+ * The documentation says returning 1 is an error indicator, but not having
+ * been writing isn't exactly a an error.  Hopefully this doesn't cause
+ * problems for other people. 
+ */
+int
+TIFFFlushData(TIFF* tif)
+{
+	if ((tif->tif_flags & TIFF_BEENWRITING) == 0)
+		return (1);
+	if (tif->tif_flags & TIFF_POSTENCODE) {
+		tif->tif_flags &= ~TIFF_POSTENCODE;
+		if (!(*tif->tif_postencode)(tif))
+			return (0);
+	}
+	return (TIFFFlushData1(tif));
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_getimage.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_getimage.c
new file mode 100644
index 0000000..a5d7a44
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_getimage.c
@@ -0,0 +1,2991 @@
+/* $Id: tif_getimage.c,v 1.82 2012-06-06 00:17:49 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Read and return a packed RGBA image.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include <stdio.h>
+
+static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32);
+static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32);
+static int gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32);
+static int gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32);
+static int PickContigCase(TIFFRGBAImage*);
+static int PickSeparateCase(TIFFRGBAImage*);
+
+static int BuildMapUaToAa(TIFFRGBAImage* img);
+static int BuildMapBitdepth16To8(TIFFRGBAImage* img);
+
+static const char photoTag[] = "PhotometricInterpretation";
+
+/* 
+ * Helper constants used in Orientation tag handling
+ */
+#define FLIP_VERTICALLY 0x01
+#define FLIP_HORIZONTALLY 0x02
+
+/*
+ * Color conversion constants. We will define display types here.
+ */
+
+static const TIFFDisplay display_sRGB = {
+	{			/* XYZ -> luminance matrix */
+		{  3.2410F, -1.5374F, -0.4986F },
+		{  -0.9692F, 1.8760F, 0.0416F },
+		{  0.0556F, -0.2040F, 1.0570F }
+	},	
+	100.0F, 100.0F, 100.0F,	/* Light o/p for reference white */
+	255, 255, 255,		/* Pixel values for ref. white */
+	1.0F, 1.0F, 1.0F,	/* Residual light o/p for black pixel */
+	2.4F, 2.4F, 2.4F,	/* Gamma values for the three guns */
+};
+
+/*
+ * Check the image to see if TIFFReadRGBAImage can deal with it.
+ * 1/0 is returned according to whether or not the image can
+ * be handled.  If 0 is returned, emsg contains the reason
+ * why it is being rejected.
+ */
+int
+TIFFRGBAImageOK(TIFF* tif, char emsg[1024])
+{
+	TIFFDirectory* td = &tif->tif_dir;
+	uint16 photometric;
+	int colorchannels;
+
+	if (!tif->tif_decodestatus) {
+		sprintf(emsg, "Sorry, requested compression method is not configured");
+		return (0);
+	}
+	switch (td->td_bitspersample) {
+		case 1:
+		case 2:
+		case 4:
+		case 8:
+		case 16:
+			break;
+		default:
+			sprintf(emsg, "Sorry, can not handle images with %d-bit samples",
+			    td->td_bitspersample);
+			return (0);
+	}
+	colorchannels = td->td_samplesperpixel - td->td_extrasamples;
+	if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) {
+		switch (colorchannels) {
+			case 1:
+				photometric = PHOTOMETRIC_MINISBLACK;
+				break;
+			case 3:
+				photometric = PHOTOMETRIC_RGB;
+				break;
+			default:
+				sprintf(emsg, "Missing needed %s tag", photoTag);
+				return (0);
+		}
+	}
+	switch (photometric) {
+		case PHOTOMETRIC_MINISWHITE:
+		case PHOTOMETRIC_MINISBLACK:
+		case PHOTOMETRIC_PALETTE:
+			if (td->td_planarconfig == PLANARCONFIG_CONTIG
+			    && td->td_samplesperpixel != 1
+			    && td->td_bitspersample < 8 ) {
+				sprintf(emsg,
+				    "Sorry, can not handle contiguous data with %s=%d, "
+				    "and %s=%d and Bits/Sample=%d",
+				    photoTag, photometric,
+				    "Samples/pixel", td->td_samplesperpixel,
+				    td->td_bitspersample);
+				return (0);
+			}
+			/*
+			 * We should likely validate that any extra samples are either
+			 * to be ignored, or are alpha, and if alpha we should try to use
+			 * them.  But for now we won't bother with this.
+			*/
+			break;
+		case PHOTOMETRIC_YCBCR:
+			/*
+			 * TODO: if at all meaningful and useful, make more complete
+			 * support check here, or better still, refactor to let supporting
+			 * code decide whether there is support and what meaningfull
+			 * error to return
+			 */
+			break;
+		case PHOTOMETRIC_RGB:
+			if (colorchannels < 3) {
+				sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
+				    "Color channels", colorchannels);
+				return (0);
+			}
+			break;
+		case PHOTOMETRIC_SEPARATED:
+			{
+				uint16 inkset;
+				TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
+				if (inkset != INKSET_CMYK) {
+					sprintf(emsg,
+					    "Sorry, can not handle separated image with %s=%d",
+					    "InkSet", inkset);
+					return 0;
+				}
+				if (td->td_samplesperpixel < 4) {
+					sprintf(emsg,
+					    "Sorry, can not handle separated image with %s=%d",
+					    "Samples/pixel", td->td_samplesperpixel);
+					return 0;
+				}
+				break;
+			}
+		case PHOTOMETRIC_LOGL:
+			if (td->td_compression != COMPRESSION_SGILOG) {
+				sprintf(emsg, "Sorry, LogL data must have %s=%d",
+				    "Compression", COMPRESSION_SGILOG);
+				return (0);
+			}
+			break;
+		case PHOTOMETRIC_LOGLUV:
+			if (td->td_compression != COMPRESSION_SGILOG &&
+			    td->td_compression != COMPRESSION_SGILOG24) {
+				sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d",
+				    "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24);
+				return (0);
+			}
+			if (td->td_planarconfig != PLANARCONFIG_CONTIG) {
+				sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d",
+				    "Planarconfiguration", td->td_planarconfig);
+				return (0);
+			}
+			break;
+		case PHOTOMETRIC_CIELAB:
+			break;
+		default:
+			sprintf(emsg, "Sorry, can not handle image with %s=%d",
+			    photoTag, photometric);
+			return (0);
+	}
+	return (1);
+}
+
+void
+TIFFRGBAImageEnd(TIFFRGBAImage* img)
+{
+	if (img->Map)
+		_TIFFfree(img->Map), img->Map = NULL;
+	if (img->BWmap)
+		_TIFFfree(img->BWmap), img->BWmap = NULL;
+	if (img->PALmap)
+		_TIFFfree(img->PALmap), img->PALmap = NULL;
+	if (img->ycbcr)
+		_TIFFfree(img->ycbcr), img->ycbcr = NULL;
+	if (img->cielab)
+		_TIFFfree(img->cielab), img->cielab = NULL;
+	if (img->UaToAa)
+		_TIFFfree(img->UaToAa), img->UaToAa = NULL;
+	if (img->Bitdepth16To8)
+		_TIFFfree(img->Bitdepth16To8), img->Bitdepth16To8 = NULL;
+
+	if( img->redcmap ) {
+		_TIFFfree( img->redcmap );
+		_TIFFfree( img->greencmap );
+		_TIFFfree( img->bluecmap );
+                img->redcmap = img->greencmap = img->bluecmap = NULL;
+	}
+}
+
+static int
+isCCITTCompression(TIFF* tif)
+{
+    uint16 compress;
+    TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
+    return (compress == COMPRESSION_CCITTFAX3 ||
+	    compress == COMPRESSION_CCITTFAX4 ||
+	    compress == COMPRESSION_CCITTRLE ||
+	    compress == COMPRESSION_CCITTRLEW);
+}
+
+int
+TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024])
+{
+	uint16* sampleinfo;
+	uint16 extrasamples;
+	uint16 planarconfig;
+	uint16 compress;
+	int colorchannels;
+	uint16 *red_orig, *green_orig, *blue_orig;
+	int n_color;
+
+	/* Initialize to normal values */
+	img->row_offset = 0;
+	img->col_offset = 0;
+	img->redcmap = NULL;
+	img->greencmap = NULL;
+	img->bluecmap = NULL;
+	img->req_orientation = ORIENTATION_BOTLEFT;     /* It is the default */
+
+	img->tif = tif;
+	img->stoponerr = stop;
+	TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample);
+	switch (img->bitspersample) {
+		case 1:
+		case 2:
+		case 4:
+		case 8:
+		case 16:
+			break;
+		default:
+			sprintf(emsg, "Sorry, can not handle images with %d-bit samples",
+			    img->bitspersample);
+			goto fail_return;
+	}
+	img->alpha = 0;
+	TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel);
+	TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
+	    &extrasamples, &sampleinfo);
+	if (extrasamples >= 1)
+	{
+		switch (sampleinfo[0]) {
+			case EXTRASAMPLE_UNSPECIFIED:          /* Workaround for some images without */
+				if (img->samplesperpixel > 3)  /* correct info about alpha channel */
+					img->alpha = EXTRASAMPLE_ASSOCALPHA;
+				break;
+			case EXTRASAMPLE_ASSOCALPHA:           /* data is pre-multiplied */
+			case EXTRASAMPLE_UNASSALPHA:           /* data is not pre-multiplied */
+				img->alpha = sampleinfo[0];
+				break;
+		}
+	}
+
+#ifdef DEFAULT_EXTRASAMPLE_AS_ALPHA
+	if( !TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric))
+		img->photometric = PHOTOMETRIC_MINISWHITE;
+
+	if( extrasamples == 0
+	    && img->samplesperpixel == 4
+	    && img->photometric == PHOTOMETRIC_RGB )
+	{
+		img->alpha = EXTRASAMPLE_ASSOCALPHA;
+		extrasamples = 1;
+	}
+#endif
+
+	colorchannels = img->samplesperpixel - extrasamples;
+	TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress);
+	TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
+	if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) {
+		switch (colorchannels) {
+			case 1:
+				if (isCCITTCompression(tif))
+					img->photometric = PHOTOMETRIC_MINISWHITE;
+				else
+					img->photometric = PHOTOMETRIC_MINISBLACK;
+				break;
+			case 3:
+				img->photometric = PHOTOMETRIC_RGB;
+				break;
+			default:
+				sprintf(emsg, "Missing needed %s tag", photoTag);
+                                goto fail_return;
+		}
+	}
+	switch (img->photometric) {
+		case PHOTOMETRIC_PALETTE:
+			if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
+			    &red_orig, &green_orig, &blue_orig)) {
+				sprintf(emsg, "Missing required \"Colormap\" tag");
+                                goto fail_return;
+			}
+
+			/* copy the colormaps so we can modify them */
+			n_color = (1L << img->bitspersample);
+			img->redcmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color);
+			img->greencmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color);
+			img->bluecmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color);
+			if( !img->redcmap || !img->greencmap || !img->bluecmap ) {
+				sprintf(emsg, "Out of memory for colormap copy");
+                                goto fail_return;
+			}
+
+			_TIFFmemcpy( img->redcmap, red_orig, n_color * 2 );
+			_TIFFmemcpy( img->greencmap, green_orig, n_color * 2 );
+			_TIFFmemcpy( img->bluecmap, blue_orig, n_color * 2 );
+
+			/* fall thru... */
+		case PHOTOMETRIC_MINISWHITE:
+		case PHOTOMETRIC_MINISBLACK:
+			if (planarconfig == PLANARCONFIG_CONTIG
+			    && img->samplesperpixel != 1
+			    && img->bitspersample < 8 ) {
+				sprintf(emsg,
+				    "Sorry, can not handle contiguous data with %s=%d, "
+				    "and %s=%d and Bits/Sample=%d",
+				    photoTag, img->photometric,
+				    "Samples/pixel", img->samplesperpixel,
+				    img->bitspersample);
+                                goto fail_return;
+			}
+			break;
+		case PHOTOMETRIC_YCBCR:
+			/* It would probably be nice to have a reality check here. */
+			if (planarconfig == PLANARCONFIG_CONTIG)
+				/* can rely on libjpeg to convert to RGB */
+				/* XXX should restore current state on exit */
+				switch (compress) {
+					case COMPRESSION_JPEG:
+						/*
+						 * TODO: when complete tests verify complete desubsampling
+						 * and YCbCr handling, remove use of TIFFTAG_JPEGCOLORMODE in
+						 * favor of tif_getimage.c native handling
+						 */
+						TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+						img->photometric = PHOTOMETRIC_RGB;
+						break;
+					default:
+						/* do nothing */;
+						break;
+				}
+			/*
+			 * TODO: if at all meaningful and useful, make more complete
+			 * support check here, or better still, refactor to let supporting
+			 * code decide whether there is support and what meaningfull
+			 * error to return
+			 */
+			break;
+		case PHOTOMETRIC_RGB:
+			if (colorchannels < 3) {
+				sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
+				    "Color channels", colorchannels);
+                                goto fail_return;
+			}
+			break;
+		case PHOTOMETRIC_SEPARATED:
+			{
+				uint16 inkset;
+				TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
+				if (inkset != INKSET_CMYK) {
+					sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+					    "InkSet", inkset);
+                                        goto fail_return;
+				}
+				if (img->samplesperpixel < 4) {
+					sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+					    "Samples/pixel", img->samplesperpixel);
+                                        goto fail_return;
+				}
+			}
+			break;
+		case PHOTOMETRIC_LOGL:
+			if (compress != COMPRESSION_SGILOG) {
+				sprintf(emsg, "Sorry, LogL data must have %s=%d",
+				    "Compression", COMPRESSION_SGILOG);
+                                goto fail_return;
+			}
+			TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
+			img->photometric = PHOTOMETRIC_MINISBLACK;	/* little white lie */
+			img->bitspersample = 8;
+			break;
+		case PHOTOMETRIC_LOGLUV:
+			if (compress != COMPRESSION_SGILOG && compress != COMPRESSION_SGILOG24) {
+				sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d",
+				    "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24);
+                                goto fail_return;
+			}
+			if (planarconfig != PLANARCONFIG_CONTIG) {
+				sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d",
+				    "Planarconfiguration", planarconfig);
+				return (0);
+			}
+			TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
+			img->photometric = PHOTOMETRIC_RGB;		/* little white lie */
+			img->bitspersample = 8;
+			break;
+		case PHOTOMETRIC_CIELAB:
+			break;
+		default:
+			sprintf(emsg, "Sorry, can not handle image with %s=%d",
+			    photoTag, img->photometric);
+                        goto fail_return;
+	}
+	img->Map = NULL;
+	img->BWmap = NULL;
+	img->PALmap = NULL;
+	img->ycbcr = NULL;
+	img->cielab = NULL;
+	img->UaToAa = NULL;
+	img->Bitdepth16To8 = NULL;
+	TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
+	TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
+	TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation);
+	img->isContig =
+	    !(planarconfig == PLANARCONFIG_SEPARATE && img->samplesperpixel > 1);
+	if (img->isContig) {
+		if (!PickContigCase(img)) {
+			sprintf(emsg, "Sorry, can not handle image");
+			goto fail_return;
+		}
+	} else {
+		if (!PickSeparateCase(img)) {
+			sprintf(emsg, "Sorry, can not handle image");
+			goto fail_return;
+		}
+	}
+	return 1;
+
+  fail_return:
+        _TIFFfree( img->redcmap );
+        _TIFFfree( img->greencmap );
+        _TIFFfree( img->bluecmap );
+        img->redcmap = img->greencmap = img->bluecmap = NULL;
+        return 0;
+}
+
+int
+TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+    if (img->get == NULL) {
+		TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup");
+		return (0);
+	}
+	if (img->put.any == NULL) {
+		TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif),
+		"No \"put\" routine setupl; probably can not handle image format");
+		return (0);
+    }
+    return (*img->get)(img, raster, w, h);
+}
+
+/*
+ * Read the specified image into an ABGR-format rastertaking in account
+ * specified orientation.
+ */
+int
+TIFFReadRGBAImageOriented(TIFF* tif,
+			  uint32 rwidth, uint32 rheight, uint32* raster,
+			  int orientation, int stop)
+{
+    char emsg[1024] = "";
+    TIFFRGBAImage img;
+    int ok;
+
+	if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop, emsg)) {
+		img.req_orientation = orientation;
+		/* XXX verify rwidth and rheight against width and height */
+		ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth,
+			rwidth, img.height);
+		TIFFRGBAImageEnd(&img);
+	} else {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg);
+		ok = 0;
+    }
+    return (ok);
+}
+
+/*
+ * Read the specified image into an ABGR-format raster. Use bottom left
+ * origin for raster by default.
+ */
+int
+TIFFReadRGBAImage(TIFF* tif,
+		  uint32 rwidth, uint32 rheight, uint32* raster, int stop)
+{
+	return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster,
+					 ORIENTATION_BOTLEFT, stop);
+}
+
+static int 
+setorientation(TIFFRGBAImage* img)
+{
+	switch (img->orientation) {
+		case ORIENTATION_TOPLEFT:
+		case ORIENTATION_LEFTTOP:
+			if (img->req_orientation == ORIENTATION_TOPRIGHT ||
+			    img->req_orientation == ORIENTATION_RIGHTTOP)
+				return FLIP_HORIZONTALLY;
+			else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
+			    img->req_orientation == ORIENTATION_RIGHTBOT)
+				return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
+			else if (img->req_orientation == ORIENTATION_BOTLEFT ||
+			    img->req_orientation == ORIENTATION_LEFTBOT)
+				return FLIP_VERTICALLY;
+			else
+				return 0;
+		case ORIENTATION_TOPRIGHT:
+		case ORIENTATION_RIGHTTOP:
+			if (img->req_orientation == ORIENTATION_TOPLEFT ||
+			    img->req_orientation == ORIENTATION_LEFTTOP)
+				return FLIP_HORIZONTALLY;
+			else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
+			    img->req_orientation == ORIENTATION_RIGHTBOT)
+				return FLIP_VERTICALLY;
+			else if (img->req_orientation == ORIENTATION_BOTLEFT ||
+			    img->req_orientation == ORIENTATION_LEFTBOT)
+				return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
+			else
+				return 0;
+		case ORIENTATION_BOTRIGHT:
+		case ORIENTATION_RIGHTBOT:
+			if (img->req_orientation == ORIENTATION_TOPLEFT ||
+			    img->req_orientation == ORIENTATION_LEFTTOP)
+				return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
+			else if (img->req_orientation == ORIENTATION_TOPRIGHT ||
+			    img->req_orientation == ORIENTATION_RIGHTTOP)
+				return FLIP_VERTICALLY;
+			else if (img->req_orientation == ORIENTATION_BOTLEFT ||
+			    img->req_orientation == ORIENTATION_LEFTBOT)
+				return FLIP_HORIZONTALLY;
+			else
+				return 0;
+		case ORIENTATION_BOTLEFT:
+		case ORIENTATION_LEFTBOT:
+			if (img->req_orientation == ORIENTATION_TOPLEFT ||
+			    img->req_orientation == ORIENTATION_LEFTTOP)
+				return FLIP_VERTICALLY;
+			else if (img->req_orientation == ORIENTATION_TOPRIGHT ||
+			    img->req_orientation == ORIENTATION_RIGHTTOP)
+				return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
+			else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
+			    img->req_orientation == ORIENTATION_RIGHTBOT)
+				return FLIP_HORIZONTALLY;
+			else
+				return 0;
+		default:	/* NOTREACHED */
+			return 0;
+	}
+}
+
+/*
+ * Get an tile-organized image that has
+ *	PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ *	SamplesPerPixel == 1
+ */	
+static int
+gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+    TIFF* tif = img->tif;
+    tileContigRoutine put = img->put.contig;
+    uint32 col, row, y, rowstoread;
+    tmsize_t pos;
+    uint32 tw, th;
+    unsigned char* buf;
+    int32 fromskew, toskew;
+    uint32 nrow;
+    int ret = 1, flip;
+
+    buf = (unsigned char*) _TIFFmalloc(TIFFTileSize(tif));
+    if (buf == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "No space for tile buffer");
+		return (0);
+    }
+    _TIFFmemset(buf, 0, TIFFTileSize(tif));
+    TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+    TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+
+    flip = setorientation(img);
+    if (flip & FLIP_VERTICALLY) {
+	    y = h - 1;
+	    toskew = -(int32)(tw + w);
+    }
+    else {
+	    y = 0;
+	    toskew = -(int32)(tw - w);
+    }
+     
+    for (row = 0; row < h; row += nrow)
+    {
+        rowstoread = th - (row + img->row_offset) % th;
+    	nrow = (row + rowstoread > h ? h - row : rowstoread);
+	for (col = 0; col < w; col += tw) 
+        {
+	    if (TIFFReadTile(tif, buf, col+img->col_offset,  
+			     row+img->row_offset, 0, 0)==(tmsize_t)(-1) && img->stoponerr)
+            {
+                ret = 0;
+                break;
+            }
+	    
+	    pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif);  
+
+    	    if (col + tw > w) 
+            {
+                /*
+                 * Tile is clipped horizontally.  Calculate
+                 * visible portion and skewing factors.
+                 */
+                uint32 npix = w - col;
+                fromskew = tw - npix;
+                (*put)(img, raster+y*w+col, col, y,
+                       npix, nrow, fromskew, toskew + fromskew, buf + pos);
+            }
+            else 
+            {
+                (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf + pos);
+            }
+        }
+
+        y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow);
+    }
+    _TIFFfree(buf);
+
+    if (flip & FLIP_HORIZONTALLY) {
+	    uint32 line;
+
+	    for (line = 0; line < h; line++) {
+		    uint32 *left = raster + (line * w);
+		    uint32 *right = left + w - 1;
+		    
+		    while ( left < right ) {
+			    uint32 temp = *left;
+			    *left = *right;
+			    *right = temp;
+			    left++, right--;
+		    }
+	    }
+    }
+
+    return (ret);
+}
+
+/*
+ * Get an tile-organized image that has
+ *	 SamplesPerPixel > 1
+ *	 PlanarConfiguration separated
+ * We assume that all such images are RGB.
+ */	
+static int
+gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+	TIFF* tif = img->tif;
+	tileSeparateRoutine put = img->put.separate;
+	uint32 col, row, y, rowstoread;
+	tmsize_t pos;
+	uint32 tw, th;
+	unsigned char* buf;
+	unsigned char* p0;
+	unsigned char* p1;
+	unsigned char* p2;
+	unsigned char* pa;
+	tmsize_t tilesize;
+	tmsize_t bufsize;
+	int32 fromskew, toskew;
+	int alpha = img->alpha;
+	uint32 nrow;
+	int ret = 1, flip;
+        int colorchannels;
+
+	tilesize = TIFFTileSize(tif);  
+	bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,tilesize);
+	if (bufsize == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtTileSeparate");
+		return (0);
+	}
+	buf = (unsigned char*) _TIFFmalloc(bufsize);
+	if (buf == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "No space for tile buffer");
+		return (0);
+	}
+	_TIFFmemset(buf, 0, bufsize);
+	p0 = buf;
+	p1 = p0 + tilesize;
+	p2 = p1 + tilesize;
+	pa = (alpha?(p2+tilesize):NULL);
+	TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+	TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+
+	flip = setorientation(img);
+	if (flip & FLIP_VERTICALLY) {
+		y = h - 1;
+		toskew = -(int32)(tw + w);
+	}
+	else {
+		y = 0;
+		toskew = -(int32)(tw - w);
+	}
+
+        switch( img->photometric )
+        {
+          case PHOTOMETRIC_MINISWHITE:
+          case PHOTOMETRIC_MINISBLACK:
+          case PHOTOMETRIC_PALETTE:
+            colorchannels = 1;
+            p2 = p1 = p0;
+            break;
+
+          default:
+            colorchannels = 3;
+            break;
+        }
+
+	for (row = 0; row < h; row += nrow)
+	{
+		rowstoread = th - (row + img->row_offset) % th;
+		nrow = (row + rowstoread > h ? h - row : rowstoread);
+		for (col = 0; col < w; col += tw)
+		{
+			if (TIFFReadTile(tif, p0, col+img->col_offset,  
+			    row+img->row_offset,0,0)==(tmsize_t)(-1) && img->stoponerr)
+			{
+				ret = 0;
+				break;
+			}
+			if (colorchannels > 1 
+                            && TIFFReadTile(tif, p1, col+img->col_offset,  
+                                            row+img->row_offset,0,1) == (tmsize_t)(-1) 
+                            && img->stoponerr)
+			{
+				ret = 0;
+				break;
+			}
+			if (colorchannels > 1 
+                            && TIFFReadTile(tif, p2, col+img->col_offset,  
+                                            row+img->row_offset,0,2) == (tmsize_t)(-1) 
+                            && img->stoponerr)
+			{
+				ret = 0;
+				break;
+			}
+			if (alpha
+                            && TIFFReadTile(tif,pa,col+img->col_offset,  
+                                            row+img->row_offset,0,colorchannels) == (tmsize_t)(-1) 
+                            && img->stoponerr)
+                        {
+                            ret = 0;
+                            break;
+			}
+
+			pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif);  
+
+			if (col + tw > w)
+			{
+				/*
+				 * Tile is clipped horizontally.  Calculate
+				 * visible portion and skewing factors.
+				 */
+				uint32 npix = w - col;
+				fromskew = tw - npix;
+				(*put)(img, raster+y*w+col, col, y,
+				    npix, nrow, fromskew, toskew + fromskew,
+				    p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL));
+			} else {
+				(*put)(img, raster+y*w+col, col, y,
+				    tw, nrow, 0, toskew, p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL));
+			}
+		}
+
+		y += (flip & FLIP_VERTICALLY ?-(int32) nrow : (int32) nrow);
+	}
+
+	if (flip & FLIP_HORIZONTALLY) {
+		uint32 line;
+
+		for (line = 0; line < h; line++) {
+			uint32 *left = raster + (line * w);
+			uint32 *right = left + w - 1;
+
+			while ( left < right ) {
+				uint32 temp = *left;
+				*left = *right;
+				*right = temp;
+				left++, right--;
+			}
+		}
+	}
+
+	_TIFFfree(buf);
+	return (ret);
+}
+
+/*
+ * Get a strip-organized image that has
+ *	PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ *	SamplesPerPixel == 1
+ */	
+static int
+gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+	TIFF* tif = img->tif;
+	tileContigRoutine put = img->put.contig;
+	uint32 row, y, nrow, nrowsub, rowstoread;
+	tmsize_t pos;
+	unsigned char* buf;
+	uint32 rowsperstrip;
+	uint16 subsamplinghor,subsamplingver;
+	uint32 imagewidth = img->width;
+	tmsize_t scanline;
+	int32 fromskew, toskew;
+	int ret = 1, flip;
+
+	buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif));
+	if (buf == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
+		return (0);
+	}
+	_TIFFmemset(buf, 0, TIFFStripSize(tif));
+
+	flip = setorientation(img);
+	if (flip & FLIP_VERTICALLY) {
+		y = h - 1;
+		toskew = -(int32)(w + w);
+	} else {
+		y = 0;
+		toskew = -(int32)(w - w);
+	}
+
+	TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+	TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver);
+	scanline = TIFFScanlineSize(tif);
+	fromskew = (w < imagewidth ? imagewidth - w : 0);
+	for (row = 0; row < h; row += nrow)
+	{
+		rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip;
+		nrow = (row + rowstoread > h ? h - row : rowstoread);
+		nrowsub = nrow;
+		if ((nrowsub%subsamplingver)!=0)
+			nrowsub+=subsamplingver-nrowsub%subsamplingver;
+		if (TIFFReadEncodedStrip(tif,
+		    TIFFComputeStrip(tif,row+img->row_offset, 0),
+		    buf,
+		    ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline)==(tmsize_t)(-1)
+		    && img->stoponerr)
+		{
+			ret = 0;
+			break;
+		}
+
+		pos = ((row + img->row_offset) % rowsperstrip) * scanline;
+		(*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf + pos);
+		y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow);
+	}
+
+	if (flip & FLIP_HORIZONTALLY) {
+		uint32 line;
+
+		for (line = 0; line < h; line++) {
+			uint32 *left = raster + (line * w);
+			uint32 *right = left + w - 1;
+
+			while ( left < right ) {
+				uint32 temp = *left;
+				*left = *right;
+				*right = temp;
+				left++, right--;
+			}
+		}
+	}
+
+	_TIFFfree(buf);
+	return (ret);
+}
+
+/*
+ * Get a strip-organized image with
+ *	 SamplesPerPixel > 1
+ *	 PlanarConfiguration separated
+ * We assume that all such images are RGB.
+ */
+static int
+gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+	TIFF* tif = img->tif;
+	tileSeparateRoutine put = img->put.separate;
+	unsigned char *buf;
+	unsigned char *p0, *p1, *p2, *pa;
+	uint32 row, y, nrow, rowstoread;
+	tmsize_t pos;
+	tmsize_t scanline;
+	uint32 rowsperstrip, offset_row;
+	uint32 imagewidth = img->width;
+	tmsize_t stripsize;
+	tmsize_t bufsize;
+	int32 fromskew, toskew;
+	int alpha = img->alpha;
+	int ret = 1, flip, colorchannels;
+
+	stripsize = TIFFStripSize(tif);  
+	bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,stripsize);
+	if (bufsize == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtStripSeparate");
+		return (0);
+	}
+	p0 = buf = (unsigned char *)_TIFFmalloc(bufsize);
+	if (buf == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+		return (0);
+	}
+	_TIFFmemset(buf, 0, bufsize);
+	p1 = p0 + stripsize;
+	p2 = p1 + stripsize;
+	pa = (alpha?(p2+stripsize):NULL);
+
+	flip = setorientation(img);
+	if (flip & FLIP_VERTICALLY) {
+		y = h - 1;
+		toskew = -(int32)(w + w);
+	}
+	else {
+		y = 0;
+		toskew = -(int32)(w - w);
+	}
+
+        switch( img->photometric )
+        {
+          case PHOTOMETRIC_MINISWHITE:
+          case PHOTOMETRIC_MINISBLACK:
+          case PHOTOMETRIC_PALETTE:
+            colorchannels = 1;
+            p2 = p1 = p0;
+            break;
+
+          default:
+            colorchannels = 3;
+            break;
+        }
+
+	TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+	scanline = TIFFScanlineSize(tif);  
+	fromskew = (w < imagewidth ? imagewidth - w : 0);
+	for (row = 0; row < h; row += nrow)
+	{
+		rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip;
+		nrow = (row + rowstoread > h ? h - row : rowstoread);
+		offset_row = row + img->row_offset;
+		if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0),
+		    p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1)
+		    && img->stoponerr)
+		{
+			ret = 0;
+			break;
+		}
+		if (colorchannels > 1 
+                    && TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1),
+                                            p1, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) == (tmsize_t)(-1)
+		    && img->stoponerr)
+		{
+			ret = 0;
+			break;
+		}
+		if (colorchannels > 1 
+                    && TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2),
+                                            p2, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) == (tmsize_t)(-1)
+		    && img->stoponerr)
+		{
+			ret = 0;
+			break;
+		}
+		if (alpha)
+		{
+			if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, colorchannels),
+			    pa, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1)
+			    && img->stoponerr)
+			{
+				ret = 0;
+				break;
+			}
+		}
+
+		pos = ((row + img->row_offset) % rowsperstrip) * scanline;
+		(*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, p0 + pos, p1 + pos,
+		    p2 + pos, (alpha?(pa+pos):NULL));
+		y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow);
+	}
+
+	if (flip & FLIP_HORIZONTALLY) {
+		uint32 line;
+
+		for (line = 0; line < h; line++) {
+			uint32 *left = raster + (line * w);
+			uint32 *right = left + w - 1;
+
+			while ( left < right ) {
+				uint32 temp = *left;
+				*left = *right;
+				*right = temp;
+				left++, right--;
+			}
+		}
+	}
+
+	_TIFFfree(buf);
+	return (ret);
+}
+
+/*
+ * The following routines move decoded data returned
+ * from the TIFF library into rasters filled with packed
+ * ABGR pixels (i.e. suitable for passing to lrecwrite.)
+ *
+ * The routines have been created according to the most
+ * important cases and optimized.  PickContigCase and
+ * PickSeparateCase analyze the parameters and select
+ * the appropriate "get" and "put" routine to use.
+ */
+#define	REPEAT8(op)	REPEAT4(op); REPEAT4(op)
+#define	REPEAT4(op)	REPEAT2(op); REPEAT2(op)
+#define	REPEAT2(op)	op; op
+#define	CASE8(x,op)			\
+    switch (x) {			\
+    case 7: op; case 6: op; case 5: op;	\
+    case 4: op; case 3: op; case 2: op;	\
+    case 1: op;				\
+    }
+#define	CASE4(x,op)	switch (x) { case 3: op; case 2: op; case 1: op; }
+#define	NOP
+
+#define	UNROLL8(w, op1, op2) {		\
+    uint32 _x;				\
+    for (_x = w; _x >= 8; _x -= 8) {	\
+	op1;				\
+	REPEAT8(op2);			\
+    }					\
+    if (_x > 0) {			\
+	op1;				\
+	CASE8(_x,op2);			\
+    }					\
+}
+#define	UNROLL4(w, op1, op2) {		\
+    uint32 _x;				\
+    for (_x = w; _x >= 4; _x -= 4) {	\
+	op1;				\
+	REPEAT4(op2);			\
+    }					\
+    if (_x > 0) {			\
+	op1;				\
+	CASE4(_x,op2);			\
+    }					\
+}
+#define	UNROLL2(w, op1, op2) {		\
+    uint32 _x;				\
+    for (_x = w; _x >= 2; _x -= 2) {	\
+	op1;				\
+	REPEAT2(op2);			\
+    }					\
+    if (_x) {				\
+	op1;				\
+	op2;				\
+    }					\
+}
+    
+#define	SKEW(r,g,b,skew)	{ r += skew; g += skew; b += skew; }
+#define	SKEW4(r,g,b,a,skew)	{ r += skew; g += skew; b += skew; a+= skew; }
+
+#define A1 (((uint32)0xffL)<<24)
+#define	PACK(r,g,b)	\
+	((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|A1)
+#define	PACK4(r,g,b,a)	\
+	((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24))
+#define W2B(v) (((v)>>8)&0xff)
+/* TODO: PACKW should have be made redundant in favor of Bitdepth16To8 LUT */
+#define	PACKW(r,g,b)	\
+	((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|A1)
+#define	PACKW4(r,g,b,a)	\
+	((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24))
+
+#define	DECLAREContigPutFunc(name) \
+static void name(\
+    TIFFRGBAImage* img, \
+    uint32* cp, \
+    uint32 x, uint32 y, \
+    uint32 w, uint32 h, \
+    int32 fromskew, int32 toskew, \
+    unsigned char* pp \
+)
+
+/*
+ * 8-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put8bitcmaptile)
+{
+    uint32** PALmap = img->PALmap;
+    int samplesperpixel = img->samplesperpixel;
+
+    (void) y;
+    while (h-- > 0) {
+	for (x = w; x-- > 0;)
+        {
+	    *cp++ = PALmap[*pp][0];
+            pp += samplesperpixel;
+        }
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 4-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put4bitcmaptile)
+{
+    uint32** PALmap = img->PALmap;
+
+    (void) x; (void) y;
+    fromskew /= 2;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 2-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put2bitcmaptile)
+{
+    uint32** PALmap = img->PALmap;
+
+    (void) x; (void) y;
+    fromskew /= 4;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 1-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put1bitcmaptile)
+{
+    uint32** PALmap = img->PALmap;
+
+    (void) x; (void) y;
+    fromskew /= 8;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 8-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(putgreytile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    uint32** BWmap = img->BWmap;
+
+    (void) y;
+    while (h-- > 0) {
+	for (x = w; x-- > 0;)
+        {
+	    *cp++ = BWmap[*pp][0];
+            pp += samplesperpixel;
+        }
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 8-bit greyscale with associated alpha => colormap/RGBA
+ */
+DECLAREContigPutFunc(putagreytile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    uint32** BWmap = img->BWmap;
+
+    (void) y;
+    while (h-- > 0) {
+	for (x = w; x-- > 0;)
+        {
+            *cp++ = BWmap[*pp][0] & (*(pp+1) << 24 | ~A1);
+            pp += samplesperpixel;
+        }
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 16-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put16bitbwtile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    uint32** BWmap = img->BWmap;
+
+    (void) y;
+    while (h-- > 0) {
+        uint16 *wp = (uint16 *) pp;
+
+	for (x = w; x-- > 0;)
+        {
+            /* use high order byte of 16bit value */
+
+	    *cp++ = BWmap[*wp >> 8][0];
+            pp += 2 * samplesperpixel;
+            wp += samplesperpixel;
+        }
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 1-bit bilevel => colormap/RGB
+ */
+DECLAREContigPutFunc(put1bitbwtile)
+{
+    uint32** BWmap = img->BWmap;
+
+    (void) x; (void) y;
+    fromskew /= 8;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 2-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put2bitbwtile)
+{
+    uint32** BWmap = img->BWmap;
+
+    (void) x; (void) y;
+    fromskew /= 4;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 4-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put4bitbwtile)
+{
+    uint32** BWmap = img->BWmap;
+
+    (void) x; (void) y;
+    fromskew /= 2;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 8-bit packed samples, no Map => RGB
+ */
+DECLAREContigPutFunc(putRGBcontig8bittile)
+{
+    int samplesperpixel = img->samplesperpixel;
+
+    (void) x; (void) y;
+    fromskew *= samplesperpixel;
+    while (h-- > 0) {
+	UNROLL8(w, NOP,
+	    *cp++ = PACK(pp[0], pp[1], pp[2]);
+	    pp += samplesperpixel);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 8-bit packed samples => RGBA w/ associated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBAAcontig8bittile)
+{
+    int samplesperpixel = img->samplesperpixel;
+
+    (void) x; (void) y;
+    fromskew *= samplesperpixel;
+    while (h-- > 0) {
+	UNROLL8(w, NOP,
+	    *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]);
+	    pp += samplesperpixel);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 8-bit packed samples => RGBA w/ unassociated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBUAcontig8bittile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		uint32 r, g, b, a;
+		uint8* m;
+		for (x = w; x-- > 0;) {
+			a = pp[3];
+			m = img->UaToAa+(a<<8);
+			r = m[pp[0]];
+			g = m[pp[1]];
+			b = m[pp[2]];
+			*cp++ = PACK4(r,g,b,a);
+			pp += samplesperpixel;
+		}
+		cp += toskew;
+		pp += fromskew;
+	}
+}
+
+/*
+ * 16-bit packed samples => RGB
+ */
+DECLAREContigPutFunc(putRGBcontig16bittile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	uint16 *wp = (uint16 *)pp;
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		for (x = w; x-- > 0;) {
+			*cp++ = PACK(img->Bitdepth16To8[wp[0]],
+			    img->Bitdepth16To8[wp[1]],
+			    img->Bitdepth16To8[wp[2]]);
+			wp += samplesperpixel;
+		}
+		cp += toskew;
+		wp += fromskew;
+	}
+}
+
+/*
+ * 16-bit packed samples => RGBA w/ associated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBAAcontig16bittile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	uint16 *wp = (uint16 *)pp;
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		for (x = w; x-- > 0;) {
+			*cp++ = PACK4(img->Bitdepth16To8[wp[0]],
+			    img->Bitdepth16To8[wp[1]],
+			    img->Bitdepth16To8[wp[2]],
+			    img->Bitdepth16To8[wp[3]]);
+			wp += samplesperpixel;
+		}
+		cp += toskew;
+		wp += fromskew;
+	}
+}
+
+/*
+ * 16-bit packed samples => RGBA w/ unassociated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBUAcontig16bittile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	uint16 *wp = (uint16 *)pp;
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		uint32 r,g,b,a;
+		uint8* m;
+		for (x = w; x-- > 0;) {
+			a = img->Bitdepth16To8[wp[3]];
+			m = img->UaToAa+(a<<8);
+			r = m[img->Bitdepth16To8[wp[0]]];
+			g = m[img->Bitdepth16To8[wp[1]]];
+			b = m[img->Bitdepth16To8[wp[2]]];
+			*cp++ = PACK4(r,g,b,a);
+			wp += samplesperpixel;
+		}
+		cp += toskew;
+		wp += fromskew;
+	}
+}
+
+/*
+ * 8-bit packed CMYK samples w/o Map => RGB
+ *
+ * NB: The conversion of CMYK->RGB is *very* crude.
+ */
+/*DECLAREContigPutFunc(putRGBcontig8bitCMYKtile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    uint16 r, g, b, k;
+	
+    (void) x; (void) y;
+    fromskew *= samplesperpixel;
+    while (h-- > 0) {
+		UNROLL8(w, NOP,
+	 	    k = 255 - pp[3];
+	 	    r = (k*(255-pp[0]))/255;
+	 	    g = (k*(255-pp[1]))/255;
+	 	    b = (k*(255-pp[2]))/255;
+		*cp++ = PACK(r, g, b);
+		pp += samplesperpixel);
+		cp += toskew;
+		pp += fromskew;
+}*/
+/* Modify in 20090723 by Sunliang.Liu */
+DECLAREContigPutFunc(putRGBcontig8bitCMYKtile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	uint8 r, g, b, k;
+
+	(void) x; (void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		UNROLL8(w, NOP,
+			if(!TIFFCmyk2Rgb(img->tif->tif_clientdata,pp[0],pp[1],pp[2],pp[3],
+				&r,&g,&b)){
+					k = 255 - pp[3];
+					r = (k*(255-pp[0]))/255;
+					g = (k*(255-pp[1]))/255;
+					b = (k*(255-pp[2]))/255;
+			}
+
+			*cp++ = PACK(r, g, b);
+			pp += samplesperpixel);
+			cp += toskew;
+			pp += fromskew;
+	}
+}
+
+/*
+ * 16-bit packed CMYK samples w/o Map => RGB(8-bit)
+ *
+ * NB: The conversion of CMYK->RGB is *very* crude.
+ */
+DECLAREContigPutFunc(putRGBcontig16bitCMYKtile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	uint16* wp = (uint16*)pp;
+	uint8 C, M, Y, K;
+	uint8 r, g, b;
+
+	(void) x; (void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		UNROLL8(w, NOP,
+			C = wp[0]>>8;M = wp[1]>>8;Y = wp[2]>>8;K = wp[3]>>8;
+		if(!TIFFCmyk2Rgb(img->tif->tif_clientdata,C,M,Y,K,
+			&r,&g,&b)){
+				K = 255 - K;
+				r = (K*(255-C))/255;
+				g = (K*(255-M))/255;
+				b = (K*(255-Y))/255;
+		}
+
+		*cp++ = PACK(r, g, b);
+		wp += samplesperpixel);
+		cp += toskew;
+		wp += fromskew;
+	}
+}
+
+/*
+ * 8-bit packed CMYK samples w/Map => RGB
+ *
+ * NB: The conversion of CMYK->RGB is *very* crude.
+ */
+/*
+DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    TIFFRGBValue* Map = img->Map;
+    uint16 r, g, b, k;
+
+    (void) y;
+    fromskew *= samplesperpixel;
+    while (h-- > 0) {
+	for (x = w; x-- > 0;) {
+	    k = 255 - pp[3];
+	    r = (k*(255-pp[0]))/255;
+	    g = (k*(255-pp[1]))/255;
+	    b = (k*(255-pp[2]))/255;
+	    *cp++ = PACK(Map[r], Map[g], Map[b]);
+	    pp += samplesperpixel;
+	}
+	pp += fromskew;
+	cp += toskew;
+    }
+}*/
+/* Modify in 20090723 by Sunliang.Liu */
+DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	TIFFRGBValue* Map = img->Map;
+	uint8 r, g, b, k;
+
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		for (x = w; x-- > 0;) {
+			if(!TIFFCmyk2Rgb(img->tif->tif_clientdata,pp[0],pp[1],pp[2],pp[3],
+				&r,&g,&b)){
+					k = 255 - pp[3];
+					r = (k*(255-pp[0]))/255;
+					g = (k*(255-pp[1]))/255;
+					b = (k*(255-pp[2]))/255;
+			}
+			*cp++ = PACK(Map[r], Map[g], Map[b]);
+			pp += samplesperpixel;
+		}
+		pp += fromskew;
+		cp += toskew;
+	}
+}
+
+/*
+ * 16-bit packed CMYK samples w/Map => RGB(8-bit)
+ *
+ * NB: The conversion of CMYK->RGB is *very* crude.
+ */
+DECLAREContigPutFunc(putRGBcontig16bitCMYKMaptile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	TIFFRGBValue* Map = img->Map;
+	uint16* wp = (uint16*)pp;
+	uint8 C, M, Y, K;
+	uint8 r, g, b;
+
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		for (x = w; x-- > 0;) {
+			C = wp[0]>>8;M = wp[1]>>8;Y = wp[2]>>8;K = wp[3]>>8;
+			if(!TIFFCmyk2Rgb(img->tif->tif_clientdata,C,M,Y,K,
+				&r,&g,&b)){
+					K = 255 - K;
+					r = (K*(255-C))/255;
+					g = (K*(255-M))/255;
+					b = (K*(255-Y))/255;
+			}
+			*cp++ = PACK(Map[r], Map[g], Map[b]);
+			wp += samplesperpixel;
+		}
+		wp += fromskew;
+		cp += toskew;
+	}
+}
+
+#define	DECLARESepPutFunc(name) \
+static void name(\
+    TIFFRGBAImage* img,\
+    uint32* cp,\
+    uint32 x, uint32 y, \
+    uint32 w, uint32 h,\
+    int32 fromskew, int32 toskew,\
+    unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a\
+)
+
+/*
+ * 8-bit unpacked samples => RGB
+ */
+DECLARESepPutFunc(putRGBseparate8bittile)
+{
+    (void) img; (void) x; (void) y; (void) a;
+    while (h-- > 0) {
+	UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++));
+	SKEW(r, g, b, fromskew);
+	cp += toskew;
+    }
+}
+
+/*
+ * 8-bit unpacked samples => RGBA w/ associated alpha
+ */
+DECLARESepPutFunc(putRGBAAseparate8bittile)
+{
+	(void) img; (void) x; (void) y; 
+	while (h-- > 0) {
+		UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++));
+		SKEW4(r, g, b, a, fromskew);
+		cp += toskew;
+	}
+}
+
+/*
+ * 8-bit unpacked CMYK samples => RGBA
+ */
+DECLARESepPutFunc(putCMYKseparate8bittile)
+{
+	(void) img; (void) y;
+	while (h-- > 0) {
+		uint32 rv, gv, bv, kv;
+		for (x = w; x-- > 0;) {
+			kv = 255 - *a++;
+			rv = (kv*(255-*r++))/255;
+			gv = (kv*(255-*g++))/255;
+			bv = (kv*(255-*b++))/255;
+			*cp++ = PACK4(rv,gv,bv,255);
+		}
+		SKEW4(r, g, b, a, fromskew);
+		cp += toskew;
+	}
+}
+
+/*
+ * 8-bit unpacked samples => RGBA w/ unassociated alpha
+ */
+DECLARESepPutFunc(putRGBUAseparate8bittile)
+{
+	(void) img; (void) y;
+	while (h-- > 0) {
+		uint32 rv, gv, bv, av;
+		uint8* m;
+		for (x = w; x-- > 0;) {
+			av = *a++;
+			m = img->UaToAa+(av<<8);
+			rv = m[*r++];
+			gv = m[*g++];
+			bv = m[*b++];
+			*cp++ = PACK4(rv,gv,bv,av);
+		}
+		SKEW4(r, g, b, a, fromskew);
+		cp += toskew;
+	}
+}
+
+/*
+ * 16-bit unpacked samples => RGB
+ */
+DECLARESepPutFunc(putRGBseparate16bittile)
+{
+	uint16 *wr = (uint16*) r;
+	uint16 *wg = (uint16*) g;
+	uint16 *wb = (uint16*) b;
+	(void) img; (void) y; (void) a;
+	while (h-- > 0) {
+		for (x = 0; x < w; x++)
+			*cp++ = PACK(img->Bitdepth16To8[*wr++],
+			    img->Bitdepth16To8[*wg++],
+			    img->Bitdepth16To8[*wb++]);
+		SKEW(wr, wg, wb, fromskew);
+		cp += toskew;
+	}
+}
+
+/*
+ * 16-bit unpacked samples => RGBA w/ associated alpha
+ */
+DECLARESepPutFunc(putRGBAAseparate16bittile)
+{
+	uint16 *wr = (uint16*) r;
+	uint16 *wg = (uint16*) g;
+	uint16 *wb = (uint16*) b;
+	uint16 *wa = (uint16*) a;
+	(void) img; (void) y;
+	while (h-- > 0) {
+		for (x = 0; x < w; x++)
+			*cp++ = PACK4(img->Bitdepth16To8[*wr++],
+			    img->Bitdepth16To8[*wg++],
+			    img->Bitdepth16To8[*wb++],
+			    img->Bitdepth16To8[*wa++]);
+		SKEW4(wr, wg, wb, wa, fromskew);
+		cp += toskew;
+	}
+}
+
+/*
+ * 16-bit unpacked samples => RGBA w/ unassociated alpha
+ */
+DECLARESepPutFunc(putRGBUAseparate16bittile)
+{
+	uint16 *wr = (uint16*) r;
+	uint16 *wg = (uint16*) g;
+	uint16 *wb = (uint16*) b;
+	uint16 *wa = (uint16*) a;
+	(void) img; (void) y;
+	while (h-- > 0) {
+		uint32 r,g,b,a;
+		uint8* m;
+		for (x = w; x-- > 0;) {
+			a = img->Bitdepth16To8[*wa++];
+			m = img->UaToAa+(a<<8);
+			r = m[img->Bitdepth16To8[*wr++]];
+			g = m[img->Bitdepth16To8[*wg++]];
+			b = m[img->Bitdepth16To8[*wb++]];
+			*cp++ = PACK4(r,g,b,a);
+		}
+		SKEW4(wr, wg, wb, wa, fromskew);
+		cp += toskew;
+	}
+}
+
+/*
+ * 8-bit packed CIE L*a*b 1976 samples => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitCIELab)
+{
+	float X, Y, Z;
+	uint32 r, g, b;
+	(void) y;
+	fromskew *= 3;
+	while (h-- > 0) {
+		for (x = w; x-- > 0;) {
+			TIFFCIELabToXYZ(img->cielab,
+					(unsigned char)pp[0],
+					(signed char)pp[1],
+					(signed char)pp[2],
+					&X, &Y, &Z);
+			TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b);
+			*cp++ = PACK(r, g, b);
+			pp += 3;
+		}
+		cp += toskew;
+		pp += fromskew;
+	}
+}
+
+/*
+ * YCbCr -> RGB conversion and packing routines.
+ */
+
+#define	YCbCrtoRGB(dst, Y) {						\
+	uint32 r, g, b;							\
+	TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b);		\
+	dst = PACK(r, g, b);						\
+}
+
+/*
+ * 8-bit packed YCbCr samples => RGB 
+ * This function is generic for different sampling sizes, 
+ * and can handle blocks sizes that aren't multiples of the
+ * sampling size.  However, it is substantially less optimized
+ * than the specific sampling cases.  It is used as a fallback
+ * for difficult blocks.
+ */
+#ifdef notdef
+static void putcontig8bitYCbCrGenericTile( 
+    TIFFRGBAImage* img, 
+    uint32* cp, 
+    uint32 x, uint32 y, 
+    uint32 w, uint32 h, 
+    int32 fromskew, int32 toskew, 
+    unsigned char* pp,
+    int h_group, 
+    int v_group )
+
+{
+    uint32* cp1 = cp+w+toskew;
+    uint32* cp2 = cp1+w+toskew;
+    uint32* cp3 = cp2+w+toskew;
+    int32 incr = 3*w+4*toskew;
+    int32   Cb, Cr;
+    int     group_size = v_group * h_group + 2;
+
+    (void) y;
+    fromskew = (fromskew * group_size) / h_group;
+
+    for( yy = 0; yy < h; yy++ )
+    {
+        unsigned char *pp_line;
+        int     y_line_group = yy / v_group;
+        int     y_remainder = yy - y_line_group * v_group;
+
+        pp_line = pp + v_line_group * 
+
+        
+        for( xx = 0; xx < w; xx++ )
+        {
+            Cb = pp
+        }
+    }
+    for (; h >= 4; h -= 4) {
+	x = w>>2;
+	do {
+	    Cb = pp[16];
+	    Cr = pp[17];
+
+	    YCbCrtoRGB(cp [0], pp[ 0]);
+	    YCbCrtoRGB(cp [1], pp[ 1]);
+	    YCbCrtoRGB(cp [2], pp[ 2]);
+	    YCbCrtoRGB(cp [3], pp[ 3]);
+	    YCbCrtoRGB(cp1[0], pp[ 4]);
+	    YCbCrtoRGB(cp1[1], pp[ 5]);
+	    YCbCrtoRGB(cp1[2], pp[ 6]);
+	    YCbCrtoRGB(cp1[3], pp[ 7]);
+	    YCbCrtoRGB(cp2[0], pp[ 8]);
+	    YCbCrtoRGB(cp2[1], pp[ 9]);
+	    YCbCrtoRGB(cp2[2], pp[10]);
+	    YCbCrtoRGB(cp2[3], pp[11]);
+	    YCbCrtoRGB(cp3[0], pp[12]);
+	    YCbCrtoRGB(cp3[1], pp[13]);
+	    YCbCrtoRGB(cp3[2], pp[14]);
+	    YCbCrtoRGB(cp3[3], pp[15]);
+
+	    cp += 4, cp1 += 4, cp2 += 4, cp3 += 4;
+	    pp += 18;
+	} while (--x);
+	cp += incr, cp1 += incr, cp2 += incr, cp3 += incr;
+	pp += fromskew;
+    }
+}
+#endif
+
+/*
+ * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr44tile)
+{
+    uint32* cp1 = cp+w+toskew;
+    uint32* cp2 = cp1+w+toskew;
+    uint32* cp3 = cp2+w+toskew;
+    int32 incr = 3*w+4*toskew;
+
+    (void) y;
+    /* adjust fromskew */
+    fromskew = (fromskew * 18) / 4;
+    if ((h & 3) == 0 && (w & 3) == 0) {				        
+        for (; h >= 4; h -= 4) {
+            x = w>>2;
+            do {
+                int32 Cb = pp[16];
+                int32 Cr = pp[17];
+
+                YCbCrtoRGB(cp [0], pp[ 0]);
+                YCbCrtoRGB(cp [1], pp[ 1]);
+                YCbCrtoRGB(cp [2], pp[ 2]);
+                YCbCrtoRGB(cp [3], pp[ 3]);
+                YCbCrtoRGB(cp1[0], pp[ 4]);
+                YCbCrtoRGB(cp1[1], pp[ 5]);
+                YCbCrtoRGB(cp1[2], pp[ 6]);
+                YCbCrtoRGB(cp1[3], pp[ 7]);
+                YCbCrtoRGB(cp2[0], pp[ 8]);
+                YCbCrtoRGB(cp2[1], pp[ 9]);
+                YCbCrtoRGB(cp2[2], pp[10]);
+                YCbCrtoRGB(cp2[3], pp[11]);
+                YCbCrtoRGB(cp3[0], pp[12]);
+                YCbCrtoRGB(cp3[1], pp[13]);
+                YCbCrtoRGB(cp3[2], pp[14]);
+                YCbCrtoRGB(cp3[3], pp[15]);
+
+                cp += 4, cp1 += 4, cp2 += 4, cp3 += 4;
+                pp += 18;
+            } while (--x);
+            cp += incr, cp1 += incr, cp2 += incr, cp3 += incr;
+            pp += fromskew;
+        }
+    } else {
+        while (h > 0) {
+            for (x = w; x > 0;) {
+                int32 Cb = pp[16];
+                int32 Cr = pp[17];
+                switch (x) {
+                default:
+                    switch (h) {
+                    default: YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */
+                    case 3:  YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */
+                    case 2:  YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */
+                    case 1:  YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */
+                    }                                    /* FALLTHROUGH */
+                case 3:
+                    switch (h) {
+                    default: YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */
+                    case 3:  YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */
+                    case 2:  YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */
+                    case 1:  YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */
+                    }                                    /* FALLTHROUGH */
+                case 2:
+                    switch (h) {
+                    default: YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */
+                    case 3:  YCbCrtoRGB(cp2[1], pp[ 9]); /* FALLTHROUGH */
+                    case 2:  YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */
+                    case 1:  YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */
+                    }                                    /* FALLTHROUGH */
+                case 1:
+                    switch (h) {
+                    default: YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */
+                    case 3:  YCbCrtoRGB(cp2[0], pp[ 8]); /* FALLTHROUGH */
+                    case 2:  YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */
+                    case 1:  YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */
+                    }                                    /* FALLTHROUGH */
+                }
+                if (x < 4) {
+                    cp += x; cp1 += x; cp2 += x; cp3 += x;
+                    x = 0;
+                }
+                else {
+                    cp += 4; cp1 += 4; cp2 += 4; cp3 += 4;
+                    x -= 4;
+                }
+                pp += 18;
+            }
+            if (h <= 4)
+                break;
+            h -= 4;
+            cp += incr, cp1 += incr, cp2 += incr, cp3 += incr;
+            pp += fromskew;
+        }
+    }
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr42tile)
+{
+    uint32* cp1 = cp+w+toskew;
+    int32 incr = 2*toskew+w;
+
+    (void) y;
+    fromskew = (fromskew * 10) / 4;
+    if ((h & 3) == 0 && (w & 1) == 0) {
+        for (; h >= 2; h -= 2) {
+            x = w>>2;
+            do {
+                int32 Cb = pp[8];
+                int32 Cr = pp[9];
+                
+                YCbCrtoRGB(cp [0], pp[0]);
+                YCbCrtoRGB(cp [1], pp[1]);
+                YCbCrtoRGB(cp [2], pp[2]);
+                YCbCrtoRGB(cp [3], pp[3]);
+                YCbCrtoRGB(cp1[0], pp[4]);
+                YCbCrtoRGB(cp1[1], pp[5]);
+                YCbCrtoRGB(cp1[2], pp[6]);
+                YCbCrtoRGB(cp1[3], pp[7]);
+                
+                cp += 4, cp1 += 4;
+                pp += 10;
+            } while (--x);
+            cp += incr, cp1 += incr;
+            pp += fromskew;
+        }
+    } else {
+        while (h > 0) {
+            for (x = w; x > 0;) {
+                int32 Cb = pp[8];
+                int32 Cr = pp[9];
+                switch (x) {
+                default:
+                    switch (h) {
+                    default: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */
+                    case 1:  YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */
+                    }                                    /* FALLTHROUGH */
+                case 3:
+                    switch (h) {
+                    default: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */
+                    case 1:  YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */
+                    }                                    /* FALLTHROUGH */
+                case 2:
+                    switch (h) {
+                    default: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */
+                    case 1:  YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */
+                    }                                    /* FALLTHROUGH */
+                case 1:
+                    switch (h) {
+                    default: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */
+                    case 1:  YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */
+                    }                                    /* FALLTHROUGH */
+                }
+                if (x < 4) {
+                    cp += x; cp1 += x;
+                    x = 0;
+                }
+                else {
+                    cp += 4; cp1 += 4;
+                    x -= 4;
+                }
+                pp += 10;
+            }
+            if (h <= 2)
+                break;
+            h -= 2;
+            cp += incr, cp1 += incr;
+            pp += fromskew;
+        }
+    }
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr41tile)
+{
+    (void) y;
+    /* XXX adjust fromskew */
+    do {
+	x = w>>2;
+	do {
+	    int32 Cb = pp[4];
+	    int32 Cr = pp[5];
+
+	    YCbCrtoRGB(cp [0], pp[0]);
+	    YCbCrtoRGB(cp [1], pp[1]);
+	    YCbCrtoRGB(cp [2], pp[2]);
+	    YCbCrtoRGB(cp [3], pp[3]);
+
+	    cp += 4;
+	    pp += 6;
+	} while (--x);
+
+        if( (w&3) != 0 )
+        {
+	    int32 Cb = pp[4];
+	    int32 Cr = pp[5];
+
+            switch( (w&3) ) {
+              case 3: YCbCrtoRGB(cp [2], pp[2]);
+              case 2: YCbCrtoRGB(cp [1], pp[1]);
+              case 1: YCbCrtoRGB(cp [0], pp[0]);
+              case 0: break;
+            }
+
+            cp += (w&3);
+            pp += 6;
+        }
+
+	cp += toskew;
+	pp += fromskew;
+    } while (--h);
+
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr22tile)
+{
+	uint32* cp2;
+	int32 incr = 2*toskew+w;
+	(void) y;
+	fromskew = (fromskew / 2) * 6;
+	cp2 = cp+w+toskew;
+	while (h>=2) {
+		x = w;
+		while (x>=2) {
+			uint32 Cb = pp[4];
+			uint32 Cr = pp[5];
+			YCbCrtoRGB(cp[0], pp[0]);
+			YCbCrtoRGB(cp[1], pp[1]);
+			YCbCrtoRGB(cp2[0], pp[2]);
+			YCbCrtoRGB(cp2[1], pp[3]);
+			cp += 2;
+			cp2 += 2;
+			pp += 6;
+			x -= 2;
+		}
+		if (x==1) {
+			uint32 Cb = pp[4];
+			uint32 Cr = pp[5];
+			YCbCrtoRGB(cp[0], pp[0]);
+			YCbCrtoRGB(cp2[0], pp[2]);
+			cp ++ ;
+			cp2 ++ ;
+			pp += 6;
+		}
+		cp += incr;
+		cp2 += incr;
+		pp += fromskew;
+		h-=2;
+	}
+	if (h==1) {
+		x = w;
+		while (x>=2) {
+			uint32 Cb = pp[4];
+			uint32 Cr = pp[5];
+			YCbCrtoRGB(cp[0], pp[0]);
+			YCbCrtoRGB(cp[1], pp[1]);
+			cp += 2;
+			cp2 += 2;
+			pp += 6;
+			x -= 2;
+		}
+		if (x==1) {
+			uint32 Cb = pp[4];
+			uint32 Cr = pp[5];
+			YCbCrtoRGB(cp[0], pp[0]);
+		}
+	}
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr21tile)
+{
+	(void) y;
+	fromskew = (fromskew * 4) / 2;
+	do {
+		x = w>>1;
+		do {
+			int32 Cb = pp[2];
+			int32 Cr = pp[3];
+
+			YCbCrtoRGB(cp[0], pp[0]);
+			YCbCrtoRGB(cp[1], pp[1]);
+
+			cp += 2;
+			pp += 4;
+		} while (--x);
+
+		if( (w&1) != 0 )
+		{
+			int32 Cb = pp[2];
+			int32 Cr = pp[3];
+
+			YCbCrtoRGB(cp[0], pp[0]);
+
+			cp += 1;
+			pp += 4;
+		}
+
+		cp += toskew;
+		pp += fromskew;
+	} while (--h);
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 1,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr12tile)
+{
+	uint32* cp2;
+	int32 incr = 2*toskew+w;
+	(void) y;
+	fromskew = (fromskew / 2) * 4;
+	cp2 = cp+w+toskew;
+	while (h>=2) {
+		x = w;
+		do {
+			uint32 Cb = pp[2];
+			uint32 Cr = pp[3];
+			YCbCrtoRGB(cp[0], pp[0]);
+			YCbCrtoRGB(cp2[0], pp[1]);
+			cp ++;
+			cp2 ++;
+			pp += 4;
+		} while (--x);
+		cp += incr;
+		cp2 += incr;
+		pp += fromskew;
+		h-=2;
+	}
+	if (h==1) {
+		x = w;
+		do {
+			uint32 Cb = pp[2];
+			uint32 Cr = pp[3];
+			YCbCrtoRGB(cp[0], pp[0]);
+			cp ++;
+			pp += 4;
+		} while (--x);
+	}
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ no subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr11tile)
+{
+	(void) y;
+	fromskew *= 3;
+	do {
+		x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */
+		do {
+			int32 Cb = pp[1];
+			int32 Cr = pp[2];
+
+			YCbCrtoRGB(*cp++, pp[0]);
+
+			pp += 3;
+		} while (--x);
+		cp += toskew;
+		pp += fromskew;
+	} while (--h);
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ no subsampling => RGB
+ */
+DECLARESepPutFunc(putseparate8bitYCbCr11tile)
+{
+	(void) y;
+	(void) a;
+	/* TODO: naming of input vars is still off, change obfuscating declaration inside define, or resolve obfuscation */
+	while (h-- > 0) {
+		x = w;
+		do {
+			uint32 dr, dg, db;
+			TIFFYCbCrtoRGB(img->ycbcr,*r++,*g++,*b++,&dr,&dg,&db);
+			*cp++ = PACK(dr,dg,db);
+		} while (--x);
+		SKEW(r, g, b, fromskew);
+		cp += toskew;
+	}
+}
+#undef YCbCrtoRGB
+
+static int
+initYCbCrConversion(TIFFRGBAImage* img)
+{
+	static const char module[] = "initYCbCrConversion";
+
+	float *luma, *refBlackWhite;
+
+	if (img->ycbcr == NULL) {
+		img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc(
+		    TIFFroundup_32(sizeof (TIFFYCbCrToRGB), sizeof (long))  
+		    + 4*256*sizeof (TIFFRGBValue)
+		    + 2*256*sizeof (int)
+		    + 3*256*sizeof (int32)
+		    );
+		if (img->ycbcr == NULL) {
+			TIFFErrorExt(img->tif->tif_clientdata, module,
+			    "No space for YCbCr->RGB conversion state");
+			return (0);
+		}
+	}
+
+	TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma);
+	TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE,
+	    &refBlackWhite);
+	if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0)
+		return(0);
+	return (1);
+}
+
+static tileContigRoutine
+initCIELabConversion(TIFFRGBAImage* img)
+{
+	static const char module[] = "initCIELabConversion";
+
+	float   *whitePoint;
+	float   refWhite[3];
+
+	if (!img->cielab) {
+		img->cielab = (TIFFCIELabToRGB *)
+			_TIFFmalloc(sizeof(TIFFCIELabToRGB));
+		if (!img->cielab) {
+			TIFFErrorExt(img->tif->tif_clientdata, module,
+			    "No space for CIE L*a*b*->RGB conversion state.");
+			return NULL;
+		}
+	}
+
+	TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint);
+	refWhite[1] = 100.0F;
+	refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1];
+	refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1])
+		      / whitePoint[1] * refWhite[1];
+	if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0) {
+		TIFFErrorExt(img->tif->tif_clientdata, module,
+		    "Failed to initialize CIE L*a*b*->RGB conversion state.");
+		_TIFFfree(img->cielab);
+		return NULL;
+	}
+
+	return (tileContigRoutine)putcontig8bitCIELab;
+}
+
+/*
+ * Greyscale images with less than 8 bits/sample are handled
+ * with a table to avoid lots of shifts and masks.  The table
+ * is setup so that put*bwtile (below) can retrieve 8/bitspersample
+ * pixel values simply by indexing into the table with one
+ * number.
+ */
+static int
+makebwmap(TIFFRGBAImage* img)
+{
+    TIFFRGBValue* Map = img->Map;
+    int bitspersample = img->bitspersample;
+    int nsamples = 8 / bitspersample;
+    int i;
+    uint32* p;
+
+    if( nsamples == 0 )
+        nsamples = 1;
+
+    img->BWmap = (uint32**) _TIFFmalloc(
+	256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32)));
+    if (img->BWmap == NULL) {
+		TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for B&W mapping table");
+		return (0);
+    }
+    p = (uint32*)(img->BWmap + 256);
+    for (i = 0; i < 256; i++) {
+	TIFFRGBValue c;
+	img->BWmap[i] = p;
+	switch (bitspersample) {
+#define	GREY(x)	c = Map[x]; *p++ = PACK(c,c,c);
+	case 1:
+	    GREY(i>>7);
+	    GREY((i>>6)&1);
+	    GREY((i>>5)&1);
+	    GREY((i>>4)&1);
+	    GREY((i>>3)&1);
+	    GREY((i>>2)&1);
+	    GREY((i>>1)&1);
+	    GREY(i&1);
+	    break;
+	case 2:
+	    GREY(i>>6);
+	    GREY((i>>4)&3);
+	    GREY((i>>2)&3);
+	    GREY(i&3);
+	    break;
+	case 4:
+	    GREY(i>>4);
+	    GREY(i&0xf);
+	    break;
+	case 8:
+        case 16:
+	    GREY(i);
+	    break;
+	}
+#undef	GREY
+    }
+    return (1);
+}
+
+/*
+ * Construct a mapping table to convert from the range
+ * of the data samples to [0,255] --for display.  This
+ * process also handles inverting B&W images when needed.
+ */ 
+static int
+setupMap(TIFFRGBAImage* img)
+{
+    int32 x, range;
+
+    range = (int32)((1L<<img->bitspersample)-1);
+    
+    /* treat 16 bit the same as eight bit */
+    if( img->bitspersample == 16 )
+        range = (int32) 255;
+
+    img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue));
+    if (img->Map == NULL) {
+		TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif),
+			"No space for photometric conversion table");
+		return (0);
+    }
+    if (img->photometric == PHOTOMETRIC_MINISWHITE) {
+	for (x = 0; x <= range; x++)
+	    img->Map[x] = (TIFFRGBValue) (((range - x) * 255) / range);
+    } else {
+	for (x = 0; x <= range; x++)
+	    img->Map[x] = (TIFFRGBValue) ((x * 255) / range);
+    }
+    if (img->bitspersample <= 16 &&
+	(img->photometric == PHOTOMETRIC_MINISBLACK ||
+	 img->photometric == PHOTOMETRIC_MINISWHITE)) {
+	/*
+	 * Use photometric mapping table to construct
+	 * unpacking tables for samples <= 8 bits.
+	 */
+	if (!makebwmap(img))
+	    return (0);
+	/* no longer need Map, free it */
+	_TIFFfree(img->Map), img->Map = NULL;
+    }
+    return (1);
+}
+
+static int
+checkcmap(TIFFRGBAImage* img)
+{
+    uint16* r = img->redcmap;
+    uint16* g = img->greencmap;
+    uint16* b = img->bluecmap;
+    long n = 1L<<img->bitspersample;
+
+    while (n-- > 0)
+	if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+	    return (16);
+    return (8);
+}
+
+static void
+cvtcmap(TIFFRGBAImage* img)
+{
+    uint16* r = img->redcmap;
+    uint16* g = img->greencmap;
+    uint16* b = img->bluecmap;
+    long i;
+
+    for (i = (1L<<img->bitspersample)-1; i >= 0; i--) {
+#define	CVT(x)		((uint16)((x)>>8))
+	r[i] = CVT(r[i]);
+	g[i] = CVT(g[i]);
+	b[i] = CVT(b[i]);
+#undef	CVT
+    }
+}
+
+/*
+ * Palette images with <= 8 bits/sample are handled
+ * with a table to avoid lots of shifts and masks.  The table
+ * is setup so that put*cmaptile (below) can retrieve 8/bitspersample
+ * pixel values simply by indexing into the table with one
+ * number.
+ */
+static int
+makecmap(TIFFRGBAImage* img)
+{
+    int bitspersample = img->bitspersample;
+    int nsamples = 8 / bitspersample;
+    uint16* r = img->redcmap;
+    uint16* g = img->greencmap;
+    uint16* b = img->bluecmap;
+    uint32 *p;
+    int i;
+
+    img->PALmap = (uint32**) _TIFFmalloc(
+	256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32)));
+    if (img->PALmap == NULL) {
+		TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for Palette mapping table");
+		return (0);
+	}
+    p = (uint32*)(img->PALmap + 256);
+    for (i = 0; i < 256; i++) {
+	TIFFRGBValue c;
+	img->PALmap[i] = p;
+#define	CMAP(x)	c = (TIFFRGBValue) x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff);
+	switch (bitspersample) {
+	case 1:
+	    CMAP(i>>7);
+	    CMAP((i>>6)&1);
+	    CMAP((i>>5)&1);
+	    CMAP((i>>4)&1);
+	    CMAP((i>>3)&1);
+	    CMAP((i>>2)&1);
+	    CMAP((i>>1)&1);
+	    CMAP(i&1);
+	    break;
+	case 2:
+	    CMAP(i>>6);
+	    CMAP((i>>4)&3);
+	    CMAP((i>>2)&3);
+	    CMAP(i&3);
+	    break;
+	case 4:
+	    CMAP(i>>4);
+	    CMAP(i&0xf);
+	    break;
+	case 8:
+	    CMAP(i);
+	    break;
+	}
+#undef CMAP
+    }
+    return (1);
+}
+
+/* 
+ * Construct any mapping table used
+ * by the associated put routine.
+ */
+static int
+buildMap(TIFFRGBAImage* img)
+{
+    switch (img->photometric) {
+    case PHOTOMETRIC_RGB:
+    case PHOTOMETRIC_YCBCR:
+    case PHOTOMETRIC_SEPARATED:
+	if (img->bitspersample == 8)
+	    break;
+	/* fall thru... */
+    case PHOTOMETRIC_MINISBLACK:
+    case PHOTOMETRIC_MINISWHITE:
+	if (!setupMap(img))
+	    return (0);
+	break;
+    case PHOTOMETRIC_PALETTE:
+	/*
+	 * Convert 16-bit colormap to 8-bit (unless it looks
+	 * like an old-style 8-bit colormap).
+	 */
+	if (checkcmap(img) == 16)
+	    cvtcmap(img);
+	else
+	    TIFFWarningExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "Assuming 8-bit colormap");
+	/*
+	 * Use mapping table and colormap to construct
+	 * unpacking tables for samples < 8 bits.
+	 */
+	if (img->bitspersample <= 8 && !makecmap(img))
+	    return (0);
+	break;
+    }
+    return (1);
+}
+
+/*
+ * Select the appropriate conversion routine for packed data.
+ */
+static int
+PickContigCase(TIFFRGBAImage* img)
+{
+	img->get = TIFFIsTiled(img->tif) ? gtTileContig : gtStripContig;
+	img->put.contig = NULL;
+	switch (img->photometric) {
+		case PHOTOMETRIC_RGB:
+			switch (img->bitspersample) {
+				case 8:
+					if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+						img->put.contig = putRGBAAcontig8bittile;
+					else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+					{
+						if (BuildMapUaToAa(img))
+							img->put.contig = putRGBUAcontig8bittile;
+					}
+					else
+						img->put.contig = putRGBcontig8bittile;
+					break;
+				case 16:
+					if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+					{
+						if (BuildMapBitdepth16To8(img))
+							img->put.contig = putRGBAAcontig16bittile;
+					}
+					else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+					{
+						if (BuildMapBitdepth16To8(img) &&
+						    BuildMapUaToAa(img))
+							img->put.contig = putRGBUAcontig16bittile;
+					}
+					else
+					{
+						if (BuildMapBitdepth16To8(img))
+							img->put.contig = putRGBcontig16bittile;
+					}
+					break;
+			}
+			break;
+		case PHOTOMETRIC_SEPARATED:
+			if (buildMap(img)) {
+				if (img->bitspersample == 8) {
+				if (!img->Map)
+					img->put.contig = putRGBcontig8bitCMYKtile;
+				else
+					img->put.contig = putRGBcontig8bitCMYKMaptile;
+			}
+			else if(img->bitspersample == 16) /*LiuSunliang added 16bpp CMYK support.*/
+			{
+				if (!img->Map)
+					img->put.contig = putRGBcontig16bitCMYKtile;
+				else
+					img->put.contig = putRGBcontig16bitCMYKMaptile;
+			}
+		}
+		break;
+	case PHOTOMETRIC_PALETTE:
+			if (buildMap(img)) {
+				switch (img->bitspersample) {
+					case 8:
+						img->put.contig = put8bitcmaptile;
+						break;
+					case 4:
+						img->put.contig = put4bitcmaptile;
+						break;
+					case 2:
+						img->put.contig = put2bitcmaptile;
+						break;
+					case 1:
+						img->put.contig = put1bitcmaptile;
+						break;
+				}
+			}
+			break;
+		case PHOTOMETRIC_MINISWHITE:
+		case PHOTOMETRIC_MINISBLACK:
+			if (buildMap(img)) {
+				switch (img->bitspersample) {
+					case 16:
+						img->put.contig = put16bitbwtile;
+						break;
+					case 8:
+						if (img->alpha && img->samplesperpixel == 2)
+							img->put.contig = putagreytile;
+						else
+							img->put.contig = putgreytile;
+						break;
+					case 4:
+						img->put.contig = put4bitbwtile;
+						break;
+					case 2:
+						img->put.contig = put2bitbwtile;
+						break;
+					case 1:
+						img->put.contig = put1bitbwtile;
+						break;
+				}
+			}
+			break;
+		case PHOTOMETRIC_YCBCR:
+			if ((img->bitspersample==8) && (img->samplesperpixel==3))
+			{
+				if (initYCbCrConversion(img)!=0)
+				{
+					/*
+					 * The 6.0 spec says that subsampling must be
+					 * one of 1, 2, or 4, and that vertical subsampling
+					 * must always be <= horizontal subsampling; so
+					 * there are only a few possibilities and we just
+					 * enumerate the cases.
+					 * Joris: added support for the [1,2] case, nonetheless, to accomodate
+					 * some OJPEG files
+					 */
+					uint16 SubsamplingHor;
+					uint16 SubsamplingVer;
+					TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &SubsamplingHor, &SubsamplingVer);
+					switch ((SubsamplingHor<<4)|SubsamplingVer) {
+						case 0x44:
+							img->put.contig = putcontig8bitYCbCr44tile;
+							break;
+						case 0x42:
+							img->put.contig = putcontig8bitYCbCr42tile;
+							break;
+						case 0x41:
+							img->put.contig = putcontig8bitYCbCr41tile;
+							break;
+						case 0x22:
+							img->put.contig = putcontig8bitYCbCr22tile;
+							break;
+						case 0x21:
+							img->put.contig = putcontig8bitYCbCr21tile;
+							break;
+						case 0x12:
+							img->put.contig = putcontig8bitYCbCr12tile;
+							break;
+						case 0x11:
+							img->put.contig = putcontig8bitYCbCr11tile;
+							break;
+					}
+				}
+			}
+			break;
+		case PHOTOMETRIC_CIELAB:
+			if (buildMap(img)) {
+				if (img->bitspersample == 8)
+					img->put.contig = initCIELabConversion(img);
+				break;
+			}
+	}
+	return ((img->get!=NULL) && (img->put.contig!=NULL));
+}
+
+/*
+ * Select the appropriate conversion routine for unpacked data.
+ *
+ * NB: we assume that unpacked single channel data is directed
+ *	 to the "packed routines.
+ */
+static int
+PickSeparateCase(TIFFRGBAImage* img)
+{
+	img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate;
+	img->put.separate = NULL;
+	switch (img->photometric) {
+	case PHOTOMETRIC_MINISWHITE:
+	case PHOTOMETRIC_MINISBLACK:
+		/* greyscale images processed pretty much as RGB by gtTileSeparate */
+	case PHOTOMETRIC_RGB:
+		switch (img->bitspersample) {
+		case 8:
+			if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+				img->put.separate = putRGBAAseparate8bittile;
+			else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+			{
+				if (BuildMapUaToAa(img))
+					img->put.separate = putRGBUAseparate8bittile;
+			}
+			else
+				img->put.separate = putRGBseparate8bittile;
+			break;
+		case 16:
+			if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+			{
+				if (BuildMapBitdepth16To8(img))
+					img->put.separate = putRGBAAseparate16bittile;
+			}
+			else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+			{
+				if (BuildMapBitdepth16To8(img) &&
+				    BuildMapUaToAa(img))
+					img->put.separate = putRGBUAseparate16bittile;
+			}
+			else
+			{
+				if (BuildMapBitdepth16To8(img))
+					img->put.separate = putRGBseparate16bittile;
+			}
+			break;
+		}
+		break;
+	case PHOTOMETRIC_SEPARATED:
+		if (img->bitspersample == 8 && img->samplesperpixel == 4)
+		{
+			img->alpha = 1; // Not alpha, but seems like the only way to get 4th band
+			img->put.separate = putCMYKseparate8bittile;
+		}
+		break;
+	case PHOTOMETRIC_YCBCR:
+		if ((img->bitspersample==8) && (img->samplesperpixel==3))
+		{
+			if (initYCbCrConversion(img)!=0)
+			{
+				uint16 hs, vs;
+				TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs);
+				switch ((hs<<4)|vs) {
+				case 0x11:
+					img->put.separate = putseparate8bitYCbCr11tile;
+					break;
+					/* TODO: add other cases here */
+				}
+			}
+		}
+		break;
+	}
+	return ((img->get!=NULL) && (img->put.separate!=NULL));
+}
+
+static int
+BuildMapUaToAa(TIFFRGBAImage* img)
+{
+	static const char module[]="BuildMapUaToAa";
+	uint8* m;
+	uint16 na,nv;
+	assert(img->UaToAa==NULL);
+	img->UaToAa=_TIFFmalloc(65536);
+	if (img->UaToAa==NULL)
+	{
+		TIFFErrorExt(img->tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	m=img->UaToAa;
+	for (na=0; na<256; na++)
+	{
+		for (nv=0; nv<256; nv++)
+			*m++=(nv*na+127)/255;
+	}
+	return(1);
+}
+
+static int
+BuildMapBitdepth16To8(TIFFRGBAImage* img)
+{
+	static const char module[]="BuildMapBitdepth16To8";
+	uint8* m;
+	uint32 n;
+	assert(img->Bitdepth16To8==NULL);
+	img->Bitdepth16To8=_TIFFmalloc(65536);
+	if (img->Bitdepth16To8==NULL)
+	{
+		TIFFErrorExt(img->tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	m=img->Bitdepth16To8;
+	for (n=0; n<65536; n++)
+		*m++=(n+128)/257;
+	return(1);
+}
+
+
+/*
+ * Read a whole strip off data from the file, and convert to RGBA form.
+ * If this is the last strip, then it will only contain the portion of
+ * the strip that is actually within the image space.  The result is
+ * organized in bottom to top form.
+ */
+
+
+int
+TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster )
+
+{
+    char 	emsg[1024] = "";
+    TIFFRGBAImage img;
+    int 	ok;
+    uint32	rowsperstrip, rows_to_read;
+
+    if( TIFFIsTiled( tif ) )
+    {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+                  "Can't use TIFFReadRGBAStrip() with tiled file.");
+	return (0);
+    }
+    
+    TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+    if( (row % rowsperstrip) != 0 )
+    {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+				"Row passed to TIFFReadRGBAStrip() must be first in a strip.");
+		return (0);
+    }
+
+    if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
+
+        img.row_offset = row;
+        img.col_offset = 0;
+
+        if( row + rowsperstrip > img.height )
+            rows_to_read = img.height - row;
+        else
+            rows_to_read = rowsperstrip;
+        
+	ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read );
+        
+	TIFFRGBAImageEnd(&img);
+    } else {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg);
+		ok = 0;
+    }
+    
+    return (ok);
+}
+
+/*
+ * Read a whole tile off data from the file, and convert to RGBA form.
+ * The returned RGBA data is organized from bottom to top of tile,
+ * and may include zeroed areas if the tile extends off the image.
+ */
+
+int
+TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster)
+
+{
+    char 	emsg[1024] = "";
+    TIFFRGBAImage img;
+    int 	ok;
+    uint32	tile_xsize, tile_ysize;
+    uint32	read_xsize, read_ysize;
+    uint32	i_row;
+
+    /*
+     * Verify that our request is legal - on a tile file, and on a
+     * tile boundary.
+     */
+    
+    if( !TIFFIsTiled( tif ) )
+    {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+				  "Can't use TIFFReadRGBATile() with stripped file.");
+		return (0);
+    }
+    
+    TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize);
+    TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize);
+    if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 )
+    {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+                  "Row/col passed to TIFFReadRGBATile() must be top"
+                  "left corner of a tile.");
+	return (0);
+    }
+
+    /*
+     * Setup the RGBA reader.
+     */
+    
+    if (!TIFFRGBAImageOK(tif, emsg) 
+	|| !TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
+	    TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg);
+	    return( 0 );
+    }
+
+    /*
+     * The TIFFRGBAImageGet() function doesn't allow us to get off the
+     * edge of the image, even to fill an otherwise valid tile.  So we
+     * figure out how much we can read, and fix up the tile buffer to
+     * a full tile configuration afterwards.
+     */
+
+    if( row + tile_ysize > img.height )
+        read_ysize = img.height - row;
+    else
+        read_ysize = tile_ysize;
+    
+    if( col + tile_xsize > img.width )
+        read_xsize = img.width - col;
+    else
+        read_xsize = tile_xsize;
+
+    /*
+     * Read the chunk of imagery.
+     */
+    
+    img.row_offset = row;
+    img.col_offset = col;
+
+    ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize );
+        
+    TIFFRGBAImageEnd(&img);
+
+    /*
+     * If our read was incomplete we will need to fix up the tile by
+     * shifting the data around as if a full tile of data is being returned.
+     *
+     * This is all the more complicated because the image is organized in
+     * bottom to top format. 
+     */
+
+    if( read_xsize == tile_xsize && read_ysize == tile_ysize )
+        return( ok );
+
+    for( i_row = 0; i_row < read_ysize; i_row++ ) {
+        memmove( raster + (tile_ysize - i_row - 1) * tile_xsize,
+                 raster + (read_ysize - i_row - 1) * read_xsize,
+                 read_xsize * sizeof(uint32) );
+        _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize,
+                     0, sizeof(uint32) * (tile_xsize - read_xsize) );
+    }
+
+    for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) {
+        _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize,
+                     0, sizeof(uint32) * tile_xsize );
+    }
+
+    return (ok);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_jpeg.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_jpeg.c
new file mode 100644
index 0000000..84f0f9e
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_jpeg.c
@@ -0,0 +1,2311 @@
+/* $Id: tif_jpeg.c,v 1.111 2012-07-06 18:48:04 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1994-1997 Sam Leffler
+ * Copyright (c) 1994-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+
+#include "tiffiop.h"
+#ifdef JPEG_SUPPORT
+
+/*
+ * TIFF Library
+ *
+ * JPEG Compression support per TIFF Technical Note #2
+ * (*not* per the original TIFF 6.0 spec).
+ *
+ * This file is simply an interface to the libjpeg library written by
+ * the Independent JPEG Group.  You need release 5 or later of the IJG
+ * code, which you can find on the Internet at ftp.uu.net:/graphics/jpeg/.
+ *
+ * Contributed by Tom Lane <tgl@sss.pgh.pa.us>.
+ */
+#include <setjmp.h>
+
+int TIFFFillStrip(TIFF* tif, uint32 strip);
+int TIFFFillTile(TIFF* tif, uint32 tile);
+int TIFFReInitJPEG_12( TIFF *tif, int scheme, int is_encode );
+
+/* We undefine FAR to avoid conflict with JPEG definition */
+
+#ifdef FAR
+#undef FAR
+#endif
+
+/*
+  Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is
+  not defined.  Unfortunately, the MinGW and Borland compilers include
+  a typedef for INT32, which causes a conflict.  MSVC does not include
+  a conficting typedef given the headers which are included.
+*/
+#if defined(__BORLANDC__) || defined(__MINGW32__)
+# define XMD_H 1
+#endif
+
+/*
+   The windows RPCNDR.H file defines boolean, but defines it with the
+   unsigned char size.  You should compile JPEG library using appropriate
+   definitions in jconfig.h header, but many users compile library in wrong
+   way. That causes errors of the following type:
+
+   "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432,
+   caller expects 464"
+
+   For such users we wil fix the problem here. See install.doc file from
+   the JPEG library distribution for details.
+*/
+
+/* Define "boolean" as unsigned char, not int, per Windows custom. */
+#if defined(WIN32) && !defined(__MINGW32__)
+# ifndef __RPCNDR_H__            /* don't conflict if rpcndr.h already read */
+   typedef unsigned char boolean;
+# endif
+# define HAVE_BOOLEAN            /* prevent jmorecfg.h from redefining it */
+#endif
+
+#ifndef _FX_JPEG_TURBO_
+	#include "../../libjpeg/jpeglib.h"
+	#include "../../libjpeg/jerror.h"
+#else
+	#include "../../libjpeg-turbo/jpeglib.h"
+	#include "../../libjpeg-turbo/jerror.h"
+#endif//_FX_JPEG_TURBO_
+
+/* 
+ * Do we want to do special processing suitable for when JSAMPLE is a
+ * 16bit value?  
+ */
+
+#if defined(JPEG_LIB_MK1)
+#  define JPEG_LIB_MK1_OR_12BIT 1
+#elif BITS_IN_JSAMPLE == 12
+#  define JPEG_LIB_MK1_OR_12BIT 1
+#endif
+
+/*
+ * We are using width_in_blocks which is supposed to be private to
+ * libjpeg. Unfortunately, the libjpeg delivered with Cygwin has
+ * renamed this member to width_in_data_units.  Since the header has
+ * also renamed a define, use that unique define name in order to
+ * detect the problem header and adjust to suit.
+ */
+#if defined(D_MAX_DATA_UNITS_IN_MCU)
+#define width_in_blocks width_in_data_units
+#endif
+
+/*
+ * On some machines it may be worthwhile to use _setjmp or sigsetjmp
+ * in place of plain setjmp.  These macros will make it easier.
+ */
+#define SETJMP(jbuf)		setjmp(jbuf)
+#define LONGJMP(jbuf,code)	longjmp(jbuf,code)
+#define JMP_BUF			jmp_buf
+
+typedef struct jpeg_destination_mgr jpeg_destination_mgr;
+typedef struct jpeg_source_mgr jpeg_source_mgr;
+typedef struct jpeg_error_mgr jpeg_error_mgr;
+
+/*
+ * State block for each open TIFF file using
+ * libjpeg to do JPEG compression/decompression.
+ *
+ * libjpeg's visible state is either a jpeg_compress_struct
+ * or jpeg_decompress_struct depending on which way we
+ * are going.  comm can be used to refer to the fields
+ * which are common to both.
+ *
+ * NB: cinfo is required to be the first member of JPEGState,
+ *     so we can safely cast JPEGState* -> jpeg_xxx_struct*
+ *     and vice versa!
+ */
+typedef struct {
+	union {
+		struct jpeg_compress_struct c;
+		struct jpeg_decompress_struct d;
+		struct jpeg_common_struct comm;
+	} cinfo;			/* NB: must be first */
+	int             cinfo_initialized;
+
+	jpeg_error_mgr	err;		/* libjpeg error manager */
+	JMP_BUF		exit_jmpbuf;	/* for catching libjpeg failures */
+	/*
+	 * The following two members could be a union, but
+	 * they're small enough that it's not worth the effort.
+	 */
+	jpeg_destination_mgr dest;	/* data dest for compression */
+	jpeg_source_mgr	src;		/* data source for decompression */
+					/* private state */
+	TIFF*		tif;		/* back link needed by some code */
+	uint16		photometric;	/* copy of PhotometricInterpretation */
+	uint16		h_sampling;	/* luminance sampling factors */
+	uint16		v_sampling;
+	tmsize_t   	bytesperline;	/* decompressed bytes per scanline */
+	/* pointers to intermediate buffers when processing downsampled data */
+	JSAMPARRAY	ds_buffer[MAX_COMPONENTS];
+	int		scancount;	/* number of "scanlines" accumulated */
+	int		samplesperclump;
+
+	TIFFVGetMethod	vgetparent;	/* super-class method */
+	TIFFVSetMethod	vsetparent;	/* super-class method */
+	TIFFPrintMethod printdir;	/* super-class method */
+	TIFFStripMethod	defsparent;	/* super-class method */
+	TIFFTileMethod	deftparent;	/* super-class method */
+					/* pseudo-tag fields */
+	void*		jpegtables;	/* JPEGTables tag value, or NULL */
+	uint32		jpegtables_length; /* number of bytes in same */
+	int		jpegquality;	/* Compression quality level */
+	int		jpegcolormode;	/* Auto RGB<=>YCbCr convert? */
+	int		jpegtablesmode;	/* What to put in JPEGTables */
+
+        int             ycbcrsampling_fetched;
+} JPEGState;
+
+#define	JState(tif)	((JPEGState*)(tif)->tif_data)
+
+static int JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int JPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int JPEGEncodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int JPEGInitializeLibJPEG(TIFF * tif, int decode );
+static int DecodeRowError(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+
+#define	FIELD_JPEGTABLES	(FIELD_CODEC+0)
+
+static const TIFFField jpegFields[] = {
+    { TIFFTAG_JPEGTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_C32_UINT8, FIELD_JPEGTABLES, FALSE, TRUE, "JPEGTables", NULL },
+    { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL },
+    { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL },
+    { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL }
+};
+
+/*
+ * libjpeg interface layer.
+ *
+ * We use setjmp/longjmp to return control to libtiff
+ * when a fatal error is encountered within the JPEG
+ * library.  We also direct libjpeg error and warning
+ * messages through the appropriate libtiff handlers.
+ */
+
+/*
+ * Error handling routines (these replace corresponding
+ * IJG routines from jerror.c).  These are used for both
+ * compression and decompression.
+ */
+static void
+TIFFjpeg_error_exit(j_common_ptr cinfo)
+{
+	JPEGState *sp = (JPEGState *) cinfo;	/* NB: cinfo assumed first */
+	char buffer[JMSG_LENGTH_MAX];
+
+	(*cinfo->err->format_message) (cinfo, buffer);
+	TIFFErrorExt(sp->tif->tif_clientdata, "JPEGLib", "%s", buffer);		/* display the error message */
+	jpeg_abort(cinfo);			/* clean up libjpeg state */
+	LONGJMP(sp->exit_jmpbuf, 1);		/* return to libtiff caller */
+}
+
+/*
+ * This routine is invoked only for warning messages,
+ * since error_exit does its own thing and trace_level
+ * is never set > 0.
+ */
+static void
+TIFFjpeg_output_message(j_common_ptr cinfo)
+{
+	char buffer[JMSG_LENGTH_MAX];
+
+	(*cinfo->err->format_message) (cinfo, buffer);
+	TIFFWarningExt(((JPEGState *) cinfo)->tif->tif_clientdata, "JPEGLib", "%s", buffer);
+}
+
+/*
+ * Interface routines.  This layer of routines exists
+ * primarily to limit side-effects from using setjmp.
+ * Also, normal/error returns are converted into return
+ * values per libtiff practice.
+ */
+#define	CALLJPEG(sp, fail, op)	(SETJMP((sp)->exit_jmpbuf) ? (fail) : (op))
+#define	CALLVJPEG(sp, op)	CALLJPEG(sp, 0, ((op),1))
+
+static int
+TIFFjpeg_create_compress(JPEGState* sp)
+{
+	/* initialize JPEG error handling */
+	sp->cinfo.c.err = jpeg_std_error(&sp->err);
+	sp->err.error_exit = TIFFjpeg_error_exit;
+	sp->err.output_message = TIFFjpeg_output_message;
+
+	return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_create_decompress(JPEGState* sp)
+{
+	/* initialize JPEG error handling */
+	sp->cinfo.d.err = jpeg_std_error(&sp->err);
+	sp->err.error_exit = TIFFjpeg_error_exit;
+	sp->err.output_message = TIFFjpeg_output_message;
+
+	return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_set_defaults(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace)
+{
+	return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace));
+}
+
+static int
+TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline)
+{
+	return CALLVJPEG(sp,
+	    jpeg_set_quality(&sp->cinfo.c, quality, force_baseline));
+}
+
+static int
+TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress)
+{
+	return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress));
+}
+
+static int
+TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables)
+{
+	return CALLVJPEG(sp,
+	    jpeg_start_compress(&sp->cinfo.c, write_all_tables));
+}
+
+static int
+TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c,
+	    scanlines, (JDIMENSION) num_lines));
+}
+
+static int
+TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c,
+	    data, (JDIMENSION) num_lines));
+}
+
+static int
+TIFFjpeg_finish_compress(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_write_tables(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_read_header(JPEGState* sp, boolean require_image)
+{
+	return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image));
+}
+
+static int
+TIFFjpeg_start_decompress(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d,
+	    scanlines, (JDIMENSION) max_lines));
+}
+
+static int
+TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d,
+	    data, (JDIMENSION) max_lines));
+}
+
+static int
+TIFFjpeg_finish_decompress(JPEGState* sp)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_abort(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm));
+}
+
+static int
+TIFFjpeg_destroy(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm));
+}
+
+static JSAMPARRAY
+TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id,
+		      JDIMENSION samplesperrow, JDIMENSION numrows)
+{
+	return CALLJPEG(sp, (JSAMPARRAY) NULL,
+	    (*sp->cinfo.comm.mem->alloc_sarray)
+		(&sp->cinfo.comm, pool_id, samplesperrow, numrows));
+}
+
+/*
+ * JPEG library destination data manager.
+ * These routines direct compressed data from libjpeg into the
+ * libtiff output buffer.
+ */
+
+static void
+std_init_destination(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	TIFF* tif = sp->tif;
+
+	sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata;
+	sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize;
+}
+
+static boolean
+std_empty_output_buffer(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	TIFF* tif = sp->tif;
+
+	/* the entire buffer has been filled */
+	tif->tif_rawcc = tif->tif_rawdatasize;
+
+#ifdef IPPJ_HUFF
+       /*
+        * The Intel IPP performance library does not necessarily fill up
+        * the whole output buffer on each pass, so only dump out the parts
+        * that have been filled.
+        *   http://trac.osgeo.org/gdal/wiki/JpegIPP
+        */
+       if ( sp->dest.free_in_buffer >= 0 ) {
+               tif->tif_rawcc = tif->tif_rawdatasize - sp->dest.free_in_buffer;
+       }
+#endif
+
+	TIFFFlushData1(tif);
+	sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata;
+	sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize;
+
+	return (TRUE);
+}
+
+static void
+std_term_destination(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	TIFF* tif = sp->tif;
+
+	tif->tif_rawcp = (uint8*) sp->dest.next_output_byte;
+	tif->tif_rawcc =
+	    tif->tif_rawdatasize - (tmsize_t) sp->dest.free_in_buffer;
+	/* NB: libtiff does the final buffer flush */
+}
+
+static void
+TIFFjpeg_data_dest(JPEGState* sp, TIFF* tif)
+{
+	(void) tif;
+	sp->cinfo.c.dest = &sp->dest;
+	sp->dest.init_destination = std_init_destination;
+	sp->dest.empty_output_buffer = std_empty_output_buffer;
+	sp->dest.term_destination = std_term_destination;
+}
+
+/*
+ * Alternate destination manager for outputting to JPEGTables field.
+ */
+
+static void
+tables_init_destination(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+
+	/* while building, jpegtables_length is allocated buffer size */
+	sp->dest.next_output_byte = (JOCTET*) sp->jpegtables;
+	sp->dest.free_in_buffer = (size_t) sp->jpegtables_length;
+}
+
+static boolean
+tables_empty_output_buffer(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	void* newbuf;
+
+	/* the entire buffer has been filled; enlarge it by 1000 bytes */
+	newbuf = _TIFFrealloc((void*) sp->jpegtables,
+			      (tmsize_t) (sp->jpegtables_length + 1000));
+	if (newbuf == NULL)
+		ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100);
+	sp->dest.next_output_byte = (JOCTET*) newbuf + sp->jpegtables_length;
+	sp->dest.free_in_buffer = (size_t) 1000;
+	sp->jpegtables = newbuf;
+	sp->jpegtables_length += 1000;
+	return (TRUE);
+}
+
+static void
+tables_term_destination(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+
+	/* set tables length to number of bytes actually emitted */
+	sp->jpegtables_length -= (uint32) sp->dest.free_in_buffer;
+}
+
+static int
+TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif)
+{
+	(void) tif;
+	/*
+	 * Allocate a working buffer for building tables.
+	 * Initial size is 1000 bytes, which is usually adequate.
+	 */
+	if (sp->jpegtables)
+		_TIFFfree(sp->jpegtables);
+	sp->jpegtables_length = 1000;
+	sp->jpegtables = (void*) _TIFFmalloc((tmsize_t) sp->jpegtables_length);
+	if (sp->jpegtables == NULL) {
+		sp->jpegtables_length = 0;
+		TIFFErrorExt(sp->tif->tif_clientdata, "TIFFjpeg_tables_dest", "No space for JPEGTables");
+		return (0);
+	}
+	sp->cinfo.c.dest = &sp->dest;
+	sp->dest.init_destination = tables_init_destination;
+	sp->dest.empty_output_buffer = tables_empty_output_buffer;
+	sp->dest.term_destination = tables_term_destination;
+	return (1);
+}
+
+/*
+ * JPEG library source data manager.
+ * These routines supply compressed data to libjpeg.
+ */
+
+static void
+std_init_source(j_decompress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	TIFF* tif = sp->tif;
+
+	sp->src.next_input_byte = (const JOCTET*) tif->tif_rawdata;
+	sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc;
+}
+
+static boolean
+std_fill_input_buffer(j_decompress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState* ) cinfo;
+	static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI };
+
+#ifdef IPPJ_HUFF
+        /*
+         * The Intel IPP performance library does not necessarily read the whole
+         * input buffer in one pass, so it is possible to get here with data
+         * yet to read. 
+         * 
+         * We just return without doing anything, until the entire buffer has
+         * been read.  
+         * http://trac.osgeo.org/gdal/wiki/JpegIPP
+         */
+        if( sp->src.bytes_in_buffer > 0 ) {
+            return (TRUE);
+        }
+#endif
+
+	/*
+         * Normally the whole strip/tile is read and so we don't need to do
+         * a fill.  In the case of CHUNKY_STRIP_READ_SUPPORT we might not have
+         * all the data, but the rawdata is refreshed between scanlines and
+         * we push this into the io machinery in JPEGDecode(). 	 
+         * http://trac.osgeo.org/gdal/ticket/3894
+	 */
+        
+	WARNMS(cinfo, JWRN_JPEG_EOF);
+	/* insert a fake EOI marker */
+	sp->src.next_input_byte = dummy_EOI;
+	sp->src.bytes_in_buffer = 2;
+	return (TRUE);
+}
+
+static void
+std_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+
+	if (num_bytes > 0) {
+		if ((size_t)num_bytes > sp->src.bytes_in_buffer) {
+			/* oops, buffer overrun */
+			(void) std_fill_input_buffer(cinfo);
+		} else {
+			sp->src.next_input_byte += (size_t) num_bytes;
+			sp->src.bytes_in_buffer -= (size_t) num_bytes;
+		}
+	}
+}
+
+static void
+std_term_source(j_decompress_ptr cinfo)
+{
+	/* No work necessary here */
+	(void) cinfo;
+}
+
+static void
+TIFFjpeg_data_src(JPEGState* sp, TIFF* tif)
+{
+	(void) tif;
+	sp->cinfo.d.src = &sp->src;
+	sp->src.init_source = std_init_source;
+	sp->src.fill_input_buffer = std_fill_input_buffer;
+	sp->src.skip_input_data = std_skip_input_data;
+	sp->src.resync_to_restart = jpeg_resync_to_restart;
+	sp->src.term_source = std_term_source;
+	sp->src.bytes_in_buffer = 0;		/* for safety */
+	sp->src.next_input_byte = NULL;
+}
+
+/*
+ * Alternate source manager for reading from JPEGTables.
+ * We can share all the code except for the init routine.
+ */
+
+static void
+tables_init_source(j_decompress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+
+	sp->src.next_input_byte = (const JOCTET*) sp->jpegtables;
+	sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length;
+}
+
+static void
+TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif)
+{
+	TIFFjpeg_data_src(sp, tif);
+	sp->src.init_source = tables_init_source;
+}
+
+/*
+ * Allocate downsampled-data buffers needed for downsampled I/O.
+ * We use values computed in jpeg_start_compress or jpeg_start_decompress.
+ * We use libjpeg's allocator so that buffers will be released automatically
+ * when done with strip/tile.
+ * This is also a handy place to compute samplesperclump, bytesperline.
+ */
+static int
+alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info,
+			  int num_components)
+{
+	JPEGState* sp = JState(tif);
+	int ci;
+	jpeg_component_info* compptr;
+	JSAMPARRAY buf;
+	int samples_per_clump = 0;
+
+	for (ci = 0, compptr = comp_info; ci < num_components;
+	     ci++, compptr++) {
+		samples_per_clump += compptr->h_samp_factor *
+			compptr->v_samp_factor;
+		buf = TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE,
+				compptr->width_in_blocks * DCTSIZE,
+				(JDIMENSION) (compptr->v_samp_factor*DCTSIZE));
+		if (buf == NULL)
+			return (0);
+		sp->ds_buffer[ci] = buf;
+	}
+	sp->samplesperclump = samples_per_clump;
+	return (1);
+}
+
+
+/*
+ * JPEG Decoding.
+ */
+
+#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING
+
+#define JPEG_MARKER_SOF0 0xC0
+#define JPEG_MARKER_SOF1 0xC1
+#define JPEG_MARKER_SOF3 0xC3
+#define JPEG_MARKER_DHT 0xC4
+#define JPEG_MARKER_SOI 0xD8
+#define JPEG_MARKER_SOS 0xDA
+#define JPEG_MARKER_DQT 0xDB
+#define JPEG_MARKER_DRI 0xDD
+#define JPEG_MARKER_APP0 0xE0
+#define JPEG_MARKER_COM 0xFE
+struct JPEGFixupTagsSubsamplingData
+{
+	TIFF* tif;
+	void* buffer;
+	uint32 buffersize;
+	uint8* buffercurrentbyte;
+	uint32 bufferbytesleft;
+	uint64 fileoffset;
+	uint64 filebytesleft;
+	uint8 filepositioned;
+};
+static void JPEGFixupTagsSubsampling(TIFF* tif);
+static int JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data);
+static int JPEGFixupTagsSubsamplingReadByte(struct JPEGFixupTagsSubsamplingData* data, uint8* result);
+static int JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData* data, uint16* result);
+static void JPEGFixupTagsSubsamplingSkip(struct JPEGFixupTagsSubsamplingData* data, uint16 skiplength);
+
+#endif
+
+static int
+JPEGFixupTags(TIFF* tif)
+{
+#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING
+	if ((tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR)&&
+	    (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&&
+	    (tif->tif_dir.td_samplesperpixel==3))
+		JPEGFixupTagsSubsampling(tif);
+#endif
+        
+	return(1);
+}
+
+#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING
+
+static void
+JPEGFixupTagsSubsampling(TIFF* tif)
+{
+	/*
+	 * Some JPEG-in-TIFF produces do not emit the YCBCRSUBSAMPLING values in
+	 * the TIFF tags, but still use non-default (2,2) values within the jpeg
+	 * data stream itself.  In order for TIFF applications to work properly
+	 * - for instance to get the strip buffer size right - it is imperative
+	 * that the subsampling be available before we start reading the image
+	 * data normally.  This function will attempt to analyze the first strip in
+	 * order to get the sampling values from the jpeg data stream.
+	 *
+	 * Note that JPEGPreDeocode() will produce a fairly loud warning when the
+	 * discovered sampling does not match the default sampling (2,2) or whatever
+	 * was actually in the tiff tags.
+	 *
+	 * See the bug in bugzilla for details:
+	 *
+	 * http://bugzilla.remotesensing.org/show_bug.cgi?id=168
+	 *
+	 * Frank Warmerdam, July 2002
+	 * Joris Van Damme, May 2007
+	 */
+	static const char module[] = "JPEGFixupTagsSubsampling";
+	struct JPEGFixupTagsSubsamplingData m;
+
+        _TIFFFillStriles( tif );
+        
+        if( tif->tif_dir.td_stripbytecount == NULL
+            || tif->tif_dir.td_stripbytecount[0] == 0 )
+        {
+            /* Do not even try to check if the first strip/tile does not
+               yet exist, as occurs when GDAL has created a new NULL file
+               for instance. */
+            return;
+        }
+
+	m.tif=tif;
+	m.buffersize=2048;
+	m.buffer=_TIFFmalloc(m.buffersize);
+	if (m.buffer==NULL)
+	{
+		TIFFWarningExt(tif->tif_clientdata,module,
+		    "Unable to allocate memory for auto-correcting of subsampling values; auto-correcting skipped");
+		return;
+	}
+	m.buffercurrentbyte=NULL;
+	m.bufferbytesleft=0;
+	m.fileoffset=tif->tif_dir.td_stripoffset[0];
+	m.filepositioned=0;
+	m.filebytesleft=tif->tif_dir.td_stripbytecount[0];
+	if (!JPEGFixupTagsSubsamplingSec(&m))
+		TIFFWarningExt(tif->tif_clientdata,module,
+		    "Unable to auto-correct subsampling values, likely corrupt JPEG compressed data in first strip/tile; auto-correcting skipped");
+	_TIFFfree(m.buffer);
+}
+
+static int
+JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data)
+{
+	static const char module[] = "JPEGFixupTagsSubsamplingSec";
+	uint8 m;
+	while (1)
+	{
+		while (1)
+		{
+			if (!JPEGFixupTagsSubsamplingReadByte(data,&m))
+				return(0);
+			if (m==255)
+				break;
+		}
+		while (1)
+		{
+			if (!JPEGFixupTagsSubsamplingReadByte(data,&m))
+				return(0);
+			if (m!=255)
+				break;
+		}
+		switch (m)
+		{
+			case JPEG_MARKER_SOI:
+				/* this type of marker has no data and should be skipped */
+				break;
+			case JPEG_MARKER_COM:
+			case JPEG_MARKER_APP0:
+			case JPEG_MARKER_APP0+1:
+			case JPEG_MARKER_APP0+2:
+			case JPEG_MARKER_APP0+3:
+			case JPEG_MARKER_APP0+4:
+			case JPEG_MARKER_APP0+5:
+			case JPEG_MARKER_APP0+6:
+			case JPEG_MARKER_APP0+7:
+			case JPEG_MARKER_APP0+8:
+			case JPEG_MARKER_APP0+9:
+			case JPEG_MARKER_APP0+10:
+			case JPEG_MARKER_APP0+11:
+			case JPEG_MARKER_APP0+12:
+			case JPEG_MARKER_APP0+13:
+			case JPEG_MARKER_APP0+14:
+			case JPEG_MARKER_APP0+15:
+			case JPEG_MARKER_DQT:
+			case JPEG_MARKER_SOS:
+			case JPEG_MARKER_DHT:
+			case JPEG_MARKER_DRI:
+				/* this type of marker has data, but it has no use to us and should be skipped */
+				{
+					uint16 n;
+					if (!JPEGFixupTagsSubsamplingReadWord(data,&n))
+						return(0);
+					if (n<2)
+						return(0);
+					n-=2;
+					if (n>0)
+						JPEGFixupTagsSubsamplingSkip(data,n);
+				}
+				break;
+			case JPEG_MARKER_SOF0:
+			case JPEG_MARKER_SOF1:
+				/* this marker contains the subsampling factors we're scanning for */
+				{
+					uint16 n;
+					uint16 o;
+					uint8 p;
+					uint8 ph,pv;
+					if (!JPEGFixupTagsSubsamplingReadWord(data,&n))
+						return(0);
+					if (n!=8+data->tif->tif_dir.td_samplesperpixel*3)
+						return(0);
+					JPEGFixupTagsSubsamplingSkip(data,7);
+					if (!JPEGFixupTagsSubsamplingReadByte(data,&p))
+						return(0);
+					ph=(p>>4);
+					pv=(p&15);
+					JPEGFixupTagsSubsamplingSkip(data,1);
+					for (o=1; o<data->tif->tif_dir.td_samplesperpixel; o++)
+					{
+						JPEGFixupTagsSubsamplingSkip(data,1);
+						if (!JPEGFixupTagsSubsamplingReadByte(data,&p))
+							return(0);
+						if (p!=0x11)
+						{
+							TIFFWarningExt(data->tif->tif_clientdata,module,
+							    "Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed");
+							return(1);
+						}
+						JPEGFixupTagsSubsamplingSkip(data,1);
+					}
+					if (((ph!=1)&&(ph!=2)&&(ph!=4))||((pv!=1)&&(pv!=2)&&(pv!=4)))
+					{
+						TIFFWarningExt(data->tif->tif_clientdata,module,
+						    "Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed");
+						return(1);
+					}
+					if ((ph!=data->tif->tif_dir.td_ycbcrsubsampling[0])||(pv!=data->tif->tif_dir.td_ycbcrsubsampling[1]))
+					{
+						TIFFWarningExt(data->tif->tif_clientdata,module,
+						    "Auto-corrected former TIFF subsampling values [%d,%d] to match subsampling values inside JPEG compressed data [%d,%d]",
+						    (int)data->tif->tif_dir.td_ycbcrsubsampling[0],
+						    (int)data->tif->tif_dir.td_ycbcrsubsampling[1],
+						    (int)ph,(int)pv);
+						data->tif->tif_dir.td_ycbcrsubsampling[0]=ph;
+						data->tif->tif_dir.td_ycbcrsubsampling[1]=pv;
+					}
+				}
+				return(1);
+			default:
+				return(0);
+		}
+	}
+}
+
+static int
+JPEGFixupTagsSubsamplingReadByte(struct JPEGFixupTagsSubsamplingData* data, uint8* result)
+{
+	if (data->bufferbytesleft==0)
+	{
+		uint32 m;
+		if (data->filebytesleft==0)
+			return(0);
+		if (!data->filepositioned)
+		{
+			TIFFSeekFile(data->tif,data->fileoffset,SEEK_SET);
+			data->filepositioned=1;
+		}
+		m=data->buffersize;
+		if ((uint64)m>data->filebytesleft)
+			m=(uint32)data->filebytesleft;
+		assert(m<0x80000000UL);
+		if (TIFFReadFile(data->tif,data->buffer,(tmsize_t)m)!=(tmsize_t)m)
+			return(0);
+		data->buffercurrentbyte=data->buffer;
+		data->bufferbytesleft=m;
+		data->fileoffset+=m;
+		data->filebytesleft-=m;
+	}
+	*result=*data->buffercurrentbyte;
+	data->buffercurrentbyte++;
+	data->bufferbytesleft--;
+	return(1);
+}
+
+static int
+JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData* data, uint16* result)
+{
+	uint8 ma;
+	uint8 mb;
+	if (!JPEGFixupTagsSubsamplingReadByte(data,&ma))
+		return(0);
+	if (!JPEGFixupTagsSubsamplingReadByte(data,&mb))
+		return(0);
+	*result=(ma<<8)|mb;
+	return(1);
+}
+
+static void
+JPEGFixupTagsSubsamplingSkip(struct JPEGFixupTagsSubsamplingData* data, uint16 skiplength)
+{
+	if ((uint32)skiplength<=data->bufferbytesleft)
+	{
+		data->buffercurrentbyte+=skiplength;
+		data->bufferbytesleft-=skiplength;
+	}
+	else
+	{
+		uint16 m;
+		m=skiplength-data->bufferbytesleft;
+		if (m<=data->filebytesleft)
+		{
+			data->bufferbytesleft=0;
+			data->fileoffset+=m;
+			data->filebytesleft-=m;
+			data->filepositioned=0;
+		}
+		else
+		{
+			data->bufferbytesleft=0;
+			data->filebytesleft=0;
+		}
+	}
+}
+
+#endif
+
+
+static int
+JPEGSetupDecode(TIFF* tif)
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+
+#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG)
+        if( tif->tif_dir.td_bitspersample == 12 )
+            return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 0 );
+#endif
+
+	JPEGInitializeLibJPEG( tif, TRUE );
+
+	assert(sp != NULL);
+	assert(sp->cinfo.comm.is_decompressor);
+
+	/* Read JPEGTables if it is present */
+	if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) {
+		TIFFjpeg_tables_src(sp, tif);
+		if(TIFFjpeg_read_header(sp,FALSE) != JPEG_HEADER_TABLES_ONLY) {
+			TIFFErrorExt(tif->tif_clientdata, "JPEGSetupDecode", "Bogus JPEGTables field");
+			return (0);
+		}
+	}
+
+	/* Grab parameters that are same for all strips/tiles */
+	sp->photometric = td->td_photometric;
+	switch (sp->photometric) {
+	case PHOTOMETRIC_YCBCR:
+		sp->h_sampling = td->td_ycbcrsubsampling[0];
+		sp->v_sampling = td->td_ycbcrsubsampling[1];
+		break;
+	default:
+		/* TIFF 6.0 forbids subsampling of all other color spaces */
+		sp->h_sampling = 1;
+		sp->v_sampling = 1;
+		break;
+	}
+
+	/* Set up for reading normal data */
+	TIFFjpeg_data_src(sp, tif);
+	tif->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */
+	return (1);
+}
+
+/*
+ * Set up for decoding a strip or tile.
+ */
+static int
+JPEGPreDecode(TIFF* tif, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+	static const char module[] = "JPEGPreDecode";
+	uint32 segment_width, segment_height;
+	int downsampled_output;
+	int ci;
+
+	assert(sp != NULL);
+  
+	if (sp->cinfo.comm.is_decompressor == 0)
+	{
+		tif->tif_setupdecode( tif );
+	}
+  
+	assert(sp->cinfo.comm.is_decompressor);
+	/*
+	 * Reset decoder state from any previous strip/tile,
+	 * in case application didn't read the whole strip.
+	 */
+	if (!TIFFjpeg_abort(sp))
+		return (0);
+	/*
+	 * Read the header for this strip/tile.
+	 */
+        
+	if (TIFFjpeg_read_header(sp, TRUE) != JPEG_HEADER_OK)
+		return (0);
+
+        tif->tif_rawcp = (uint8*) sp->src.next_input_byte;
+        tif->tif_rawcc = sp->src.bytes_in_buffer;
+
+	/*
+	 * Check image parameters and set decompression parameters.
+	 */
+	segment_width = td->td_imagewidth;
+	segment_height = td->td_imagelength - tif->tif_row;
+	if (isTiled(tif)) {
+                segment_width = td->td_tilewidth;
+                segment_height = td->td_tilelength;
+		sp->bytesperline = TIFFTileRowSize(tif);
+	} else {
+		if (segment_height > td->td_rowsperstrip)
+			segment_height = td->td_rowsperstrip;
+		sp->bytesperline = TIFFScanlineSize(tif);
+	}
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) {
+		/*
+		 * For PC 2, scale down the expected strip/tile size
+		 * to match a downsampled component
+		 */
+		segment_width = TIFFhowmany_32(segment_width, sp->h_sampling);
+		segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
+	}
+	if (sp->cinfo.d.image_width < segment_width ||
+	    sp->cinfo.d.image_height < segment_height) {
+		TIFFWarningExt(tif->tif_clientdata, module,
+			       "Improper JPEG strip/tile size, "
+			       "expected %dx%d, got %dx%d",
+			       segment_width, segment_height,
+			       sp->cinfo.d.image_width,
+			       sp->cinfo.d.image_height);
+	} 
+	if (sp->cinfo.d.image_width > segment_width ||
+	    sp->cinfo.d.image_height > segment_height) {
+		/*
+		 * This case could be dangerous, if the strip or tile size has
+		 * been reported as less than the amount of data jpeg will
+		 * return, some potential security issues arise. Catch this
+		 * case and error out.
+		 */
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "JPEG strip/tile size exceeds expected dimensions,"
+			     " expected %dx%d, got %dx%d",
+			     segment_width, segment_height,
+			     sp->cinfo.d.image_width, sp->cinfo.d.image_height);
+		return (0);
+	}
+	if (sp->cinfo.d.num_components !=
+	    (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+	     td->td_samplesperpixel : 1)) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG component count");
+		return (0);
+	}
+#ifdef JPEG_LIB_MK1
+	if (12 != td->td_bitspersample && 8 != td->td_bitspersample) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision");
+		return (0);
+	}
+	sp->cinfo.d.data_precision = td->td_bitspersample;
+	sp->cinfo.d.bits_in_jsample = td->td_bitspersample;
+#else
+	if (sp->cinfo.d.data_precision != td->td_bitspersample) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision");
+		return (0);
+	}
+#endif
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+		/* Component 0 should have expected sampling factors */
+		if (sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling ||
+		    sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				       "Improper JPEG sampling factors %d,%d\n"
+				       "Apparently should be %d,%d.",
+				       sp->cinfo.d.comp_info[0].h_samp_factor,
+				       sp->cinfo.d.comp_info[0].v_samp_factor,
+				       sp->h_sampling, sp->v_sampling);
+			return (0);
+		}
+		/* Rest should have sampling factors 1,1 */
+		for (ci = 1; ci < sp->cinfo.d.num_components; ci++) {
+			if (sp->cinfo.d.comp_info[ci].h_samp_factor != 1 ||
+			    sp->cinfo.d.comp_info[ci].v_samp_factor != 1) {
+				TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors");
+				return (0);
+			}
+		}
+	} else {
+		/* PC 2's single component should have sampling factors 1,1 */
+		if (sp->cinfo.d.comp_info[0].h_samp_factor != 1 ||
+		    sp->cinfo.d.comp_info[0].v_samp_factor != 1) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors");
+			return (0);
+		}
+	}
+	downsampled_output = FALSE;
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
+	    sp->photometric == PHOTOMETRIC_YCBCR &&
+	    sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+		/* Convert YCbCr to RGB */
+		sp->cinfo.d.jpeg_color_space = JCS_YCbCr;
+		sp->cinfo.d.out_color_space = JCS_RGB;
+	} else {
+		/* Suppress colorspace handling */
+		sp->cinfo.d.jpeg_color_space = JCS_UNKNOWN;
+		sp->cinfo.d.out_color_space = JCS_UNKNOWN;
+		if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
+		    (sp->h_sampling != 1 || sp->v_sampling != 1))
+			downsampled_output = TRUE;
+		/* XXX what about up-sampling? */
+	}
+	if (downsampled_output) {
+		/* Need to use raw-data interface to libjpeg */
+		sp->cinfo.d.raw_data_out = TRUE;
+#if JPEG_LIB_VERSION >= 70
+		sp->cinfo.d.do_fancy_upsampling = FALSE;
+#endif /* JPEG_LIB_VERSION >= 70 */
+		tif->tif_decoderow = DecodeRowError;
+		tif->tif_decodestrip = JPEGDecodeRaw;
+		tif->tif_decodetile = JPEGDecodeRaw;
+	} else {
+		/* Use normal interface to libjpeg */
+		sp->cinfo.d.raw_data_out = FALSE;
+		tif->tif_decoderow = JPEGDecode;
+		tif->tif_decodestrip = JPEGDecode;
+		tif->tif_decodetile = JPEGDecode;  
+	}
+	/* Start JPEG decompressor */
+	if (!TIFFjpeg_start_decompress(sp))
+		return (0);
+	/* Allocate downsampled-data buffers if needed */
+	if (downsampled_output) {
+		if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info,
+					       sp->cinfo.d.num_components))
+			return (0);
+		sp->scancount = DCTSIZE;	/* mark buffer empty */
+	}
+	return (1);
+}
+
+/*
+ * Decode a chunk of pixels.
+ * "Standard" case: returned data is not downsampled.
+ */
+/*ARGSUSED*/ static int
+JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	tmsize_t nrows;
+	(void) s;
+
+        /*
+        ** Update available information, buffer may have been refilled
+        ** between decode requests
+        */
+	sp->src.next_input_byte = (const JOCTET*) tif->tif_rawcp;
+	sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc;
+
+        if( sp->bytesperline == 0 )
+                return 0;
+        
+	nrows = cc / sp->bytesperline;
+	if (cc % sp->bytesperline)
+		TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline not read");
+
+	if( nrows > (tmsize_t) sp->cinfo.d.image_height )
+		nrows = sp->cinfo.d.image_height;
+
+	/* data is expected to be read in multiples of a scanline */
+	if (nrows)
+	{
+		JSAMPROW line_work_buf = NULL;
+
+		/*
+		 * For 6B, only use temporary buffer for 12 bit imagery.
+		 * For Mk1 always use it.
+		 */
+#if !defined(JPEG_LIB_MK1)
+		if( sp->cinfo.d.data_precision == 12 )
+#endif
+		{
+			line_work_buf = (JSAMPROW)
+			    _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width
+			    * sp->cinfo.d.num_components );
+		}
+
+		do {
+			if( line_work_buf != NULL )
+			{
+				/*
+				 * In the MK1 case, we aways read into a 16bit buffer, and then
+				 * pack down to 12bit or 8bit.  In 6B case we only read into 16
+				 * bit buffer for 12bit data, which we need to repack.
+				*/
+				if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1)
+					return (0);
+
+				if( sp->cinfo.d.data_precision == 12 )
+				{
+					int value_pairs = (sp->cinfo.d.output_width
+					    * sp->cinfo.d.num_components) / 2;
+					int iPair;
+
+					for( iPair = 0; iPair < value_pairs; iPair++ )
+					{
+						unsigned char *out_ptr =
+						    ((unsigned char *) buf) + iPair * 3;
+						JSAMPLE *in_ptr = line_work_buf + iPair * 2;
+
+						out_ptr[0] = (in_ptr[0] & 0xff0) >> 4;
+						out_ptr[1] = ((in_ptr[0] & 0xf) << 4)
+						    | ((in_ptr[1] & 0xf00) >> 8);
+						out_ptr[2] = ((in_ptr[1] & 0xff) >> 0);
+					}
+				}
+				else if( sp->cinfo.d.data_precision == 8 )
+				{
+					int value_count = (sp->cinfo.d.output_width
+					    * sp->cinfo.d.num_components);
+					int iValue;
+
+					for( iValue = 0; iValue < value_count; iValue++ )
+					{
+						((unsigned char *) buf)[iValue] =
+						    line_work_buf[iValue] & 0xff;
+					}
+				}
+			}
+			else
+			{
+				/*
+				 * In the libjpeg6b 8bit case.  We read directly into the
+				 * TIFF buffer.
+				*/
+				JSAMPROW bufptr = (JSAMPROW)buf;
+
+				if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1)
+					return (0);
+			}
+
+			++tif->tif_row;
+			buf += sp->bytesperline;
+			cc -= sp->bytesperline;
+		} while (--nrows > 0);
+
+		if( line_work_buf != NULL )
+			_TIFFfree( line_work_buf );
+	}
+
+        /* Update information on consumed data */
+        tif->tif_rawcp = (uint8*) sp->src.next_input_byte;
+        tif->tif_rawcc = sp->src.bytes_in_buffer;
+                
+	/* Close down the decompressor if we've finished the strip or tile. */
+	return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height
+	    || TIFFjpeg_finish_decompress(sp);
+}
+
+/*ARGSUSED*/ static int
+DecodeRowError(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+
+{
+    (void) buf;
+    (void) cc;
+    (void) s;
+
+    TIFFErrorExt(tif->tif_clientdata, "TIFFReadScanline",
+                 "scanline oriented access is not supported for downsampled JPEG compressed images, consider enabling TIFF_JPEGCOLORMODE as JPEGCOLORMODE_RGB." );
+    return 0;
+}
+
+/*
+ * Decode a chunk of pixels.
+ * Returned data is downsampled per sampling factors.
+ */
+/*ARGSUSED*/ static int
+JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	tmsize_t nrows;
+	(void) s;
+
+	/* data is expected to be read in multiples of a scanline */
+	if ( (nrows = sp->cinfo.d.image_height) ) {
+
+		/* Cb,Cr both have sampling factors 1, so this is correct */
+		JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width;            
+		int samples_per_clump = sp->samplesperclump;
+
+#if defined(JPEG_LIB_MK1_OR_12BIT)
+		unsigned short* tmpbuf = _TIFFmalloc(sizeof(unsigned short) *
+						     sp->cinfo.d.output_width *
+						     sp->cinfo.d.num_components);
+		if(tmpbuf==NULL) {
+                        TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw",
+				     "Out of memory");
+			return 0;
+                }
+#endif
+
+		do {
+			jpeg_component_info *compptr;
+			int ci, clumpoffset;
+
+                        if( cc < sp->bytesperline ) {
+				TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw",
+					     "application buffer not large enough for all data.");
+				return 0;
+                        }
+
+			/* Reload downsampled-data buffer if needed */
+			if (sp->scancount >= DCTSIZE) {
+				int n = sp->cinfo.d.max_v_samp_factor * DCTSIZE;
+				if (TIFFjpeg_read_raw_data(sp, sp->ds_buffer, n) != n)
+					return (0);
+				sp->scancount = 0;
+			}
+			/*
+			 * Fastest way to unseparate data is to make one pass
+			 * over the scanline for each row of each component.
+			 */
+			clumpoffset = 0;    /* first sample in clump */
+			for (ci = 0, compptr = sp->cinfo.d.comp_info;
+			     ci < sp->cinfo.d.num_components;
+			     ci++, compptr++) {
+				int hsamp = compptr->h_samp_factor;
+				int vsamp = compptr->v_samp_factor;
+				int ypos;
+
+				for (ypos = 0; ypos < vsamp; ypos++) {
+					JSAMPLE *inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos];
+					JDIMENSION nclump;
+#if defined(JPEG_LIB_MK1_OR_12BIT)
+					JSAMPLE *outptr = (JSAMPLE*)tmpbuf + clumpoffset;
+#else
+					JSAMPLE *outptr = (JSAMPLE*)buf + clumpoffset;
+					if (cc < (tmsize_t) (clumpoffset + samples_per_clump*(clumps_per_line-1) + hsamp)) {
+						TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw",
+							     "application buffer not large enough for all data, possible subsampling issue");
+						return 0;
+					}
+#endif
+
+					if (hsamp == 1) {
+						/* fast path for at least Cb and Cr */
+						for (nclump = clumps_per_line; nclump-- > 0; ) {
+							outptr[0] = *inptr++;
+							outptr += samples_per_clump;
+						}
+					} else {
+						int xpos;
+
+						/* general case */
+						for (nclump = clumps_per_line; nclump-- > 0; ) {
+							for (xpos = 0; xpos < hsamp; xpos++)
+								outptr[xpos] = *inptr++;
+							outptr += samples_per_clump;
+						}
+					}
+					clumpoffset += hsamp;
+				}
+			}
+
+#if defined(JPEG_LIB_MK1_OR_12BIT)
+			{
+				if (sp->cinfo.d.data_precision == 8)
+				{
+					int i=0;
+					int len = sp->cinfo.d.output_width * sp->cinfo.d.num_components;
+					for (i=0; i<len; i++)
+					{
+						((unsigned char*)buf)[i] = tmpbuf[i] & 0xff;
+					}
+				}
+				else
+				{         /* 12-bit */
+					int value_pairs = (sp->cinfo.d.output_width
+							   * sp->cinfo.d.num_components) / 2;
+					int iPair;
+					for( iPair = 0; iPair < value_pairs; iPair++ )
+					{
+						unsigned char *out_ptr = ((unsigned char *) buf) + iPair * 3;
+						JSAMPLE *in_ptr = (JSAMPLE *) (tmpbuf + iPair * 2);
+						out_ptr[0] = (in_ptr[0] & 0xff0) >> 4;
+						out_ptr[1] = ((in_ptr[0] & 0xf) << 4)
+							| ((in_ptr[1] & 0xf00) >> 8);
+						out_ptr[2] = ((in_ptr[1] & 0xff) >> 0);
+					}
+				}
+			}
+#endif
+
+			sp->scancount ++;
+			tif->tif_row += sp->v_sampling;
+
+			buf += sp->bytesperline;
+			cc -= sp->bytesperline;
+
+			nrows -= sp->v_sampling;
+		} while (nrows > 0);
+
+#if defined(JPEG_LIB_MK1_OR_12BIT)
+		_TIFFfree(tmpbuf);
+#endif
+
+	}
+
+	/* Close down the decompressor if done. */
+	return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height
+		|| TIFFjpeg_finish_decompress(sp);
+}
+
+
+/*
+ * JPEG Encoding.
+ */
+
+static void
+unsuppress_quant_table (JPEGState* sp, int tblno)
+{
+	JQUANT_TBL* qtbl;
+
+	if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL)
+		qtbl->sent_table = FALSE;
+}
+
+static void
+unsuppress_huff_table (JPEGState* sp, int tblno)
+{
+	JHUFF_TBL* htbl;
+
+	if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL)
+		htbl->sent_table = FALSE;
+	if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL)
+		htbl->sent_table = FALSE;
+}
+
+static int
+prepare_JPEGTables(TIFF* tif)
+{
+	JPEGState* sp = JState(tif);
+
+	/* Initialize quant tables for current quality setting */
+	if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE))
+		return (0);
+	/* Mark only the tables we want for output */
+	/* NB: chrominance tables are currently used only with YCbCr */
+	if (!TIFFjpeg_suppress_tables(sp, TRUE))
+		return (0);
+	if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) {
+		unsuppress_quant_table(sp, 0);
+		if (sp->photometric == PHOTOMETRIC_YCBCR)
+			unsuppress_quant_table(sp, 1);
+	}
+	if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) {
+		unsuppress_huff_table(sp, 0);
+		if (sp->photometric == PHOTOMETRIC_YCBCR)
+			unsuppress_huff_table(sp, 1);
+	}
+	/* Direct libjpeg output into jpegtables */
+	if (!TIFFjpeg_tables_dest(sp, tif))
+		return (0);
+	/* Emit tables-only datastream */
+	if (!TIFFjpeg_write_tables(sp))
+		return (0);
+
+	return (1);
+}
+
+static int
+JPEGSetupEncode(TIFF* tif)
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+	static const char module[] = "JPEGSetupEncode";
+
+#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG)
+        if( tif->tif_dir.td_bitspersample == 12 )
+            return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 1 );
+#endif
+
+        JPEGInitializeLibJPEG( tif, FALSE );
+
+	assert(sp != NULL);
+	assert(!sp->cinfo.comm.is_decompressor);
+
+	/*
+	 * Initialize all JPEG parameters to default values.
+	 * Note that jpeg_set_defaults needs legal values for
+	 * in_color_space and input_components.
+	 */
+	sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+	sp->cinfo.c.input_components = 1;
+	if (!TIFFjpeg_set_defaults(sp))
+		return (0);
+	/* Set per-file parameters */
+	sp->photometric = td->td_photometric;
+	switch (sp->photometric) {
+	case PHOTOMETRIC_YCBCR:
+		sp->h_sampling = td->td_ycbcrsubsampling[0];
+		sp->v_sampling = td->td_ycbcrsubsampling[1];
+		/*
+		 * A ReferenceBlackWhite field *must* be present since the
+		 * default value is inappropriate for YCbCr.  Fill in the
+		 * proper value if application didn't set it.
+		 */
+		{
+			float *ref;
+			if (!TIFFGetField(tif, TIFFTAG_REFERENCEBLACKWHITE,
+					  &ref)) {
+				float refbw[6];
+				long top = 1L << td->td_bitspersample;
+				refbw[0] = 0;
+				refbw[1] = (float)(top-1L);
+				refbw[2] = (float)(top>>1);
+				refbw[3] = refbw[1];
+				refbw[4] = refbw[2];
+				refbw[5] = refbw[1];
+				TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE,
+					     refbw);
+			}
+		}
+		break;
+	case PHOTOMETRIC_PALETTE:		/* disallowed by Tech Note */
+	case PHOTOMETRIC_MASK:
+		TIFFErrorExt(tif->tif_clientdata, module,
+			  "PhotometricInterpretation %d not allowed for JPEG",
+			  (int) sp->photometric);
+		return (0);
+	default:
+		/* TIFF 6.0 forbids subsampling of all other color spaces */
+		sp->h_sampling = 1;
+		sp->v_sampling = 1;
+		break;
+	}
+
+	/* Verify miscellaneous parameters */
+
+	/*
+	 * This would need work if libtiff ever supports different
+	 * depths for different components, or if libjpeg ever supports
+	 * run-time selection of depth.  Neither is imminent.
+	 */
+#ifdef JPEG_LIB_MK1
+        /* BITS_IN_JSAMPLE now permits 8 and 12 --- dgilbert */
+	if (td->td_bitspersample != 8 && td->td_bitspersample != 12) 
+#else
+	if (td->td_bitspersample != BITS_IN_JSAMPLE )
+#endif
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "BitsPerSample %d not allowed for JPEG",
+			  (int) td->td_bitspersample);
+		return (0);
+	}
+	sp->cinfo.c.data_precision = td->td_bitspersample;
+#ifdef JPEG_LIB_MK1
+        sp->cinfo.c.bits_in_jsample = td->td_bitspersample;
+#endif
+	if (isTiled(tif)) {
+		if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				  "JPEG tile height must be multiple of %d",
+				  sp->v_sampling * DCTSIZE);
+			return (0);
+		}
+		if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				  "JPEG tile width must be multiple of %d",
+				  sp->h_sampling * DCTSIZE);
+			return (0);
+		}
+	} else {
+		if (td->td_rowsperstrip < td->td_imagelength &&
+		    (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				  "RowsPerStrip must be multiple of %d for JPEG",
+				  sp->v_sampling * DCTSIZE);
+			return (0);
+		}
+	}
+
+	/* Create a JPEGTables field if appropriate */
+	if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) {
+                if( sp->jpegtables == NULL
+                    || memcmp(sp->jpegtables,"\0\0\0\0\0\0\0\0\0",8) == 0 )
+                {
+                        if (!prepare_JPEGTables(tif))
+                                return (0);
+                        /* Mark the field present */
+                        /* Can't use TIFFSetField since BEENWRITING is already set! */
+                        tif->tif_flags |= TIFF_DIRTYDIRECT;
+                        TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
+                }
+	} else {
+		/* We do not support application-supplied JPEGTables, */
+		/* so mark the field not present */
+		TIFFClrFieldBit(tif, FIELD_JPEGTABLES);
+	}
+
+	/* Direct libjpeg output to libtiff's output buffer */
+	TIFFjpeg_data_dest(sp, tif);
+
+	return (1);
+}
+
+/*
+ * Set encoding state at the start of a strip or tile.
+ */
+static int
+JPEGPreEncode(TIFF* tif, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+	static const char module[] = "JPEGPreEncode";
+	uint32 segment_width, segment_height;
+	int downsampled_input;
+
+	assert(sp != NULL);
+  
+	if (sp->cinfo.comm.is_decompressor == 1)
+	{
+		tif->tif_setupencode( tif );
+	}
+  
+	assert(!sp->cinfo.comm.is_decompressor);
+	/*
+	 * Set encoding parameters for this strip/tile.
+	 */
+	if (isTiled(tif)) {
+		segment_width = td->td_tilewidth;
+		segment_height = td->td_tilelength;
+		sp->bytesperline = TIFFTileRowSize(tif);
+	} else {
+		segment_width = td->td_imagewidth;
+		segment_height = td->td_imagelength - tif->tif_row;
+		if (segment_height > td->td_rowsperstrip)
+			segment_height = td->td_rowsperstrip;
+		sp->bytesperline = TIFFScanlineSize(tif);
+	}
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) {
+		/* for PC 2, scale down the strip/tile size
+		 * to match a downsampled component
+		 */
+		segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); 
+		segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
+	}
+	if (segment_width > 65535 || segment_height > 65535) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Strip/tile too large for JPEG");
+		return (0);
+	}
+	sp->cinfo.c.image_width = segment_width;
+	sp->cinfo.c.image_height = segment_height;
+	downsampled_input = FALSE;
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+		sp->cinfo.c.input_components = td->td_samplesperpixel;
+		if (sp->photometric == PHOTOMETRIC_YCBCR) {
+			if (sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+				sp->cinfo.c.in_color_space = JCS_RGB;
+			} else {
+				sp->cinfo.c.in_color_space = JCS_YCbCr;
+				if (sp->h_sampling != 1 || sp->v_sampling != 1)
+					downsampled_input = TRUE;
+			}
+			if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr))
+				return (0);
+			/*
+			 * Set Y sampling factors;
+			 * we assume jpeg_set_colorspace() set the rest to 1
+			 */
+			sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling;
+			sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling;
+		} else {
+			if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1)
+				sp->cinfo.c.in_color_space = JCS_GRAYSCALE;
+			else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3)
+				sp->cinfo.c.in_color_space = JCS_RGB;
+			else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4)
+				sp->cinfo.c.in_color_space = JCS_CMYK;
+			else
+				sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+			if (!TIFFjpeg_set_colorspace(sp, sp->cinfo.c.in_color_space))
+				return (0);
+			/* jpeg_set_colorspace set all sampling factors to 1 */
+		}
+	} else {
+		sp->cinfo.c.input_components = 1;
+		sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+		if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN))
+			return (0);
+		sp->cinfo.c.comp_info[0].component_id = s;
+		/* jpeg_set_colorspace() set sampling factors to 1 */
+		if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) {
+			sp->cinfo.c.comp_info[0].quant_tbl_no = 1;
+			sp->cinfo.c.comp_info[0].dc_tbl_no = 1;
+			sp->cinfo.c.comp_info[0].ac_tbl_no = 1;
+		}
+	}
+	/* ensure libjpeg won't write any extraneous markers */
+	sp->cinfo.c.write_JFIF_header = FALSE;
+	sp->cinfo.c.write_Adobe_marker = FALSE;
+	/* set up table handling correctly */
+        if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE))
+		return (0);
+	if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) {
+		unsuppress_quant_table(sp, 0);
+		unsuppress_quant_table(sp, 1);
+	}
+	if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF)
+		sp->cinfo.c.optimize_coding = FALSE;
+	else
+		sp->cinfo.c.optimize_coding = TRUE;
+	if (downsampled_input) {
+		/* Need to use raw-data interface to libjpeg */
+		sp->cinfo.c.raw_data_in = TRUE;
+		tif->tif_encoderow = JPEGEncodeRaw;
+		tif->tif_encodestrip = JPEGEncodeRaw;
+		tif->tif_encodetile = JPEGEncodeRaw;
+	} else {
+		/* Use normal interface to libjpeg */
+		sp->cinfo.c.raw_data_in = FALSE;
+		tif->tif_encoderow = JPEGEncode;
+		tif->tif_encodestrip = JPEGEncode;
+		tif->tif_encodetile = JPEGEncode;
+	}
+	/* Start JPEG compressor */
+	if (!TIFFjpeg_start_compress(sp, FALSE))
+		return (0);
+	/* Allocate downsampled-data buffers if needed */
+	if (downsampled_input) {
+		if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info,
+					       sp->cinfo.c.num_components))
+			return (0);
+	}
+	sp->scancount = 0;
+
+	return (1);
+}
+
+/*
+ * Encode a chunk of pixels.
+ * "Standard" case: incoming data is not downsampled.
+ */
+static int
+JPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	tmsize_t nrows;
+	JSAMPROW bufptr[1];
+        short *line16 = NULL;
+        int    line16_count = 0;
+
+	(void) s;
+	assert(sp != NULL);
+	/* data is expected to be supplied in multiples of a scanline */
+	nrows = cc / sp->bytesperline;
+	if (cc % sp->bytesperline)
+            TIFFWarningExt(tif->tif_clientdata, tif->tif_name, 
+                           "fractional scanline discarded");
+
+        /* The last strip will be limited to image size */
+        if( !isTiled(tif) && tif->tif_row+nrows > tif->tif_dir.td_imagelength )
+            nrows = tif->tif_dir.td_imagelength - tif->tif_row;
+
+        if( sp->cinfo.c.data_precision == 12 )
+        {
+            line16_count = (int)((sp->bytesperline * 2) / 3);
+            line16 = (short *) _TIFFmalloc(sizeof(short) * line16_count);
+	    // FIXME: undiagnosed malloc failure
+        }
+            
+	while (nrows-- > 0) {
+
+            if( sp->cinfo.c.data_precision == 12 )
+            {
+
+                int value_pairs = line16_count / 2;
+                int iPair;
+
+		bufptr[0] = (JSAMPROW) line16;
+
+                for( iPair = 0; iPair < value_pairs; iPair++ )
+                {
+                    unsigned char *in_ptr =
+                        ((unsigned char *) buf) + iPair * 3;
+                    JSAMPLE *out_ptr = (JSAMPLE *) (line16 + iPair * 2);
+
+                    out_ptr[0] = (in_ptr[0] << 4) | ((in_ptr[1] & 0xf0) >> 4);
+                    out_ptr[1] = ((in_ptr[1] & 0x0f) << 8) | in_ptr[2];
+                }
+            }
+            else
+            {
+		bufptr[0] = (JSAMPROW) buf;
+            }
+            if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1)
+                return (0);
+            if (nrows > 0)
+                tif->tif_row++;
+            buf += sp->bytesperline;
+	}
+
+        if( sp->cinfo.c.data_precision == 12 )
+        {
+            _TIFFfree( line16 );
+        }
+            
+	return (1);
+}
+
+/*
+ * Encode a chunk of pixels.
+ * Incoming data is expected to be downsampled per sampling factors.
+ */
+static int
+JPEGEncodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	JSAMPLE* inptr;
+	JSAMPLE* outptr;
+	tmsize_t nrows;
+	JDIMENSION clumps_per_line, nclump;
+	int clumpoffset, ci, xpos, ypos;
+	jpeg_component_info* compptr;
+	int samples_per_clump = sp->samplesperclump;
+	tmsize_t bytesperclumpline;
+
+	(void) s;
+	assert(sp != NULL);
+	/* data is expected to be supplied in multiples of a clumpline */
+	/* a clumpline is equivalent to v_sampling desubsampled scanlines */
+	/* TODO: the following calculation of bytesperclumpline, should substitute calculation of sp->bytesperline, except that it is per v_sampling lines */
+	bytesperclumpline = (((sp->cinfo.c.image_width+sp->h_sampling-1)/sp->h_sampling)
+			     *(sp->h_sampling*sp->v_sampling+2)*sp->cinfo.c.data_precision+7)
+			    /8;
+
+	nrows = ( cc / bytesperclumpline ) * sp->v_sampling;
+	if (cc % bytesperclumpline)
+		TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline discarded");
+
+	/* Cb,Cr both have sampling factors 1, so this is correct */
+	clumps_per_line = sp->cinfo.c.comp_info[1].downsampled_width;
+
+	while (nrows > 0) {
+		/*
+		 * Fastest way to separate the data is to make one pass
+		 * over the scanline for each row of each component.
+		 */
+		clumpoffset = 0;		/* first sample in clump */
+		for (ci = 0, compptr = sp->cinfo.c.comp_info;
+		     ci < sp->cinfo.c.num_components;
+		     ci++, compptr++) {
+		    int hsamp = compptr->h_samp_factor;
+		    int vsamp = compptr->v_samp_factor;
+		    int padding = (int) (compptr->width_in_blocks * DCTSIZE -
+					 clumps_per_line * hsamp);
+		    for (ypos = 0; ypos < vsamp; ypos++) {
+			inptr = ((JSAMPLE*) buf) + clumpoffset;
+			outptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos];
+			if (hsamp == 1) {
+			    /* fast path for at least Cb and Cr */
+			    for (nclump = clumps_per_line; nclump-- > 0; ) {
+				*outptr++ = inptr[0];
+				inptr += samples_per_clump;
+			    }
+			} else {
+			    /* general case */
+			    for (nclump = clumps_per_line; nclump-- > 0; ) {
+				for (xpos = 0; xpos < hsamp; xpos++)
+				    *outptr++ = inptr[xpos];
+				inptr += samples_per_clump;
+			    }
+			}
+			/* pad each scanline as needed */
+			for (xpos = 0; xpos < padding; xpos++) {
+			    *outptr = outptr[-1];
+			    outptr++;
+			}
+			clumpoffset += hsamp;
+		    }
+		}
+		sp->scancount++;
+		if (sp->scancount >= DCTSIZE) {
+			int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE;
+			if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n)
+				return (0);
+			sp->scancount = 0;
+		}
+		tif->tif_row += sp->v_sampling;
+		buf += bytesperclumpline;
+		nrows -= sp->v_sampling;
+	}
+	return (1);
+}
+
+/*
+ * Finish up at the end of a strip or tile.
+ */
+static int
+JPEGPostEncode(TIFF* tif)
+{
+	JPEGState *sp = JState(tif);
+
+	if (sp->scancount > 0) {
+		/*
+		 * Need to emit a partial bufferload of downsampled data.
+		 * Pad the data vertically.
+		 */
+		int ci, ypos, n;
+		jpeg_component_info* compptr;
+
+		for (ci = 0, compptr = sp->cinfo.c.comp_info;
+		     ci < sp->cinfo.c.num_components;
+		     ci++, compptr++) {
+			int vsamp = compptr->v_samp_factor;
+			tmsize_t row_width = compptr->width_in_blocks * DCTSIZE
+				* sizeof(JSAMPLE);
+			for (ypos = sp->scancount * vsamp;
+			     ypos < DCTSIZE * vsamp; ypos++) {
+				_TIFFmemcpy((void*)sp->ds_buffer[ci][ypos],
+					    (void*)sp->ds_buffer[ci][ypos-1],
+					    row_width);
+
+			}
+		}
+		n = sp->cinfo.c.max_v_samp_factor * DCTSIZE;
+		if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n)
+			return (0);
+	}
+
+	return (TIFFjpeg_finish_compress(JState(tif)));
+}
+
+static void
+JPEGCleanup(TIFF* tif)
+{
+	JPEGState *sp = JState(tif);
+	
+	assert(sp != 0);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+	tif->tif_tagmethods.printdir = sp->printdir;
+
+	if( sp != NULL ) {
+		if( sp->cinfo_initialized )
+		    TIFFjpeg_destroy(sp);	/* release libjpeg resources */
+		if (sp->jpegtables)		/* tag value */
+			_TIFFfree(sp->jpegtables);
+	}
+	_TIFFfree(tif->tif_data);	/* release local state */
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+static void 
+JPEGResetUpsampled( TIFF* tif )
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	/*
+	 * Mark whether returned data is up-sampled or not so TIFFStripSize
+	 * and TIFFTileSize return values that reflect the true amount of
+	 * data.
+	 */
+	tif->tif_flags &= ~TIFF_UPSAMPLED;
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+		if (td->td_photometric == PHOTOMETRIC_YCBCR &&
+		    sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+			tif->tif_flags |= TIFF_UPSAMPLED;
+		} else {
+#ifdef notdef
+			if (td->td_ycbcrsubsampling[0] != 1 ||
+			    td->td_ycbcrsubsampling[1] != 1)
+				; /* XXX what about up-sampling? */
+#endif
+		}
+	}
+
+	/*
+	 * Must recalculate cached tile size in case sampling state changed.
+	 * Should we really be doing this now if image size isn't set? 
+	 */
+        if( tif->tif_tilesize > 0 )
+            tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1);   
+        if( tif->tif_scanlinesize > 0 )
+            tif->tif_scanlinesize = TIFFScanlineSize(tif); 
+}
+
+static int
+JPEGVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	JPEGState* sp = JState(tif);
+	const TIFFField* fip;
+	uint32 v32;
+
+	assert(sp != NULL);
+
+	switch (tag) {
+	case TIFFTAG_JPEGTABLES:
+		v32 = (uint32) va_arg(ap, uint32);
+		if (v32 == 0) {
+			/* XXX */
+			return (0);
+		}
+		_TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*),
+		    (long) v32);
+		sp->jpegtables_length = v32;
+		TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
+		break;
+	case TIFFTAG_JPEGQUALITY:
+		sp->jpegquality = (int) va_arg(ap, int);
+		return (1);			/* pseudo tag */
+	case TIFFTAG_JPEGCOLORMODE:
+		sp->jpegcolormode = (int) va_arg(ap, int);
+		JPEGResetUpsampled( tif );
+		return (1);			/* pseudo tag */
+	case TIFFTAG_PHOTOMETRIC:
+	{
+		int ret_value = (*sp->vsetparent)(tif, tag, ap);
+		JPEGResetUpsampled( tif );
+		return ret_value;
+	}
+	case TIFFTAG_JPEGTABLESMODE:
+		sp->jpegtablesmode = (int) va_arg(ap, int);
+		return (1);			/* pseudo tag */
+	case TIFFTAG_YCBCRSUBSAMPLING:
+		/* mark the fact that we have a real ycbcrsubsampling! */
+		sp->ycbcrsampling_fetched = 1;
+		/* should we be recomputing upsampling info here? */
+		return (*sp->vsetparent)(tif, tag, ap);
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+
+	if ((fip = TIFFFieldWithTag(tif, tag))) {
+		TIFFSetFieldBit(tif, fip->field_bit);
+	} else {
+		return (0);
+	}
+
+	tif->tif_flags |= TIFF_DIRTYDIRECT;
+	return (1);
+}
+
+static int
+JPEGVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	JPEGState* sp = JState(tif);
+
+	assert(sp != NULL);
+
+	switch (tag) {
+		case TIFFTAG_JPEGTABLES:
+			*va_arg(ap, uint32*) = sp->jpegtables_length;
+			*va_arg(ap, void**) = sp->jpegtables;
+			break;
+		case TIFFTAG_JPEGQUALITY:
+			*va_arg(ap, int*) = sp->jpegquality;
+			break;
+		case TIFFTAG_JPEGCOLORMODE:
+			*va_arg(ap, int*) = sp->jpegcolormode;
+			break;
+		case TIFFTAG_JPEGTABLESMODE:
+			*va_arg(ap, int*) = sp->jpegtablesmode;
+			break;
+		default:
+			return (*sp->vgetparent)(tif, tag, ap);
+	}
+	return (1);
+}
+
+static void
+JPEGPrintDir(TIFF* tif, FILE* fd, long flags)
+{
+	JPEGState* sp = JState(tif);
+
+	assert(sp != NULL);
+	(void) flags;
+
+        if( sp != NULL ) {
+		if (TIFFFieldSet(tif,FIELD_JPEGTABLES))
+			fprintf(fd, "  JPEG Tables: (%lu bytes)\n",
+				(unsigned long) sp->jpegtables_length);
+		if (sp->printdir)
+			(*sp->printdir)(tif, fd, flags);
+	}
+}
+
+static uint32
+JPEGDefaultStripSize(TIFF* tif, uint32 s)
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+
+	s = (*sp->defsparent)(tif, s);
+	if (s < td->td_imagelength)
+		s = TIFFroundup_32(s, td->td_ycbcrsubsampling[1] * DCTSIZE);
+	return (s);
+}
+
+static void
+JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+
+	(*sp->deftparent)(tif, tw, th);
+	*tw = TIFFroundup_32(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE);
+	*th = TIFFroundup_32(*th, td->td_ycbcrsubsampling[1] * DCTSIZE);
+}
+
+/*
+ * The JPEG library initialized used to be done in TIFFInitJPEG(), but
+ * now that we allow a TIFF file to be opened in update mode it is necessary
+ * to have some way of deciding whether compression or decompression is
+ * desired other than looking at tif->tif_mode.  We accomplish this by 
+ * examining {TILE/STRIP}BYTECOUNTS to see if there is a non-zero entry.
+ * If so, we assume decompression is desired. 
+ *
+ * This is tricky, because TIFFInitJPEG() is called while the directory is
+ * being read, and generally speaking the BYTECOUNTS tag won't have been read
+ * at that point.  So we try to defer jpeg library initialization till we
+ * do have that tag ... basically any access that might require the compressor
+ * or decompressor that occurs after the reading of the directory. 
+ *
+ * In an ideal world compressors or decompressors would be setup
+ * at the point where a single tile or strip was accessed (for read or write)
+ * so that stuff like update of missing tiles, or replacement of tiles could
+ * be done. However, we aren't trying to crack that nut just yet ...
+ *
+ * NFW, Feb 3rd, 2003.
+ */
+
+static int JPEGInitializeLibJPEG( TIFF * tif, int decompress )
+{
+    JPEGState* sp = JState(tif);
+
+    if(sp->cinfo_initialized)
+    {
+        if( !decompress && sp->cinfo.comm.is_decompressor )
+            TIFFjpeg_destroy( sp );
+        else if( decompress && !sp->cinfo.comm.is_decompressor )
+            TIFFjpeg_destroy( sp );
+        else
+            return 1;
+
+        sp->cinfo_initialized = 0;
+    }
+
+    /*
+     * Initialize libjpeg.
+     */
+    if ( decompress ) {
+        if (!TIFFjpeg_create_decompress(sp))
+            return (0);
+    } else {
+        if (!TIFFjpeg_create_compress(sp))
+            return (0);
+    }
+
+    sp->cinfo_initialized = TRUE;
+
+    return 1;
+}
+
+int
+TIFFInitJPEG(TIFF* tif, int scheme)
+{
+	JPEGState* sp;
+
+	assert(scheme == COMPRESSION_JPEG);
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, jpegFields, TIFFArrayCount(jpegFields))) {
+		TIFFErrorExt(tif->tif_clientdata,
+			     "TIFFInitJPEG",
+			     "Merging JPEG codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (JPEGState));
+
+	if (tif->tif_data == NULL) {
+		TIFFErrorExt(tif->tif_clientdata,
+			     "TIFFInitJPEG", "No space for JPEG state block");
+		return 0;
+	}
+        _TIFFmemset(tif->tif_data, 0, sizeof(JPEGState));
+
+	sp = JState(tif);
+	sp->tif = tif;				/* back link */
+
+	/*
+	 * Override parent get/set field methods.
+	 */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield = JPEGVGetField; /* hook for codec tags */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield = JPEGVSetField; /* hook for codec tags */
+	sp->printdir = tif->tif_tagmethods.printdir;
+	tif->tif_tagmethods.printdir = JPEGPrintDir;   /* hook for codec tags */
+
+	/* Default values for codec-specific fields */
+	sp->jpegtables = NULL;
+	sp->jpegtables_length = 0;
+	sp->jpegquality = 75;			/* Default IJG quality */
+	sp->jpegcolormode = JPEGCOLORMODE_RAW;
+	sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF;
+        sp->ycbcrsampling_fetched = 0;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = JPEGFixupTags;
+	tif->tif_setupdecode = JPEGSetupDecode;
+	tif->tif_predecode = JPEGPreDecode;
+	tif->tif_decoderow = JPEGDecode;
+	tif->tif_decodestrip = JPEGDecode;
+	tif->tif_decodetile = JPEGDecode;
+	tif->tif_setupencode = JPEGSetupEncode;
+	tif->tif_preencode = JPEGPreEncode;
+	tif->tif_postencode = JPEGPostEncode;
+	tif->tif_encoderow = JPEGEncode;
+	tif->tif_encodestrip = JPEGEncode;
+	tif->tif_encodetile = JPEGEncode;  
+	tif->tif_cleanup = JPEGCleanup;
+	sp->defsparent = tif->tif_defstripsize;
+	tif->tif_defstripsize = JPEGDefaultStripSize;
+	sp->deftparent = tif->tif_deftilesize;
+	tif->tif_deftilesize = JPEGDefaultTileSize;
+	tif->tif_flags |= TIFF_NOBITREV;	/* no bit reversal, please */
+
+        sp->cinfo_initialized = FALSE;
+
+	/*
+        ** Create a JPEGTables field if no directory has yet been created. 
+        ** We do this just to ensure that sufficient space is reserved for
+        ** the JPEGTables field.  It will be properly created the right
+        ** size later. 
+        */
+        if( tif->tif_diroff == 0 )
+        {
+#define SIZE_OF_JPEGTABLES 2000
+/*
+The following line assumes incorrectly that all JPEG-in-TIFF files will have
+a JPEGTABLES tag generated and causes null-filled JPEGTABLES tags to be written
+when the JPEG data is placed with TIFFWriteRawStrip.  The field bit should be 
+set, anyway, later when actual JPEGTABLES header is generated, so removing it 
+here hopefully is harmless.
+            TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
+*/
+            sp->jpegtables_length = SIZE_OF_JPEGTABLES;
+            sp->jpegtables = (void *) _TIFFmalloc(sp->jpegtables_length);
+	    // FIXME: NULL-deref after malloc failure
+	    _TIFFmemset(sp->jpegtables, 0, SIZE_OF_JPEGTABLES);
+#undef SIZE_OF_JPEGTABLES
+        }
+
+	return 1;
+}
+#endif /* JPEG_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_luv.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_luv.c
new file mode 100644
index 0000000..0c22989
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_luv.c
@@ -0,0 +1,1687 @@
+/* $Id: tif_luv.c,v 1.35 2011-04-02 20:54:09 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1997 Greg Ward Larson
+ * Copyright (c) 1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any
+ * advertising or publicity relating to the software without the specific,
+ * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#ifdef LOGLUV_SUPPORT
+
+/*
+ * TIFF Library.
+ * LogLuv compression support for high dynamic range images.
+ *
+ * Contributed by Greg Larson.
+ *
+ * LogLuv image support uses the TIFF library to store 16 or 10-bit
+ * log luminance values with 8 bits each of u and v or a 14-bit index.
+ *
+ * The codec can take as input and produce as output 32-bit IEEE float values 
+ * as well as 16-bit integer values.  A 16-bit luminance is interpreted
+ * as a sign bit followed by a 15-bit integer that is converted
+ * to and from a linear magnitude using the transformation:
+ *
+ *	L = 2^( (Le+.5)/256 - 64 )		# real from 15-bit
+ *
+ *	Le = floor( 256*(log2(L) + 64) )	# 15-bit from real
+ *
+ * The actual conversion to world luminance units in candelas per sq. meter
+ * requires an additional multiplier, which is stored in the TIFFTAG_STONITS.
+ * This value is usually set such that a reasonable exposure comes from
+ * clamping decoded luminances above 1 to 1 in the displayed image.
+ *
+ * The 16-bit values for u and v may be converted to real values by dividing
+ * each by 32768.  (This allows for negative values, which aren't useful as
+ * far as we know, but are left in case of future improvements in human
+ * color vision.)
+ *
+ * Conversion from (u,v), which is actually the CIE (u',v') system for
+ * you color scientists, is accomplished by the following transformation:
+ *
+ *	u = 4*x / (-2*x + 12*y + 3)
+ *	v = 9*y / (-2*x + 12*y + 3)
+ *
+ *	x = 9*u / (6*u - 16*v + 12)
+ *	y = 4*v / (6*u - 16*v + 12)
+ *
+ * This process is greatly simplified by passing 32-bit IEEE floats
+ * for each of three CIE XYZ coordinates.  The codec then takes care
+ * of conversion to and from LogLuv, though the application is still
+ * responsible for interpreting the TIFFTAG_STONITS calibration factor.
+ *
+ * By definition, a CIE XYZ vector of [1 1 1] corresponds to a neutral white
+ * point of (x,y)=(1/3,1/3).  However, most color systems assume some other
+ * white point, such as D65, and an absolute color conversion to XYZ then
+ * to another color space with a different white point may introduce an
+ * unwanted color cast to the image.  It is often desirable, therefore, to
+ * perform a white point conversion that maps the input white to [1 1 1]
+ * in XYZ, then record the original white point using the TIFFTAG_WHITEPOINT
+ * tag value.  A decoder that demands absolute color calibration may use
+ * this white point tag to get back the original colors, but usually it
+ * will be ignored and the new white point will be used instead that
+ * matches the output color space.
+ *
+ * Pixel information is compressed into one of two basic encodings, depending
+ * on the setting of the compression tag, which is one of COMPRESSION_SGILOG
+ * or COMPRESSION_SGILOG24.  For COMPRESSION_SGILOG, greyscale data is
+ * stored as:
+ *
+ *	 1       15
+ *	|-+---------------|
+ *
+ * COMPRESSION_SGILOG color data is stored as:
+ *
+ *	 1       15           8        8
+ *	|-+---------------|--------+--------|
+ *	 S       Le           ue       ve
+ *
+ * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as:
+ *
+ *	     10           14
+ *	|----------|--------------|
+ *	     Le'          Ce
+ *
+ * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is
+ * encoded as an index for optimal color resolution.  The 10 log bits are
+ * defined by the following conversions:
+ *
+ *	L = 2^((Le'+.5)/64 - 12)		# real from 10-bit
+ *
+ *	Le' = floor( 64*(log2(L) + 12) )	# 10-bit from real
+ *
+ * The 10 bits of the smaller format may be converted into the 15 bits of
+ * the larger format by multiplying by 4 and adding 13314.  Obviously,
+ * a smaller range of magnitudes is covered (about 5 orders of magnitude
+ * instead of 38), and the lack of a sign bit means that negative luminances
+ * are not allowed.  (Well, they aren't allowed in the real world, either,
+ * but they are useful for certain types of image processing.)
+ *
+ * The desired user format is controlled by the setting the internal
+ * pseudo tag TIFFTAG_SGILOGDATAFMT to one of:
+ *  SGILOGDATAFMT_FLOAT       = IEEE 32-bit float XYZ values
+ *  SGILOGDATAFMT_16BIT	      = 16-bit integer encodings of logL, u and v
+ * Raw data i/o is also possible using:
+ *  SGILOGDATAFMT_RAW         = 32-bit unsigned integer with encoded pixel
+ * In addition, the following decoding is provided for ease of display:
+ *  SGILOGDATAFMT_8BIT        = 8-bit default RGB gamma-corrected values
+ *
+ * For grayscale images, we provide the following data formats:
+ *  SGILOGDATAFMT_FLOAT       = IEEE 32-bit float Y values
+ *  SGILOGDATAFMT_16BIT       = 16-bit integer w/ encoded luminance
+ *  SGILOGDATAFMT_8BIT        = 8-bit gray monitor values
+ *
+ * Note that the COMPRESSION_SGILOG applies a simple run-length encoding
+ * scheme by separating the logL, u and v bytes for each row and applying
+ * a PackBits type of compression.  Since the 24-bit encoding is not
+ * adaptive, the 32-bit color format takes less space in many cases.
+ *
+ * Further control is provided over the conversion from higher-resolution
+ * formats to final encoded values through the pseudo tag
+ * TIFFTAG_SGILOGENCODE:
+ *  SGILOGENCODE_NODITHER     = do not dither encoded values
+ *  SGILOGENCODE_RANDITHER    = apply random dithering during encoding
+ *
+ * The default value of this tag is SGILOGENCODE_NODITHER for
+ * COMPRESSION_SGILOG to maximize run-length encoding and
+ * SGILOGENCODE_RANDITHER for COMPRESSION_SGILOG24 to turn
+ * quantization errors into noise.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+/*
+ * State block for each open TIFF
+ * file using LogLuv compression/decompression.
+ */
+typedef struct logLuvState LogLuvState;
+
+struct logLuvState {
+	int                     user_datafmt;   /* user data format */
+	int                     encode_meth;    /* encoding method */
+	int                     pixel_size;     /* bytes per pixel */
+
+	uint8*                  tbuf;           /* translation buffer */
+	tmsize_t                tbuflen;        /* buffer length */
+	void (*tfunc)(LogLuvState*, uint8*, tmsize_t);
+
+	TIFFVSetMethod          vgetparent;     /* super-class method */
+	TIFFVSetMethod          vsetparent;     /* super-class method */
+};
+
+#define DecoderState(tif)	((LogLuvState*) (tif)->tif_data)
+#define EncoderState(tif)	((LogLuvState*) (tif)->tif_data)
+
+#define SGILOGDATAFMT_UNKNOWN -1
+
+#define MINRUN 4 /* minimum run length */
+
+/*
+ * Decode a string of 16-bit gray pixels.
+ */
+static int
+LogL16Decode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "LogL16Decode";
+	LogLuvState* sp = DecoderState(tif);
+	int shft;
+	tmsize_t i;
+	tmsize_t npixels;
+	unsigned char* bp;
+	int16* tp;
+	int16 b;
+	tmsize_t cc;
+	int rc;
+
+	assert(s == 0);
+	assert(sp != NULL);
+
+	npixels = occ / sp->pixel_size;
+
+	if (sp->user_datafmt == SGILOGDATAFMT_16BIT)
+		tp = (int16*) op;
+	else {
+		assert(sp->tbuflen >= npixels);
+		tp = (int16*) sp->tbuf;
+	}
+	_TIFFmemset((void*) tp, 0, npixels*sizeof (tp[0]));
+
+	bp = (unsigned char*) tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	/* get each byte string */
+	for (shft = 2*8; (shft -= 8) >= 0; ) {
+		for (i = 0; i < npixels && cc > 0; )
+			if (*bp >= 128) {		/* run */
+				rc = *bp++ + (2-128);   /* TODO: potential input buffer overrun when decoding corrupt or truncated data */
+				b = (int16)(*bp++ << shft);
+				cc -= 2;
+				while (rc-- && i < npixels)
+					tp[i++] |= b;
+			} else {			/* non-run */
+				rc = *bp++;		/* nul is noop */
+				while (--cc && rc-- && i < npixels)
+					tp[i++] |= (int16)*bp++ << shft;
+			}
+		if (i != npixels) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Not enough data at row %lu (short %I64d pixels)",
+				     (unsigned long) tif->tif_row,
+				     (unsigned __int64) (npixels - i));
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Not enough data at row %lu (short %llu pixels)",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long long) (npixels - i));
+#endif
+			tif->tif_rawcp = (uint8*) bp;
+			tif->tif_rawcc = cc;
+			return (0);
+		}
+	}
+	(*sp->tfunc)(sp, op, npixels);
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	return (1);
+}
+
+/*
+ * Decode a string of 24-bit pixels.
+ */
+static int
+LogLuvDecode24(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "LogLuvDecode24";
+	LogLuvState* sp = DecoderState(tif);
+	tmsize_t cc;
+	tmsize_t i;
+	tmsize_t npixels;
+	unsigned char* bp;
+	uint32* tp;
+
+	assert(s == 0);
+	assert(sp != NULL);
+
+	npixels = occ / sp->pixel_size;
+
+	if (sp->user_datafmt == SGILOGDATAFMT_RAW)
+		tp = (uint32 *)op;
+	else {
+		assert(sp->tbuflen >= npixels);
+		tp = (uint32 *) sp->tbuf;
+	}
+	/* copy to array of uint32 */
+	bp = (unsigned char*) tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	for (i = 0; i < npixels && cc > 0; i++) {
+		tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2];
+		bp += 3;
+		cc -= 3;
+	}
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	if (i != npixels) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at row %lu (short %I64d pixels)",
+			     (unsigned long) tif->tif_row,
+			     (unsigned __int64) (npixels - i));
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at row %lu (short %llu pixels)",
+			     (unsigned long) tif->tif_row,
+			     (unsigned long long) (npixels - i));
+#endif
+		return (0);
+	}
+	(*sp->tfunc)(sp, op, npixels);
+	return (1);
+}
+
+/*
+ * Decode a string of 32-bit pixels.
+ */
+static int
+LogLuvDecode32(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "LogLuvDecode32";
+	LogLuvState* sp;
+	int shft;
+	tmsize_t i;
+	tmsize_t npixels;
+	unsigned char* bp;
+	uint32* tp;
+	uint32 b;
+	tmsize_t cc;
+	int rc;
+
+	assert(s == 0);
+	sp = DecoderState(tif);
+	assert(sp != NULL);
+
+	npixels = occ / sp->pixel_size;
+
+	if (sp->user_datafmt == SGILOGDATAFMT_RAW)
+		tp = (uint32*) op;
+	else {
+		assert(sp->tbuflen >= npixels);
+		tp = (uint32*) sp->tbuf;
+	}
+	_TIFFmemset((void*) tp, 0, npixels*sizeof (tp[0]));
+
+	bp = (unsigned char*) tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	/* get each byte string */
+	for (shft = 4*8; (shft -= 8) >= 0; ) {
+		for (i = 0; i < npixels && cc > 0; )
+			if (*bp >= 128) {		/* run */
+				rc = *bp++ + (2-128);
+				b = (uint32)*bp++ << shft;
+				cc -= 2;                /* TODO: potential input buffer overrun when decoding corrupt or truncated data */
+				while (rc-- && i < npixels)
+					tp[i++] |= b;
+			} else {			/* non-run */
+				rc = *bp++;		/* nul is noop */
+				while (--cc && rc-- && i < npixels)
+					tp[i++] |= (uint32)*bp++ << shft;
+			}
+		if (i != npixels) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at row %lu (short %I64d pixels)",
+				     (unsigned long) tif->tif_row,
+				     (unsigned __int64) (npixels - i));
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at row %lu (short %llu pixels)",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long long) (npixels - i));
+#endif
+			tif->tif_rawcp = (uint8*) bp;
+			tif->tif_rawcc = cc;
+			return (0);
+		}
+	}
+	(*sp->tfunc)(sp, op, npixels);
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	return (1);
+}
+
+/*
+ * Decode a strip of pixels.  We break it into rows to
+ * maintain synchrony with the encode algorithm, which
+ * is row by row.
+ */
+static int
+LogLuvDecodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowlen = TIFFScanlineSize(tif);
+
+	assert(cc%rowlen == 0);
+	while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s))
+		bp += rowlen, cc -= rowlen;
+	return (cc == 0);
+}
+
+/*
+ * Decode a tile of pixels.  We break it into rows to
+ * maintain synchrony with the encode algorithm, which
+ * is row by row.
+ */
+static int
+LogLuvDecodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowlen = TIFFTileRowSize(tif);
+
+	assert(cc%rowlen == 0);
+	while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s))
+		bp += rowlen, cc -= rowlen;
+	return (cc == 0);
+}
+
+/*
+ * Encode a row of 16-bit pixels.
+ */
+static int
+LogL16Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	LogLuvState* sp = EncoderState(tif);
+	int shft;
+	tmsize_t i;
+	tmsize_t j;
+	tmsize_t npixels;
+	uint8* op;
+	int16* tp;
+	int16 b;
+	tmsize_t occ;
+	int rc=0, mask;
+	tmsize_t beg;
+
+	assert(s == 0);
+	assert(sp != NULL);
+	npixels = cc / sp->pixel_size;
+
+	if (sp->user_datafmt == SGILOGDATAFMT_16BIT)
+		tp = (int16*) bp;
+	else {
+		tp = (int16*) sp->tbuf;
+		assert(sp->tbuflen >= npixels);
+		(*sp->tfunc)(sp, bp, npixels);
+	}
+	/* compress each byte string */
+	op = tif->tif_rawcp;
+	occ = tif->tif_rawdatasize - tif->tif_rawcc;
+	for (shft = 2*8; (shft -= 8) >= 0; )
+		for (i = 0; i < npixels; i += rc) {
+			if (occ < 4) {
+				tif->tif_rawcp = op;
+				tif->tif_rawcc = tif->tif_rawdatasize - occ;
+				if (!TIFFFlushData1(tif))
+					return (-1);
+				op = tif->tif_rawcp;
+				occ = tif->tif_rawdatasize - tif->tif_rawcc;
+			}
+			mask = 0xff << shft;		/* find next run */
+			for (beg = i; beg < npixels; beg += rc) {
+				b = (int16) (tp[beg] & mask);
+				rc = 1;
+				while (rc < 127+2 && beg+rc < npixels &&
+				    (tp[beg+rc] & mask) == b)
+					rc++;
+				if (rc >= MINRUN)
+					break;		/* long enough */
+			}
+			if (beg-i > 1 && beg-i < MINRUN) {
+				b = (int16) (tp[i] & mask);/*check short run */
+				j = i+1;
+				while ((tp[j++] & mask) == b)
+					if (j == beg) {
+						*op++ = (uint8)(128-2+j-i);
+						*op++ = (uint8)(b >> shft);
+						occ -= 2;
+						i = beg;
+						break;
+					}
+			}
+			while (i < beg) {		/* write out non-run */
+				if ((j = beg-i) > 127) j = 127;
+				if (occ < j+3) {
+					tif->tif_rawcp = op;
+					tif->tif_rawcc = tif->tif_rawdatasize - occ;
+					if (!TIFFFlushData1(tif))
+						return (-1);
+					op = tif->tif_rawcp;
+					occ = tif->tif_rawdatasize - tif->tif_rawcc;
+				}
+				*op++ = (uint8) j; occ--;
+				while (j--) {
+					*op++ = (uint8) (tp[i++] >> shft & 0xff);
+					occ--;
+				}
+			}
+			if (rc >= MINRUN) {		/* write out run */
+				*op++ = (uint8) (128-2+rc);
+				*op++ = (uint8) (tp[beg] >> shft & 0xff);
+				occ -= 2;
+			} else
+				rc = 0;
+		}
+	tif->tif_rawcp = op;
+	tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+	return (1);
+}
+
+/*
+ * Encode a row of 24-bit pixels.
+ */
+static int
+LogLuvEncode24(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	LogLuvState* sp = EncoderState(tif);
+	tmsize_t i;
+	tmsize_t npixels;
+	tmsize_t occ;
+	uint8* op;
+	uint32* tp;
+
+	assert(s == 0);
+	assert(sp != NULL);
+	npixels = cc / sp->pixel_size;
+
+	if (sp->user_datafmt == SGILOGDATAFMT_RAW)
+		tp = (uint32*) bp;
+	else {
+		tp = (uint32*) sp->tbuf;
+		assert(sp->tbuflen >= npixels);
+		(*sp->tfunc)(sp, bp, npixels);
+	}
+	/* write out encoded pixels */
+	op = tif->tif_rawcp;
+	occ = tif->tif_rawdatasize - tif->tif_rawcc;
+	for (i = npixels; i--; ) {
+		if (occ < 3) {
+			tif->tif_rawcp = op;
+			tif->tif_rawcc = tif->tif_rawdatasize - occ;
+			if (!TIFFFlushData1(tif))
+				return (-1);
+			op = tif->tif_rawcp;
+			occ = tif->tif_rawdatasize - tif->tif_rawcc;
+		}
+		*op++ = (uint8)(*tp >> 16);
+		*op++ = (uint8)(*tp >> 8 & 0xff);
+		*op++ = (uint8)(*tp++ & 0xff);
+		occ -= 3;
+	}
+	tif->tif_rawcp = op;
+	tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+	return (1);
+}
+
+/*
+ * Encode a row of 32-bit pixels.
+ */
+static int
+LogLuvEncode32(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	LogLuvState* sp = EncoderState(tif);
+	int shft;
+	tmsize_t i;
+	tmsize_t j;
+	tmsize_t npixels;
+	uint8* op;
+	uint32* tp;
+	uint32 b;
+	tmsize_t occ;
+	int rc=0, mask;
+	tmsize_t beg;
+
+	assert(s == 0);
+	assert(sp != NULL);
+
+	npixels = cc / sp->pixel_size;
+
+	if (sp->user_datafmt == SGILOGDATAFMT_RAW)
+		tp = (uint32*) bp;
+	else {
+		tp = (uint32*) sp->tbuf;
+		assert(sp->tbuflen >= npixels);
+		(*sp->tfunc)(sp, bp, npixels);
+	}
+	/* compress each byte string */
+	op = tif->tif_rawcp;
+	occ = tif->tif_rawdatasize - tif->tif_rawcc;
+	for (shft = 4*8; (shft -= 8) >= 0; )
+		for (i = 0; i < npixels; i += rc) {
+			if (occ < 4) {
+				tif->tif_rawcp = op;
+				tif->tif_rawcc = tif->tif_rawdatasize - occ;
+				if (!TIFFFlushData1(tif))
+					return (-1);
+				op = tif->tif_rawcp;
+				occ = tif->tif_rawdatasize - tif->tif_rawcc;
+			}
+			mask = 0xff << shft;		/* find next run */
+			for (beg = i; beg < npixels; beg += rc) {
+				b = tp[beg] & mask;
+				rc = 1;
+				while (rc < 127+2 && beg+rc < npixels &&
+						(tp[beg+rc] & mask) == b)
+					rc++;
+				if (rc >= MINRUN)
+					break;		/* long enough */
+			}
+			if (beg-i > 1 && beg-i < MINRUN) {
+				b = tp[i] & mask;	/* check short run */
+				j = i+1;
+				while ((tp[j++] & mask) == b)
+					if (j == beg) {
+						*op++ = (uint8)(128-2+j-i);
+						*op++ = (uint8)(b >> shft);
+						occ -= 2;
+						i = beg;
+						break;
+					}
+			}
+			while (i < beg) {		/* write out non-run */
+				if ((j = beg-i) > 127) j = 127;
+				if (occ < j+3) {
+					tif->tif_rawcp = op;
+					tif->tif_rawcc = tif->tif_rawdatasize - occ;
+					if (!TIFFFlushData1(tif))
+						return (-1);
+					op = tif->tif_rawcp;
+					occ = tif->tif_rawdatasize - tif->tif_rawcc;
+				}
+				*op++ = (uint8) j; occ--;
+				while (j--) {
+					*op++ = (uint8)(tp[i++] >> shft & 0xff);
+					occ--;
+				}
+			}
+			if (rc >= MINRUN) {		/* write out run */
+				*op++ = (uint8) (128-2+rc);
+				*op++ = (uint8)(tp[beg] >> shft & 0xff);
+				occ -= 2;
+			} else
+				rc = 0;
+		}
+	tif->tif_rawcp = op;
+	tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+	return (1);
+}
+
+/*
+ * Encode a strip of pixels.  We break it into rows to
+ * avoid encoding runs across row boundaries.
+ */
+static int
+LogLuvEncodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowlen = TIFFScanlineSize(tif);
+
+	assert(cc%rowlen == 0);
+	while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1)
+		bp += rowlen, cc -= rowlen;
+	return (cc == 0);
+}
+
+/*
+ * Encode a tile of pixels.  We break it into rows to
+ * avoid encoding runs across row boundaries.
+ */
+static int
+LogLuvEncodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowlen = TIFFTileRowSize(tif);
+
+	assert(cc%rowlen == 0);
+	while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1)
+		bp += rowlen, cc -= rowlen;
+	return (cc == 0);
+}
+
+/*
+ * Encode/Decode functions for converting to and from user formats.
+ */
+
+#include "uvcode.h"
+
+#ifndef UVSCALE
+#define U_NEU		0.210526316
+#define V_NEU		0.473684211
+#define UVSCALE		410.
+#endif
+
+#ifndef	M_LN2
+#define M_LN2		0.69314718055994530942
+#endif
+#ifndef M_PI
+#define M_PI		3.14159265358979323846
+#endif
+#ifndef log2
+#define log2(x)		((1./M_LN2)*log(x))
+#endif
+#define exp2(x)		exp(M_LN2*(x))
+
+#define itrunc(x,m)	((m)==SGILOGENCODE_NODITHER ? \
+				(int)(x) : \
+				(int)((x) + rand()*(1./RAND_MAX) - .5))
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+double
+LogL16toY(int p16)		/* compute luminance from 16-bit LogL */
+{
+	int	Le = p16 & 0x7fff;
+	double	Y;
+
+	if (!Le)
+		return (0.);
+	Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.);
+	return (!(p16 & 0x8000) ? Y : -Y);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+LogL16fromY(double Y, int em)	/* get 16-bit LogL from Y */
+{
+	if (Y >= 1.8371976e19)
+		return (0x7fff);
+	if (Y <= -1.8371976e19)
+		return (0xffff);
+	if (Y > 5.4136769e-20)
+		return itrunc(256.*(log2(Y) + 64.), em);
+	if (Y < -5.4136769e-20)
+		return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em));
+	return (0);
+}
+
+static void
+L16toY(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	int16* l16 = (int16*) sp->tbuf;
+	float* yp = (float*) op;
+
+	while (n-- > 0)
+		*yp++ = (float)LogL16toY(*l16++);
+}
+
+static void
+L16toGry(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	int16* l16 = (int16*) sp->tbuf;
+	uint8* gp = (uint8*) op;
+
+	while (n-- > 0) {
+		double Y = LogL16toY(*l16++);
+		*gp++ = (uint8) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y)));
+	}
+}
+
+static void
+L16fromY(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	int16* l16 = (int16*) sp->tbuf;
+	float* yp = (float*) op;
+
+	while (n-- > 0)
+		*l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+XYZtoRGB24(float xyz[3], uint8 rgb[3])
+{
+	double	r, g, b;
+					/* assume CCIR-709 primaries */
+	r =  2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2];
+	g = -1.022*xyz[0] +  1.978*xyz[1] +  0.044*xyz[2];
+	b =  0.061*xyz[0] + -0.224*xyz[1] +  1.163*xyz[2];
+					/* assume 2.0 gamma for speed */
+	/* could use integer sqrt approx., but this is probably faster */
+	rgb[0] = (uint8)((r<=0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r)));
+	rgb[1] = (uint8)((g<=0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g)));
+	rgb[2] = (uint8)((b<=0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b)));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+double
+LogL10toY(int p10)		/* compute luminance from 10-bit LogL */
+{
+	if (p10 == 0)
+		return (0.);
+	return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+LogL10fromY(double Y, int em)	/* get 10-bit LogL from Y */
+{
+	if (Y >= 15.742)
+		return (0x3ff);
+	else if (Y <= .00024283)
+		return (0);
+	else
+		return itrunc(64.*(log2(Y) + 12.), em);
+}
+
+#define NANGLES		100
+#define uv2ang(u, v)	( (NANGLES*.499999999/M_PI) \
+				* atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES )
+
+static int
+oog_encode(double u, double v)		/* encode out-of-gamut chroma */
+{
+	static int	oog_table[NANGLES];
+	static int	initialized = 0;
+	register int	i;
+
+	if (!initialized) {		/* set up perimeter table */
+		double	eps[NANGLES], ua, va, ang, epsa;
+		int	ui, vi, ustep;
+		for (i = NANGLES; i--; )
+			eps[i] = 2.;
+		for (vi = UV_NVS; vi--; ) {
+			va = UV_VSTART + (vi+.5)*UV_SQSIZ;
+			ustep = uv_row[vi].nus-1;
+			if (vi == UV_NVS-1 || vi == 0 || ustep <= 0)
+				ustep = 1;
+			for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) {
+				ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
+				ang = uv2ang(ua, va);
+				i = (int) ang;
+				epsa = fabs(ang - (i+.5));
+				if (epsa < eps[i]) {
+					oog_table[i] = uv_row[vi].ncum + ui;
+					eps[i] = epsa;
+				}
+			}
+		}
+		for (i = NANGLES; i--; )	/* fill any holes */
+			if (eps[i] > 1.5) {
+				int	i1, i2;
+				for (i1 = 1; i1 < NANGLES/2; i1++)
+					if (eps[(i+i1)%NANGLES] < 1.5)
+						break;
+				for (i2 = 1; i2 < NANGLES/2; i2++)
+					if (eps[(i+NANGLES-i2)%NANGLES] < 1.5)
+						break;
+				if (i1 < i2)
+					oog_table[i] =
+						oog_table[(i+i1)%NANGLES];
+				else
+					oog_table[i] =
+						oog_table[(i+NANGLES-i2)%NANGLES];
+			}
+		initialized = 1;
+	}
+	i = (int) uv2ang(u, v);		/* look up hue angle */
+	return (oog_table[i]);
+}
+
+#undef uv2ang
+#undef NANGLES
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+uv_encode(double u, double v, int em)	/* encode (u',v') coordinates */
+{
+	register int	vi, ui;
+
+	if (v < UV_VSTART)
+		return oog_encode(u, v);
+	vi = itrunc((v - UV_VSTART)*(1./UV_SQSIZ), em);
+	if (vi >= UV_NVS)
+		return oog_encode(u, v);
+	if (u < uv_row[vi].ustart)
+		return oog_encode(u, v);
+	ui = itrunc((u - uv_row[vi].ustart)*(1./UV_SQSIZ), em);
+	if (ui >= uv_row[vi].nus)
+		return oog_encode(u, v);
+
+	return (uv_row[vi].ncum + ui);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+uv_decode(double *up, double *vp, int c)	/* decode (u',v') index */
+{
+	int	upper, lower;
+	register int	ui, vi;
+
+	if (c < 0 || c >= UV_NDIVS)
+		return (-1);
+	lower = 0;				/* binary search */
+	upper = UV_NVS;
+	while (upper - lower > 1) {
+		vi = (lower + upper) >> 1;
+		ui = c - uv_row[vi].ncum;
+		if (ui > 0)
+			lower = vi;
+		else if (ui < 0)
+			upper = vi;
+		else {
+			lower = vi;
+			break;
+		}
+	}
+	vi = lower;
+	ui = c - uv_row[vi].ncum;
+	*up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
+	*vp = UV_VSTART + (vi+.5)*UV_SQSIZ;
+	return (0);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+LogLuv24toXYZ(uint32 p, float XYZ[3])
+{
+	int	Ce;
+	double	L, u, v, s, x, y;
+					/* decode luminance */
+	L = LogL10toY(p>>14 & 0x3ff);
+	if (L <= 0.) {
+		XYZ[0] = XYZ[1] = XYZ[2] = 0.;
+		return;
+	}
+					/* decode color */
+	Ce = p & 0x3fff;
+	if (uv_decode(&u, &v, Ce) < 0) {
+		u = U_NEU; v = V_NEU;
+	}
+	s = 1./(6.*u - 16.*v + 12.);
+	x = 9.*u * s;
+	y = 4.*v * s;
+					/* convert to XYZ */
+	XYZ[0] = (float)(x/y * L);
+	XYZ[1] = (float)L;
+	XYZ[2] = (float)((1.-x-y)/y * L);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+uint32
+LogLuv24fromXYZ(float XYZ[3], int em)
+{
+	int	Le, Ce;
+	double	u, v, s;
+					/* encode luminance */
+	Le = LogL10fromY(XYZ[1], em);
+					/* encode color */
+	s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
+	if (!Le || s <= 0.) {
+		u = U_NEU;
+		v = V_NEU;
+	} else {
+		u = 4.*XYZ[0] / s;
+		v = 9.*XYZ[1] / s;
+	}
+	Ce = uv_encode(u, v, em);
+	if (Ce < 0)			/* never happens */
+		Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
+					/* combine encodings */
+	return (Le << 14 | Ce);
+}
+
+static void
+Luv24toXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	float* xyz = (float*) op;
+
+	while (n-- > 0) {
+		LogLuv24toXYZ(*luv, xyz);
+		xyz += 3;
+		luv++;
+	}
+}
+
+static void
+Luv24toLuv48(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	int16* luv3 = (int16*) op;
+
+	while (n-- > 0) {
+		double u, v;
+
+		*luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314);
+		if (uv_decode(&u, &v, *luv&0x3fff) < 0) {
+			u = U_NEU;
+			v = V_NEU;
+		}
+		*luv3++ = (int16)(u * (1L<<15));
+		*luv3++ = (int16)(v * (1L<<15));
+		luv++;
+	}
+}
+
+static void
+Luv24toRGB(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	uint8* rgb = (uint8*) op;
+
+	while (n-- > 0) {
+		float xyz[3];
+
+		LogLuv24toXYZ(*luv++, xyz);
+		XYZtoRGB24(xyz, rgb);
+		rgb += 3;
+	}
+}
+
+static void
+Luv24fromXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	float* xyz = (float*) op;
+
+	while (n-- > 0) {
+		*luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth);
+		xyz += 3;
+	}
+}
+
+static void
+Luv24fromLuv48(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	int16* luv3 = (int16*) op;
+
+	while (n-- > 0) {
+		int Le, Ce;
+
+		if (luv3[0] <= 0)
+			Le = 0;
+		else if (luv3[0] >= (1<<12)+3314)
+			Le = (1<<10) - 1;
+		else if (sp->encode_meth == SGILOGENCODE_NODITHER)
+			Le = (luv3[0]-3314) >> 2;
+		else
+			Le = itrunc(.25*(luv3[0]-3314.), sp->encode_meth);
+
+		Ce = uv_encode((luv3[1]+.5)/(1<<15), (luv3[2]+.5)/(1<<15),
+					sp->encode_meth);
+		if (Ce < 0)	/* never happens */
+			Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
+		*luv++ = (uint32)Le << 14 | Ce;
+		luv3 += 3;
+	}
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+LogLuv32toXYZ(uint32 p, float XYZ[3])
+{
+	double	L, u, v, s, x, y;
+					/* decode luminance */
+	L = LogL16toY((int)p >> 16);
+	if (L <= 0.) {
+		XYZ[0] = XYZ[1] = XYZ[2] = 0.;
+		return;
+	}
+					/* decode color */
+	u = 1./UVSCALE * ((p>>8 & 0xff) + .5);
+	v = 1./UVSCALE * ((p & 0xff) + .5);
+	s = 1./(6.*u - 16.*v + 12.);
+	x = 9.*u * s;
+	y = 4.*v * s;
+					/* convert to XYZ */
+	XYZ[0] = (float)(x/y * L);
+	XYZ[1] = (float)L;
+	XYZ[2] = (float)((1.-x-y)/y * L);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+uint32
+LogLuv32fromXYZ(float XYZ[3], int em)
+{
+	unsigned int	Le, ue, ve;
+	double	u, v, s;
+					/* encode luminance */
+	Le = (unsigned int)LogL16fromY(XYZ[1], em);
+					/* encode color */
+	s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
+	if (!Le || s <= 0.) {
+		u = U_NEU;
+		v = V_NEU;
+	} else {
+		u = 4.*XYZ[0] / s;
+		v = 9.*XYZ[1] / s;
+	}
+	if (u <= 0.) ue = 0;
+	else ue = itrunc(UVSCALE*u, em);
+	if (ue > 255) ue = 255;
+	if (v <= 0.) ve = 0;
+	else ve = itrunc(UVSCALE*v, em);
+	if (ve > 255) ve = 255;
+					/* combine encodings */
+	return (Le << 16 | ue << 8 | ve);
+}
+
+static void
+Luv32toXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	float* xyz = (float*) op;
+
+	while (n-- > 0) {
+		LogLuv32toXYZ(*luv++, xyz);
+		xyz += 3;
+	}
+}
+
+static void
+Luv32toLuv48(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	int16* luv3 = (int16*) op;
+
+	while (n-- > 0) {
+		double u, v;
+
+		*luv3++ = (int16)(*luv >> 16);
+		u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5);
+		v = 1./UVSCALE * ((*luv & 0xff) + .5);
+		*luv3++ = (int16)(u * (1L<<15));
+		*luv3++ = (int16)(v * (1L<<15));
+		luv++;
+	}
+}
+
+static void
+Luv32toRGB(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	uint8* rgb = (uint8*) op;
+
+	while (n-- > 0) {
+		float xyz[3];
+
+		LogLuv32toXYZ(*luv++, xyz);
+		XYZtoRGB24(xyz, rgb);
+		rgb += 3;
+	}
+}
+
+static void
+Luv32fromXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	float* xyz = (float*) op;
+
+	while (n-- > 0) {
+		*luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth);
+		xyz += 3;
+	}
+}
+
+static void
+Luv32fromLuv48(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;
+	int16* luv3 = (int16*) op;
+
+	if (sp->encode_meth == SGILOGENCODE_NODITHER) {
+		while (n-- > 0) {
+			*luv++ = (uint32)luv3[0] << 16 |
+				(luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) |
+				(luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff);
+			luv3 += 3;
+		}
+		return;
+	}
+	while (n-- > 0) {
+		*luv++ = (uint32)luv3[0] << 16 |
+	(itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) |
+		(itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff);
+		luv3 += 3;
+	}
+}
+
+static void
+_logLuvNop(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	(void) sp; (void) op; (void) n;
+}
+
+static int
+LogL16GuessDataFmt(TIFFDirectory *td)
+{
+#define	PACK(s,b,f)	(((b)<<6)|((s)<<3)|(f))
+	switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) {
+	case PACK(1, 32, SAMPLEFORMAT_IEEEFP):
+		return (SGILOGDATAFMT_FLOAT);
+	case PACK(1, 16, SAMPLEFORMAT_VOID):
+	case PACK(1, 16, SAMPLEFORMAT_INT):
+	case PACK(1, 16, SAMPLEFORMAT_UINT):
+		return (SGILOGDATAFMT_16BIT);
+	case PACK(1,  8, SAMPLEFORMAT_VOID):
+	case PACK(1,  8, SAMPLEFORMAT_UINT):
+		return (SGILOGDATAFMT_8BIT);
+	}
+#undef PACK
+	return (SGILOGDATAFMT_UNKNOWN);
+}
+
+static tmsize_t
+multiply_ms(tmsize_t m1, tmsize_t m2)
+{
+	tmsize_t bytes = m1 * m2;
+
+	if (m1 && bytes / m1 != m2)
+		bytes = 0;
+
+	return bytes;
+}
+
+static int
+LogL16InitState(TIFF* tif)
+{
+	static const char module[] = "LogL16InitState";
+	TIFFDirectory *td = &tif->tif_dir;
+	LogLuvState* sp = DecoderState(tif);
+
+	assert(sp != NULL);
+	assert(td->td_photometric == PHOTOMETRIC_LOGL);
+
+	/* for some reason, we can't do this in TIFFInitLogL16 */
+	if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
+		sp->user_datafmt = LogL16GuessDataFmt(td);
+	switch (sp->user_datafmt) {
+	case SGILOGDATAFMT_FLOAT:
+		sp->pixel_size = sizeof (float);
+		break;
+	case SGILOGDATAFMT_16BIT:
+		sp->pixel_size = sizeof (int16);
+		break;
+	case SGILOGDATAFMT_8BIT:
+		sp->pixel_size = sizeof (uint8);
+		break;
+	default:
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "No support for converting user data format to LogL");
+		return (0);
+	}
+        if( isTiled(tif) )
+            sp->tbuflen = multiply_ms(td->td_tilewidth, td->td_tilelength);
+        else
+            sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip);
+	if (multiply_ms(sp->tbuflen, sizeof (int16)) == 0 ||
+	    (sp->tbuf = (uint8*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer");
+		return (0);
+	}
+	return (1);
+}
+
+static int
+LogLuvGuessDataFmt(TIFFDirectory *td)
+{
+	int guess;
+
+	/*
+	 * If the user didn't tell us their datafmt,
+	 * take our best guess from the bitspersample.
+	 */
+#define	PACK(a,b)	(((a)<<3)|(b))
+	switch (PACK(td->td_bitspersample, td->td_sampleformat)) {
+	case PACK(32, SAMPLEFORMAT_IEEEFP):
+		guess = SGILOGDATAFMT_FLOAT;
+		break;
+	case PACK(32, SAMPLEFORMAT_VOID):
+	case PACK(32, SAMPLEFORMAT_UINT):
+	case PACK(32, SAMPLEFORMAT_INT):
+		guess = SGILOGDATAFMT_RAW;
+		break;
+	case PACK(16, SAMPLEFORMAT_VOID):
+	case PACK(16, SAMPLEFORMAT_INT):
+	case PACK(16, SAMPLEFORMAT_UINT):
+		guess = SGILOGDATAFMT_16BIT;
+		break;
+	case PACK( 8, SAMPLEFORMAT_VOID):
+	case PACK( 8, SAMPLEFORMAT_UINT):
+		guess = SGILOGDATAFMT_8BIT;
+		break;
+	default:
+		guess = SGILOGDATAFMT_UNKNOWN;
+		break;
+#undef PACK
+	}
+	/*
+	 * Double-check samples per pixel.
+	 */
+	switch (td->td_samplesperpixel) {
+	case 1:
+		if (guess != SGILOGDATAFMT_RAW)
+			guess = SGILOGDATAFMT_UNKNOWN;
+		break;
+	case 3:
+		if (guess == SGILOGDATAFMT_RAW)
+			guess = SGILOGDATAFMT_UNKNOWN;
+		break;
+	default:
+		guess = SGILOGDATAFMT_UNKNOWN;
+		break;
+	}
+	return (guess);
+}
+
+static int
+LogLuvInitState(TIFF* tif)
+{
+	static const char module[] = "LogLuvInitState";
+	TIFFDirectory* td = &tif->tif_dir;
+	LogLuvState* sp = DecoderState(tif);
+
+	assert(sp != NULL);
+	assert(td->td_photometric == PHOTOMETRIC_LOGLUV);
+
+	/* for some reason, we can't do this in TIFFInitLogLuv */
+	if (td->td_planarconfig != PLANARCONFIG_CONTIG) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "SGILog compression cannot handle non-contiguous data");
+		return (0);
+	}
+	if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
+		sp->user_datafmt = LogLuvGuessDataFmt(td);
+	switch (sp->user_datafmt) {
+	case SGILOGDATAFMT_FLOAT:
+		sp->pixel_size = 3*sizeof (float);
+		break;
+	case SGILOGDATAFMT_16BIT:
+		sp->pixel_size = 3*sizeof (int16);
+		break;
+	case SGILOGDATAFMT_RAW:
+		sp->pixel_size = sizeof (uint32);
+		break;
+	case SGILOGDATAFMT_8BIT:
+		sp->pixel_size = 3*sizeof (uint8);
+		break;
+	default:
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "No support for converting user data format to LogLuv");
+		return (0);
+	}
+        if( isTiled(tif) )
+            sp->tbuflen = multiply_ms(td->td_tilewidth, td->td_tilelength);
+        else
+            sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip);
+	if (multiply_ms(sp->tbuflen, sizeof (uint32)) == 0 ||
+	    (sp->tbuf = (uint8*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer");
+		return (0);
+	}
+	return (1);
+}
+
+static int
+LogLuvFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+static int
+LogLuvSetupDecode(TIFF* tif)
+{
+	static const char module[] = "LogLuvSetupDecode";
+	LogLuvState* sp = DecoderState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	tif->tif_postdecode = _TIFFNoPostDecode;
+	switch (td->td_photometric) {
+	case PHOTOMETRIC_LOGLUV:
+		if (!LogLuvInitState(tif))
+			break;
+		if (td->td_compression == COMPRESSION_SGILOG24) {
+			tif->tif_decoderow = LogLuvDecode24;
+			switch (sp->user_datafmt) {
+			case SGILOGDATAFMT_FLOAT:
+				sp->tfunc = Luv24toXYZ;  
+				break;
+			case SGILOGDATAFMT_16BIT:
+				sp->tfunc = Luv24toLuv48;  
+				break;
+			case SGILOGDATAFMT_8BIT:
+				sp->tfunc = Luv24toRGB;
+				break;
+			}
+		} else {
+			tif->tif_decoderow = LogLuvDecode32;
+			switch (sp->user_datafmt) {
+			case SGILOGDATAFMT_FLOAT:
+				sp->tfunc = Luv32toXYZ;
+				break;
+			case SGILOGDATAFMT_16BIT:
+				sp->tfunc = Luv32toLuv48;
+				break;
+			case SGILOGDATAFMT_8BIT:
+				sp->tfunc = Luv32toRGB;
+				break;
+			}
+		}
+		return (1);
+	case PHOTOMETRIC_LOGL:
+		if (!LogL16InitState(tif))
+			break;
+		tif->tif_decoderow = LogL16Decode;
+		switch (sp->user_datafmt) {
+		case SGILOGDATAFMT_FLOAT:
+			sp->tfunc = L16toY;
+			break;
+		case SGILOGDATAFMT_8BIT:
+			sp->tfunc = L16toGry;
+			break;
+		}
+		return (1);
+	default:
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Inappropriate photometric interpretation %d for SGILog compression; %s",
+		    td->td_photometric, "must be either LogLUV or LogL");
+		break;
+	}
+	return (0);
+}
+
+static int
+LogLuvSetupEncode(TIFF* tif)
+{
+	static const char module[] = "LogLuvSetupEncode";
+	LogLuvState* sp = EncoderState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	switch (td->td_photometric) {
+	case PHOTOMETRIC_LOGLUV:
+		if (!LogLuvInitState(tif))
+			break;
+		if (td->td_compression == COMPRESSION_SGILOG24) {
+			tif->tif_encoderow = LogLuvEncode24;
+			switch (sp->user_datafmt) {
+			case SGILOGDATAFMT_FLOAT:
+				sp->tfunc = Luv24fromXYZ;
+				break;
+			case SGILOGDATAFMT_16BIT:
+				sp->tfunc = Luv24fromLuv48;  
+				break;
+			case SGILOGDATAFMT_RAW:
+				break;
+			default:
+				goto notsupported;
+			}
+		} else {
+			tif->tif_encoderow = LogLuvEncode32;  
+			switch (sp->user_datafmt) {
+			case SGILOGDATAFMT_FLOAT:
+				sp->tfunc = Luv32fromXYZ;  
+				break;
+			case SGILOGDATAFMT_16BIT:
+				sp->tfunc = Luv32fromLuv48;  
+				break;
+			case SGILOGDATAFMT_RAW:
+				break;
+			default:
+				goto notsupported;
+			}
+		}
+		break;
+	case PHOTOMETRIC_LOGL:
+		if (!LogL16InitState(tif))
+			break;
+		tif->tif_encoderow = LogL16Encode;  
+		switch (sp->user_datafmt) {
+		case SGILOGDATAFMT_FLOAT:
+			sp->tfunc = L16fromY;
+			break;
+		case SGILOGDATAFMT_16BIT:
+			break;
+		default:
+			goto notsupported;
+		}
+		break;
+	default:
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Inappropriate photometric interpretation %d for SGILog compression; %s",
+		    td->td_photometric, "must be either LogLUV or LogL");
+		break;
+	}
+	return (1);
+notsupported:
+	TIFFErrorExt(tif->tif_clientdata, module,
+	    "SGILog compression supported only for %s, or raw data",
+	    td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv");
+	return (0);
+}
+
+static void
+LogLuvClose(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+	/*
+	 * For consistency, we always want to write out the same
+	 * bitspersample and sampleformat for our TIFF file,
+	 * regardless of the data format being used by the application.
+	 * Since this routine is called after tags have been set but
+	 * before they have been recorded in the file, we reset them here.
+	 */
+	td->td_samplesperpixel =
+	    (td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3;
+	td->td_bitspersample = 16;
+	td->td_sampleformat = SAMPLEFORMAT_INT;
+}
+
+static void
+LogLuvCleanup(TIFF* tif)
+{
+	LogLuvState* sp = (LogLuvState *)tif->tif_data;
+
+	assert(sp != 0);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+	if (sp->tbuf)
+		_TIFFfree(sp->tbuf);
+	_TIFFfree(sp);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+LogLuvVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	static const char module[] = "LogLuvVSetField";
+	LogLuvState* sp = DecoderState(tif);
+	int bps, fmt;
+
+	switch (tag) {
+	case TIFFTAG_SGILOGDATAFMT:
+		sp->user_datafmt = (int) va_arg(ap, int);
+		/*
+		 * Tweak the TIFF header so that the rest of libtiff knows what
+		 * size of data will be passed between app and library, and
+		 * assume that the app knows what it is doing and is not
+		 * confused by these header manipulations...
+		 */
+		switch (sp->user_datafmt) {
+		case SGILOGDATAFMT_FLOAT:
+			bps = 32, fmt = SAMPLEFORMAT_IEEEFP;
+			break;
+		case SGILOGDATAFMT_16BIT:
+			bps = 16, fmt = SAMPLEFORMAT_INT;
+			break;
+		case SGILOGDATAFMT_RAW:
+			bps = 32, fmt = SAMPLEFORMAT_UINT;
+			TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+			break;
+		case SGILOGDATAFMT_8BIT:
+			bps = 8, fmt = SAMPLEFORMAT_UINT;
+			break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			    "Unknown data format %d for LogLuv compression",
+			    sp->user_datafmt);
+			return (0);
+		}
+		TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps);
+		TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt);
+		/*
+		 * Must recalculate sizes should bits/sample change.
+		 */
+		tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t) -1;
+		tif->tif_scanlinesize = TIFFScanlineSize(tif);
+		return (1);
+	case TIFFTAG_SGILOGENCODE:
+		sp->encode_meth = (int) va_arg(ap, int);
+		if (sp->encode_meth != SGILOGENCODE_NODITHER &&
+		    sp->encode_meth != SGILOGENCODE_RANDITHER) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Unknown encoding %d for LogLuv compression",
+			    sp->encode_meth);
+			return (0);
+		}
+		return (1);
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+}
+
+static int
+LogLuvVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	LogLuvState *sp = (LogLuvState *)tif->tif_data;
+
+	switch (tag) {
+	case TIFFTAG_SGILOGDATAFMT:
+		*va_arg(ap, int*) = sp->user_datafmt;
+		return (1);
+	default:
+		return (*sp->vgetparent)(tif, tag, ap);
+	}
+}
+
+static const TIFFField LogLuvFields[] = {
+    { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogDataFmt", NULL},
+    { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogEncode", NULL}
+};
+
+int
+TIFFInitSGILog(TIFF* tif, int scheme)
+{
+	static const char module[] = "TIFFInitSGILog";
+	LogLuvState* sp;
+
+	assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG);
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, LogLuvFields,
+			      TIFFArrayCount(LogLuvFields))) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Merging SGILog codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (LogLuvState));
+	if (tif->tif_data == NULL)
+		goto bad;
+	sp = (LogLuvState*) tif->tif_data;
+	_TIFFmemset((void*)sp, 0, sizeof (*sp));
+	sp->user_datafmt = SGILOGDATAFMT_UNKNOWN;
+	sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ?
+	    SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER;
+	sp->tfunc = _logLuvNop;
+
+	/*
+	 * Install codec methods.
+	 * NB: tif_decoderow & tif_encoderow are filled
+	 *     in at setup time.
+	 */
+	tif->tif_fixuptags = LogLuvFixupTags;  
+	tif->tif_setupdecode = LogLuvSetupDecode;
+	tif->tif_decodestrip = LogLuvDecodeStrip;
+	tif->tif_decodetile = LogLuvDecodeTile;
+	tif->tif_setupencode = LogLuvSetupEncode;
+	tif->tif_encodestrip = LogLuvEncodeStrip;  
+	tif->tif_encodetile = LogLuvEncodeTile;
+	tif->tif_close = LogLuvClose;
+	tif->tif_cleanup = LogLuvCleanup;
+
+	/*
+	 * Override parent get/set field methods.
+	 */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield = LogLuvVGetField;   /* hook for codec tags */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield = LogLuvVSetField;   /* hook for codec tags */
+
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module,
+		     "%s: No space for LogLuv state block", tif->tif_name);
+	return (0);
+}
+#endif /* LOGLUV_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_lzw.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_lzw.c
new file mode 100644
index 0000000..5c9ab0b
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_lzw.c
@@ -0,0 +1,1169 @@
+/* $Id: tif_lzw.c,v 1.45 2011-04-02 20:54:09 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#ifdef LZW_SUPPORT
+/*
+ * TIFF Library.  
+ * Rev 5.0 Lempel-Ziv & Welch Compression Support
+ *
+ * This code is derived from the compress program whose code is
+ * derived from software contributed to Berkeley by James A. Woods,
+ * derived from original work by Spencer Thomas and Joseph Orost.
+ *
+ * The original Berkeley copyright notice appears below in its entirety.
+ */
+#include "tif_predict.h"
+
+#include <stdio.h>
+
+/*
+ * NB: The 5.0 spec describes a different algorithm than Aldus
+ *     implements.  Specifically, Aldus does code length transitions
+ *     one code earlier than should be done (for real LZW).
+ *     Earlier versions of this library implemented the correct
+ *     LZW algorithm, but emitted codes in a bit order opposite
+ *     to the TIFF spec.  Thus, to maintain compatibility w/ Aldus
+ *     we interpret MSB-LSB ordered codes to be images written w/
+ *     old versions of this library, but otherwise adhere to the
+ *     Aldus "off by one" algorithm.
+ *
+ * Future revisions to the TIFF spec are expected to "clarify this issue".
+ */
+#define LZW_COMPAT              /* include backwards compatibility code */
+/*
+ * Each strip of data is supposed to be terminated by a CODE_EOI.
+ * If the following #define is included, the decoder will also
+ * check for end-of-strip w/o seeing this code.  This makes the
+ * library more robust, but also slower.
+ */
+#define LZW_CHECKEOS            /* include checks for strips w/o EOI code */
+
+#define MAXCODE(n)	((1L<<(n))-1)
+/*
+ * The TIFF spec specifies that encoded bit
+ * strings range from 9 to 12 bits.
+ */
+#define BITS_MIN        9               /* start with 9 bits */
+#define BITS_MAX        12              /* max of 12 bit strings */
+/* predefined codes */
+#define CODE_CLEAR      256             /* code to clear string table */
+#define CODE_EOI        257             /* end-of-information code */
+#define CODE_FIRST      258             /* first free code entry */
+#define CODE_MAX        MAXCODE(BITS_MAX)
+#define HSIZE           9001L           /* 91% occupancy */
+#define HSHIFT          (13-8)
+#ifdef LZW_COMPAT
+/* NB: +1024 is for compatibility with old files */
+#define CSIZE           (MAXCODE(BITS_MAX)+1024L)
+#else
+#define CSIZE           (MAXCODE(BITS_MAX)+1L)
+#endif
+
+/*
+ * State block for each open TIFF file using LZW
+ * compression/decompression.  Note that the predictor
+ * state block must be first in this data structure.
+ */
+typedef struct {
+	TIFFPredictorState predict;     /* predictor super class */
+
+	unsigned short  nbits;          /* # of bits/code */
+	unsigned short  maxcode;        /* maximum code for lzw_nbits */
+	unsigned short  free_ent;       /* next free entry in hash table */
+	long            nextdata;       /* next bits of i/o */
+	long            nextbits;       /* # of valid bits in lzw_nextdata */
+
+	int             rw_mode;        /* preserve rw_mode from init */
+} LZWBaseState;
+
+#define lzw_nbits       base.nbits
+#define lzw_maxcode     base.maxcode
+#define lzw_free_ent    base.free_ent
+#define lzw_nextdata    base.nextdata
+#define lzw_nextbits    base.nextbits
+
+/*
+ * Encoding-specific state.
+ */
+typedef uint16 hcode_t;			/* codes fit in 16 bits */
+typedef struct {
+	long	hash;
+	hcode_t	code;
+} hash_t;
+
+/*
+ * Decoding-specific state.
+ */
+typedef struct code_ent {
+	struct code_ent *next;
+	unsigned short	length;		/* string len, including this token */
+	unsigned char	value;		/* data value */
+	unsigned char	firstchar;	/* first token of string */
+} code_t;
+
+typedef int (*decodeFunc)(TIFF*, uint8*, tmsize_t, uint16);
+
+typedef struct {
+	LZWBaseState base;
+
+	/* Decoding specific data */
+	long    dec_nbitsmask;		/* lzw_nbits 1 bits, right adjusted */
+	long    dec_restart;		/* restart count */
+#ifdef LZW_CHECKEOS
+	uint64  dec_bitsleft;		/* available bits in raw data */
+#endif
+	decodeFunc dec_decode;		/* regular or backwards compatible */
+	code_t* dec_codep;		/* current recognized code */
+	code_t* dec_oldcodep;		/* previously recognized code */
+	code_t* dec_free_entp;		/* next free entry */
+	code_t* dec_maxcodep;		/* max available entry */
+	code_t* dec_codetab;		/* kept separate for small machines */
+
+	/* Encoding specific data */
+	int     enc_oldcode;		/* last code encountered */
+	long    enc_checkpoint;		/* point at which to clear table */
+#define CHECK_GAP	10000		/* enc_ratio check interval */
+	long    enc_ratio;		/* current compression ratio */
+	long    enc_incount;		/* (input) data bytes encoded */
+	long    enc_outcount;		/* encoded (output) bytes */
+	uint8*  enc_rawlimit;		/* bound on tif_rawdata buffer */
+	hash_t* enc_hashtab;		/* kept separate for small machines */
+} LZWCodecState;
+
+#define LZWState(tif)		((LZWBaseState*) (tif)->tif_data)
+#define DecoderState(tif)	((LZWCodecState*) LZWState(tif))
+#define EncoderState(tif)	((LZWCodecState*) LZWState(tif))
+
+static int LZWDecode(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s);
+#ifdef LZW_COMPAT
+static int LZWDecodeCompat(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s);
+#endif
+static void cl_hash(LZWCodecState*);
+
+/*
+ * LZW Decoder.
+ */
+
+#ifdef LZW_CHECKEOS
+/*
+ * This check shouldn't be necessary because each
+ * strip is suppose to be terminated with CODE_EOI.
+ */
+#define	NextCode(_tif, _sp, _bp, _code, _get) {				\
+	if ((_sp)->dec_bitsleft < (uint64)nbits) {			\
+		TIFFWarningExt(_tif->tif_clientdata, module,		\
+		    "LZWDecode: Strip %d not terminated with EOI code", \
+		    _tif->tif_curstrip);				\
+		_code = CODE_EOI;					\
+	} else {							\
+		_get(_sp,_bp,_code);					\
+		(_sp)->dec_bitsleft -= nbits;				\
+	}								\
+}
+#else
+#define	NextCode(tif, sp, bp, code, get) get(sp, bp, code)
+#endif
+
+static int
+LZWFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+static int
+LZWSetupDecode(TIFF* tif)
+{
+	static const char module[] = "LZWSetupDecode";
+	LZWCodecState* sp = DecoderState(tif);
+	int code;
+
+	if( sp == NULL )
+	{
+		/*
+		 * Allocate state block so tag methods have storage to record
+		 * values.
+		*/
+		tif->tif_data = (uint8*) _TIFFmalloc(sizeof(LZWCodecState));
+		if (tif->tif_data == NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata, module, "No space for LZW state block");
+			return (0);
+		}
+
+		DecoderState(tif)->dec_codetab = NULL;
+		DecoderState(tif)->dec_decode = NULL;
+
+		/*
+		 * Setup predictor setup.
+		 */
+		(void) TIFFPredictorInit(tif);
+
+		sp = DecoderState(tif);
+	}
+
+	assert(sp != NULL);
+
+	if (sp->dec_codetab == NULL) {
+		sp->dec_codetab = (code_t*)_TIFFmalloc(CSIZE*sizeof (code_t));
+		if (sp->dec_codetab == NULL) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				     "No space for LZW code table");
+			return (0);
+		}
+		/*
+		 * Pre-load the table.
+		 */
+		code = 255;
+		do {
+			sp->dec_codetab[code].value = code;
+			sp->dec_codetab[code].firstchar = code;
+			sp->dec_codetab[code].length = 1;
+			sp->dec_codetab[code].next = NULL;
+		} while (code--);
+		/*
+		 * Zero-out the unused entries
+                 */
+                 _TIFFmemset(&sp->dec_codetab[CODE_CLEAR], 0,
+			     (CODE_FIRST - CODE_CLEAR) * sizeof (code_t));
+	}
+	return (1);
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+LZWPreDecode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "LZWPreDecode";
+	LZWCodecState *sp = DecoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	if( sp->dec_codetab == NULL )
+        {
+            tif->tif_setupdecode( tif );
+        }
+
+	/*
+	 * Check for old bit-reversed codes.
+	 */
+	if (tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) {
+#ifdef LZW_COMPAT
+		if (!sp->dec_decode) {
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Old-style LZW codes, convert file");
+			/*
+			 * Override default decoding methods with
+			 * ones that deal with the old coding.
+			 * Otherwise the predictor versions set
+			 * above will call the compatibility routines
+			 * through the dec_decode method.
+			 */
+			tif->tif_decoderow = LZWDecodeCompat;
+			tif->tif_decodestrip = LZWDecodeCompat;
+			tif->tif_decodetile = LZWDecodeCompat;
+			/*
+			 * If doing horizontal differencing, must
+			 * re-setup the predictor logic since we
+			 * switched the basic decoder methods...
+			 */
+			(*tif->tif_setupdecode)(tif);
+			sp->dec_decode = LZWDecodeCompat;
+		}
+		sp->lzw_maxcode = MAXCODE(BITS_MIN);
+#else /* !LZW_COMPAT */
+		if (!sp->dec_decode) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Old-style LZW codes not supported");
+			sp->dec_decode = LZWDecode;
+		}
+		return (0);
+#endif/* !LZW_COMPAT */
+	} else {
+		sp->lzw_maxcode = MAXCODE(BITS_MIN)-1;
+		sp->dec_decode = LZWDecode;
+	}
+	sp->lzw_nbits = BITS_MIN;
+	sp->lzw_nextbits = 0;
+	sp->lzw_nextdata = 0;
+
+	sp->dec_restart = 0;
+	sp->dec_nbitsmask = MAXCODE(BITS_MIN);
+#ifdef LZW_CHECKEOS
+	sp->dec_bitsleft = ((uint64)tif->tif_rawcc) << 3;
+#endif
+	sp->dec_free_entp = sp->dec_codetab + CODE_FIRST;
+	/*
+	 * Zero entries that are not yet filled in.  We do
+	 * this to guard against bogus input data that causes
+	 * us to index into undefined entries.  If you can
+	 * come up with a way to safely bounds-check input codes
+	 * while decoding then you can remove this operation.
+	 */
+	_TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof (code_t));
+	sp->dec_oldcodep = &sp->dec_codetab[-1];
+	sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask-1];
+	return (1);
+}
+
+/*
+ * Decode a "hunk of data".
+ */
+#define	GetNextCode(sp, bp, code) {				\
+	nextdata = (nextdata<<8) | *(bp)++;			\
+	nextbits += 8;						\
+	if (nextbits < nbits) {					\
+		nextdata = (nextdata<<8) | *(bp)++;		\
+		nextbits += 8;					\
+	}							\
+	code = (hcode_t)((nextdata >> (nextbits-nbits)) & nbitsmask);	\
+	nextbits -= nbits;					\
+}
+
+static void
+codeLoop(TIFF* tif, const char* module)
+{
+	TIFFErrorExt(tif->tif_clientdata, module,
+	    "Bogus encoding, loop in the code table; scanline %d",
+	    tif->tif_row);
+}
+
+static int
+LZWDecode(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s)
+{
+	static const char module[] = "LZWDecode";
+	LZWCodecState *sp = DecoderState(tif);
+	char *op = (char*) op0;
+	long occ = (long) occ0;
+	char *tp;
+	unsigned char *bp;
+	hcode_t code;
+	int len;
+	long nbits, nextbits, nextdata, nbitsmask;
+	code_t *codep, *free_entp, *maxcodep, *oldcodep;
+
+	(void) s;
+	assert(sp != NULL);
+        assert(sp->dec_codetab != NULL);
+
+	/*
+	  Fail if value does not fit in long.
+	*/
+	if ((tmsize_t) occ != occ0)
+	        return (0);
+	/*
+	 * Restart interrupted output operation.
+	 */
+	if (sp->dec_restart) {
+		long residue;
+
+		codep = sp->dec_codep;
+		residue = codep->length - sp->dec_restart;
+		if (residue > occ) {
+			/*
+			 * Residue from previous decode is sufficient
+			 * to satisfy decode request.  Skip to the
+			 * start of the decoded string, place decoded
+			 * values in the output buffer, and return.
+			 */
+			sp->dec_restart += occ;
+			do {
+				codep = codep->next;
+			} while (--residue > occ && codep);
+			if (codep) {
+				tp = op + occ;
+				do {
+					*--tp = codep->value;
+					codep = codep->next;
+				} while (--occ && codep);
+			}
+			return (1);
+		}
+		/*
+		 * Residue satisfies only part of the decode request.
+		 */
+		op += residue, occ -= residue;
+		tp = op;
+		do {
+			int t;
+			--tp;
+			t = codep->value;
+			codep = codep->next;
+			*tp = t;
+		} while (--residue && codep);
+		sp->dec_restart = 0;
+	}
+
+	bp = (unsigned char *)tif->tif_rawcp;
+	nbits = sp->lzw_nbits;
+	nextdata = sp->lzw_nextdata;
+	nextbits = sp->lzw_nextbits;
+	nbitsmask = sp->dec_nbitsmask;
+	oldcodep = sp->dec_oldcodep;
+	free_entp = sp->dec_free_entp;
+	maxcodep = sp->dec_maxcodep;
+
+	while (occ > 0) {
+		NextCode(tif, sp, bp, code, GetNextCode);
+		if (code == CODE_EOI)
+			break;
+		if (code == CODE_CLEAR) {
+			free_entp = sp->dec_codetab + CODE_FIRST;
+			_TIFFmemset(free_entp, 0,
+				    (CSIZE - CODE_FIRST) * sizeof (code_t));
+			nbits = BITS_MIN;
+			nbitsmask = MAXCODE(BITS_MIN);
+			maxcodep = sp->dec_codetab + nbitsmask-1;
+			NextCode(tif, sp, bp, code, GetNextCode);
+			if (code == CODE_EOI)
+				break;
+			if (code >= CODE_CLEAR) {
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+				"LZWDecode: Corrupted LZW table at scanline %d",
+					     tif->tif_row);
+				return (0);
+			}
+			*op++ = (char)code, occ--;
+			oldcodep = sp->dec_codetab + code;
+			continue;
+		}
+		codep = sp->dec_codetab + code;
+
+		/*
+		 * Add the new entry to the code table.
+		 */
+		if (free_entp < &sp->dec_codetab[0] ||
+		    free_entp >= &sp->dec_codetab[CSIZE]) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Corrupted LZW table at scanline %d",
+			    tif->tif_row);
+			return (0);
+		}
+
+		free_entp->next = oldcodep;
+		if (free_entp->next < &sp->dec_codetab[0] ||
+		    free_entp->next >= &sp->dec_codetab[CSIZE]) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Corrupted LZW table at scanline %d",
+			    tif->tif_row);
+			return (0);
+		}
+		free_entp->firstchar = free_entp->next->firstchar;
+		free_entp->length = free_entp->next->length+1;
+		free_entp->value = (codep < free_entp) ?
+		    codep->firstchar : free_entp->firstchar;
+		if (++free_entp > maxcodep) {
+			if (++nbits > BITS_MAX)		/* should not happen */
+				nbits = BITS_MAX;
+			nbitsmask = MAXCODE(nbits);
+			maxcodep = sp->dec_codetab + nbitsmask-1;
+		}
+		oldcodep = codep;
+		if (code >= 256) {
+			/*
+			 * Code maps to a string, copy string
+			 * value to output (written in reverse).
+			 */
+			if(codep->length == 0) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Wrong length of decoded string: "
+				    "data probably corrupted at scanline %d",
+				    tif->tif_row);
+				return (0);
+			}
+			if (codep->length > occ) {
+				/*
+				 * String is too long for decode buffer,
+				 * locate portion that will fit, copy to
+				 * the decode buffer, and setup restart
+				 * logic for the next decoding call.
+				 */
+				sp->dec_codep = codep;
+				do {
+					codep = codep->next;
+				} while (codep && codep->length > occ);
+				if (codep) {
+					sp->dec_restart = (long)occ;
+					tp = op + occ;
+					do  {
+						*--tp = codep->value;
+						codep = codep->next;
+					}  while (--occ && codep);
+					if (codep)
+						codeLoop(tif, module);
+				}
+				break;
+			}
+			len = codep->length;
+			tp = op + len;
+			do {
+				int t;
+				--tp;
+				t = codep->value;
+				codep = codep->next;
+				*tp = t;
+			} while (codep && tp > op);
+			if (codep) {
+			    codeLoop(tif, module);
+			    break;
+			}
+			assert(occ >= len);
+			op += len, occ -= len;
+		} else
+			*op++ = (char)code, occ--;
+	}
+
+	tif->tif_rawcp = (uint8*) bp;
+	sp->lzw_nbits = (unsigned short) nbits;
+	sp->lzw_nextdata = nextdata;
+	sp->lzw_nextbits = nextbits;
+	sp->dec_nbitsmask = nbitsmask;
+	sp->dec_oldcodep = oldcodep;
+	sp->dec_free_entp = free_entp;
+	sp->dec_maxcodep = maxcodep;
+
+	if (occ > 0) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at scanline %d (short %I64d bytes)",
+			     tif->tif_row, (unsigned __int64) occ);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at scanline %d (short %llu bytes)",
+			     tif->tif_row, (unsigned long long) occ);
+#endif
+		return (0);
+	}
+	return (1);
+}
+
+#ifdef LZW_COMPAT
+/*
+ * Decode a "hunk of data" for old images.
+ */
+#define	GetNextCodeCompat(sp, bp, code) {			\
+	nextdata |= (unsigned long) *(bp)++ << nextbits;	\
+	nextbits += 8;						\
+	if (nextbits < nbits) {					\
+		nextdata |= (unsigned long) *(bp)++ << nextbits;\
+		nextbits += 8;					\
+	}							\
+	code = (hcode_t)(nextdata & nbitsmask);			\
+	nextdata >>= nbits;					\
+	nextbits -= nbits;					\
+}
+
+static int
+LZWDecodeCompat(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s)
+{
+	static const char module[] = "LZWDecodeCompat";
+	LZWCodecState *sp = DecoderState(tif);
+	char *op = (char*) op0;
+	long occ = (long) occ0;
+	char *tp;
+	unsigned char *bp;
+	int code, nbits;
+	long nextbits, nextdata, nbitsmask;
+	code_t *codep, *free_entp, *maxcodep, *oldcodep;
+
+	(void) s;
+	assert(sp != NULL);
+
+	/*
+	  Fail if value does not fit in long.
+	*/
+	if ((tmsize_t) occ != occ0)
+	        return (0);
+
+	/*
+	 * Restart interrupted output operation.
+	 */
+	if (sp->dec_restart) {
+		long residue;
+
+		codep = sp->dec_codep;
+		residue = codep->length - sp->dec_restart;
+		if (residue > occ) {
+			/*
+			 * Residue from previous decode is sufficient
+			 * to satisfy decode request.  Skip to the
+			 * start of the decoded string, place decoded
+			 * values in the output buffer, and return.
+			 */
+			sp->dec_restart += occ;
+			do {
+				codep = codep->next;
+			} while (--residue > occ);
+			tp = op + occ;
+			do {
+				*--tp = codep->value;
+				codep = codep->next;
+			} while (--occ);
+			return (1);
+		}
+		/*
+		 * Residue satisfies only part of the decode request.
+		 */
+		op += residue, occ -= residue;
+		tp = op;
+		do {
+			*--tp = codep->value;
+			codep = codep->next;
+		} while (--residue);
+		sp->dec_restart = 0;
+	}
+
+	bp = (unsigned char *)tif->tif_rawcp;
+	nbits = sp->lzw_nbits;
+	nextdata = sp->lzw_nextdata;
+	nextbits = sp->lzw_nextbits;
+	nbitsmask = sp->dec_nbitsmask;
+	oldcodep = sp->dec_oldcodep;
+	free_entp = sp->dec_free_entp;
+	maxcodep = sp->dec_maxcodep;
+
+	while (occ > 0) {
+		NextCode(tif, sp, bp, code, GetNextCodeCompat);
+		if (code == CODE_EOI)
+			break;
+		if (code == CODE_CLEAR) {
+			free_entp = sp->dec_codetab + CODE_FIRST;
+			_TIFFmemset(free_entp, 0,
+				    (CSIZE - CODE_FIRST) * sizeof (code_t));
+			nbits = BITS_MIN;
+			nbitsmask = MAXCODE(BITS_MIN);
+			maxcodep = sp->dec_codetab + nbitsmask;
+			NextCode(tif, sp, bp, code, GetNextCodeCompat);
+			if (code == CODE_EOI)
+				break;
+			if (code >= CODE_CLEAR) {
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+				"LZWDecode: Corrupted LZW table at scanline %d",
+					     tif->tif_row);
+				return (0);
+			}
+			*op++ = code, occ--;
+			oldcodep = sp->dec_codetab + code;
+			continue;
+		}
+		codep = sp->dec_codetab + code;
+
+		/*
+		 * Add the new entry to the code table.
+		 */
+		if (free_entp < &sp->dec_codetab[0] ||
+		    free_entp >= &sp->dec_codetab[CSIZE]) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Corrupted LZW table at scanline %d", tif->tif_row);
+			return (0);
+		}
+
+		free_entp->next = oldcodep;
+		if (free_entp->next < &sp->dec_codetab[0] ||
+		    free_entp->next >= &sp->dec_codetab[CSIZE]) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Corrupted LZW table at scanline %d", tif->tif_row);
+			return (0);
+		}
+		free_entp->firstchar = free_entp->next->firstchar;
+		free_entp->length = free_entp->next->length+1;
+		free_entp->value = (codep < free_entp) ?
+		    codep->firstchar : free_entp->firstchar;
+		if (++free_entp > maxcodep) {
+			if (++nbits > BITS_MAX)		/* should not happen */
+				nbits = BITS_MAX;
+			nbitsmask = MAXCODE(nbits);
+			maxcodep = sp->dec_codetab + nbitsmask;
+		}
+		oldcodep = codep;
+		if (code >= 256) {
+			/*
+			 * Code maps to a string, copy string
+			 * value to output (written in reverse).
+			 */
+			if(codep->length == 0) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Wrong length of decoded "
+				    "string: data probably corrupted at scanline %d",
+				    tif->tif_row);
+				return (0);
+			}
+			if (codep->length > occ) {
+				/*
+				 * String is too long for decode buffer,
+				 * locate portion that will fit, copy to
+				 * the decode buffer, and setup restart
+				 * logic for the next decoding call.
+				 */
+				sp->dec_codep = codep;
+				do {
+					codep = codep->next;
+				} while (codep->length > occ);
+				sp->dec_restart = occ;
+				tp = op + occ;
+				do  {
+					*--tp = codep->value;
+					codep = codep->next;
+				}  while (--occ);
+				break;
+			}
+			assert(occ >= codep->length);
+			op += codep->length, occ -= codep->length;
+			tp = op;
+			do {
+				*--tp = codep->value;
+			} while( (codep = codep->next) != NULL );
+		} else
+			*op++ = code, occ--;
+	}
+
+	tif->tif_rawcp = (uint8*) bp;
+	sp->lzw_nbits = nbits;
+	sp->lzw_nextdata = nextdata;
+	sp->lzw_nextbits = nextbits;
+	sp->dec_nbitsmask = nbitsmask;
+	sp->dec_oldcodep = oldcodep;
+	sp->dec_free_entp = free_entp;
+	sp->dec_maxcodep = maxcodep;
+
+	if (occ > 0) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at scanline %d (short %I64d bytes)",
+			     tif->tif_row, (unsigned __int64) occ);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at scanline %d (short %llu bytes)",
+			     tif->tif_row, (unsigned long long) occ);
+#endif
+		return (0);
+	}
+	return (1);
+}
+#endif /* LZW_COMPAT */
+
+/*
+ * LZW Encoding.
+ */
+
+static int
+LZWSetupEncode(TIFF* tif)
+{
+	static const char module[] = "LZWSetupEncode";
+	LZWCodecState* sp = EncoderState(tif);
+
+	assert(sp != NULL);
+	sp->enc_hashtab = (hash_t*) _TIFFmalloc(HSIZE*sizeof (hash_t));
+	if (sp->enc_hashtab == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "No space for LZW hash table");
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+LZWPreEncode(TIFF* tif, uint16 s)
+{
+	LZWCodecState *sp = EncoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+
+	if( sp->enc_hashtab == NULL )
+        {
+            tif->tif_setupencode( tif );
+        }
+
+	sp->lzw_nbits = BITS_MIN;
+	sp->lzw_maxcode = MAXCODE(BITS_MIN);
+	sp->lzw_free_ent = CODE_FIRST;
+	sp->lzw_nextbits = 0;
+	sp->lzw_nextdata = 0;
+	sp->enc_checkpoint = CHECK_GAP;
+	sp->enc_ratio = 0;
+	sp->enc_incount = 0;
+	sp->enc_outcount = 0;
+	/*
+	 * The 4 here insures there is space for 2 max-sized
+	 * codes in LZWEncode and LZWPostDecode.
+	 */
+	sp->enc_rawlimit = tif->tif_rawdata + tif->tif_rawdatasize-1 - 4;
+	cl_hash(sp);		/* clear hash table */
+	sp->enc_oldcode = (hcode_t) -1;	/* generates CODE_CLEAR in LZWEncode */
+	return (1);
+}
+
+#define	CALCRATIO(sp, rat) {					\
+	if (incount > 0x007fffff) { /* NB: shift will overflow */\
+		rat = outcount >> 8;				\
+		rat = (rat == 0 ? 0x7fffffff : incount/rat);	\
+	} else							\
+		rat = (incount<<8) / outcount;			\
+}
+#define	PutNextCode(op, c) {					\
+	nextdata = (nextdata << nbits) | c;			\
+	nextbits += nbits;					\
+	*op++ = (unsigned char)(nextdata >> (nextbits-8));		\
+	nextbits -= 8;						\
+	if (nextbits >= 8) {					\
+		*op++ = (unsigned char)(nextdata >> (nextbits-8));	\
+		nextbits -= 8;					\
+	}							\
+	outcount += nbits;					\
+}
+
+/*
+ * Encode a chunk of pixels.
+ *
+ * Uses an open addressing double hashing (no chaining) on the 
+ * prefix code/next character combination.  We do a variant of
+ * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's
+ * relatively-prime secondary probe.  Here, the modular division
+ * first probe is gives way to a faster exclusive-or manipulation. 
+ * Also do block compression with an adaptive reset, whereby the
+ * code table is cleared when the compression ratio decreases,
+ * but after the table fills.  The variable-length output codes
+ * are re-sized at this point, and a CODE_CLEAR is generated
+ * for the decoder. 
+ */
+static int
+LZWEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	register LZWCodecState *sp = EncoderState(tif);
+	register long fcode;
+	register hash_t *hp;
+	register int h, c;
+	hcode_t ent;
+	long disp;
+	long incount, outcount, checkpoint;
+	long nextdata, nextbits;
+	int free_ent, maxcode, nbits;
+	uint8* op;
+	uint8* limit;
+
+	(void) s;
+	if (sp == NULL)
+		return (0);
+
+        assert(sp->enc_hashtab != NULL);
+
+	/*
+	 * Load local state.
+	 */
+	incount = sp->enc_incount;
+	outcount = sp->enc_outcount;
+	checkpoint = sp->enc_checkpoint;
+	nextdata = sp->lzw_nextdata;
+	nextbits = sp->lzw_nextbits;
+	free_ent = sp->lzw_free_ent;
+	maxcode = sp->lzw_maxcode;
+	nbits = sp->lzw_nbits;
+	op = tif->tif_rawcp;
+	limit = sp->enc_rawlimit;
+	ent = sp->enc_oldcode;
+
+	if (ent == (hcode_t) -1 && cc > 0) {
+		/*
+		 * NB: This is safe because it can only happen
+		 *     at the start of a strip where we know there
+		 *     is space in the data buffer.
+		 */
+		PutNextCode(op, CODE_CLEAR);
+		ent = *bp++; cc--; incount++;
+	}
+	while (cc > 0) {
+		c = *bp++; cc--; incount++;
+		fcode = ((long)c << BITS_MAX) + ent;
+		h = (c << HSHIFT) ^ ent;	/* xor hashing */
+#ifdef _WINDOWS
+		/*
+		 * Check hash index for an overflow.
+		 */
+		if (h >= HSIZE)
+			h -= HSIZE;
+#endif
+		hp = &sp->enc_hashtab[h];
+		if (hp->hash == fcode) {
+			ent = hp->code;
+			continue;
+		}
+		if (hp->hash >= 0) {
+			/*
+			 * Primary hash failed, check secondary hash.
+			 */
+			disp = HSIZE - h;
+			if (h == 0)
+				disp = 1;
+			do {
+				/*
+				 * Avoid pointer arithmetic 'cuz of
+				 * wraparound problems with segments.
+				 */
+				if ((h -= disp) < 0)
+					h += HSIZE;
+				hp = &sp->enc_hashtab[h];
+				if (hp->hash == fcode) {
+					ent = hp->code;
+					goto hit;
+				}
+			} while (hp->hash >= 0);
+		}
+		/*
+		 * New entry, emit code and add to table.
+		 */
+		/*
+		 * Verify there is space in the buffer for the code
+		 * and any potential Clear code that might be emitted
+		 * below.  The value of limit is setup so that there
+		 * are at least 4 bytes free--room for 2 codes.
+		 */
+		if (op > limit) {
+			tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata);
+			TIFFFlushData1(tif);
+			op = tif->tif_rawdata;
+		}
+		PutNextCode(op, ent);
+		ent = c;
+		hp->code = free_ent++;
+		hp->hash = fcode;
+		if (free_ent == CODE_MAX-1) {
+			/* table is full, emit clear code and reset */
+			cl_hash(sp);
+			sp->enc_ratio = 0;
+			incount = 0;
+			outcount = 0;
+			free_ent = CODE_FIRST;
+			PutNextCode(op, CODE_CLEAR);
+			nbits = BITS_MIN;
+			maxcode = MAXCODE(BITS_MIN);
+		} else {
+			/*
+			 * If the next entry is going to be too big for
+			 * the code size, then increase it, if possible.
+			 */
+			if (free_ent > maxcode) {
+				nbits++;
+				assert(nbits <= BITS_MAX);
+				maxcode = (int) MAXCODE(nbits);
+			} else if (incount >= checkpoint) {
+				long rat;
+				/*
+				 * Check compression ratio and, if things seem
+				 * to be slipping, clear the hash table and
+				 * reset state.  The compression ratio is a
+				 * 24+8-bit fractional number.
+				 */
+				checkpoint = incount+CHECK_GAP;
+				CALCRATIO(sp, rat);
+				if (rat <= sp->enc_ratio) {
+					cl_hash(sp);
+					sp->enc_ratio = 0;
+					incount = 0;
+					outcount = 0;
+					free_ent = CODE_FIRST;
+					PutNextCode(op, CODE_CLEAR);
+					nbits = BITS_MIN;
+					maxcode = MAXCODE(BITS_MIN);
+				} else
+					sp->enc_ratio = rat;
+			}
+		}
+	hit:
+		;
+	}
+
+	/*
+	 * Restore global state.
+	 */
+	sp->enc_incount = incount;
+	sp->enc_outcount = outcount;
+	sp->enc_checkpoint = checkpoint;
+	sp->enc_oldcode = ent;
+	sp->lzw_nextdata = nextdata;
+	sp->lzw_nextbits = nextbits;
+	sp->lzw_free_ent = free_ent;
+	sp->lzw_maxcode = maxcode;
+	sp->lzw_nbits = nbits;
+	tif->tif_rawcp = op;
+	return (1);
+}
+
+/*
+ * Finish off an encoded strip by flushing the last
+ * string and tacking on an End Of Information code.
+ */
+static int
+LZWPostEncode(TIFF* tif)
+{
+	register LZWCodecState *sp = EncoderState(tif);
+	uint8* op = tif->tif_rawcp;
+	long nextbits = sp->lzw_nextbits;
+	long nextdata = sp->lzw_nextdata;
+	long outcount = sp->enc_outcount;
+	int nbits = sp->lzw_nbits;
+
+	if (op > sp->enc_rawlimit) {
+		tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata);
+		TIFFFlushData1(tif);
+		op = tif->tif_rawdata;
+	}
+	if (sp->enc_oldcode != (hcode_t) -1) {
+		PutNextCode(op, sp->enc_oldcode);
+		sp->enc_oldcode = (hcode_t) -1;
+	}
+	PutNextCode(op, CODE_EOI);
+	if (nextbits > 0) 
+		*op++ = (unsigned char)(nextdata << (8-nextbits));
+	tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata);
+	return (1);
+}
+
+/*
+ * Reset encoding hash table.
+ */
+static void
+cl_hash(LZWCodecState* sp)
+{
+	register hash_t *hp = &sp->enc_hashtab[HSIZE-1];
+	register long i = HSIZE-8;
+
+	do {
+		i -= 8;
+		hp[-7].hash = -1;
+		hp[-6].hash = -1;
+		hp[-5].hash = -1;
+		hp[-4].hash = -1;
+		hp[-3].hash = -1;
+		hp[-2].hash = -1;
+		hp[-1].hash = -1;
+		hp[ 0].hash = -1;
+		hp -= 8;
+	} while (i >= 0);
+	for (i += 8; i > 0; i--, hp--)
+		hp->hash = -1;
+}
+
+static void
+LZWCleanup(TIFF* tif)
+{
+	(void)TIFFPredictorCleanup(tif);
+
+	assert(tif->tif_data != 0);
+
+	if (DecoderState(tif)->dec_codetab)
+		_TIFFfree(DecoderState(tif)->dec_codetab);
+
+	if (EncoderState(tif)->enc_hashtab)
+		_TIFFfree(EncoderState(tif)->enc_hashtab);
+
+	_TIFFfree(tif->tif_data);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+int
+TIFFInitLZW(TIFF* tif, int scheme)
+{
+	static const char module[] = "TIFFInitLZW";
+	assert(scheme == COMPRESSION_LZW);
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (LZWCodecState));
+	if (tif->tif_data == NULL)
+		goto bad;
+	DecoderState(tif)->dec_codetab = NULL;
+	DecoderState(tif)->dec_decode = NULL;
+	EncoderState(tif)->enc_hashtab = NULL;
+        LZWState(tif)->rw_mode = tif->tif_mode;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = LZWFixupTags; 
+	tif->tif_setupdecode = LZWSetupDecode;
+	tif->tif_predecode = LZWPreDecode;
+	tif->tif_decoderow = LZWDecode;
+	tif->tif_decodestrip = LZWDecode;
+	tif->tif_decodetile = LZWDecode;
+	tif->tif_setupencode = LZWSetupEncode;
+	tif->tif_preencode = LZWPreEncode;
+	tif->tif_postencode = LZWPostEncode;
+	tif->tif_encoderow = LZWEncode;
+	tif->tif_encodestrip = LZWEncode;
+	tif->tif_encodetile = LZWEncode;
+	tif->tif_cleanup = LZWCleanup;
+	/*
+	 * Setup predictor setup.
+	 */
+	(void) TIFFPredictorInit(tif);
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module, 
+		     "No space for LZW state block");
+	return (0);
+}
+
+/*
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#endif /* LZW_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_next.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_next.c
new file mode 100644
index 0000000..8c4fec4
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_next.c
@@ -0,0 +1,162 @@
+/* $Id: tif_next.c,v 1.13 2010-03-10 18:56:48 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#ifdef NEXT_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * NeXT 2-bit Grey Scale Compression Algorithm Support
+ */
+
+#define SETPIXEL(op, v) {			\
+	switch (npixels++ & 3) {		\
+	case 0:	op[0]  = (unsigned char) ((v) << 6); break;	\
+	case 1:	op[0] |= (v) << 4; break;	\
+	case 2:	op[0] |= (v) << 2; break;	\
+	case 3:	*op++ |= (v);	   break;	\
+	}					\
+}
+
+#define LITERALROW	0x00
+#define LITERALSPAN	0x40
+#define WHITE   	((1<<2)-1)
+
+static int
+NeXTDecode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "NeXTDecode";
+	unsigned char *bp, *op;
+	tmsize_t cc;
+	uint8* row;
+	tmsize_t scanline, n;
+
+	(void) s;
+	/*
+	 * Each scanline is assumed to start off as all
+	 * white (we assume a PhotometricInterpretation
+	 * of ``min-is-black'').
+	 */
+	for (op = (unsigned char*) buf, cc = occ; cc-- > 0;)
+		*op++ = 0xff;
+
+	bp = (unsigned char *)tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	scanline = tif->tif_scanlinesize;
+	if (occ % scanline)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (0);
+	}
+	for (row = buf; occ > 0; occ -= scanline, row += scanline) {
+		n = *bp++, cc--;
+		switch (n) {
+		case LITERALROW:
+			/*
+			 * The entire scanline is given as literal values.
+			 */
+			if (cc < scanline)
+				goto bad;
+			_TIFFmemcpy(row, bp, scanline);
+			bp += scanline;
+			cc -= scanline;
+			break;
+		case LITERALSPAN: {
+			tmsize_t off;
+			/*
+			 * The scanline has a literal span that begins at some
+			 * offset.
+			 */
+			off = (bp[0] * 256) + bp[1];
+			n = (bp[2] * 256) + bp[3];
+			if (cc < 4+n || off+n > scanline)
+				goto bad;
+			_TIFFmemcpy(row+off, bp+4, n);
+			bp += 4+n;
+			cc -= 4+n;
+			break;
+		}
+		default: {
+			uint32 npixels = 0, grey;
+			uint32 imagewidth = tif->tif_dir.td_imagewidth;
+
+			/*
+			 * The scanline is composed of a sequence of constant
+			 * color ``runs''.  We shift into ``run mode'' and
+			 * interpret bytes as codes of the form
+			 * <color><npixels> until we've filled the scanline.
+			 */
+			op = row;
+			for (;;) {
+				grey = (uint32)((n>>6) & 0x3);
+				n &= 0x3f;
+				/*
+				 * Ensure the run does not exceed the scanline
+				 * bounds, potentially resulting in a security
+				 * issue.
+				 */
+				while (n-- > 0 && npixels < imagewidth)
+					SETPIXEL(op, grey);
+				if (npixels >= imagewidth)
+					break;
+				if (cc == 0)
+					goto bad;
+				n = *bp++, cc--;
+			}
+			break;
+		}
+		}
+	}
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module, "Not enough data for scanline %ld",
+	    (long) tif->tif_row);
+	return (0);
+}
+
+int
+TIFFInitNeXT(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	tif->tif_decoderow = NeXTDecode;  
+	tif->tif_decodestrip = NeXTDecode;  
+	tif->tif_decodetile = NeXTDecode;
+	return (1);
+}
+#endif /* NEXT_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_ojpeg.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_ojpeg.c
new file mode 100644
index 0000000..bed4f9b
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_ojpeg.c
@@ -0,0 +1,2506 @@
+/* $Id: tif_ojpeg.c,v 1.56 2012-05-24 03:15:18 fwarmerdam Exp $ */
+
+/* WARNING: The type of JPEG encapsulation defined by the TIFF Version 6.0
+   specification is now totally obsolete and deprecated for new applications and
+   images. This file was was created solely in order to read unconverted images
+   still present on some users' computer systems. It will never be extended
+   to write such files. Writing new-style JPEG compressed TIFFs is implemented
+   in tif_jpeg.c.
+
+   The code is carefully crafted to robustly read all gathered JPEG-in-TIFF
+   testfiles, and anticipate as much as possible all other... But still, it may
+   fail on some. If you encounter problems, please report them on the TIFF
+   mailing list and/or to Joris Van Damme <info@awaresystems.be>.
+
+   Please read the file called "TIFF Technical Note #2" if you need to be
+   convinced this compression scheme is bad and breaks TIFF. That document
+   is linked to from the LibTiff site <http://www.remotesensing.org/libtiff/>
+   and from AWare Systems' TIFF section
+   <http://www.awaresystems.be/imaging/tiff.html>. It is also absorbed
+   in Adobe's specification supplements, marked "draft" up to this day, but
+   supported by the TIFF community.
+
+   This file interfaces with Release 6B of the JPEG Library written by the
+   Independent JPEG Group. Previous versions of this file required a hack inside
+   the LibJpeg library. This version no longer requires that. Remember to
+   remove the hack if you update from the old version.
+
+   Copyright (c) Joris Van Damme <info@awaresystems.be>
+   Copyright (c) AWare Systems <http://www.awaresystems.be/>
+
+   The licence agreement for this file is the same as the rest of the LibTiff
+   library.
+
+   IN NO EVENT SHALL JORIS VAN DAMME OR AWARE SYSTEMS BE LIABLE FOR
+   ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+   OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+   WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+   LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+   OF THIS SOFTWARE.
+
+   Joris Van Damme and/or AWare Systems may be available for custom
+   developement. If you like what you see, and need anything similar or related,
+   contact <info@awaresystems.be>.
+*/
+
+/* What is what, and what is not?
+
+   This decoder starts with an input stream, that is essentially the JpegInterchangeFormat
+   stream, if any, followed by the strile data, if any. This stream is read in
+   OJPEGReadByte and related functions.
+
+   It analyzes the start of this stream, until it encounters non-marker data, i.e.
+   compressed image data. Some of the header markers it sees have no actual content,
+   like the SOI marker, and APP/COM markers that really shouldn't even be there. Some
+   other markers do have content, and the valuable bits and pieces of information
+   in these markers are saved, checking all to verify that the stream is more or
+   less within expected bounds. This happens inside the OJPEGReadHeaderInfoSecStreamXxx
+   functions.
+
+   Some OJPEG imagery contains no valid JPEG header markers. This situation is picked
+   up on if we've seen no SOF marker when we're at the start of the compressed image
+   data. In this case, the tables are read from JpegXxxTables tags, and the other
+   bits and pieces of information is initialized to its most basic value. This is
+   implemented in the OJPEGReadHeaderInfoSecTablesXxx functions.
+
+   When this is complete, a good and valid JPEG header can be assembled, and this is
+   passed through to LibJpeg. When that's done, the remainder of the input stream, i.e.
+   the compressed image data, can be passed through unchanged. This is done in
+   OJPEGWriteStream functions.
+
+   LibTiff rightly expects to know the subsampling values before decompression. Just like
+   in new-style JPEG-in-TIFF, though, or even more so, actually, the YCbCrsubsampling
+   tag is notoriously unreliable. To correct these tag values with the ones inside
+   the JPEG stream, the first part of the input stream is pre-scanned in
+   OJPEGSubsamplingCorrect, making no note of any other data, reporting no warnings
+   or errors, up to the point where either these values are read, or it's clear they
+   aren't there. This means that some of the data is read twice, but we feel speed
+   in correcting these values is important enough to warrant this sacrifice. Allthough
+   there is currently no define or other configuration mechanism to disable this behaviour,
+   the actual header scanning is build to robustly respond with error report if it
+   should encounter an uncorrected mismatch of subsampling values. See
+   OJPEGReadHeaderInfoSecStreamSof.
+
+   The restart interval and restart markers are the most tricky part... The restart
+   interval can be specified in a tag. It can also be set inside the input JPEG stream.
+   It can be used inside the input JPEG stream. If reading from strile data, we've
+   consistenly discovered the need to insert restart markers in between the different
+   striles, as is also probably the most likely interpretation of the original TIFF 6.0
+   specification. With all this setting of interval, and actual use of markers that is not
+   predictable at the time of valid JPEG header assembly, the restart thing may turn
+   out the Achilles heel of this implementation. Fortunately, most OJPEG writer vendors
+   succeed in reading back what they write, which may be the reason why we've been able
+   to discover ways that seem to work.
+
+   Some special provision is made for planarconfig separate OJPEG files. These seem
+   to consistently contain header info, a SOS marker, a plane, SOS marker, plane, SOS,
+   and plane. This may or may not be a valid JPEG configuration, we don't know and don't
+   care. We want LibTiff to be able to access the planes individually, without huge
+   buffering inside LibJpeg, anyway. So we compose headers to feed to LibJpeg, in this
+   case, that allow us to pass a single plane such that LibJpeg sees a valid
+   single-channel JPEG stream. Locating subsequent SOS markers, and thus subsequent
+   planes, is done inside OJPEGReadSecondarySos.
+
+   The benefit of the scheme is... that it works, basically. We know of no other that
+   does. It works without checking software tag, or otherwise going about things in an
+   OJPEG flavor specific manner. Instead, it is a single scheme, that covers the cases
+   with and without JpegInterchangeFormat, with and without striles, with part of
+   the header in JpegInterchangeFormat and remainder in first strile, etc. It is forgiving
+   and robust, may likely work with OJPEG flavors we've not seen yet, and makes most out
+   of the data.
+
+   Another nice side-effect is that a complete JPEG single valid stream is build if
+   planarconfig is not separate (vast majority). We may one day use that to build
+   converters to JPEG, and/or to new-style JPEG compression inside TIFF.
+
+   A dissadvantage is the lack of random access to the individual striles. This is the
+   reason for much of the complicated restart-and-position stuff inside OJPEGPreDecode.
+   Applications would do well accessing all striles in order, as this will result in
+   a single sequential scan of the input stream, and no restarting of LibJpeg decoding
+   session.
+*/
+
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+
+#include "tiffiop.h"
+#ifdef OJPEG_SUPPORT
+
+/* Configuration defines here are:
+ * JPEG_ENCAP_EXTERNAL: The normal way to call libjpeg, uses longjump. In some environments,
+ * 	like eg LibTiffDelphi, this is not possible. For this reason, the actual calls to
+ * 	libjpeg, with longjump stuff, are encapsulated in dedicated functions. When
+ * 	JPEG_ENCAP_EXTERNAL is defined, these encapsulating functions are declared external
+ * 	to this unit, and can be defined elsewhere to use stuff other then longjump.
+ * 	The default mode, without JPEG_ENCAP_EXTERNAL, implements the call encapsulators
+ * 	here, internally, with normal longjump.
+ * SETJMP, LONGJMP, JMP_BUF: On some machines/environments a longjump equivalent is
+ * 	conviniently available, but still it may be worthwhile to use _setjmp or sigsetjmp
+ * 	in place of plain setjmp. These macros will make it easier. It is useless
+ * 	to fiddle with these if you define JPEG_ENCAP_EXTERNAL.
+ * OJPEG_BUFFER: Define the size of the desired buffer here. Should be small enough so as to guarantee
+ * 	instant processing, optimal streaming and optimal use of processor cache, but also big
+ * 	enough so as to not result in significant call overhead. It should be at least a few
+ * 	bytes to accomodate some structures (this is verified in asserts), but it would not be
+ * 	sensible to make it this small anyway, and it should be at most 64K since it is indexed
+ * 	with uint16. We recommend 2K.
+ * EGYPTIANWALK: You could also define EGYPTIANWALK here, but it is not used anywhere and has
+ * 	absolutely no effect. That is why most people insist the EGYPTIANWALK is a bit silly.
+ */
+
+/* define LIBJPEG_ENCAP_EXTERNAL */
+#define SETJMP(jbuf) setjmp(jbuf)
+#define LONGJMP(jbuf,code) longjmp(jbuf,code)
+#define JMP_BUF jmp_buf
+#define OJPEG_BUFFER 2048
+/* define EGYPTIANWALK */
+
+#define JPEG_MARKER_SOF0 0xC0
+#define JPEG_MARKER_SOF1 0xC1
+#define JPEG_MARKER_SOF3 0xC3
+#define JPEG_MARKER_DHT 0xC4
+#define JPEG_MARKER_RST0 0XD0
+#define JPEG_MARKER_SOI 0xD8
+#define JPEG_MARKER_EOI 0xD9
+#define JPEG_MARKER_SOS 0xDA
+#define JPEG_MARKER_DQT 0xDB
+#define JPEG_MARKER_DRI 0xDD
+#define JPEG_MARKER_APP0 0xE0
+#define JPEG_MARKER_COM 0xFE
+
+#define FIELD_OJPEG_JPEGINTERCHANGEFORMAT (FIELD_CODEC+0)
+#define FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH (FIELD_CODEC+1)
+#define FIELD_OJPEG_JPEGQTABLES (FIELD_CODEC+2)
+#define FIELD_OJPEG_JPEGDCTABLES (FIELD_CODEC+3)
+#define FIELD_OJPEG_JPEGACTABLES (FIELD_CODEC+4)
+#define FIELD_OJPEG_JPEGPROC (FIELD_CODEC+5)
+#define FIELD_OJPEG_JPEGRESTARTINTERVAL (FIELD_CODEC+6)
+
+static const TIFFField ojpegFields[] = {
+	{TIFFTAG_JPEGIFOFFSET,1,1,TIFF_LONG8,0,TIFF_SETGET_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGINTERCHANGEFORMAT,TRUE,FALSE,"JpegInterchangeFormat",NULL},
+	{TIFFTAG_JPEGIFBYTECOUNT,1,1,TIFF_LONG8,0,TIFF_SETGET_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH,TRUE,FALSE,"JpegInterchangeFormatLength",NULL},
+	{TIFFTAG_JPEGQTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGQTABLES,FALSE,TRUE,"JpegQTables",NULL},
+	{TIFFTAG_JPEGDCTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGDCTABLES,FALSE,TRUE,"JpegDcTables",NULL},
+	{TIFFTAG_JPEGACTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGACTABLES,FALSE,TRUE,"JpegAcTables",NULL},
+	{TIFFTAG_JPEGPROC,1,1,TIFF_SHORT,0,TIFF_SETGET_UINT16,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGPROC,FALSE,FALSE,"JpegProc",NULL},
+	{TIFFTAG_JPEGRESTARTINTERVAL,1,1,TIFF_SHORT,0,TIFF_SETGET_UINT16,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGRESTARTINTERVAL,FALSE,FALSE,"JpegRestartInterval",NULL},
+};
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+#include <setjmp.h>
+#endif
+
+/* We undefine FAR to avoid conflict with JPEG definition */
+
+#ifdef FAR
+#undef FAR
+#endif
+
+/*
+  Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is
+  not defined.  Unfortunately, the MinGW and Borland compilers include
+  a typedef for INT32, which causes a conflict.  MSVC does not include
+  a conficting typedef given the headers which are included.
+*/
+#if defined(__BORLANDC__) || defined(__MINGW32__)
+# define XMD_H 1
+#endif
+
+/* Define "boolean" as unsigned char, not int, per Windows custom. */
+#if defined(__WIN32__) && !defined(__MINGW32__)
+# ifndef __RPCNDR_H__            /* don't conflict if rpcndr.h already read */
+   typedef unsigned char boolean;
+# endif
+# define HAVE_BOOLEAN            /* prevent jmorecfg.h from redefining it */
+#endif
+
+#ifndef _FX_JPEG_TURBO_
+	#include "../../libjpeg/jpeglib.h"
+	#include "../../libjpeg/jerror.h"
+#else
+	#include "../../libjpeg-turbo/jpeglib.h"
+	#include "../../libjpeg-turbo/jerror.h"
+#endif//_FX_JPEG_TURBO_
+
+typedef struct jpeg_error_mgr jpeg_error_mgr;
+typedef struct jpeg_common_struct jpeg_common_struct;
+typedef struct jpeg_decompress_struct jpeg_decompress_struct;
+typedef struct jpeg_source_mgr jpeg_source_mgr;
+
+typedef enum {
+	osibsNotSetYet,
+	osibsJpegInterchangeFormat,
+	osibsStrile,
+	osibsEof
+} OJPEGStateInBufferSource;
+
+typedef enum {
+	ososSoi,
+	ososQTable0,ososQTable1,ososQTable2,ososQTable3,
+	ososDcTable0,ososDcTable1,ososDcTable2,ososDcTable3,
+	ososAcTable0,ososAcTable1,ososAcTable2,ososAcTable3,
+	ososDri,
+	ososSof,
+	ososSos,
+	ososCompressed,
+	ososRst,
+	ososEoi
+} OJPEGStateOutState;
+
+typedef struct {
+	TIFF* tif;
+	#ifndef LIBJPEG_ENCAP_EXTERNAL
+	JMP_BUF exit_jmpbuf;
+	#endif
+	TIFFVGetMethod vgetparent;
+	TIFFVSetMethod vsetparent;
+	TIFFPrintMethod printdir;
+	uint64 file_size;
+	uint32 image_width;
+	uint32 image_length;
+	uint32 strile_width;
+	uint32 strile_length;
+	uint32 strile_length_total;
+	uint8 samples_per_pixel;
+	uint8 plane_sample_offset;
+	uint8 samples_per_pixel_per_plane;
+	uint64 jpeg_interchange_format;
+	uint64 jpeg_interchange_format_length;
+	uint8 jpeg_proc;
+	uint8 subsamplingcorrect;
+	uint8 subsamplingcorrect_done;
+	uint8 subsampling_tag;
+	uint8 subsampling_hor;
+	uint8 subsampling_ver;
+	uint8 subsampling_force_desubsampling_inside_decompression;
+	uint8 qtable_offset_count;
+	uint8 dctable_offset_count;
+	uint8 actable_offset_count;
+	uint64 qtable_offset[3];
+	uint64 dctable_offset[3];
+	uint64 actable_offset[3];
+	uint8* qtable[4];
+	uint8* dctable[4];
+	uint8* actable[4];
+	uint16 restart_interval;
+	uint8 restart_index;
+	uint8 sof_log;
+	uint8 sof_marker_id;
+	uint32 sof_x;
+	uint32 sof_y;
+	uint8 sof_c[3];
+	uint8 sof_hv[3];
+	uint8 sof_tq[3];
+	uint8 sos_cs[3];
+	uint8 sos_tda[3];
+	struct {
+		uint8 log;
+		OJPEGStateInBufferSource in_buffer_source;
+		uint32 in_buffer_next_strile;
+		uint64 in_buffer_file_pos;
+		uint64 in_buffer_file_togo;
+	} sos_end[3];
+	uint8 readheader_done;
+	uint8 writeheader_done;
+	uint16 write_cursample;
+	uint32 write_curstrile;
+	uint8 libjpeg_session_active;
+	uint8 libjpeg_jpeg_query_style;
+	jpeg_error_mgr libjpeg_jpeg_error_mgr;
+	jpeg_decompress_struct libjpeg_jpeg_decompress_struct;
+	jpeg_source_mgr libjpeg_jpeg_source_mgr;
+	uint8 subsampling_convert_log;
+	uint32 subsampling_convert_ylinelen;
+	uint32 subsampling_convert_ylines;
+	uint32 subsampling_convert_clinelen;
+	uint32 subsampling_convert_clines;
+	uint32 subsampling_convert_ybuflen;
+	uint32 subsampling_convert_cbuflen;
+	uint32 subsampling_convert_ycbcrbuflen;
+	uint8* subsampling_convert_ycbcrbuf;
+	uint8* subsampling_convert_ybuf;
+	uint8* subsampling_convert_cbbuf;
+	uint8* subsampling_convert_crbuf;
+	uint32 subsampling_convert_ycbcrimagelen;
+	uint8** subsampling_convert_ycbcrimage;
+	uint32 subsampling_convert_clinelenout;
+	uint32 subsampling_convert_state;
+	uint32 bytes_per_line;   /* if the codec outputs subsampled data, a 'line' in bytes_per_line */
+	uint32 lines_per_strile; /* and lines_per_strile means subsampling_ver desubsampled rows     */
+	OJPEGStateInBufferSource in_buffer_source;
+	uint32 in_buffer_next_strile;
+	uint32 in_buffer_strile_count;
+	uint64 in_buffer_file_pos;
+	uint8 in_buffer_file_pos_log;
+	uint64 in_buffer_file_togo;
+	uint16 in_buffer_togo;
+	uint8* in_buffer_cur;
+	uint8 in_buffer[OJPEG_BUFFER];
+	OJPEGStateOutState out_state;
+	uint8 out_buffer[OJPEG_BUFFER];
+	uint8* skip_buffer;
+} OJPEGState;
+
+static int OJPEGVGetField(TIFF* tif, uint32 tag, va_list ap);
+static int OJPEGVSetField(TIFF* tif, uint32 tag, va_list ap);
+static void OJPEGPrintDir(TIFF* tif, FILE* fd, long flags);
+
+static int OJPEGFixupTags(TIFF* tif);
+static int OJPEGSetupDecode(TIFF* tif);
+static int OJPEGPreDecode(TIFF* tif, uint16 s);
+static int OJPEGPreDecodeSkipRaw(TIFF* tif);
+static int OJPEGPreDecodeSkipScanlines(TIFF* tif);
+static int OJPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int OJPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc);
+static int OJPEGDecodeScanlines(TIFF* tif, uint8* buf, tmsize_t cc);
+static void OJPEGPostDecode(TIFF* tif, uint8* buf, tmsize_t cc);
+static int OJPEGSetupEncode(TIFF* tif);
+static int OJPEGPreEncode(TIFF* tif, uint16 s);
+static int OJPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int OJPEGPostEncode(TIFF* tif);
+static void OJPEGCleanup(TIFF* tif);
+
+static void OJPEGSubsamplingCorrect(TIFF* tif);
+static int OJPEGReadHeaderInfo(TIFF* tif);
+static int OJPEGReadSecondarySos(TIFF* tif, uint16 s);
+static int OJPEGWriteHeaderInfo(TIFF* tif);
+static void OJPEGLibjpegSessionAbort(TIFF* tif);
+
+static int OJPEGReadHeaderInfoSec(TIFF* tif);
+static int OJPEGReadHeaderInfoSecStreamDri(TIFF* tif);
+static int OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif);
+static int OJPEGReadHeaderInfoSecStreamDht(TIFF* tif);
+static int OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id);
+static int OJPEGReadHeaderInfoSecStreamSos(TIFF* tif);
+static int OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif);
+static int OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif);
+static int OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif);
+
+static int OJPEGReadBufferFill(OJPEGState* sp);
+static int OJPEGReadByte(OJPEGState* sp, uint8* byte);
+static int OJPEGReadBytePeek(OJPEGState* sp, uint8* byte);
+static void OJPEGReadByteAdvance(OJPEGState* sp);
+static int OJPEGReadWord(OJPEGState* sp, uint16* word);
+static int OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem);
+static void OJPEGReadSkip(OJPEGState* sp, uint16 len);
+
+static int OJPEGWriteStream(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len);
+static void OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len);
+static void OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len);
+static void OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len);
+static int OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len);
+
+#ifdef LIBJPEG_ENCAP_EXTERNAL
+extern int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo);
+extern int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image);
+extern int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo);
+extern int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines);
+extern int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines);
+extern void jpeg_encap_unwind(TIFF* tif);
+#else
+static int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* j);
+static int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image);
+static int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo);
+static int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines);
+static int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines);
+static void jpeg_encap_unwind(TIFF* tif);
+#endif
+
+static void OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo);
+static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo);
+static void OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo);
+static boolean OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo);
+static void OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes);
+static boolean OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired);
+static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo);
+
+int
+TIFFInitOJPEG(TIFF* tif, int scheme)
+{
+	static const char module[]="TIFFInitOJPEG";
+	OJPEGState* sp;
+
+	assert(scheme==COMPRESSION_OJPEG);
+
+        /*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, ojpegFields, TIFFArrayCount(ojpegFields))) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Merging Old JPEG codec-specific tags failed");
+		return 0;
+	}
+
+	/* state block */
+	sp = (OJPEGState*)_TIFFmalloc(sizeof(OJPEGState));		// // add (OJPEGState*) cast
+	if (sp == NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"No space for OJPEG state block");
+		return(0);
+	}
+	_TIFFmemset(sp,0,sizeof(OJPEGState));
+	sp->tif=tif;
+	sp->jpeg_proc=1;
+	sp->subsampling_hor=2;
+	sp->subsampling_ver=2;
+	TIFFSetField(tif,TIFFTAG_YCBCRSUBSAMPLING,2,2);
+	/* tif codec methods */
+	tif->tif_fixuptags=OJPEGFixupTags;  
+	tif->tif_setupdecode=OJPEGSetupDecode;
+	tif->tif_predecode=OJPEGPreDecode;
+	tif->tif_postdecode=OJPEGPostDecode;  
+	tif->tif_decoderow=OJPEGDecode;  
+	tif->tif_decodestrip=OJPEGDecode;  
+	tif->tif_decodetile=OJPEGDecode;  
+	tif->tif_setupencode=OJPEGSetupEncode;
+	tif->tif_preencode=OJPEGPreEncode;
+	tif->tif_postencode=OJPEGPostEncode;
+	tif->tif_encoderow=OJPEGEncode;  
+	tif->tif_encodestrip=OJPEGEncode;  
+	tif->tif_encodetile=OJPEGEncode;  
+	tif->tif_cleanup=OJPEGCleanup;
+	tif->tif_data=(uint8*)sp;
+	/* tif tag methods */
+	sp->vgetparent=tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield=OJPEGVGetField;
+	sp->vsetparent=tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield=OJPEGVSetField;
+	sp->printdir=tif->tif_tagmethods.printdir;
+	tif->tif_tagmethods.printdir=OJPEGPrintDir;
+	/* Some OJPEG files don't have strip or tile offsets or bytecounts tags.
+	   Some others do, but have totally meaningless or corrupt values
+	   in these tags. In these cases, the JpegInterchangeFormat stream is
+	   reliable. In any case, this decoder reads the compressed data itself,
+	   from the most reliable locations, and we need to notify encapsulating
+	   LibTiff not to read raw strips or tiles for us. */
+	tif->tif_flags|=TIFF_NOREADRAW;
+	return(1);
+}
+
+static int
+OJPEGVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	switch(tag)
+	{
+		case TIFFTAG_JPEGIFOFFSET:
+			*va_arg(ap,uint64*)=(uint64)sp->jpeg_interchange_format;
+			break;
+		case TIFFTAG_JPEGIFBYTECOUNT:
+			*va_arg(ap,uint64*)=(uint64)sp->jpeg_interchange_format_length;
+			break;
+		case TIFFTAG_YCBCRSUBSAMPLING:
+			if (sp->subsamplingcorrect_done==0)
+				OJPEGSubsamplingCorrect(tif);
+			*va_arg(ap,uint16*)=(uint16)sp->subsampling_hor;
+			*va_arg(ap,uint16*)=(uint16)sp->subsampling_ver;
+			break;
+		case TIFFTAG_JPEGQTABLES:
+			*va_arg(ap,uint32*)=(uint32)sp->qtable_offset_count;
+			*va_arg(ap,void**)=(void*)sp->qtable_offset; 
+			break;
+		case TIFFTAG_JPEGDCTABLES:
+			*va_arg(ap,uint32*)=(uint32)sp->dctable_offset_count;
+			*va_arg(ap,void**)=(void*)sp->dctable_offset;  
+			break;
+		case TIFFTAG_JPEGACTABLES:
+			*va_arg(ap,uint32*)=(uint32)sp->actable_offset_count;
+			*va_arg(ap,void**)=(void*)sp->actable_offset;
+			break;
+		case TIFFTAG_JPEGPROC:
+			*va_arg(ap,uint16*)=(uint16)sp->jpeg_proc;
+			break;
+		case TIFFTAG_JPEGRESTARTINTERVAL:
+			*va_arg(ap,uint16*)=sp->restart_interval;
+			break;
+		default:
+			return (*sp->vgetparent)(tif,tag,ap);
+	}
+	return (1);
+}
+
+static int
+OJPEGVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	static const char module[]="OJPEGVSetField";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint32 ma;
+	uint64* mb;
+	uint32 n;
+	switch(tag)
+	{
+		case TIFFTAG_JPEGIFOFFSET:
+			sp->jpeg_interchange_format=(uint64)va_arg(ap,uint64);
+			break;
+		case TIFFTAG_JPEGIFBYTECOUNT:
+			sp->jpeg_interchange_format_length=(uint64)va_arg(ap,uint64);
+			break;
+		case TIFFTAG_YCBCRSUBSAMPLING:
+			sp->subsampling_tag=1;
+			sp->subsampling_hor=(uint8)va_arg(ap,uint16_vap);
+			sp->subsampling_ver=(uint8)va_arg(ap,uint16_vap);
+			tif->tif_dir.td_ycbcrsubsampling[0]=sp->subsampling_hor;
+			tif->tif_dir.td_ycbcrsubsampling[1]=sp->subsampling_ver;
+			break;
+		case TIFFTAG_JPEGQTABLES:
+			ma=(uint32)va_arg(ap,uint32);
+			if (ma!=0)
+			{
+				if (ma>3)
+				{
+					TIFFErrorExt(tif->tif_clientdata,module,"JpegQTables tag has incorrect count");
+					return(0);
+				}
+				sp->qtable_offset_count=(uint8)ma;
+				mb=(uint64*)va_arg(ap,uint64*);
+				for (n=0; n<ma; n++)
+					sp->qtable_offset[n]=mb[n];
+			}
+			break;
+		case TIFFTAG_JPEGDCTABLES:
+			ma=(uint32)va_arg(ap,uint32);
+			if (ma!=0)
+			{
+				if (ma>3)
+				{
+					TIFFErrorExt(tif->tif_clientdata,module,"JpegDcTables tag has incorrect count");
+					return(0);
+				}
+				sp->dctable_offset_count=(uint8)ma;
+				mb=(uint64*)va_arg(ap,uint64*);
+				for (n=0; n<ma; n++)
+					sp->dctable_offset[n]=mb[n];
+			}
+			break;
+		case TIFFTAG_JPEGACTABLES:
+			ma=(uint32)va_arg(ap,uint32);
+			if (ma!=0)
+			{
+				if (ma>3)
+				{
+					TIFFErrorExt(tif->tif_clientdata,module,"JpegAcTables tag has incorrect count");
+					return(0);
+				}
+				sp->actable_offset_count=(uint8)ma;
+				mb=(uint64*)va_arg(ap,uint64*);
+				for (n=0; n<ma; n++)
+					sp->actable_offset[n]=mb[n];
+			}
+			break;
+		case TIFFTAG_JPEGPROC:
+			sp->jpeg_proc=(uint8)va_arg(ap,uint16_vap);
+			break;
+		case TIFFTAG_JPEGRESTARTINTERVAL:
+			sp->restart_interval=(uint16)va_arg(ap,uint16_vap);
+			break;
+		default:
+			return (*sp->vsetparent)(tif,tag,ap);
+	}
+	TIFFSetFieldBit(tif,TIFFFieldWithTag(tif,tag)->field_bit);
+	tif->tif_flags|=TIFF_DIRTYDIRECT;
+	return(1);
+}
+
+static void
+OJPEGPrintDir(TIFF* tif, FILE* fd, long flags)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 m;
+	(void)flags;
+	assert(sp!=NULL);
+	if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMAT))
+		fprintf(fd,"  JpegInterchangeFormat: " TIFF_UINT64_FORMAT "\n",(TIFF_UINT64_T)sp->jpeg_interchange_format);  
+	if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH))
+		fprintf(fd,"  JpegInterchangeFormatLength: " TIFF_UINT64_FORMAT "\n",(TIFF_UINT64_T)sp->jpeg_interchange_format_length);  
+	if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGQTABLES))
+	{
+		fprintf(fd,"  JpegQTables:");
+		for (m=0; m<sp->qtable_offset_count; m++)
+			fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->qtable_offset[m]);
+		fprintf(fd,"\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGDCTABLES))
+	{
+		fprintf(fd,"  JpegDcTables:");
+		for (m=0; m<sp->dctable_offset_count; m++)
+			fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->dctable_offset[m]);
+		fprintf(fd,"\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGACTABLES))
+	{
+		fprintf(fd,"  JpegAcTables:");
+		for (m=0; m<sp->actable_offset_count; m++)
+			fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->actable_offset[m]);
+		fprintf(fd,"\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGPROC))
+		fprintf(fd,"  JpegProc: %u\n",(unsigned int)sp->jpeg_proc);
+	if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGRESTARTINTERVAL))
+		fprintf(fd,"  JpegRestartInterval: %u\n",(unsigned int)sp->restart_interval);
+	if (sp->printdir)
+		(*sp->printdir)(tif, fd, flags);
+}
+
+static int
+OJPEGFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return(1);
+}
+
+static int
+OJPEGSetupDecode(TIFF* tif)
+{
+	static const char module[]="OJPEGSetupDecode";
+	TIFFWarningExt(tif->tif_clientdata,module,"Depreciated and troublesome old-style JPEG compression mode, please convert to new-style JPEG compression and notify vendor of writing software");
+	return(1);
+}
+
+static int
+OJPEGPreDecode(TIFF* tif, uint16 s)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint32 m;
+	if (sp->subsamplingcorrect_done==0)
+		OJPEGSubsamplingCorrect(tif);
+	if (sp->readheader_done==0)
+	{
+		if (OJPEGReadHeaderInfo(tif)==0)
+			return(0);
+	}
+	if (sp->sos_end[s].log==0)
+	{
+		if (OJPEGReadSecondarySos(tif,s)==0)
+			return(0);
+	}
+	if isTiled(tif)
+		m=tif->tif_curtile;
+	else
+		m=tif->tif_curstrip;
+	if ((sp->writeheader_done!=0) && ((sp->write_cursample!=s) || (sp->write_curstrile>m)))
+	{
+		if (sp->libjpeg_session_active!=0)
+			OJPEGLibjpegSessionAbort(tif);
+		sp->writeheader_done=0;
+	}
+	if (sp->writeheader_done==0)
+	{
+		sp->plane_sample_offset=(uint8)s;
+		sp->write_cursample=s;
+		sp->write_curstrile=s*tif->tif_dir.td_stripsperimage;
+		if ((sp->in_buffer_file_pos_log==0) ||
+		    (sp->in_buffer_file_pos-sp->in_buffer_togo!=sp->sos_end[s].in_buffer_file_pos))
+		{
+			sp->in_buffer_source=sp->sos_end[s].in_buffer_source;
+			sp->in_buffer_next_strile=sp->sos_end[s].in_buffer_next_strile;
+			sp->in_buffer_file_pos=sp->sos_end[s].in_buffer_file_pos;
+			sp->in_buffer_file_pos_log=0;
+			sp->in_buffer_file_togo=sp->sos_end[s].in_buffer_file_togo;
+			sp->in_buffer_togo=0;
+			sp->in_buffer_cur=0;
+		}
+		if (OJPEGWriteHeaderInfo(tif)==0)
+			return(0);
+	}
+	while (sp->write_curstrile<m)          
+	{
+		if (sp->libjpeg_jpeg_query_style==0)
+		{
+			if (OJPEGPreDecodeSkipRaw(tif)==0)
+				return(0);
+		}
+		else
+		{
+			if (OJPEGPreDecodeSkipScanlines(tif)==0)
+				return(0);
+		}
+		sp->write_curstrile++;
+	}
+	return(1);
+}
+
+static int
+OJPEGPreDecodeSkipRaw(TIFF* tif)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint32 m;
+	m=sp->lines_per_strile;
+	if (sp->subsampling_convert_state!=0)
+	{
+		if (sp->subsampling_convert_clines-sp->subsampling_convert_state>=m)
+		{
+			sp->subsampling_convert_state+=m;
+			if (sp->subsampling_convert_state==sp->subsampling_convert_clines)
+				sp->subsampling_convert_state=0;
+			return(1);
+		}
+		m-=sp->subsampling_convert_clines-sp->subsampling_convert_state;
+		sp->subsampling_convert_state=0;
+	}
+	while (m>=sp->subsampling_convert_clines)
+	{
+		if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0)
+			return(0);
+		m-=sp->subsampling_convert_clines;
+	}
+	if (m>0)
+	{
+		if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0)
+			return(0);
+		sp->subsampling_convert_state=m;
+	}
+	return(1);
+}
+
+static int
+OJPEGPreDecodeSkipScanlines(TIFF* tif)
+{
+	static const char module[]="OJPEGPreDecodeSkipScanlines";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint32 m;
+	if (sp->skip_buffer==NULL)
+	{
+		// add (uint8*) cast
+		sp->skip_buffer = (uint8*)_TIFFmalloc(sp->bytes_per_line);
+		if (sp->skip_buffer == NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			return(0);
+		}
+	}
+	for (m=0; m<sp->lines_per_strile; m++)
+	{
+		if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&sp->skip_buffer,1)==0)
+			return(0);
+	}
+	return(1);
+}
+
+static int
+OJPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	(void)s;
+	if (sp->libjpeg_jpeg_query_style==0)
+	{
+		if (OJPEGDecodeRaw(tif,buf,cc)==0)
+			return(0);
+	}
+	else
+	{
+		if (OJPEGDecodeScanlines(tif,buf,cc)==0)
+			return(0);
+	}
+	return(1);
+}
+
+static int
+OJPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+	static const char module[]="OJPEGDecodeRaw";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8* m;
+	tmsize_t n;
+	uint8* oy;
+	uint8* ocb;
+	uint8* ocr;
+	uint8* p;
+	uint32 q;
+	uint8* r;
+	uint8 sx,sy;
+	if (cc%sp->bytes_per_line!=0)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read");
+		return(0);
+	}
+	assert(cc>0);
+	m=buf;
+	n=cc;
+	do
+	{
+		if (sp->subsampling_convert_state==0)
+		{
+			if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0)
+				return(0);
+		}
+		oy=sp->subsampling_convert_ybuf+sp->subsampling_convert_state*sp->subsampling_ver*sp->subsampling_convert_ylinelen;
+		ocb=sp->subsampling_convert_cbbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen;
+		ocr=sp->subsampling_convert_crbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen;
+		p=m;
+		for (q=0; q<sp->subsampling_convert_clinelenout; q++)
+		{
+			r=oy;
+			for (sy=0; sy<sp->subsampling_ver; sy++)
+			{
+				for (sx=0; sx<sp->subsampling_hor; sx++)
+					*p++=*r++;
+				r+=sp->subsampling_convert_ylinelen-sp->subsampling_hor;
+			}
+			oy+=sp->subsampling_hor;
+			*p++=*ocb++;
+			*p++=*ocr++;
+		}
+		sp->subsampling_convert_state++;
+		if (sp->subsampling_convert_state==sp->subsampling_convert_clines)
+			sp->subsampling_convert_state=0;
+		m+=sp->bytes_per_line;
+		n-=sp->bytes_per_line;
+	} while(n>0);
+	return(1);
+}
+
+static int
+OJPEGDecodeScanlines(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+	static const char module[]="OJPEGDecodeScanlines";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8* m;
+	tmsize_t n;
+	if (cc%sp->bytes_per_line!=0)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read");
+		return(0);
+	}
+	assert(cc>0);
+	m=buf;
+	n=cc;
+	do
+	{
+		if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&m,1)==0)
+			return(0);
+		m+=sp->bytes_per_line;
+		n-=sp->bytes_per_line;
+	} while(n>0);
+	return(1);
+}
+
+static void
+OJPEGPostDecode(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	(void)buf;
+	(void)cc;
+	sp->write_curstrile++;
+	if (sp->write_curstrile%tif->tif_dir.td_stripsperimage==0)  
+	{
+		assert(sp->libjpeg_session_active!=0);
+		OJPEGLibjpegSessionAbort(tif);
+		sp->writeheader_done=0;
+	}
+}
+
+static int
+OJPEGSetupEncode(TIFF* tif)
+{
+	static const char module[]="OJPEGSetupEncode";
+	TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead");
+	return(0);
+}
+
+static int
+OJPEGPreEncode(TIFF* tif, uint16 s)
+{
+	static const char module[]="OJPEGPreEncode";
+	(void)s;
+	TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead");
+	return(0);
+}
+
+static int
+OJPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	static const char module[]="OJPEGEncode";
+	(void)buf;
+	(void)cc;
+	(void)s;
+	TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead");
+	return(0);
+}
+
+static int
+OJPEGPostEncode(TIFF* tif)
+{
+	static const char module[]="OJPEGPostEncode";
+	TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead");
+	return(0);
+}
+
+static void
+OJPEGCleanup(TIFF* tif)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	if (sp!=0)
+	{
+		tif->tif_tagmethods.vgetfield=sp->vgetparent;
+		tif->tif_tagmethods.vsetfield=sp->vsetparent;
+		tif->tif_tagmethods.printdir=sp->printdir;
+		if (sp->qtable[0]!=0)
+			_TIFFfree(sp->qtable[0]);
+		if (sp->qtable[1]!=0)
+			_TIFFfree(sp->qtable[1]);
+		if (sp->qtable[2]!=0)
+			_TIFFfree(sp->qtable[2]);
+		if (sp->qtable[3]!=0)
+			_TIFFfree(sp->qtable[3]);
+		if (sp->dctable[0]!=0)
+			_TIFFfree(sp->dctable[0]);
+		if (sp->dctable[1]!=0)
+			_TIFFfree(sp->dctable[1]);
+		if (sp->dctable[2]!=0)
+			_TIFFfree(sp->dctable[2]);
+		if (sp->dctable[3]!=0)
+			_TIFFfree(sp->dctable[3]);
+		if (sp->actable[0]!=0)
+			_TIFFfree(sp->actable[0]);
+		if (sp->actable[1]!=0)
+			_TIFFfree(sp->actable[1]);
+		if (sp->actable[2]!=0)
+			_TIFFfree(sp->actable[2]);
+		if (sp->actable[3]!=0)
+			_TIFFfree(sp->actable[3]);
+		if (sp->libjpeg_session_active!=0)
+			OJPEGLibjpegSessionAbort(tif);
+		if (sp->subsampling_convert_ycbcrbuf!=0)
+			_TIFFfree(sp->subsampling_convert_ycbcrbuf);
+		if (sp->subsampling_convert_ycbcrimage!=0)
+			_TIFFfree(sp->subsampling_convert_ycbcrimage);
+		if (sp->skip_buffer!=0)
+			_TIFFfree(sp->skip_buffer);
+		_TIFFfree(sp);
+		tif->tif_data=NULL;
+		_TIFFSetDefaultCompressionState(tif);
+	}
+}
+
+static void
+OJPEGSubsamplingCorrect(TIFF* tif)
+{
+	static const char module[]="OJPEGSubsamplingCorrect";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 mh;
+	uint8 mv;
+        _TIFFFillStriles( tif );
+        
+	assert(sp->subsamplingcorrect_done==0);
+	if ((tif->tif_dir.td_samplesperpixel!=3) || ((tif->tif_dir.td_photometric!=PHOTOMETRIC_YCBCR) &&
+	    (tif->tif_dir.td_photometric!=PHOTOMETRIC_ITULAB)))
+	{
+		if (sp->subsampling_tag!=0)
+			TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag not appropriate for this Photometric and/or SamplesPerPixel");
+		sp->subsampling_hor=1;
+		sp->subsampling_ver=1;
+		sp->subsampling_force_desubsampling_inside_decompression=0;
+	}
+	else
+	{
+		sp->subsamplingcorrect_done=1;
+		mh=sp->subsampling_hor;
+		mv=sp->subsampling_ver;
+		sp->subsamplingcorrect=1;
+		OJPEGReadHeaderInfoSec(tif);
+		if (sp->subsampling_force_desubsampling_inside_decompression!=0)
+		{
+			sp->subsampling_hor=1;
+			sp->subsampling_ver=1;
+		}
+		sp->subsamplingcorrect=0;
+		if (((sp->subsampling_hor!=mh) || (sp->subsampling_ver!=mv)) && (sp->subsampling_force_desubsampling_inside_decompression==0))
+		{
+			if (sp->subsampling_tag==0)
+				TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data [%d,%d] does not match default values [2,2]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver);
+			else
+				TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data [%d,%d] does not match subsampling tag values [%d,%d]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver,mh,mv);
+		}
+		if (sp->subsampling_force_desubsampling_inside_decompression!=0)
+		{
+			if (sp->subsampling_tag==0)
+				TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data does not match default values [2,2] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression");
+			else
+				TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data does not match subsampling tag values [%d,%d] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression",mh,mv);
+		}
+		if (sp->subsampling_force_desubsampling_inside_decompression==0)
+		{
+			if (sp->subsampling_hor<sp->subsampling_ver)
+				TIFFWarningExt(tif->tif_clientdata,module,"Subsampling values [%d,%d] are not allowed in TIFF",sp->subsampling_hor,sp->subsampling_ver);
+		}
+	}
+	sp->subsamplingcorrect_done=1;
+}
+
+static int
+OJPEGReadHeaderInfo(TIFF* tif)
+{
+	static const char module[]="OJPEGReadHeaderInfo";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	assert(sp->readheader_done==0);
+	sp->image_width=tif->tif_dir.td_imagewidth;
+	sp->image_length=tif->tif_dir.td_imagelength;
+	if isTiled(tif)
+	{
+		sp->strile_width=tif->tif_dir.td_tilewidth;
+		sp->strile_length=tif->tif_dir.td_tilelength;
+		sp->strile_length_total=((sp->image_length+sp->strile_length-1)/sp->strile_length)*sp->strile_length;
+	}
+	else
+	{
+		sp->strile_width=sp->image_width;
+		sp->strile_length=tif->tif_dir.td_rowsperstrip;
+		sp->strile_length_total=sp->image_length;
+	}
+	if (tif->tif_dir.td_samplesperpixel==1)
+	{
+		sp->samples_per_pixel=1;
+		sp->plane_sample_offset=0;
+		sp->samples_per_pixel_per_plane=sp->samples_per_pixel;
+		sp->subsampling_hor=1;
+		sp->subsampling_ver=1;
+	}
+	else
+	{
+		if (tif->tif_dir.td_samplesperpixel!=3)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"SamplesPerPixel %d not supported for this compression scheme",sp->samples_per_pixel);
+			return(0);
+		}
+		sp->samples_per_pixel=3;
+		sp->plane_sample_offset=0;
+		if (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)
+			sp->samples_per_pixel_per_plane=3;
+		else
+			sp->samples_per_pixel_per_plane=1;
+	}
+	if (sp->strile_length<sp->image_length)
+	{
+		if (sp->strile_length%(sp->subsampling_ver*8)!=0)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Incompatible vertical subsampling and image strip/tile length");
+			return(0);
+		}
+		sp->restart_interval=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8))*(sp->strile_length/(sp->subsampling_ver*8));
+	}
+	if (OJPEGReadHeaderInfoSec(tif)==0)
+		return(0);
+	sp->sos_end[0].log=1;
+	sp->sos_end[0].in_buffer_source=sp->in_buffer_source;
+	sp->sos_end[0].in_buffer_next_strile=sp->in_buffer_next_strile;
+	sp->sos_end[0].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo;
+	sp->sos_end[0].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; 
+	sp->readheader_done=1;
+	return(1);
+}
+
+static int
+OJPEGReadSecondarySos(TIFF* tif, uint16 s)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 m;
+	assert(s>0);
+	assert(s<3);
+	assert(sp->sos_end[0].log!=0);
+	assert(sp->sos_end[s].log==0);
+	sp->plane_sample_offset=s-1;
+	while(sp->sos_end[sp->plane_sample_offset].log==0)
+		sp->plane_sample_offset--;
+	sp->in_buffer_source=sp->sos_end[sp->plane_sample_offset].in_buffer_source;
+	sp->in_buffer_next_strile=sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile;
+	sp->in_buffer_file_pos=sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos;
+	sp->in_buffer_file_pos_log=0;
+	sp->in_buffer_file_togo=sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo;
+	sp->in_buffer_togo=0;
+	sp->in_buffer_cur=0;
+	while(sp->plane_sample_offset<s)
+	{
+		do
+		{
+			if (OJPEGReadByte(sp,&m)==0)
+				return(0);
+			if (m==255)
+			{
+				do
+				{
+					if (OJPEGReadByte(sp,&m)==0)
+						return(0);
+					if (m!=255)
+						break;
+				} while(1);
+				if (m==JPEG_MARKER_SOS)
+					break;
+			}
+		} while(1);
+		sp->plane_sample_offset++;
+		if (OJPEGReadHeaderInfoSecStreamSos(tif)==0)
+			return(0);
+		sp->sos_end[sp->plane_sample_offset].log=1;
+		sp->sos_end[sp->plane_sample_offset].in_buffer_source=sp->in_buffer_source;
+		sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile=sp->in_buffer_next_strile;
+		sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo;
+		sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo;
+	}
+	return(1);
+}
+
+static int
+OJPEGWriteHeaderInfo(TIFF* tif)
+{
+	static const char module[]="OJPEGWriteHeaderInfo";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8** m;
+	uint32 n;
+	/* if a previous attempt failed, don't try again */
+	if (sp->libjpeg_session_active != 0) 
+		return 0;
+	sp->out_state=ososSoi;
+	sp->restart_index=0;
+	jpeg_std_error(&(sp->libjpeg_jpeg_error_mgr));
+	sp->libjpeg_jpeg_error_mgr.output_message=OJPEGLibjpegJpegErrorMgrOutputMessage;
+	sp->libjpeg_jpeg_error_mgr.error_exit=OJPEGLibjpegJpegErrorMgrErrorExit;
+	sp->libjpeg_jpeg_decompress_struct.err=&(sp->libjpeg_jpeg_error_mgr);
+	sp->libjpeg_jpeg_decompress_struct.client_data=(void*)tif;
+	if (jpeg_create_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0)
+		return(0);
+	sp->libjpeg_session_active=1;
+	sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=0;
+	sp->libjpeg_jpeg_source_mgr.init_source=OJPEGLibjpegJpegSourceMgrInitSource;
+	sp->libjpeg_jpeg_source_mgr.fill_input_buffer=OJPEGLibjpegJpegSourceMgrFillInputBuffer;
+	sp->libjpeg_jpeg_source_mgr.skip_input_data=OJPEGLibjpegJpegSourceMgrSkipInputData;
+	sp->libjpeg_jpeg_source_mgr.resync_to_restart=OJPEGLibjpegJpegSourceMgrResyncToRestart;
+	sp->libjpeg_jpeg_source_mgr.term_source=OJPEGLibjpegJpegSourceMgrTermSource;
+	sp->libjpeg_jpeg_decompress_struct.src=&(sp->libjpeg_jpeg_source_mgr);
+	if (jpeg_read_header_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),1)==0)
+		return(0);
+	if ((sp->subsampling_force_desubsampling_inside_decompression==0) && (sp->samples_per_pixel_per_plane>1))
+	{
+		sp->libjpeg_jpeg_decompress_struct.raw_data_out=1;
+#if JPEG_LIB_VERSION >= 70
+		sp->libjpeg_jpeg_decompress_struct.do_fancy_upsampling=FALSE;
+#endif
+		sp->libjpeg_jpeg_query_style=0;
+		if (sp->subsampling_convert_log==0)
+		{
+			assert(sp->subsampling_convert_ycbcrbuf==0);
+			assert(sp->subsampling_convert_ycbcrimage==0);
+			sp->subsampling_convert_ylinelen=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8)*sp->subsampling_hor*8);
+			sp->subsampling_convert_ylines=sp->subsampling_ver*8;
+			sp->subsampling_convert_clinelen=sp->subsampling_convert_ylinelen/sp->subsampling_hor;
+			sp->subsampling_convert_clines=8;
+			sp->subsampling_convert_ybuflen=sp->subsampling_convert_ylinelen*sp->subsampling_convert_ylines;
+			sp->subsampling_convert_cbuflen=sp->subsampling_convert_clinelen*sp->subsampling_convert_clines;
+			sp->subsampling_convert_ycbcrbuflen=sp->subsampling_convert_ybuflen+2*sp->subsampling_convert_cbuflen;
+			sp->subsampling_convert_ycbcrbuf = (uint8*)_TIFFmalloc(sp->subsampling_convert_ycbcrbuflen);	// add (uint8*) cast
+			if (sp->subsampling_convert_ycbcrbuf==0)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+				return(0);
+			}
+			sp->subsampling_convert_ybuf=sp->subsampling_convert_ycbcrbuf;
+			sp->subsampling_convert_cbbuf=sp->subsampling_convert_ybuf+sp->subsampling_convert_ybuflen;
+			sp->subsampling_convert_crbuf=sp->subsampling_convert_cbbuf+sp->subsampling_convert_cbuflen;
+			sp->subsampling_convert_ycbcrimagelen=3+sp->subsampling_convert_ylines+2*sp->subsampling_convert_clines;
+			sp->subsampling_convert_ycbcrimage = (uint8**)_TIFFmalloc(sp->subsampling_convert_ycbcrimagelen * sizeof(uint8*));// add (uint8**) cast
+			if (sp->subsampling_convert_ycbcrimage==0)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+				return(0);
+			}
+			m=sp->subsampling_convert_ycbcrimage;
+			*m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3);
+			*m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines);
+			*m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines+sp->subsampling_convert_clines);
+			for (n=0; n<sp->subsampling_convert_ylines; n++)
+				*m++=sp->subsampling_convert_ybuf+n*sp->subsampling_convert_ylinelen;
+			for (n=0; n<sp->subsampling_convert_clines; n++)
+				*m++=sp->subsampling_convert_cbbuf+n*sp->subsampling_convert_clinelen;
+			for (n=0; n<sp->subsampling_convert_clines; n++)
+				*m++=sp->subsampling_convert_crbuf+n*sp->subsampling_convert_clinelen;
+			sp->subsampling_convert_clinelenout=((sp->strile_width+sp->subsampling_hor-1)/sp->subsampling_hor);
+			sp->subsampling_convert_state=0;
+			sp->bytes_per_line=sp->subsampling_convert_clinelenout*(sp->subsampling_ver*sp->subsampling_hor+2);
+			sp->lines_per_strile=((sp->strile_length+sp->subsampling_ver-1)/sp->subsampling_ver);
+			sp->subsampling_convert_log=1;
+		}
+	}
+	else
+	{
+		sp->libjpeg_jpeg_decompress_struct.jpeg_color_space=JCS_UNKNOWN;
+		sp->libjpeg_jpeg_decompress_struct.out_color_space=JCS_UNKNOWN;
+		sp->libjpeg_jpeg_query_style=1;
+		sp->bytes_per_line=sp->samples_per_pixel_per_plane*sp->strile_width;
+		sp->lines_per_strile=sp->strile_length;
+	}
+	if (jpeg_start_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0)
+		return(0);
+	sp->writeheader_done=1;
+	return(1);
+}
+
+static void
+OJPEGLibjpegSessionAbort(TIFF* tif)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	assert(sp->libjpeg_session_active!=0);
+	jpeg_destroy((jpeg_common_struct*)(&(sp->libjpeg_jpeg_decompress_struct)));
+	sp->libjpeg_session_active=0;
+}
+
+static int
+OJPEGReadHeaderInfoSec(TIFF* tif)
+{
+	static const char module[]="OJPEGReadHeaderInfoSec";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 m;
+	uint16 n;
+	uint8 o;
+	if (sp->file_size==0)
+		sp->file_size=TIFFGetFileSize(tif);
+	if (sp->jpeg_interchange_format!=0)
+	{
+		if (sp->jpeg_interchange_format>=sp->file_size)
+		{
+			sp->jpeg_interchange_format=0;
+			sp->jpeg_interchange_format_length=0;
+		}
+		else
+		{
+			if ((sp->jpeg_interchange_format_length==0) || (sp->jpeg_interchange_format+sp->jpeg_interchange_format_length>sp->file_size))
+				sp->jpeg_interchange_format_length=sp->file_size-sp->jpeg_interchange_format;
+		}
+	}
+	sp->in_buffer_source=osibsNotSetYet;
+	sp->in_buffer_next_strile=0;
+	sp->in_buffer_strile_count=tif->tif_dir.td_nstrips;
+	sp->in_buffer_file_togo=0;
+	sp->in_buffer_togo=0;
+	do
+	{
+		if (OJPEGReadBytePeek(sp,&m)==0)
+			return(0);
+		if (m!=255)
+			break;
+		OJPEGReadByteAdvance(sp);
+		do
+		{
+			if (OJPEGReadByte(sp,&m)==0)
+				return(0);
+		} while(m==255);
+		switch(m)
+		{
+			case JPEG_MARKER_SOI:
+				/* this type of marker has no data, and should be skipped */
+				break;
+			case JPEG_MARKER_COM:
+			case JPEG_MARKER_APP0:
+			case JPEG_MARKER_APP0+1:
+			case JPEG_MARKER_APP0+2:
+			case JPEG_MARKER_APP0+3:
+			case JPEG_MARKER_APP0+4:
+			case JPEG_MARKER_APP0+5:
+			case JPEG_MARKER_APP0+6:
+			case JPEG_MARKER_APP0+7:
+			case JPEG_MARKER_APP0+8:
+			case JPEG_MARKER_APP0+9:
+			case JPEG_MARKER_APP0+10:
+			case JPEG_MARKER_APP0+11:
+			case JPEG_MARKER_APP0+12:
+			case JPEG_MARKER_APP0+13:
+			case JPEG_MARKER_APP0+14:
+			case JPEG_MARKER_APP0+15:
+				/* this type of marker has data, but it has no use to us (and no place here) and should be skipped */
+				if (OJPEGReadWord(sp,&n)==0)
+					return(0);
+				if (n<2)
+				{
+					if (sp->subsamplingcorrect==0)
+						TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data");
+					return(0);
+				}
+				if (n>2)
+					OJPEGReadSkip(sp,n-2);
+				break;
+			case JPEG_MARKER_DRI:
+				if (OJPEGReadHeaderInfoSecStreamDri(tif)==0)
+					return(0);
+				break;
+			case JPEG_MARKER_DQT:
+				if (OJPEGReadHeaderInfoSecStreamDqt(tif)==0)
+					return(0);
+				break;
+			case JPEG_MARKER_DHT:
+				if (OJPEGReadHeaderInfoSecStreamDht(tif)==0)
+					return(0);
+				break;
+			case JPEG_MARKER_SOF0:
+			case JPEG_MARKER_SOF1:
+			case JPEG_MARKER_SOF3:
+				if (OJPEGReadHeaderInfoSecStreamSof(tif,m)==0)
+					return(0);
+				if (sp->subsamplingcorrect!=0)
+					return(1);
+				break;
+			case JPEG_MARKER_SOS:
+				if (sp->subsamplingcorrect!=0)
+					return(1);
+				assert(sp->plane_sample_offset==0);
+				if (OJPEGReadHeaderInfoSecStreamSos(tif)==0)
+					return(0);
+				break;
+			default:
+				TIFFErrorExt(tif->tif_clientdata,module,"Unknown marker type %d in JPEG data",m);
+				return(0);
+		}
+	} while(m!=JPEG_MARKER_SOS);
+	if (sp->subsamplingcorrect)
+		return(1);
+	if (sp->sof_log==0)
+	{
+		if (OJPEGReadHeaderInfoSecTablesQTable(tif)==0)
+			return(0);
+		sp->sof_marker_id=JPEG_MARKER_SOF0;
+		for (o=0; o<sp->samples_per_pixel; o++)
+			sp->sof_c[o]=o;
+		sp->sof_hv[0]=((sp->subsampling_hor<<4)|sp->subsampling_ver);
+		for (o=1; o<sp->samples_per_pixel; o++)
+			sp->sof_hv[o]=17;
+		sp->sof_x=sp->strile_width;
+		sp->sof_y=sp->strile_length_total;
+		sp->sof_log=1;
+		if (OJPEGReadHeaderInfoSecTablesDcTable(tif)==0)
+			return(0);
+		if (OJPEGReadHeaderInfoSecTablesAcTable(tif)==0)
+			return(0);
+		for (o=1; o<sp->samples_per_pixel; o++)
+			sp->sos_cs[o]=o;
+	}
+	return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamDri(TIFF* tif)
+{
+	/* this could easilly cause trouble in some cases... but no such cases have occured sofar */
+	static const char module[]="OJPEGReadHeaderInfoSecStreamDri";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint16 m;
+	if (OJPEGReadWord(sp,&m)==0)
+		return(0);
+	if (m!=4)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DRI marker in JPEG data");
+		return(0);
+	}
+	if (OJPEGReadWord(sp,&m)==0)
+		return(0);
+	sp->restart_interval=m;
+	return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif)
+{
+	/* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */
+	static const char module[]="OJPEGReadHeaderInfoSecStreamDqt";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint16 m;
+	uint32 na;
+	uint8* nb;
+	uint8 o;
+	if (OJPEGReadWord(sp,&m)==0)
+		return(0);
+	if (m<=2)
+	{
+		if (sp->subsamplingcorrect==0)
+			TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data");
+		return(0);
+	}
+	if (sp->subsamplingcorrect!=0)
+		OJPEGReadSkip(sp,m-2);
+	else
+	{
+		m-=2;
+		do
+		{
+			if (m<65)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data");
+				return(0);
+			}
+			na = sizeof(uint32) + 69;
+			nb = (uint8*)_TIFFmalloc(na);	// add (uint8*) cast
+			if (nb == 0)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+				return(0);
+			}
+			*(uint32*)nb=na;
+			nb[sizeof(uint32)]=255;
+			nb[sizeof(uint32)+1]=JPEG_MARKER_DQT;
+			nb[sizeof(uint32)+2]=0;
+			nb[sizeof(uint32)+3]=67;
+			if (OJPEGReadBlock(sp,65,&nb[sizeof(uint32)+4])==0) {
+				_TIFFfree(nb);
+				return(0);
+			}
+			o=nb[sizeof(uint32)+4]&15;
+			if (3<o)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data");
+				_TIFFfree(nb);
+				return(0);
+			}
+			if (sp->qtable[o]!=0)
+				_TIFFfree(sp->qtable[o]);
+			sp->qtable[o]=nb;
+			m-=65;
+		} while(m>0);
+	}
+	return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamDht(TIFF* tif)
+{
+	/* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */
+	/* TODO: the following assumes there is only one table in this marker... but i'm not quite sure that assumption is guaranteed correct */
+	static const char module[]="OJPEGReadHeaderInfoSecStreamDht";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint16 m;
+	uint32 na;
+	uint8* nb;
+	uint8 o;
+	if (OJPEGReadWord(sp,&m)==0)
+		return(0);
+	if (m<=2)
+	{
+		if (sp->subsamplingcorrect==0)
+			TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+		return(0);
+	}
+	if (sp->subsamplingcorrect!=0)
+	{
+		OJPEGReadSkip(sp,m-2);
+	}
+	else
+	{
+		na = sizeof(uint32) + 2 + m;
+		nb = (uint8*)_TIFFmalloc(na);	// add (uint8*) cast
+		if (nb == 0)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			return(0);
+		}
+		*(uint32*)nb=na;
+		nb[sizeof(uint32)]=255;
+		nb[sizeof(uint32)+1]=JPEG_MARKER_DHT;
+		nb[sizeof(uint32)+2]=(m>>8);
+		nb[sizeof(uint32)+3]=(m&255);
+		if (OJPEGReadBlock(sp,m-2,&nb[sizeof(uint32)+4])==0)
+			return(0);
+		o=nb[sizeof(uint32)+4];
+		if ((o&240)==0)
+		{
+			if (3<o)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+				return(0);
+			}
+			if (sp->dctable[o]!=0)
+				_TIFFfree(sp->dctable[o]);
+			sp->dctable[o]=nb;
+		}
+		else
+		{
+			if ((o&240)!=16)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+				return(0);
+			}
+			o&=15;
+			if (3<o)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+				return(0);
+			}
+			if (sp->actable[o]!=0)
+				_TIFFfree(sp->actable[o]);
+			sp->actable[o]=nb;
+		}
+	}
+	return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id)
+{
+	/* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */
+	static const char module[]="OJPEGReadHeaderInfoSecStreamSof";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint16 m;
+	uint16 n;
+	uint8 o;
+	uint16 p;
+	uint16 q;
+	if (sp->sof_log!=0)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data");
+		return(0);
+	}
+	if (sp->subsamplingcorrect==0)
+		sp->sof_marker_id=marker_id;
+	/* Lf: data length */
+	if (OJPEGReadWord(sp,&m)==0)
+		return(0);
+	if (m<11)
+	{
+		if (sp->subsamplingcorrect==0)
+			TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data");
+		return(0);
+	}
+	m-=8;
+	if (m%3!=0)
+	{
+		if (sp->subsamplingcorrect==0)
+			TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data");
+		return(0);
+	}
+	n=m/3;
+	if (sp->subsamplingcorrect==0)
+	{
+		if (n!=sp->samples_per_pixel)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of samples");
+			return(0);
+		}
+	}
+	/* P: Sample precision */
+	if (OJPEGReadByte(sp,&o)==0)
+		return(0);
+	if (o!=8)
+	{
+		if (sp->subsamplingcorrect==0)
+			TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of bits per sample");
+		return(0);
+	}
+	/* Y: Number of lines, X: Number of samples per line */
+	if (sp->subsamplingcorrect)
+		OJPEGReadSkip(sp,4);
+	else
+	{
+		/* Y: Number of lines */
+		if (OJPEGReadWord(sp,&p)==0)
+			return(0);
+		if (((uint32)p<sp->image_length) && ((uint32)p<sp->strile_length_total))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected height");
+			return(0);
+		}
+		sp->sof_y=p;
+		/* X: Number of samples per line */
+		if (OJPEGReadWord(sp,&p)==0)
+			return(0);
+		if (((uint32)p<sp->image_width) && ((uint32)p<sp->strile_width))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected width");
+			return(0);
+		}
+		if ((uint32)p>sp->strile_width)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data image width exceeds expected image width");
+			return(0);
+		}
+		sp->sof_x=p;
+	}
+	/* Nf: Number of image components in frame */
+	if (OJPEGReadByte(sp,&o)==0)
+		return(0);
+	if (o!=n)
+	{
+		if (sp->subsamplingcorrect==0)
+			TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data");
+		return(0);
+	}
+	/* per component stuff */
+	/* TODO: double-check that flow implies that n cannot be as big as to make us overflow sof_c, sof_hv and sof_tq arrays */
+	for (q=0; q<n; q++)
+	{
+		/* C: Component identifier */
+		if (OJPEGReadByte(sp,&o)==0)
+			return(0);
+		if (sp->subsamplingcorrect==0)
+			sp->sof_c[q]=o;
+		/* H: Horizontal sampling factor, and V: Vertical sampling factor */
+		if (OJPEGReadByte(sp,&o)==0)
+			return(0);
+		if (sp->subsamplingcorrect!=0)
+		{
+			if (q==0)
+			{
+				sp->subsampling_hor=(o>>4);
+				sp->subsampling_ver=(o&15);
+				if (((sp->subsampling_hor!=1) && (sp->subsampling_hor!=2) && (sp->subsampling_hor!=4)) ||
+					((sp->subsampling_ver!=1) && (sp->subsampling_ver!=2) && (sp->subsampling_ver!=4)))
+					sp->subsampling_force_desubsampling_inside_decompression=1;
+			}
+			else
+			{
+				if (o!=17)
+					sp->subsampling_force_desubsampling_inside_decompression=1;
+			}
+		}
+		else
+		{
+			sp->sof_hv[q]=o;
+			if (sp->subsampling_force_desubsampling_inside_decompression==0)
+			{
+				if (q==0)
+				{
+					if (o!=((sp->subsampling_hor<<4)|sp->subsampling_ver))
+					{
+						TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values");
+						return(0);
+					}
+				}
+				else
+				{
+					if (o!=17)
+					{
+						TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values");
+						return(0);
+					}
+				}
+			}
+		}
+		/* Tq: Quantization table destination selector */
+		if (OJPEGReadByte(sp,&o)==0)
+			return(0);
+		if (sp->subsamplingcorrect==0)
+			sp->sof_tq[q]=o;
+	}
+	if (sp->subsamplingcorrect==0)
+		sp->sof_log=1;
+	return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamSos(TIFF* tif)
+{
+	/* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */
+	static const char module[]="OJPEGReadHeaderInfoSecStreamSos";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint16 m;
+	uint8 n;
+	uint8 o;
+	assert(sp->subsamplingcorrect==0);
+	if (sp->sof_log==0)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data");
+		return(0);
+	}
+	/* Ls */
+	if (OJPEGReadWord(sp,&m)==0)
+		return(0);
+	if (m!=6+sp->samples_per_pixel_per_plane*2)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data");
+		return(0);
+	}
+	/* Ns */
+	if (OJPEGReadByte(sp,&n)==0)
+		return(0);
+	if (n!=sp->samples_per_pixel_per_plane)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data");
+		return(0);
+	}
+	/* Cs, Td, and Ta */
+	for (o=0; o<sp->samples_per_pixel_per_plane; o++)
+	{
+		/* Cs */
+		if (OJPEGReadByte(sp,&n)==0)
+			return(0);
+		sp->sos_cs[sp->plane_sample_offset+o]=n;
+		/* Td and Ta */
+		if (OJPEGReadByte(sp,&n)==0)
+			return(0);
+		sp->sos_tda[sp->plane_sample_offset+o]=n;
+	}
+	/* skip Ss, Se, Ah, en Al -> no check, as per Tom Lane recommendation, as per LibJpeg source */
+	OJPEGReadSkip(sp,3);
+	return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif)
+{
+	static const char module[]="OJPEGReadHeaderInfoSecTablesQTable";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 m;
+	uint8 n;
+	uint32 oa;
+	uint8* ob;
+	uint32 p;
+	if (sp->qtable_offset[0]==0)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables");
+		return(0);
+	}
+	sp->in_buffer_file_pos_log=0;
+	for (m=0; m<sp->samples_per_pixel; m++)
+	{
+		if ((sp->qtable_offset[m]!=0) && ((m==0) || (sp->qtable_offset[m]!=sp->qtable_offset[m-1])))
+		{
+			for (n=0; n<m-1; n++)
+			{
+				if (sp->qtable_offset[m]==sp->qtable_offset[n])
+				{
+					TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegQTables tag value");
+					return(0);
+				}
+			}
+			oa=sizeof(uint32)+69;
+			ob = (uint8*)_TIFFmalloc(oa);	// add (uint8*) cast
+			if (ob==0)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+				return(0);
+			}
+			*(uint32*)ob=oa;
+			ob[sizeof(uint32)]=255;
+			ob[sizeof(uint32)+1]=JPEG_MARKER_DQT;
+			ob[sizeof(uint32)+2]=0;
+			ob[sizeof(uint32)+3]=67;
+			ob[sizeof(uint32)+4]=m;
+			TIFFSeekFile(tif,sp->qtable_offset[m],SEEK_SET); 
+			p=(uint32)TIFFReadFile(tif,&ob[sizeof(uint32)+5],64);
+			if (p!=64)
+				return(0);
+			sp->qtable[m]=ob;
+			sp->sof_tq[m]=m;
+		}
+		else
+			sp->sof_tq[m]=sp->sof_tq[m-1];
+	}
+	return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif)
+{
+	static const char module[]="OJPEGReadHeaderInfoSecTablesDcTable";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 m;
+	uint8 n;
+	uint8 o[16];
+	uint32 p;
+	uint32 q;
+	uint32 ra;
+	uint8* rb;
+	if (sp->dctable_offset[0]==0)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables");
+		return(0);
+	}
+	sp->in_buffer_file_pos_log=0;
+	for (m=0; m<sp->samples_per_pixel; m++)
+	{
+		if ((sp->dctable_offset[m]!=0) && ((m==0) || (sp->dctable_offset[m]!=sp->dctable_offset[m-1])))
+		{
+			for (n=0; n<m-1; n++)
+			{
+				if (sp->dctable_offset[m]==sp->dctable_offset[n])
+				{
+					TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegDcTables tag value");
+					return(0);
+				}
+			}
+			TIFFSeekFile(tif,sp->dctable_offset[m],SEEK_SET);
+			p=(uint32)TIFFReadFile(tif,o,16);
+			if (p!=16)
+				return(0);
+			q=0;
+			for (n=0; n<16; n++)
+				q+=o[n];
+			ra=sizeof(uint32)+21+q;
+			rb = (uint8*)_TIFFmalloc(ra);	// add (uint8*) cast
+			if (rb==0)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+				return(0);
+			}
+			*(uint32*)rb=ra;
+			rb[sizeof(uint32)]=255;
+			rb[sizeof(uint32)+1]=JPEG_MARKER_DHT;
+			rb[sizeof(uint32)+2]=((19+q)>>8);
+			rb[sizeof(uint32)+3]=((19+q)&255);
+			rb[sizeof(uint32)+4]=m;
+			for (n=0; n<16; n++)
+				rb[sizeof(uint32)+5+n]=o[n];
+			p=(uint32)TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q);
+			if (p!=q)
+				return(0);
+			sp->dctable[m]=rb;
+			sp->sos_tda[m]=(m<<4);
+		}
+		else
+			sp->sos_tda[m]=sp->sos_tda[m-1];
+	}
+	return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif)
+{
+	static const char module[]="OJPEGReadHeaderInfoSecTablesAcTable";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 m;
+	uint8 n;
+	uint8 o[16];
+	uint32 p;
+	uint32 q;
+	uint32 ra;
+	uint8* rb;
+	if (sp->actable_offset[0]==0)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables");
+		return(0);
+	}
+	sp->in_buffer_file_pos_log=0;
+	for (m=0; m<sp->samples_per_pixel; m++)
+	{
+		if ((sp->actable_offset[m]!=0) && ((m==0) || (sp->actable_offset[m]!=sp->actable_offset[m-1])))
+		{
+			for (n=0; n<m-1; n++)
+			{
+				if (sp->actable_offset[m]==sp->actable_offset[n])
+				{
+					TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegAcTables tag value");
+					return(0);
+				}
+			}
+			TIFFSeekFile(tif,sp->actable_offset[m],SEEK_SET);  
+			p=(uint32)TIFFReadFile(tif,o,16);
+			if (p!=16)
+				return(0);
+			q=0;
+			for (n=0; n<16; n++)
+				q+=o[n];
+			ra=sizeof(uint32)+21+q;
+			rb = (uint8*)_TIFFmalloc(ra);	// add (uint8*) cast
+			if (rb==0)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+				return(0);
+			}
+			*(uint32*)rb=ra;
+			rb[sizeof(uint32)]=255;
+			rb[sizeof(uint32)+1]=JPEG_MARKER_DHT;
+			rb[sizeof(uint32)+2]=((19+q)>>8);
+			rb[sizeof(uint32)+3]=((19+q)&255);
+			rb[sizeof(uint32)+4]=(16|m);
+			for (n=0; n<16; n++)
+				rb[sizeof(uint32)+5+n]=o[n];
+			p=(uint32)TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q);
+			if (p!=q)
+				return(0);
+			sp->actable[m]=rb;
+			sp->sos_tda[m]=(sp->sos_tda[m]|m);
+		}
+		else
+			sp->sos_tda[m]=(sp->sos_tda[m]|(sp->sos_tda[m-1]&15));
+	}
+	return(1);
+}
+
+static int
+OJPEGReadBufferFill(OJPEGState* sp)
+{
+	uint16 m;
+	tmsize_t n;
+	/* TODO: double-check: when subsamplingcorrect is set, no call to TIFFErrorExt or TIFFWarningExt should be made
+	 * in any other case, seek or read errors should be passed through */
+	do
+	{
+		if (sp->in_buffer_file_togo!=0)
+		{
+			if (sp->in_buffer_file_pos_log==0)
+			{
+				TIFFSeekFile(sp->tif,sp->in_buffer_file_pos,SEEK_SET);
+				sp->in_buffer_file_pos_log=1;
+			}
+			m=OJPEG_BUFFER;
+			if ((uint64)m>sp->in_buffer_file_togo)
+				m=(uint16)sp->in_buffer_file_togo;
+			n=TIFFReadFile(sp->tif,sp->in_buffer,(tmsize_t)m);
+			if (n==0)
+				return(0);
+			assert(n>0);
+			assert(n<=OJPEG_BUFFER);
+			assert(n<65536);
+			assert((uint64)n<=sp->in_buffer_file_togo);
+			m=(uint16)n;
+			sp->in_buffer_togo=m;
+			sp->in_buffer_cur=sp->in_buffer;
+			sp->in_buffer_file_togo-=m;
+			sp->in_buffer_file_pos+=m;
+			break;
+		}
+		sp->in_buffer_file_pos_log=0;
+		switch(sp->in_buffer_source)
+		{
+			case osibsNotSetYet:
+				if (sp->jpeg_interchange_format!=0)
+				{
+					sp->in_buffer_file_pos=sp->jpeg_interchange_format;
+					sp->in_buffer_file_togo=sp->jpeg_interchange_format_length;
+				}
+				sp->in_buffer_source=osibsJpegInterchangeFormat;
+				break;
+			case osibsJpegInterchangeFormat:
+				sp->in_buffer_source=osibsStrile;
+			case osibsStrile:
+				if (!_TIFFFillStriles( sp->tif ) 
+				    || sp->tif->tif_dir.td_stripoffset == NULL
+				    || sp->tif->tif_dir.td_stripbytecount == NULL)
+					return 0;
+
+				if (sp->in_buffer_next_strile==sp->in_buffer_strile_count)
+					sp->in_buffer_source=osibsEof;
+				else
+				{
+					sp->in_buffer_file_pos=sp->tif->tif_dir.td_stripoffset[sp->in_buffer_next_strile];
+					if (sp->in_buffer_file_pos!=0)
+					{
+						if (sp->in_buffer_file_pos>=sp->file_size)
+							sp->in_buffer_file_pos=0;
+						else if (sp->tif->tif_dir.td_stripbytecount==NULL)
+							sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos;
+						else
+						{
+							if (sp->tif->tif_dir.td_stripbytecount == 0) {
+								TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip byte counts are missing");
+								return(0);
+							}
+							sp->in_buffer_file_togo=sp->tif->tif_dir.td_stripbytecount[sp->in_buffer_next_strile];
+							if (sp->in_buffer_file_togo==0)
+								sp->in_buffer_file_pos=0;
+							else if (sp->in_buffer_file_pos+sp->in_buffer_file_togo>sp->file_size)
+								sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos;
+						}
+					}
+					sp->in_buffer_next_strile++;
+				}
+				break;
+			default:
+				return(0);
+		}
+	} while (1);
+	return(1);
+}
+
+static int
+OJPEGReadByte(OJPEGState* sp, uint8* byte)
+{
+	if (sp->in_buffer_togo==0)
+	{
+		if (OJPEGReadBufferFill(sp)==0)
+			return(0);
+		assert(sp->in_buffer_togo>0);
+	}
+	*byte=*(sp->in_buffer_cur);
+	sp->in_buffer_cur++;
+	sp->in_buffer_togo--;
+	return(1);
+}
+
+static int
+OJPEGReadBytePeek(OJPEGState* sp, uint8* byte)
+{
+	if (sp->in_buffer_togo==0)
+	{
+		if (OJPEGReadBufferFill(sp)==0)
+			return(0);
+		assert(sp->in_buffer_togo>0);
+	}
+	*byte=*(sp->in_buffer_cur);
+	return(1);
+}
+
+static void
+OJPEGReadByteAdvance(OJPEGState* sp)
+{
+	assert(sp->in_buffer_togo>0);
+	sp->in_buffer_cur++;
+	sp->in_buffer_togo--;
+}
+
+static int
+OJPEGReadWord(OJPEGState* sp, uint16* word)
+{
+	uint8 m;
+	if (OJPEGReadByte(sp,&m)==0)
+		return(0);
+	*word=(m<<8);
+	if (OJPEGReadByte(sp,&m)==0)
+		return(0);
+	*word|=m;
+	return(1);
+}
+
+static int
+OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem)
+{
+	uint16 mlen;
+	uint8* mmem;
+	uint16 n;
+	assert(len>0);
+	mlen=len;
+	mmem = (uint8*)mem;		// add (uint8*) cast
+	do
+	{
+		if (sp->in_buffer_togo==0)
+		{
+			if (OJPEGReadBufferFill(sp)==0)
+				return(0);
+			assert(sp->in_buffer_togo>0);
+		}
+		n=mlen;
+		if (n>sp->in_buffer_togo)
+			n=sp->in_buffer_togo;
+		_TIFFmemcpy(mmem,sp->in_buffer_cur,n);
+		sp->in_buffer_cur+=n;
+		sp->in_buffer_togo-=n;
+		mlen-=n;
+		mmem+=n;
+	} while(mlen>0);
+	return(1);
+}
+
+static void
+OJPEGReadSkip(OJPEGState* sp, uint16 len)
+{
+	uint16 m;
+	uint16 n;
+	m=len;
+	n=m;
+	if (n>sp->in_buffer_togo)
+		n=sp->in_buffer_togo;
+	sp->in_buffer_cur+=n;
+	sp->in_buffer_togo-=n;
+	m-=n;
+	if (m>0)
+	{
+		assert(sp->in_buffer_togo==0);
+		n=m;
+		if ((uint64)n>sp->in_buffer_file_togo)
+			n=(uint16)sp->in_buffer_file_togo;
+		sp->in_buffer_file_pos+=n;
+		sp->in_buffer_file_togo-=n;
+		sp->in_buffer_file_pos_log=0;
+		/* we don't skip past jpeginterchangeformat/strile block...
+		 * if that is asked from us, we're dealing with totally bazurk
+		 * data anyway, and we've not seen this happening on any
+		 * testfile, so we might as well likely cause some other
+		 * meaningless error to be passed at some later time
+		 */
+	}
+}
+
+static int
+OJPEGWriteStream(TIFF* tif, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	*len=0;
+	do
+	{
+		assert(sp->out_state<=ososEoi);
+		switch(sp->out_state)
+		{
+			case ososSoi:
+				OJPEGWriteStreamSoi(tif,mem,len);
+				break;
+			case ososQTable0:
+				OJPEGWriteStreamQTable(tif,0,mem,len);
+				break;
+			case ososQTable1:
+				OJPEGWriteStreamQTable(tif,1,mem,len);
+				break;
+			case ososQTable2:
+				OJPEGWriteStreamQTable(tif,2,mem,len);
+				break;
+			case ososQTable3:
+				OJPEGWriteStreamQTable(tif,3,mem,len);
+				break;
+			case ososDcTable0:
+				OJPEGWriteStreamDcTable(tif,0,mem,len);
+				break;
+			case ososDcTable1:
+				OJPEGWriteStreamDcTable(tif,1,mem,len);
+				break;
+			case ososDcTable2:
+				OJPEGWriteStreamDcTable(tif,2,mem,len);
+				break;
+			case ososDcTable3:
+				OJPEGWriteStreamDcTable(tif,3,mem,len);
+				break;
+			case ososAcTable0:
+				OJPEGWriteStreamAcTable(tif,0,mem,len);
+				break;
+			case ososAcTable1:
+				OJPEGWriteStreamAcTable(tif,1,mem,len);
+				break;
+			case ososAcTable2:
+				OJPEGWriteStreamAcTable(tif,2,mem,len);
+				break;
+			case ososAcTable3:
+				OJPEGWriteStreamAcTable(tif,3,mem,len);
+				break;
+			case ososDri:
+				OJPEGWriteStreamDri(tif,mem,len);
+				break;
+			case ososSof:
+				OJPEGWriteStreamSof(tif,mem,len);
+				break;
+			case ososSos:
+				OJPEGWriteStreamSos(tif,mem,len);
+				break;
+			case ososCompressed:
+				if (OJPEGWriteStreamCompressed(tif,mem,len)==0)
+					return(0);
+				break;
+			case ososRst:
+				OJPEGWriteStreamRst(tif,mem,len);
+				break;
+			case ososEoi:
+				OJPEGWriteStreamEoi(tif,mem,len);
+				break;
+		}
+	} while (*len==0);
+	return(1);
+}
+
+static void
+OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	assert(OJPEG_BUFFER>=2);
+	sp->out_buffer[0]=255;
+	sp->out_buffer[1]=JPEG_MARKER_SOI;
+	*len=2;
+	*mem=(void*)sp->out_buffer;
+	sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	if (sp->qtable[table_index]!=0)
+	{
+		*mem=(void*)(sp->qtable[table_index]+sizeof(uint32));
+		*len=*((uint32*)sp->qtable[table_index])-sizeof(uint32);
+	}
+	sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	if (sp->dctable[table_index]!=0)
+	{
+		*mem=(void*)(sp->dctable[table_index]+sizeof(uint32));
+		*len=*((uint32*)sp->dctable[table_index])-sizeof(uint32);
+	}
+	sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	if (sp->actable[table_index]!=0)
+	{
+		*mem=(void*)(sp->actable[table_index]+sizeof(uint32));
+		*len=*((uint32*)sp->actable[table_index])-sizeof(uint32);
+	}
+	sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	assert(OJPEG_BUFFER>=6);
+	if (sp->restart_interval!=0)
+	{
+		sp->out_buffer[0]=255;
+		sp->out_buffer[1]=JPEG_MARKER_DRI;
+		sp->out_buffer[2]=0;
+		sp->out_buffer[3]=4;
+		sp->out_buffer[4]=(sp->restart_interval>>8);
+		sp->out_buffer[5]=(sp->restart_interval&255);
+		*len=6;
+		*mem=(void*)sp->out_buffer;
+	}
+	sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 m;
+	assert(OJPEG_BUFFER>=2+8+sp->samples_per_pixel_per_plane*3);
+	assert(255>=8+sp->samples_per_pixel_per_plane*3);
+	sp->out_buffer[0]=255;
+	sp->out_buffer[1]=sp->sof_marker_id;
+	/* Lf */
+	sp->out_buffer[2]=0;
+	sp->out_buffer[3]=8+sp->samples_per_pixel_per_plane*3;
+	/* P */
+	sp->out_buffer[4]=8;
+	/* Y */
+	sp->out_buffer[5]=(sp->sof_y>>8);
+	sp->out_buffer[6]=(sp->sof_y&255);
+	/* X */
+	sp->out_buffer[7]=(sp->sof_x>>8);
+	sp->out_buffer[8]=(sp->sof_x&255);
+	/* Nf */
+	sp->out_buffer[9]=sp->samples_per_pixel_per_plane;
+	for (m=0; m<sp->samples_per_pixel_per_plane; m++)
+	{
+		/* C */
+		sp->out_buffer[10+m*3]=sp->sof_c[sp->plane_sample_offset+m];
+		/* H and V */
+		sp->out_buffer[10+m*3+1]=sp->sof_hv[sp->plane_sample_offset+m];
+		/* Tq */
+		sp->out_buffer[10+m*3+2]=sp->sof_tq[sp->plane_sample_offset+m];
+	}
+	*len=10+sp->samples_per_pixel_per_plane*3;
+	*mem=(void*)sp->out_buffer;
+	sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 m;
+	assert(OJPEG_BUFFER>=2+6+sp->samples_per_pixel_per_plane*2);
+	assert(255>=6+sp->samples_per_pixel_per_plane*2);
+	sp->out_buffer[0]=255;
+	sp->out_buffer[1]=JPEG_MARKER_SOS;
+	/* Ls */
+	sp->out_buffer[2]=0;
+	sp->out_buffer[3]=6+sp->samples_per_pixel_per_plane*2;
+	/* Ns */
+	sp->out_buffer[4]=sp->samples_per_pixel_per_plane;
+	for (m=0; m<sp->samples_per_pixel_per_plane; m++)
+	{
+		/* Cs */
+		sp->out_buffer[5+m*2]=sp->sos_cs[sp->plane_sample_offset+m];
+		/* Td and Ta */
+		sp->out_buffer[5+m*2+1]=sp->sos_tda[sp->plane_sample_offset+m];
+	}
+	/* Ss */
+	sp->out_buffer[5+sp->samples_per_pixel_per_plane*2]=0;
+	/* Se */
+	sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+1]=63;
+	/* Ah and Al */
+	sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+2]=0;
+	*len=8+sp->samples_per_pixel_per_plane*2;
+	*mem=(void*)sp->out_buffer;
+	sp->out_state++;
+}
+
+static int
+OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	if (sp->in_buffer_togo==0)
+	{
+		if (OJPEGReadBufferFill(sp)==0)
+			return(0);
+		assert(sp->in_buffer_togo>0);
+	}
+	*len=sp->in_buffer_togo;
+	*mem=(void*)sp->in_buffer_cur;
+	sp->in_buffer_togo=0;
+	if (sp->in_buffer_file_togo==0)
+	{
+		switch(sp->in_buffer_source)
+		{
+			case osibsStrile:
+				if (sp->in_buffer_next_strile<sp->in_buffer_strile_count)
+					sp->out_state=ososRst;
+				else
+					sp->out_state=ososEoi;
+				break;
+			case osibsEof:
+				sp->out_state=ososEoi;
+				break;
+			default:
+				break;
+		}
+	}
+	return(1);
+}
+
+static void
+OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	assert(OJPEG_BUFFER>=2);
+	sp->out_buffer[0]=255;
+	sp->out_buffer[1]=JPEG_MARKER_RST0+sp->restart_index;
+	sp->restart_index++;
+	if (sp->restart_index==8)
+		sp->restart_index=0;
+	*len=2;
+	*mem=(void*)sp->out_buffer;
+	sp->out_state=ososCompressed;
+}
+
+static void
+OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	assert(OJPEG_BUFFER>=2);
+	sp->out_buffer[0]=255;
+	sp->out_buffer[1]=JPEG_MARKER_EOI;
+	*len=2;
+	*mem=(void*)sp->out_buffer;
+}
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_create_decompress(cinfo),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_header(cinfo,require_image),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_start_decompress(cinfo),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_scanlines(cinfo,scanlines,max_lines),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_raw_data(cinfo,data,max_lines),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static void
+jpeg_encap_unwind(TIFF* tif)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	LONGJMP(sp->exit_jmpbuf,1);
+}
+#endif
+
+static void
+OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo)
+{
+	char buffer[JMSG_LENGTH_MAX];
+	(*cinfo->err->format_message)(cinfo,buffer);
+	TIFFWarningExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg","%s",buffer);
+}
+
+static void
+OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo)
+{
+	char buffer[JMSG_LENGTH_MAX];
+	(*cinfo->err->format_message)(cinfo,buffer);
+	TIFFErrorExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg","%s",buffer);
+	jpeg_encap_unwind((TIFF*)(cinfo->client_data));
+}
+
+static void
+OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo)
+{
+	(void)cinfo;
+}
+
+static boolean
+OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo)
+{
+	TIFF* tif=(TIFF*)cinfo->client_data;
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	void* mem=0;
+	uint32 len=0U;
+	if (OJPEGWriteStream(tif,&mem,&len)==0)
+	{
+		TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Premature end of JPEG data");
+		jpeg_encap_unwind(tif);
+	}
+	sp->libjpeg_jpeg_source_mgr.bytes_in_buffer = len;
+	sp->libjpeg_jpeg_source_mgr.next_input_byte = (const JOCTET * )mem;		// add (const JOCTET * ) cast
+	return(1);
+}
+
+static void
+OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes)
+{
+	TIFF* tif=(TIFF*)cinfo->client_data;
+	(void)num_bytes;
+	TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error");
+	jpeg_encap_unwind(tif);
+}
+
+static boolean
+OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired)
+{
+	TIFF* tif=(TIFF*)cinfo->client_data;
+	(void)desired;
+	TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error");
+	jpeg_encap_unwind(tif);
+	return(0);
+}
+
+static void
+OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo)
+{
+	(void)cinfo;
+}
+
+#endif
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif//#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_open.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_open.c
new file mode 100644
index 0000000..95e8d1f
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_open.c
@@ -0,0 +1,728 @@
+/* $Id: tif_open.c,v 1.46 2010-12-06 16:54:54 faxguy Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+/*
+ * Dummy functions to fill the omitted client procedures.
+ */
+static int
+_tiffDummyMapProc(thandle_t fd, void** pbase, toff_t* psize)
+{
+	(void) fd; (void) pbase; (void) psize;
+	return (0);
+}
+
+static void
+_tiffDummyUnmapProc(thandle_t fd, void* base, toff_t size)
+{
+	(void) fd; (void) base; (void) size;
+}
+
+int
+_TIFFgetMode(const char* mode, const char* module)
+{
+	int m = -1;
+
+	switch (mode[0]) {
+	case 'r':
+		m = O_RDONLY;
+		if (mode[1] == '+')
+			m = O_RDWR;
+		break;
+	case 'w':
+	case 'a':
+		m = O_RDWR|O_CREAT;
+		if (mode[0] == 'w')
+			m |= O_TRUNC;
+		break;
+	default:
+		TIFFErrorExt(0, module, "\"%s\": Bad mode", mode);
+		break;
+	}
+	return (m);
+}
+
+TIFF*
+TIFFClientOpen(
+	const char* name, const char* mode,
+	thandle_t clientdata,
+	TIFFReadWriteProc readproc,
+	TIFFReadWriteProc writeproc,
+	TIFFSeekProc seekproc,
+	TIFFCloseProc closeproc,
+	TIFFSizeProc sizeproc,
+	TIFFMapFileProc mapproc,
+	TIFFUnmapFileProc unmapproc
+)
+{
+	static const char module[] = "TIFFClientOpen";
+	TIFF *tif;
+	int m;
+	const char* cp;
+
+	/* The following are configuration checks. They should be redundant, but should not
+	 * compile to any actual code in an optimised release build anyway. If any of them
+	 * fail, (makefile-based or other) configuration is not correct */
+	assert(sizeof(uint8)==1);
+	assert(sizeof(int8)==1);
+	assert(sizeof(uint16)==2);
+	assert(sizeof(int16)==2);
+	assert(sizeof(uint32)==4);
+	assert(sizeof(int32)==4);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(int64)==8);
+	assert(sizeof(tmsize_t)==sizeof(void*));
+	{
+		union{
+			uint8 a8[2];
+			uint16 a16;
+		} n;
+		n.a8[0]=1;
+		n.a8[1]=0;
+		#ifdef WORDS_BIGENDIAN
+		assert(n.a16==256);
+		#else
+		assert(n.a16==1);
+		#endif
+	}
+
+	m = _TIFFgetMode(mode, module);
+	if (m == -1)
+		goto bad2;
+	tif = (TIFF *)_TIFFmalloc((tmsize_t)(sizeof (TIFF) + strlen(name) + 1));
+	if (tif == NULL) {
+		TIFFErrorExt(clientdata, module, "%s: Out of memory (TIFF structure)", name);
+		goto bad2;
+	}
+	_TIFFmemset(tif, 0, sizeof (*tif));
+	tif->tif_name = (char *)tif + sizeof (TIFF);
+	strcpy(tif->tif_name, name);
+	tif->tif_mode = m &~ (O_CREAT|O_TRUNC);
+	tif->tif_curdir = (uint16) -1;		/* non-existent directory */
+	tif->tif_curoff = 0;
+	tif->tif_curstrip = (uint32) -1;	/* invalid strip */
+	tif->tif_row = (uint32) -1;		/* read/write pre-increment */
+	tif->tif_clientdata = clientdata;
+	if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) {
+		TIFFErrorExt(clientdata, module,
+		    "One of the client procedures is NULL pointer.");
+		goto bad2;
+	}
+	tif->tif_readproc = readproc;
+	tif->tif_writeproc = writeproc;
+	tif->tif_seekproc = seekproc;
+	tif->tif_closeproc = closeproc;
+	tif->tif_sizeproc = sizeproc;
+	if (mapproc)
+		tif->tif_mapproc = mapproc;
+	else
+		tif->tif_mapproc = _tiffDummyMapProc;
+	if (unmapproc)
+		tif->tif_unmapproc = unmapproc;
+	else
+		tif->tif_unmapproc = _tiffDummyUnmapProc;
+	_TIFFSetDefaultCompressionState(tif);    /* setup default state */
+	/*
+	 * Default is to return data MSB2LSB and enable the
+	 * use of memory-mapped files and strip chopping when
+	 * a file is opened read-only.
+	 */
+	tif->tif_flags = FILLORDER_MSB2LSB;
+	if (m == O_RDONLY )
+		tif->tif_flags |= TIFF_MAPPED;
+
+	#ifdef STRIPCHOP_DEFAULT
+	if (m == O_RDONLY || m == O_RDWR)
+		tif->tif_flags |= STRIPCHOP_DEFAULT;
+	#endif
+
+	/*
+	 * Process library-specific flags in the open mode string.
+	 * The following flags may be used to control intrinsic library
+	 * behaviour that may or may not be desirable (usually for
+	 * compatibility with some application that claims to support
+	 * TIFF but only supports some braindead idea of what the
+	 * vendor thinks TIFF is):
+	 *
+	 * 'l' use little-endian byte order for creating a file
+	 * 'b' use big-endian byte order for creating a file
+	 * 'L' read/write information using LSB2MSB bit order
+	 * 'B' read/write information using MSB2LSB bit order
+	 * 'H' read/write information using host bit order
+	 * 'M' enable use of memory-mapped files when supported
+	 * 'm' disable use of memory-mapped files
+	 * 'C' enable strip chopping support when reading
+	 * 'c' disable strip chopping support
+	 * 'h' read TIFF header only, do not load the first IFD
+	 * '4' ClassicTIFF for creating a file (default)
+	 * '8' BigTIFF for creating a file
+	 *
+	 * The use of the 'l' and 'b' flags is strongly discouraged.
+	 * These flags are provided solely because numerous vendors,
+	 * typically on the PC, do not correctly support TIFF; they
+	 * only support the Intel little-endian byte order.  This
+	 * support is not configured by default because it supports
+	 * the violation of the TIFF spec that says that readers *MUST*
+	 * support both byte orders.  It is strongly recommended that
+	 * you not use this feature except to deal with busted apps
+	 * that write invalid TIFF.  And even in those cases you should
+	 * bang on the vendors to fix their software.
+	 *
+	 * The 'L', 'B', and 'H' flags are intended for applications
+	 * that can optimize operations on data by using a particular
+	 * bit order.  By default the library returns data in MSB2LSB
+	 * bit order for compatibiltiy with older versions of this
+	 * library.  Returning data in the bit order of the native cpu
+	 * makes the most sense but also requires applications to check
+	 * the value of the FillOrder tag; something they probably do
+	 * not do right now.
+	 *
+	 * The 'M' and 'm' flags are provided because some virtual memory
+	 * systems exhibit poor behaviour when large images are mapped.
+	 * These options permit clients to control the use of memory-mapped
+	 * files on a per-file basis.
+	 *
+	 * The 'C' and 'c' flags are provided because the library support
+	 * for chopping up large strips into multiple smaller strips is not
+	 * application-transparent and as such can cause problems.  The 'c'
+	 * option permits applications that only want to look at the tags,
+	 * for example, to get the unadulterated TIFF tag information.
+	 */
+	for (cp = mode; *cp; cp++)
+		switch (*cp) {
+			case 'b':
+				#ifndef WORDS_BIGENDIAN
+				if (m&O_CREAT)
+					tif->tif_flags |= TIFF_SWAB;
+				#endif
+				break;
+			case 'l':
+				#ifdef WORDS_BIGENDIAN
+				if ((m&O_CREAT))
+					tif->tif_flags |= TIFF_SWAB;
+				#endif
+				break;
+			case 'B':
+				tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+				    FILLORDER_MSB2LSB;
+				break;
+			case 'L':
+				tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+				    FILLORDER_LSB2MSB;
+				break;
+			case 'H':
+				tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+				    HOST_FILLORDER;
+				break;
+			case 'M':
+				if (m == O_RDONLY)
+					tif->tif_flags |= TIFF_MAPPED;
+				break;
+			case 'm':
+				if (m == O_RDONLY)
+					tif->tif_flags &= ~TIFF_MAPPED;
+				break;
+			case 'C':
+				if (m == O_RDONLY)
+					tif->tif_flags |= TIFF_STRIPCHOP;
+				break;
+			case 'c':
+				if (m == O_RDONLY)
+					tif->tif_flags &= ~TIFF_STRIPCHOP;
+				break;
+			case 'h':
+				tif->tif_flags |= TIFF_HEADERONLY;
+				break;
+			case '8':
+				if (m&O_CREAT)
+					tif->tif_flags |= TIFF_BIGTIFF;
+				break;
+		}
+	/*
+	 * Read in TIFF header.
+	 */
+	if ((m & O_TRUNC) ||
+	    !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeaderClassic))) {
+		if (tif->tif_mode == O_RDONLY) {
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Cannot read TIFF header");
+			goto bad;
+		}
+		/*
+		 * Setup header and write.
+		 */
+		#ifdef WORDS_BIGENDIAN
+		tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB
+		    ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN;
+		#else
+		tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB
+		    ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN;
+		#endif
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC;
+			tif->tif_header.classic.tiff_diroff = 0;
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&tif->tif_header.common.tiff_version);
+			tif->tif_header_size = sizeof(TIFFHeaderClassic);
+		}
+		else
+		{
+			tif->tif_header.common.tiff_version = TIFF_VERSION_BIG;
+			tif->tif_header.big.tiff_offsetsize = 8;
+			tif->tif_header.big.tiff_unused = 0;
+			tif->tif_header.big.tiff_diroff = 0;
+			if (tif->tif_flags & TIFF_SWAB)
+			{
+				TIFFSwabShort(&tif->tif_header.common.tiff_version);
+				TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize);
+			}
+			tif->tif_header_size = sizeof (TIFFHeaderBig);
+		}
+		/*
+		 * The doc for "fopen" for some STD_C_LIBs says that if you
+		 * open a file for modify ("+"), then you must fseek (or
+		 * fflush?) between any freads and fwrites.  This is not
+		 * necessary on most systems, but has been shown to be needed
+		 * on Solaris.
+		 */
+		TIFFSeekFile( tif, 0, SEEK_SET );
+		if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size))) {
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Error writing TIFF header");
+			goto bad;
+		}
+		/*
+		 * Setup the byte order handling.
+		 */
+		if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) {
+			#ifndef WORDS_BIGENDIAN
+			tif->tif_flags |= TIFF_SWAB;
+			#endif
+		} else {
+			#ifdef WORDS_BIGENDIAN
+			tif->tif_flags |= TIFF_SWAB;
+			#endif
+		}
+		/*
+		 * Setup default directory.
+		 */
+		if (!TIFFDefaultDirectory(tif))
+			goto bad;
+		tif->tif_diroff = 0;
+		tif->tif_dirlist = NULL;
+		tif->tif_dirlistsize = 0;
+		tif->tif_dirnumber = 0;
+		return (tif);
+	}
+	/*
+	 * Setup the byte order handling.
+	 */
+	if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN &&
+	    tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN
+	    #if MDI_SUPPORT
+	    &&
+	    #if HOST_BIGENDIAN
+	    tif->tif_header.common.tiff_magic != MDI_BIGENDIAN
+	    #else
+	    tif->tif_header.common.tiff_magic != MDI_LITTLEENDIAN
+	    #endif
+	    ) {
+		TIFFErrorExt(tif->tif_clientdata, name,
+		    "Not a TIFF or MDI file, bad magic number %d (0x%x)",
+	    #else
+	    ) {
+		TIFFErrorExt(tif->tif_clientdata, name,
+		    "Not a TIFF file, bad magic number %d (0x%x)",
+	    #endif
+		    tif->tif_header.common.tiff_magic,
+		    tif->tif_header.common.tiff_magic);
+		goto bad;
+	}
+	if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) {
+		#ifndef WORDS_BIGENDIAN
+		tif->tif_flags |= TIFF_SWAB;
+		#endif
+	} else {
+		#ifdef WORDS_BIGENDIAN
+		tif->tif_flags |= TIFF_SWAB;
+		#endif
+	}
+	if (tif->tif_flags & TIFF_SWAB) 
+		TIFFSwabShort(&tif->tif_header.common.tiff_version);
+	if ((tif->tif_header.common.tiff_version != TIFF_VERSION_CLASSIC)&&
+	    (tif->tif_header.common.tiff_version != TIFF_VERSION_BIG)) {
+		TIFFErrorExt(tif->tif_clientdata, name,
+		    "Not a TIFF file, bad version number %d (0x%x)",
+		    tif->tif_header.common.tiff_version,
+		    tif->tif_header.common.tiff_version);
+		goto bad;
+	}
+	if (tif->tif_header.common.tiff_version == TIFF_VERSION_CLASSIC)
+	{
+		if (tif->tif_flags & TIFF_SWAB)
+			TIFFSwabLong(&tif->tif_header.classic.tiff_diroff);
+		tif->tif_header_size = sizeof(TIFFHeaderClassic);
+	}
+	else
+	{
+		if (!ReadOK(tif, ((uint8*)(&tif->tif_header) + sizeof(TIFFHeaderClassic)), (sizeof(TIFFHeaderBig)-sizeof(TIFFHeaderClassic))))
+		{
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Cannot read TIFF header");
+			goto bad;
+		}
+		if (tif->tif_flags & TIFF_SWAB)
+		{
+			TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize);
+			TIFFSwabLong8(&tif->tif_header.big.tiff_diroff);
+		}
+		if (tif->tif_header.big.tiff_offsetsize != 8)
+		{
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Not a TIFF file, bad BigTIFF offsetsize %d (0x%x)",
+			    tif->tif_header.big.tiff_offsetsize,
+			    tif->tif_header.big.tiff_offsetsize);
+			goto bad;
+		}
+		if (tif->tif_header.big.tiff_unused != 0)
+		{
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Not a TIFF file, bad BigTIFF unused %d (0x%x)",
+			    tif->tif_header.big.tiff_unused,
+			    tif->tif_header.big.tiff_unused);
+			goto bad;
+		}
+		tif->tif_header_size = sizeof(TIFFHeaderBig);
+		tif->tif_flags |= TIFF_BIGTIFF;
+	}
+	tif->tif_flags |= TIFF_MYBUFFER;
+	tif->tif_rawcp = tif->tif_rawdata = 0;
+	tif->tif_rawdatasize = 0;
+        tif->tif_rawdataoff = 0;
+        tif->tif_rawdataloaded = 0;
+
+	switch (mode[0]) {
+		case 'r':
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+				tif->tif_nextdiroff = tif->tif_header.classic.tiff_diroff;
+			else
+				tif->tif_nextdiroff = tif->tif_header.big.tiff_diroff;
+			/*
+			 * Try to use a memory-mapped file if the client
+			 * has not explicitly suppressed usage with the
+			 * 'm' flag in the open mode (see above).
+			 */
+			if (tif->tif_flags & TIFF_MAPPED)
+			{
+				toff_t n;
+				if (TIFFMapFileContents(tif,(void**)(&tif->tif_base),&n))
+				{
+					tif->tif_size=(tmsize_t)n;
+					assert((toff_t)tif->tif_size==n);
+				}
+				else
+					tif->tif_flags &= ~TIFF_MAPPED;
+			}
+			/*
+			 * Sometimes we do not want to read the first directory (for example,
+			 * it may be broken) and want to proceed to other directories. I this
+			 * case we use the TIFF_HEADERONLY flag to open file and return
+			 * immediately after reading TIFF header.
+			 */
+			if (tif->tif_flags & TIFF_HEADERONLY)
+				return (tif);
+
+			/*
+			 * Setup initial directory.
+			 */
+			if (TIFFReadDirectory(tif)) {
+				tif->tif_rawcc = (tmsize_t)-1;
+				tif->tif_flags |= TIFF_BUFFERSETUP;
+				return (tif);
+			}
+			break;
+		case 'a':
+			/*
+			 * New directories are automatically append
+			 * to the end of the directory chain when they
+			 * are written out (see TIFFWriteDirectory).
+			 */
+			if (!TIFFDefaultDirectory(tif))
+				goto bad;
+			return (tif);
+	}
+bad:
+	tif->tif_mode = O_RDONLY;	/* XXX avoid flush */
+        TIFFCleanup(tif);
+bad2:
+	return ((TIFF*)0);
+}
+
+/*
+ * Query functions to access private data.
+ */
+
+/*
+ * Return open file's name.
+ */
+const char *
+TIFFFileName(TIFF* tif)
+{
+	return (tif->tif_name);
+}
+
+/*
+ * Set the file name.
+ */
+const char *
+TIFFSetFileName(TIFF* tif, const char *name)
+{
+	const char* old_name = tif->tif_name;
+	tif->tif_name = (char *)name;
+	return (old_name);
+}
+
+/*
+ * Return open file's I/O descriptor.
+ */
+int
+TIFFFileno(TIFF* tif)
+{
+	return (tif->tif_fd);
+}
+
+/*
+ * Set open file's I/O descriptor, and return previous value.
+ */
+int
+TIFFSetFileno(TIFF* tif, int fd)
+{
+        int old_fd = tif->tif_fd;
+	tif->tif_fd = fd;
+	return old_fd;
+}
+
+/*
+ * Return open file's clientdata.
+ */
+thandle_t
+TIFFClientdata(TIFF* tif)
+{
+	return (tif->tif_clientdata);
+}
+
+/*
+ * Set open file's clientdata, and return previous value.
+ */
+thandle_t
+TIFFSetClientdata(TIFF* tif, thandle_t newvalue)
+{
+	thandle_t m = tif->tif_clientdata;
+	tif->tif_clientdata = newvalue;
+	return m;
+}
+
+/*
+ * Return read/write mode.
+ */
+int
+TIFFGetMode(TIFF* tif)
+{
+	return (tif->tif_mode);
+}
+
+/*
+ * Return read/write mode.
+ */
+int
+TIFFSetMode(TIFF* tif, int mode)
+{
+	int old_mode = tif->tif_mode;
+	tif->tif_mode = mode;
+	return (old_mode);
+}
+
+/*
+ * Return nonzero if file is organized in
+ * tiles; zero if organized as strips.
+ */
+int
+TIFFIsTiled(TIFF* tif)
+{
+	return (isTiled(tif));
+}
+
+/*
+ * Return current row being read/written.
+ */
+uint32
+TIFFCurrentRow(TIFF* tif)
+{
+	return (tif->tif_row);
+}
+
+/*
+ * Return index of the current directory.
+ */
+uint16
+TIFFCurrentDirectory(TIFF* tif)
+{
+	return (tif->tif_curdir);
+}
+
+/*
+ * Return current strip.
+ */
+uint32
+TIFFCurrentStrip(TIFF* tif)
+{
+	return (tif->tif_curstrip);
+}
+
+/*
+ * Return current tile.
+ */
+uint32
+TIFFCurrentTile(TIFF* tif)
+{
+	return (tif->tif_curtile);
+}
+
+/*
+ * Return nonzero if the file has byte-swapped data.
+ */
+int
+TIFFIsByteSwapped(TIFF* tif)
+{
+	return ((tif->tif_flags & TIFF_SWAB) != 0);
+}
+
+/*
+ * Return nonzero if the data is returned up-sampled.
+ */
+int
+TIFFIsUpSampled(TIFF* tif)
+{
+	return (isUpSampled(tif));
+}
+
+/*
+ * Return nonzero if the data is returned in MSB-to-LSB bit order.
+ */
+int
+TIFFIsMSB2LSB(TIFF* tif)
+{
+	return (isFillOrder(tif, FILLORDER_MSB2LSB));
+}
+
+/*
+ * Return nonzero if given file was written in big-endian order.
+ */
+int
+TIFFIsBigEndian(TIFF* tif)
+{
+	return (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN);
+}
+
+/*
+ * Return pointer to file read method.
+ */
+TIFFReadWriteProc
+TIFFGetReadProc(TIFF* tif)
+{
+	return (tif->tif_readproc);
+}
+
+/*
+ * Return pointer to file write method.
+ */
+TIFFReadWriteProc
+TIFFGetWriteProc(TIFF* tif)
+{
+	return (tif->tif_writeproc);
+}
+
+/*
+ * Return pointer to file seek method.
+ */
+TIFFSeekProc
+TIFFGetSeekProc(TIFF* tif)
+{
+	return (tif->tif_seekproc);
+}
+
+/*
+ * Return pointer to file close method.
+ */
+TIFFCloseProc
+TIFFGetCloseProc(TIFF* tif)
+{
+	return (tif->tif_closeproc);
+}
+
+/*
+ * Return pointer to file size requesting method.
+ */
+TIFFSizeProc
+TIFFGetSizeProc(TIFF* tif)
+{
+	return (tif->tif_sizeproc);
+}
+
+/*
+ * Return pointer to memory mapping method.
+ */
+TIFFMapFileProc
+TIFFGetMapFileProc(TIFF* tif)
+{
+	return (tif->tif_mapproc);
+}
+
+/*
+ * Return pointer to memory unmapping method.
+ */
+TIFFUnmapFileProc
+TIFFGetUnmapFileProc(TIFF* tif)
+{
+	return (tif->tif_unmapproc);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_packbits.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_packbits.c
new file mode 100644
index 0000000..6fb517f
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_packbits.c
@@ -0,0 +1,302 @@
+/* $Id: tif_packbits.c,v 1.22 2012-06-20 05:25:33 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#ifdef PACKBITS_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * PackBits Compression Algorithm Support
+ */
+#include <stdio.h>
+
+static int
+PackBitsPreEncode(TIFF* tif, uint16 s)
+{
+	(void) s;
+
+	if (!(tif->tif_data = (uint8*)_TIFFmalloc(sizeof(tmsize_t))))
+		return (0);
+	/*
+	 * Calculate the scanline/tile-width size in bytes.
+	 */
+	if (isTiled(tif))
+		*(tmsize_t*)tif->tif_data = TIFFTileRowSize(tif);
+	else
+		*(tmsize_t*)tif->tif_data = TIFFScanlineSize(tif);
+	return (1);
+}
+
+static int
+PackBitsPostEncode(TIFF* tif)
+{
+        if (tif->tif_data)
+            _TIFFfree(tif->tif_data);
+	return (1);
+}
+
+/*
+ * Encode a run of pixels.
+ */
+static int
+PackBitsEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	unsigned char* bp = (unsigned char*) buf;
+	uint8* op;
+	uint8* ep;
+	uint8* lastliteral;
+	long n, slop;
+	int b;
+	enum { BASE, LITERAL, RUN, LITERAL_RUN } state;
+
+	(void) s;
+	op = tif->tif_rawcp;
+	ep = tif->tif_rawdata + tif->tif_rawdatasize;
+	state = BASE;
+	lastliteral = 0;
+	while (cc > 0) {
+		/*
+		 * Find the longest string of identical bytes.
+		 */
+		b = *bp++, cc--, n = 1;
+		for (; cc > 0 && b == *bp; cc--, bp++)
+			n++;
+	again:
+		if (op + 2 >= ep) {		/* insure space for new data */
+			/*
+			 * Be careful about writing the last
+			 * literal.  Must write up to that point
+			 * and then copy the remainder to the
+			 * front of the buffer.
+			 */
+			if (state == LITERAL || state == LITERAL_RUN) {
+				slop = (long)(op - lastliteral);
+				tif->tif_rawcc += (tmsize_t)(lastliteral - tif->tif_rawcp);
+				if (!TIFFFlushData1(tif))
+					return (-1);
+				op = tif->tif_rawcp;
+				while (slop-- > 0)
+					*op++ = *lastliteral++;
+				lastliteral = tif->tif_rawcp;
+			} else {
+				tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
+				if (!TIFFFlushData1(tif))
+					return (-1);
+				op = tif->tif_rawcp;
+			}
+		}
+		switch (state) {
+		case BASE:		/* initial state, set run/literal */
+			if (n > 1) {
+				state = RUN;
+				if (n > 128) {
+					*op++ = (uint8) -127;
+					*op++ = (uint8) b;
+					n -= 128;
+					goto again;
+				}
+				*op++ = (uint8)(-(n-1));
+				*op++ = (uint8) b;
+			} else {
+				lastliteral = op;
+				*op++ = 0;
+				*op++ = (uint8) b;
+				state = LITERAL;
+			}
+			break;
+		case LITERAL:		/* last object was literal string */
+			if (n > 1) {
+				state = LITERAL_RUN;
+				if (n > 128) {
+					*op++ = (uint8) -127;
+					*op++ = (uint8) b;
+					n -= 128;
+					goto again;
+				}
+				*op++ = (uint8)(-(n-1));	/* encode run */
+				*op++ = (uint8) b;
+			} else {			/* extend literal */
+				if (++(*lastliteral) == 127)
+					state = BASE;
+				*op++ = (uint8) b;
+			}
+			break;
+		case RUN:		/* last object was run */
+			if (n > 1) {
+				if (n > 128) {
+					*op++ = (uint8) -127;
+					*op++ = (uint8) b;
+					n -= 128;
+					goto again;
+				}
+				*op++ = (uint8)(-(n-1));
+				*op++ = (uint8) b;
+			} else {
+				lastliteral = op;
+				*op++ = 0;
+				*op++ = (uint8) b;
+				state = LITERAL;
+			}
+			break;
+		case LITERAL_RUN:	/* literal followed by a run */
+			/*
+			 * Check to see if previous run should
+			 * be converted to a literal, in which
+			 * case we convert literal-run-literal
+			 * to a single literal.
+			 */
+			if (n == 1 && op[-2] == (uint8) -1 &&
+			    *lastliteral < 126) {
+				state = (((*lastliteral) += 2) == 127 ?
+				    BASE : LITERAL);
+				op[-2] = op[-1];	/* replicate */
+			} else
+				state = RUN;
+			goto again;
+		}
+	}
+	tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
+	tif->tif_rawcp = op;
+	return (1);
+}
+
+/*
+ * Encode a rectangular chunk of pixels.  We break it up
+ * into row-sized pieces to insure that encoded runs do
+ * not span rows.  Otherwise, there can be problems with
+ * the decoder if data is read, for example, by scanlines
+ * when it was encoded by strips.
+ */
+static int
+PackBitsEncodeChunk(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowsize = *(tmsize_t*)tif->tif_data;
+
+	while (cc > 0) {
+		tmsize_t chunk = rowsize;
+		
+		if( cc < chunk )
+		    chunk = cc;
+
+		if (PackBitsEncode(tif, bp, chunk, s) < 0)
+		    return (-1);
+		bp += chunk;
+		cc -= chunk;
+	}
+	return (1);
+}
+
+static int
+PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "PackBitsDecode";
+	char *bp;
+	tmsize_t cc;
+	long n;
+	int b;
+
+	(void) s;
+	bp = (char*) tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	while (cc > 0 && occ > 0) {
+		n = (long) *bp++, cc--;
+		/*
+		 * Watch out for compilers that
+		 * don't sign extend chars...
+		 */
+		if (n >= 128)
+			n -= 256;
+		if (n < 0) {		/* replicate next byte -n+1 times */
+			if (n == -128)	/* nop */
+				continue;
+			n = -n + 1;
+			if( occ < (tmsize_t)n )
+			{
+				TIFFWarningExt(tif->tif_clientdata, module,
+				    "Discarding %lu bytes to avoid buffer overrun",
+				    (unsigned long) ((tmsize_t)n - occ));
+				n = (long)occ;
+			}
+			occ -= n;
+			b = *bp++, cc--;
+			while (n-- > 0)
+				*op++ = (uint8) b;
+		} else {		/* copy next n+1 bytes literally */
+			if (occ < (tmsize_t)(n + 1))
+			{
+				TIFFWarningExt(tif->tif_clientdata, module,
+				    "Discarding %lu bytes to avoid buffer overrun",
+				    (unsigned long) ((tmsize_t)n - occ + 1));
+				n = (long)occ - 1;
+			}
+			if (cc < (tmsize_t) (n+1)) 
+			{
+				TIFFWarningExt(tif->tif_clientdata, module,
+					       "Terminating PackBitsDecode due to lack of data.");
+				break;
+			}
+			_TIFFmemcpy(op, bp, ++n);
+			op += n; occ -= n;
+			bp += n; cc -= n;
+		}
+	}
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	if (occ > 0) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Not enough data for scanline %lu",
+		    (unsigned long) tif->tif_row);
+		return (0);
+	}
+	return (1);
+}
+
+int
+TIFFInitPackBits(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	tif->tif_decoderow = PackBitsDecode;
+	tif->tif_decodestrip = PackBitsDecode;
+	tif->tif_decodetile = PackBitsDecode;
+	tif->tif_preencode = PackBitsPreEncode;
+	tif->tif_postencode = PackBitsPostEncode;
+	tif->tif_encoderow = PackBitsEncode;
+	tif->tif_encodestrip = PackBitsEncodeChunk;
+	tif->tif_encodetile = PackBitsEncodeChunk;
+	return (1);
+}
+#endif /* PACKBITS_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_pixarlog.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_pixarlog.c
new file mode 100644
index 0000000..5aaf8be
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_pixarlog.c
@@ -0,0 +1,1428 @@
+/* $Id: tif_pixarlog.c,v 1.38 2012-06-21 01:01:53 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1996-1997 Sam Leffler
+ * Copyright (c) 1996 Pixar
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Pixar, Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#ifdef PIXARLOG_SUPPORT
+
+/*
+ * TIFF Library.
+ * PixarLog Compression Support
+ *
+ * Contributed by Dan McCoy.
+ *
+ * PixarLog film support uses the TIFF library to store companded
+ * 11 bit values into a tiff file, which are compressed using the 
+ * zip compressor.  
+ *
+ * The codec can take as input and produce as output 32-bit IEEE float values 
+ * as well as 16-bit or 8-bit unsigned integer values.
+ *
+ * On writing any of the above are converted into the internal
+ * 11-bit log format.   In the case of  8 and 16 bit values, the
+ * input is assumed to be unsigned linear color values that represent
+ * the range 0-1.  In the case of IEEE values, the 0-1 range is assumed to
+ * be the normal linear color range, in addition over 1 values are
+ * accepted up to a value of about 25.0 to encode "hot" hightlights and such.
+ * The encoding is lossless for 8-bit values, slightly lossy for the
+ * other bit depths.  The actual color precision should be better
+ * than the human eye can perceive with extra room to allow for
+ * error introduced by further image computation.  As with any quantized
+ * color format, it is possible to perform image calculations which
+ * expose the quantization error. This format should certainly be less 
+ * susceptable to such errors than standard 8-bit encodings, but more
+ * susceptable than straight 16-bit or 32-bit encodings.
+ *
+ * On reading the internal format is converted to the desired output format.
+ * The program can request which format it desires by setting the internal
+ * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values:
+ *  PIXARLOGDATAFMT_FLOAT     = provide IEEE float values.
+ *  PIXARLOGDATAFMT_16BIT     = provide unsigned 16-bit integer values
+ *  PIXARLOGDATAFMT_8BIT      = provide unsigned 8-bit integer values
+ *
+ * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer
+ * values with the difference that if there are exactly three or four channels
+ * (rgb or rgba) it swaps the channel order (bgr or abgr).
+ *
+ * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly
+ * packed in 16-bit values.   However no tools are supplied for interpreting
+ * these values.
+ *
+ * "hot" (over 1.0) areas written in floating point get clamped to
+ * 1.0 in the integer data types.
+ *
+ * When the file is closed after writing, the bit depth and sample format
+ * are set always to appear as if 8-bit data has been written into it.
+ * That way a naive program unaware of the particulars of the encoding
+ * gets the format it is most likely able to handle.
+ *
+ * The codec does it's own horizontal differencing step on the coded
+ * values so the libraries predictor stuff should be turned off.
+ * The codec also handle byte swapping the encoded values as necessary
+ * since the library does not have the information necessary
+ * to know the bit depth of the raw unencoded buffer.
+ *
+ * NOTE: This decoder does not appear to update tif_rawcp, and tif_rawcc.
+ * This can cause problems with the implementation of CHUNKY_STRIP_READ_SUPPORT
+ * as noted in http://trac.osgeo.org/gdal/ticket/3894.   FrankW - Jan'11
+ */
+
+#include "tif_predict.h"
+#include "../../fx_zlib/include/fx_zlib.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+/* Tables for converting to/from 11 bit coded values */
+
+#define  TSIZE	 2048		/* decode table size (11-bit tokens) */
+#define  TSIZEP1 2049		/* Plus one for slop */
+#define  ONE	 1250		/* token value of 1.0 exactly */
+#define  RATIO	 1.004		/* nominal ratio for log part */
+
+#define CODE_MASK 0x7ff         /* 11 bits. */
+
+static float  Fltsize;
+static float  LogK1, LogK2;
+
+#define REPEAT(n, op)   { int i; i=n; do { i--; op; } while (i>0); }
+
+static void
+horizontalAccumulateF(uint16 *wp, int n, int stride, float *op,
+	float *ToLinearF)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+    register float  t0, t1, t2, t3;
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    t0 = ToLinearF[cr = (wp[0] & mask)];
+	    t1 = ToLinearF[cg = (wp[1] & mask)];
+	    t2 = ToLinearF[cb = (wp[2] & mask)];
+	    op[0] = t0;
+	    op[1] = t1;
+	    op[2] = t2;
+	    n -= 3;
+	    while (n > 0) {
+		wp += 3;
+		op += 3;
+		n -= 3;
+		t0 = ToLinearF[(cr += wp[0]) & mask];
+		t1 = ToLinearF[(cg += wp[1]) & mask];
+		t2 = ToLinearF[(cb += wp[2]) & mask];
+		op[0] = t0;
+		op[1] = t1;
+		op[2] = t2;
+	    }
+	} else if (stride == 4) {
+	    t0 = ToLinearF[cr = (wp[0] & mask)];
+	    t1 = ToLinearF[cg = (wp[1] & mask)];
+	    t2 = ToLinearF[cb = (wp[2] & mask)];
+	    t3 = ToLinearF[ca = (wp[3] & mask)];
+	    op[0] = t0;
+	    op[1] = t1;
+	    op[2] = t2;
+	    op[3] = t3;
+	    n -= 4;
+	    while (n > 0) {
+		wp += 4;
+		op += 4;
+		n -= 4;
+		t0 = ToLinearF[(cr += wp[0]) & mask];
+		t1 = ToLinearF[(cg += wp[1]) & mask];
+		t2 = ToLinearF[(cb += wp[2]) & mask];
+		t3 = ToLinearF[(ca += wp[3]) & mask];
+		op[0] = t0;
+		op[1] = t1;
+		op[2] = t2;
+		op[3] = t3;
+	    }
+	} else {
+	    REPEAT(stride, *op = ToLinearF[*wp&mask]; wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; *op = ToLinearF[*wp&mask]; wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+static void
+horizontalAccumulate12(uint16 *wp, int n, int stride, int16 *op,
+	float *ToLinearF)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+    register float  t0, t1, t2, t3;
+
+#define SCALE12 2048.0F
+#define CLAMP12(t) (((t) < 3071) ? (uint16) (t) : 3071)
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12;
+	    t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12;
+	    t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12;
+	    op[0] = CLAMP12(t0);
+	    op[1] = CLAMP12(t1);
+	    op[2] = CLAMP12(t2);
+	    n -= 3;
+	    while (n > 0) {
+		wp += 3;
+		op += 3;
+		n -= 3;
+		t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12;
+		t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12;
+		t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12;
+		op[0] = CLAMP12(t0);
+		op[1] = CLAMP12(t1);
+		op[2] = CLAMP12(t2);
+	    }
+	} else if (stride == 4) {
+	    t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12;
+	    t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12;
+	    t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12;
+	    t3 = ToLinearF[ca = (wp[3] & mask)] * SCALE12;
+	    op[0] = CLAMP12(t0);
+	    op[1] = CLAMP12(t1);
+	    op[2] = CLAMP12(t2);
+	    op[3] = CLAMP12(t3);
+	    n -= 4;
+	    while (n > 0) {
+		wp += 4;
+		op += 4;
+		n -= 4;
+		t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12;
+		t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12;
+		t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12;
+		t3 = ToLinearF[(ca += wp[3]) & mask] * SCALE12;
+		op[0] = CLAMP12(t0);
+		op[1] = CLAMP12(t1);
+		op[2] = CLAMP12(t2);
+		op[3] = CLAMP12(t3);
+	    }
+	} else {
+	    REPEAT(stride, t0 = ToLinearF[*wp&mask] * SCALE12;
+                           *op = CLAMP12(t0); wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; t0 = ToLinearF[wp[stride]&mask]*SCALE12;
+		    *op = CLAMP12(t0);  wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+static void
+horizontalAccumulate16(uint16 *wp, int n, int stride, uint16 *op,
+	uint16 *ToLinear16)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    op[0] = ToLinear16[cr = (wp[0] & mask)];
+	    op[1] = ToLinear16[cg = (wp[1] & mask)];
+	    op[2] = ToLinear16[cb = (wp[2] & mask)];
+	    n -= 3;
+	    while (n > 0) {
+		wp += 3;
+		op += 3;
+		n -= 3;
+		op[0] = ToLinear16[(cr += wp[0]) & mask];
+		op[1] = ToLinear16[(cg += wp[1]) & mask];
+		op[2] = ToLinear16[(cb += wp[2]) & mask];
+	    }
+	} else if (stride == 4) {
+	    op[0] = ToLinear16[cr = (wp[0] & mask)];
+	    op[1] = ToLinear16[cg = (wp[1] & mask)];
+	    op[2] = ToLinear16[cb = (wp[2] & mask)];
+	    op[3] = ToLinear16[ca = (wp[3] & mask)];
+	    n -= 4;
+	    while (n > 0) {
+		wp += 4;
+		op += 4;
+		n -= 4;
+		op[0] = ToLinear16[(cr += wp[0]) & mask];
+		op[1] = ToLinear16[(cg += wp[1]) & mask];
+		op[2] = ToLinear16[(cb += wp[2]) & mask];
+		op[3] = ToLinear16[(ca += wp[3]) & mask];
+	    }
+	} else {
+	    REPEAT(stride, *op = ToLinear16[*wp&mask]; wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; *op = ToLinear16[*wp&mask]; wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+/* 
+ * Returns the log encoded 11-bit values with the horizontal
+ * differencing undone.
+ */
+static void
+horizontalAccumulate11(uint16 *wp, int n, int stride, uint16 *op)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    op[0] = cr = wp[0];  op[1] = cg = wp[1];  op[2] = cb = wp[2];
+	    n -= 3;
+	    while (n > 0) {
+		wp += 3;
+		op += 3;
+		n -= 3;
+		op[0] = (cr += wp[0]) & mask;
+		op[1] = (cg += wp[1]) & mask;
+		op[2] = (cb += wp[2]) & mask;
+	    }
+	} else if (stride == 4) {
+	    op[0] = cr = wp[0];  op[1] = cg = wp[1];
+	    op[2] = cb = wp[2];  op[3] = ca = wp[3];
+	    n -= 4;
+	    while (n > 0) {
+		wp += 4;
+		op += 4;
+		n -= 4;
+		op[0] = (cr += wp[0]) & mask;
+		op[1] = (cg += wp[1]) & mask;
+		op[2] = (cb += wp[2]) & mask;
+		op[3] = (ca += wp[3]) & mask;
+	    } 
+	} else {
+	    REPEAT(stride, *op = *wp&mask; wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; *op = *wp&mask; wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+static void
+horizontalAccumulate8(uint16 *wp, int n, int stride, unsigned char *op,
+	unsigned char *ToLinear8)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    op[0] = ToLinear8[cr = (wp[0] & mask)];
+	    op[1] = ToLinear8[cg = (wp[1] & mask)];
+	    op[2] = ToLinear8[cb = (wp[2] & mask)];
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		wp += 3;
+		op += 3;
+		op[0] = ToLinear8[(cr += wp[0]) & mask];
+		op[1] = ToLinear8[(cg += wp[1]) & mask];
+		op[2] = ToLinear8[(cb += wp[2]) & mask];
+	    }
+	} else if (stride == 4) {
+	    op[0] = ToLinear8[cr = (wp[0] & mask)];
+	    op[1] = ToLinear8[cg = (wp[1] & mask)];
+	    op[2] = ToLinear8[cb = (wp[2] & mask)];
+	    op[3] = ToLinear8[ca = (wp[3] & mask)];
+	    n -= 4;
+	    while (n > 0) {
+		n -= 4;
+		wp += 4;
+		op += 4;
+		op[0] = ToLinear8[(cr += wp[0]) & mask];
+		op[1] = ToLinear8[(cg += wp[1]) & mask];
+		op[2] = ToLinear8[(cb += wp[2]) & mask];
+		op[3] = ToLinear8[(ca += wp[3]) & mask];
+	    }
+	} else {
+	    REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+
+static void
+horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op,
+	unsigned char *ToLinear8)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+    register unsigned char  t0, t1, t2, t3;
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    op[0] = 0;
+	    t1 = ToLinear8[cb = (wp[2] & mask)];
+	    t2 = ToLinear8[cg = (wp[1] & mask)];
+	    t3 = ToLinear8[cr = (wp[0] & mask)];
+	    op[1] = t1;
+	    op[2] = t2;
+	    op[3] = t3;
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		wp += 3;
+		op += 4;
+		op[0] = 0;
+		t1 = ToLinear8[(cb += wp[2]) & mask];
+		t2 = ToLinear8[(cg += wp[1]) & mask];
+		t3 = ToLinear8[(cr += wp[0]) & mask];
+		op[1] = t1;
+		op[2] = t2;
+		op[3] = t3;
+	    }
+	} else if (stride == 4) {
+	    t0 = ToLinear8[ca = (wp[3] & mask)];
+	    t1 = ToLinear8[cb = (wp[2] & mask)];
+	    t2 = ToLinear8[cg = (wp[1] & mask)];
+	    t3 = ToLinear8[cr = (wp[0] & mask)];
+	    op[0] = t0;
+	    op[1] = t1;
+	    op[2] = t2;
+	    op[3] = t3;
+	    n -= 4;
+	    while (n > 0) {
+		n -= 4;
+		wp += 4;
+		op += 4;
+		t0 = ToLinear8[(ca += wp[3]) & mask];
+		t1 = ToLinear8[(cb += wp[2]) & mask];
+		t2 = ToLinear8[(cg += wp[1]) & mask];
+		t3 = ToLinear8[(cr += wp[0]) & mask];
+		op[0] = t0;
+		op[1] = t1;
+		op[2] = t2;
+		op[3] = t3;
+	    }
+	} else {
+	    REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+/*
+ * State block for each open TIFF
+ * file using PixarLog compression/decompression.
+ */
+typedef	struct {
+	TIFFPredictorState	predict;
+	z_stream		stream;
+	uint16			*tbuf; 
+	uint16			stride;
+	int			state;
+	int			user_datafmt;
+	int			quality;
+#define PLSTATE_INIT 1
+
+	TIFFVSetMethod		vgetparent;	/* super-class method */
+	TIFFVSetMethod		vsetparent;	/* super-class method */
+
+	float *ToLinearF;
+	uint16 *ToLinear16;
+	unsigned char *ToLinear8;
+	uint16  *FromLT2;
+	uint16  *From14; /* Really for 16-bit data, but we shift down 2 */
+	uint16  *From8;
+	
+} PixarLogState;
+
+static int
+PixarLogMakeTables(PixarLogState *sp)
+{
+
+/*
+ *    We make several tables here to convert between various external
+ *    representations (float, 16-bit, and 8-bit) and the internal
+ *    11-bit companded representation.  The 11-bit representation has two
+ *    distinct regions.  A linear bottom end up through .018316 in steps
+ *    of about .000073, and a region of constant ratio up to about 25.
+ *    These floating point numbers are stored in the main table ToLinearF. 
+ *    All other tables are derived from this one.  The tables (and the
+ *    ratios) are continuous at the internal seam.
+ */
+
+    int  nlin, lt2size;
+    int  i, j;
+    double  b, c, linstep, v;
+    float *ToLinearF;
+    uint16 *ToLinear16;
+    unsigned char *ToLinear8;
+    uint16  *FromLT2;
+    uint16  *From14; /* Really for 16-bit data, but we shift down 2 */
+    uint16  *From8;
+
+    c = log(RATIO);	
+    nlin = (int)(1./c);	/* nlin must be an integer */
+    c = 1./nlin;
+    b = exp(-c*ONE);	/* multiplicative scale factor [b*exp(c*ONE) = 1] */
+    linstep = b*c*exp(1.);
+
+    LogK1 = (float)(1./c);	/* if (v >= 2)  token = k1*log(v*k2) */
+    LogK2 = (float)(1./b);
+    lt2size = (int)(2./linstep) + 1;
+    FromLT2 = (uint16 *)_TIFFmalloc(lt2size*sizeof(uint16));
+    From14 = (uint16 *)_TIFFmalloc(16384*sizeof(uint16));
+    From8 = (uint16 *)_TIFFmalloc(256*sizeof(uint16));
+    ToLinearF = (float *)_TIFFmalloc(TSIZEP1 * sizeof(float));
+    ToLinear16 = (uint16 *)_TIFFmalloc(TSIZEP1 * sizeof(uint16));
+    ToLinear8 = (unsigned char *)_TIFFmalloc(TSIZEP1 * sizeof(unsigned char));
+    if (FromLT2 == NULL || From14  == NULL || From8   == NULL ||
+	 ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL) {
+	if (FromLT2) _TIFFfree(FromLT2);
+	if (From14) _TIFFfree(From14);
+	if (From8) _TIFFfree(From8);
+	if (ToLinearF) _TIFFfree(ToLinearF);
+	if (ToLinear16) _TIFFfree(ToLinear16);
+	if (ToLinear8) _TIFFfree(ToLinear8);
+	sp->FromLT2 = NULL;
+	sp->From14 = NULL;
+	sp->From8 = NULL;
+	sp->ToLinearF = NULL;
+	sp->ToLinear16 = NULL;
+	sp->ToLinear8 = NULL;
+	return 0;
+    }
+
+    j = 0;
+
+    for (i = 0; i < nlin; i++)  {
+	v = i * linstep;
+	ToLinearF[j++] = (float)v;
+    }
+
+    for (i = nlin; i < TSIZE; i++)
+	ToLinearF[j++] = (float)(b*exp(c*i));
+
+    ToLinearF[2048] = ToLinearF[2047];
+
+    for (i = 0; i < TSIZEP1; i++)  {
+	v = ToLinearF[i]*65535.0 + 0.5;
+	ToLinear16[i] = (v > 65535.0) ? 65535 : (uint16)v;
+	v = ToLinearF[i]*255.0  + 0.5;
+	ToLinear8[i]  = (v > 255.0) ? 255 : (unsigned char)v;
+    }
+
+    j = 0;
+    for (i = 0; i < lt2size; i++)  {
+	if ((i*linstep)*(i*linstep) > ToLinearF[j]*ToLinearF[j+1])
+	    j++;
+	FromLT2[i] = j;
+    }
+
+    /*
+     * Since we lose info anyway on 16-bit data, we set up a 14-bit
+     * table and shift 16-bit values down two bits on input.
+     * saves a little table space.
+     */
+    j = 0;
+    for (i = 0; i < 16384; i++)  {
+	while ((i/16383.)*(i/16383.) > ToLinearF[j]*ToLinearF[j+1])
+	    j++;
+	From14[i] = j;
+    }
+
+    j = 0;
+    for (i = 0; i < 256; i++)  {
+	while ((i/255.)*(i/255.) > ToLinearF[j]*ToLinearF[j+1])
+	    j++;
+	From8[i] = j;
+    }
+
+    Fltsize = (float)(lt2size/2);
+
+    sp->ToLinearF = ToLinearF;
+    sp->ToLinear16 = ToLinear16;
+    sp->ToLinear8 = ToLinear8;
+    sp->FromLT2 = FromLT2;
+    sp->From14 = From14;
+    sp->From8 = From8;
+
+    return 1;
+}
+
+#define DecoderState(tif)	((PixarLogState*) (tif)->tif_data)
+#define EncoderState(tif)	((PixarLogState*) (tif)->tif_data)
+
+static int PixarLogEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
+static int PixarLogDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s);
+
+#define PIXARLOGDATAFMT_UNKNOWN	-1
+
+static int
+PixarLogGuessDataFmt(TIFFDirectory *td)
+{
+	int guess = PIXARLOGDATAFMT_UNKNOWN;
+	int format = td->td_sampleformat;
+
+	/* If the user didn't tell us his datafmt,
+	 * take our best guess from the bitspersample.
+	 */
+	switch (td->td_bitspersample) {
+	 case 32:
+		if (format == SAMPLEFORMAT_IEEEFP)
+			guess = PIXARLOGDATAFMT_FLOAT;
+		break;
+	 case 16:
+		if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+			guess = PIXARLOGDATAFMT_16BIT;
+		break;
+	 case 12:
+		if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT)
+			guess = PIXARLOGDATAFMT_12BITPICIO;
+		break;
+	 case 11:
+		if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+			guess = PIXARLOGDATAFMT_11BITLOG;
+		break;
+	 case 8:
+		if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+			guess = PIXARLOGDATAFMT_8BIT;
+		break;
+	}
+
+	return guess;
+}
+
+static tmsize_t
+multiply_ms(tmsize_t m1, tmsize_t m2)
+{
+	tmsize_t bytes = m1 * m2;
+
+	if (m1 && bytes / m1 != m2)
+		bytes = 0;
+
+	return bytes;
+}
+
+static int
+PixarLogFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+static int
+PixarLogSetupDecode(TIFF* tif)
+{
+	static const char module[] = "PixarLogSetupDecode";
+	TIFFDirectory *td = &tif->tif_dir;
+	PixarLogState* sp = DecoderState(tif);
+	tmsize_t tbuf_size;
+
+	assert(sp != NULL);
+
+	/* Make sure no byte swapping happens on the data
+	 * after decompression. */
+	tif->tif_postdecode = _TIFFNoPostDecode;  
+
+	/* for some reason, we can't do this in TIFFInitPixarLog */
+
+	sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+	    td->td_samplesperpixel : 1);
+	tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth),
+				      td->td_rowsperstrip), sizeof(uint16));
+	if (tbuf_size == 0)
+		return (0);   /* TODO: this is an error return without error report through TIFFErrorExt */
+	sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size+sizeof(uint16)*sp->stride);
+	if (sp->tbuf == NULL)
+		return (0);
+	if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
+		sp->user_datafmt = PixarLogGuessDataFmt(td);
+	if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"PixarLog compression can't handle bits depth/data format combination (depth: %d)", 
+			td->td_bitspersample);
+		return (0);
+	}
+
+	if (inflateInit(&sp->stream) != Z_OK) {
+		TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg);
+		return (0);
+	} else {
+		sp->state |= PLSTATE_INIT;
+		return (1);
+	}
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+PixarLogPreDecode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "PixarLogPreDecode";
+	PixarLogState* sp = DecoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	sp->stream.next_in = tif->tif_rawdata;
+	assert(sizeof(sp->stream.avail_in)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_in = (uInt) tif->tif_rawcc;
+	if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	return (inflateReset(&sp->stream) == Z_OK);
+}
+
+static int
+PixarLogDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "PixarLogDecode";
+	TIFFDirectory *td = &tif->tif_dir;
+	PixarLogState* sp = DecoderState(tif);
+	tmsize_t i;
+	tmsize_t nsamples;
+	int llen;
+	uint16 *up;
+
+	switch (sp->user_datafmt) {
+	case PIXARLOGDATAFMT_FLOAT:
+		nsamples = occ / sizeof(float);	/* XXX float == 32 bits */
+		break;
+	case PIXARLOGDATAFMT_16BIT:
+	case PIXARLOGDATAFMT_12BITPICIO:
+	case PIXARLOGDATAFMT_11BITLOG:
+		nsamples = occ / sizeof(uint16); /* XXX uint16 == 16 bits */
+		break;
+	case PIXARLOGDATAFMT_8BIT:
+	case PIXARLOGDATAFMT_8BITABGR:
+		nsamples = occ;
+		break;
+	default:
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"%d bit input not supported in PixarLog",
+			td->td_bitspersample);
+		return 0;
+	}
+
+	llen = sp->stride * td->td_imagewidth;
+
+	(void) s;
+	assert(sp != NULL);
+	sp->stream.next_out = (unsigned char *) sp->tbuf;
+	assert(sizeof(sp->stream.avail_out)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_out = (uInt) (nsamples * sizeof(uint16));
+	if (sp->stream.avail_out != nsamples * sizeof(uint16))
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	do {
+		int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
+		if (state == Z_STREAM_END) {
+			break;			/* XXX */
+		}
+		if (state == Z_DATA_ERROR) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Decoding error at scanline %lu, %s",
+			    (unsigned long) tif->tif_row, sp->stream.msg);
+			if (inflateSync(&sp->stream) != Z_OK)
+				return (0);
+			continue;
+		}
+		if (state != Z_OK) {
+			TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+			    sp->stream.msg);
+			return (0);
+		}
+	} while (sp->stream.avail_out > 0);
+
+	/* hopefully, we got all the bytes we needed */
+	if (sp->stream.avail_out != 0) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Not enough data at scanline %lu (short " TIFF_UINT64_FORMAT " bytes)",
+		    (unsigned long) tif->tif_row, (TIFF_UINT64_T) sp->stream.avail_out);
+		return (0);
+	}
+
+	up = sp->tbuf;
+	/* Swap bytes in the data if from a different endian machine. */
+	if (tif->tif_flags & TIFF_SWAB)
+		TIFFSwabArrayOfShort(up, nsamples);
+
+	/*
+	 * if llen is not an exact multiple of nsamples, the decode operation
+	 * may overflow the output buffer, so truncate it enough to prevent
+	 * that but still salvage as much data as possible.
+	 */
+	if (nsamples % llen) { 
+		TIFFWarningExt(tif->tif_clientdata, module,
+			"stride %lu is not a multiple of sample count, "
+			"%lu, data truncated.", (unsigned long) llen, (unsigned long) nsamples);
+		nsamples -= nsamples % llen;
+	}
+
+	for (i = 0; i < nsamples; i += llen, up += llen) {
+		switch (sp->user_datafmt)  {
+		case PIXARLOGDATAFMT_FLOAT:
+			horizontalAccumulateF(up, llen, sp->stride,
+					(float *)op, sp->ToLinearF);
+			op += llen * sizeof(float);
+			break;
+		case PIXARLOGDATAFMT_16BIT:
+			horizontalAccumulate16(up, llen, sp->stride,
+					(uint16 *)op, sp->ToLinear16);
+			op += llen * sizeof(uint16);
+			break;
+		case PIXARLOGDATAFMT_12BITPICIO:
+			horizontalAccumulate12(up, llen, sp->stride,
+					(int16 *)op, sp->ToLinearF);
+			op += llen * sizeof(int16);
+			break;
+		case PIXARLOGDATAFMT_11BITLOG:
+			horizontalAccumulate11(up, llen, sp->stride,
+					(uint16 *)op);
+			op += llen * sizeof(uint16);
+			break;
+		case PIXARLOGDATAFMT_8BIT:
+			horizontalAccumulate8(up, llen, sp->stride,
+					(unsigned char *)op, sp->ToLinear8);
+			op += llen * sizeof(unsigned char);
+			break;
+		case PIXARLOGDATAFMT_8BITABGR:
+			horizontalAccumulate8abgr(up, llen, sp->stride,
+					(unsigned char *)op, sp->ToLinear8);
+			op += llen * sizeof(unsigned char);
+			break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, module,
+				  "Unsupported bits/sample: %d",
+				  td->td_bitspersample);
+			return (0);
+		}
+	}
+
+	return (1);
+}
+
+static int
+PixarLogSetupEncode(TIFF* tif)
+{
+	static const char module[] = "PixarLogSetupEncode";
+	TIFFDirectory *td = &tif->tif_dir;
+	PixarLogState* sp = EncoderState(tif);
+	tmsize_t tbuf_size;
+
+	assert(sp != NULL);
+
+	/* for some reason, we can't do this in TIFFInitPixarLog */
+
+	sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+	    td->td_samplesperpixel : 1);
+	tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth),
+				      td->td_rowsperstrip), sizeof(uint16));
+	if (tbuf_size == 0)
+		return (0);  /* TODO: this is an error return without error report through TIFFErrorExt */
+	sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size);
+	if (sp->tbuf == NULL)
+		return (0);
+	if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
+		sp->user_datafmt = PixarLogGuessDataFmt(td);
+	if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) {
+		TIFFErrorExt(tif->tif_clientdata, module, "PixarLog compression can't handle %d bit linear encodings", td->td_bitspersample);
+		return (0);
+	}
+
+	if (deflateInit(&sp->stream, sp->quality) != Z_OK) {
+		TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg);
+		return (0);
+	} else {
+		sp->state |= PLSTATE_INIT;
+		return (1);
+	}
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+PixarLogPreEncode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "PixarLogPreEncode";
+	PixarLogState *sp = EncoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	sp->stream.next_out = tif->tif_rawdata;
+	assert(sizeof(sp->stream.avail_out)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_out = (uInt)tif->tif_rawdatasize;
+	if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	return (deflateReset(&sp->stream) == Z_OK);
+}
+
+static void
+horizontalDifferenceF(float *ip, int n, int stride, uint16 *wp, uint16 *FromLT2)
+{
+    int32 r1, g1, b1, a1, r2, g2, b2, a2, mask;
+    float fltsize = Fltsize;
+
+#define  CLAMP(v) ( (v<(float)0.)   ? 0				\
+		  : (v<(float)2.)   ? FromLT2[(int)(v*fltsize)]	\
+		  : (v>(float)24.2) ? 2047			\
+		  : LogK1*log(v*LogK2) + 0.5 )
+
+    mask = CODE_MASK;
+    if (n >= stride) {
+	if (stride == 3) {
+	    r2 = wp[0] = (uint16) CLAMP(ip[0]);
+	    g2 = wp[1] = (uint16) CLAMP(ip[1]);
+	    b2 = wp[2] = (uint16) CLAMP(ip[2]);
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		wp += 3;
+		ip += 3;
+		r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1;
+		g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1;
+		b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1;
+	    }
+	} else if (stride == 4) {
+	    r2 = wp[0] = (uint16) CLAMP(ip[0]);
+	    g2 = wp[1] = (uint16) CLAMP(ip[1]);
+	    b2 = wp[2] = (uint16) CLAMP(ip[2]);
+	    a2 = wp[3] = (uint16) CLAMP(ip[3]);
+	    n -= 4;
+	    while (n > 0) {
+		n -= 4;
+		wp += 4;
+		ip += 4;
+		r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1;
+		g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1;
+		b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1;
+		a1 = (int32) CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1;
+	    }
+	} else {
+	    ip += n - 1;	/* point to last one */
+	    wp += n - 1;	/* point to last one */
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]);
+				wp[stride] -= wp[0];
+				wp[stride] &= mask;
+				wp--; ip--)
+		n -= stride;
+	    }
+	    REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); wp--; ip--)
+	}
+    }
+}
+
+static void
+horizontalDifference16(unsigned short *ip, int n, int stride, 
+	unsigned short *wp, uint16 *From14)
+{
+    register int  r1, g1, b1, a1, r2, g2, b2, a2, mask;
+
+/* assumption is unsigned pixel values */
+#undef   CLAMP
+#define  CLAMP(v) From14[(v) >> 2]
+
+    mask = CODE_MASK;
+    if (n >= stride) {
+	if (stride == 3) {
+	    r2 = wp[0] = CLAMP(ip[0]);  g2 = wp[1] = CLAMP(ip[1]);
+	    b2 = wp[2] = CLAMP(ip[2]);
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		wp += 3;
+		ip += 3;
+		r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1;
+		g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1;
+		b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1;
+	    }
+	} else if (stride == 4) {
+	    r2 = wp[0] = CLAMP(ip[0]);  g2 = wp[1] = CLAMP(ip[1]);
+	    b2 = wp[2] = CLAMP(ip[2]);  a2 = wp[3] = CLAMP(ip[3]);
+	    n -= 4;
+	    while (n > 0) {
+		n -= 4;
+		wp += 4;
+		ip += 4;
+		r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1;
+		g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1;
+		b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1;
+		a1 = CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1;
+	    }
+	} else {
+	    ip += n - 1;	/* point to last one */
+	    wp += n - 1;	/* point to last one */
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride, wp[0] = CLAMP(ip[0]);
+				wp[stride] -= wp[0];
+				wp[stride] &= mask;
+				wp--; ip--)
+		n -= stride;
+	    }
+	    REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--)
+	}
+    }
+}
+
+
+static void
+horizontalDifference8(unsigned char *ip, int n, int stride, 
+	unsigned short *wp, uint16 *From8)
+{
+    register int  r1, g1, b1, a1, r2, g2, b2, a2, mask;
+
+#undef	 CLAMP
+#define  CLAMP(v) (From8[(v)])
+
+    mask = CODE_MASK;
+    if (n >= stride) {
+	if (stride == 3) {
+	    r2 = wp[0] = CLAMP(ip[0]);  g2 = wp[1] = CLAMP(ip[1]);
+	    b2 = wp[2] = CLAMP(ip[2]);
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		r1 = CLAMP(ip[3]); wp[3] = (r1-r2) & mask; r2 = r1;
+		g1 = CLAMP(ip[4]); wp[4] = (g1-g2) & mask; g2 = g1;
+		b1 = CLAMP(ip[5]); wp[5] = (b1-b2) & mask; b2 = b1;
+		wp += 3;
+		ip += 3;
+	    }
+	} else if (stride == 4) {
+	    r2 = wp[0] = CLAMP(ip[0]);  g2 = wp[1] = CLAMP(ip[1]);
+	    b2 = wp[2] = CLAMP(ip[2]);  a2 = wp[3] = CLAMP(ip[3]);
+	    n -= 4;
+	    while (n > 0) {
+		n -= 4;
+		r1 = CLAMP(ip[4]); wp[4] = (r1-r2) & mask; r2 = r1;
+		g1 = CLAMP(ip[5]); wp[5] = (g1-g2) & mask; g2 = g1;
+		b1 = CLAMP(ip[6]); wp[6] = (b1-b2) & mask; b2 = b1;
+		a1 = CLAMP(ip[7]); wp[7] = (a1-a2) & mask; a2 = a1;
+		wp += 4;
+		ip += 4;
+	    }
+	} else {
+	    wp += n + stride - 1;	/* point to last one */
+	    ip += n + stride - 1;	/* point to last one */
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride, wp[0] = CLAMP(ip[0]);
+				wp[stride] -= wp[0];
+				wp[stride] &= mask;
+				wp--; ip--)
+		n -= stride;
+	    }
+	    REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--)
+	}
+    }
+}
+
+/*
+ * Encode a chunk of pixels.
+ */
+static int
+PixarLogEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "PixarLogEncode";
+	TIFFDirectory *td = &tif->tif_dir;
+	PixarLogState *sp = EncoderState(tif);
+	tmsize_t i;
+	tmsize_t n;
+	int llen;
+	unsigned short * up;
+
+	(void) s;
+
+	switch (sp->user_datafmt) {
+	case PIXARLOGDATAFMT_FLOAT:
+		n = cc / sizeof(float);		/* XXX float == 32 bits */
+		break;
+	case PIXARLOGDATAFMT_16BIT:
+	case PIXARLOGDATAFMT_12BITPICIO:
+	case PIXARLOGDATAFMT_11BITLOG:
+		n = cc / sizeof(uint16);	/* XXX uint16 == 16 bits */
+		break;
+	case PIXARLOGDATAFMT_8BIT:
+	case PIXARLOGDATAFMT_8BITABGR:
+		n = cc;
+		break;
+	default:
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"%d bit input not supported in PixarLog",
+			td->td_bitspersample);
+		return 0;
+	}
+
+	llen = sp->stride * td->td_imagewidth;
+
+	for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen) {
+		switch (sp->user_datafmt)  {
+		case PIXARLOGDATAFMT_FLOAT:
+			horizontalDifferenceF((float *)bp, llen, 
+				sp->stride, up, sp->FromLT2);
+			bp += llen * sizeof(float);
+			break;
+		case PIXARLOGDATAFMT_16BIT:
+			horizontalDifference16((uint16 *)bp, llen, 
+				sp->stride, up, sp->From14);
+			bp += llen * sizeof(uint16);
+			break;
+		case PIXARLOGDATAFMT_8BIT:
+			horizontalDifference8((unsigned char *)bp, llen, 
+				sp->stride, up, sp->From8);
+			bp += llen * sizeof(unsigned char);
+			break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%d bit input not supported in PixarLog",
+				td->td_bitspersample);
+			return 0;
+		}
+	}
+ 
+	sp->stream.next_in = (unsigned char *) sp->tbuf;
+	assert(sizeof(sp->stream.avail_in)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_in = (uInt) (n * sizeof(uint16));
+	if ((sp->stream.avail_in / sizeof(uint16)) != (uInt) n)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+
+	do {
+		if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Encoder error: %s",
+			    sp->stream.msg);
+			return (0);
+		}
+		if (sp->stream.avail_out == 0) {
+			tif->tif_rawcc = tif->tif_rawdatasize;
+			TIFFFlushData1(tif);
+			sp->stream.next_out = tif->tif_rawdata;
+			sp->stream.avail_out = (uInt) tif->tif_rawdatasize;  /* this is a safe typecast, as check is made already in PixarLogPreEncode */
+		}
+	} while (sp->stream.avail_in > 0);
+	return (1);
+}
+
+/*
+ * Finish off an encoded strip by flushing the last
+ * string and tacking on an End Of Information code.
+ */
+
+static int
+PixarLogPostEncode(TIFF* tif)
+{
+	static const char module[] = "PixarLogPostEncode";
+	PixarLogState *sp = EncoderState(tif);
+	int state;
+
+	sp->stream.avail_in = 0;
+
+	do {
+		state = deflate(&sp->stream, Z_FINISH);
+		switch (state) {
+		case Z_STREAM_END:
+		case Z_OK:
+		    if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) {
+			    tif->tif_rawcc =
+				tif->tif_rawdatasize - sp->stream.avail_out;
+			    TIFFFlushData1(tif);
+			    sp->stream.next_out = tif->tif_rawdata;
+			    sp->stream.avail_out = (uInt) tif->tif_rawdatasize;  /* this is a safe typecast, as check is made already in PixarLogPreEncode */
+		    }
+		    break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+			sp->stream.msg);
+		    return (0);
+		}
+	} while (state != Z_STREAM_END);
+	return (1);
+}
+
+static void
+PixarLogClose(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+	/* In a really sneaky (and really incorrect, and untruthfull, and
+	 * troublesome, and error-prone) maneuver that completely goes against
+	 * the spirit of TIFF, and breaks TIFF, on close, we covertly
+	 * modify both bitspersample and sampleformat in the directory to
+	 * indicate 8-bit linear.  This way, the decode "just works" even for
+	 * readers that don't know about PixarLog, or how to set
+	 * the PIXARLOGDATFMT pseudo-tag.
+	 */
+	td->td_bitspersample = 8;
+	td->td_sampleformat = SAMPLEFORMAT_UINT;
+}
+
+static void
+PixarLogCleanup(TIFF* tif)
+{
+	PixarLogState* sp = (PixarLogState*) tif->tif_data;
+
+	assert(sp != 0);
+
+	(void)TIFFPredictorCleanup(tif);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+	if (sp->FromLT2) _TIFFfree(sp->FromLT2);
+	if (sp->From14) _TIFFfree(sp->From14);
+	if (sp->From8) _TIFFfree(sp->From8);
+	if (sp->ToLinearF) _TIFFfree(sp->ToLinearF);
+	if (sp->ToLinear16) _TIFFfree(sp->ToLinear16);
+	if (sp->ToLinear8) _TIFFfree(sp->ToLinear8);
+	if (sp->state&PLSTATE_INIT) {
+		if (tif->tif_mode == O_RDONLY)
+			inflateEnd(&sp->stream);
+		else
+			deflateEnd(&sp->stream);
+	}
+	if (sp->tbuf)
+		_TIFFfree(sp->tbuf);
+	_TIFFfree(sp);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+PixarLogVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+    static const char module[] = "PixarLogVSetField";
+    PixarLogState *sp = (PixarLogState *)tif->tif_data;
+    int result;
+
+    switch (tag) {
+     case TIFFTAG_PIXARLOGQUALITY:
+		sp->quality = (int) va_arg(ap, int);
+		if (tif->tif_mode != O_RDONLY && (sp->state&PLSTATE_INIT)) {
+			if (deflateParams(&sp->stream,
+			    sp->quality, Z_DEFAULT_STRATEGY) != Z_OK) {
+				TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+					sp->stream.msg);
+				return (0);
+			}
+		}
+		return (1);
+     case TIFFTAG_PIXARLOGDATAFMT:
+	sp->user_datafmt = (int) va_arg(ap, int);
+	/* Tweak the TIFF header so that the rest of libtiff knows what
+	 * size of data will be passed between app and library, and
+	 * assume that the app knows what it is doing and is not
+	 * confused by these header manipulations...
+	 */
+	switch (sp->user_datafmt) {
+	 case PIXARLOGDATAFMT_8BIT:
+	 case PIXARLOGDATAFMT_8BITABGR:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+	    break;
+	 case PIXARLOGDATAFMT_11BITLOG:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+	    break;
+	 case PIXARLOGDATAFMT_12BITPICIO:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
+	    break;
+	 case PIXARLOGDATAFMT_16BIT:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+	    break;
+	 case PIXARLOGDATAFMT_FLOAT:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
+	    break;
+	}
+	/*
+	 * Must recalculate sizes should bits/sample change.
+	 */
+	tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1);
+	tif->tif_scanlinesize = TIFFScanlineSize(tif);
+	result = 1;		/* NB: pseudo tag */
+	break;
+     default:
+	result = (*sp->vsetparent)(tif, tag, ap);
+    }
+    return (result);
+}
+
+static int
+PixarLogVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+    PixarLogState *sp = (PixarLogState *)tif->tif_data;
+
+    switch (tag) {
+     case TIFFTAG_PIXARLOGQUALITY:
+	*va_arg(ap, int*) = sp->quality;
+	break;
+     case TIFFTAG_PIXARLOGDATAFMT:
+	*va_arg(ap, int*) = sp->user_datafmt;
+	break;
+     default:
+	return (*sp->vgetparent)(tif, tag, ap);
+    }
+    return (1);
+}
+
+static const TIFFField pixarlogFields[] = {
+    {TIFFTAG_PIXARLOGDATAFMT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL},
+    {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}
+};
+
+int
+TIFFInitPixarLog(TIFF* tif, int scheme)
+{
+	static const char module[] = "TIFFInitPixarLog";
+
+	PixarLogState* sp;
+
+	assert(scheme == COMPRESSION_PIXARLOG);
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, pixarlogFields,
+			      TIFFArrayCount(pixarlogFields))) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Merging PixarLog codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (PixarLogState));
+	if (tif->tif_data == NULL)
+		goto bad;
+	sp = (PixarLogState*) tif->tif_data;
+	_TIFFmemset(sp, 0, sizeof (*sp));
+	sp->stream.data_type = Z_BINARY;
+	sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = PixarLogFixupTags; 
+	tif->tif_setupdecode = PixarLogSetupDecode;
+	tif->tif_predecode = PixarLogPreDecode;
+	tif->tif_decoderow = PixarLogDecode;
+	tif->tif_decodestrip = PixarLogDecode;  
+	tif->tif_decodetile = PixarLogDecode;
+	tif->tif_setupencode = PixarLogSetupEncode;
+	tif->tif_preencode = PixarLogPreEncode;
+	tif->tif_postencode = PixarLogPostEncode;
+	tif->tif_encoderow = PixarLogEncode;  
+	tif->tif_encodestrip = PixarLogEncode;
+	tif->tif_encodetile = PixarLogEncode;  
+	tif->tif_close = PixarLogClose;
+	tif->tif_cleanup = PixarLogCleanup;
+
+	/* Override SetField so we can handle our private pseudo-tag */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield = PixarLogVGetField;   /* hook for codec tags */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield = PixarLogVSetField;   /* hook for codec tags */
+
+	/* Default values for codec-specific fields */
+	sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */
+	sp->state = 0;
+
+	/* we don't wish to use the predictor, 
+	 * the default is none, which predictor value 1
+	 */
+	(void) TIFFPredictorInit(tif);
+
+	/*
+	 * build the companding tables 
+	 */
+	PixarLogMakeTables(sp);
+
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module,
+		     "No space for PixarLog state block");
+	return (0);
+}
+#endif /* PIXARLOG_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.c
new file mode 100644
index 0000000..190d016
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.c
@@ -0,0 +1,813 @@
+/* $Id: tif_predict.c,v 1.32 2010-03-10 18:56:49 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Predictor Tag Support (used by multiple codecs).
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include "tif_predict.h"
+
+#define	PredictorState(tif)	((TIFFPredictorState*) (tif)->tif_data)
+
+static void horAcc8(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horAcc16(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horAcc32(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void swabHorAcc16(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void swabHorAcc32(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horDiff8(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horDiff16(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horDiff32(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void fpAcc(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void fpDiff(TIFF* tif, uint8* cp0, tmsize_t cc);
+static int PredictorDecodeRow(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s);
+static int PredictorDecodeTile(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s);
+static int PredictorEncodeRow(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
+static int PredictorEncodeTile(TIFF* tif, uint8* bp0, tmsize_t cc0, uint16 s);
+
+static int
+PredictorSetup(TIFF* tif)
+{
+	static const char module[] = "PredictorSetup";
+
+	TIFFPredictorState* sp = PredictorState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	switch (sp->predictor)		/* no differencing */
+	{
+		case PREDICTOR_NONE:
+			return 1;
+		case PREDICTOR_HORIZONTAL:
+			if (td->td_bitspersample != 8
+			    && td->td_bitspersample != 16
+			    && td->td_bitspersample != 32) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Horizontal differencing \"Predictor\" not supported with %d-bit samples",
+				    td->td_bitspersample);
+				return 0;
+			}
+			break;
+		case PREDICTOR_FLOATINGPOINT:
+			if (td->td_sampleformat != SAMPLEFORMAT_IEEEFP) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Floating point \"Predictor\" not supported with %d data format",
+				    td->td_sampleformat);
+				return 0;
+			}
+			break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "\"Predictor\" value %d not supported",
+			    sp->predictor);
+			return 0;
+	}
+	sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+	    td->td_samplesperpixel : 1);
+	/*
+	 * Calculate the scanline/tile-width size in bytes.
+	 */
+	if (isTiled(tif))
+		sp->rowsize = TIFFTileRowSize(tif);
+	else
+		sp->rowsize = TIFFScanlineSize(tif);
+	if (sp->rowsize == 0)
+		return 0;
+
+	return 1;
+}
+
+static int
+PredictorSetupDecode(TIFF* tif)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif))
+		return 0;
+
+	if (sp->predictor == 2) {
+		switch (td->td_bitspersample) {
+			case 8:  sp->decodepfunc = horAcc8; break;
+			case 16: sp->decodepfunc = horAcc16; break;
+			case 32: sp->decodepfunc = horAcc32; break;
+		}
+		/*
+		 * Override default decoding method with one that does the
+		 * predictor stuff.
+		 */
+                if( tif->tif_decoderow != PredictorDecodeRow )
+                {
+                    sp->decoderow = tif->tif_decoderow;
+                    tif->tif_decoderow = PredictorDecodeRow;
+                    sp->decodestrip = tif->tif_decodestrip;
+                    tif->tif_decodestrip = PredictorDecodeTile;
+                    sp->decodetile = tif->tif_decodetile;
+                    tif->tif_decodetile = PredictorDecodeTile;
+                }
+
+		/*
+		 * If the data is horizontally differenced 16-bit data that
+		 * requires byte-swapping, then it must be byte swapped before
+		 * the accumulation step.  We do this with a special-purpose
+		 * routine and override the normal post decoding logic that
+		 * the library setup when the directory was read.
+		 */
+		if (tif->tif_flags & TIFF_SWAB) {
+			if (sp->decodepfunc == horAcc16) {
+				sp->decodepfunc = swabHorAcc16;
+				tif->tif_postdecode = _TIFFNoPostDecode;
+            } else if (sp->decodepfunc == horAcc32) {
+				sp->decodepfunc = swabHorAcc32;
+				tif->tif_postdecode = _TIFFNoPostDecode;
+            }
+		}
+	}
+
+	else if (sp->predictor == 3) {
+		sp->decodepfunc = fpAcc;
+		/*
+		 * Override default decoding method with one that does the
+		 * predictor stuff.
+		 */
+                if( tif->tif_decoderow != PredictorDecodeRow )
+                {
+                    sp->decoderow = tif->tif_decoderow;
+                    tif->tif_decoderow = PredictorDecodeRow;
+                    sp->decodestrip = tif->tif_decodestrip;
+                    tif->tif_decodestrip = PredictorDecodeTile;
+                    sp->decodetile = tif->tif_decodetile;
+                    tif->tif_decodetile = PredictorDecodeTile;
+                }
+		/*
+		 * The data should not be swapped outside of the floating
+		 * point predictor, the accumulation routine should return
+		 * byres in the native order.
+		 */
+		if (tif->tif_flags & TIFF_SWAB) {
+			tif->tif_postdecode = _TIFFNoPostDecode;
+		}
+		/*
+		 * Allocate buffer to keep the decoded bytes before
+		 * rearranging in the ight order
+		 */
+	}
+
+	return 1;
+}
+
+static int
+PredictorSetupEncode(TIFF* tif)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	if (!(*sp->setupencode)(tif) || !PredictorSetup(tif))
+		return 0;
+
+	if (sp->predictor == 2) {
+		switch (td->td_bitspersample) {
+			case 8:  sp->encodepfunc = horDiff8; break;
+			case 16: sp->encodepfunc = horDiff16; break;
+			case 32: sp->encodepfunc = horDiff32; break;
+		}
+		/*
+		 * Override default encoding method with one that does the
+		 * predictor stuff.
+		 */
+                if( tif->tif_encoderow != PredictorEncodeRow )
+                {
+                    sp->encoderow = tif->tif_encoderow;
+                    tif->tif_encoderow = PredictorEncodeRow;
+                    sp->encodestrip = tif->tif_encodestrip;
+                    tif->tif_encodestrip = PredictorEncodeTile;
+                    sp->encodetile = tif->tif_encodetile;
+                    tif->tif_encodetile = PredictorEncodeTile;
+                }
+	}
+
+	else if (sp->predictor == 3) {
+		sp->encodepfunc = fpDiff;
+		/*
+		 * Override default encoding method with one that does the
+		 * predictor stuff.
+		 */
+                if( tif->tif_encoderow != PredictorEncodeRow )
+                {
+                    sp->encoderow = tif->tif_encoderow;
+                    tif->tif_encoderow = PredictorEncodeRow;
+                    sp->encodestrip = tif->tif_encodestrip;
+                    tif->tif_encodestrip = PredictorEncodeTile;
+                    sp->encodetile = tif->tif_encodetile;
+                    tif->tif_encodetile = PredictorEncodeTile;
+                }
+	}
+
+	return 1;
+}
+
+#define REPEAT4(n, op)		\
+    switch (n) {		\
+    default: { tmsize_t i; for (i = n-4; i > 0; i--) { op; } } \
+    case 4:  op;		\
+    case 3:  op;		\
+    case 2:  op;		\
+    case 1:  op;		\
+    case 0:  ;			\
+    }
+
+static void
+horAcc8(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	/*
+	 * compare v4.0.3 with v3.9.5, 
+	 * we find that horAcc8 uses while loop in the v4.0.3 and uses do while loop in the v3.9.5.
+	 * times of do while loop are less than while loop, so we use v3.9.5 instead of v4.0.3.
+	 */
+#if 0
+	tmsize_t stride = PredictorState(tif)->stride;
+
+	char* cp = (char*) cp0;
+	assert((cc%stride)==0);
+	if (cc > stride) {
+		/*
+		 * Pipeline the most common cases.
+		 */
+		if (stride == 3)  {
+			unsigned int cr = cp[0];
+			unsigned int cg = cp[1];
+			unsigned int cb = cp[2];
+			cc -= 3;
+			cp += 3;
+			while (cc>0) {
+				cp[0] = (char) (cr += cp[0]);
+				cp[1] = (char) (cg += cp[1]);
+				cp[2] = (char) (cb += cp[2]);
+				cc -= 3;
+				cp += 3;
+			}
+		} else if (stride == 4)  {
+			unsigned int cr = cp[0];
+			unsigned int cg = cp[1];
+			unsigned int cb = cp[2];
+			unsigned int ca = cp[3];
+			cc -= 4;
+			cp += 4;
+			while (cc>0) {
+				cp[0] = (char) (cr += cp[0]);
+				cp[1] = (char) (cg += cp[1]);
+				cp[2] = (char) (cb += cp[2]);
+				cp[3] = (char) (ca += cp[3]);
+				cc -= 4;
+				cp += 4;
+			}
+		} else  {
+			cc -= stride;
+			do {
+				REPEAT4(stride, cp[stride] =
+					(char) (cp[stride] + *cp); cp++)
+				cc -= stride;
+			} while (cc>0);
+		}
+	}
+#else
+	tsize_t stride = PredictorState(tif)->stride;
+
+	char* cp = (char*) cp0;
+	if (cc > stride) {
+		cc -= stride;
+		/*
+		 * Pipeline the most common cases.
+		 */
+		if (stride == 3)  {
+			unsigned int cr = cp[0];
+			unsigned int cg = cp[1];
+			unsigned int cb = cp[2];
+			do {
+				cc -= 3, cp += 3;
+				cp[0] = (char) (cr += cp[0]);
+				cp[1] = (char) (cg += cp[1]);
+				cp[2] = (char) (cb += cp[2]);
+			} while ((int32) cc > 0);
+		} else if (stride == 4)  {
+			unsigned int cr = cp[0];
+			unsigned int cg = cp[1];
+			unsigned int cb = cp[2];
+			unsigned int ca = cp[3];
+			do {
+				cc -= 4, cp += 4;
+				cp[0] = (char) (cr += cp[0]);
+				cp[1] = (char) (cg += cp[1]);
+				cp[2] = (char) (cb += cp[2]);
+				cp[3] = (char) (ca += cp[3]);
+			} while ((int32) cc > 0);
+		} else  {
+			do {
+				REPEAT4(stride, cp[stride] =
+					(char) (cp[stride] + *cp); cp++)
+				cc -= stride;
+			} while ((int32) cc > 0);
+		}
+	}
+#endif
+}
+
+static void
+swabHorAcc16(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint16* wp = (uint16*) cp0;
+	tmsize_t wc = cc / 2;
+
+	assert((cc%(2*stride))==0);
+
+	if (wc > stride) {
+		TIFFSwabArrayOfShort(wp, wc);
+		wc -= stride;
+		do {
+			REPEAT4(stride, wp[stride] += wp[0]; wp++)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+static void
+horAcc16(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint16* wp = (uint16*) cp0;
+	tmsize_t wc = cc / 2;
+
+	assert((cc%(2*stride))==0);
+
+	if (wc > stride) {
+		wc -= stride;
+		do {
+			REPEAT4(stride, wp[stride] += wp[0]; wp++)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+static void
+swabHorAcc32(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint32* wp = (uint32*) cp0;
+	tmsize_t wc = cc / 4;
+
+	assert((cc%(4*stride))==0);
+
+	if (wc > stride) {
+		TIFFSwabArrayOfLong(wp, wc);
+		wc -= stride;
+		do {
+			REPEAT4(stride, wp[stride] += wp[0]; wp++)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+static void
+horAcc32(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint32* wp = (uint32*) cp0;
+	tmsize_t wc = cc / 4;
+
+	assert((cc%(4*stride))==0);
+
+	if (wc > stride) {
+		wc -= stride;
+		do {
+			REPEAT4(stride, wp[stride] += wp[0]; wp++)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+/*
+ * Floating point predictor accumulation routine.
+ */
+static void
+fpAcc(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint32 bps = tif->tif_dir.td_bitspersample / 8;
+	tmsize_t wc = cc / bps;
+	tmsize_t count = cc;
+	uint8 *cp = (uint8 *) cp0;
+	uint8 *tmp = (uint8 *)_TIFFmalloc(cc);
+
+	assert((cc%(bps*stride))==0);
+
+	if (!tmp)
+		return;
+
+	while (count > stride) {
+		REPEAT4(stride, cp[stride] += cp[0]; cp++)
+		count -= stride;
+	}
+
+	_TIFFmemcpy(tmp, cp0, cc);
+	cp = (uint8 *) cp0;
+	for (count = 0; count < wc; count++) {
+		uint32 byte;
+		for (byte = 0; byte < bps; byte++) {
+			#if WORDS_BIGENDIAN
+			cp[bps * count + byte] = tmp[byte * wc + count];
+			#else
+			cp[bps * count + byte] =
+				tmp[(bps - byte - 1) * wc + count];
+			#endif
+		}
+	}
+	_TIFFfree(tmp);
+}
+
+/*
+ * Decode a scanline and apply the predictor routine.
+ */
+static int
+PredictorDecodeRow(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s)
+{
+	TIFFPredictorState *sp = PredictorState(tif);
+
+	assert(sp != NULL);
+	assert(sp->decoderow != NULL);
+	assert(sp->decodepfunc != NULL);  
+
+	if ((*sp->decoderow)(tif, op0, occ0, s)) {
+		(*sp->decodepfunc)(tif, op0, occ0);
+		return 1;
+	} else
+		return 0;
+}
+
+/*
+ * Decode a tile/strip and apply the predictor routine.
+ * Note that horizontal differencing must be done on a
+ * row-by-row basis.  The width of a "row" has already
+ * been calculated at pre-decode time according to the
+ * strip/tile dimensions.
+ */
+static int
+PredictorDecodeTile(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s)
+{
+	TIFFPredictorState *sp = PredictorState(tif);
+
+	assert(sp != NULL);
+	assert(sp->decodetile != NULL);
+
+	if ((*sp->decodetile)(tif, op0, occ0, s)) {
+		tmsize_t rowsize = sp->rowsize;
+		assert(rowsize > 0);
+		assert((occ0%rowsize)==0);
+		assert(sp->decodepfunc != NULL);
+		while (occ0 > 0) {
+			(*sp->decodepfunc)(tif, op0, rowsize);
+			occ0 -= rowsize;
+			op0 += rowsize;
+		}
+		return 1;
+	} else
+		return 0;
+}
+
+static void
+horDiff8(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	tmsize_t stride = sp->stride;
+	char* cp = (char*) cp0;
+
+	assert((cc%stride)==0);
+
+	if (cc > stride) {
+		cc -= stride;
+		/*
+		 * Pipeline the most common cases.
+		 */
+		if (stride == 3) {
+			int r1, g1, b1;
+			int r2 = cp[0];
+			int g2 = cp[1];
+			int b2 = cp[2];
+			do {
+				r1 = cp[3]; cp[3] = r1-r2; r2 = r1;
+				g1 = cp[4]; cp[4] = g1-g2; g2 = g1;
+				b1 = cp[5]; cp[5] = b1-b2; b2 = b1;
+				cp += 3;
+			} while ((cc -= 3) > 0);
+		} else if (stride == 4) {
+			int r1, g1, b1, a1;
+			int r2 = cp[0];
+			int g2 = cp[1];
+			int b2 = cp[2];
+			int a2 = cp[3];
+			do {
+				r1 = cp[4]; cp[4] = r1-r2; r2 = r1;
+				g1 = cp[5]; cp[5] = g1-g2; g2 = g1;
+				b1 = cp[6]; cp[6] = b1-b2; b2 = b1;
+				a1 = cp[7]; cp[7] = a1-a2; a2 = a1;
+				cp += 4;
+			} while ((cc -= 4) > 0);
+		} else {
+			cp += cc - 1;
+			do {
+				REPEAT4(stride, cp[stride] -= cp[0]; cp--)
+			} while ((cc -= stride) > 0);
+		}
+	}
+}
+
+static void
+horDiff16(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	tmsize_t stride = sp->stride;
+	int16 *wp = (int16*) cp0;
+	tmsize_t wc = cc/2;
+
+	assert((cc%(2*stride))==0);
+
+	if (wc > stride) {
+		wc -= stride;
+		wp += wc - 1;
+		do {
+			REPEAT4(stride, wp[stride] -= wp[0]; wp--)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+static void
+horDiff32(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	tmsize_t stride = sp->stride;
+	int32 *wp = (int32*) cp0;
+	tmsize_t wc = cc/4;
+
+	assert((cc%(4*stride))==0);
+
+	if (wc > stride) {
+		wc -= stride;
+		wp += wc - 1;
+		do {
+			REPEAT4(stride, wp[stride] -= wp[0]; wp--)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+/*
+ * Floating point predictor differencing routine.
+ */
+static void
+fpDiff(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint32 bps = tif->tif_dir.td_bitspersample / 8;
+	tmsize_t wc = cc / bps;
+	tmsize_t count;
+	uint8 *cp = (uint8 *) cp0;
+	uint8 *tmp = (uint8 *)_TIFFmalloc(cc);
+
+	assert((cc%(bps*stride))==0);
+
+	if (!tmp)
+		return;
+
+	_TIFFmemcpy(tmp, cp0, cc);
+	for (count = 0; count < wc; count++) {
+		uint32 byte;
+		for (byte = 0; byte < bps; byte++) {
+			#if WORDS_BIGENDIAN
+			cp[byte * wc + count] = tmp[bps * count + byte];
+			#else
+			cp[(bps - byte - 1) * wc + count] =
+				tmp[bps * count + byte];
+			#endif
+		}
+	}
+	_TIFFfree(tmp);
+
+	cp = (uint8 *) cp0;
+	cp += cc - stride - 1;
+	for (count = cc; count > stride; count -= stride)
+		REPEAT4(stride, cp[stride] -= cp[0]; cp--)
+}
+
+static int
+PredictorEncodeRow(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	TIFFPredictorState *sp = PredictorState(tif);
+
+	assert(sp != NULL);
+	assert(sp->encodepfunc != NULL);
+	assert(sp->encoderow != NULL);
+
+	/* XXX horizontal differencing alters user's data XXX */
+	(*sp->encodepfunc)(tif, bp, cc);
+	return (*sp->encoderow)(tif, bp, cc, s);
+}
+
+static int
+PredictorEncodeTile(TIFF* tif, uint8* bp0, tmsize_t cc0, uint16 s)
+{
+	static const char module[] = "PredictorEncodeTile";
+	TIFFPredictorState *sp = PredictorState(tif);
+        uint8 *working_copy;
+	tmsize_t cc = cc0, rowsize;
+	unsigned char* bp;
+        int result_code;
+
+	assert(sp != NULL);
+	assert(sp->encodepfunc != NULL);
+	assert(sp->encodetile != NULL);
+
+        /* 
+         * Do predictor manipulation in a working buffer to avoid altering
+         * the callers buffer. http://trac.osgeo.org/gdal/ticket/1965
+         */
+        working_copy = (uint8*) _TIFFmalloc(cc0);
+        if( working_copy == NULL )
+        {
+            TIFFErrorExt(tif->tif_clientdata, module, 
+                         "Out of memory allocating " TIFF_SSIZE_FORMAT " byte temp buffer.",
+                         cc0 );
+            return 0;
+        }
+        memcpy( working_copy, bp0, cc0 );
+        bp = working_copy;
+
+	rowsize = sp->rowsize;
+	assert(rowsize > 0);
+	assert((cc0%rowsize)==0);
+	while (cc > 0) {
+		(*sp->encodepfunc)(tif, bp, rowsize);
+		cc -= rowsize;
+		bp += rowsize;
+	}
+	result_code = (*sp->encodetile)(tif, working_copy, cc0, s);
+
+        _TIFFfree( working_copy );
+
+        return result_code;
+}
+
+#define	FIELD_PREDICTOR	(FIELD_CODEC+0)		/* XXX */
+
+static const TIFFField predictFields[] = {
+    { TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UINT16, FIELD_PREDICTOR, FALSE, FALSE, "Predictor", NULL },
+};
+
+static int
+PredictorVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	TIFFPredictorState *sp = PredictorState(tif);
+
+	assert(sp != NULL);
+	assert(sp->vsetparent != NULL);
+
+	switch (tag) {
+	case TIFFTAG_PREDICTOR:
+		sp->predictor = (uint16) va_arg(ap, uint16_vap);
+		TIFFSetFieldBit(tif, FIELD_PREDICTOR);
+		break;
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+	tif->tif_flags |= TIFF_DIRTYDIRECT;
+	return 1;
+}
+
+static int
+PredictorVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	TIFFPredictorState *sp = PredictorState(tif);
+
+	assert(sp != NULL);
+	assert(sp->vgetparent != NULL);
+
+	switch (tag) {
+	case TIFFTAG_PREDICTOR:
+		*va_arg(ap, uint16*) = sp->predictor;
+		break;
+	default:
+		return (*sp->vgetparent)(tif, tag, ap);
+	}
+	return 1;
+}
+
+static void
+PredictorPrintDir(TIFF* tif, FILE* fd, long flags)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+
+	(void) flags;
+	if (TIFFFieldSet(tif,FIELD_PREDICTOR)) {
+		fprintf(fd, "  Predictor: ");
+		switch (sp->predictor) {
+			case 1: fprintf(fd, "none "); break;
+			case 2: fprintf(fd, "horizontal differencing "); break;
+			case 3: fprintf(fd, "floating point predictor "); break;
+		}
+		fprintf(fd, "%u (0x%x)\n", sp->predictor, sp->predictor);
+	}
+	if (sp->printdir)
+		(*sp->printdir)(tif, fd, flags);
+}
+
+int
+TIFFPredictorInit(TIFF* tif)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+
+	assert(sp != 0);
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, predictFields,
+			      TIFFArrayCount(predictFields))) {
+		TIFFErrorExt(tif->tif_clientdata, "TIFFPredictorInit",
+		    "Merging Predictor codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Override parent get/set field methods.
+	 */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield =
+            PredictorVGetField;/* hook for predictor tag */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield =
+	    PredictorVSetField;/* hook for predictor tag */
+	sp->printdir = tif->tif_tagmethods.printdir;
+	tif->tif_tagmethods.printdir =
+            PredictorPrintDir;	/* hook for predictor tag */
+
+	sp->setupdecode = tif->tif_setupdecode;
+	tif->tif_setupdecode = PredictorSetupDecode;
+	sp->setupencode = tif->tif_setupencode;
+	tif->tif_setupencode = PredictorSetupEncode;
+
+	sp->predictor = 1;			/* default value */
+	sp->encodepfunc = NULL;			/* no predictor routine */
+	sp->decodepfunc = NULL;			/* no predictor routine */
+	return 1;
+}
+
+int
+TIFFPredictorCleanup(TIFF* tif)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+
+	assert(sp != 0);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+	tif->tif_tagmethods.printdir = sp->printdir;
+	tif->tif_setupdecode = sp->setupdecode;
+	tif->tif_setupencode = sp->setupencode;
+
+	return 1;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.h b/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.h
new file mode 100644
index 0000000..dc7144c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.h
@@ -0,0 +1,77 @@
+/* $Id: tif_predict.h,v 1.8 2010-03-10 18:56:49 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1995-1997 Sam Leffler
+ * Copyright (c) 1995-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFPREDICT_
+#define	_TIFFPREDICT_
+/*
+ * ``Library-private'' Support for the Predictor Tag
+ */
+
+/*
+ * Codecs that want to support the Predictor tag must place
+ * this structure first in their private state block so that
+ * the predictor code can cast tif_data to find its state.
+ */
+typedef struct {
+	int             predictor;	/* predictor tag value */
+	tmsize_t        stride;		/* sample stride over data */
+	tmsize_t        rowsize;	/* tile/strip row size */
+
+	TIFFCodeMethod  encoderow;	/* parent codec encode/decode row */
+	TIFFCodeMethod  encodestrip;	/* parent codec encode/decode strip */
+	TIFFCodeMethod  encodetile;	/* parent codec encode/decode tile */ 
+	TIFFPostMethod  encodepfunc;	/* horizontal differencer */
+
+	TIFFCodeMethod  decoderow;	/* parent codec encode/decode row */
+	TIFFCodeMethod  decodestrip;	/* parent codec encode/decode strip */
+	TIFFCodeMethod  decodetile;	/* parent codec encode/decode tile */ 
+	TIFFPostMethod  decodepfunc;	/* horizontal accumulator */
+
+	TIFFVGetMethod  vgetparent;	/* super-class method */
+	TIFFVSetMethod  vsetparent;	/* super-class method */
+	TIFFPrintMethod printdir;	/* super-class method */
+	TIFFBoolMethod  setupdecode;	/* super-class method */
+	TIFFBoolMethod  setupencode;	/* super-class method */
+} TIFFPredictorState;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern int TIFFPredictorInit(TIFF*);
+extern int TIFFPredictorCleanup(TIFF*);
+#if defined(__cplusplus)
+}
+#endif
+#endif /* _TIFFPREDICT_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_print.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_print.c
new file mode 100644
index 0000000..3ee43fc
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_print.c
@@ -0,0 +1,719 @@
+/* $Id: tif_print.c,v 1.60 2012-08-19 16:56:35 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Printing Support
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include <stdio.h>
+
+#include <ctype.h>
+
+static void
+_TIFFprintAsciiBounded(FILE* fd, const char* cp, int max_chars);
+
+static const char *photoNames[] = {
+    "min-is-white",				/* PHOTOMETRIC_MINISWHITE */
+    "min-is-black",				/* PHOTOMETRIC_MINISBLACK */
+    "RGB color",				/* PHOTOMETRIC_RGB */
+    "palette color (RGB from colormap)",	/* PHOTOMETRIC_PALETTE */
+    "transparency mask",			/* PHOTOMETRIC_MASK */
+    "separated",				/* PHOTOMETRIC_SEPARATED */
+    "YCbCr",					/* PHOTOMETRIC_YCBCR */
+    "7 (0x7)",
+    "CIE L*a*b*",				/* PHOTOMETRIC_CIELAB */
+    "ICC L*a*b*",				/* PHOTOMETRIC_ICCLAB */
+    "ITU L*a*b*" 				/* PHOTOMETRIC_ITULAB */
+};
+#define	NPHOTONAMES	(sizeof (photoNames) / sizeof (photoNames[0]))
+
+static const char *orientNames[] = {
+    "0 (0x0)",
+    "row 0 top, col 0 lhs",			/* ORIENTATION_TOPLEFT */
+    "row 0 top, col 0 rhs",			/* ORIENTATION_TOPRIGHT */
+    "row 0 bottom, col 0 rhs",			/* ORIENTATION_BOTRIGHT */
+    "row 0 bottom, col 0 lhs",			/* ORIENTATION_BOTLEFT */
+    "row 0 lhs, col 0 top",			/* ORIENTATION_LEFTTOP */
+    "row 0 rhs, col 0 top",			/* ORIENTATION_RIGHTTOP */
+    "row 0 rhs, col 0 bottom",			/* ORIENTATION_RIGHTBOT */
+    "row 0 lhs, col 0 bottom",			/* ORIENTATION_LEFTBOT */
+};
+#define	NORIENTNAMES	(sizeof (orientNames) / sizeof (orientNames[0]))
+
+static void
+_TIFFPrintField(FILE* fd, const TIFFField *fip,
+		uint32 value_count, void *raw_data)
+{
+	uint32 j;
+		
+	fprintf(fd, "  %s: ", fip->field_name);
+
+	for(j = 0; j < value_count; j++) {
+		if(fip->field_type == TIFF_BYTE)
+			fprintf(fd, "%u", ((uint8 *) raw_data)[j]);
+		else if(fip->field_type == TIFF_UNDEFINED)
+			fprintf(fd, "0x%x",
+			    (unsigned int) ((unsigned char *) raw_data)[j]);
+		else if(fip->field_type == TIFF_SBYTE)
+			fprintf(fd, "%d", ((int8 *) raw_data)[j]);
+		else if(fip->field_type == TIFF_SHORT)
+			fprintf(fd, "%u", ((uint16 *) raw_data)[j]);
+		else if(fip->field_type == TIFF_SSHORT)
+			fprintf(fd, "%d", ((int16 *) raw_data)[j]);
+		else if(fip->field_type == TIFF_LONG)
+			fprintf(fd, "%lu",
+			    (unsigned long)((uint32 *) raw_data)[j]);
+		else if(fip->field_type == TIFF_SLONG)
+			fprintf(fd, "%ld", (long)((int32 *) raw_data)[j]);
+		else if(fip->field_type == TIFF_IFD)
+			fprintf(fd, "0x%lx",
+				(unsigned long)((uint32 *) raw_data)[j]);
+		else if(fip->field_type == TIFF_RATIONAL
+			|| fip->field_type == TIFF_SRATIONAL
+			|| fip->field_type == TIFF_FLOAT)
+			fprintf(fd, "%f", ((float *) raw_data)[j]);
+		else if(fip->field_type == TIFF_LONG8)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, "%I64u",
+			    (unsigned __int64)((uint64 *) raw_data)[j]);
+#else
+			fprintf(fd, "%llu",
+			    (unsigned long long)((uint64 *) raw_data)[j]);
+#endif
+		else if(fip->field_type == TIFF_SLONG8)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, "%I64d", (__int64)((int64 *) raw_data)[j]);
+#else
+			fprintf(fd, "%lld", (long long)((int64 *) raw_data)[j]);
+#endif
+		else if(fip->field_type == TIFF_IFD8)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, "0x%I64x",
+				(unsigned __int64)((uint64 *) raw_data)[j]);
+#else
+			fprintf(fd, "0x%llx",
+				(unsigned long long)((uint64 *) raw_data)[j]);
+#endif
+		else if(fip->field_type == TIFF_FLOAT)
+			fprintf(fd, "%f", ((float *)raw_data)[j]);
+		else if(fip->field_type == TIFF_DOUBLE)
+			fprintf(fd, "%f", ((double *) raw_data)[j]);
+		else if(fip->field_type == TIFF_ASCII) {
+			fprintf(fd, "%s", (char *) raw_data);
+			break;
+		}
+		else {
+			fprintf(fd, "<unsupported data type in TIFFPrint>");
+			break;
+		}
+
+		if(j < value_count - 1)
+			fprintf(fd, ",");
+	}
+
+	fprintf(fd, "\n");
+}
+
+static int
+_TIFFPrettyPrintField(TIFF* tif, const TIFFField *fip, FILE* fd, uint32 tag,
+		      uint32 value_count, void *raw_data)
+{
+        (void) tif;
+
+	/* do not try to pretty print auto-defined fields */
+	if (strncmp(fip->field_name,"Tag ", 4) == 0) {
+		return 0;
+	}
+        
+	switch (tag)
+	{
+		case TIFFTAG_INKSET:
+			if (value_count == 2 && fip->field_type == TIFF_SHORT) {
+				fprintf(fd, "  Ink Set: ");
+				switch (*((uint16*)raw_data)) {
+				case INKSET_CMYK:
+					fprintf(fd, "CMYK\n");
+					break;
+				default:
+					fprintf(fd, "%u (0x%x)\n",
+						*((uint16*)raw_data),
+						*((uint16*)raw_data));
+					break;
+				}
+				return 1;
+			}
+			return 0;
+
+		case TIFFTAG_DOTRANGE:
+			if (value_count == 2 && fip->field_type == TIFF_SHORT) {
+				fprintf(fd, "  Dot Range: %u-%u\n",
+					((uint16*)raw_data)[0], ((uint16*)raw_data)[1]);
+				return 1;
+			}
+			return 0;
+
+		case TIFFTAG_WHITEPOINT:
+			if (value_count == 2 && fip->field_type == TIFF_RATIONAL) {
+				fprintf(fd, "  White Point: %g-%g\n",
+					((float *)raw_data)[0], ((float *)raw_data)[1]);
+				return 1;
+			} 
+			return 0;
+
+		case TIFFTAG_XMLPACKET:
+		{
+			uint32 i;
+
+			fprintf(fd, "  XMLPacket (XMP Metadata):\n" );
+			for(i = 0; i < value_count; i++)
+				fputc(((char *)raw_data)[i], fd);
+			fprintf( fd, "\n" );
+			return 1;
+		}
+		case TIFFTAG_RICHTIFFIPTC:
+			/*
+			 * XXX: for some weird reason RichTIFFIPTC tag
+			 * defined as array of LONG values.
+			 */
+			fprintf(fd,
+			    "  RichTIFFIPTC Data: <present>, %lu bytes\n",
+			    (unsigned long) value_count * 4);
+			return 1;
+
+		case TIFFTAG_PHOTOSHOP:
+			fprintf(fd, "  Photoshop Data: <present>, %lu bytes\n",
+			    (unsigned long) value_count);
+			return 1;
+
+		case TIFFTAG_ICCPROFILE:
+			fprintf(fd, "  ICC Profile: <present>, %lu bytes\n",
+			    (unsigned long) value_count);
+			return 1;
+
+		case TIFFTAG_STONITS:
+			if (value_count == 1 && fip->field_type == TIFF_DOUBLE) { 
+				fprintf(fd,
+					"  Sample to Nits conversion factor: %.4e\n",
+					*((double*)raw_data));
+				return 1;
+			}
+			return 0;
+	}
+
+	return 0;
+}
+
+/*
+ * Print the contents of the current directory
+ * to the specified stdio file stream.
+ */
+void
+TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	char *sep;
+	uint16 i;
+	long l, n;
+
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+	fprintf(fd, "TIFF Directory at offset 0x%I64x (%I64u)\n",
+		(unsigned __int64) tif->tif_diroff,
+		(unsigned __int64) tif->tif_diroff);
+#else
+	fprintf(fd, "TIFF Directory at offset 0x%llx (%llu)\n",
+		(unsigned long long) tif->tif_diroff,
+		(unsigned long long) tif->tif_diroff);
+#endif
+	if (TIFFFieldSet(tif,FIELD_SUBFILETYPE)) {
+		fprintf(fd, "  Subfile Type:");
+		sep = " ";
+		if (td->td_subfiletype & FILETYPE_REDUCEDIMAGE) {
+			fprintf(fd, "%sreduced-resolution image", sep);
+			sep = "/";
+		}
+		if (td->td_subfiletype & FILETYPE_PAGE) {
+			fprintf(fd, "%smulti-page document", sep);
+			sep = "/";
+		}
+		if (td->td_subfiletype & FILETYPE_MASK)
+			fprintf(fd, "%stransparency mask", sep);
+		fprintf(fd, " (%lu = 0x%lx)\n",
+		    (long) td->td_subfiletype, (long) td->td_subfiletype);
+	}
+	if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) {
+		fprintf(fd, "  Image Width: %lu Image Length: %lu",
+		    (unsigned long) td->td_imagewidth, (unsigned long) td->td_imagelength);
+		if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH))
+			fprintf(fd, " Image Depth: %lu",
+			    (unsigned long) td->td_imagedepth);
+		fprintf(fd, "\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS)) {
+		fprintf(fd, "  Tile Width: %lu Tile Length: %lu",
+		    (unsigned long) td->td_tilewidth, (unsigned long) td->td_tilelength);
+		if (TIFFFieldSet(tif,FIELD_TILEDEPTH))
+			fprintf(fd, " Tile Depth: %lu",
+			    (unsigned long) td->td_tiledepth);
+		fprintf(fd, "\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_RESOLUTION)) {
+		fprintf(fd, "  Resolution: %g, %g",
+		    td->td_xresolution, td->td_yresolution);
+		if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT)) {
+			switch (td->td_resolutionunit) {
+			case RESUNIT_NONE:
+				fprintf(fd, " (unitless)");
+				break;
+			case RESUNIT_INCH:
+				fprintf(fd, " pixels/inch");
+				break;
+			case RESUNIT_CENTIMETER:
+				fprintf(fd, " pixels/cm");
+				break;
+			default:
+				fprintf(fd, " (unit %u = 0x%x)",
+				    td->td_resolutionunit,
+				    td->td_resolutionunit);
+				break;
+			}
+		}
+		fprintf(fd, "\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_POSITION))
+		fprintf(fd, "  Position: %g, %g\n",
+		    td->td_xposition, td->td_yposition);
+	if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
+		fprintf(fd, "  Bits/Sample: %u\n", td->td_bitspersample);
+	if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT)) {
+		fprintf(fd, "  Sample Format: ");
+		switch (td->td_sampleformat) {
+		case SAMPLEFORMAT_VOID:
+			fprintf(fd, "void\n");
+			break;
+		case SAMPLEFORMAT_INT:
+			fprintf(fd, "signed integer\n");
+			break;
+		case SAMPLEFORMAT_UINT:
+			fprintf(fd, "unsigned integer\n");
+			break;
+		case SAMPLEFORMAT_IEEEFP:
+			fprintf(fd, "IEEE floating point\n");
+			break;
+		case SAMPLEFORMAT_COMPLEXINT:
+			fprintf(fd, "complex signed integer\n");
+			break;
+		case SAMPLEFORMAT_COMPLEXIEEEFP:
+			fprintf(fd, "complex IEEE floating point\n");
+			break;
+		default:
+			fprintf(fd, "%u (0x%x)\n",
+			    td->td_sampleformat, td->td_sampleformat);
+			break;
+		}
+	}
+	if (TIFFFieldSet(tif,FIELD_COMPRESSION)) {
+		const TIFFCodec* c = TIFFFindCODEC(td->td_compression);
+		fprintf(fd, "  Compression Scheme: ");
+		if (c)
+			fprintf(fd, "%s\n", c->name);
+		else
+			fprintf(fd, "%u (0x%x)\n",
+			    td->td_compression, td->td_compression);
+	}
+	if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) {
+		fprintf(fd, "  Photometric Interpretation: ");
+		if (td->td_photometric < NPHOTONAMES)
+			fprintf(fd, "%s\n", photoNames[td->td_photometric]);
+		else {
+			switch (td->td_photometric) {
+			case PHOTOMETRIC_LOGL:
+				fprintf(fd, "CIE Log2(L)\n");
+				break;
+			case PHOTOMETRIC_LOGLUV:
+				fprintf(fd, "CIE Log2(L) (u',v')\n");
+				break;
+			default:
+				fprintf(fd, "%u (0x%x)\n",
+				    td->td_photometric, td->td_photometric);
+				break;
+			}
+		}
+	}
+	if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES) && td->td_extrasamples) {
+		fprintf(fd, "  Extra Samples: %u<", td->td_extrasamples);
+		sep = "";
+		for (i = 0; i < td->td_extrasamples; i++) {
+			switch (td->td_sampleinfo[i]) {
+			case EXTRASAMPLE_UNSPECIFIED:
+				fprintf(fd, "%sunspecified", sep);
+				break;
+			case EXTRASAMPLE_ASSOCALPHA:
+				fprintf(fd, "%sassoc-alpha", sep);
+				break;
+			case EXTRASAMPLE_UNASSALPHA:
+				fprintf(fd, "%sunassoc-alpha", sep);
+				break;
+			default:
+				fprintf(fd, "%s%u (0x%x)", sep,
+				    td->td_sampleinfo[i], td->td_sampleinfo[i]);
+				break;
+			}
+			sep = ", ";
+		}
+		fprintf(fd, ">\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_INKNAMES)) {
+		char* cp;
+		fprintf(fd, "  Ink Names: ");
+		i = td->td_samplesperpixel;
+		sep = "";
+		for (cp = td->td_inknames; 
+		     i > 0 && cp < td->td_inknames + td->td_inknameslen; 
+		     cp = strchr(cp,'\0')+1, i--) {
+			int max_chars = 
+				(int)(td->td_inknameslen - (cp - td->td_inknames));
+			fputs(sep, fd);
+			_TIFFprintAsciiBounded(fd, cp, max_chars);
+			sep = ", ";
+		}
+                fputs("\n", fd);
+	}
+	if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) {
+		fprintf(fd, "  Thresholding: ");
+		switch (td->td_threshholding) {
+		case THRESHHOLD_BILEVEL:
+			fprintf(fd, "bilevel art scan\n");
+			break;
+		case THRESHHOLD_HALFTONE:
+			fprintf(fd, "halftone or dithered scan\n");
+			break;
+		case THRESHHOLD_ERRORDIFFUSE:
+			fprintf(fd, "error diffused\n");
+			break;
+		default:
+			fprintf(fd, "%u (0x%x)\n",
+			    td->td_threshholding, td->td_threshholding);
+			break;
+		}
+	}
+	if (TIFFFieldSet(tif,FIELD_FILLORDER)) {
+		fprintf(fd, "  FillOrder: ");
+		switch (td->td_fillorder) {
+		case FILLORDER_MSB2LSB:
+			fprintf(fd, "msb-to-lsb\n");
+			break;
+		case FILLORDER_LSB2MSB:
+			fprintf(fd, "lsb-to-msb\n");
+			break;
+		default:
+			fprintf(fd, "%u (0x%x)\n",
+			    td->td_fillorder, td->td_fillorder);
+			break;
+		}
+	}
+	if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING))
+        {
+		fprintf(fd, "  YCbCr Subsampling: %u, %u\n",
+			td->td_ycbcrsubsampling[0], td->td_ycbcrsubsampling[1] );
+	}
+	if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING)) {
+		fprintf(fd, "  YCbCr Positioning: ");
+		switch (td->td_ycbcrpositioning) {
+		case YCBCRPOSITION_CENTERED:
+			fprintf(fd, "centered\n");
+			break;
+		case YCBCRPOSITION_COSITED:
+			fprintf(fd, "cosited\n");
+			break;
+		default:
+			fprintf(fd, "%u (0x%x)\n",
+			    td->td_ycbcrpositioning, td->td_ycbcrpositioning);
+			break;
+		}
+	}
+	if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS))
+		fprintf(fd, "  Halftone Hints: light %u dark %u\n",
+		    td->td_halftonehints[0], td->td_halftonehints[1]);
+	if (TIFFFieldSet(tif,FIELD_ORIENTATION)) {
+		fprintf(fd, "  Orientation: ");
+		if (td->td_orientation < NORIENTNAMES)
+			fprintf(fd, "%s\n", orientNames[td->td_orientation]);
+		else
+			fprintf(fd, "%u (0x%x)\n",
+			    td->td_orientation, td->td_orientation);
+	}
+	if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
+		fprintf(fd, "  Samples/Pixel: %u\n", td->td_samplesperpixel);
+	if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP)) {
+		fprintf(fd, "  Rows/Strip: ");
+		if (td->td_rowsperstrip == (uint32) -1)
+			fprintf(fd, "(infinite)\n");
+		else
+			fprintf(fd, "%lu\n", (unsigned long) td->td_rowsperstrip);
+	}
+	if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE))
+		fprintf(fd, "  Min Sample Value: %u\n", td->td_minsamplevalue);
+	if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE))
+		fprintf(fd, "  Max Sample Value: %u\n", td->td_maxsamplevalue);
+	if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE)) {
+		int count = (tif->tif_flags & TIFF_PERSAMPLE) ? td->td_samplesperpixel : 1;
+		fprintf(fd, "  SMin Sample Value:");
+		for (i = 0; i < count; ++i)
+			fprintf(fd, " %g", td->td_sminsamplevalue[i]);
+		fprintf(fd, "\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE)) {
+		int count = (tif->tif_flags & TIFF_PERSAMPLE) ? td->td_samplesperpixel : 1;
+		fprintf(fd, "  SMax Sample Value:");
+		for (i = 0; i < count; ++i)
+			fprintf(fd, " %g", td->td_smaxsamplevalue[i]);
+		fprintf(fd, "\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_PLANARCONFIG)) {
+		fprintf(fd, "  Planar Configuration: ");
+		switch (td->td_planarconfig) {
+		case PLANARCONFIG_CONTIG:
+			fprintf(fd, "single image plane\n");
+			break;
+		case PLANARCONFIG_SEPARATE:
+			fprintf(fd, "separate image planes\n");
+			break;
+		default:
+			fprintf(fd, "%u (0x%x)\n",
+			    td->td_planarconfig, td->td_planarconfig);
+			break;
+		}
+	}
+	if (TIFFFieldSet(tif,FIELD_PAGENUMBER))
+		fprintf(fd, "  Page Number: %u-%u\n",
+		    td->td_pagenumber[0], td->td_pagenumber[1]);
+	if (TIFFFieldSet(tif,FIELD_COLORMAP)) {
+		fprintf(fd, "  Color Map: ");
+		if (flags & TIFFPRINT_COLORMAP) {
+			fprintf(fd, "\n");
+			n = 1L<<td->td_bitspersample;
+			for (l = 0; l < n; l++)
+				fprintf(fd, "   %5lu: %5u %5u %5u\n",
+				    l,
+				    td->td_colormap[0][l],
+				    td->td_colormap[1][l],
+				    td->td_colormap[2][l]);
+		} else
+			fprintf(fd, "(present)\n");
+	}
+	if (TIFFFieldSet(tif,FIELD_REFBLACKWHITE)) {
+		fprintf(fd, "  Reference Black/White:\n");
+		for (i = 0; i < 3; i++)
+		fprintf(fd, "    %2d: %5g %5g\n", i,
+			td->td_refblackwhite[2*i+0],
+			td->td_refblackwhite[2*i+1]);
+	}
+	if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION)) {
+		fprintf(fd, "  Transfer Function: ");
+		if (flags & TIFFPRINT_CURVES) {
+			fprintf(fd, "\n");
+			n = 1L<<td->td_bitspersample;
+			for (l = 0; l < n; l++) {
+				fprintf(fd, "    %2lu: %5u",
+				    l, td->td_transferfunction[0][l]);
+				for (i = 1; i < td->td_samplesperpixel; i++)
+					fprintf(fd, " %5u",
+					    td->td_transferfunction[i][l]);
+				fputc('\n', fd);
+			}
+		} else
+			fprintf(fd, "(present)\n");
+	}
+	if (TIFFFieldSet(tif, FIELD_SUBIFD) && (td->td_subifd)) {
+		fprintf(fd, "  SubIFD Offsets:");
+		for (i = 0; i < td->td_nsubifd; i++)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, " %5I64u",
+				(unsigned __int64) td->td_subifd[i]);
+#else
+			fprintf(fd, " %5llu",
+				(unsigned long long) td->td_subifd[i]);
+#endif
+		fputc('\n', fd);
+	}
+
+	/*
+	** Custom tag support.
+	*/
+	{
+		int  i;
+		short count;
+
+		count = (short) TIFFGetTagListCount(tif);
+		for(i = 0; i < count; i++) {
+			uint32 tag = TIFFGetTagListEntry(tif, i);
+			const TIFFField *fip;
+			uint32 value_count;
+			int mem_alloc = 0;
+			void *raw_data;
+
+			fip = TIFFFieldWithTag(tif, tag);
+			if(fip == NULL)
+				continue;
+
+			if(fip->field_passcount) {
+				if (fip->field_readcount == TIFF_VARIABLE ) {
+					if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1)
+						continue;
+				} else if (fip->field_readcount == TIFF_VARIABLE2 ) {
+					uint16 small_value_count;
+					if(TIFFGetField(tif, tag, &small_value_count, &raw_data) != 1)
+						continue;
+					value_count = small_value_count;
+				} else {
+					assert (fip->field_readcount == TIFF_VARIABLE
+						|| fip->field_readcount == TIFF_VARIABLE2);
+					continue;
+				} 
+			} else {
+				if (fip->field_readcount == TIFF_VARIABLE
+				    || fip->field_readcount == TIFF_VARIABLE2)
+					value_count = 1;
+				else if (fip->field_readcount == TIFF_SPP)
+					value_count = td->td_samplesperpixel;
+				else
+					value_count = fip->field_readcount;
+				if (fip->field_tag == TIFFTAG_DOTRANGE
+				    && strcmp(fip->field_name,"DotRange") == 0) {
+					/* TODO: This is an evil exception and should not have been
+					   handled this way ... likely best if we move it into
+					   the directory structure with an explicit field in 
+					   libtiff 4.1 and assign it a FIELD_ value */
+					static uint16 dotrange[2];
+					raw_data = dotrange;
+					TIFFGetField(tif, tag, dotrange+0, dotrange+1);
+				} else if (fip->field_type == TIFF_ASCII
+					   || fip->field_readcount == TIFF_VARIABLE
+					   || fip->field_readcount == TIFF_VARIABLE2
+					   || fip->field_readcount == TIFF_SPP
+					   || value_count > 1) {
+					if(TIFFGetField(tif, tag, &raw_data) != 1)
+						continue;
+				} else {
+					raw_data = _TIFFmalloc(
+					    _TIFFDataSize(fip->field_type)
+					    * value_count);
+					mem_alloc = 1;
+					if(TIFFGetField(tif, tag, raw_data) != 1) {
+						_TIFFfree(raw_data);
+						continue;
+					}
+				}
+			}
+
+			/*
+			 * Catch the tags which needs to be specially handled
+			 * and pretty print them. If tag not handled in
+			 * _TIFFPrettyPrintField() fall down and print it as
+			 * any other tag.
+			 */
+			if (!_TIFFPrettyPrintField(tif, fip, fd, tag, value_count, raw_data))
+				_TIFFPrintField(fd, fip, value_count, raw_data);
+
+			if(mem_alloc)
+				_TIFFfree(raw_data);
+		}
+	}
+        
+	if (tif->tif_tagmethods.printdir)
+		(*tif->tif_tagmethods.printdir)(tif, fd, flags);
+
+        _TIFFFillStriles( tif );
+        
+	if ((flags & TIFFPRINT_STRIPS) &&
+	    TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) {
+		uint32 s;
+
+		fprintf(fd, "  %lu %s:\n",
+		    (long) td->td_nstrips,
+		    isTiled(tif) ? "Tiles" : "Strips");
+		for (s = 0; s < td->td_nstrips; s++)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, "    %3lu: [%8I64u, %8I64u]\n",
+			    (unsigned long) s,
+			    (unsigned __int64) td->td_stripoffset[s],
+			    (unsigned __int64) td->td_stripbytecount[s]);
+#else
+			fprintf(fd, "    %3lu: [%8llu, %8llu]\n",
+			    (unsigned long) s,
+			    (unsigned long long) td->td_stripoffset[s],
+			    (unsigned long long) td->td_stripbytecount[s]);
+#endif
+	}
+}
+
+void
+_TIFFprintAscii(FILE* fd, const char* cp)
+{
+	_TIFFprintAsciiBounded( fd, cp, (int)strlen(cp));
+}
+
+static void
+_TIFFprintAsciiBounded(FILE* fd, const char* cp, int max_chars)
+{
+	for (; max_chars > 0 && *cp != '\0'; cp++, max_chars--) {
+		const char* tp;
+
+		if (isprint((int)*cp)) {
+			fputc(*cp, fd);
+			continue;
+		}
+		for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++)
+			if (*tp++ == *cp)
+				break;
+		if (*tp)
+			fprintf(fd, "\\%c", *tp);
+		else
+			fprintf(fd, "\\%03o", *cp & 0xff);
+	}
+}
+
+void
+_TIFFprintAsciiTag(FILE* fd, const char* name, const char* value)
+{
+	fprintf(fd, "  %s: \"", name);
+	_TIFFprintAscii(fd, value);
+	fprintf(fd, "\"\n");
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_read.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_read.c
new file mode 100644
index 0000000..a25a5a6
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_read.c
@@ -0,0 +1,1116 @@
+/* $Id: tif_read.c,v 1.41 2012-07-06 19:22:58 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ * Scanline-oriented Read Support
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include <stdio.h>
+
+int TIFFFillStrip(TIFF* tif, uint32 strip);
+int TIFFFillTile(TIFF* tif, uint32 tile);
+static int TIFFStartStrip(TIFF* tif, uint32 strip);
+static int TIFFStartTile(TIFF* tif, uint32 tile);
+static int TIFFCheckRead(TIFF*, int);
+static tmsize_t
+TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,const char* module);
+
+#define NOSTRIP ((uint32)(-1))       /* undefined state */
+#define NOTILE ((uint32)(-1))         /* undefined state */
+
+static int
+TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart )
+{
+	static const char module[] = "TIFFFillStripPartial";
+	register TIFFDirectory *td = &tif->tif_dir;
+        uint64 unused_data;
+        uint64 read_offset;
+        tmsize_t cc, to_read;
+        /* tmsize_t bytecountm; */
+        
+        if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+            return 0;
+        
+        /*
+         * Expand raw data buffer, if needed, to hold data
+         * strip coming from file (perhaps should set upper
+         * bound on the size of a buffer we'll use?).
+         */
+
+        /* bytecountm=(tmsize_t) td->td_stripbytecount[strip]; */
+        if (read_ahead*2 > tif->tif_rawdatasize) {
+                assert( restart );
+                
+                tif->tif_curstrip = NOSTRIP;
+                if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
+                        TIFFErrorExt(tif->tif_clientdata, module,
+                                     "Data buffer too small to hold part of strip %lu",
+                                     (unsigned long) strip);
+                        return (0);
+                }
+                if (!TIFFReadBufferSetup(tif, 0, read_ahead*2))
+                        return (0);
+        }
+
+        if( restart )
+        {
+                tif->tif_rawdataloaded = 0;
+                tif->tif_rawdataoff = 0;
+        }
+
+        /*
+        ** If we are reading more data, move any unused data to the
+        ** start of the buffer.
+        */
+        if( tif->tif_rawdataloaded > 0 )
+                unused_data = tif->tif_rawdataloaded - (tif->tif_rawcp - tif->tif_rawdata);
+        else
+                unused_data = 0;
+        
+        if( unused_data > 0 )
+        {
+		assert((tif->tif_flags&TIFF_BUFFERMMAP)==0);
+                memmove( tif->tif_rawdata, tif->tif_rawcp, (size_t)unused_data );
+        }
+
+        /*
+        ** Seek to the point in the file where more data should be read.
+        */
+        read_offset = td->td_stripoffset[strip]
+                + tif->tif_rawdataoff + tif->tif_rawdataloaded;
+
+        if (!SeekOK(tif, read_offset)) {
+                TIFFErrorExt(tif->tif_clientdata, module,
+                             "Seek error at scanline %lu, strip %lu",
+                             (unsigned long) tif->tif_row, (unsigned long) strip);
+                return 0;
+        }
+
+        /*
+        ** How much do we want to read?
+        */
+        to_read = (tmsize_t)(tif->tif_rawdatasize - unused_data);
+        if( (uint64) to_read > td->td_stripbytecount[strip] 
+            - tif->tif_rawdataoff - tif->tif_rawdataloaded )
+        {
+                to_read = (tmsize_t)(td->td_stripbytecount[strip]
+                        - tif->tif_rawdataoff - tif->tif_rawdataloaded);
+        }
+
+	assert((tif->tif_flags&TIFF_BUFFERMMAP)==0);
+        cc = TIFFReadFile(tif, tif->tif_rawdata + unused_data, to_read);
+
+        if (cc != to_read) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+                TIFFErrorExt(tif->tif_clientdata, module,
+                             "Read error at scanline %lu; got %I64u bytes, expected %I64u",
+                             (unsigned long) tif->tif_row,
+                             (unsigned __int64) cc,
+                             (unsigned __int64) to_read);
+#else
+                TIFFErrorExt(tif->tif_clientdata, module,
+                             "Read error at scanline %lu; got %llu bytes, expected %llu",
+                             (unsigned long) tif->tif_row,
+                             (unsigned long long) cc,
+                             (unsigned long long) to_read);
+#endif
+                return 0;
+        }
+        
+        tif->tif_rawdataoff = (tmsize_t)(tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data) ;
+        tif->tif_rawdataloaded = (tmsize_t)unused_data + to_read;
+
+        tif->tif_rawcp = tif->tif_rawdata;
+                        
+        if (!isFillOrder(tif, td->td_fillorder) &&
+            (tif->tif_flags & TIFF_NOBITREV) == 0) {
+		assert((tif->tif_flags&TIFF_BUFFERMMAP)==0);
+                TIFFReverseBits(tif->tif_rawdata + unused_data, to_read );
+	}
+
+        /*
+        ** When starting a strip from the beginning we need to
+        ** restart the decoder.
+        */
+        if( restart )
+                return TIFFStartStrip(tif, strip);
+        else
+                return 1;
+}
+
+/*
+ * Seek to a random row+sample in a file.
+ *
+ * Only used by TIFFReadScanline, and is only used on
+ * strip organized files.  We do some tricky stuff to try
+ * and avoid reading the whole compressed raw data for big
+ * strips.
+ */
+static int
+TIFFSeek(TIFF* tif, uint32 row, uint16 sample )
+{
+	register TIFFDirectory *td = &tif->tif_dir;
+	uint32 strip;
+        int    whole_strip;
+	tmsize_t read_ahead = 0;
+
+        /*
+        ** Establish what strip we are working from.
+        */
+	if (row >= td->td_imagelength) {	/* out of range */
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		    "%lu: Row out of range, max %lu",
+		    (unsigned long) row,
+		    (unsigned long) td->td_imagelength);
+		return (0);
+	}
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+		if (sample >= td->td_samplesperpixel) {
+			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			    "%lu: Sample out of range, max %lu",
+			    (unsigned long) sample, (unsigned long) td->td_samplesperpixel);
+			return (0);
+		}
+		strip = (uint32)sample*td->td_stripsperimage + row/td->td_rowsperstrip;
+	} else
+		strip = row / td->td_rowsperstrip;
+
+        /*
+         * Do we want to treat this strip as one whole chunk or
+         * read it a few lines at a time?
+         */
+#if defined(CHUNKY_STRIP_READ_SUPPORT)
+        if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+            return 0;
+        whole_strip = tif->tif_dir.td_stripbytecount[strip] < 10
+                || isMapped(tif);
+#else
+        whole_strip = 1;
+#endif
+        
+        if( !whole_strip )
+        {
+                read_ahead = tif->tif_scanlinesize * 16 + 5000;
+        }
+
+        /*
+         * If we haven't loaded this strip, do so now, possibly
+         * only reading the first part.
+         */
+	if (strip != tif->tif_curstrip) {	/* different strip, refill */
+                
+                if( whole_strip )
+                {
+                        if (!TIFFFillStrip(tif, strip))
+                                return (0);
+                }
+                else
+                {
+                        if( !TIFFFillStripPartial(tif,strip,read_ahead,1) )
+                                return 0;
+                }
+	}
+
+        /*
+        ** If we already have some data loaded, do we need to read some more?
+        */
+        else if( !whole_strip )
+        {
+                if( ((tif->tif_rawdata + tif->tif_rawdataloaded) - tif->tif_rawcp) < read_ahead 
+                    && (uint64) tif->tif_rawdataoff+tif->tif_rawdataloaded < td->td_stripbytecount[strip] )
+                {
+                        if( !TIFFFillStripPartial(tif,strip,read_ahead,0) )
+                                return 0;
+                }
+        }
+
+        if (row < tif->tif_row) {
+		/*
+		 * Moving backwards within the same strip: backup
+		 * to the start and then decode forward (below).
+		 *
+		 * NB: If you're planning on lots of random access within a
+		 * strip, it's better to just read and decode the entire
+		 * strip, and then access the decoded data in a random fashion.
+		 */
+
+                if( tif->tif_rawdataoff != 0 )
+                {
+                        if( !TIFFFillStripPartial(tif,strip,read_ahead,1) )
+                                return 0;
+                }
+                else
+                {
+                        if (!TIFFStartStrip(tif, strip))
+                                return (0);
+                }
+	}
+        
+	if (row != tif->tif_row) {
+		/*
+		 * Seek forward to the desired row.
+		 */
+
+                /* TODO: Will this really work with partial buffers? */
+                
+		if (!(*tif->tif_seek)(tif, row - tif->tif_row))
+			return (0);
+		tif->tif_row = row;
+	}
+
+	return (1);
+}
+
+int
+TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample)
+{
+	int e;
+
+	if (!TIFFCheckRead(tif, 0))
+		return (-1);
+	if( (e = TIFFSeek(tif, row, sample)) != 0) {
+		/*
+		 * Decompress desired row into user buffer.
+		 */
+		e = (*tif->tif_decoderow)
+		    (tif, (uint8*) buf, tif->tif_scanlinesize, sample);  
+
+		/* we are now poised at the beginning of the next row */
+		tif->tif_row = row + 1;
+
+		if (e)
+			(*tif->tif_postdecode)(tif, (uint8*) buf,
+			    tif->tif_scanlinesize);  
+	}
+	return (e > 0 ? 1 : -1);
+}
+
+/*
+ * Read a strip of data and decompress the specified
+ * amount into the user-supplied buffer.
+ */
+tmsize_t
+TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
+{
+	static const char module[] = "TIFFReadEncodedStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 rowsperstrip;
+	uint32 stripsperplane;
+	uint32 stripinplane;
+	uint16 plane, comp;
+	uint32 rows;
+	tmsize_t stripsize;
+	if (!TIFFCheckRead(tif,0))
+		return((tmsize_t)(-1));
+	if (strip>=td->td_nstrips)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,
+		    "%lu: Strip out of range, max %lu",(unsigned long)strip,
+		    (unsigned long)td->td_nstrips);
+		return((tmsize_t)(-1));
+	}
+	/*
+	 * Calculate the strip size according to the number of
+	 * rows in the strip (check for truncated last strip on any
+	 * of the separations).
+	 */
+	rowsperstrip=td->td_rowsperstrip;
+	if (rowsperstrip>td->td_imagelength)
+		rowsperstrip=td->td_imagelength;
+	stripsperplane=((td->td_imagelength+rowsperstrip-1)/rowsperstrip);
+	stripinplane=(strip%stripsperplane);
+	plane=(strip/stripsperplane);
+	rows=td->td_imagelength-stripinplane*rowsperstrip;
+	if (rows>rowsperstrip)
+		rows=rowsperstrip;
+	stripsize=TIFFVStripSize(tif,rows);
+	if (stripsize==0)
+		return((tmsize_t)(-1));
+	if ((size!=(tmsize_t)(-1))&&(size<stripsize))
+		stripsize=size;
+
+	/*
+	 * discard those.
+	 * keep code modified by Changjin Gao.
+	 * Xiaochuan Liu 20100828.
+	 */
+	/*if (!TIFFFillStrip(tif,strip))
+		return((tmsize_t)(-1));
+	if ((*tif->tif_decodestrip)(tif,buf,stripsize,plane)<=0)
+		return((tmsize_t)(-1));
+	(*tif->tif_postdecode)(tif,buf,stripsize);
+	return(stripsize);*/
+	
+	/*
+	* Changjin Gao 20110726 fixed decode error issue.
+	* Test file: mantis #27308 020511-1158450.tiff.
+	*/
+	comp = COMPRESSION_NONE;
+StripDecode:
+	if (TIFFFillStrip(tif, strip) && (*tif->tif_decodestrip)(tif, buf, stripsize, plane) > 0)
+	{
+		(*tif->tif_postdecode)(tif, buf, stripsize);
+		return (stripsize);
+	}
+	else
+	{
+		if (comp < 9)
+		{
+			TIFFSetField(tif, TIFFTAG_COMPRESSION, comp);
+			TIFFSetField(tif, TIFFTAG_FAXMODE,FAXMODE_CLASSIC);
+			comp++;
+			goto StripDecode;
+		}
+
+		return ((tsize_t) -1);
+	}
+}
+
+static tmsize_t
+TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,
+    const char* module)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ))
+        return ((tmsize_t)(-1));
+        
+	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+	if (!isMapped(tif)) {
+		tmsize_t cc;
+
+		if (!SeekOK(tif, td->td_stripoffset[strip])) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Seek error at scanline %lu, strip %lu",
+			    (unsigned long) tif->tif_row, (unsigned long) strip);
+			return ((tmsize_t)(-1));
+		}
+		cc = TIFFReadFile(tif, buf, size);
+		if (cc != size) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+		"Read error at scanline %lu; got %I64u bytes, expected %I64u",
+				     (unsigned long) tif->tif_row,
+				     (unsigned __int64) cc,
+				     (unsigned __int64) size);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+		"Read error at scanline %lu; got %llu bytes, expected %llu",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long long) cc,
+				     (unsigned long long) size);
+#endif
+			return ((tmsize_t)(-1));
+		}
+	} else {
+		tmsize_t ma,mb;
+		tmsize_t n;
+		ma=(tmsize_t)td->td_stripoffset[strip];
+		mb=ma+size;
+		if (((uint64)ma!=td->td_stripoffset[strip])||(ma>tif->tif_size))
+			n=0;
+		else if ((mb<ma)||(mb<size)||(mb>tif->tif_size))
+			n=tif->tif_size-ma;
+		else
+			n=size;
+		if (n!=size) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+	"Read error at scanline %lu, strip %lu; got %I64u bytes, expected %I64u",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) strip,
+				     (unsigned __int64) n,
+				     (unsigned __int64) size);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+	"Read error at scanline %lu, strip %lu; got %llu bytes, expected %llu",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) strip,
+				     (unsigned long long) n,
+				     (unsigned long long) size);
+#endif
+			return ((tmsize_t)(-1));
+		}
+		_TIFFmemcpy(buf, tif->tif_base + ma,
+			    size);
+	}
+	return (size);
+}
+
+/*
+ * Read a strip of data from the file.
+ */
+tmsize_t
+TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
+{
+	static const char module[] = "TIFFReadRawStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 bytecount;
+	tmsize_t bytecountm;
+
+	if (!TIFFCheckRead(tif, 0))
+		return ((tmsize_t)(-1));
+	if (strip >= td->td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		     "%lu: Strip out of range, max %lu",
+		     (unsigned long) strip,
+		     (unsigned long) td->td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	if (tif->tif_flags&TIFF_NOREADRAW)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Compression scheme does not support access to raw uncompressed data");
+		return ((tmsize_t)(-1));
+	}
+	bytecount = td->td_stripbytecount[strip];
+	if (bytecount <= 0) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%I64u: Invalid strip byte count, strip %lu",
+			     (unsigned __int64) bytecount,
+			     (unsigned long) strip);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%llu: Invalid strip byte count, strip %lu",
+			     (unsigned long long) bytecount,
+			     (unsigned long) strip);
+#endif
+		return ((tmsize_t)(-1));
+	}
+	bytecountm = (tmsize_t)bytecount;
+	if ((uint64)bytecountm!=bytecount) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Integer overflow");
+		return ((tmsize_t)(-1));
+	}
+	if (size != (tmsize_t)(-1) && size < bytecountm)
+		bytecountm = size;
+	return (TIFFReadRawStrip1(tif, strip, buf, bytecountm, module));
+}
+
+/*
+ * Read the specified strip and setup for decoding. The data buffer is
+ * expanded, as necessary, to hold the strip's data.
+ */
+int
+TIFFFillStrip(TIFF* tif, uint32 strip)
+{
+	static const char module[] = "TIFFFillStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+        return 0;
+        
+	if ((tif->tif_flags&TIFF_NOREADRAW)==0)
+	{
+		uint64 bytecount = td->td_stripbytecount[strip];
+		if (bytecount <= 0) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"Invalid strip byte count %I64u, strip %lu",
+				     (unsigned __int64) bytecount,
+				     (unsigned long) strip);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"Invalid strip byte count %llu, strip %lu",
+				     (unsigned long long) bytecount,
+				     (unsigned long) strip);
+#endif
+			return (0);
+		}
+		if (isMapped(tif) &&
+		    (isFillOrder(tif, td->td_fillorder)
+		    || (tif->tif_flags & TIFF_NOBITREV))) {
+			/*
+			 * The image is mapped into memory and we either don't
+			 * need to flip bits or the compression routine is
+			 * going to handle this operation itself.  In this
+			 * case, avoid copying the raw data and instead just
+			 * reference the data from the memory mapped file
+			 * image.  This assumes that the decompression
+			 * routines do not modify the contents of the raw data
+			 * buffer (if they try to, the application will get a
+			 * fault since the file is mapped read-only).
+			 */
+			if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+				_TIFFfree(tif->tif_rawdata);
+				tif->tif_rawdata = NULL;
+				tif->tif_rawdatasize = 0;
+			}
+			tif->tif_flags &= ~TIFF_MYBUFFER;
+			/*
+			 * We must check for overflow, potentially causing
+			 * an OOB read. Instead of simple
+			 *
+			 *  td->td_stripoffset[strip]+bytecount > tif->tif_size
+			 *
+			 * comparison (which can overflow) we do the following
+			 * two comparisons:
+			 */
+			if (bytecount > (uint64)tif->tif_size ||
+			    td->td_stripoffset[strip] > (uint64)tif->tif_size - bytecount) {
+				/*
+				 * This error message might seem strange, but
+				 * it's what would happen if a read were done
+				 * instead.
+				 */
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+				TIFFErrorExt(tif->tif_clientdata, module,
+
+					"Read error on strip %lu; "
+					"got %I64u bytes, expected %I64u",
+					(unsigned long) strip,
+					(unsigned __int64) tif->tif_size - td->td_stripoffset[strip],
+					(unsigned __int64) bytecount);
+#else
+				TIFFErrorExt(tif->tif_clientdata, module,
+
+					"Read error on strip %lu; "
+					"got %llu bytes, expected %llu",
+					(unsigned long) strip,
+					(unsigned long long) tif->tif_size - td->td_stripoffset[strip],
+					(unsigned long long) bytecount);
+#endif
+				tif->tif_curstrip = NOSTRIP;
+				return (0);
+			}
+			tif->tif_rawdatasize = (tmsize_t)bytecount;
+			tif->tif_rawdata = tif->tif_base + (tmsize_t)td->td_stripoffset[strip];
+                        tif->tif_rawdataoff = 0;
+                        tif->tif_rawdataloaded = (tmsize_t) bytecount;
+
+			/* 
+			 * When we have tif_rawdata reference directly into the memory mapped file
+			 * we need to be pretty careful about how we use the rawdata.  It is not
+			 * a general purpose working buffer as it normally otherwise is.  So we
+			 * keep track of this fact to avoid using it improperly.
+			 */
+			tif->tif_flags |= TIFF_BUFFERMMAP;
+		} else {
+			/*
+			 * Expand raw data buffer, if needed, to hold data
+			 * strip coming from file (perhaps should set upper
+			 * bound on the size of a buffer we'll use?).
+			 */
+			tmsize_t bytecountm;
+			bytecountm=(tmsize_t)bytecount;
+			if ((uint64)bytecountm!=bytecount)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+				return(0);
+			}
+			if (bytecountm > tif->tif_rawdatasize) {
+				tif->tif_curstrip = NOSTRIP;
+				if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					    "Data buffer too small to hold strip %lu",
+					    (unsigned long) strip);
+					return (0);
+				}
+				if (!TIFFReadBufferSetup(tif, 0, bytecountm))
+					return (0);
+			}
+			if (tif->tif_flags&TIFF_BUFFERMMAP) {
+				tif->tif_curstrip = NOSTRIP;
+				if (!TIFFReadBufferSetup(tif, 0, bytecountm))
+					return (0);
+			}
+			if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata,
+				bytecountm, module) != bytecountm)
+				return (0);
+
+                        tif->tif_rawdataoff = 0;
+                        tif->tif_rawdataloaded = bytecountm;
+                        
+			if (!isFillOrder(tif, td->td_fillorder) &&
+			    (tif->tif_flags & TIFF_NOBITREV) == 0)
+				TIFFReverseBits(tif->tif_rawdata, bytecountm);
+                }
+	}
+	return (TIFFStartStrip(tif, strip));
+}
+
+/*
+ * Tile-oriented Read Support
+ * Contributed by Nancy Cam (Silicon Graphics).
+ */
+
+/*
+ * Read and decompress a tile of data.  The
+ * tile is selected by the (x,y,z,s) coordinates.
+ */
+tmsize_t
+TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s)
+{
+	if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s))
+		return ((tmsize_t)(-1));
+	return (TIFFReadEncodedTile(tif,
+	    TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1)));
+}
+
+/*
+ * Read a tile of data and decompress the specified
+ * amount into the user-supplied buffer.
+ */
+tmsize_t
+TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size)
+{
+	static const char module[] = "TIFFReadEncodedTile";
+	TIFFDirectory *td = &tif->tif_dir;
+	tmsize_t tilesize = tif->tif_tilesize;
+
+	if (!TIFFCheckRead(tif, 1))
+		return ((tmsize_t)(-1));
+	if (tile >= td->td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "%lu: Tile out of range, max %lu",
+		    (unsigned long) tile, (unsigned long) td->td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	if (size == (tmsize_t)(-1))
+		size = tilesize;
+	else if (size > tilesize)
+		size = tilesize;
+	if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif,
+	    (uint8*) buf, size, (uint16)(tile/td->td_stripsperimage))) {
+		(*tif->tif_postdecode)(tif, (uint8*) buf, size);
+		return (size);
+	} else
+		return ((tmsize_t)(-1));
+}
+
+static tmsize_t
+TIFFReadRawTile1(TIFF* tif, uint32 tile, void* buf, tmsize_t size, const char* module)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ))
+        return ((tmsize_t)(-1));
+
+	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+	if (!isMapped(tif)) {
+		tmsize_t cc;
+
+		if (!SeekOK(tif, td->td_stripoffset[tile])) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Seek error at row %lu, col %lu, tile %lu",
+			    (unsigned long) tif->tif_row,
+			    (unsigned long) tif->tif_col,
+			    (unsigned long) tile);
+			return ((tmsize_t)(-1));
+		}
+		cc = TIFFReadFile(tif, buf, size);
+		if (cc != size) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+	"Read error at row %lu, col %lu; got %I64u bytes, expected %I64u",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) tif->tif_col,
+				     (unsigned __int64) cc,
+				     (unsigned __int64) size);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+	"Read error at row %lu, col %lu; got %llu bytes, expected %llu",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) tif->tif_col,
+				     (unsigned long long) cc,
+				     (unsigned long long) size);
+#endif
+			return ((tmsize_t)(-1));
+		}
+	} else {
+		tmsize_t ma,mb;
+		tmsize_t n;
+		ma=(tmsize_t)td->td_stripoffset[tile];
+		mb=ma+size;
+		if (((uint64)ma!=td->td_stripoffset[tile])||(ma>tif->tif_size))
+			n=0;
+		else if ((mb<ma)||(mb<size)||(mb>tif->tif_size))
+			n=tif->tif_size-ma;
+		else
+			n=size;
+		if (n!=size) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+"Read error at row %lu, col %lu, tile %lu; got %I64u bytes, expected %I64u",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) tif->tif_col,
+				     (unsigned long) tile,
+				     (unsigned __int64) n,
+				     (unsigned __int64) size);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+"Read error at row %lu, col %lu, tile %lu; got %llu bytes, expected %llu",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) tif->tif_col,
+				     (unsigned long) tile,
+				     (unsigned long long) n,
+				     (unsigned long long) size);
+#endif
+			return ((tmsize_t)(-1));
+		}
+		_TIFFmemcpy(buf, tif->tif_base + ma, size);
+	}
+	return (size);
+}
+
+/*
+ * Read a tile of data from the file.
+ */
+tmsize_t
+TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size)
+{
+	static const char module[] = "TIFFReadRawTile";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 bytecount64;
+	tmsize_t bytecountm;
+
+	if (!TIFFCheckRead(tif, 1))
+		return ((tmsize_t)(-1));
+	if (tile >= td->td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "%lu: Tile out of range, max %lu",
+		    (unsigned long) tile, (unsigned long) td->td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	if (tif->tif_flags&TIFF_NOREADRAW)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module,
+		"Compression scheme does not support access to raw uncompressed data");
+		return ((tmsize_t)(-1));
+	}
+	bytecount64 = td->td_stripbytecount[tile];
+	if (size != (tmsize_t)(-1) && (uint64)size < bytecount64)
+		bytecount64 = (uint64)size;
+	bytecountm = (tmsize_t)bytecount64;
+	if ((uint64)bytecountm!=bytecount64)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		return ((tmsize_t)(-1));
+	}
+	return (TIFFReadRawTile1(tif, tile, buf, bytecountm, module));
+}
+
+/*
+ * Read the specified tile and setup for decoding. The data buffer is
+ * expanded, as necessary, to hold the tile's data.
+ */
+int
+TIFFFillTile(TIFF* tif, uint32 tile)
+{
+	static const char module[] = "TIFFFillTile";
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+        return 0;
+        
+	if ((tif->tif_flags&TIFF_NOREADRAW)==0)
+	{
+		uint64 bytecount = td->td_stripbytecount[tile];
+		if (bytecount <= 0) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%I64u: Invalid tile byte count, tile %lu",
+				     (unsigned __int64) bytecount,
+				     (unsigned long) tile);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%llu: Invalid tile byte count, tile %lu",
+				     (unsigned long long) bytecount,
+				     (unsigned long) tile);
+#endif
+			return (0);
+		}
+		if (isMapped(tif) &&
+		    (isFillOrder(tif, td->td_fillorder)
+		     || (tif->tif_flags & TIFF_NOBITREV))) {
+			/*
+			 * The image is mapped into memory and we either don't
+			 * need to flip bits or the compression routine is
+			 * going to handle this operation itself.  In this
+			 * case, avoid copying the raw data and instead just
+			 * reference the data from the memory mapped file
+			 * image.  This assumes that the decompression
+			 * routines do not modify the contents of the raw data
+			 * buffer (if they try to, the application will get a
+			 * fault since the file is mapped read-only).
+			 */
+			if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+				_TIFFfree(tif->tif_rawdata);
+				tif->tif_rawdata = NULL;
+				tif->tif_rawdatasize = 0;
+			}
+			tif->tif_flags &= ~TIFF_MYBUFFER;
+			/*
+			 * We must check for overflow, potentially causing
+			 * an OOB read. Instead of simple
+			 *
+			 *  td->td_stripoffset[tile]+bytecount > tif->tif_size
+			 *
+			 * comparison (which can overflow) we do the following
+			 * two comparisons:
+			 */
+			if (bytecount > (uint64)tif->tif_size ||
+			    td->td_stripoffset[tile] > (uint64)tif->tif_size - bytecount) {
+				tif->tif_curtile = NOTILE;
+				return (0);
+			}
+			tif->tif_rawdatasize = (tmsize_t)bytecount;
+			tif->tif_rawdata =
+				tif->tif_base + (tmsize_t)td->td_stripoffset[tile];
+                        tif->tif_rawdataoff = 0;
+                        tif->tif_rawdataloaded = (tmsize_t) bytecount;
+			tif->tif_flags |= TIFF_BUFFERMMAP;
+		} else {
+			/*
+			 * Expand raw data buffer, if needed, to hold data
+			 * tile coming from file (perhaps should set upper
+			 * bound on the size of a buffer we'll use?).
+			 */
+			tmsize_t bytecountm;
+			bytecountm=(tmsize_t)bytecount;
+			if ((uint64)bytecountm!=bytecount)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+				return(0);
+			}
+			if (bytecountm > tif->tif_rawdatasize) {
+				tif->tif_curtile = NOTILE;
+				if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					    "Data buffer too small to hold tile %lu",
+					    (unsigned long) tile);
+					return (0);
+				}
+				if (!TIFFReadBufferSetup(tif, 0, bytecountm))
+					return (0);
+			}
+			if (tif->tif_flags&TIFF_BUFFERMMAP) {
+				tif->tif_curtile = NOTILE;
+				if (!TIFFReadBufferSetup(tif, 0, bytecountm))
+					return (0);
+			}
+
+			if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata,
+			    bytecountm, module) != bytecountm)
+				return (0);
+
+                        tif->tif_rawdataoff = 0;
+                        tif->tif_rawdataloaded = bytecountm;
+                        
+			if (!isFillOrder(tif, td->td_fillorder) &&
+			    (tif->tif_flags & TIFF_NOBITREV) == 0)
+				TIFFReverseBits(tif->tif_rawdata,
+                                                tif->tif_rawdataloaded);
+		}
+	}
+	return (TIFFStartTile(tif, tile));
+}
+
+/*
+ * Setup the raw data buffer in preparation for
+ * reading a strip of raw data.  If the buffer
+ * is specified as zero, then a buffer of appropriate
+ * size is allocated by the library.  Otherwise,
+ * the client must guarantee that the buffer is
+ * large enough to hold any individual strip of
+ * raw data.
+ */
+int
+TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size)
+{
+	static const char module[] = "TIFFReadBufferSetup";
+
+	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+	tif->tif_flags &= ~TIFF_BUFFERMMAP;
+
+	if (tif->tif_rawdata) {
+		if (tif->tif_flags & TIFF_MYBUFFER)
+			_TIFFfree(tif->tif_rawdata);
+		tif->tif_rawdata = NULL;
+		tif->tif_rawdatasize = 0;
+	}
+	if (bp) {
+		tif->tif_rawdatasize = size;
+		tif->tif_rawdata = (uint8*) bp;
+		tif->tif_flags &= ~TIFF_MYBUFFER;
+	} else {
+		tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64((uint64)size, 1024);
+		if (tif->tif_rawdatasize==0)
+			tif->tif_rawdatasize=(tmsize_t)(-1);
+		tif->tif_rawdata = (uint8*) _TIFFmalloc(tif->tif_rawdatasize);
+		tif->tif_flags |= TIFF_MYBUFFER;
+	}
+	if (tif->tif_rawdata == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "No space for data buffer at scanline %lu",
+		    (unsigned long) tif->tif_row);
+		tif->tif_rawdatasize = 0;
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Set state to appear as if a
+ * strip has just been read in.
+ */
+static int
+TIFFStartStrip(TIFF* tif, uint32 strip)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+        return 0;
+
+	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+		if (!(*tif->tif_setupdecode)(tif))
+			return (0);
+		tif->tif_flags |= TIFF_CODERSETUP;
+	}
+	tif->tif_curstrip = strip;
+	tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+        tif->tif_flags &= ~TIFF_BUF4WRITE;
+
+	if (tif->tif_flags&TIFF_NOREADRAW)
+	{
+		tif->tif_rawcp = NULL;
+		tif->tif_rawcc = 0;  
+	}
+	else
+	{
+		tif->tif_rawcp = tif->tif_rawdata;
+		tif->tif_rawcc = (tmsize_t)td->td_stripbytecount[strip];
+	}
+	return ((*tif->tif_predecode)(tif,
+			(uint16)(strip / td->td_stripsperimage)));
+}
+
+/*
+ * Set state to appear as if a
+ * tile has just been read in.
+ */
+static int
+TIFFStartTile(TIFF* tif, uint32 tile)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+        return 0;
+
+	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+		if (!(*tif->tif_setupdecode)(tif))
+			return (0);
+		tif->tif_flags |= TIFF_CODERSETUP;
+	}
+	tif->tif_curtile = tile;
+	tif->tif_row =
+	    (tile % TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth)) *
+		td->td_tilelength;
+	tif->tif_col =
+	    (tile % TIFFhowmany_32(td->td_imagelength, td->td_tilelength)) *
+		td->td_tilewidth;
+        tif->tif_flags &= ~TIFF_BUF4WRITE;
+	if (tif->tif_flags&TIFF_NOREADRAW)
+	{
+		tif->tif_rawcp = NULL;
+		tif->tif_rawcc = 0;
+	}
+	else
+	{
+		tif->tif_rawcp = tif->tif_rawdata;
+		tif->tif_rawcc = (tmsize_t)td->td_stripbytecount[tile];
+	}
+	return ((*tif->tif_predecode)(tif,
+			(uint16)(tile/td->td_stripsperimage)));
+}
+
+static int
+TIFFCheckRead(TIFF* tif, int tiles)
+{
+	if (tif->tif_mode == O_WRONLY) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "File not open for reading");
+		return (0);
+	}
+	if (tiles ^ isTiled(tif)) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ?
+		    "Can not read tiles from a stripped image" :
+		    "Can not read scanlines from a tiled image");
+		return (0);
+	}
+	return (1);
+}
+
+void
+_TIFFNoPostDecode(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif; (void) buf; (void) cc;
+}
+
+void
+_TIFFSwab16BitData(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif;
+    assert((cc & 1) == 0);
+    TIFFSwabArrayOfShort((uint16*) buf, cc/2);
+}
+
+void
+_TIFFSwab24BitData(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif;
+    assert((cc % 3) == 0);
+    TIFFSwabArrayOfTriples((uint8*) buf, cc/3);
+}
+
+void
+_TIFFSwab32BitData(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif;
+    assert((cc & 3) == 0);
+    TIFFSwabArrayOfLong((uint32*) buf, cc/4);
+}
+
+void
+_TIFFSwab64BitData(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif;
+    assert((cc & 7) == 0);
+    TIFFSwabArrayOfDouble((double*) buf, cc/8);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_strip.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_strip.c
new file mode 100644
index 0000000..047c598
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_strip.c
@@ -0,0 +1,386 @@
+/* $Id: tif_strip.c,v 1.35 2012-06-06 05:33:55 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Strip-organized Image Support Routines.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+/*
+ * Compute which strip a (row,sample) value is in.
+ */
+uint32
+TIFFComputeStrip(TIFF* tif, uint32 row, uint16 sample)
+{
+	static const char module[] = "TIFFComputeStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 strip;
+
+	strip = row / td->td_rowsperstrip;
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+		if (sample >= td->td_samplesperpixel) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "%lu: Sample out of range, max %lu",
+			    (unsigned long) sample, (unsigned long) td->td_samplesperpixel);
+			return (0);
+		}
+		strip += (uint32)sample*td->td_stripsperimage;
+	}
+	return (strip);
+}
+
+/*
+ * Compute how many strips are in an image.
+ */
+uint32
+TIFFNumberOfStrips(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 nstrips;
+
+	nstrips = (td->td_rowsperstrip == (uint32) -1 ? 1 :
+	     TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip));
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+		nstrips = _TIFFMultiply32(tif, nstrips, (uint32)td->td_samplesperpixel,
+		    "TIFFNumberOfStrips");
+	return (nstrips);
+}
+
+/*
+ * Compute the # bytes in a variable height, row-aligned strip.
+ */
+uint64
+TIFFVStripSize64(TIFF* tif, uint32 nrows)
+{
+	static const char module[] = "TIFFVStripSize64";
+	TIFFDirectory *td = &tif->tif_dir;
+	if (nrows==(uint32)(-1))
+		nrows=td->td_imagelength;
+	if ((td->td_planarconfig==PLANARCONFIG_CONTIG)&&
+	    (td->td_photometric == PHOTOMETRIC_YCBCR)&&
+	    (!isUpSampled(tif)))
+	{
+		/*
+		 * Packed YCbCr data contain one Cb+Cr for every
+		 * HorizontalSampling*VerticalSampling Y values.
+		 * Must also roundup width and height when calculating
+		 * since images that are not a multiple of the
+		 * horizontal/vertical subsampling area include
+		 * YCbCr data for the extended image.
+		 */
+		uint16 ycbcrsubsampling[2];
+		uint16 samplingblock_samples;
+		uint32 samplingblocks_hor;
+		uint32 samplingblocks_ver;
+		uint64 samplingrow_samples;
+		uint64 samplingrow_size;
+		if(td->td_samplesperpixel!=3)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,
+			    "Invalid td_samplesperpixel value");
+			return 0;
+		}
+		TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0,
+		    ycbcrsubsampling+1);
+		if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4)
+		    ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,
+				     "Invalid YCbCr subsampling (%dx%d)", 
+				     ycbcrsubsampling[0], 
+				     ycbcrsubsampling[1] );
+			return 0;
+		}
+		samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2;
+		samplingblocks_hor=TIFFhowmany_32(td->td_imagewidth,ycbcrsubsampling[0]);
+		samplingblocks_ver=TIFFhowmany_32(nrows,ycbcrsubsampling[1]);
+		samplingrow_samples=_TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module);
+		samplingrow_size=TIFFhowmany8_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module));
+		return(_TIFFMultiply64(tif,samplingrow_size,samplingblocks_ver,module));
+	}
+	else
+		return(_TIFFMultiply64(tif,nrows,TIFFScanlineSize64(tif),module));
+}
+tmsize_t
+TIFFVStripSize(TIFF* tif, uint32 nrows)
+{
+	static const char module[] = "TIFFVStripSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFVStripSize64(tif,nrows);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute the # bytes in a raw strip.
+ */
+uint64
+TIFFRawStripSize64(TIFF* tif, uint32 strip)
+{
+	static const char module[] = "TIFFRawStripSize64";
+	TIFFDirectory* td = &tif->tif_dir;
+	uint64 bytecount = td->td_stripbytecount[strip];
+
+	if (bytecount == 0)
+	{
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%I64u: Invalid strip byte count, strip %lu",
+			     (unsigned __int64) bytecount,
+			     (unsigned long) strip);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%llu: Invalid strip byte count, strip %lu",
+			     (unsigned long long) bytecount,
+			     (unsigned long) strip);
+#endif
+		bytecount = (uint64) -1;
+	}
+
+	return bytecount;
+}
+tmsize_t
+TIFFRawStripSize(TIFF* tif, uint32 strip)
+{
+	static const char module[] = "TIFFRawStripSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFRawStripSize64(tif,strip);
+	if (m==(uint64)(-1))
+		n=(tmsize_t)(-1);
+	else
+	{
+		n=(tmsize_t)m;
+		if ((uint64)n!=m)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+			n=0;
+		}
+	}
+	return(n);
+}
+
+/*
+ * Compute the # bytes in a (row-aligned) strip.
+ *
+ * Note that if RowsPerStrip is larger than the
+ * recorded ImageLength, then the strip size is
+ * truncated to reflect the actual space required
+ * to hold the strip.
+ */
+uint64
+TIFFStripSize64(TIFF* tif)
+{
+	TIFFDirectory* td = &tif->tif_dir;
+	uint32 rps = td->td_rowsperstrip;
+	if (rps > td->td_imagelength)
+		rps = td->td_imagelength;
+	return (TIFFVStripSize64(tif, rps));
+}
+tmsize_t
+TIFFStripSize(TIFF* tif)
+{
+	static const char module[] = "TIFFStripSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFStripSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute a default strip size based on the image
+ * characteristics and a requested value.  If the
+ * request is <1 then we choose a strip size according
+ * to certain heuristics.
+ */
+uint32
+TIFFDefaultStripSize(TIFF* tif, uint32 request)
+{
+	return (*tif->tif_defstripsize)(tif, request);
+}
+
+uint32
+_TIFFDefaultStripSize(TIFF* tif, uint32 s)
+{
+	if ((int32) s < 1) {
+		/*
+		 * If RowsPerStrip is unspecified, try to break the
+		 * image up into strips that are approximately
+		 * STRIP_SIZE_DEFAULT bytes long.
+		 */
+		uint64 scanlinesize;
+		uint64 rows;
+		scanlinesize=TIFFScanlineSize64(tif);
+		if (scanlinesize==0)
+			scanlinesize=1;
+		rows=(uint64)STRIP_SIZE_DEFAULT/scanlinesize;
+		if (rows==0)
+			rows=1;
+		else if (rows>0xFFFFFFFF)
+			rows=0xFFFFFFFF;
+		s=(uint32)rows;
+	}
+	return (s);
+}
+
+/*
+ * Return the number of bytes to read/write in a call to
+ * one of the scanline-oriented i/o routines.  Note that
+ * this number may be 1/samples-per-pixel if data is
+ * stored as separate planes.
+ * The ScanlineSize in case of YCbCrSubsampling is defined as the
+ * strip size divided by the strip height, i.e. the size of a pack of vertical
+ * subsampling lines divided by vertical subsampling. It should thus make
+ * sense when multiplied by a multiple of vertical subsampling.
+ */
+uint64
+TIFFScanlineSize64(TIFF* tif)
+{
+	static const char module[] = "TIFFScanlineSize64";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 scanline_size;
+	if (td->td_planarconfig==PLANARCONFIG_CONTIG)
+	{
+		if ((td->td_photometric==PHOTOMETRIC_YCBCR)&&
+		    (td->td_samplesperpixel==3)&&
+		    (!isUpSampled(tif)))
+		{
+			uint16 ycbcrsubsampling[2];
+			uint16 samplingblock_samples;
+			uint32 samplingblocks_hor;
+			uint64 samplingrow_samples;
+			uint64 samplingrow_size;
+			if(td->td_samplesperpixel!=3)
+			{
+                            TIFFErrorExt(tif->tif_clientdata,module,
+                                         "Invalid td_samplesperpixel value");
+                            return 0;
+			}
+			TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,
+                                              ycbcrsubsampling+0,
+                                              ycbcrsubsampling+1);
+			if (((ycbcrsubsampling[0]!=1)&&(ycbcrsubsampling[0]!=2)&&(ycbcrsubsampling[0]!=4)) ||
+			    ((ycbcrsubsampling[1]!=1)&&(ycbcrsubsampling[1]!=2)&&(ycbcrsubsampling[1]!=4)))
+			{
+                            TIFFErrorExt(tif->tif_clientdata,module,
+                                         "Invalid YCbCr subsampling");
+                            return 0;
+			}
+			samplingblock_samples = ycbcrsubsampling[0]*ycbcrsubsampling[1]+2;
+			samplingblocks_hor = TIFFhowmany_32(td->td_imagewidth,ycbcrsubsampling[0]);
+			samplingrow_samples = _TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module);
+			samplingrow_size = TIFFhowmany_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module),8);
+			scanline_size = (samplingrow_size/ycbcrsubsampling[1]);
+		}
+		else
+		{
+			uint64 scanline_samples;
+			scanline_samples=_TIFFMultiply64(tif,td->td_imagewidth,td->td_samplesperpixel,module);
+			scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,scanline_samples,td->td_bitspersample,module),8);
+		}
+	}
+	else
+		scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,td->td_imagewidth,td->td_bitspersample,module),8);
+	return(scanline_size);
+}
+tmsize_t
+TIFFScanlineSize(TIFF* tif)
+{
+	static const char module[] = "TIFFScanlineSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFScanlineSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer arithmetic overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Return the number of bytes required to store a complete
+ * decoded and packed raster scanline (as opposed to the
+ * I/O size returned by TIFFScanlineSize which may be less
+ * if data is store as separate planes).
+ */
+uint64
+TIFFRasterScanlineSize64(TIFF* tif)
+{
+	static const char module[] = "TIFFRasterScanlineSize64";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 scanline;
+
+	scanline = _TIFFMultiply64(tif, td->td_bitspersample, td->td_imagewidth, module);
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+		scanline = _TIFFMultiply64(tif, scanline, td->td_samplesperpixel, module);
+		return (TIFFhowmany8_64(scanline));
+	} else
+		return (_TIFFMultiply64(tif, TIFFhowmany8_64(scanline),
+		    td->td_samplesperpixel, module));
+}
+tmsize_t
+TIFFRasterScanlineSize(TIFF* tif)
+{
+	static const char module[] = "TIFFRasterScanlineSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFRasterScanlineSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer arithmetic overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_swab.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_swab.c
new file mode 100644
index 0000000..a60814b
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_swab.c
@@ -0,0 +1,313 @@
+/* $Id: tif_swab.c,v 1.13 2010-03-10 18:56:49 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library Bit & Byte Swapping Support.
+ *
+ * XXX We assume short = 16-bits and long = 32-bits XXX
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+#ifndef TIFFSwabShort
+void
+TIFFSwabShort(uint16* wp)
+{
+	register unsigned char* cp = (unsigned char*) wp;
+	unsigned char t;
+	assert(sizeof(uint16)==2);
+	t = cp[1]; cp[1] = cp[0]; cp[0] = t;
+}
+#endif
+
+#ifndef TIFFSwabLong
+void
+TIFFSwabLong(uint32* lp)
+{
+	register unsigned char* cp = (unsigned char*) lp;
+	unsigned char t;
+	assert(sizeof(uint32)==4);
+	t = cp[3]; cp[3] = cp[0]; cp[0] = t;
+	t = cp[2]; cp[2] = cp[1]; cp[1] = t;
+}
+#endif
+
+#ifndef TIFFSwabLong8
+void
+TIFFSwabLong8(uint64* lp)
+{
+	register unsigned char* cp = (unsigned char*) lp;
+	unsigned char t;
+	assert(sizeof(uint64)==8);
+	t = cp[7]; cp[7] = cp[0]; cp[0] = t;
+	t = cp[6]; cp[6] = cp[1]; cp[1] = t;
+	t = cp[5]; cp[5] = cp[2]; cp[2] = t;
+	t = cp[4]; cp[4] = cp[3]; cp[3] = t;
+}
+#endif
+
+#ifndef TIFFSwabArrayOfShort
+void
+TIFFSwabArrayOfShort(register uint16* wp, tmsize_t n)
+{
+	register unsigned char* cp;
+	register unsigned char t;
+	assert(sizeof(uint16)==2);
+	/* XXX unroll loop some */
+	while (n-- > 0) {
+		cp = (unsigned char*) wp;
+		t = cp[1]; cp[1] = cp[0]; cp[0] = t;
+		wp++;
+	}
+}
+#endif
+
+#ifndef TIFFSwabArrayOfTriples
+void
+TIFFSwabArrayOfTriples(register uint8* tp, tmsize_t n)
+{
+	unsigned char* cp;
+	unsigned char t;
+
+	/* XXX unroll loop some */
+	while (n-- > 0) {
+		cp = (unsigned char*) tp;
+		t = cp[2]; cp[2] = cp[0]; cp[0] = t;
+		tp += 3;
+	}
+}
+#endif
+
+#ifndef TIFFSwabArrayOfLong
+void
+TIFFSwabArrayOfLong(register uint32* lp, tmsize_t n)
+{
+	register unsigned char *cp;
+	register unsigned char t;
+	assert(sizeof(uint32)==4);
+	/* XXX unroll loop some */
+	while (n-- > 0) {
+		cp = (unsigned char *)lp;
+		t = cp[3]; cp[3] = cp[0]; cp[0] = t;
+		t = cp[2]; cp[2] = cp[1]; cp[1] = t;
+		lp++;
+	}
+}
+#endif
+
+#ifndef TIFFSwabArrayOfLong8
+void
+TIFFSwabArrayOfLong8(register uint64* lp, tmsize_t n)
+{
+	register unsigned char *cp;
+	register unsigned char t;
+	assert(sizeof(uint64)==8);
+	/* XXX unroll loop some */
+	while (n-- > 0) {
+		cp = (unsigned char *)lp;
+		t = cp[7]; cp[7] = cp[0]; cp[0] = t;
+		t = cp[6]; cp[6] = cp[1]; cp[1] = t;
+		t = cp[5]; cp[5] = cp[2]; cp[2] = t;
+		t = cp[4]; cp[4] = cp[3]; cp[3] = t;
+		lp++;
+	}
+}
+#endif
+
+#ifndef TIFFSwabFloat
+void
+TIFFSwabFloat(float* fp)
+{
+	register unsigned char* cp = (unsigned char*) fp;
+	unsigned char t;
+	assert(sizeof(float)==4);
+	t = cp[3]; cp[3] = cp[0]; cp[0] = t;
+	t = cp[2]; cp[2] = cp[1]; cp[1] = t;
+}
+#endif
+
+#ifndef TIFFSwabArrayOfFloat
+void
+TIFFSwabArrayOfFloat(register float* fp, tmsize_t n)
+{
+	register unsigned char *cp;
+	register unsigned char t;
+	assert(sizeof(float)==4);
+	/* XXX unroll loop some */
+	while (n-- > 0) {
+		cp = (unsigned char *)fp;
+		t = cp[3]; cp[3] = cp[0]; cp[0] = t;
+		t = cp[2]; cp[2] = cp[1]; cp[1] = t;
+		fp++;
+	}
+}
+#endif
+
+#ifndef TIFFSwabDouble
+void
+TIFFSwabDouble(double *dp)
+{
+	register unsigned char* cp = (unsigned char*) dp;
+	unsigned char t;
+	assert(sizeof(double)==8);
+	t = cp[7]; cp[7] = cp[0]; cp[0] = t;
+	t = cp[6]; cp[6] = cp[1]; cp[1] = t;
+	t = cp[5]; cp[5] = cp[2]; cp[2] = t;
+	t = cp[4]; cp[4] = cp[3]; cp[3] = t;
+}
+#endif
+
+#ifndef TIFFSwabArrayOfDouble
+void
+TIFFSwabArrayOfDouble(double* dp, tmsize_t n)
+{
+	register unsigned char *cp;
+	register unsigned char t;
+	assert(sizeof(double)==8);
+	/* XXX unroll loop some */
+	while (n-- > 0) {
+		cp = (unsigned char *)dp;
+		t = cp[7]; cp[7] = cp[0]; cp[0] = t;
+		t = cp[6]; cp[6] = cp[1]; cp[1] = t;
+		t = cp[5]; cp[5] = cp[2]; cp[2] = t;
+		t = cp[4]; cp[4] = cp[3]; cp[3] = t;
+		dp++;
+	}
+}
+#endif
+
+/*
+ * Bit reversal tables.  TIFFBitRevTable[<byte>] gives
+ * the bit reversed value of <byte>.  Used in various
+ * places in the library when the FillOrder requires
+ * bit reversal of byte values (e.g. CCITT Fax 3
+ * encoding/decoding).  TIFFNoBitRevTable is provided
+ * for algorithms that want an equivalent table that
+ * do not reverse bit values.
+ */
+static const unsigned char TIFFBitRevTable[256] = {
+    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+static const unsigned char TIFFNoBitRevTable[256] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 
+    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
+    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
+    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 
+    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 
+    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 
+    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 
+    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 
+    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 
+};
+
+const unsigned char*
+TIFFGetBitRevTable(int reversed)
+{
+	return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable);
+}
+
+void
+TIFFReverseBits(uint8* cp, tmsize_t n)  
+{
+	for (; n > 8; n -= 8) {
+		cp[0] = TIFFBitRevTable[cp[0]];
+		cp[1] = TIFFBitRevTable[cp[1]];
+		cp[2] = TIFFBitRevTable[cp[2]];
+		cp[3] = TIFFBitRevTable[cp[3]];
+		cp[4] = TIFFBitRevTable[cp[4]];
+		cp[5] = TIFFBitRevTable[cp[5]];
+		cp[6] = TIFFBitRevTable[cp[6]];
+		cp[7] = TIFFBitRevTable[cp[7]];
+		cp += 8;
+	}
+	while (n-- > 0)
+		*cp = TIFFBitRevTable[*cp], cp++;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_thunder.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_thunder.c
new file mode 100644
index 0000000..e7cb0d4
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_thunder.c
@@ -0,0 +1,210 @@
+/* $Id: tif_thunder.c,v 1.12 2011-04-02 20:54:09 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include <assert.h>
+#ifdef THUNDER_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * ThunderScan 4-bit Compression Algorithm Support
+ */
+
+/*
+ * ThunderScan uses an encoding scheme designed for
+ * 4-bit pixel values.  Data is encoded in bytes, with
+ * each byte split into a 2-bit code word and a 6-bit
+ * data value.  The encoding gives raw data, runs of
+ * pixels, or pixel values encoded as a delta from the
+ * previous pixel value.  For the latter, either 2-bit
+ * or 3-bit delta values are used, with the deltas packed
+ * into a single byte.
+ */
+#define	THUNDER_DATA		0x3f	/* mask for 6-bit data */
+#define	THUNDER_CODE		0xc0	/* mask for 2-bit code word */
+/* code values */
+#define	THUNDER_RUN		0x00	/* run of pixels w/ encoded count */
+#define	THUNDER_2BITDELTAS	0x40	/* 3 pixels w/ encoded 2-bit deltas */
+#define	    DELTA2_SKIP		2	/* skip code for 2-bit deltas */
+#define	THUNDER_3BITDELTAS	0x80	/* 2 pixels w/ encoded 3-bit deltas */
+#define	    DELTA3_SKIP		4	/* skip code for 3-bit deltas */
+#define	THUNDER_RAW		0xc0	/* raw data encoded */
+
+static const int twobitdeltas[4] = { 0, 1, 0, -1 };
+static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 };
+
+#define	SETPIXEL(op, v) {                     \
+	lastpixel = (v) & 0xf;                \
+        if ( npixels < maxpixels )         \
+        {                                     \
+	  if (npixels++ & 1)                  \
+	    *op++ |= lastpixel;               \
+	  else                                \
+	    op[0] = (uint8) (lastpixel << 4); \
+        }                                     \
+}
+
+static int
+ThunderSetupDecode(TIFF* tif)
+{
+	static const char module[] = "ThunderSetupDecode";
+
+        if( tif->tif_dir.td_bitspersample != 4 )
+        {
+                TIFFErrorExt(tif->tif_clientdata, module,
+                             "Wrong bitspersample value (%d), Thunder decoder only supports 4bits per sample.",
+                             (int) tif->tif_dir.td_bitspersample );
+                return 0;
+        }
+        
+
+	return (1);
+}
+
+static int
+ThunderDecode(TIFF* tif, uint8* op, tmsize_t maxpixels)
+{
+	static const char module[] = "ThunderDecode";
+	register unsigned char *bp;
+	register tmsize_t cc;
+	unsigned int lastpixel;
+	tmsize_t npixels;
+
+	bp = (unsigned char *)tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	lastpixel = 0;
+	npixels = 0;
+	while (cc > 0 && npixels < maxpixels) {
+		int n, delta;
+
+		n = *bp++, cc--;
+		switch (n & THUNDER_CODE) {
+		case THUNDER_RUN:		/* pixel run */
+			/*
+			 * Replicate the last pixel n times,
+			 * where n is the lower-order 6 bits.
+			 */
+			if (npixels & 1) {
+				op[0] |= lastpixel;
+				lastpixel = *op++; npixels++; n--;
+			} else
+				lastpixel |= lastpixel << 4;
+			npixels += n;
+			if (npixels < maxpixels) {
+				for (; n > 0; n -= 2)
+					*op++ = (uint8) lastpixel;
+			}
+			if (n == -1)
+				*--op &= 0xf0;
+			lastpixel &= 0xf;
+			break;
+		case THUNDER_2BITDELTAS:	/* 2-bit deltas */
+			if ((delta = ((n >> 4) & 3)) != DELTA2_SKIP)
+				SETPIXEL(op, lastpixel + twobitdeltas[delta]);
+			if ((delta = ((n >> 2) & 3)) != DELTA2_SKIP)
+				SETPIXEL(op, lastpixel + twobitdeltas[delta]);
+			if ((delta = (n & 3)) != DELTA2_SKIP)
+				SETPIXEL(op, lastpixel + twobitdeltas[delta]);
+			break;
+		case THUNDER_3BITDELTAS:	/* 3-bit deltas */
+			if ((delta = ((n >> 3) & 7)) != DELTA3_SKIP)
+				SETPIXEL(op, lastpixel + threebitdeltas[delta]);
+			if ((delta = (n & 7)) != DELTA3_SKIP)
+				SETPIXEL(op, lastpixel + threebitdeltas[delta]);
+			break;
+		case THUNDER_RAW:		/* raw data */
+			SETPIXEL(op, n);
+			break;
+		}
+	}
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	if (npixels != maxpixels) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%s data at scanline %lu (%I64u != %I64u)",
+			     npixels < maxpixels ? "Not enough" : "Too much",
+			     (unsigned long) tif->tif_row,
+			     (unsigned __int64) npixels,
+			     (unsigned __int64) maxpixels);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%s data at scanline %lu (%llu != %llu)",
+			     npixels < maxpixels ? "Not enough" : "Too much",
+			     (unsigned long) tif->tif_row,
+			     (unsigned long long) npixels,
+			     (unsigned long long) maxpixels);
+#endif
+		return (0);
+	}
+
+        return (1);
+}
+
+static int
+ThunderDecodeRow(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "ThunderDecodeRow";
+	uint8* row = buf;
+	
+	(void) s;
+	if (occ % tif->tif_scanlinesize)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (0);
+	}
+	while (occ > 0) {
+		if (!ThunderDecode(tif, row, tif->tif_dir.td_imagewidth))
+			return (0);
+		occ -= tif->tif_scanlinesize;
+		row += tif->tif_scanlinesize;
+	}
+	return (1);
+}
+
+int
+TIFFInitThunderScan(TIFF* tif, int scheme)
+{
+	(void) scheme;
+
+        tif->tif_setupdecode = ThunderSetupDecode;
+	tif->tif_decoderow = ThunderDecodeRow;
+	tif->tif_decodestrip = ThunderDecodeRow; 
+	return (1);
+}
+#endif /* THUNDER_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_tile.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_tile.c
new file mode 100644
index 0000000..24ba82c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_tile.c
@@ -0,0 +1,302 @@
+/* $Id: tif_tile.c,v 1.23 2012-06-06 05:33:55 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Tiled Image Support Routines.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+/*
+ * Compute which tile an (x,y,z,s) value is in.
+ */
+uint32
+TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 dx = td->td_tilewidth;
+	uint32 dy = td->td_tilelength;
+	uint32 dz = td->td_tiledepth;
+	uint32 tile = 1;
+
+	if (td->td_imagedepth == 1)
+		z = 0;
+	if (dx == (uint32) -1)
+		dx = td->td_imagewidth;
+	if (dy == (uint32) -1)
+		dy = td->td_imagelength;
+	if (dz == (uint32) -1)
+		dz = td->td_imagedepth;
+	if (dx != 0 && dy != 0 && dz != 0) {
+		uint32 xpt = TIFFhowmany_32(td->td_imagewidth, dx);
+		uint32 ypt = TIFFhowmany_32(td->td_imagelength, dy);
+		uint32 zpt = TIFFhowmany_32(td->td_imagedepth, dz);
+
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) 
+			tile = (xpt*ypt*zpt)*s +
+			     (xpt*ypt)*(z/dz) +
+			     xpt*(y/dy) +
+			     x/dx;
+		else
+			tile = (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx;
+	}
+	return (tile);
+}
+
+/*
+ * Check an (x,y,z,s) coordinate
+ * against the image bounds.
+ */
+int
+TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+	if (x >= td->td_imagewidth) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%lu: Col out of range, max %lu",
+			     (unsigned long) x,
+			     (unsigned long) (td->td_imagewidth - 1));
+		return (0);
+	}
+	if (y >= td->td_imagelength) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%lu: Row out of range, max %lu",
+			     (unsigned long) y,
+			     (unsigned long) (td->td_imagelength - 1));
+		return (0);
+	}
+	if (z >= td->td_imagedepth) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%lu: Depth out of range, max %lu",
+			     (unsigned long) z,
+			     (unsigned long) (td->td_imagedepth - 1));
+		return (0);
+	}
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE &&
+	    s >= td->td_samplesperpixel) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%lu: Sample out of range, max %lu",
+			     (unsigned long) s,
+			     (unsigned long) (td->td_samplesperpixel - 1));
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Compute how many tiles are in an image.
+ */
+uint32
+TIFFNumberOfTiles(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 dx = td->td_tilewidth;
+	uint32 dy = td->td_tilelength;
+	uint32 dz = td->td_tiledepth;
+	uint32 ntiles;
+
+	if (dx == (uint32) -1)
+		dx = td->td_imagewidth;
+	if (dy == (uint32) -1)
+		dy = td->td_imagelength;
+	if (dz == (uint32) -1)
+		dz = td->td_imagedepth;
+	ntiles = (dx == 0 || dy == 0 || dz == 0) ? 0 :
+	    _TIFFMultiply32(tif, _TIFFMultiply32(tif, TIFFhowmany_32(td->td_imagewidth, dx),
+	    TIFFhowmany_32(td->td_imagelength, dy),
+	    "TIFFNumberOfTiles"),
+	    TIFFhowmany_32(td->td_imagedepth, dz), "TIFFNumberOfTiles");
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+		ntiles = _TIFFMultiply32(tif, ntiles, td->td_samplesperpixel,
+		    "TIFFNumberOfTiles");
+	return (ntiles);
+}
+
+/*
+ * Compute the # bytes in each row of a tile.
+ */
+uint64
+TIFFTileRowSize64(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 rowsize;
+
+	if (td->td_tilelength == 0 || td->td_tilewidth == 0)
+		return (0);
+	rowsize = _TIFFMultiply64(tif, td->td_bitspersample, td->td_tilewidth,
+	    "TIFFTileRowSize");
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG)
+		rowsize = _TIFFMultiply64(tif, rowsize, td->td_samplesperpixel,
+		    "TIFFTileRowSize");
+	return (TIFFhowmany8_64(rowsize));
+}
+tmsize_t
+TIFFTileRowSize(TIFF* tif)
+{
+	static const char module[] = "TIFFTileRowSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFTileRowSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute the # bytes in a variable length, row-aligned tile.
+ */
+uint64
+TIFFVTileSize64(TIFF* tif, uint32 nrows)
+{
+	static const char module[] = "TIFFVTileSize64";
+	TIFFDirectory *td = &tif->tif_dir;
+	if (td->td_tilelength == 0 || td->td_tilewidth == 0 ||
+	    td->td_tiledepth == 0)
+		return (0);
+	if ((td->td_planarconfig==PLANARCONFIG_CONTIG)&&
+	    (td->td_photometric==PHOTOMETRIC_YCBCR)&&
+	    (td->td_samplesperpixel==3)&&
+	    (!isUpSampled(tif)))
+	{
+		/*
+		 * Packed YCbCr data contain one Cb+Cr for every
+		 * HorizontalSampling*VerticalSampling Y values.
+		 * Must also roundup width and height when calculating
+		 * since images that are not a multiple of the
+		 * horizontal/vertical subsampling area include
+		 * YCbCr data for the extended image.
+		 */
+		uint16 ycbcrsubsampling[2];
+		uint16 samplingblock_samples;
+		uint32 samplingblocks_hor;
+		uint32 samplingblocks_ver;
+		uint64 samplingrow_samples;
+		uint64 samplingrow_size;
+		TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0,
+		    ycbcrsubsampling+1);
+		if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4)
+		    ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,
+				     "Invalid YCbCr subsampling (%dx%d)", 
+				     ycbcrsubsampling[0], 
+				     ycbcrsubsampling[1] );
+			return 0;
+		}
+		samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2;
+		samplingblocks_hor=TIFFhowmany_32(td->td_tilewidth,ycbcrsubsampling[0]);
+		samplingblocks_ver=TIFFhowmany_32(nrows,ycbcrsubsampling[1]);
+		samplingrow_samples=_TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module);
+		samplingrow_size=TIFFhowmany8_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module));
+		return(_TIFFMultiply64(tif,samplingrow_size,samplingblocks_ver,module));
+	}
+	else
+		return(_TIFFMultiply64(tif,nrows,TIFFTileRowSize64(tif),module));
+}
+tmsize_t
+TIFFVTileSize(TIFF* tif, uint32 nrows)
+{
+	static const char module[] = "TIFFVTileSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFVTileSize64(tif,nrows);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute the # bytes in a row-aligned tile.
+ */
+uint64
+TIFFTileSize64(TIFF* tif)
+{
+	return (TIFFVTileSize64(tif, tif->tif_dir.td_tilelength));
+}
+tmsize_t
+TIFFTileSize(TIFF* tif)
+{
+	static const char module[] = "TIFFTileSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFTileSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute a default tile size based on the image
+ * characteristics and a requested value.  If a
+ * request is <1 then we choose a size according
+ * to certain heuristics.
+ */
+void
+TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
+{
+	(*tif->tif_deftilesize)(tif, tw, th);
+}
+
+void
+_TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
+{
+	(void) tif;
+	if (*(int32*) tw < 1)
+		*tw = 256;
+	if (*(int32*) th < 1)
+		*th = 256;
+	/* roundup to a multiple of 16 per the spec */
+	if (*tw & 0xf)
+		*tw = TIFFroundup_32(*tw, 16);
+	if (*th & 0xf)
+		*th = TIFFroundup_32(*th, 16);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_version.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_version.c
new file mode 100644
index 0000000..41aa8b0
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_version.c
@@ -0,0 +1,43 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_version.c,v 1.3 2010-03-10 18:56:49 bfriesen Exp $ */
+/*
+ * Copyright (c) 1992-1997 Sam Leffler
+ * Copyright (c) 1992-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+static const char TIFFVersion[] = TIFFLIB_VERSION_STR;
+
+const char*
+TIFFGetVersion(void)
+{
+	return (TIFFVersion);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_warning.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_warning.c
new file mode 100644
index 0000000..ac6b3b9
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_warning.c
@@ -0,0 +1,87 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_warning.c,v 1.3 2010-03-10 18:56:49 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+
+/*TIFFErrorHandlerExt _TIFFwarningHandlerExt = NULL;*/
+/* Modify here for use _TIFFwarningHandlerExt by Sunliang.Liu 20090715 */
+TIFFErrorHandler _TIFFwarningHandler = NULL;
+
+TIFFErrorHandler
+TIFFSetWarningHandler(TIFFErrorHandler handler)
+{
+	TIFFErrorHandler prev = _TIFFwarningHandler;
+	_TIFFwarningHandler = handler;
+	return (prev);
+}
+
+TIFFErrorHandlerExt
+TIFFSetWarningHandlerExt(TIFFErrorHandlerExt handler)
+{
+	TIFFErrorHandlerExt prev = _TIFFwarningHandlerExt;
+	_TIFFwarningHandlerExt = handler;
+	return (prev);
+}
+
+void
+TIFFWarning(const char* module, const char* fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	if (_TIFFwarningHandler)
+		(*_TIFFwarningHandler)(module, fmt, ap);
+	if (_TIFFwarningHandlerExt)
+		(*_TIFFwarningHandlerExt)(0, module, fmt, ap);
+	va_end(ap);
+}
+
+void
+TIFFWarningExt(thandle_t fd, const char* module, const char* fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	if (_TIFFwarningHandler)
+		(*_TIFFwarningHandler)(module, fmt, ap);
+	if (_TIFFwarningHandlerExt)
+		(*_TIFFwarningHandlerExt)(fd, module, fmt, ap);
+	va_end(ap);
+}
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_write.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_write.c
new file mode 100644
index 0000000..11a537c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_write.c
@@ -0,0 +1,774 @@
+/* $Id: tif_write.c,v 1.37 2012-08-13 22:10:17 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Scanline-oriented Write Support
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#include <stdio.h>
+
+#define STRIPINCR	20		/* expansion factor on strip array */
+
+#define WRITECHECKSTRIPS(tif, module)				\
+	(((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),0,module))
+#define WRITECHECKTILES(tif, module)				\
+	(((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),1,module))
+#define BUFFERCHECK(tif)					\
+	((((tif)->tif_flags & TIFF_BUFFERSETUP) && tif->tif_rawdata) ||	\
+	    TIFFWriteBufferSetup((tif), NULL, (tmsize_t) -1))
+
+static int TIFFGrowStrips(TIFF* tif, uint32 delta, const char* module);
+static int TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc);
+
+int
+TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample)
+{
+	static const char module[] = "TIFFWriteScanline";
+	register TIFFDirectory *td;
+	int status, imagegrew = 0;
+	uint32 strip;
+
+	if (!WRITECHECKSTRIPS(tif, module))
+		return (-1);
+	/*
+	 * Handle delayed allocation of data buffer.  This
+	 * permits it to be sized more intelligently (using
+	 * directory information).
+	 */
+	if (!BUFFERCHECK(tif))
+		return (-1);
+        tif->tif_flags |= TIFF_BUF4WRITE; /* not strictly sure this is right*/
+
+	td = &tif->tif_dir;
+	/*
+	 * Extend image length if needed
+	 * (but only for PlanarConfig=1).
+	 */
+	if (row >= td->td_imagelength) {	/* extend image */
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Can not change \"ImageLength\" when using separate planes");
+			return (-1);
+		}
+		td->td_imagelength = row+1;
+		imagegrew = 1;
+	}
+	/*
+	 * Calculate strip and check for crossings.
+	 */
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+		if (sample >= td->td_samplesperpixel) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "%lu: Sample out of range, max %lu",
+			    (unsigned long) sample, (unsigned long) td->td_samplesperpixel);
+			return (-1);
+		}
+		strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip;
+	} else
+		strip = row / td->td_rowsperstrip;
+	/*
+	 * Check strip array to make sure there's space. We don't support
+	 * dynamically growing files that have data organized in separate
+	 * bitplanes because it's too painful.  In that case we require that
+	 * the imagelength be set properly before the first write (so that the
+	 * strips array will be fully allocated above).
+	 */
+	if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module))
+		return (-1);
+	if (strip != tif->tif_curstrip) {
+		/*
+		 * Changing strips -- flush any data present.
+		 */
+		if (!TIFFFlushData(tif))
+			return (-1);
+		tif->tif_curstrip = strip;
+		/*
+		 * Watch out for a growing image.  The value of strips/image
+		 * will initially be 1 (since it can't be deduced until the
+		 * imagelength is known).
+		 */
+		if (strip >= td->td_stripsperimage && imagegrew)
+			td->td_stripsperimage =
+			    TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip);
+		tif->tif_row =
+		    (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+		if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+			if (!(*tif->tif_setupencode)(tif))
+				return (-1);
+			tif->tif_flags |= TIFF_CODERSETUP;
+		}
+        
+		tif->tif_rawcc = 0;
+		tif->tif_rawcp = tif->tif_rawdata;
+
+		if( td->td_stripbytecount[strip] > 0 )
+		{
+			/* if we are writing over existing tiles, zero length */
+			td->td_stripbytecount[strip] = 0;
+
+			/* this forces TIFFAppendToStrip() to do a seek */
+			tif->tif_curoff = 0;
+		}
+
+		if (!(*tif->tif_preencode)(tif, sample))
+			return (-1);
+		tif->tif_flags |= TIFF_POSTENCODE;
+	}
+	/*
+	 * Ensure the write is either sequential or at the
+	 * beginning of a strip (or that we can randomly
+	 * access the data -- i.e. no encoding).
+	 */
+	if (row != tif->tif_row) {
+		if (row < tif->tif_row) {
+			/*
+			 * Moving backwards within the same strip:
+			 * backup to the start and then decode
+			 * forward (below).
+			 */
+			tif->tif_row = (strip % td->td_stripsperimage) *
+			    td->td_rowsperstrip;
+			tif->tif_rawcp = tif->tif_rawdata;
+		}
+		/*
+		 * Seek forward to the desired row.
+		 */
+		if (!(*tif->tif_seek)(tif, row - tif->tif_row))
+			return (-1);
+		tif->tif_row = row;
+	}
+
+	/* swab if needed - note that source buffer will be altered */
+	tif->tif_postdecode( tif, (uint8*) buf, tif->tif_scanlinesize );
+
+	status = (*tif->tif_encoderow)(tif, (uint8*) buf,
+	    tif->tif_scanlinesize, sample);
+
+        /* we are now poised at the beginning of the next row */
+	tif->tif_row = row + 1;
+	return (status);
+}
+
+/*
+ * Encode the supplied data and write it to the
+ * specified strip.
+ *
+ * NB: Image length must be setup before writing.
+ */
+tmsize_t
+TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFWriteEncodedStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint16 sample;
+
+	if (!WRITECHECKSTRIPS(tif, module))
+		return ((tmsize_t) -1);
+	/*
+	 * Check strip array to make sure there's space.
+	 * We don't support dynamically growing files that
+	 * have data organized in separate bitplanes because
+	 * it's too painful.  In that case we require that
+	 * the imagelength be set properly before the first
+	 * write (so that the strips array will be fully
+	 * allocated above).
+	 */
+	if (strip >= td->td_nstrips) {
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Can not grow image by strips when using separate planes");
+			return ((tmsize_t) -1);
+		}
+		if (!TIFFGrowStrips(tif, 1, module))
+			return ((tmsize_t) -1);
+		td->td_stripsperimage =
+		    TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip);  
+	}
+	/*
+	 * Handle delayed allocation of data buffer.  This
+	 * permits it to be sized according to the directory
+	 * info.
+	 */
+	if (!BUFFERCHECK(tif))
+		return ((tmsize_t) -1);
+
+        tif->tif_flags |= TIFF_BUF4WRITE;
+	tif->tif_curstrip = strip;
+
+	tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+		if (!(*tif->tif_setupencode)(tif))
+			return ((tmsize_t) -1);
+		tif->tif_flags |= TIFF_CODERSETUP;
+	}
+
+	if( td->td_stripbytecount[strip] > 0 )
+        {
+            /* Make sure that at the first attempt of rewriting the tile, we will have */
+            /* more bytes available in the output buffer than the previous byte count, */
+            /* so that TIFFAppendToStrip() will detect the overflow when it is called the first */
+            /* time if the new compressed tile is bigger than the older one. (GDAL #4771) */
+            if( tif->tif_rawdatasize <= (tmsize_t)td->td_stripbytecount[strip] )
+            {
+                if( !(TIFFWriteBufferSetup(tif, NULL,
+                    (tmsize_t)TIFFroundup_64((uint64)(td->td_stripbytecount[strip] + 1), 1024))) )
+                    return ((tmsize_t)(-1));
+            }
+
+	    /* Force TIFFAppendToStrip() to consider placing data at end
+               of file. */
+            tif->tif_curoff = 0;
+        }
+
+    tif->tif_rawcc = 0;
+    tif->tif_rawcp = tif->tif_rawdata;
+
+	tif->tif_flags &= ~TIFF_POSTENCODE;
+	sample = (uint16)(strip / td->td_stripsperimage);
+	if (!(*tif->tif_preencode)(tif, sample))
+		return ((tmsize_t) -1);
+
+        /* swab if needed - note that source buffer will be altered */
+	tif->tif_postdecode( tif, (uint8*) data, cc );
+
+	if (!(*tif->tif_encodestrip)(tif, (uint8*) data, cc, sample))
+		return (0);
+	if (!(*tif->tif_postencode)(tif))
+		return ((tmsize_t) -1);
+	if (!isFillOrder(tif, td->td_fillorder) &&
+	    (tif->tif_flags & TIFF_NOBITREV) == 0)
+		TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc);
+	if (tif->tif_rawcc > 0 &&
+	    !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc))
+		return ((tmsize_t) -1);
+	tif->tif_rawcc = 0;
+	tif->tif_rawcp = tif->tif_rawdata;
+	return (cc);
+}
+
+/*
+ * Write the supplied data to the specified strip.
+ *
+ * NB: Image length must be setup before writing.
+ */
+tmsize_t
+TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFWriteRawStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+
+	if (!WRITECHECKSTRIPS(tif, module))
+		return ((tmsize_t) -1);
+	/*
+	 * Check strip array to make sure there's space.
+	 * We don't support dynamically growing files that
+	 * have data organized in separate bitplanes because
+	 * it's too painful.  In that case we require that
+	 * the imagelength be set properly before the first
+	 * write (so that the strips array will be fully
+	 * allocated above).
+	 */
+	if (strip >= td->td_nstrips) {
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Can not grow image by strips when using separate planes");
+			return ((tmsize_t) -1);
+		}
+		/*
+		 * Watch out for a growing image.  The value of
+		 * strips/image will initially be 1 (since it
+		 * can't be deduced until the imagelength is known).
+		 */
+		if (strip >= td->td_stripsperimage)
+			td->td_stripsperimage =
+			    TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip);
+		if (!TIFFGrowStrips(tif, 1, module))
+			return ((tmsize_t) -1);
+	}
+	tif->tif_curstrip = strip;
+	tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+	return (TIFFAppendToStrip(tif, strip, (uint8*) data, cc) ?
+	    cc : (tmsize_t) -1);
+}
+
+/*
+ * Write and compress a tile of data.  The
+ * tile is selected by the (x,y,z,s) coordinates.
+ */
+tmsize_t
+TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s)
+{
+	if (!TIFFCheckTile(tif, x, y, z, s))
+		return ((tmsize_t)(-1));
+	/*
+	 * NB: A tile size of -1 is used instead of tif_tilesize knowing
+	 *     that TIFFWriteEncodedTile will clamp this to the tile size.
+	 *     This is done because the tile size may not be defined until
+	 *     after the output buffer is setup in TIFFWriteBufferSetup.
+	 */
+	return (TIFFWriteEncodedTile(tif,
+	    TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1)));
+}
+
+/*
+ * Encode the supplied data and write it to the
+ * specified tile.  There must be space for the
+ * data.  The function clamps individual writes
+ * to a tile to the tile size, but does not (and
+ * can not) check that multiple writes to the same
+ * tile do not write more than tile size data.
+ *
+ * NB: Image length must be setup before writing; this
+ *     interface does not support automatically growing
+ *     the image on each write (as TIFFWriteScanline does).
+ */
+tmsize_t
+TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFWriteEncodedTile";
+	TIFFDirectory *td;
+	uint16 sample;
+
+	if (!WRITECHECKTILES(tif, module))
+		return ((tmsize_t)(-1));
+	td = &tif->tif_dir;
+	if (tile >= td->td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Tile %lu out of range, max %lu",
+		    (unsigned long) tile, (unsigned long) td->td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	/*
+	 * Handle delayed allocation of data buffer.  This
+	 * permits it to be sized more intelligently (using
+	 * directory information).
+	 */
+	if (!BUFFERCHECK(tif))
+		return ((tmsize_t)(-1));
+
+        tif->tif_flags |= TIFF_BUF4WRITE;
+	tif->tif_curtile = tile;
+
+	if( td->td_stripbytecount[tile] > 0 )
+        {
+            /* Make sure that at the first attempt of rewriting the tile, we will have */
+            /* more bytes available in the output buffer than the previous byte count, */
+            /* so that TIFFAppendToStrip() will detect the overflow when it is called the first */
+            /* time if the new compressed tile is bigger than the older one. (GDAL #4771) */
+            if( tif->tif_rawdatasize <= (tmsize_t)td->td_stripbytecount[tile] )
+            {
+                if( !(TIFFWriteBufferSetup(tif, NULL,
+                    (tmsize_t)TIFFroundup_64((uint64)(td->td_stripbytecount[tile] + 1), 1024))) )
+                    return ((tmsize_t)(-1));
+            }
+
+	    /* Force TIFFAppendToStrip() to consider placing data at end
+               of file. */
+            tif->tif_curoff = 0;
+        }
+
+    tif->tif_rawcc = 0;
+    tif->tif_rawcp = tif->tif_rawdata;
+
+	/* 
+	 * Compute tiles per row & per column to compute
+	 * current row and column
+	 */
+	tif->tif_row = (tile % TIFFhowmany_32(td->td_imagelength, td->td_tilelength))
+		* td->td_tilelength;
+	tif->tif_col = (tile % TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth))
+		* td->td_tilewidth;
+
+	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+		if (!(*tif->tif_setupencode)(tif))
+			return ((tmsize_t)(-1));
+		tif->tif_flags |= TIFF_CODERSETUP;
+	}
+	tif->tif_flags &= ~TIFF_POSTENCODE;
+	sample = (uint16)(tile/td->td_stripsperimage);
+	if (!(*tif->tif_preencode)(tif, sample))
+		return ((tmsize_t)(-1));
+	/*
+	 * Clamp write amount to the tile size.  This is mostly
+	 * done so that callers can pass in some large number
+	 * (e.g. -1) and have the tile size used instead.
+	 */
+	if ( cc < 1 || cc > tif->tif_tilesize)
+		cc = tif->tif_tilesize;
+
+        /* swab if needed - note that source buffer will be altered */
+	tif->tif_postdecode( tif, (uint8*) data, cc );
+
+	if (!(*tif->tif_encodetile)(tif, (uint8*) data, cc, sample))
+		return (0);
+	if (!(*tif->tif_postencode)(tif))
+		return ((tmsize_t)(-1));
+	if (!isFillOrder(tif, td->td_fillorder) &&
+	    (tif->tif_flags & TIFF_NOBITREV) == 0)
+		TIFFReverseBits((uint8*)tif->tif_rawdata, tif->tif_rawcc);
+	if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile,
+	    tif->tif_rawdata, tif->tif_rawcc))
+		return ((tmsize_t)(-1));
+	tif->tif_rawcc = 0;
+	tif->tif_rawcp = tif->tif_rawdata;
+	return (cc);
+}
+
+/*
+ * Write the supplied data to the specified strip.
+ * There must be space for the data; we don't check
+ * if strips overlap!
+ *
+ * NB: Image length must be setup before writing; this
+ *     interface does not support automatically growing
+ *     the image on each write (as TIFFWriteScanline does).
+ */
+tmsize_t
+TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFWriteRawTile";
+
+	if (!WRITECHECKTILES(tif, module))
+		return ((tmsize_t)(-1));
+	if (tile >= tif->tif_dir.td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Tile %lu out of range, max %lu",
+		    (unsigned long) tile,
+		    (unsigned long) tif->tif_dir.td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	return (TIFFAppendToStrip(tif, tile, (uint8*) data, cc) ?
+	    cc : (tmsize_t)(-1));
+}
+
+#define	isUnspecified(tif, f) \
+    (TIFFFieldSet(tif,f) && (tif)->tif_dir.td_imagelength == 0)
+
+int
+TIFFSetupStrips(TIFF* tif)
+{
+	TIFFDirectory* td = &tif->tif_dir;
+
+	if (isTiled(tif))
+		td->td_stripsperimage =
+		    isUnspecified(tif, FIELD_TILEDIMENSIONS) ?
+			td->td_samplesperpixel : TIFFNumberOfTiles(tif);
+	else
+		td->td_stripsperimage =
+		    isUnspecified(tif, FIELD_ROWSPERSTRIP) ?
+			td->td_samplesperpixel : TIFFNumberOfStrips(tif);
+	td->td_nstrips = td->td_stripsperimage;
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+		td->td_stripsperimage /= td->td_samplesperpixel;
+	td->td_stripoffset = (uint64 *)
+	    _TIFFmalloc(td->td_nstrips * sizeof (uint64));
+	td->td_stripbytecount = (uint64 *)
+	    _TIFFmalloc(td->td_nstrips * sizeof (uint64));
+	if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL)
+		return (0);
+	/*
+	 * Place data at the end-of-file
+	 * (by setting offsets to zero).
+	 */
+	_TIFFmemset(td->td_stripoffset, 0, td->td_nstrips*sizeof (uint64));
+	_TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint64));
+	TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
+	TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
+	return (1);
+}
+#undef isUnspecified
+
+/*
+ * Verify file is writable and that the directory
+ * information is setup properly.  In doing the latter
+ * we also "freeze" the state of the directory so
+ * that important information is not changed.
+ */
+int
+TIFFWriteCheck(TIFF* tif, int tiles, const char* module)
+{
+	if (tif->tif_mode == O_RDONLY) {
+		TIFFErrorExt(tif->tif_clientdata, module, "File not open for writing");
+		return (0);
+	}
+	if (tiles ^ isTiled(tif)) {
+		TIFFErrorExt(tif->tif_clientdata, module, tiles ?
+		    "Can not write tiles to a stripped image" :
+		    "Can not write scanlines to a tiled image");
+		return (0);
+	}
+
+        _TIFFFillStriles( tif );
+        
+	/*
+	 * On the first write verify all the required information
+	 * has been setup and initialize any data structures that
+	 * had to wait until directory information was set.
+	 * Note that a lot of our work is assumed to remain valid
+	 * because we disallow any of the important parameters
+	 * from changing after we start writing (i.e. once
+	 * TIFF_BEENWRITING is set, TIFFSetField will only allow
+	 * the image's length to be changed).
+	 */
+	if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Must set \"ImageWidth\" before writing data");
+		return (0);
+	}
+	if (tif->tif_dir.td_samplesperpixel == 1) {
+		/* 
+		 * Planarconfiguration is irrelevant in case of single band
+		 * images and need not be included. We will set it anyway,
+		 * because this field is used in other parts of library even
+		 * in the single band case.
+		 */
+		if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG))
+                    tif->tif_dir.td_planarconfig = PLANARCONFIG_CONTIG;
+	} else {
+		if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Must set \"PlanarConfiguration\" before writing data");
+			return (0);
+		}
+	}
+	if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) {
+		tif->tif_dir.td_nstrips = 0;
+		TIFFErrorExt(tif->tif_clientdata, module, "No space for %s arrays",
+		    isTiled(tif) ? "tile" : "strip");
+		return (0);
+	}
+	if (isTiled(tif))
+	{
+		tif->tif_tilesize = TIFFTileSize(tif);
+		if (tif->tif_tilesize == 0)
+			return (0);
+	}
+	else
+		tif->tif_tilesize = (tmsize_t)(-1);
+	tif->tif_scanlinesize = TIFFScanlineSize(tif);
+	if (tif->tif_scanlinesize == 0)
+		return (0);
+	tif->tif_flags |= TIFF_BEENWRITING;
+	return (1);
+}
+
+/*
+ * Setup the raw data buffer used for encoding.
+ */
+int
+TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size)
+{
+	static const char module[] = "TIFFWriteBufferSetup";
+
+	if (tif->tif_rawdata) {
+		if (tif->tif_flags & TIFF_MYBUFFER) {
+			_TIFFfree(tif->tif_rawdata);
+			tif->tif_flags &= ~TIFF_MYBUFFER;
+		}
+		tif->tif_rawdata = NULL;
+	}
+	if (size == (tmsize_t)(-1)) {
+		size = (isTiled(tif) ?
+		    tif->tif_tilesize : TIFFStripSize(tif));
+		/*
+		 * Make raw data buffer at least 8K
+		 */
+		if (size < 8*1024)
+			size = 8*1024;
+		bp = NULL;			/* NB: force malloc */
+	}
+	if (bp == NULL) {
+		bp = _TIFFmalloc(size);
+		if (bp == NULL) {
+			TIFFErrorExt(tif->tif_clientdata, module, "No space for output buffer");
+			return (0);
+		}
+		tif->tif_flags |= TIFF_MYBUFFER;
+	} else
+		tif->tif_flags &= ~TIFF_MYBUFFER;
+	tif->tif_rawdata = (uint8*) bp;
+	tif->tif_rawdatasize = size;
+	tif->tif_rawcc = 0;
+	tif->tif_rawcp = tif->tif_rawdata;
+	tif->tif_flags |= TIFF_BUFFERSETUP;
+	return (1);
+}
+
+/*
+ * Grow the strip data structures by delta strips.
+ */
+static int
+TIFFGrowStrips(TIFF* tif, uint32 delta, const char* module)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64* new_stripoffset;
+	uint64* new_stripbytecount;
+
+	assert(td->td_planarconfig == PLANARCONFIG_CONTIG);
+	new_stripoffset = (uint64*)_TIFFrealloc(td->td_stripoffset,
+		(td->td_nstrips + delta) * sizeof (uint64));
+	new_stripbytecount = (uint64*)_TIFFrealloc(td->td_stripbytecount,
+		(td->td_nstrips + delta) * sizeof (uint64));
+	if (new_stripoffset == NULL || new_stripbytecount == NULL) {
+		if (new_stripoffset)
+			_TIFFfree(new_stripoffset);
+		if (new_stripbytecount)
+			_TIFFfree(new_stripbytecount);
+		td->td_nstrips = 0;
+		TIFFErrorExt(tif->tif_clientdata, module, "No space to expand strip arrays");
+		return (0);
+	}
+	td->td_stripoffset = new_stripoffset;
+	td->td_stripbytecount = new_stripbytecount;
+	_TIFFmemset(td->td_stripoffset + td->td_nstrips,
+		    0, delta*sizeof (uint64));
+	_TIFFmemset(td->td_stripbytecount + td->td_nstrips,
+		    0, delta*sizeof (uint64));
+	td->td_nstrips += delta;
+        tif->tif_flags |= TIFF_DIRTYDIRECT;
+
+	return (1);
+}
+
+/*
+ * Append the data to the specified strip.
+ */
+static int
+TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFAppendToStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 m;
+        int64 old_byte_count = -1;
+
+	if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) {
+            assert(td->td_nstrips > 0);
+
+            if( td->td_stripbytecount[strip] != 0 
+                && td->td_stripoffset[strip] != 0 
+                && td->td_stripbytecount[strip] >= (uint64) cc )
+            {
+                /* 
+                 * There is already tile data on disk, and the new tile
+                 * data we have will fit in the same space.  The only 
+                 * aspect of this that is risky is that there could be
+                 * more data to append to this strip before we are done
+                 * depending on how we are getting called.
+                 */
+                if (!SeekOK(tif, td->td_stripoffset[strip])) {
+                    TIFFErrorExt(tif->tif_clientdata, module,
+                                 "Seek error at scanline %lu",
+                                 (unsigned long)tif->tif_row);
+                    return (0);
+                }
+            }
+            else
+            {
+                /* 
+                 * Seek to end of file, and set that as our location to 
+                 * write this strip.
+                 */
+                td->td_stripoffset[strip] = TIFFSeekFile(tif, 0, SEEK_END);
+                tif->tif_flags |= TIFF_DIRTYSTRIP;
+            }
+
+            tif->tif_curoff = td->td_stripoffset[strip];
+
+            /*
+             * We are starting a fresh strip/tile, so set the size to zero.
+             */
+            old_byte_count = td->td_stripbytecount[strip];
+            td->td_stripbytecount[strip] = 0;
+	}
+
+	m = tif->tif_curoff+cc;
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+		m = (uint32)m;
+	if ((m<tif->tif_curoff)||(m<(uint64)cc))
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Maximum TIFF file size exceeded");
+		return (0);
+	}
+	if (!WriteOK(tif, data, cc)) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Write error at scanline %lu",
+		    (unsigned long) tif->tif_row);
+		    return (0);
+	}
+	tif->tif_curoff = m;
+	td->td_stripbytecount[strip] += cc;
+
+        if( (int64) td->td_stripbytecount[strip] != old_byte_count )
+            tif->tif_flags |= TIFF_DIRTYSTRIP;
+            
+	return (1);
+}
+
+/*
+ * Internal version of TIFFFlushData that can be
+ * called by ``encodestrip routines'' w/o concern
+ * for infinite recursion.
+ */
+int
+TIFFFlushData1(TIFF* tif)
+{
+	if (tif->tif_rawcc > 0 && tif->tif_flags & TIFF_BUF4WRITE ) {
+		if (!isFillOrder(tif, tif->tif_dir.td_fillorder) &&
+		    (tif->tif_flags & TIFF_NOBITREV) == 0)
+			TIFFReverseBits((uint8*)tif->tif_rawdata,
+			    tif->tif_rawcc);
+		if (!TIFFAppendToStrip(tif,
+		    isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip,
+		    tif->tif_rawdata, tif->tif_rawcc))
+			return (0);
+		tif->tif_rawcc = 0;
+		tif->tif_rawcp = tif->tif_rawdata;
+	}
+	return (1);
+}
+
+/*
+ * Set the current write offset.  This should only be
+ * used to set the offset to a known previous location
+ * (very carefully), or to 0 so that the next write gets
+ * appended to the end of the file.
+ */
+void
+TIFFSetWriteOffset(TIFF* tif, toff_t off)
+{
+	tif->tif_curoff = off;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_zip.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_zip.c
new file mode 100644
index 0000000..0bb2a8c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_zip.c
@@ -0,0 +1,471 @@
+/* $Id: tif_zip.c,v 1.31 2011-01-06 16:00:23 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1995-1997 Sam Leffler
+ * Copyright (c) 1995-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_)
+#include "tiffiop.h"
+#ifdef ZIP_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * ZIP (aka Deflate) Compression Support
+ *
+ * This file is simply an interface to the zlib library written by
+ * Jean-loup Gailly and Mark Adler.  You must use version 1.0 or later
+ * of the library: this code assumes the 1.0 API and also depends on
+ * the ability to write the zlib header multiple times (one per strip)
+ * which was not possible with versions prior to 0.95.  Note also that
+ * older versions of this codec avoided this bug by supressing the header
+ * entirely.  This means that files written with the old library cannot
+ * be read; they should be converted to a different compression scheme
+ * and then reconverted.
+ *
+ * The data format used by the zlib library is described in the files
+ * zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the
+ * directory ftp://ftp.uu.net/pub/archiving/zip/doc.  The library was
+ * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz.
+ */
+#include "tif_predict.h"
+#include "../../fx_zlib/include/fx_zlib.h"
+
+#include <stdio.h>
+
+/*
+ * Sigh, ZLIB_VERSION is defined as a string so there's no
+ * way to do a proper check here.  Instead we guess based
+ * on the presence of #defines that were added between the
+ * 0.95 and 1.0 distributions.
+ */
+#if !defined(Z_NO_COMPRESSION) || !defined(Z_DEFLATED)
+#error "Antiquated ZLIB software; you must use version 1.0 or later"
+#endif
+
+/*
+ * State block for each open TIFF
+ * file using ZIP compression/decompression.
+ */
+typedef struct {
+	TIFFPredictorState predict;
+        z_stream        stream;
+	int             zipquality;            /* compression level */
+	int             state;                 /* state flags */
+#define ZSTATE_INIT_DECODE 0x01
+#define ZSTATE_INIT_ENCODE 0x02
+
+	TIFFVGetMethod  vgetparent;            /* super-class method */
+	TIFFVSetMethod  vsetparent;            /* super-class method */
+} ZIPState;
+
+#define ZState(tif)             ((ZIPState*) (tif)->tif_data)
+#define DecoderState(tif)       ZState(tif)
+#define EncoderState(tif)       ZState(tif)
+
+static int ZIPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
+static int ZIPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s);
+
+static int
+ZIPFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+static int
+ZIPSetupDecode(TIFF* tif)
+{
+	static const char module[] = "ZIPSetupDecode";
+	ZIPState* sp = DecoderState(tif);
+
+	assert(sp != NULL);
+        
+        /* if we were last encoding, terminate this mode */
+	if (sp->state & ZSTATE_INIT_ENCODE) {
+	    deflateEnd(&sp->stream);
+	    sp->state = 0;
+	}
+
+	if (inflateInit(&sp->stream) != Z_OK) {
+		TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg);
+		return (0);
+	} else {
+		sp->state |= ZSTATE_INIT_DECODE;
+		return (1);
+	}
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+ZIPPreDecode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "ZIPPreDecode";
+	ZIPState* sp = DecoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+
+	if( (sp->state & ZSTATE_INIT_DECODE) == 0 )
+            tif->tif_setupdecode( tif );
+
+	sp->stream.next_in = tif->tif_rawdata;
+	assert(sizeof(sp->stream.avail_in)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_in = (uInt) tif->tif_rawcc;
+	if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	return (inflateReset(&sp->stream) == Z_OK);
+}
+
+static int
+ZIPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "ZIPDecode";
+	ZIPState* sp = DecoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	assert(sp->state == ZSTATE_INIT_DECODE);
+
+        sp->stream.next_in = tif->tif_rawcp;
+	sp->stream.avail_in = (uInt) tif->tif_rawcc;
+        
+	sp->stream.next_out = op;
+	assert(sizeof(sp->stream.avail_out)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_out = (uInt) occ;
+	if ((tmsize_t)sp->stream.avail_out != occ)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	do {
+		int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
+		if (state == Z_STREAM_END)
+			break;
+		if (state == Z_DATA_ERROR) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Decoding error at scanline %lu, %s",
+			    (unsigned long) tif->tif_row, sp->stream.msg);
+			if (inflateSync(&sp->stream) != Z_OK)
+				return (0);
+			continue;
+		}
+		if (state != Z_OK) {
+			TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+			    sp->stream.msg);
+			return (0);
+		}
+	} while (sp->stream.avail_out > 0);
+	if (sp->stream.avail_out != 0) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Not enough data at scanline %lu (short " TIFF_UINT64_FORMAT " bytes)",
+		    (unsigned long) tif->tif_row, (TIFF_UINT64_T) sp->stream.avail_out);
+		return (0);
+	}
+
+        tif->tif_rawcp = sp->stream.next_in;
+        tif->tif_rawcc = sp->stream.avail_in;
+
+	return (1);
+}
+
+static int
+ZIPSetupEncode(TIFF* tif)
+{
+	static const char module[] = "ZIPSetupEncode";
+	ZIPState* sp = EncoderState(tif);
+
+	assert(sp != NULL);
+	if (sp->state & ZSTATE_INIT_DECODE) {
+		inflateEnd(&sp->stream);
+		sp->state = 0;
+	}
+
+	if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) {
+		TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg);
+		return (0);
+	} else {
+		sp->state |= ZSTATE_INIT_ENCODE;
+		return (1);
+	}
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+ZIPPreEncode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "ZIPPreEncode";
+	ZIPState *sp = EncoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	if( sp->state != ZSTATE_INIT_ENCODE )
+            tif->tif_setupencode( tif );
+
+	sp->stream.next_out = tif->tif_rawdata;
+	assert(sizeof(sp->stream.avail_out)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_out = (uInt)tif->tif_rawdatasize;
+	if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	return (deflateReset(&sp->stream) == Z_OK);
+}
+
+/*
+ * Encode a chunk of pixels.
+ */
+static int
+ZIPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "ZIPEncode";
+	ZIPState *sp = EncoderState(tif);
+
+	assert(sp != NULL);
+	assert(sp->state == ZSTATE_INIT_ENCODE);
+
+	(void) s;
+	sp->stream.next_in = bp;
+	assert(sizeof(sp->stream.avail_in)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_in = (uInt) cc;
+	if ((tmsize_t)sp->stream.avail_in != cc)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	do {
+		if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Encoder error: %s",
+			    sp->stream.msg);
+			return (0);
+		}
+		if (sp->stream.avail_out == 0) {
+			tif->tif_rawcc = tif->tif_rawdatasize;
+			TIFFFlushData1(tif);
+			sp->stream.next_out = tif->tif_rawdata;
+			sp->stream.avail_out = (uInt) tif->tif_rawdatasize;  /* this is a safe typecast, as check is made already in ZIPPreEncode */
+		}
+	} while (sp->stream.avail_in > 0);
+	return (1);
+}
+
+/*
+ * Finish off an encoded strip by flushing the last
+ * string and tacking on an End Of Information code.
+ */
+static int
+ZIPPostEncode(TIFF* tif)
+{
+	static const char module[] = "ZIPPostEncode";
+	ZIPState *sp = EncoderState(tif);
+	int state;
+
+	sp->stream.avail_in = 0;
+	do {
+		state = deflate(&sp->stream, Z_FINISH);
+		switch (state) {
+		case Z_STREAM_END:
+		case Z_OK:
+			if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
+			{
+				tif->tif_rawcc =  tif->tif_rawdatasize - sp->stream.avail_out;
+				TIFFFlushData1(tif);
+				sp->stream.next_out = tif->tif_rawdata;
+				sp->stream.avail_out = (uInt) tif->tif_rawdatasize;  /* this is a safe typecast, as check is made already in ZIPPreEncode */
+			}
+			break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+			    sp->stream.msg);
+			return (0);
+		}
+	} while (state != Z_STREAM_END);
+	return (1);
+}
+
+static void
+ZIPCleanup(TIFF* tif)
+{
+	ZIPState* sp = ZState(tif);
+
+	assert(sp != 0);
+
+	(void)TIFFPredictorCleanup(tif);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+	if (sp->state & ZSTATE_INIT_ENCODE) {
+		deflateEnd(&sp->stream);
+		sp->state = 0;
+	} else if( sp->state & ZSTATE_INIT_DECODE) {
+		inflateEnd(&sp->stream);
+		sp->state = 0;
+	}
+	_TIFFfree(sp);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+ZIPVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	static const char module[] = "ZIPVSetField";
+	ZIPState* sp = ZState(tif);
+
+	switch (tag) {
+	case TIFFTAG_ZIPQUALITY:
+		sp->zipquality = (int) va_arg(ap, int);
+		if ( sp->state&ZSTATE_INIT_ENCODE ) {
+			if (deflateParams(&sp->stream,
+			    sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) {
+				TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+				    sp->stream.msg);
+				return (0);
+			}
+		}
+		return (1);
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+	/*NOTREACHED*/
+}
+
+static int
+ZIPVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	ZIPState* sp = ZState(tif);
+
+	switch (tag) {
+	case TIFFTAG_ZIPQUALITY:
+		*va_arg(ap, int*) = sp->zipquality;
+		break;
+	default:
+		return (*sp->vgetparent)(tif, tag, ap);
+	}
+	return (1);
+}
+
+static const TIFFField zipFields[] = {
+    { TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL },
+};
+
+int
+TIFFInitZIP(TIFF* tif, int scheme)
+{
+	static const char module[] = "TIFFInitZIP";
+	ZIPState* sp;
+
+	assert( (scheme == COMPRESSION_DEFLATE)
+		|| (scheme == COMPRESSION_ADOBE_DEFLATE));
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, zipFields, TIFFArrayCount(zipFields))) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Merging Deflate codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (ZIPState));
+	if (tif->tif_data == NULL)
+		goto bad;
+	sp = ZState(tif);
+	sp->stream.zalloc = NULL;
+	sp->stream.zfree = NULL;
+	sp->stream.opaque = NULL;
+	sp->stream.data_type = Z_BINARY;
+
+	/*
+	 * Override parent get/set field methods.
+	 */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield = ZIPVGetField; /* hook for codec tags */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield = ZIPVSetField; /* hook for codec tags */
+
+	/* Default values for codec-specific fields */
+	sp->zipquality = Z_DEFAULT_COMPRESSION;	/* default comp. level */
+	sp->state = 0;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = ZIPFixupTags; 
+	tif->tif_setupdecode = ZIPSetupDecode;
+	tif->tif_predecode = ZIPPreDecode;
+	tif->tif_decoderow = ZIPDecode;
+	tif->tif_decodestrip = ZIPDecode;
+	tif->tif_decodetile = ZIPDecode;  
+	tif->tif_setupencode = ZIPSetupEncode;
+	tif->tif_preencode = ZIPPreEncode;
+	tif->tif_postencode = ZIPPostEncode;
+	tif->tif_encoderow = ZIPEncode;
+	tif->tif_encodestrip = ZIPEncode;
+	tif->tif_encodetile = ZIPEncode;
+	tif->tif_cleanup = ZIPCleanup;
+	/*
+	 * Setup predictor setup.
+	 */
+	(void) TIFFPredictorInit(tif);
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module,
+		     "No space for ZIP state block");
+	return (0);
+}
+#endif /* ZIP_SUPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
+#endif
+
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiff.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiff.h
new file mode 100644
index 0000000..19b4e79
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiff.h
@@ -0,0 +1,678 @@
+/* $Id: tiff.h,v 1.68 2012-08-19 16:56:35 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFF_
+#define	_TIFF_
+
+#include "tiffconf.h"
+
+/*
+ * Tag Image File Format (TIFF)
+ *
+ * Based on Rev 6.0 from:
+ *    Developer's Desk
+ *    Aldus Corporation
+ *    411 First Ave. South
+ *    Suite 200
+ *    Seattle, WA  98104
+ *    206-622-5500
+ *
+ *    (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf)
+ *
+ * For BigTIFF design notes see the following links
+ *    http://www.remotesensing.org/libtiff/bigtiffdesign.html
+ *    http://www.awaresystems.be/imaging/tiff/bigtiff.html
+ */
+
+#define TIFF_VERSION_CLASSIC 42
+#define TIFF_VERSION_BIG 43
+
+#define TIFF_BIGENDIAN      0x4d4d
+#define TIFF_LITTLEENDIAN   0x4949
+#define MDI_LITTLEENDIAN    0x5045
+#define MDI_BIGENDIAN       0x4550
+
+/*
+ * Intrinsic data types required by the file format:
+ *
+ * 8-bit quantities     int8/uint8
+ * 16-bit quantities    int16/uint16
+ * 32-bit quantities    int32/uint32
+ * 64-bit quantities    int64/uint64
+ * strings              unsigned char*
+ */
+
+typedef TIFF_INT8_T   int8;
+typedef TIFF_UINT8_T  uint8;
+
+typedef TIFF_INT16_T  int16;
+typedef TIFF_UINT16_T uint16;
+
+typedef TIFF_INT32_T  int32;
+typedef TIFF_UINT32_T uint32;
+
+typedef TIFF_INT64_T  int64;
+typedef TIFF_UINT64_T uint64;
+
+/*
+ * Some types as promoted in a variable argument list
+ * We use uint16_vap rather then directly using int, because this way
+ * we document the type we actually want to pass through, conceptually,
+ * rather then confusing the issue by merely stating the type it gets
+ * promoted to
+ */
+
+typedef int uint16_vap;
+
+/*
+ * TIFF header.
+ */
+typedef struct {
+	uint16 tiff_magic;      /* magic number (defines byte order) */
+	uint16 tiff_version;    /* TIFF version number */
+} TIFFHeaderCommon;
+typedef struct {
+	uint16 tiff_magic;      /* magic number (defines byte order) */
+	uint16 tiff_version;    /* TIFF version number */
+	uint32 tiff_diroff;     /* byte offset to first directory */
+} TIFFHeaderClassic;
+typedef struct {
+	uint16 tiff_magic;      /* magic number (defines byte order) */
+	uint16 tiff_version;    /* TIFF version number */
+	uint16 tiff_offsetsize; /* size of offsets, should be 8 */
+	uint16 tiff_unused;     /* unused word, should be 0 */
+	uint64 tiff_diroff;     /* byte offset to first directory */
+} TIFFHeaderBig;
+
+
+/*
+ * NB: In the comments below,
+ *  - items marked with a + are obsoleted by revision 5.0,
+ *  - items marked with a ! are introduced in revision 6.0.
+ *  - items marked with a % are introduced post revision 6.0.
+ *  - items marked with a $ are obsoleted by revision 6.0.
+ *  - items marked with a & are introduced by Adobe DNG specification.
+ */
+
+/*
+ * Tag data type information.
+ *
+ * Note: RATIONALs are the ratio of two 32-bit integer values.
+ */
+typedef enum {
+	TIFF_NOTYPE = 0,      /* placeholder */
+	TIFF_BYTE = 1,        /* 8-bit unsigned integer */
+	TIFF_ASCII = 2,       /* 8-bit bytes w/ last byte null */
+	TIFF_SHORT = 3,       /* 16-bit unsigned integer */
+	TIFF_LONG = 4,        /* 32-bit unsigned integer */
+	TIFF_RATIONAL = 5,    /* 64-bit unsigned fraction */
+	TIFF_SBYTE = 6,       /* !8-bit signed integer */
+	TIFF_UNDEFINED = 7,   /* !8-bit untyped data */
+	TIFF_SSHORT = 8,      /* !16-bit signed integer */
+	TIFF_SLONG = 9,       /* !32-bit signed integer */
+	TIFF_SRATIONAL = 10,  /* !64-bit signed fraction */
+	TIFF_FLOAT = 11,      /* !32-bit IEEE floating point */
+	TIFF_DOUBLE = 12,     /* !64-bit IEEE floating point */
+	TIFF_IFD = 13,        /* %32-bit unsigned integer (offset) */
+	TIFF_LONG8 = 16,      /* BigTIFF 64-bit unsigned integer */
+	TIFF_SLONG8 = 17,     /* BigTIFF 64-bit signed integer */
+	TIFF_IFD8 = 18        /* BigTIFF 64-bit unsigned integer (offset) */
+} TIFFDataType;
+
+/*
+ * TIFF Tag Definitions.
+ */
+#define	TIFFTAG_SUBFILETYPE		254	/* subfile data descriptor */
+#define	    FILETYPE_REDUCEDIMAGE	0x1	/* reduced resolution version */
+#define	    FILETYPE_PAGE		0x2	/* one page of many */
+#define	    FILETYPE_MASK		0x4	/* transparency mask */
+#define	TIFFTAG_OSUBFILETYPE		255	/* +kind of data in subfile */
+#define	    OFILETYPE_IMAGE		1	/* full resolution image data */
+#define	    OFILETYPE_REDUCEDIMAGE	2	/* reduced size image data */
+#define	    OFILETYPE_PAGE		3	/* one page of many */
+#define	TIFFTAG_IMAGEWIDTH		256	/* image width in pixels */
+#define	TIFFTAG_IMAGELENGTH		257	/* image height in pixels */
+#define	TIFFTAG_BITSPERSAMPLE		258	/* bits per channel (sample) */
+#define	TIFFTAG_COMPRESSION		259	/* data compression technique */
+#define	    COMPRESSION_NONE		1	/* dump mode */
+#define	    COMPRESSION_CCITTRLE	2	/* CCITT modified Huffman RLE */
+#define	    COMPRESSION_CCITTFAX3	3	/* CCITT Group 3 fax encoding */
+#define     COMPRESSION_CCITT_T4        3       /* CCITT T.4 (TIFF 6 name) */
+#define	    COMPRESSION_CCITTFAX4	4	/* CCITT Group 4 fax encoding */
+#define     COMPRESSION_CCITT_T6        4       /* CCITT T.6 (TIFF 6 name) */
+#define	    COMPRESSION_LZW		5       /* Lempel-Ziv  & Welch */
+#define	    COMPRESSION_OJPEG		6	/* !6.0 JPEG */
+#define	    COMPRESSION_JPEG		7	/* %JPEG DCT compression */
+#define     COMPRESSION_T85			9	/* !TIFF/FX T.85 JBIG compression */
+#define     COMPRESSION_T43			10	/* !TIFF/FX T.43 colour by layered JBIG compression */
+#define	    COMPRESSION_NEXT		32766	/* NeXT 2-bit RLE */
+#define	    COMPRESSION_CCITTRLEW	32771	/* #1 w/ word alignment */
+#define	    COMPRESSION_PACKBITS	32773	/* Macintosh RLE */
+#define	    COMPRESSION_THUNDERSCAN	32809	/* ThunderScan RLE */
+/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) */
+#define	    COMPRESSION_IT8CTPAD	32895   /* IT8 CT w/padding */
+#define	    COMPRESSION_IT8LW		32896   /* IT8 Linework RLE */
+#define	    COMPRESSION_IT8MP		32897   /* IT8 Monochrome picture */
+#define	    COMPRESSION_IT8BL		32898   /* IT8 Binary line art */
+/* compression codes 32908-32911 are reserved for Pixar */
+#define     COMPRESSION_PIXARFILM	32908   /* Pixar companded 10bit LZW */
+#define	    COMPRESSION_PIXARLOG	32909   /* Pixar companded 11bit ZIP */
+#define	    COMPRESSION_DEFLATE		32946	/* Deflate compression */
+#define     COMPRESSION_ADOBE_DEFLATE   8       /* Deflate compression,
+						   as recognized by Adobe */
+/* compression code 32947 is reserved for Oceana Matrix <dev@oceana.com> */
+#define     COMPRESSION_DCS             32947   /* Kodak DCS encoding */
+#define	    COMPRESSION_JBIG		34661	/* ISO JBIG */
+#define     COMPRESSION_SGILOG		34676	/* SGI Log Luminance RLE */
+#define     COMPRESSION_SGILOG24	34677	/* SGI Log 24-bit packed */
+#define     COMPRESSION_JP2000          34712   /* Leadtools JPEG2000 */
+#define	    COMPRESSION_LZMA		34925	/* LZMA2 */
+#define	TIFFTAG_PHOTOMETRIC		262	/* photometric interpretation */
+#define	    PHOTOMETRIC_MINISWHITE	0	/* min value is white */
+#define	    PHOTOMETRIC_MINISBLACK	1	/* min value is black */
+#define	    PHOTOMETRIC_RGB		2	/* RGB color model */
+#define	    PHOTOMETRIC_PALETTE		3	/* color map indexed */
+#define	    PHOTOMETRIC_MASK		4	/* $holdout mask */
+#define	    PHOTOMETRIC_SEPARATED	5	/* !color separations */
+#define	    PHOTOMETRIC_YCBCR		6	/* !CCIR 601 */
+#define	    PHOTOMETRIC_CIELAB		8	/* !1976 CIE L*a*b* */
+#define	    PHOTOMETRIC_ICCLAB		9	/* ICC L*a*b* [Adobe TIFF Technote 4] */
+#define	    PHOTOMETRIC_ITULAB		10	/* ITU L*a*b* */
+#define     PHOTOMETRIC_LOGL		32844	/* CIE Log2(L) */
+#define     PHOTOMETRIC_LOGLUV		32845	/* CIE Log2(L) (u',v') */
+#define	TIFFTAG_THRESHHOLDING		263	/* +thresholding used on data */
+#define	    THRESHHOLD_BILEVEL		1	/* b&w art scan */
+#define	    THRESHHOLD_HALFTONE		2	/* or dithered scan */
+#define	    THRESHHOLD_ERRORDIFFUSE	3	/* usually floyd-steinberg */
+#define	TIFFTAG_CELLWIDTH		264	/* +dithering matrix width */
+#define	TIFFTAG_CELLLENGTH		265	/* +dithering matrix height */
+#define	TIFFTAG_FILLORDER		266	/* data order within a byte */
+#define	    FILLORDER_MSB2LSB		1	/* most significant -> least */
+#define	    FILLORDER_LSB2MSB		2	/* least significant -> most */
+#define	TIFFTAG_DOCUMENTNAME		269	/* name of doc. image is from */
+#define	TIFFTAG_IMAGEDESCRIPTION	270	/* info about image */
+#define	TIFFTAG_MAKE			271	/* scanner manufacturer name */
+#define	TIFFTAG_MODEL			272	/* scanner model name/number */
+#define	TIFFTAG_STRIPOFFSETS		273	/* offsets to data strips */
+#define	TIFFTAG_ORIENTATION		274	/* +image orientation */
+#define	    ORIENTATION_TOPLEFT		1	/* row 0 top, col 0 lhs */
+#define	    ORIENTATION_TOPRIGHT	2	/* row 0 top, col 0 rhs */
+#define	    ORIENTATION_BOTRIGHT	3	/* row 0 bottom, col 0 rhs */
+#define	    ORIENTATION_BOTLEFT		4	/* row 0 bottom, col 0 lhs */
+#define	    ORIENTATION_LEFTTOP		5	/* row 0 lhs, col 0 top */
+#define	    ORIENTATION_RIGHTTOP	6	/* row 0 rhs, col 0 top */
+#define	    ORIENTATION_RIGHTBOT	7	/* row 0 rhs, col 0 bottom */
+#define	    ORIENTATION_LEFTBOT		8	/* row 0 lhs, col 0 bottom */
+#define	TIFFTAG_SAMPLESPERPIXEL		277	/* samples per pixel */
+#define	TIFFTAG_ROWSPERSTRIP		278	/* rows per strip of data */
+#define	TIFFTAG_STRIPBYTECOUNTS		279	/* bytes counts for strips */
+#define	TIFFTAG_MINSAMPLEVALUE		280	/* +minimum sample value */
+#define	TIFFTAG_MAXSAMPLEVALUE		281	/* +maximum sample value */
+#define	TIFFTAG_XRESOLUTION		282	/* pixels/resolution in x */
+#define	TIFFTAG_YRESOLUTION		283	/* pixels/resolution in y */
+#define	TIFFTAG_PLANARCONFIG		284	/* storage organization */
+#define	    PLANARCONFIG_CONTIG		1	/* single image plane */
+#define	    PLANARCONFIG_SEPARATE	2	/* separate planes of data */
+#define	TIFFTAG_PAGENAME		285	/* page name image is from */
+#define	TIFFTAG_XPOSITION		286	/* x page offset of image lhs */
+#define	TIFFTAG_YPOSITION		287	/* y page offset of image lhs */
+#define	TIFFTAG_FREEOFFSETS		288	/* +byte offset to free block */
+#define	TIFFTAG_FREEBYTECOUNTS		289	/* +sizes of free blocks */
+#define	TIFFTAG_GRAYRESPONSEUNIT	290	/* $gray scale curve accuracy */
+#define	    GRAYRESPONSEUNIT_10S	1	/* tenths of a unit */
+#define	    GRAYRESPONSEUNIT_100S	2	/* hundredths of a unit */
+#define	    GRAYRESPONSEUNIT_1000S	3	/* thousandths of a unit */
+#define	    GRAYRESPONSEUNIT_10000S	4	/* ten-thousandths of a unit */
+#define	    GRAYRESPONSEUNIT_100000S	5	/* hundred-thousandths */
+#define	TIFFTAG_GRAYRESPONSECURVE	291	/* $gray scale response curve */
+#define	TIFFTAG_GROUP3OPTIONS		292	/* 32 flag bits */
+#define	TIFFTAG_T4OPTIONS		292	/* TIFF 6.0 proper name alias */
+#define	    GROUP3OPT_2DENCODING	0x1	/* 2-dimensional coding */
+#define	    GROUP3OPT_UNCOMPRESSED	0x2	/* data not compressed */
+#define	    GROUP3OPT_FILLBITS		0x4	/* fill to byte boundary */
+#define	TIFFTAG_GROUP4OPTIONS		293	/* 32 flag bits */
+#define TIFFTAG_T6OPTIONS               293     /* TIFF 6.0 proper name */
+#define	    GROUP4OPT_UNCOMPRESSED	0x2	/* data not compressed */
+#define	TIFFTAG_RESOLUTIONUNIT		296	/* units of resolutions */
+#define	    RESUNIT_NONE		1	/* no meaningful units */
+#define	    RESUNIT_INCH		2	/* english */
+#define	    RESUNIT_CENTIMETER		3	/* metric */
+#define	TIFFTAG_PAGENUMBER		297	/* page numbers of multi-page */
+#define	TIFFTAG_COLORRESPONSEUNIT	300	/* $color curve accuracy */
+#define	    COLORRESPONSEUNIT_10S	1	/* tenths of a unit */
+#define	    COLORRESPONSEUNIT_100S	2	/* hundredths of a unit */
+#define	    COLORRESPONSEUNIT_1000S	3	/* thousandths of a unit */
+#define	    COLORRESPONSEUNIT_10000S	4	/* ten-thousandths of a unit */
+#define	    COLORRESPONSEUNIT_100000S	5	/* hundred-thousandths */
+#define	TIFFTAG_TRANSFERFUNCTION	301	/* !colorimetry info */
+#define	TIFFTAG_SOFTWARE		305	/* name & release */
+#define	TIFFTAG_DATETIME		306	/* creation date and time */
+#define	TIFFTAG_ARTIST			315	/* creator of image */
+#define	TIFFTAG_HOSTCOMPUTER		316	/* machine where created */
+#define	TIFFTAG_PREDICTOR		317	/* prediction scheme w/ LZW */
+#define     PREDICTOR_NONE		1	/* no prediction scheme used */
+#define     PREDICTOR_HORIZONTAL	2	/* horizontal differencing */
+#define     PREDICTOR_FLOATINGPOINT	3	/* floating point predictor */
+#define	TIFFTAG_WHITEPOINT		318	/* image white point */
+#define	TIFFTAG_PRIMARYCHROMATICITIES	319	/* !primary chromaticities */
+#define	TIFFTAG_COLORMAP		320	/* RGB map for pallette image */
+#define	TIFFTAG_HALFTONEHINTS		321	/* !highlight+shadow info */
+#define	TIFFTAG_TILEWIDTH		322	/* !tile width in pixels */
+#define	TIFFTAG_TILELENGTH		323	/* !tile height in pixels */
+#define TIFFTAG_TILEOFFSETS		324	/* !offsets to data tiles */
+#define TIFFTAG_TILEBYTECOUNTS		325	/* !byte counts for tiles */
+#define	TIFFTAG_BADFAXLINES		326	/* lines w/ wrong pixel count */
+#define	TIFFTAG_CLEANFAXDATA		327	/* regenerated line info */
+#define	    CLEANFAXDATA_CLEAN		0	/* no errors detected */
+#define	    CLEANFAXDATA_REGENERATED	1	/* receiver regenerated lines */
+#define	    CLEANFAXDATA_UNCLEAN	2	/* uncorrected errors exist */
+#define	TIFFTAG_CONSECUTIVEBADFAXLINES	328	/* max consecutive bad lines */
+#define	TIFFTAG_SUBIFD			330	/* subimage descriptors */
+#define	TIFFTAG_INKSET			332	/* !inks in separated image */
+#define	    INKSET_CMYK			1	/* !cyan-magenta-yellow-black color */
+#define	    INKSET_MULTIINK		2	/* !multi-ink or hi-fi color */
+#define	TIFFTAG_INKNAMES		333	/* !ascii names of inks */
+#define	TIFFTAG_NUMBEROFINKS		334	/* !number of inks */
+#define	TIFFTAG_DOTRANGE		336	/* !0% and 100% dot codes */
+#define	TIFFTAG_TARGETPRINTER		337	/* !separation target */
+#define	TIFFTAG_EXTRASAMPLES		338	/* !info about extra samples */
+#define	    EXTRASAMPLE_UNSPECIFIED	0	/* !unspecified data */
+#define	    EXTRASAMPLE_ASSOCALPHA	1	/* !associated alpha data */
+#define	    EXTRASAMPLE_UNASSALPHA	2	/* !unassociated alpha data */
+#define	TIFFTAG_SAMPLEFORMAT		339	/* !data sample format */
+#define	    SAMPLEFORMAT_UINT		1	/* !unsigned integer data */
+#define	    SAMPLEFORMAT_INT		2	/* !signed integer data */
+#define	    SAMPLEFORMAT_IEEEFP		3	/* !IEEE floating point data */
+#define	    SAMPLEFORMAT_VOID		4	/* !untyped data */
+#define	    SAMPLEFORMAT_COMPLEXINT	5	/* !complex signed int */
+#define	    SAMPLEFORMAT_COMPLEXIEEEFP	6	/* !complex ieee floating */
+#define	TIFFTAG_SMINSAMPLEVALUE		340	/* !variable MinSampleValue */
+#define	TIFFTAG_SMAXSAMPLEVALUE		341	/* !variable MaxSampleValue */
+#define	TIFFTAG_CLIPPATH		343	/* %ClipPath
+						   [Adobe TIFF technote 2] */
+#define	TIFFTAG_XCLIPPATHUNITS		344	/* %XClipPathUnits
+						   [Adobe TIFF technote 2] */
+#define	TIFFTAG_YCLIPPATHUNITS		345	/* %YClipPathUnits
+						   [Adobe TIFF technote 2] */
+#define	TIFFTAG_INDEXED			346	/* %Indexed
+						   [Adobe TIFF Technote 3] */
+#define	TIFFTAG_JPEGTABLES		347	/* %JPEG table stream */
+#define	TIFFTAG_OPIPROXY		351	/* %OPI Proxy [Adobe TIFF technote] */
+/* Tags 400-435 are from the TIFF/FX spec */
+#define TIFFTAG_GLOBALPARAMETERSIFD	400	/* ! */
+#define TIFFTAG_PROFILETYPE			401	/* ! */
+#define     PROFILETYPE_UNSPECIFIED	0	/* ! */
+#define     PROFILETYPE_G3_FAX		1	/* ! */
+#define TIFFTAG_FAXPROFILE			402	/* ! */
+#define     FAXPROFILE_S			1	/* !TIFF/FX FAX profile S */
+#define     FAXPROFILE_F			2	/* !TIFF/FX FAX profile F */
+#define     FAXPROFILE_J			3	/* !TIFF/FX FAX profile J */
+#define     FAXPROFILE_C			4	/* !TIFF/FX FAX profile C */
+#define     FAXPROFILE_L			5	/* !TIFF/FX FAX profile L */
+#define     FAXPROFILE_M			6	/* !TIFF/FX FAX profile LM */
+#define TIFFTAG_CODINGMETHODS		403	/* !TIFF/FX coding methods */
+#define     CODINGMETHODS_T4_1D		(1 << 1)	/* !T.4 1D */
+#define     CODINGMETHODS_T4_2D		(1 << 2)	/* !T.4 2D */
+#define     CODINGMETHODS_T6		(1 << 3)	/* !T.6 */
+#define     CODINGMETHODS_T85 		(1 << 4)	/* !T.85 JBIG */
+#define     CODINGMETHODS_T42 		(1 << 5)	/* !T.42 JPEG */
+#define     CODINGMETHODS_T43		(1 << 6)	/* !T.43 colour by layered JBIG */
+#define TIFFTAG_VERSIONYEAR			404	/* !TIFF/FX version year */
+#define TIFFTAG_MODENUMBER			405	/* !TIFF/FX mode number */
+#define TIFFTAG_DECODE				433	/* !TIFF/FX decode */
+#define TIFFTAG_IMAGEBASECOLOR		434	/* !TIFF/FX image base colour */
+#define TIFFTAG_T82OPTIONS			435	/* !TIFF/FX T.82 options */
+/*
+ * Tags 512-521 are obsoleted by Technical Note #2 which specifies a
+ * revised JPEG-in-TIFF scheme.
+ */
+#define	TIFFTAG_JPEGPROC		512	/* !JPEG processing algorithm */
+#define	    JPEGPROC_BASELINE		1	/* !baseline sequential */
+#define	    JPEGPROC_LOSSLESS		14	/* !Huffman coded lossless */
+#define	TIFFTAG_JPEGIFOFFSET		513	/* !pointer to SOI marker */
+#define	TIFFTAG_JPEGIFBYTECOUNT		514	/* !JFIF stream length */
+#define	TIFFTAG_JPEGRESTARTINTERVAL	515	/* !restart interval length */
+#define	TIFFTAG_JPEGLOSSLESSPREDICTORS	517	/* !lossless proc predictor */
+#define	TIFFTAG_JPEGPOINTTRANSFORM	518	/* !lossless point transform */
+#define	TIFFTAG_JPEGQTABLES		519	/* !Q matrice offsets */
+#define	TIFFTAG_JPEGDCTABLES		520	/* !DCT table offsets */
+#define	TIFFTAG_JPEGACTABLES		521	/* !AC coefficient offsets */
+#define	TIFFTAG_YCBCRCOEFFICIENTS	529	/* !RGB -> YCbCr transform */
+#define	TIFFTAG_YCBCRSUBSAMPLING	530	/* !YCbCr subsampling factors */
+#define	TIFFTAG_YCBCRPOSITIONING	531	/* !subsample positioning */
+#define	    YCBCRPOSITION_CENTERED	1	/* !as in PostScript Level 2 */
+#define	    YCBCRPOSITION_COSITED	2	/* !as in CCIR 601-1 */
+#define	TIFFTAG_REFERENCEBLACKWHITE	532	/* !colorimetry info */
+#define TIFFTAG_STRIPROWCOUNTS		559 /* !TIFF/FX strip row counts */
+#define	TIFFTAG_XMLPACKET		700	/* %XML packet
+						   [Adobe XMP Specification,
+						   January 2004 */
+#define TIFFTAG_OPIIMAGEID		32781	/* %OPI ImageID
+						   [Adobe TIFF technote] */
+/* tags 32952-32956 are private tags registered to Island Graphics */
+#define TIFFTAG_REFPTS			32953	/* image reference points */
+#define TIFFTAG_REGIONTACKPOINT		32954	/* region-xform tack point */
+#define TIFFTAG_REGIONWARPCORNERS	32955	/* warp quadrilateral */
+#define TIFFTAG_REGIONAFFINE		32956	/* affine transformation mat */
+/* tags 32995-32999 are private tags registered to SGI */
+#define	TIFFTAG_MATTEING		32995	/* $use ExtraSamples */
+#define	TIFFTAG_DATATYPE		32996	/* $use SampleFormat */
+#define	TIFFTAG_IMAGEDEPTH		32997	/* z depth of image */
+#define	TIFFTAG_TILEDEPTH		32998	/* z depth/data tile */
+/* tags 33300-33309 are private tags registered to Pixar */
+/*
+ * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH
+ * are set when an image has been cropped out of a larger image.  
+ * They reflect the size of the original uncropped image.
+ * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used
+ * to determine the position of the smaller image in the larger one.
+ */
+#define TIFFTAG_PIXAR_IMAGEFULLWIDTH    33300   /* full image size in x */
+#define TIFFTAG_PIXAR_IMAGEFULLLENGTH   33301   /* full image size in y */
+ /* Tags 33302-33306 are used to identify special image modes and data
+  * used by Pixar's texture formats.
+  */
+#define TIFFTAG_PIXAR_TEXTUREFORMAT	33302	/* texture map format */
+#define TIFFTAG_PIXAR_WRAPMODES		33303	/* s & t wrap modes */
+#define TIFFTAG_PIXAR_FOVCOT		33304	/* cotan(fov) for env. maps */
+#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305
+#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306
+/* tag 33405 is a private tag registered to Eastman Kodak */
+#define TIFFTAG_WRITERSERIALNUMBER      33405   /* device serial number */
+/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */
+#define	TIFFTAG_COPYRIGHT		33432	/* copyright string */
+/* IPTC TAG from RichTIFF specifications */
+#define TIFFTAG_RICHTIFFIPTC		33723
+/* 34016-34029 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) */
+#define TIFFTAG_IT8SITE			34016	/* site name */
+#define TIFFTAG_IT8COLORSEQUENCE	34017	/* color seq. [RGB,CMYK,etc] */
+#define TIFFTAG_IT8HEADER		34018	/* DDES Header */
+#define TIFFTAG_IT8RASTERPADDING	34019	/* raster scanline padding */
+#define TIFFTAG_IT8BITSPERRUNLENGTH	34020	/* # of bits in short run */
+#define TIFFTAG_IT8BITSPEREXTENDEDRUNLENGTH 34021/* # of bits in long run */
+#define TIFFTAG_IT8COLORTABLE		34022	/* LW colortable */
+#define TIFFTAG_IT8IMAGECOLORINDICATOR	34023	/* BP/BL image color switch */
+#define TIFFTAG_IT8BKGCOLORINDICATOR	34024	/* BP/BL bg color switch */
+#define TIFFTAG_IT8IMAGECOLORVALUE	34025	/* BP/BL image color value */
+#define TIFFTAG_IT8BKGCOLORVALUE	34026	/* BP/BL bg color value */
+#define TIFFTAG_IT8PIXELINTENSITYRANGE	34027	/* MP pixel intensity value */
+#define TIFFTAG_IT8TRANSPARENCYINDICATOR 34028	/* HC transparency switch */
+#define TIFFTAG_IT8COLORCHARACTERIZATION 34029	/* color character. table */
+#define TIFFTAG_IT8HCUSAGE		34030	/* HC usage indicator */
+#define TIFFTAG_IT8TRAPINDICATOR	34031	/* Trapping indicator
+						   (untrapped=0, trapped=1) */
+#define TIFFTAG_IT8CMYKEQUIVALENT	34032	/* CMYK color equivalents */
+/* tags 34232-34236 are private tags registered to Texas Instruments */
+#define TIFFTAG_FRAMECOUNT              34232   /* Sequence Frame Count */
+/* tag 34377 is private tag registered to Adobe for PhotoShop */
+#define TIFFTAG_PHOTOSHOP		34377 
+/* tags 34665, 34853 and 40965 are documented in EXIF specification */
+#define TIFFTAG_EXIFIFD			34665	/* Pointer to EXIF private directory */
+/* tag 34750 is a private tag registered to Adobe? */
+#define TIFFTAG_ICCPROFILE		34675	/* ICC profile data */
+#define TIFFTAG_IMAGELAYER		34732	/* !TIFF/FX image layer information */
+/* tag 34750 is a private tag registered to Pixel Magic */
+#define	TIFFTAG_JBIGOPTIONS		34750	/* JBIG options */
+#define TIFFTAG_GPSIFD			34853	/* Pointer to GPS private directory */
+/* tags 34908-34914 are private tags registered to SGI */
+#define	TIFFTAG_FAXRECVPARAMS		34908	/* encoded Class 2 ses. parms */
+#define	TIFFTAG_FAXSUBADDRESS		34909	/* received SubAddr string */
+#define	TIFFTAG_FAXRECVTIME		34910	/* receive time (secs) */
+#define	TIFFTAG_FAXDCS			34911	/* encoded fax ses. params, Table 2/T.30 */
+/* tags 37439-37443 are registered to SGI <gregl@sgi.com> */
+#define TIFFTAG_STONITS			37439	/* Sample value to Nits */
+/* tag 34929 is a private tag registered to FedEx */
+#define	TIFFTAG_FEDEX_EDR		34929	/* unknown use */
+#define TIFFTAG_INTEROPERABILITYIFD	40965	/* Pointer to Interoperability private directory */
+/* Adobe Digital Negative (DNG) format tags */
+#define TIFFTAG_DNGVERSION		50706	/* &DNG version number */
+#define TIFFTAG_DNGBACKWARDVERSION	50707	/* &DNG compatibility version */
+#define TIFFTAG_UNIQUECAMERAMODEL	50708	/* &name for the camera model */
+#define TIFFTAG_LOCALIZEDCAMERAMODEL	50709	/* &localized camera model
+						   name */
+#define TIFFTAG_CFAPLANECOLOR		50710	/* &CFAPattern->LinearRaw space
+						   mapping */
+#define TIFFTAG_CFALAYOUT		50711	/* &spatial layout of the CFA */
+#define TIFFTAG_LINEARIZATIONTABLE	50712	/* &lookup table description */
+#define TIFFTAG_BLACKLEVELREPEATDIM	50713	/* &repeat pattern size for
+						   the BlackLevel tag */
+#define TIFFTAG_BLACKLEVEL		50714	/* &zero light encoding level */
+#define TIFFTAG_BLACKLEVELDELTAH	50715	/* &zero light encoding level
+						   differences (columns) */
+#define TIFFTAG_BLACKLEVELDELTAV	50716	/* &zero light encoding level
+						   differences (rows) */
+#define TIFFTAG_WHITELEVEL		50717	/* &fully saturated encoding
+						   level */
+#define TIFFTAG_DEFAULTSCALE		50718	/* &default scale factors */
+#define TIFFTAG_DEFAULTCROPORIGIN	50719	/* &origin of the final image
+						   area */
+#define TIFFTAG_DEFAULTCROPSIZE		50720	/* &size of the final image 
+						   area */
+#define TIFFTAG_COLORMATRIX1		50721	/* &XYZ->reference color space
+						   transformation matrix 1 */
+#define TIFFTAG_COLORMATRIX2		50722	/* &XYZ->reference color space
+						   transformation matrix 2 */
+#define TIFFTAG_CAMERACALIBRATION1	50723	/* &calibration matrix 1 */
+#define TIFFTAG_CAMERACALIBRATION2	50724	/* &calibration matrix 2 */
+#define TIFFTAG_REDUCTIONMATRIX1	50725	/* &dimensionality reduction
+						   matrix 1 */
+#define TIFFTAG_REDUCTIONMATRIX2	50726	/* &dimensionality reduction
+						   matrix 2 */
+#define TIFFTAG_ANALOGBALANCE		50727	/* &gain applied the stored raw
+						   values*/
+#define TIFFTAG_ASSHOTNEUTRAL		50728	/* &selected white balance in
+						   linear reference space */
+#define TIFFTAG_ASSHOTWHITEXY		50729	/* &selected white balance in
+						   x-y chromaticity
+						   coordinates */
+#define TIFFTAG_BASELINEEXPOSURE	50730	/* &how much to move the zero
+						   point */
+#define TIFFTAG_BASELINENOISE		50731	/* &relative noise level */
+#define TIFFTAG_BASELINESHARPNESS	50732	/* &relative amount of
+						   sharpening */
+#define TIFFTAG_BAYERGREENSPLIT		50733	/* &how closely the values of
+						   the green pixels in the
+						   blue/green rows track the
+						   values of the green pixels
+						   in the red/green rows */
+#define TIFFTAG_LINEARRESPONSELIMIT	50734	/* &non-linear encoding range */
+#define TIFFTAG_CAMERASERIALNUMBER	50735	/* &camera's serial number */
+#define TIFFTAG_LENSINFO		50736	/* info about the lens */
+#define TIFFTAG_CHROMABLURRADIUS	50737	/* &chroma blur radius */
+#define TIFFTAG_ANTIALIASSTRENGTH	50738	/* &relative strength of the
+						   camera's anti-alias filter */
+#define TIFFTAG_SHADOWSCALE		50739	/* &used by Adobe Camera Raw */
+#define TIFFTAG_DNGPRIVATEDATA		50740	/* &manufacturer's private data */
+#define TIFFTAG_MAKERNOTESAFETY		50741	/* &whether the EXIF MakerNote
+						   tag is safe to preserve
+						   along with the rest of the
+						   EXIF data */
+#define	TIFFTAG_CALIBRATIONILLUMINANT1	50778	/* &illuminant 1 */
+#define TIFFTAG_CALIBRATIONILLUMINANT2	50779	/* &illuminant 2 */
+#define TIFFTAG_BESTQUALITYSCALE	50780	/* &best quality multiplier */
+#define TIFFTAG_RAWDATAUNIQUEID		50781	/* &unique identifier for
+						   the raw image data */
+#define TIFFTAG_ORIGINALRAWFILENAME	50827	/* &file name of the original
+						   raw file */
+#define TIFFTAG_ORIGINALRAWFILEDATA	50828	/* &contents of the original
+						   raw file */
+#define TIFFTAG_ACTIVEAREA		50829	/* &active (non-masked) pixels
+						   of the sensor */
+#define TIFFTAG_MASKEDAREAS		50830	/* &list of coordinates
+						   of fully masked pixels */
+#define TIFFTAG_ASSHOTICCPROFILE	50831	/* &these two tags used to */
+#define TIFFTAG_ASSHOTPREPROFILEMATRIX	50832	/* map cameras's color space
+						   into ICC profile space */
+#define TIFFTAG_CURRENTICCPROFILE	50833	/* & */
+#define TIFFTAG_CURRENTPREPROFILEMATRIX	50834	/* & */
+/* tag 65535 is an undefined tag used by Eastman Kodak */
+#define TIFFTAG_DCSHUESHIFTVALUES       65535   /* hue shift correction data */
+
+/*
+ * The following are ``pseudo tags'' that can be used to control
+ * codec-specific functionality.  These tags are not written to file.
+ * Note that these values start at 0xffff+1 so that they'll never
+ * collide with Aldus-assigned tags.
+ *
+ * If you want your private pseudo tags ``registered'' (i.e. added to
+ * this file), please post a bug report via the tracking system at
+ * http://www.remotesensing.org/libtiff/bugs.html with the appropriate
+ * C definitions to add.
+ */
+#define	TIFFTAG_FAXMODE			65536	/* Group 3/4 format control */
+#define	    FAXMODE_CLASSIC	0x0000		/* default, include RTC */
+#define	    FAXMODE_NORTC	0x0001		/* no RTC at end of data */
+#define	    FAXMODE_NOEOL	0x0002		/* no EOL code at end of row */
+#define	    FAXMODE_BYTEALIGN	0x0004		/* byte align row */
+#define	    FAXMODE_WORDALIGN	0x0008		/* word align row */
+#define	    FAXMODE_CLASSF	FAXMODE_NORTC	/* TIFF Class F */
+#define	TIFFTAG_JPEGQUALITY		65537	/* Compression quality level */
+/* Note: quality level is on the IJG 0-100 scale.  Default value is 75 */
+#define	TIFFTAG_JPEGCOLORMODE		65538	/* Auto RGB<=>YCbCr convert? */
+#define	    JPEGCOLORMODE_RAW	0x0000		/* no conversion (default) */
+#define	    JPEGCOLORMODE_RGB	0x0001		/* do auto conversion */
+#define	TIFFTAG_JPEGTABLESMODE		65539	/* What to put in JPEGTables */
+#define	    JPEGTABLESMODE_QUANT 0x0001		/* include quantization tbls */
+#define	    JPEGTABLESMODE_HUFF	0x0002		/* include Huffman tbls */
+/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */
+#define	TIFFTAG_FAXFILLFUNC		65540	/* G3/G4 fill function */
+#define	TIFFTAG_PIXARLOGDATAFMT		65549	/* PixarLogCodec I/O data sz */
+#define	    PIXARLOGDATAFMT_8BIT	0	/* regular u_char samples */
+#define	    PIXARLOGDATAFMT_8BITABGR	1	/* ABGR-order u_chars */
+#define	    PIXARLOGDATAFMT_11BITLOG	2	/* 11-bit log-encoded (raw) */
+#define	    PIXARLOGDATAFMT_12BITPICIO	3	/* as per PICIO (1.0==2048) */
+#define	    PIXARLOGDATAFMT_16BIT	4	/* signed short samples */
+#define	    PIXARLOGDATAFMT_FLOAT	5	/* IEEE float samples */
+/* 65550-65556 are allocated to Oceana Matrix <dev@oceana.com> */
+#define TIFFTAG_DCSIMAGERTYPE           65550   /* imager model & filter */
+#define     DCSIMAGERMODEL_M3           0       /* M3 chip (1280 x 1024) */
+#define     DCSIMAGERMODEL_M5           1       /* M5 chip (1536 x 1024) */
+#define     DCSIMAGERMODEL_M6           2       /* M6 chip (3072 x 2048) */
+#define     DCSIMAGERFILTER_IR          0       /* infrared filter */
+#define     DCSIMAGERFILTER_MONO        1       /* monochrome filter */
+#define     DCSIMAGERFILTER_CFA         2       /* color filter array */
+#define     DCSIMAGERFILTER_OTHER       3       /* other filter */
+#define TIFFTAG_DCSINTERPMODE           65551   /* interpolation mode */
+#define     DCSINTERPMODE_NORMAL        0x0     /* whole image, default */
+#define     DCSINTERPMODE_PREVIEW       0x1     /* preview of image (384x256) */
+#define TIFFTAG_DCSBALANCEARRAY         65552   /* color balance values */
+#define TIFFTAG_DCSCORRECTMATRIX        65553   /* color correction values */
+#define TIFFTAG_DCSGAMMA                65554   /* gamma value */
+#define TIFFTAG_DCSTOESHOULDERPTS       65555   /* toe & shoulder points */
+#define TIFFTAG_DCSCALIBRATIONFD        65556   /* calibration file desc */
+/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */
+#define	TIFFTAG_ZIPQUALITY		65557	/* compression quality level */
+#define	TIFFTAG_PIXARLOGQUALITY		65558	/* PixarLog uses same scale */
+/* 65559 is allocated to Oceana Matrix <dev@oceana.com> */
+#define TIFFTAG_DCSCLIPRECTANGLE	65559	/* area of image to acquire */
+#define TIFFTAG_SGILOGDATAFMT		65560	/* SGILog user data format */
+#define     SGILOGDATAFMT_FLOAT		0	/* IEEE float samples */
+#define     SGILOGDATAFMT_16BIT		1	/* 16-bit samples */
+#define     SGILOGDATAFMT_RAW		2	/* uninterpreted data */
+#define     SGILOGDATAFMT_8BIT		3	/* 8-bit RGB monitor values */
+#define TIFFTAG_SGILOGENCODE		65561 /* SGILog data encoding control*/
+#define     SGILOGENCODE_NODITHER	0     /* do not dither encoded values*/
+#define     SGILOGENCODE_RANDITHER	1     /* randomly dither encd values */
+#define	TIFFTAG_LZMAPRESET		65562	/* LZMA2 preset (compression level) */
+#define TIFFTAG_PERSAMPLE       65563	/* interface for per sample tags */
+#define     PERSAMPLE_MERGED        0	/* present as a single value */
+#define     PERSAMPLE_MULTI         1	/* present as multiple values */
+
+/*
+ * EXIF tags
+ */
+#define EXIFTAG_EXPOSURETIME		33434	/* Exposure time */
+#define EXIFTAG_FNUMBER			33437	/* F number */
+#define EXIFTAG_EXPOSUREPROGRAM		34850	/* Exposure program */
+#define EXIFTAG_SPECTRALSENSITIVITY	34852	/* Spectral sensitivity */
+#define EXIFTAG_ISOSPEEDRATINGS		34855	/* ISO speed rating */
+#define EXIFTAG_OECF			34856	/* Optoelectric conversion
+						   factor */
+#define EXIFTAG_EXIFVERSION		36864	/* Exif version */
+#define EXIFTAG_DATETIMEORIGINAL	36867	/* Date and time of original
+						   data generation */
+#define EXIFTAG_DATETIMEDIGITIZED	36868	/* Date and time of digital
+						   data generation */
+#define EXIFTAG_COMPONENTSCONFIGURATION	37121	/* Meaning of each component */
+#define EXIFTAG_COMPRESSEDBITSPERPIXEL	37122	/* Image compression mode */
+#define EXIFTAG_SHUTTERSPEEDVALUE	37377	/* Shutter speed */
+#define EXIFTAG_APERTUREVALUE		37378	/* Aperture */
+#define EXIFTAG_BRIGHTNESSVALUE		37379	/* Brightness */
+#define EXIFTAG_EXPOSUREBIASVALUE	37380	/* Exposure bias */
+#define EXIFTAG_MAXAPERTUREVALUE	37381	/* Maximum lens aperture */
+#define EXIFTAG_SUBJECTDISTANCE		37382	/* Subject distance */
+#define EXIFTAG_METERINGMODE		37383	/* Metering mode */
+#define EXIFTAG_LIGHTSOURCE		37384	/* Light source */
+#define EXIFTAG_FLASH			37385	/* Flash */
+#define EXIFTAG_FOCALLENGTH		37386	/* Lens focal length */
+#define EXIFTAG_SUBJECTAREA		37396	/* Subject area */
+#define EXIFTAG_MAKERNOTE		37500	/* Manufacturer notes */
+#define EXIFTAG_USERCOMMENT		37510	/* User comments */
+#define EXIFTAG_SUBSECTIME		37520	/* DateTime subseconds */
+#define EXIFTAG_SUBSECTIMEORIGINAL	37521	/* DateTimeOriginal subseconds */
+#define EXIFTAG_SUBSECTIMEDIGITIZED	37522	/* DateTimeDigitized subseconds */
+#define EXIFTAG_FLASHPIXVERSION		40960	/* Supported Flashpix version */
+#define EXIFTAG_COLORSPACE		40961	/* Color space information */
+#define EXIFTAG_PIXELXDIMENSION		40962	/* Valid image width */
+#define EXIFTAG_PIXELYDIMENSION		40963	/* Valid image height */
+#define EXIFTAG_RELATEDSOUNDFILE	40964	/* Related audio file */
+#define EXIFTAG_FLASHENERGY		41483	/* Flash energy */
+#define EXIFTAG_SPATIALFREQUENCYRESPONSE 41484	/* Spatial frequency response */
+#define EXIFTAG_FOCALPLANEXRESOLUTION	41486	/* Focal plane X resolution */
+#define EXIFTAG_FOCALPLANEYRESOLUTION	41487	/* Focal plane Y resolution */
+#define EXIFTAG_FOCALPLANERESOLUTIONUNIT 41488	/* Focal plane resolution unit */
+#define EXIFTAG_SUBJECTLOCATION		41492	/* Subject location */
+#define EXIFTAG_EXPOSUREINDEX		41493	/* Exposure index */
+#define EXIFTAG_SENSINGMETHOD		41495	/* Sensing method */
+#define EXIFTAG_FILESOURCE		41728	/* File source */
+#define EXIFTAG_SCENETYPE		41729	/* Scene type */
+#define EXIFTAG_CFAPATTERN		41730	/* CFA pattern */
+#define EXIFTAG_CUSTOMRENDERED		41985	/* Custom image processing */
+#define EXIFTAG_EXPOSUREMODE		41986	/* Exposure mode */
+#define EXIFTAG_WHITEBALANCE		41987	/* White balance */
+#define EXIFTAG_DIGITALZOOMRATIO	41988	/* Digital zoom ratio */
+#define EXIFTAG_FOCALLENGTHIN35MMFILM	41989	/* Focal length in 35 mm film */
+#define EXIFTAG_SCENECAPTURETYPE	41990	/* Scene capture type */
+#define EXIFTAG_GAINCONTROL		41991	/* Gain control */
+#define EXIFTAG_CONTRAST		41992	/* Contrast */
+#define EXIFTAG_SATURATION		41993	/* Saturation */
+#define EXIFTAG_SHARPNESS		41994	/* Sharpness */
+#define EXIFTAG_DEVICESETTINGDESCRIPTION 41995	/* Device settings description */
+#define EXIFTAG_SUBJECTDISTANCERANGE	41996	/* Subject distance range */
+#define EXIFTAG_GAINCONTROL		41991	/* Gain control */
+#define EXIFTAG_GAINCONTROL		41991	/* Gain control */
+#define EXIFTAG_IMAGEUNIQUEID		42016	/* Unique image ID */
+
+#endif /* _TIFF_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiffconf.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiffconf.h
new file mode 100644
index 0000000..3ca425c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiffconf.h
@@ -0,0 +1,250 @@
+/* libtiff/tiffconf.h.  Generated by configure.  */
+/*
+  Configuration defines for installed libtiff.
+  This file maintained for backward compatibility. Do not use definitions
+  from this file in your programs.
+*/
+#ifndef _TIFFCONF_
+#define _TIFFCONF_
+
+#ifndef _FX_SYSTEM_H_
+# include "../../../../include/fxcrt/fx_system.h"
+#endif
+
+//NOTE: The tiff codec requires an ANSI C compiler environment for building and 
+//		presumes an ANSI C environment for use.
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+/* Define to 1 if you have the <sys/types.h> header file. */
+#if _FX_OS_ == _FX_WIN32_MOBILE_
+# define O_RDONLY       0x0000  /* open for reading only */
+# define O_WRONLY       0x0001  /* open for writing only */
+# define O_RDWR         0x0002  /* open for reading and writing */
+# define O_CREAT        0x0100  /* create and open file */
+# define O_TRUNC        0x0200  /* open and truncate */
+#else
+# define HAVE_SYS_TYPES_H 1
+# define HAVE_FCNTL_H 1
+#endif
+
+/* Compatibility stuff. */
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define as 0 or 1 according to the floating point format suported by the
+   machine */
+#define HAVE_IEEEFP 1
+
+/* Define to 1 if you have the <string.h> header file. */
+//#define HAVE_STRING_H 1
+//fx_system.h already include the string.h in ANSIC
+
+/* Define to 1 if you have the <search.h> header file. */
+/*#define HAVE_SEARCH_H 1 */
+
+/* The size of a `int', as computed by sizeof. */
+/* According typedef int	FX_INT32; in the fx_system.h*/
+#define SIZEOF_INT 4
+
+/* Sunliang.Liu 20110325. We should config the correct long size for tif 
+   fax4decode optimize in tif_fax3.c  -- Linux64 decode issue. 
+   TESTDOC: Bug #23661 - z1.tif. */
+#if _FX_CPU_ == _FX_WIN64_ || _FX_CPU_ == _FX_X64_ || _FX_CPU_ == _FX_IA64_
+/* The size of `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 8
+#else
+#define SIZEOF_UNSIGNED_LONG 4
+#endif
+
+/* Signed 8-bit type */
+#define TIFF_INT8_T signed char
+
+/* Unsigned 8-bit type */
+#define TIFF_UINT8_T unsigned char
+
+/* Signed 16-bit type */
+#define TIFF_INT16_T signed short
+
+/* Unsigned 16-bit type */
+#define TIFF_UINT16_T unsigned short
+
+/* Signed 32-bit type */
+#define TIFF_INT32_T signed int
+
+/* Unsigned 32-bit type */
+#define TIFF_UINT32_T unsigned int
+
+/* Signed 32-bit type formatter */
+#define TIFF_INT32_FORMAT "%d"
+
+/* Unsigned 32-bit type formatter */
+#define TIFF_UINT32_FORMAT "%u"
+
+#ifdef _MSC_VER		// windows
+
+/* Signed 64-bit type formatter */
+#define TIFF_INT64_FORMAT "%I64d"
+
+/* Unsigned 64-bit type formatter */
+#define TIFF_UINT64_FORMAT "%I64u"
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed __int64
+
+/* Unsigned 64-bit type */
+#define TIFF_UINT64_T unsigned __int64
+
+#else						// linux/unix
+
+#if 0 //_FX_CPU_ == _FX_X64_	// linux/unix 64
+
+/* Signed 64-bit type formatter */
+#define TIFF_INT64_FORMAT "%ld"
+
+/* Unsigned 64-bit type formatter */
+#define TIFF_UINT64_FORMAT "%lu"
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed long
+
+#else						// linux/unix 32
+
+/* Signed 64-bit type formatter */
+#define TIFF_INT64_FORMAT "%lld"
+
+/* Unsigned 64-bit type formatter */
+#define TIFF_UINT64_FORMAT "%llu"
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed long long
+
+#endif						// end _FX_CPU_
+
+/* Unsigned 64-bit type */
+#define TIFF_UINT64_T unsigned long long
+
+#endif
+
+
+/* Signed size type */
+#ifdef _MSC_VER
+
+#if defined(_WIN64)
+#define TIFF_SSIZE_T signed __int64
+#else
+#define TIFF_SSIZE_T signed int
+#endif
+
+#else
+
+#define TIFF_SSIZE_T signed long
+
+#endif
+
+/* Signed size type formatter */
+#if defined(_WIN64)
+#define TIFF_SSIZE_FORMAT "%I64d"
+#else
+#define TIFF_SSIZE_FORMAT "%ld"
+#endif
+
+/* Pointer difference type */
+#ifdef _MSC_VER
+#define TIFF_PTRDIFF_T long
+#else
+#define TIFF_PTRDIFF_T ptrdiff_t
+#endif
+
+/* Signed 64-bit type */
+/*#define TIFF_INT64_T signed __int64*/
+
+/* Unsigned 64-bit type */
+/*#define TIFF_UINT64_T unsigned __int64*/
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+# ifndef inline
+#  define inline __inline
+# endif
+#endif
+
+#define lfind _lfind
+
+#define BSDTYPES
+
+/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
+   (Intel) */
+#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_
+# define HOST_BIGENDIAN 1
+#else
+# define HOST_BIGENDIAN 0
+#endif
+
+/* Support CCITT Group 3 & 4 algorithms */
+#define CCITT_SUPPORT 1
+
+/* Support JPEG compression (requires IJG JPEG library) */
+#define JPEG_SUPPORT 1
+
+/* Support LogLuv high dynamic range encoding */
+#define LOGLUV_SUPPORT 1
+
+/* Support LZW algorithm */
+#define LZW_SUPPORT 1
+
+/* Support NeXT 2-bit RLE algorithm */
+#define NEXT_SUPPORT 1
+
+/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation
+   fails with unpatched IJG JPEG library) */
+#define  OJPEG_SUPPORT	1
+
+/* Support Macintosh PackBits algorithm */
+#define PACKBITS_SUPPORT 1
+
+/* Support Pixar log-format algorithm (requires Zlib) */
+#define PIXARLOG_SUPPORT 1
+
+/* Support ThunderScan 4-bit RLE algorithm */
+#define THUNDER_SUPPORT 1
+
+/* Support Deflate compression */
+#define ZIP_SUPPORT 1
+
+/* Support strip chopping (whether or not to convert single-strip uncompressed
+   images to mutiple strips of ~8Kb to reduce memory usage) */
+#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP
+
+/* Enable SubIFD tag (330) support */
+#define SUBIFD_SUPPORT 1
+
+/* Treat extra sample as alpha (default enabled). The RGBA interface will
+   treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+   packages produce RGBA files but don't mark the alpha properly. */
+#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1
+
+/* Pick up YCbCr subsampling info from the JPEG data stream to support files
+   lacking the tag (default enabled). */
+#define CHECK_JPEG_YCBCR_SUBSAMPLING 1
+
+/* Support MS MDI magic number files as TIFF */
+#define MDI_SUPPORT 1
+
+/*
+ * Feature support definitions.
+ * XXX: These macros are obsoleted. Don't use them in your apps!
+ * Macros stays here for backward compatibility and should be always defined.
+ */
+#define COLORIMETRY_SUPPORT
+#define YCBCR_SUPPORT
+#define CMYK_SUPPORT
+#define ICC_SUPPORT
+#define PHOTOSHOP_SUPPORT
+#define IPTC_SUPPORT
+
+#endif /* _TIFFCONF_ */
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiffio.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiffio.h
new file mode 100644
index 0000000..4c749ed
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiffio.h
@@ -0,0 +1,559 @@
+/* $Id: tiffio.h,v 1.91 2012-07-29 15:45:29 tgl Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFIO_
+#define	_TIFFIO_
+
+/*
+ * TIFF I/O Library Definitions.
+ */
+#include "tiff.h"
+#include "tiffvers.h"
+
+/*
+ * TIFF is defined as an incomplete type to hide the
+ * library's internal data structures from clients.
+ */
+typedef struct tiff TIFF;
+
+/*
+ * The following typedefs define the intrinsic size of
+ * data types used in the *exported* interfaces.  These
+ * definitions depend on the proper definition of types
+ * in tiff.h.  Note also that the varargs interface used
+ * to pass tag types and values uses the types defined in
+ * tiff.h directly.
+ *
+ * NB: ttag_t is unsigned int and not unsigned short because
+ *     ANSI C requires that the type before the ellipsis be a
+ *     promoted type (i.e. one of int, unsigned int, pointer,
+ *     or double) and because we defined pseudo-tags that are
+ *     outside the range of legal Aldus-assigned tags.
+ * NB: tsize_t is int32 and not uint32 because some functions
+ *     return -1.
+ * NB: toff_t is not off_t for many reasons; TIFFs max out at
+ *     32-bit file offsets, and BigTIFF maxes out at 64-bit
+ *     offsets being the most important, and to ensure use of
+ *     a consistently unsigned type across architectures.
+ *     Prior to libtiff 4.0, this was an unsigned 32 bit type.
+ */
+/*
+ * this is the machine addressing size type, only it's signed, so make it
+ * int32 on 32bit machines, int64 on 64bit machines
+ */
+typedef TIFF_SSIZE_T tmsize_t;
+typedef uint64 toff_t;          /* file offset */
+/* the following are deprecated and should be replaced by their defining
+   counterparts */
+typedef uint32 ttag_t;          /* directory tag */
+typedef uint16 tdir_t;          /* directory index */
+typedef uint16 tsample_t;       /* sample number */
+typedef uint32 tstrile_t;       /* strip or tile number */
+typedef tstrile_t tstrip_t;     /* strip number */
+typedef tstrile_t ttile_t;      /* tile number */
+typedef tmsize_t tsize_t;       /* i/o size in bytes */
+typedef void* tdata_t;          /* image data ref */
+
+#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32))
+#define __WIN32__
+#endif
+
+/*
+ * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c
+ * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c).
+ *
+ * By default tif_unix.c is assumed.
+ */
+
+#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows)
+#  if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO)
+#    define AVOID_WIN32_FILEIO
+#  endif
+#endif
+
+#if defined(USE_WIN32_FILEIO)
+# define VC_EXTRALEAN
+# include <windows.h>
+# ifdef __WIN32__
+DECLARE_HANDLE(thandle_t);     /* Win32 file handle */
+# else
+typedef HFILE thandle_t;       /* client data handle */
+# endif /* __WIN32__ */
+#else
+typedef void* thandle_t;       /* client data handle */
+#endif /* USE_WIN32_FILEIO */
+
+/*
+ * Flags to pass to TIFFPrintDirectory to control
+ * printing of data structures that are potentially
+ * very large.   Bit-or these flags to enable printing
+ * multiple items.
+ */
+#define TIFFPRINT_NONE	       0x0    /* no extra info */
+#define TIFFPRINT_STRIPS       0x1    /* strips/tiles info */
+#define TIFFPRINT_CURVES       0x2    /* color/gray response curves */
+#define TIFFPRINT_COLORMAP     0x4    /* colormap */
+#define TIFFPRINT_JPEGQTABLES  0x100  /* JPEG Q matrices */
+#define TIFFPRINT_JPEGACTABLES 0x200  /* JPEG AC tables */
+#define TIFFPRINT_JPEGDCTABLES 0x200  /* JPEG DC tables */
+
+/* 
+ * Colour conversion stuff
+ */
+
+/* reference white */
+#define D65_X0 (95.0470F)
+#define D65_Y0 (100.0F)
+#define D65_Z0 (108.8827F)
+
+#define D50_X0 (96.4250F)
+#define D50_Y0 (100.0F)
+#define D50_Z0 (82.4680F)
+
+/* Structure for holding information about a display device. */
+
+typedef unsigned char TIFFRGBValue;               /* 8-bit samples */
+
+typedef struct {
+	float d_mat[3][3];                        /* XYZ -> luminance matrix */
+	float d_YCR;                              /* Light o/p for reference white */
+	float d_YCG;
+	float d_YCB;
+	uint32 d_Vrwr;                            /* Pixel values for ref. white */
+	uint32 d_Vrwg;
+	uint32 d_Vrwb;
+	float d_Y0R;                              /* Residual light for black pixel */
+	float d_Y0G;
+	float d_Y0B;
+	float d_gammaR;                           /* Gamma values for the three guns */
+	float d_gammaG;
+	float d_gammaB;
+} TIFFDisplay;
+
+typedef struct {                                  /* YCbCr->RGB support */
+	TIFFRGBValue* clamptab;                   /* range clamping table */
+	int* Cr_r_tab;
+	int* Cb_b_tab;
+	int32* Cr_g_tab;
+	int32* Cb_g_tab;
+	int32* Y_tab;
+} TIFFYCbCrToRGB;
+
+typedef struct {                                  /* CIE Lab 1976->RGB support */
+	int range;                                /* Size of conversion table */
+#define CIELABTORGB_TABLE_RANGE 1500
+	float rstep, gstep, bstep;
+	float X0, Y0, Z0;                         /* Reference white point */
+	TIFFDisplay display;
+	float Yr2r[CIELABTORGB_TABLE_RANGE + 1];  /* Conversion of Yr to r */
+	float Yg2g[CIELABTORGB_TABLE_RANGE + 1];  /* Conversion of Yg to g */
+	float Yb2b[CIELABTORGB_TABLE_RANGE + 1];  /* Conversion of Yb to b */
+} TIFFCIELabToRGB;
+
+/*
+ * RGBA-style image support.
+ */
+typedef struct _TIFFRGBAImage TIFFRGBAImage;
+/*
+ * The image reading and conversion routines invoke
+ * ``put routines'' to copy/image/whatever tiles of
+ * raw image data.  A default set of routines are 
+ * provided to convert/copy raw image data to 8-bit
+ * packed ABGR format rasters.  Applications can supply
+ * alternate routines that unpack the data into a
+ * different format or, for example, unpack the data
+ * and draw the unpacked raster on the display.
+ */
+typedef void (*tileContigRoutine)
+    (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32,
+	unsigned char*);
+typedef void (*tileSeparateRoutine)
+    (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32,
+	unsigned char*, unsigned char*, unsigned char*, unsigned char*);
+/*
+ * RGBA-reader state.
+ */
+struct _TIFFRGBAImage {
+	TIFF* tif;                              /* image handle */
+	int stoponerr;                          /* stop on read error */
+	int isContig;                           /* data is packed/separate */
+	int alpha;                              /* type of alpha data present */
+	uint32 width;                           /* image width */
+	uint32 height;                          /* image height */
+	uint16 bitspersample;                   /* image bits/sample */
+	uint16 samplesperpixel;                 /* image samples/pixel */
+	uint16 orientation;                     /* image orientation */
+	uint16 req_orientation;                 /* requested orientation */
+	uint16 photometric;                     /* image photometric interp */
+	uint16* redcmap;                        /* colormap pallete */
+	uint16* greencmap;
+	uint16* bluecmap;
+	/* get image data routine */
+	int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32);
+	/* put decoded strip/tile */
+	union {
+	    void (*any)(TIFFRGBAImage*);
+	    tileContigRoutine contig;
+	    tileSeparateRoutine separate;
+	} put;
+	TIFFRGBValue* Map;                      /* sample mapping array */
+	uint32** BWmap;                         /* black&white map */
+	uint32** PALmap;                        /* palette image map */
+	TIFFYCbCrToRGB* ycbcr;                  /* YCbCr conversion state */
+	TIFFCIELabToRGB* cielab;                /* CIE L*a*b conversion state */
+
+	uint8* UaToAa;                          /* Unassociated alpha to associated alpha convertion LUT */
+	uint8* Bitdepth16To8;                   /* LUT for conversion from 16bit to 8bit values */
+
+	int row_offset;
+	int col_offset;
+};
+
+/*
+ * Macros for extracting components from the
+ * packed ABGR form returned by TIFFReadRGBAImage.
+ */
+#define TIFFGetR(abgr) ((abgr) & 0xff)
+#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff)
+#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff)
+#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff)
+
+/*
+ * A CODEC is a software package that implements decoding,
+ * encoding, or decoding+encoding of a compression algorithm.
+ * The library provides a collection of builtin codecs.
+ * More codecs may be registered through calls to the library
+ * and/or the builtin implementations may be overridden.
+ */
+typedef int (*TIFFInitMethod)(TIFF*, int);
+typedef struct {
+	char* name;
+	uint16 scheme;
+	TIFFInitMethod init;
+} TIFFCodec;
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* share internal LogLuv conversion routines? */
+#ifndef LOGLUV_PUBLIC
+#define LOGLUV_PUBLIC 1
+#endif
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#  define __attribute__(x) /*nothing*/
+#endif
+
+#if defined(c_plusplus) || defined(__cplusplus)
+extern "C" {
+#endif
+typedef void (*TIFFErrorHandler)(const char*, const char*, va_list);
+typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list);
+typedef tmsize_t (*TIFFReadWriteProc)(thandle_t, void*, tmsize_t);
+typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int);
+typedef int (*TIFFCloseProc)(thandle_t);
+typedef toff_t (*TIFFSizeProc)(thandle_t);
+typedef int (*TIFFMapFileProc)(thandle_t, void** base, toff_t* size);
+typedef void (*TIFFUnmapFileProc)(thandle_t, void* base, toff_t size);
+typedef void (*TIFFExtendProc)(TIFF*);
+
+extern const char* TIFFGetVersion(void);
+
+extern const TIFFCodec* TIFFFindCODEC(uint16);
+extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod);
+extern void TIFFUnRegisterCODEC(TIFFCodec*);
+extern int TIFFIsCODECConfigured(uint16);
+extern TIFFCodec* TIFFGetConfiguredCODECs(void);
+
+/*
+ * Auxiliary functions.
+ */
+
+extern void* _TIFFmalloc(tmsize_t s);
+extern void* _TIFFrealloc(void* p, tmsize_t s);
+extern void _TIFFmemset(void* p, int v, tmsize_t c);
+extern void _TIFFmemcpy(void* d, const void* s, tmsize_t c);
+extern int _TIFFmemcmp(const void* p1, const void* p2, tmsize_t c);
+extern void _TIFFfree(void* p);
+/* Do cmyk to rgb convert, add by Sunliang.Liu 20090723. */
+extern	int TIFFCmyk2Rgb(thandle_t context, uint8 c, uint8 m, uint8 y, uint8 k, uint8* r, uint8* g, uint8* b);
+
+/*
+** Stuff, related to tag handling and creating custom tags.
+*/
+extern int TIFFGetTagListCount( TIFF * );
+extern uint32 TIFFGetTagListEntry( TIFF *, int tag_index );
+    
+#define TIFF_ANY       TIFF_NOTYPE     /* for field descriptor searching */
+#define TIFF_VARIABLE  -1              /* marker for variable length tags */
+#define TIFF_SPP       -2              /* marker for SamplesPerPixel tags */
+#define TIFF_VARIABLE2 -3              /* marker for uint32 var-length tags */
+
+#define FIELD_CUSTOM    65
+
+typedef struct _TIFFField TIFFField;
+typedef struct _TIFFFieldArray TIFFFieldArray;
+
+extern const TIFFField* TIFFFindField(TIFF *, uint32, TIFFDataType);
+extern const TIFFField* TIFFFieldWithTag(TIFF*, uint32);
+extern const TIFFField* TIFFFieldWithName(TIFF*, const char *);
+
+extern uint32 TIFFFieldTag(const TIFFField*);
+extern const char* TIFFFieldName(const TIFFField*);
+extern TIFFDataType TIFFFieldDataType(const TIFFField*);
+extern int TIFFFieldPassCount(const TIFFField*);
+extern int TIFFFieldReadCount(const TIFFField*);
+extern int TIFFFieldWriteCount(const TIFFField*);
+
+typedef int (*TIFFVSetMethod)(TIFF*, uint32, va_list);
+typedef int (*TIFFVGetMethod)(TIFF*, uint32, va_list);
+typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long);
+
+typedef struct {
+    TIFFVSetMethod vsetfield; /* tag set routine */
+    TIFFVGetMethod vgetfield; /* tag get routine */
+    TIFFPrintMethod printdir; /* directory print routine */
+} TIFFTagMethods;
+
+extern  TIFFTagMethods *TIFFAccessTagMethods(TIFF *);
+extern  void *TIFFGetClientInfo(TIFF *, const char *);
+extern  void TIFFSetClientInfo(TIFF *, void *, const char *);
+
+extern void TIFFCleanup(TIFF* tif);
+extern void TIFFClose(TIFF* tif);
+extern int TIFFFlush(TIFF* tif);
+extern int TIFFFlushData(TIFF* tif);
+extern int TIFFGetField(TIFF* tif, uint32 tag, ...);
+extern int TIFFVGetField(TIFF* tif, uint32 tag, va_list ap);
+extern int TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...);
+extern int TIFFVGetFieldDefaulted(TIFF* tif, uint32 tag, va_list ap);
+extern int TIFFReadDirectory(TIFF* tif);
+extern int TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, const TIFFFieldArray* infoarray);
+extern int TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff);
+extern uint64 TIFFScanlineSize64(TIFF* tif);
+extern tmsize_t TIFFScanlineSize(TIFF* tif);
+extern uint64 TIFFRasterScanlineSize64(TIFF* tif);
+extern tmsize_t TIFFRasterScanlineSize(TIFF* tif);
+extern uint64 TIFFStripSize64(TIFF* tif);
+extern tmsize_t TIFFStripSize(TIFF* tif);
+extern uint64 TIFFRawStripSize64(TIFF* tif, uint32 strip);
+extern tmsize_t TIFFRawStripSize(TIFF* tif, uint32 strip);
+extern uint64 TIFFVStripSize64(TIFF* tif, uint32 nrows);
+extern tmsize_t TIFFVStripSize(TIFF* tif, uint32 nrows);
+extern uint64 TIFFTileRowSize64(TIFF* tif);
+extern tmsize_t TIFFTileRowSize(TIFF* tif);
+extern uint64 TIFFTileSize64(TIFF* tif);
+extern tmsize_t TIFFTileSize(TIFF* tif);
+extern uint64 TIFFVTileSize64(TIFF* tif, uint32 nrows);
+extern tmsize_t TIFFVTileSize(TIFF* tif, uint32 nrows);
+extern uint32 TIFFDefaultStripSize(TIFF* tif, uint32 request);
+extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*);
+extern int TIFFFileno(TIFF*);
+extern int TIFFSetFileno(TIFF*, int);
+extern thandle_t TIFFClientdata(TIFF*);
+extern thandle_t TIFFSetClientdata(TIFF*, thandle_t);
+extern int TIFFGetMode(TIFF*);
+extern int TIFFSetMode(TIFF*, int);
+extern int TIFFIsTiled(TIFF*);
+extern int TIFFIsByteSwapped(TIFF*);
+extern int TIFFIsUpSampled(TIFF*);
+extern int TIFFIsMSB2LSB(TIFF*);
+extern int TIFFIsBigEndian(TIFF*);
+extern TIFFReadWriteProc TIFFGetReadProc(TIFF*);
+extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*);
+extern TIFFSeekProc TIFFGetSeekProc(TIFF*);                                                          
+extern TIFFCloseProc TIFFGetCloseProc(TIFF*);
+extern TIFFSizeProc TIFFGetSizeProc(TIFF*);
+extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*);
+extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*);
+extern uint32 TIFFCurrentRow(TIFF*);
+extern uint16 TIFFCurrentDirectory(TIFF*);
+extern uint16 TIFFNumberOfDirectories(TIFF*);
+extern uint64 TIFFCurrentDirOffset(TIFF*);
+extern uint32 TIFFCurrentStrip(TIFF*);
+extern uint32 TIFFCurrentTile(TIFF* tif);
+extern int TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size);
+extern int TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size);  
+extern int TIFFSetupStrips(TIFF *);
+extern int TIFFWriteCheck(TIFF*, int, const char *);
+extern void TIFFFreeDirectory(TIFF*);
+extern int TIFFCreateDirectory(TIFF*);
+extern int TIFFCreateCustomDirectory(TIFF*,const TIFFFieldArray*);
+extern int TIFFCreateEXIFDirectory(TIFF*);
+extern int TIFFLastDirectory(TIFF*);
+extern int TIFFSetDirectory(TIFF*, uint16);
+extern int TIFFSetSubDirectory(TIFF*, uint64);
+extern int TIFFUnlinkDirectory(TIFF*, uint16);
+extern int TIFFSetField(TIFF*, uint32, ...);
+extern int TIFFVSetField(TIFF*, uint32, va_list);
+extern int TIFFUnsetField(TIFF*, uint32);
+extern int TIFFWriteDirectory(TIFF *);
+extern int TIFFWriteCustomDirectory(TIFF *, uint64 *);
+extern int TIFFCheckpointDirectory(TIFF *);
+extern int TIFFRewriteDirectory(TIFF *);
+
+#if defined(c_plusplus) || defined(__cplusplus)
+extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0);
+extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0);
+extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0);
+extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0);
+extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*,
+    int = ORIENTATION_BOTLEFT, int = 0);
+#else
+extern void TIFFPrintDirectory(TIFF*, FILE*, long);
+extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample);
+extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample);
+extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int);
+extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int);
+#endif
+
+extern int TIFFReadRGBAStrip(TIFF*, uint32, uint32 * );
+extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * );
+extern int TIFFRGBAImageOK(TIFF*, char [1024]);
+extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]);
+extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32);
+extern void TIFFRGBAImageEnd(TIFFRGBAImage*);
+extern TIFF* TIFFOpen(const char*, const char*);
+# ifdef __WIN32__
+extern TIFF* TIFFOpenW(const wchar_t*, const char*);
+# endif /* __WIN32__ */
+extern TIFF* TIFFFdOpen(int, const char*, const char*);
+extern TIFF* TIFFClientOpen(const char*, const char*,
+	    thandle_t,
+	    TIFFReadWriteProc, TIFFReadWriteProc,
+	    TIFFSeekProc, TIFFCloseProc,
+	    TIFFSizeProc,
+	    TIFFMapFileProc, TIFFUnmapFileProc);
+extern const char* TIFFFileName(TIFF*);
+extern const char* TIFFSetFileName(TIFF*, const char *);
+extern void TIFFError(const char*, const char*, ...) __attribute__((__format__ (__printf__,2,3)));
+extern void TIFFErrorExt(thandle_t, const char*, const char*, ...) __attribute__((__format__ (__printf__,3,4)));
+extern void TIFFWarning(const char*, const char*, ...) __attribute__((__format__ (__printf__,2,3)));
+extern void TIFFWarningExt(thandle_t, const char*, const char*, ...) __attribute__((__format__ (__printf__,3,4)));
+extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler);
+extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt);
+extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler);
+extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt);
+extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc);
+extern uint32 TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s);
+extern int TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s);
+extern uint32 TIFFNumberOfTiles(TIFF*);
+extern tmsize_t TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s);  
+extern tmsize_t TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s);
+extern uint32 TIFFComputeStrip(TIFF*, uint32, uint16);
+extern uint32 TIFFNumberOfStrips(TIFF*);
+extern tmsize_t TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size);
+extern tmsize_t TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size);  
+extern tmsize_t TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size);  
+extern tmsize_t TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size);  
+extern tmsize_t TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc);
+extern tmsize_t TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc);  
+extern tmsize_t TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc);  
+extern tmsize_t TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc);  
+extern int TIFFDataWidth(TIFFDataType);    /* table of tag datatype widths */
+extern void TIFFSetWriteOffset(TIFF* tif, toff_t off);
+extern void TIFFSwabShort(uint16*);
+extern void TIFFSwabLong(uint32*);
+extern void TIFFSwabLong8(uint64*);
+extern void TIFFSwabFloat(float*);
+extern void TIFFSwabDouble(double*);
+extern void TIFFSwabArrayOfShort(uint16* wp, tmsize_t n);
+extern void TIFFSwabArrayOfTriples(uint8* tp, tmsize_t n);
+extern void TIFFSwabArrayOfLong(uint32* lp, tmsize_t n);
+extern void TIFFSwabArrayOfLong8(uint64* lp, tmsize_t n);
+extern void TIFFSwabArrayOfFloat(float* fp, tmsize_t n);
+extern void TIFFSwabArrayOfDouble(double* dp, tmsize_t n);
+extern void TIFFReverseBits(uint8* cp, tmsize_t n);
+extern const unsigned char* TIFFGetBitRevTable(int);
+
+#ifdef LOGLUV_PUBLIC
+#define U_NEU		0.210526316
+#define V_NEU		0.473684211
+#define UVSCALE		410.
+extern double LogL16toY(int);
+extern double LogL10toY(int);
+extern void XYZtoRGB24(float*, uint8*);
+extern int uv_decode(double*, double*, int);
+extern void LogLuv24toXYZ(uint32, float*);
+extern void LogLuv32toXYZ(uint32, float*);
+#if defined(c_plusplus) || defined(__cplusplus)
+extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER);
+extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER);
+extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER);
+extern uint32 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER);
+extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER);
+#else
+extern int LogL16fromY(double, int);
+extern int LogL10fromY(double, int);
+extern int uv_encode(double, double, int);
+extern uint32 LogLuv24fromXYZ(float*, int);
+extern uint32 LogLuv32fromXYZ(float*, int);
+#endif
+#endif /* LOGLUV_PUBLIC */
+
+extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, const TIFFDisplay *, float*);
+extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32,
+    float *, float *, float *);
+extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float,
+    uint32 *, uint32 *, uint32 *);
+
+extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*);
+extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32,
+    uint32 *, uint32 *, uint32 *);
+
+/****************************************************************************
+ *               O B S O L E T E D    I N T E R F A C E S
+ *
+ * Don't use this stuff in your applications, it may be removed in the future
+ * libtiff versions.
+ ****************************************************************************/
+typedef	struct {
+	ttag_t	field_tag;		/* field's tag */
+	short	field_readcount;	/* read count/TIFF_VARIABLE/TIFF_SPP */
+	short	field_writecount;	/* write count/TIFF_VARIABLE */
+	TIFFDataType field_type;	/* type of associated data */
+        unsigned short field_bit;	/* bit in fieldsset bit vector */
+	unsigned char field_oktochange;	/* if true, can change while writing */
+	unsigned char field_passcount;	/* if true, pass dir count on set */
+	char	*field_name;		/* ASCII name */
+} TIFFFieldInfo;
+
+extern int TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], uint32);
+        
+#if defined(c_plusplus) || defined(__cplusplus)
+}
+#endif
+
+#endif /* _TIFFIO_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiffiop.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiffiop.h
new file mode 100644
index 0000000..c5ddc3c
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiffiop.h
@@ -0,0 +1,367 @@
+/* $Id: tiffiop.h,v 1.84 2012-05-30 01:50:17 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFIOP_
+#define	_TIFFIOP_
+/*
+ * ``Library-private'' definitions.
+ */
+
+#include "tiffconf.h"
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+#ifdef HAVE_ASSERT_H
+# include <assert.h>
+#else
+# define assert(x) 
+#endif
+
+#ifdef HAVE_SEARCH_H
+# include <search.h>
+#else
+extern void *lfind(const void *, const void *, size_t *, size_t,
+		   int (*)(const void *, const void *));
+#endif
+
+#include "tiffio.h"
+
+#include "tif_dir.h"
+
+#ifndef STRIP_SIZE_DEFAULT
+# define STRIP_SIZE_DEFAULT 8192
+#endif
+
+#define    streq(a,b)      (strcmp(a,b) == 0)
+
+#ifndef TRUE
+#define	TRUE	1
+#define	FALSE	0
+#endif
+
+typedef struct client_info {
+    struct client_info *next;
+    void *data;
+    char *name;
+} TIFFClientInfoLink;
+
+/*
+ * Typedefs for ``method pointers'' used internally.
+ * these are depriciated and provided only for backwards compatibility
+ */
+typedef unsigned char tidataval_t;    /* internal image data value type */
+typedef tidataval_t* tidata_t;        /* reference to internal image data */
+
+typedef void (*TIFFVoidMethod)(TIFF*);
+typedef int (*TIFFBoolMethod)(TIFF*);
+typedef int (*TIFFPreMethod)(TIFF*, uint16);
+typedef int (*TIFFCodeMethod)(TIFF* tif, uint8* buf, tmsize_t size, uint16 sample);
+typedef int (*TIFFSeekMethod)(TIFF*, uint32);
+typedef void (*TIFFPostMethod)(TIFF* tif, uint8* buf, tmsize_t size);
+typedef uint32 (*TIFFStripMethod)(TIFF*, uint32);
+typedef void (*TIFFTileMethod)(TIFF*, uint32*, uint32*);
+
+struct tiff {
+	char*                tif_name;         /* name of open file */
+	int                  tif_fd;           /* open file descriptor */
+	int                  tif_mode;         /* open mode (O_*) */
+	uint32               tif_flags;
+	#define TIFF_FILLORDER   0x00003 /* natural bit fill order for machine */
+	#define TIFF_DIRTYHEADER 0x00004 /* header must be written on close */
+	#define TIFF_DIRTYDIRECT 0x00008 /* current directory must be written */
+	#define TIFF_BUFFERSETUP 0x00010 /* data buffers setup */
+	#define TIFF_CODERSETUP  0x00020 /* encoder/decoder setup done */
+	#define TIFF_BEENWRITING 0x00040 /* written 1+ scanlines to file */
+	#define TIFF_SWAB        0x00080 /* byte swap file information */
+	#define TIFF_NOBITREV    0x00100 /* inhibit bit reversal logic */
+	#define TIFF_MYBUFFER    0x00200 /* my raw data buffer; free on close */
+	#define TIFF_ISTILED     0x00400 /* file is tile, not strip- based */
+	#define TIFF_MAPPED      0x00800 /* file is mapped into memory */
+	#define TIFF_POSTENCODE  0x01000 /* need call to postencode routine */
+	#define TIFF_INSUBIFD    0x02000 /* currently writing a subifd */
+	#define TIFF_UPSAMPLED   0x04000 /* library is doing data up-sampling */
+	#define TIFF_STRIPCHOP   0x08000 /* enable strip chopping support */
+	#define TIFF_HEADERONLY  0x10000 /* read header only, do not process the first directory */
+	#define TIFF_NOREADRAW   0x20000 /* skip reading of raw uncompressed image data */
+	#define TIFF_INCUSTOMIFD 0x40000 /* currently writing a custom IFD */
+	#define TIFF_BIGTIFF     0x80000 /* read/write bigtiff */
+        #define TIFF_BUF4WRITE  0x100000 /* rawcc bytes are for writing */
+        #define TIFF_DIRTYSTRIP 0x200000 /* stripoffsets/stripbytecount dirty*/
+        #define TIFF_PERSAMPLE  0x400000 /* get/set per sample tags as arrays */
+        #define TIFF_BUFFERMMAP 0x800000 /* read buffer (tif_rawdata) points into mmap() memory */
+	uint64               tif_diroff;       /* file offset of current directory */
+	uint64               tif_nextdiroff;   /* file offset of following directory */
+	uint64*              tif_dirlist;      /* list of offsets to already seen directories to prevent IFD looping */
+	uint16               tif_dirlistsize;  /* number of entires in offset list */
+	uint16               tif_dirnumber;    /* number of already seen directories */
+	TIFFDirectory        tif_dir;          /* internal rep of current directory */
+	TIFFDirectory        tif_customdir;    /* custom IFDs are separated from the main ones */
+	union {
+		TIFFHeaderCommon common;
+		TIFFHeaderClassic classic;
+		TIFFHeaderBig big;
+	} tif_header;
+	uint16               tif_header_size;  /* file's header block and its length */
+	uint32               tif_row;          /* current scanline */
+	uint16               tif_curdir;       /* current directory (index) */
+	uint32               tif_curstrip;     /* current strip for read/write */
+	uint64               tif_curoff;       /* current offset for read/write */
+	uint64               tif_dataoff;      /* current offset for writing dir */
+	/* SubIFD support */
+	uint16               tif_nsubifd;      /* remaining subifds to write */
+	uint64               tif_subifdoff;    /* offset for patching SubIFD link */
+	/* tiling support */
+	uint32               tif_col;          /* current column (offset by row too) */
+	uint32               tif_curtile;      /* current tile for read/write */
+	tmsize_t             tif_tilesize;     /* # of bytes in a tile */
+	/* compression scheme hooks */
+	int                  tif_decodestatus;
+	TIFFBoolMethod       tif_fixuptags;    /* called in TIFFReadDirectory */
+	TIFFBoolMethod       tif_setupdecode;  /* called once before predecode */
+	TIFFPreMethod        tif_predecode;    /* pre- row/strip/tile decoding */
+	TIFFBoolMethod       tif_setupencode;  /* called once before preencode */
+	int                  tif_encodestatus;
+	TIFFPreMethod        tif_preencode;    /* pre- row/strip/tile encoding */
+	TIFFBoolMethod       tif_postencode;   /* post- row/strip/tile encoding */
+	TIFFCodeMethod       tif_decoderow;    /* scanline decoding routine */
+	TIFFCodeMethod       tif_encoderow;    /* scanline encoding routine */
+	TIFFCodeMethod       tif_decodestrip;  /* strip decoding routine */
+	TIFFCodeMethod       tif_encodestrip;  /* strip encoding routine */
+	TIFFCodeMethod       tif_decodetile;   /* tile decoding routine */
+	TIFFCodeMethod       tif_encodetile;   /* tile encoding routine */
+	TIFFVoidMethod       tif_close;        /* cleanup-on-close routine */
+	TIFFSeekMethod       tif_seek;         /* position within a strip routine */
+	TIFFVoidMethod       tif_cleanup;      /* cleanup state routine */
+	TIFFStripMethod      tif_defstripsize; /* calculate/constrain strip size */
+	TIFFTileMethod       tif_deftilesize;  /* calculate/constrain tile size */
+	uint8*               tif_data;         /* compression scheme private data */
+	/* input/output buffering */
+	tmsize_t             tif_scanlinesize; /* # of bytes in a scanline */
+	tmsize_t             tif_scanlineskew; /* scanline skew for reading strips */
+	uint8*               tif_rawdata;      /* raw data buffer */
+	tmsize_t             tif_rawdatasize;  /* # of bytes in raw data buffer */
+        tmsize_t             tif_rawdataoff;   /* rawdata offset within strip */
+        tmsize_t             tif_rawdataloaded;/* amount of data in rawdata */
+	uint8*               tif_rawcp;        /* current spot in raw buffer */
+	tmsize_t             tif_rawcc;        /* bytes unread from raw buffer */
+	/* memory-mapped file support */
+	uint8*               tif_base;         /* base of mapped file */
+	tmsize_t             tif_size;         /* size of mapped file region (bytes, thus tmsize_t) */
+	TIFFMapFileProc      tif_mapproc;      /* map file method */
+	TIFFUnmapFileProc    tif_unmapproc;    /* unmap file method */
+	/* input/output callback methods */
+	thandle_t            tif_clientdata;   /* callback parameter */
+	TIFFReadWriteProc    tif_readproc;     /* read method */
+	TIFFReadWriteProc    tif_writeproc;    /* write method */
+	TIFFSeekProc         tif_seekproc;     /* lseek method */
+	TIFFCloseProc        tif_closeproc;    /* close method */
+	TIFFSizeProc         tif_sizeproc;     /* filesize method */
+	/* post-decoding support */
+	TIFFPostMethod       tif_postdecode;   /* post decoding routine */
+	/* tag support */
+	TIFFField**          tif_fields;       /* sorted table of registered tags */
+	size_t               tif_nfields;      /* # entries in registered tag table */
+	const TIFFField*     tif_foundfield;   /* cached pointer to already found tag */
+	TIFFTagMethods       tif_tagmethods;   /* tag get/set/print routines */
+	TIFFClientInfoLink*  tif_clientinfo;   /* extra client information. */
+	/* Backward compatibility stuff. We need these two fields for
+	 * setting up an old tag extension scheme. */
+	TIFFFieldArray*      tif_fieldscompat;
+	size_t               tif_nfieldscompat;
+};
+
+#define isPseudoTag(t) (t > 0xffff)            /* is tag value normal or pseudo */
+
+#define isTiled(tif) (((tif)->tif_flags & TIFF_ISTILED) != 0)
+#define isMapped(tif) (((tif)->tif_flags & TIFF_MAPPED) != 0)
+#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0)
+#define isUpSampled(tif) (((tif)->tif_flags & TIFF_UPSAMPLED) != 0)
+#define TIFFReadFile(tif, buf, size) \
+	((*(tif)->tif_readproc)((tif)->tif_clientdata,(buf),(size)))
+#define TIFFWriteFile(tif, buf, size) \
+	((*(tif)->tif_writeproc)((tif)->tif_clientdata,(buf),(size)))
+#define TIFFSeekFile(tif, off, whence) \
+	((*(tif)->tif_seekproc)((tif)->tif_clientdata,(off),(whence)))
+#define TIFFCloseFile(tif) \
+	((*(tif)->tif_closeproc)((tif)->tif_clientdata))
+#define TIFFGetFileSize(tif) \
+	((*(tif)->tif_sizeproc)((tif)->tif_clientdata))
+#define TIFFMapFileContents(tif, paddr, psize) \
+	((*(tif)->tif_mapproc)((tif)->tif_clientdata,(paddr),(psize)))
+#define TIFFUnmapFileContents(tif, addr, size) \
+	((*(tif)->tif_unmapproc)((tif)->tif_clientdata,(addr),(size)))
+
+/*
+ * Default Read/Seek/Write definitions.
+ */
+#ifndef ReadOK
+#define ReadOK(tif, buf, size) \
+	(TIFFReadFile((tif),(buf),(size))==(size))
+#endif
+#ifndef SeekOK
+#define SeekOK(tif, off) \
+	(TIFFSeekFile((tif),(off),SEEK_SET)==(off))
+#endif
+#ifndef WriteOK
+#define WriteOK(tif, buf, size) \
+	(TIFFWriteFile((tif),(buf),(size))==(size))
+#endif
+
+/* NB: the uint32 casts are to silence certain ANSI-C compilers */
+#define TIFFhowmany_32(x, y) (((uint32)x < (0xffffffff - (uint32)(y-1))) ? \
+			   ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y))) : \
+			   0U)
+#define TIFFhowmany8_32(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
+#define TIFFroundup_32(x, y) (TIFFhowmany_32(x,y)*(y))
+#define TIFFhowmany_64(x, y) ((((uint64)(x))+(((uint64)(y))-1))/((uint64)(y)))
+#define TIFFhowmany8_64(x) (((x)&0x07)?((uint64)(x)>>3)+1:(uint64)(x)>>3)
+#define TIFFroundup_64(x, y) (TIFFhowmany_64(x,y)*(y))
+
+/* Safe multiply which returns zero if there is an integer overflow */
+#define TIFFSafeMultiply(t,v,m) ((((t)(m) != (t)0) && (((t)(((v)*(m))/(m))) == (t)(v))) ? (t)((v)*(m)) : (t)0)
+
+#define TIFFmax(A,B) ((A)>(B)?(A):(B))
+#define TIFFmin(A,B) ((A)<(B)?(A):(B))
+
+#define TIFFArrayCount(a) (sizeof (a) / sizeof ((a)[0]))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern int _TIFFgetMode(const char* mode, const char* module);
+extern int _TIFFNoRowEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoStripEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoTileEncode(TIFF*, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoRowDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoStripDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoTileDecode(TIFF*, uint8* pp, tmsize_t cc, uint16 s);
+extern void _TIFFNoPostDecode(TIFF* tif, uint8* buf, tmsize_t cc);
+extern int _TIFFNoPreCode(TIFF* tif, uint16 s);
+extern int _TIFFNoSeek(TIFF* tif, uint32 off);
+extern void _TIFFSwab16BitData(TIFF* tif, uint8* buf, tmsize_t cc);
+extern void _TIFFSwab24BitData(TIFF* tif, uint8* buf, tmsize_t cc);
+extern void _TIFFSwab32BitData(TIFF* tif, uint8* buf, tmsize_t cc);
+extern void _TIFFSwab64BitData(TIFF* tif, uint8* buf, tmsize_t cc);
+extern int TIFFFlushData1(TIFF* tif);
+extern int TIFFDefaultDirectory(TIFF* tif);
+extern void _TIFFSetDefaultCompressionState(TIFF* tif);
+extern int _TIFFRewriteField(TIFF *, uint16, TIFFDataType, tmsize_t, void *);
+extern int TIFFSetCompressionScheme(TIFF* tif, int scheme);
+extern int TIFFSetDefaultCompressionState(TIFF* tif);
+extern uint32 _TIFFDefaultStripSize(TIFF* tif, uint32 s);
+extern void _TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th);
+extern int _TIFFDataSize(TIFFDataType type);
+
+extern void _TIFFsetByteArray(void**, void*, uint32);
+extern void _TIFFsetString(char**, char*);
+extern void _TIFFsetShortArray(uint16**, uint16*, uint32);
+extern void _TIFFsetLongArray(uint32**, uint32*, uint32);
+extern void _TIFFsetFloatArray(float**, float*, uint32);
+extern void _TIFFsetDoubleArray(double**, double*, uint32);
+
+extern void _TIFFprintAscii(FILE*, const char*);
+extern void _TIFFprintAsciiTag(FILE*, const char*, const char*);
+
+extern TIFFErrorHandler _TIFFwarningHandler;
+extern TIFFErrorHandler _TIFFerrorHandler;
+extern TIFFErrorHandlerExt _TIFFwarningHandlerExt;
+extern TIFFErrorHandlerExt _TIFFerrorHandlerExt;
+
+extern uint32 _TIFFMultiply32(TIFF*, uint32, uint32, const char*);
+extern uint64 _TIFFMultiply64(TIFF*, uint64, uint64, const char*);
+extern void* _TIFFCheckMalloc(TIFF*, tmsize_t, tmsize_t, const char*);
+extern void* _TIFFCheckRealloc(TIFF*, void*, tmsize_t, tmsize_t, const char*);
+
+extern double _TIFFUInt64ToDouble(uint64);
+extern float _TIFFUInt64ToFloat(uint64);
+
+extern int TIFFInitDumpMode(TIFF*, int);
+#ifdef PACKBITS_SUPPORT
+extern int TIFFInitPackBits(TIFF*, int);
+#endif
+#ifdef CCITT_SUPPORT
+extern int TIFFInitCCITTRLE(TIFF*, int), TIFFInitCCITTRLEW(TIFF*, int);
+extern int TIFFInitCCITTFax3(TIFF*, int), TIFFInitCCITTFax4(TIFF*, int);
+#endif
+#ifdef THUNDER_SUPPORT
+extern int TIFFInitThunderScan(TIFF*, int);
+#endif
+#ifdef NEXT_SUPPORT
+extern int TIFFInitNeXT(TIFF*, int);
+#endif
+#ifdef LZW_SUPPORT
+extern int TIFFInitLZW(TIFF*, int);
+#endif
+#ifdef OJPEG_SUPPORT
+extern int TIFFInitOJPEG(TIFF*, int);
+#endif
+#ifdef JPEG_SUPPORT
+extern int TIFFInitJPEG(TIFF*, int);
+#endif
+#ifdef JBIG_SUPPORT
+extern int TIFFInitJBIG(TIFF*, int);
+#endif
+#ifdef ZIP_SUPPORT
+extern int TIFFInitZIP(TIFF*, int);
+#endif
+#ifdef PIXARLOG_SUPPORT
+extern int TIFFInitPixarLog(TIFF*, int);
+#endif
+#ifdef LOGLUV_SUPPORT
+extern int TIFFInitSGILog(TIFF*, int);
+#endif
+#ifdef LZMA_SUPPORT
+extern int TIFFInitLZMA(TIFF*, int);
+#endif
+#ifdef VMS
+extern const TIFFCodec _TIFFBuiltinCODECS[];
+#else
+extern TIFFCodec _TIFFBuiltinCODECS[];
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* _TIFFIOP_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiffvers.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiffvers.h
new file mode 100644
index 0000000..40edc81
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiffvers.h
@@ -0,0 +1,9 @@
+#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.3\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc."
+/*
+ * This define can be used in code that requires
+ * compilation-related definitions specific to a
+ * version or versions of the library.  Runtime
+ * version checking should be done based on the
+ * string returned by TIFFGetVersion.
+ */
+#define TIFFLIB_VERSION 20120922
diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/uvcode.h b/core/src/fxcodec/fx_tiff/tiff_v403/uvcode.h
new file mode 100644
index 0000000..50f11d7
--- /dev/null
+++ b/core/src/fxcodec/fx_tiff/tiff_v403/uvcode.h
@@ -0,0 +1,180 @@
+/* Version 1.0 generated April 7, 1997 by Greg Ward Larson, SGI */
+#define UV_SQSIZ	(float)0.003500
+#define UV_NDIVS	16289
+#define UV_VSTART	(float)0.016940
+#define UV_NVS		163
+static struct {
+	float	ustart;
+	short	nus, ncum;
+}	uv_row[UV_NVS] = {
+	{ (float)0.247663,	4,	0 },
+	{ (float)0.243779,	6,	4 },
+	{ (float)0.241684,	7,	10 },
+	{ (float)0.237874,	9,	17 },
+	{ (float)0.235906,	10,	26 },
+	{ (float)0.232153,	12,	36 },
+	{ (float)0.228352,	14,	48 },
+	{ (float)0.226259,	15,	62 },
+	{ (float)0.222371,	17,	77 },
+	{ (float)0.220410,	18,	94 },
+	{ (float)0.214710,	21,	112 },
+	{ (float)0.212714,	22,	133 },
+	{ (float)0.210721,	23,	155 },
+	{ (float)0.204976,	26,	178 },
+	{ (float)0.202986,	27,	204 },
+	{ (float)0.199245,	29,	231 },
+	{ (float)0.195525,	31,	260 },
+	{ (float)0.193560,	32,	291 },
+	{ (float)0.189878,	34,	323 },
+	{ (float)0.186216,	36,	357 },
+	{ (float)0.186216,	36,	393 },
+	{ (float)0.182592,	38,	429 },
+	{ (float)0.179003,	40,	467 },
+	{ (float)0.175466,	42,	507 },
+	{ (float)0.172001,	44,	549 },
+	{ (float)0.172001,	44,	593 },
+	{ (float)0.168612,	46,	637 },
+	{ (float)0.168612,	46,	683 },
+	{ (float)0.163575,	49,	729 },
+	{ (float)0.158642,	52,	778 },
+	{ (float)0.158642,	52,	830 },
+	{ (float)0.158642,	52,	882 },
+	{ (float)0.153815,	55,	934 },
+	{ (float)0.153815,	55,	989 },
+	{ (float)0.149097,	58,	1044 },
+	{ (float)0.149097,	58,	1102 },
+	{ (float)0.142746,	62,	1160 },
+	{ (float)0.142746,	62,	1222 },
+	{ (float)0.142746,	62,	1284 },
+	{ (float)0.138270,	65,	1346 },
+	{ (float)0.138270,	65,	1411 },
+	{ (float)0.138270,	65,	1476 },
+	{ (float)0.132166,	69,	1541 },
+	{ (float)0.132166,	69,	1610 },
+	{ (float)0.126204,	73,	1679 },
+	{ (float)0.126204,	73,	1752 },
+	{ (float)0.126204,	73,	1825 },
+	{ (float)0.120381,	77,	1898 },
+	{ (float)0.120381,	77,	1975 },
+	{ (float)0.120381,	77,	2052 },
+	{ (float)0.120381,	77,	2129 },
+	{ (float)0.112962,	82,	2206 },
+	{ (float)0.112962,	82,	2288 },
+	{ (float)0.112962,	82,	2370 },
+	{ (float)0.107450,	86,	2452 },
+	{ (float)0.107450,	86,	2538 },
+	{ (float)0.107450,	86,	2624 },
+	{ (float)0.107450,	86,	2710 },
+	{ (float)0.100343,	91,	2796 },
+	{ (float)0.100343,	91,	2887 },
+	{ (float)0.100343,	91,	2978 },
+	{ (float)0.095126,	95,	3069 },
+	{ (float)0.095126,	95,	3164 },
+	{ (float)0.095126,	95,	3259 },
+	{ (float)0.095126,	95,	3354 },
+	{ (float)0.088276,	100,	3449 },
+	{ (float)0.088276,	100,	3549 },
+	{ (float)0.088276,	100,	3649 },
+	{ (float)0.088276,	100,	3749 },
+	{ (float)0.081523,	105,	3849 },
+	{ (float)0.081523,	105,	3954 },
+	{ (float)0.081523,	105,	4059 },
+	{ (float)0.081523,	105,	4164 },
+	{ (float)0.074861,	110,	4269 },
+	{ (float)0.074861,	110,	4379 },
+	{ (float)0.074861,	110,	4489 },
+	{ (float)0.074861,	110,	4599 },
+	{ (float)0.068290,	115,	4709 },
+	{ (float)0.068290,	115,	4824 },
+	{ (float)0.068290,	115,	4939 },
+	{ (float)0.068290,	115,	5054 },
+	{ (float)0.063573,	119,	5169 },
+	{ (float)0.063573,	119,	5288 },
+	{ (float)0.063573,	119,	5407 },
+	{ (float)0.063573,	119,	5526 },
+	{ (float)0.057219,	124,	5645 },
+	{ (float)0.057219,	124,	5769 },
+	{ (float)0.057219,	124,	5893 },
+	{ (float)0.057219,	124,	6017 },
+	{ (float)0.050985,	129,	6141 },
+	{ (float)0.050985,	129,	6270 },
+	{ (float)0.050985,	129,	6399 },
+	{ (float)0.050985,	129,	6528 },
+	{ (float)0.050985,	129,	6657 },
+	{ (float)0.044859,	134,	6786 },
+	{ (float)0.044859,	134,	6920 },
+	{ (float)0.044859,	134,	7054 },
+	{ (float)0.044859,	134,	7188 },
+	{ (float)0.040571,	138,	7322 },
+	{ (float)0.040571,	138,	7460 },
+	{ (float)0.040571,	138,	7598 },
+	{ (float)0.040571,	138,	7736 },
+	{ (float)0.036339,	142,	7874 },
+	{ (float)0.036339,	142,	8016 },
+	{ (float)0.036339,	142,	8158 },
+	{ (float)0.036339,	142,	8300 },
+	{ (float)0.032139,	146,	8442 },
+	{ (float)0.032139,	146,	8588 },
+	{ (float)0.032139,	146,	8734 },
+	{ (float)0.032139,	146,	8880 },
+	{ (float)0.027947,	150,	9026 },
+	{ (float)0.027947,	150,	9176 },
+	{ (float)0.027947,	150,	9326 },
+	{ (float)0.023739,	154,	9476 },
+	{ (float)0.023739,	154,	9630 },
+	{ (float)0.023739,	154,	9784 },
+	{ (float)0.023739,	154,	9938 },
+	{ (float)0.019504,	158,	10092 },
+	{ (float)0.019504,	158,	10250 },
+	{ (float)0.019504,	158,	10408 },
+	{ (float)0.016976,	161,	10566 },
+	{ (float)0.016976,	161,	10727 },
+	{ (float)0.016976,	161,	10888 },
+	{ (float)0.016976,	161,	11049 },
+	{ (float)0.012639,	165,	11210 },
+	{ (float)0.012639,	165,	11375 },
+	{ (float)0.012639,	165,	11540 },
+	{ (float)0.009991,	168,	11705 },
+	{ (float)0.009991,	168,	11873 },
+	{ (float)0.009991,	168,	12041 },
+	{ (float)0.009016,	170,	12209 },
+	{ (float)0.009016,	170,	12379 },
+	{ (float)0.009016,	170,	12549 },
+	{ (float)0.006217,	173,	12719 },
+	{ (float)0.006217,	173,	12892 },
+	{ (float)0.005097,	175,	13065 },
+	{ (float)0.005097,	175,	13240 },
+	{ (float)0.005097,	175,	13415 },
+	{ (float)0.003909,	177,	13590 },
+	{ (float)0.003909,	177,	13767 },
+	{ (float)0.002340,	177,	13944 },
+	{ (float)0.002389,	170,	14121 },
+	{ (float)0.001068,	164,	14291 },
+	{ (float)0.001653,	157,	14455 },
+	{ (float)0.000717,	150,	14612 },
+	{ (float)0.001614,	143,	14762 },
+	{ (float)0.000270,	136,	14905 },
+	{ (float)0.000484,	129,	15041 },
+	{ (float)0.001103,	123,	15170 },
+	{ (float)0.001242,	115,	15293 },
+	{ (float)0.001188,	109,	15408 },
+	{ (float)0.001011,	103,	15517 },
+	{ (float)0.000709,	97,	15620 },
+	{ (float)0.000301,	89,	15717 },
+	{ (float)0.002416,	82,	15806 },
+	{ (float)0.003251,	76,	15888 },
+	{ (float)0.003246,	69,	15964 },
+	{ (float)0.004141,	62,	16033 },
+	{ (float)0.005963,	55,	16095 },
+	{ (float)0.008839,	47,	16150 },
+	{ (float)0.010490,	40,	16197 },
+	{ (float)0.016994,	31,	16237 },
+	{ (float)0.023659,	21,	16268 },
+};
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/core/src/fxcodec/lbmp/fx_bmp.cpp b/core/src/fxcodec/lbmp/fx_bmp.cpp
new file mode 100644
index 0000000..4c6eb61
--- /dev/null
+++ b/core/src/fxcodec/lbmp/fx_bmp.cpp
@@ -0,0 +1,917 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "fx_bmp.h"

+FX_DWORD _GetDWord_LSBFirst(FX_LPBYTE p)

+{

+    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);

+}

+FX_WORD _GetWord_LSBFirst(FX_LPBYTE p)

+{

+    return p[0] | (p[1] << 8);

+}

+void _SetDWord_LSBFirst(FX_LPBYTE p, FX_DWORD v)

+{

+    p[0] = (FX_BYTE)v;

+    p[1] = (FX_BYTE)(v >> 8);

+    p[2] = (FX_BYTE)(v >> 16);

+    p[3] = (FX_BYTE)(v >> 24);

+}

+void _SetWord_LSBFirst(FX_LPBYTE p, FX_WORD v)

+{

+    p[0] = (FX_BYTE)v;

+    p[1] = (FX_BYTE)(v >> 8);

+}

+void _bmp_error(bmp_decompress_struct_p bmp_ptr, FX_LPCSTR err_msg)

+{

+    if(bmp_ptr != NULL && bmp_ptr->_bmp_error_fn != NULL) {

+        bmp_ptr->_bmp_error_fn(bmp_ptr, err_msg);

+    }

+}

+bmp_decompress_struct_p _bmp_create_decompress()

+{

+    bmp_decompress_struct_p bmp_ptr = FX_Alloc(bmp_decompress_struct, 1);

+    if(bmp_ptr == NULL) {

+        return NULL;

+    }

+    FXSYS_memset32(bmp_ptr, 0, sizeof(bmp_decompress_struct));

+    bmp_ptr->decode_status = BMP_D_STATUS_HEADER;

+    bmp_ptr->bmp_header_ptr = FX_Alloc(BmpFileHeader, 1);

+    return bmp_ptr;

+}

+void _bmp_destroy_decompress(bmp_decompress_struct_pp bmp_ptr_ptr)

+{

+    if(bmp_ptr_ptr == NULL || *bmp_ptr_ptr == NULL) {

+        return;

+    }

+    bmp_decompress_struct_p bmp_ptr = *bmp_ptr_ptr;

+    *bmp_ptr_ptr = NULL;

+    if(bmp_ptr->out_row_buffer != NULL) {

+        FX_Free(bmp_ptr->out_row_buffer);

+    }

+    if(bmp_ptr->pal_ptr != NULL) {

+        FX_Free(bmp_ptr->pal_ptr);

+    }

+    if(bmp_ptr->bmp_header_ptr != NULL)	{

+        FX_Free(bmp_ptr->bmp_header_ptr);

+    }

+    FX_Free(bmp_ptr);

+}

+FX_INT32 _bmp_read_header(bmp_decompress_struct_p bmp_ptr)

+{

+    if(bmp_ptr == NULL) {

+        return 0;

+    }

+    FX_DWORD skip_size_org = bmp_ptr->skip_size;

+    if(bmp_ptr->decode_status == BMP_D_STATUS_HEADER) {

+        ASSERT(sizeof(BmpFileHeader) == 14);

+        BmpFileHeader* bmp_header_ptr = NULL;

+        if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&bmp_header_ptr, 14) == NULL) {

+            return 2;

+        }

+        bmp_ptr->bmp_header_ptr->bfType = _GetWord_LSBFirst((FX_LPBYTE)&bmp_header_ptr->bfType);

+        bmp_ptr->bmp_header_ptr->bfOffBits = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_header_ptr->bfOffBits);

+        bmp_ptr->data_size = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_header_ptr->bfSize);

+        if(bmp_ptr->bmp_header_ptr->bfType != BMP_SIGNATURE) {

+            _bmp_error(bmp_ptr, "Not A Bmp Image");

+            return 0;

+        }

+        if(bmp_ptr->avail_in < sizeof(FX_DWORD)) {

+            bmp_ptr->skip_size = skip_size_org;

+            return 2;

+        }

+        bmp_ptr->img_ifh_size = _GetDWord_LSBFirst(bmp_ptr->next_in + bmp_ptr->skip_size);

+        bmp_ptr->pal_type = 0;

+        ASSERT(sizeof(BmpCoreHeader) == 12);

+        ASSERT(sizeof(BmpInfoHeader) == 40);

+        switch(bmp_ptr->img_ifh_size) {

+            case FX_MIN(12, sizeof(BmpCoreHeader)): {

+                    bmp_ptr->pal_type = 1;

+                    BmpCoreHeaderPtr bmp_core_header_ptr = NULL;

+                    if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&bmp_core_header_ptr, bmp_ptr->img_ifh_size) == NULL) {

+                        bmp_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                    bmp_ptr->width = (FX_DWORD)_GetWord_LSBFirst((FX_LPBYTE)&bmp_core_header_ptr->bcWidth);

+                    bmp_ptr->height = (FX_DWORD)_GetWord_LSBFirst((FX_LPBYTE)&bmp_core_header_ptr->bcHeight);

+                    bmp_ptr->bitCounts = _GetWord_LSBFirst((FX_LPBYTE)&bmp_core_header_ptr->bcBitCount);

+                    bmp_ptr->compress_flag = BMP_RGB;

+                    bmp_ptr->imgTB_flag = FALSE;

+                }

+                break;

+            case FX_MIN(40, sizeof(BmpInfoHeader)): {

+                    BmpInfoHeaderPtr bmp_info_header_ptr = NULL;

+                    if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&bmp_info_header_ptr, bmp_ptr->img_ifh_size) == NULL) {

+                        bmp_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                    bmp_ptr->width = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biWidth);

+                    bmp_ptr->height = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biHeight);

+                    bmp_ptr->bitCounts = _GetWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biBitCount);

+                    bmp_ptr->compress_flag = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biCompression);

+                    bmp_ptr->color_used = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biClrUsed);

+                    bmp_ptr->dpi_x = (FX_INT32)_GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biXPelsPerMeter);

+                    bmp_ptr->dpi_y = (FX_INT32)_GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biYPelsPerMeter);

+                    if(bmp_ptr->height < 0) {

+                        bmp_ptr->height = -bmp_ptr->height;

+                        bmp_ptr->imgTB_flag = TRUE;

+                    }

+                }

+                break;

+            default: {

+                    if(bmp_ptr->img_ifh_size > FX_MIN(40, sizeof(BmpInfoHeader))) {

+                        BmpInfoHeaderPtr bmp_info_header_ptr = NULL;

+                        if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&bmp_info_header_ptr, bmp_ptr->img_ifh_size) == NULL) {

+                            bmp_ptr->skip_size = skip_size_org;

+                            return 2;

+                        }

+                        FX_WORD biPlanes;

+                        bmp_ptr->width = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biWidth);

+                        bmp_ptr->height = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biHeight);

+                        bmp_ptr->bitCounts = _GetWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biBitCount);

+                        bmp_ptr->compress_flag = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biCompression);

+                        bmp_ptr->color_used = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biClrUsed);

+                        biPlanes = _GetWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biPlanes);

+                        bmp_ptr->dpi_x = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biXPelsPerMeter);

+                        bmp_ptr->dpi_y = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biYPelsPerMeter);

+                        if(bmp_ptr->height < 0) {

+                            bmp_ptr->height = -bmp_ptr->height;

+                            bmp_ptr->imgTB_flag = TRUE;

+                        }

+                        if(bmp_ptr->compress_flag == BMP_RGB &&

+                                biPlanes == 1 &&

+                                bmp_ptr->color_used == 0) {

+                            break;

+                        }

+                    }

+                    _bmp_error(bmp_ptr, "Unsupported Bmp File");

+                    return 0;

+                }

+        }

+        ASSERT(bmp_ptr->width > 0);

+        ASSERT(bmp_ptr->compress_flag <= BMP_BITFIELDS);

+        switch(bmp_ptr->bitCounts) {

+            case 1:

+            case 4:

+            case 8:

+            case 16:

+            case 24: {

+                    if(bmp_ptr->color_used > ((FX_DWORD)1) << bmp_ptr->bitCounts) {

+                        _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                        return 0;

+                    }

+                }

+            case 32: {

+                    if(bmp_ptr->width <= 0 || bmp_ptr->compress_flag > BMP_BITFIELDS) {

+                        _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                        return 0;

+                    }

+                }

+                break;

+            default:

+                _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                return 0;

+        }

+        bmp_ptr->src_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, bmp_ptr->bitCounts);

+        switch(bmp_ptr->bitCounts) {

+            case 1:

+            case 4:

+            case 8:

+                bmp_ptr->out_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, 8);

+                bmp_ptr->components = 1;

+                break;

+            case 16:

+            case 24:

+                bmp_ptr->out_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, 24);

+                bmp_ptr->components = 3;

+                break;

+            case 32:

+                bmp_ptr->out_row_bytes = bmp_ptr->src_row_bytes;

+                bmp_ptr->components = 4;

+                break;

+        }

+        if(bmp_ptr->out_row_buffer != NULL) {

+            FX_Free(bmp_ptr->out_row_buffer);

+            bmp_ptr->out_row_buffer = NULL;

+        }

+        bmp_ptr->out_row_buffer = FX_Alloc(FX_BYTE, bmp_ptr->out_row_bytes);

+        BMP_PTR_NOT_NULL(bmp_ptr->out_row_buffer, bmp_ptr);

+        FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);

+        _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_PAL);

+    }

+    if (bmp_ptr->decode_status == BMP_D_STATUS_PAL) {

+        skip_size_org = bmp_ptr->skip_size;

+#ifdef BMP_SUPPORT_BITFIELD

+        if(bmp_ptr->compress_flag == BMP_BITFIELDS) {

+            if(bmp_ptr->bitCounts != 16 && bmp_ptr->bitCounts != 32) {

+                _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                return 0;

+            }

+            FX_DWORD* mask;

+            if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&mask, 3 * sizeof(FX_DWORD)) == NULL) {

+                bmp_ptr->skip_size = skip_size_org;

+                return 2;

+            }

+            bmp_ptr->mask_red	= _GetDWord_LSBFirst((FX_LPBYTE)&mask[0]);

+            bmp_ptr->mask_green	= _GetDWord_LSBFirst((FX_LPBYTE)&mask[1]);

+            bmp_ptr->mask_blue	= _GetDWord_LSBFirst((FX_LPBYTE)&mask[2]);

+            if(bmp_ptr->mask_red & bmp_ptr->mask_green ||

+                    bmp_ptr->mask_red & bmp_ptr->mask_blue ||

+                    bmp_ptr->mask_green & bmp_ptr->mask_blue) {

+                _bmp_error(bmp_ptr, "The Bitfield Bmp File Is Corrupt");

+                return 0;

+            }

+            if(bmp_ptr->bmp_header_ptr->bfOffBits < 26 + bmp_ptr->img_ifh_size) {

+                bmp_ptr->bmp_header_ptr->bfOffBits = 26 + bmp_ptr->img_ifh_size;

+            }

+            _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA_PRE);

+            return 1;

+        } else if(bmp_ptr->bitCounts == 16) {

+            bmp_ptr->mask_red	= 0x7C00;

+            bmp_ptr->mask_green = 0x03E0;

+            bmp_ptr->mask_blue	= 0x001F;

+        }

+#else

+        if(bmp_ptr->compress_flag == BMP_BITFIELDS || bmp_ptr->bitCounts == 16) {

+            _bmp_error(bmp_ptr, "Unsupported Bitfield Bmp File");

+            return 0;

+        }

+#endif

+        bmp_ptr->pal_num = 0;

+        if(bmp_ptr->bitCounts < 16) {

+            bmp_ptr->pal_num = 1 << bmp_ptr->bitCounts;

+            if(bmp_ptr->color_used != 0) {

+                bmp_ptr->pal_num = bmp_ptr->color_used;

+            }

+            FX_LPBYTE src_pal_ptr = NULL;

+            FX_DWORD src_pal_size = bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4);

+            if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&src_pal_ptr, src_pal_size) == NULL) {

+                bmp_ptr->skip_size = skip_size_org;

+                return 2;

+            }

+            if(bmp_ptr->pal_ptr != NULL) {

+                FX_Free(bmp_ptr->pal_ptr);

+                bmp_ptr->pal_ptr = NULL;

+            }

+            bmp_ptr->pal_ptr = FX_Alloc(FX_DWORD, bmp_ptr->pal_num);

+            BMP_PTR_NOT_NULL(bmp_ptr->pal_ptr, bmp_ptr);

+            FX_INT32 src_pal_index = 0;

+            if(bmp_ptr->pal_type == BMP_PAL_OLD) {

+                while(src_pal_index < bmp_ptr->pal_num) {

+                    bmp_ptr->pal_ptr[src_pal_index++] = BMP_PAL_ENCODE(0x00, src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]);

+                    src_pal_ptr += 3;

+                }

+            } else {

+                while(src_pal_index < bmp_ptr->pal_num) {

+                    bmp_ptr->pal_ptr[src_pal_index++] = BMP_PAL_ENCODE(src_pal_ptr[3], src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]);

+                    src_pal_ptr += 4;

+                }

+            }

+        }

+        if(bmp_ptr->bmp_header_ptr->bfOffBits < 14 + bmp_ptr->img_ifh_size + bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4)) {

+            bmp_ptr->bmp_header_ptr->bfOffBits = 14 + bmp_ptr->img_ifh_size + bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4);

+        }

+        _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA_PRE);

+    }

+    return 1;

+}

+FX_INT32 _bmp_decode_image(bmp_decompress_struct_p bmp_ptr)

+{

+    if(bmp_ptr->decode_status == BMP_D_STATUS_DATA_PRE) {

+        bmp_ptr->avail_in = 0;

+        if(!bmp_ptr->_bmp_get_data_position_fn(bmp_ptr, bmp_ptr->bmp_header_ptr->bfOffBits)) {

+            bmp_ptr->decode_status = BMP_D_STATUS_TAIL;

+            _bmp_error(bmp_ptr, "The Bmp File Is Corrupt, Unexpected Stream Offset");

+            return 0;

+        }

+        bmp_ptr->row_num = 0;

+        _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA);

+    }

+    if(bmp_ptr->decode_status == BMP_D_STATUS_DATA) {

+        switch(bmp_ptr->compress_flag) {

+            case BMP_RGB:

+            case BMP_BITFIELDS:

+                return _bmp_decode_rgb(bmp_ptr);

+            case BMP_RLE8:

+                return _bmp_decode_rle8(bmp_ptr);

+            case BMP_RLE4:

+                return _bmp_decode_rle4(bmp_ptr);

+        }

+    }

+    _bmp_error(bmp_ptr, "Any Uncontrol Error");

+    return 0;

+}

+FX_INT32 _bmp_decode_rgb(bmp_decompress_struct_p bmp_ptr)

+{

+    FX_LPBYTE row_buf = bmp_ptr->out_row_buffer;

+    FX_LPBYTE des_buf = NULL;

+    while (bmp_ptr->row_num < bmp_ptr->height) {

+        if(_bmp_read_data(bmp_ptr, &des_buf, bmp_ptr->src_row_bytes) == NULL) {

+            return 2;

+        }

+        _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA);

+        switch(bmp_ptr->bitCounts) {

+            case 1: {

+                    for (FX_INT32 col = 0; col < bmp_ptr->width; col++) {

+                        *row_buf++ = des_buf[col >> 3] & (0x80 >> (col % 8)) ? 0x01 : 0x00;

+                    }

+                }

+                break;

+            case 4: {

+                    for (FX_INT32 col = 0; col < bmp_ptr->width; col++) {

+                        *row_buf++ = (col & 0x01) ?

+                                     (des_buf[col >> 1] & 0x0F) :

+                                     ((des_buf[col >> 1] & 0xF0) >> 4);

+                    }

+                }

+                break;

+#ifdef BMP_SUPPORT_BITFIELD

+            case 16: {

+                    FX_WORD* buf = (FX_WORD*)des_buf;

+                    FX_BYTE blue_bits = 0;

+                    FX_BYTE green_bits = 0;

+                    FX_BYTE red_bits = 0;

+                    for(FX_INT32 i = 0; i < 16; i++) {

+                        if((bmp_ptr->mask_blue >> i) & 0x01) {

+                            blue_bits++;

+                        }

+                        if((bmp_ptr->mask_green >> i) & 0x01) {

+                            green_bits++;

+                        }

+                        if((bmp_ptr->mask_red >> i) & 0x01) {

+                            red_bits++;

+                        }

+                    }

+                    green_bits += blue_bits;

+                    red_bits += green_bits;

+                    blue_bits = 8 - blue_bits;

+                    green_bits -= 8;

+                    red_bits -= 8;

+                    for (FX_INT32 col = 0; col < bmp_ptr->width; col++) {

+                        *buf = _GetWord_LSBFirst((FX_LPBYTE)buf);

+                        *row_buf++ = (FX_BYTE)((*buf & bmp_ptr->mask_blue) << blue_bits);

+                        *row_buf++ = (FX_BYTE)((*buf & bmp_ptr->mask_green) >> green_bits);

+                        *row_buf++ = (FX_BYTE)((*buf++ & bmp_ptr->mask_red) >> red_bits);

+                    }

+                }

+                break;

+#endif

+            case 8:

+            case 24:

+            case 32:

+                FXSYS_memcpy32(bmp_ptr->out_row_buffer, des_buf, bmp_ptr->src_row_bytes);

+                break;

+        }

+        row_buf = bmp_ptr->out_row_buffer;

+        bmp_ptr->_bmp_get_row_fn(bmp_ptr,

+                                 bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++),

+                                 bmp_ptr->out_row_buffer);

+    }

+    _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);

+    return 1;

+}

+FX_INT32 _bmp_decode_rle8(bmp_decompress_struct_p bmp_ptr)

+{

+    FX_LPBYTE first_byte_ptr = NULL;

+    FX_LPBYTE second_byte_ptr = NULL;

+    bmp_ptr->col_num = 0;

+    while(TRUE) {

+        FX_DWORD skip_size_org = bmp_ptr->skip_size;

+        if(_bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) {

+            return 2;

+        }

+        switch(*first_byte_ptr) {

+            case RLE_MARKER: {

+                    if(_bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) {

+                        bmp_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                    switch(*first_byte_ptr) {

+                        case RLE_EOL: {

+                                if(bmp_ptr->row_num >= bmp_ptr->height) {

+                                    _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);

+                                    _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                                    return 0;

+                                }

+                                bmp_ptr->_bmp_get_row_fn(bmp_ptr,

+                                                         bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++),

+                                                         bmp_ptr->out_row_buffer);

+                                bmp_ptr->col_num = 0;

+                                FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);

+                                _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA);

+                                continue;

+                            }

+                        case RLE_EOI: {

+                                if(bmp_ptr->row_num < bmp_ptr->height) {

+                                    bmp_ptr->_bmp_get_row_fn(bmp_ptr,

+                                                             bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++),

+                                                             bmp_ptr->out_row_buffer);

+                                }

+                                _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);

+                                return 1;

+                            }

+                        case RLE_DELTA: {

+                                FX_LPBYTE delta_ptr;

+                                if(_bmp_read_data(bmp_ptr, &delta_ptr, 2) == NULL) {

+                                    bmp_ptr->skip_size = skip_size_org;

+                                    return 2;

+                                }

+                                bmp_ptr->col_num += (FX_INT32)delta_ptr[0];

+                                FX_INT32 bmp_row_num_next = bmp_ptr->row_num + (FX_INT32)delta_ptr[1];

+                                if(bmp_ptr->col_num >= bmp_ptr->out_row_bytes || bmp_row_num_next >= bmp_ptr->height) {

+                                    _bmp_error(bmp_ptr, "The Bmp File Is Corrupt Or Not Supported");

+                                    return 0;

+                                }

+                                while(bmp_ptr->row_num < bmp_row_num_next) {

+                                    FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);

+                                    bmp_ptr->_bmp_get_row_fn(bmp_ptr,

+                                                             bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++),

+                                                             bmp_ptr->out_row_buffer);

+                                }

+                            }

+                            break;

+                        default: {

+                                if((FX_INT32)(*first_byte_ptr) > bmp_ptr->src_row_bytes - bmp_ptr->col_num) {

+                                    _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                                    return 0;

+                                }

+                                if(_bmp_read_data(bmp_ptr, &second_byte_ptr,

+                                                  *first_byte_ptr & 1 ? *first_byte_ptr + 1 : *first_byte_ptr) == NULL) {

+                                    bmp_ptr->skip_size = skip_size_org;

+                                    return 2;

+                                }

+                                FXSYS_memcpy32(bmp_ptr->out_row_buffer + bmp_ptr->col_num, second_byte_ptr, *first_byte_ptr);

+                                bmp_ptr->col_num += (FX_INT32)(*first_byte_ptr);

+                            }

+                    }

+                }

+                break;

+            default: {

+                    if(_bmp_read_data(bmp_ptr, &second_byte_ptr, 1) == NULL) {

+                        bmp_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                    if((FX_INT32)(*first_byte_ptr) > bmp_ptr->src_row_bytes - bmp_ptr->col_num) {

+                        _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                        return 0;

+                    }

+                    FXSYS_memset8(bmp_ptr->out_row_buffer + bmp_ptr->col_num, *second_byte_ptr, *first_byte_ptr);

+                    bmp_ptr->col_num += (FX_INT32)(*first_byte_ptr);

+                }

+        }

+    }

+    _bmp_error(bmp_ptr, "Any Uncontrol Error");

+    return 0;

+}

+FX_INT32 _bmp_decode_rle4(bmp_decompress_struct_p bmp_ptr)

+{

+    FX_LPBYTE first_byte_ptr = NULL;

+    FX_LPBYTE second_byte_ptr = NULL;

+    bmp_ptr->col_num = 0;

+    while (TRUE) {

+        FX_DWORD skip_size_org = bmp_ptr->skip_size;

+        if(_bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) {

+            return 2;

+        }

+        switch(*first_byte_ptr) {

+            case RLE_MARKER: {

+                    if(_bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) {

+                        bmp_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                    switch(*first_byte_ptr) {

+                        case RLE_EOL: {

+                                if(bmp_ptr->row_num >= bmp_ptr->height) {

+                                    _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);

+                                    _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                                    return 0;

+                                }

+                                bmp_ptr->_bmp_get_row_fn(bmp_ptr,

+                                                         bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++),

+                                                         bmp_ptr->out_row_buffer);

+                                bmp_ptr->col_num = 0;

+                                FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);

+                                _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA);

+                                continue;

+                            }

+                        case RLE_EOI: {

+                                if(bmp_ptr->row_num < bmp_ptr->height) {

+                                    bmp_ptr->_bmp_get_row_fn(bmp_ptr,

+                                                             bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++),

+                                                             bmp_ptr->out_row_buffer);

+                                }

+                                _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);

+                                return 1;

+                            }

+                        case RLE_DELTA: {

+                                FX_LPBYTE delta_ptr;

+                                if(_bmp_read_data(bmp_ptr, &delta_ptr, 2) == NULL) {

+                                    bmp_ptr->skip_size = skip_size_org;

+                                    return 2;

+                                }

+                                bmp_ptr->col_num += (FX_INT32)delta_ptr[0];

+                                FX_INT32 bmp_row_num_next = bmp_ptr->row_num + (FX_INT32)delta_ptr[1];

+                                if(bmp_ptr->col_num >= bmp_ptr->out_row_bytes || bmp_row_num_next >= bmp_ptr->height) {

+                                    _bmp_error(bmp_ptr, "The Bmp File Is Corrupt Or Not Supported");

+                                    return 0;

+                                }

+                                while(bmp_ptr->row_num < bmp_row_num_next) {

+                                    FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);

+                                    bmp_ptr->_bmp_get_row_fn(bmp_ptr,

+                                                             bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++),

+                                                             bmp_ptr->out_row_buffer);

+                                }

+                            }

+                            break;

+                        default: {

+                                FX_BYTE size = (FX_BYTE)(((FX_WORD)(*first_byte_ptr) + 1) >> 1);

+                                if((FX_INT32)*first_byte_ptr >= bmp_ptr->out_row_bytes - bmp_ptr->col_num) {

+                                    if(size + (bmp_ptr->col_num >> 1) > bmp_ptr->src_row_bytes) {

+                                        _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                                        return 0;

+                                    }

+                                    *first_byte_ptr = bmp_ptr->out_row_bytes - bmp_ptr->col_num - 1;

+                                }

+                                if(_bmp_read_data(bmp_ptr, &second_byte_ptr, size & 1 ? size + 1 : size) == NULL) {

+                                    bmp_ptr->skip_size = skip_size_org;

+                                    return 2;

+                                }

+                                for (FX_BYTE i = 0; i < *first_byte_ptr; i++) {

+                                    if(i & 0x01) {

+                                        *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = (*second_byte_ptr++ & 0x0F);

+                                    } else {

+                                        *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = ((*second_byte_ptr & 0xF0) >> 4);

+                                    }

+                                }

+                            }

+                    }

+                }

+                break;

+            default: {

+                    if(_bmp_read_data(bmp_ptr, &second_byte_ptr, 1) == NULL) {

+                        bmp_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                    if((FX_INT32)*first_byte_ptr > bmp_ptr->out_row_bytes - bmp_ptr->col_num) {

+                        FX_BYTE size = (FX_BYTE)(((FX_WORD)(*first_byte_ptr) + 1) >> 1);

+                        if(size + (bmp_ptr->col_num >> 1) > bmp_ptr->src_row_bytes) {

+                            _bmp_error(bmp_ptr, "The Bmp File Is Corrupt");

+                            return 0;

+                        }

+                        *first_byte_ptr = bmp_ptr->out_row_bytes - bmp_ptr->col_num - 1;

+                    }

+                    for (FX_BYTE i = 0; i < *first_byte_ptr; i++) {

+                        if(i & 0x01) {

+                            *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = (*second_byte_ptr & 0x0F);

+                        } else {

+                            *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = ((*second_byte_ptr & 0xF0) >> 4);

+                        }

+                    }

+                }

+        }

+    }

+    _bmp_error(bmp_ptr, "Any Uncontrol Error");

+    return 0;

+}

+FX_LPBYTE _bmp_read_data(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE* des_buf_pp, FX_DWORD data_size)

+{

+    if(bmp_ptr == NULL ||

+            bmp_ptr->avail_in < bmp_ptr->skip_size + data_size) {

+        return NULL;

+    }

+    *des_buf_pp = bmp_ptr->next_in + bmp_ptr->skip_size;

+    bmp_ptr->skip_size += data_size;

+    return *des_buf_pp;

+}

+void _bmp_save_decoding_status(bmp_decompress_struct_p bmp_ptr, FX_INT32 status)

+{

+    bmp_ptr->decode_status = status;

+    bmp_ptr->next_in += bmp_ptr->skip_size;

+    bmp_ptr->avail_in -= bmp_ptr->skip_size;

+    bmp_ptr->skip_size = 0;

+}

+void _bmp_input_buffer(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE src_buf, FX_DWORD src_size)

+{

+    bmp_ptr->next_in = src_buf;

+    bmp_ptr->avail_in = src_size;

+    bmp_ptr->skip_size = 0;

+}

+FX_DWORD _bmp_get_avail_input(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE* avial_buf_ptr)

+{

+    if(avial_buf_ptr != NULL) {

+        *avial_buf_ptr = NULL;

+        if(bmp_ptr->avail_in > 0) {

+            *avial_buf_ptr = bmp_ptr->next_in;

+        }

+    }

+    return bmp_ptr->avail_in;

+}

+bmp_compress_struct_p _bmp_create_compress()

+{

+    bmp_compress_struct_p bmp_ptr;

+    bmp_ptr = FX_Alloc(bmp_compress_struct, 1);

+    if (bmp_ptr) {

+        FXSYS_memset32(bmp_ptr, 0, sizeof(bmp_compress_struct));

+    }

+    return bmp_ptr;

+}

+void _bmp_destroy_compress(bmp_compress_struct_p bmp_ptr)

+{

+    if (bmp_ptr) {

+        if (bmp_ptr->src_free && bmp_ptr->src_buf) {

+            FX_Free(bmp_ptr->src_buf);

+        }

+        FX_Free(bmp_ptr);

+    }

+}

+static void WriteFileHeader(BmpFileHeaderPtr head_ptr, FX_LPBYTE dst_buf)

+{

+    FX_DWORD offset;

+    offset = 0;

+    _SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfType);

+    offset += 2;

+    _SetDWord_LSBFirst(&dst_buf[offset], head_ptr->bfSize);

+    offset += 4;

+    _SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfReserved1);

+    offset += 2;

+    _SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfReserved2);

+    offset += 2;

+    _SetDWord_LSBFirst(&dst_buf[offset], head_ptr->bfOffBits);

+    offset += 4;

+}

+static void WriteInfoHeader(BmpInfoHeaderPtr info_head_ptr, FX_LPBYTE dst_buf)

+{

+    FX_DWORD offset;

+    offset = sizeof(BmpFileHeader);

+    _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biSize);

+    offset += 4;

+    _SetDWord_LSBFirst(&dst_buf[offset], (FX_DWORD)info_head_ptr->biWidth);

+    offset += 4;

+    _SetDWord_LSBFirst(&dst_buf[offset], (FX_DWORD)info_head_ptr->biHeight);

+    offset += 4;

+    _SetWord_LSBFirst(&dst_buf[offset], info_head_ptr->biPlanes);

+    offset += 2;

+    _SetWord_LSBFirst(&dst_buf[offset], info_head_ptr->biBitCount);

+    offset += 2;

+    _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biCompression);

+    offset += 4;

+    _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biSizeImage);

+    offset += 4;

+    _SetDWord_LSBFirst(&dst_buf[offset], (FX_DWORD)info_head_ptr->biXPelsPerMeter);

+    offset += 4;

+    _SetDWord_LSBFirst(&dst_buf[offset], (FX_DWORD)info_head_ptr->biYPelsPerMeter);

+    offset += 4;

+    _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biClrUsed);

+    offset += 4;

+    _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biClrImportant);

+    offset += 4;

+}

+#ifdef BMP_SUPPORT_BITFIELD

+static void _bmp_encode_bitfields(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size)

+{

+    if (bmp_ptr->info_header.biBitCount != 16 && bmp_ptr->info_header.biBitCount != 32) {

+        return;

+    }

+    FX_DWORD size, dst_pos, i;

+    size = bmp_ptr->src_pitch * bmp_ptr->src_row * bmp_ptr->info_header.biBitCount / 16;

+    dst_pos = bmp_ptr->file_header.bfOffBits;

+    dst_size += size;

+    dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_size);

+    if (dst_buf == NULL) {

+        return;

+    }

+    FXSYS_memset32(&dst_buf[dst_pos], 0, size);

+    FX_DWORD		mask_red;

+    FX_DWORD		mask_green;

+    FX_DWORD		mask_blue;

+    mask_red	= 0x7C00;

+    mask_green = 0x03E0;

+    mask_blue	= 0x001F;

+    if (bmp_ptr->info_header.biCompression == BMP_BITFIELDS) {

+        if (bmp_ptr->bit_type == BMP_BIT_565) {

+            mask_red	= 0xF800;

+            mask_green = 0x07E0;

+            mask_blue	= 0x001F;

+        }

+        if (bmp_ptr->info_header.biBitCount == 32) {

+            mask_red	= 0xFF0000;

+            mask_green = 0x00FF00;

+            mask_blue	= 0x0000FF;

+        }

+        _SetDWord_LSBFirst(&dst_buf[dst_pos], mask_red);

+        dst_pos += 4;

+        _SetDWord_LSBFirst(&dst_buf[dst_pos], mask_green);

+        dst_pos += 4;

+        _SetDWord_LSBFirst(&dst_buf[dst_pos], mask_blue);

+        dst_pos += 4;

+        bmp_ptr->file_header.bfOffBits = dst_pos;

+    }

+    FX_BYTE blue_bits = 0;

+    FX_BYTE green_bits = 0;

+    FX_BYTE red_bits = 0;

+    for(i = 0; i < bmp_ptr->info_header.biBitCount; i++) {

+        if((mask_blue >> i) & 0x01) {

+            blue_bits++;

+        }

+        if((mask_green >> i) & 0x01) {

+            green_bits++;

+        }

+        if((mask_red >> i) & 0x01) {

+            red_bits++;

+        }

+    }

+    green_bits += blue_bits;

+    red_bits += green_bits;

+    blue_bits = 8 - blue_bits;

+    green_bits -= 8;

+    red_bits -= 8;

+    i = 0;

+    for (FX_INT32 row_num = bmp_ptr->src_row - 1; row_num > -1; row_num--, i = 0) {

+        while (i < bmp_ptr->src_width * bmp_ptr->src_bpp / 8) {

+            FX_BYTE b = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++];

+            FX_BYTE g = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++];

+            FX_BYTE r = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++];

+            if (bmp_ptr->src_bpp == 32) {

+                i++;

+            }

+            FX_DWORD pix_val = 0;

+            pix_val |= (b >> blue_bits) & mask_blue;

+            pix_val |= (g << green_bits) & mask_green;

+            pix_val |= (r << red_bits) & mask_red;

+            if (bmp_ptr->info_header.biBitCount == 16) {

+                _SetWord_LSBFirst(&dst_buf[dst_pos], (FX_WORD)pix_val);

+                dst_pos += 2;

+            } else {

+                _SetDWord_LSBFirst(&dst_buf[dst_pos], pix_val);

+                dst_pos += 4;

+            }

+        }

+    }

+    dst_size = dst_pos;

+}

+#endif

+static void _bmp_encode_rgb(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size)

+{

+    if (bmp_ptr->info_header.biBitCount == 16) {

+#ifdef BMP_SUPPORT_BITFIELD

+        _bmp_encode_bitfields(bmp_ptr, dst_buf, dst_size);

+#endif

+        return;

+    }

+    FX_DWORD size, dst_pos;

+    FX_DWORD dst_pitch = (bmp_ptr->src_width * bmp_ptr->info_header.biBitCount + 31) / 32 * 4;

+    size = dst_pitch * bmp_ptr->src_row;

+    dst_pos = bmp_ptr->file_header.bfOffBits;

+    dst_size += size;

+    dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_size);

+    if (dst_buf == NULL) {

+        return;

+    }

+    FXSYS_memset32(&dst_buf[dst_pos], 0, size);

+    for (FX_INT32 row_num = bmp_ptr->src_row - 1; row_num > -1; row_num--) {

+        FXSYS_memcpy32(&dst_buf[dst_pos], &bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch], bmp_ptr->src_pitch);

+        dst_pos += dst_pitch;

+    }

+    dst_size = dst_pos;

+}

+static FX_BYTE _bmp_rle8_search(FX_LPCBYTE buf, FX_INT32 len)

+{

+    FX_BYTE num;

+    num = 1;

+    while (num < len) {

+        if (buf[num - 1] != buf[num] || num == 0xFF) {

+            break;

+        }

+        num++;

+    }

+    return num;

+}

+static void _bmp_encode_rle8(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size)

+{

+    FX_DWORD size, dst_pos, index;

+    FX_BYTE rle[2] = {0};

+    size = bmp_ptr->src_pitch * bmp_ptr->src_row * 2;

+    dst_pos = bmp_ptr->file_header.bfOffBits;

+    dst_size += size;

+    dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_size);

+    if (dst_buf == NULL) {

+        return;

+    }

+    FXSYS_memset32(&dst_buf[dst_pos], 0, size);

+    for (FX_INT32 row_num = bmp_ptr->src_row - 1, i = 0; row_num > -1; ) {

+        index = row_num * bmp_ptr->src_pitch;

+        rle[0] = _bmp_rle8_search(&bmp_ptr->src_buf[index + i], size - index - i);

+        rle[1] = bmp_ptr->src_buf[index + i];

+        if (i + rle[0] >= (FX_INT32)bmp_ptr->src_pitch) {

+            rle[0] = FX_BYTE(bmp_ptr->src_pitch - i);

+            if (rle[0]) {

+                dst_buf[dst_pos++] = rle[0];

+                dst_buf[dst_pos++] = rle[1];

+            }

+            dst_buf[dst_pos++] = RLE_MARKER;

+            dst_buf[dst_pos++] = RLE_EOL;

+            i = 0;

+            row_num--;

+        } else {

+            i += rle[0];

+            dst_buf[dst_pos++] = rle[0];

+            dst_buf[dst_pos++] = rle[1];

+        }

+    }

+    dst_buf[dst_pos++] = RLE_MARKER;

+    dst_buf[dst_pos++] = RLE_EOI;

+    dst_size = dst_pos;

+}

+static FX_BYTE _bmp_rle4_search(FX_LPCBYTE buf, FX_INT32 len)

+{

+    FX_BYTE num;

+    num = 2;

+    while (num < len) {

+        if (buf[num - 2] != buf[num] || num == 0xFF) {

+            break;

+        }

+        num++;

+    }

+    return num;

+}

+static void _bmp_encode_rle4(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size)

+{

+    FX_DWORD size, dst_pos, index;

+    FX_BYTE rle[2] = {0};

+    size = bmp_ptr->src_pitch * bmp_ptr->src_row;

+    dst_pos = bmp_ptr->file_header.bfOffBits;

+    dst_size += size;

+    dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_size);

+    if (dst_buf == NULL) {

+        return;

+    }

+    FXSYS_memset32(&dst_buf[dst_pos], 0, size);

+    for (FX_INT32 row_num = bmp_ptr->src_row - 1, i = 0; row_num > -1; rle[1] = 0) {

+        index = row_num * bmp_ptr->src_pitch;

+        rle[0] = _bmp_rle4_search(&bmp_ptr->src_buf[index + i], size - index - i);

+        rle[1] |= (bmp_ptr->src_buf[index + i] & 0x0f) << 4;

+        rle[1] |= bmp_ptr->src_buf[index + i + 1] & 0x0f;

+        if (i + rle[0] >= (FX_INT32)bmp_ptr->src_pitch) {

+            rle[0] = FX_BYTE(bmp_ptr->src_pitch - i);

+            if (rle[0]) {

+                dst_buf[dst_pos++] = rle[0];

+                dst_buf[dst_pos++] = rle[1];

+            }

+            dst_buf[dst_pos++] = RLE_MARKER;

+            dst_buf[dst_pos++] = RLE_EOL;

+            i = 0;

+            row_num--;

+        } else {

+            i += rle[0];

+            dst_buf[dst_pos++] = rle[0];

+            dst_buf[dst_pos++] = rle[1];

+        }

+    }

+    dst_buf[dst_pos++] = RLE_MARKER;

+    dst_buf[dst_pos++] = RLE_EOI;

+    dst_size = dst_pos;

+}

+FX_BOOL _bmp_encode_image( bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size )

+{

+    FX_DWORD head_size = sizeof(BmpFileHeader) + sizeof(BmpInfoHeader);

+    FX_DWORD pal_size = sizeof(FX_DWORD) * bmp_ptr->pal_num;

+    if (bmp_ptr->info_header.biClrUsed > 0 && bmp_ptr->info_header.biClrUsed < bmp_ptr->pal_num) {

+        pal_size = sizeof(FX_DWORD) * bmp_ptr->info_header.biClrUsed;

+    }

+    dst_size = head_size + sizeof(FX_DWORD) * bmp_ptr->pal_num;

+    dst_buf = FX_AllocNL(FX_BYTE, dst_size);

+    if (dst_buf == NULL) {

+        return FALSE;

+    }

+    FXSYS_memset32(dst_buf, 0, dst_size);

+    bmp_ptr->file_header.bfOffBits = head_size;

+    if (bmp_ptr->pal_ptr && pal_size) {

+        FXSYS_memcpy32(&dst_buf[head_size], bmp_ptr->pal_ptr, pal_size);

+        bmp_ptr->file_header.bfOffBits += pal_size;

+    }

+    WriteInfoHeader(&bmp_ptr->info_header, dst_buf);

+    switch(bmp_ptr->info_header.biCompression) {

+        case BMP_RGB:

+            _bmp_encode_rgb(bmp_ptr, dst_buf, dst_size);

+            break;

+        case BMP_BITFIELDS:

+#ifdef BMP_SUPPORT_BITFIELD

+            _bmp_encode_bitfields(bmp_ptr, dst_buf, dst_size);

+#endif

+            break;

+        case BMP_RLE8:

+            _bmp_encode_rle8(bmp_ptr, dst_buf, dst_size);

+            break;

+        case BMP_RLE4:

+            _bmp_encode_rle4(bmp_ptr, dst_buf, dst_size);

+            break;

+        default:

+            ;

+    }

+    bmp_ptr->file_header.bfSize = dst_size;

+    WriteFileHeader(&bmp_ptr->file_header, dst_buf);

+    return TRUE;

+}

diff --git a/core/src/fxcodec/lbmp/fx_bmp.h b/core/src/fxcodec/lbmp/fx_bmp.h
new file mode 100644
index 0000000..1603770
--- /dev/null
+++ b/core/src/fxcodec/lbmp/fx_bmp.h
@@ -0,0 +1,142 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#ifndef _FX_BASIC_H_

+#include "../../../include/fxcrt/fx_basic.h"

+#endif

+#define BMP_SUPPORT_BITFIELD

+#define BMP_WIDTHBYTES(width,bitCount)	((width*bitCount) + 31)/32*4

+#define BMP_PAL_ENCODE(a,r,g,b) (((FX_DWORD)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))

+#define BMP_D_STATUS_HEADER		0x01

+#define BMP_D_STATUS_PAL		0x02

+#define BMP_D_STATUS_DATA_PRE	0x03

+#define BMP_D_STATUS_DATA		0x04

+#define BMP_D_STATUS_TAIL		0x00

+#define BMP_SIGNATURE	0x4D42

+#define BMP_PAL_NEW		0

+#define BMP_PAL_OLD		1

+#define RLE_MARKER		0

+#define RLE_EOL			0

+#define RLE_EOI			1

+#define RLE_DELTA		2

+#define BMP_RGB			0L

+#define BMP_RLE8		1L

+#define BMP_RLE4		2L

+#define BMP_BITFIELDS	3L

+#define BMP_BIT_555		0

+#define BMP_BIT_565		1

+#define BMP_MAX_ERROR_SIZE	256

+#pragma pack(1)

+typedef struct tagBmpFileHeader {

+    FX_WORD		bfType;

+    FX_DWORD	bfSize;

+    FX_WORD		bfReserved1;

+    FX_WORD		bfReserved2;

+    FX_DWORD	bfOffBits;

+} BmpFileHeader, *BmpFileHeaderPtr;

+typedef struct tagBmpCoreHeader {

+    FX_DWORD   bcSize;

+    FX_WORD    bcWidth;

+    FX_WORD    bcHeight;

+    FX_WORD    bcPlanes;

+    FX_WORD    bcBitCount;

+} BmpCoreHeader, *BmpCoreHeaderPtr;

+typedef struct tagBmpInfoHeader {

+    FX_DWORD	biSize;

+    FX_INT32	biWidth;

+    FX_INT32	biHeight;

+    FX_WORD		biPlanes;

+    FX_WORD		biBitCount;

+    FX_DWORD	biCompression;

+    FX_DWORD	biSizeImage;

+    FX_INT32	biXPelsPerMeter;

+    FX_INT32	biYPelsPerMeter;

+    FX_DWORD	biClrUsed;

+    FX_DWORD	biClrImportant;

+} BmpInfoHeader, *BmpInfoHeaderPtr;

+#pragma pack()

+typedef struct tag_bmp_decompress_struct bmp_decompress_struct;

+typedef bmp_decompress_struct *bmp_decompress_struct_p;

+typedef bmp_decompress_struct_p *bmp_decompress_struct_pp;

+struct tag_bmp_decompress_struct {

+    jmp_buf			jmpbuf;

+    FX_LPSTR		err_ptr;

+    void			(*_bmp_error_fn)(bmp_decompress_struct_p gif_ptr, FX_LPCSTR err_msg);

+

+    void*			context_ptr;

+

+    BmpFileHeaderPtr	bmp_header_ptr;

+    BmpInfoHeaderPtr	bmp_infoheader_ptr;

+    FX_INT32		width;

+    FX_INT32		height;

+    FX_DWORD		compress_flag;

+    FX_INT32		components;

+    FX_INT32		src_row_bytes;

+    FX_INT32		out_row_bytes;

+    FX_LPBYTE		out_row_buffer;

+    FX_WORD			bitCounts;

+    FX_DWORD		color_used;

+    FX_BOOL			imgTB_flag;

+    FX_INT32		pal_num;

+    FX_INT32		pal_type;

+    FX_DWORD*		pal_ptr;

+    FX_DWORD		data_size;

+    FX_DWORD		img_data_offset;

+    FX_DWORD		img_ifh_size;

+    FX_INT32		row_num;

+    FX_INT32		col_num;

+    FX_INT32		dpi_x;

+    FX_INT32		dpi_y;

+#ifdef BMP_SUPPORT_BITFIELD

+    FX_DWORD		mask_red;

+    FX_DWORD		mask_green;

+    FX_DWORD		mask_blue;

+#endif

+

+    FX_BOOL			(*_bmp_get_data_position_fn)(bmp_decompress_struct_p bmp_ptr, FX_DWORD cur_pos);

+    void			(*_bmp_get_row_fn)(bmp_decompress_struct_p bmp_ptr, FX_INT32 row_num, FX_LPBYTE row_buf);

+    FX_LPBYTE		next_in;

+    FX_DWORD		avail_in;

+    FX_DWORD		skip_size;

+    FX_INT32		decode_status;

+};

+void _bmp_error(bmp_decompress_struct_p bmp_ptr, FX_LPCSTR err_msg);

+bmp_decompress_struct_p _bmp_create_decompress();

+void _bmp_destroy_decompress(bmp_decompress_struct_pp bmp_ptr_ptr);

+FX_INT32 _bmp_read_header(bmp_decompress_struct_p bmp_ptr);

+FX_INT32 _bmp_decode_image(bmp_decompress_struct_p bmp_ptr);

+FX_INT32 _bmp_decode_rgb(bmp_decompress_struct_p bmp_ptr);

+FX_INT32 _bmp_decode_rle8(bmp_decompress_struct_p bmp_ptr);

+FX_INT32 _bmp_decode_rle4(bmp_decompress_struct_p bmp_ptr);

+FX_LPBYTE _bmp_read_data(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE* des_buf_pp, FX_DWORD data_size);

+void _bmp_save_decoding_status(bmp_decompress_struct_p bmp_ptr, FX_INT32 status);

+void _bmp_input_buffer(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE src_buf, FX_DWORD src_size);

+FX_DWORD _bmp_get_avail_input(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE* avial_buf_ptr);

+#define BMP_PTR_NOT_NULL(ptr,bmp_ptr)	if(ptr == NULL){						\

+        _bmp_error(bmp_ptr,"Out Of Memory");\

+        return 0;							\

+    }

+typedef struct tag_bmp_compress_struct bmp_compress_struct;

+typedef bmp_compress_struct *bmp_compress_struct_p;

+typedef bmp_compress_struct_p *bmp_compress_struct_pp;

+struct tag_bmp_compress_struct {

+    BmpFileHeader	file_header;

+    BmpInfoHeader	info_header;

+    FX_LPBYTE		src_buf;

+    FX_DWORD		src_pitch;

+    FX_DWORD		src_row;

+    FX_BYTE			src_bpp;

+    FX_DWORD		src_width;

+    FX_BOOL			src_free;

+    FX_DWORD*		pal_ptr;

+    FX_WORD			pal_num;

+#ifdef BMP_SUPPORT_BITFIELD

+    FX_BYTE			bit_type;

+#endif

+};

+bmp_compress_struct_p _bmp_create_compress();

+void _bmp_destroy_compress(bmp_compress_struct_p bmp_ptr);

+FX_BOOL _bmp_encode_image(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size);

diff --git a/core/src/fxcodec/lgif/fx_gif.cpp b/core/src/fxcodec/lgif/fx_gif.cpp
new file mode 100644
index 0000000..8f5794e
--- /dev/null
+++ b/core/src/fxcodec/lgif/fx_gif.cpp
@@ -0,0 +1,1368 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#include "fx_gif.h"

+void CGifLZWDecoder::Input(FX_LPBYTE src_buf, FX_DWORD src_size)

+{

+    next_in = src_buf;

+    avail_in = src_size;

+}

+FX_DWORD CGifLZWDecoder::GetAvailInput()

+{

+    return avail_in;

+}

+void CGifLZWDecoder::InitTable(FX_BYTE code_len)

+{

+    code_size = code_len;

+    code_clear = 1 << code_size;

+    code_end = code_clear + 1;

+    bits_left = 0;

+    code_store = 0;

+    next_in = NULL;

+    avail_in = 0;

+    stack_size = 0;

+    code_first = 0;

+    ClearTable();

+}

+void CGifLZWDecoder::ClearTable()

+{

+    code_size_cur = code_size + 1;

+    code_next = code_end + 1;

+    code_old = (FX_WORD) - 1;

+    FXSYS_memset32(code_table, 0, sizeof(tag_Table)*GIF_MAX_LZW_CODE);

+    FXSYS_memset32(stack, 0, GIF_MAX_LZW_CODE);

+    for (FX_WORD i = 0; i < code_clear; i++) {

+        code_table[i].suffix = (FX_BYTE)i;

+    }

+}

+void CGifLZWDecoder::DecodeString(FX_WORD code)

+{

+    stack_size = 0;

+    while (TRUE) {

+        ASSERT(code <= code_next);

+        if(code < code_clear || code > code_next) {

+            break;

+        }

+        stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = code_table[code].suffix;

+        code = code_table[code].prefix;

+    }

+    stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = (FX_BYTE)code;

+    code_first = (FX_BYTE)code;

+}

+void CGifLZWDecoder::AddCode(FX_WORD prefix_code, FX_BYTE append_char)

+{

+    if(code_next == GIF_MAX_LZW_CODE) {

+        return;

+    }

+    code_table[code_next].prefix = prefix_code;

+    code_table[code_next].suffix = append_char;

+    if(++code_next < GIF_MAX_LZW_CODE) {

+        if(code_next >> code_size_cur) {

+            code_size_cur++;

+        }

+    }

+}

+FX_INT32 CGifLZWDecoder::Decode(FX_LPBYTE des_buf, FX_DWORD& des_size)

+{

+    if(des_size == 0) {

+        return 3;

+    }

+    FX_DWORD i = 0;

+    if(stack_size != 0) {

+        if(des_size < stack_size) {

+            FXSYS_memcpy32(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], des_size);

+            stack_size -= (FX_WORD)des_size;

+            return 3;

+        }

+        FXSYS_memcpy32(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], stack_size);

+        des_buf += stack_size;

+        i += stack_size;

+        stack_size = 0;

+    }

+    FX_WORD code = 0;

+    while(i <= des_size && (avail_in > 0 || bits_left >= code_size_cur)) {

+        if(code_size_cur > 12) {

+            if(err_msg_ptr)	{

+                FXSYS_strncpy(err_msg_ptr, "Code Length Out Of Range", GIF_MAX_ERROR_SIZE - 1);

+            }

+            return 0;

+        }

+        if (avail_in > 0) {

+            code_store |= (*next_in++) << bits_left;

+            avail_in--;

+            bits_left += 8;

+        }

+        while (bits_left >= code_size_cur) {

+            code = (FX_WORD)code_store & ((1 << code_size_cur) - 1);

+            code_store >>= code_size_cur;

+            bits_left -= code_size_cur;

+            if(code == code_clear) {

+                ClearTable();

+                continue;

+            } else if (code == code_end) {

+                des_size = i;

+                return 1;

+            } else {

+                if(code_old != (FX_WORD) - 1) {

+                    if(code_next < GIF_MAX_LZW_CODE) {

+                        if(code == code_next) {

+                            AddCode(code_old, code_first);

+                            DecodeString(code);

+                        } else if(code > code_next) {

+                            if(err_msg_ptr)	{

+                                FXSYS_strncpy(err_msg_ptr, "Decode Error, Out Of Range", GIF_MAX_ERROR_SIZE - 1);

+                            }

+                            return 0;

+                        } else {

+                            DecodeString(code);

+                            FX_BYTE append_char = stack[GIF_MAX_LZW_CODE - stack_size];

+                            AddCode(code_old, append_char);

+                        }

+                    }

+                } else {

+                    DecodeString(code);

+                }

+                code_old = code;

+                if(i + stack_size > des_size) {

+                    FXSYS_memcpy32(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], des_size - i);

+                    stack_size -= (FX_WORD)(des_size - i);

+                    return 3;

+                }

+                FXSYS_memcpy32(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], stack_size);

+                des_buf += stack_size;

+                i += stack_size;

+                stack_size = 0;

+            }

+        }

+    }

+    if(avail_in == 0) {

+        des_size = i;

+        return 2;

+    }

+    return 0;

+}

+static FX_BOOL _gif_grow_buf(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD size)

+{

+    if (dst_len < size) {

+        FX_DWORD len_org = dst_len;

+        while (dst_buf && dst_len < size) {

+            dst_len <<= 1;

+            dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_len);

+        }

+        if (dst_buf == NULL) {

+            dst_len = size;

+            dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_len);

+            if (dst_buf == NULL) {

+                return FALSE;

+            }

+        }

+        FXSYS_memset32(dst_buf + len_org, 0, dst_len - len_org);

+        return dst_buf != NULL;

+    }

+    return TRUE;

+}

+static inline void _gif_cut_index(FX_BYTE& val, FX_DWORD index, FX_BYTE index_bit, FX_BYTE index_bit_use, FX_BYTE bit_use)

+{

+    FX_DWORD cut = ((1 << (index_bit - index_bit_use)) - 1) << index_bit_use;

+    val |= ((index & cut) >> index_bit_use) << bit_use;

+}

+static inline FX_BYTE _gif_cut_buf(FX_LPCBYTE buf, FX_DWORD& offset, FX_BYTE bit_cut, FX_BYTE& bit_offset, FX_DWORD& bit_num)

+{

+    if (bit_cut != 8) {

+        FX_WORD index = 0;

+        index |= ((1 << bit_cut) - 1) << (7 - bit_offset);

+        FX_BYTE ret = ((index & buf[offset]) >> (7 - bit_offset));

+        bit_offset += bit_cut;

+        if (bit_offset >= 8) {

+            if (bit_offset > 8) {

+                ret |= ((index & (buf[offset + 1] << 8)) >> 8);

+            }

+            bit_offset -= 8;

+            offset ++;

+        }

+        bit_num += bit_cut;

+        return ret;

+    }

+    bit_num += bit_cut;

+    return buf[offset++];

+}

+CGifLZWEncoder::CGifLZWEncoder()

+{

+    FXSYS_memset32(this, 0, sizeof(CGifLZWEncoder));

+}

+CGifLZWEncoder::~CGifLZWEncoder()

+{

+}

+void CGifLZWEncoder::ClearTable()

+{

+    index_bit_cur = code_size + 1;

+    index_num = code_end + 1;

+    table_cur = code_end + 1;

+    for (FX_WORD i = 0; i < GIF_MAX_LZW_CODE; i++) {

+        code_table[i].prefix = 0;

+        code_table[i].suffix = 0;

+    }

+}

+void CGifLZWEncoder::Start( FX_BYTE code_len, FX_LPCBYTE src_buf, FX_LPBYTE& dst_buf, FX_DWORD& offset)

+{

+    code_size = code_len + 1;

+    src_bit_cut = code_size;

+    if (code_len == 0) {

+        src_bit_cut = 1;

+        code_size = 2;

+    }

+    code_clear = 1 << code_size;

+    code_end = code_clear + 1;

+    dst_buf[offset++] = code_size;

+    bit_offset = 0;

+    ClearTable();

+    src_offset = 0;

+    src_bit_offset = 0;

+    src_bit_num = 0;

+    code_table[index_num].prefix = _gif_cut_buf(src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num);

+    code_table[index_num].suffix = _gif_cut_buf(src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num);

+}

+void CGifLZWEncoder::WriteBlock(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset)

+{

+    if (!_gif_grow_buf(dst_buf, dst_len, offset + GIF_DATA_BLOCK + 1)) {

+        longjmp(jmp, 1);

+    }

+    dst_buf[offset++] = index_buf_len;

+    FXSYS_memcpy32(&dst_buf[offset], index_buf, index_buf_len);

+    offset += index_buf_len;

+    FXSYS_memset32(index_buf, 0, GIF_DATA_BLOCK);

+    index_buf_len = 0;

+}

+void CGifLZWEncoder::EncodeString( FX_DWORD index, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset )

+{

+    FX_BYTE index_bit_use;

+    index_bit_use = 0;

+    if (index_buf_len == GIF_DATA_BLOCK) {

+        WriteBlock(dst_buf, dst_len, offset);

+    }

+    _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use, bit_offset);

+    if (index_bit_cur <= (8 - bit_offset)) {

+        bit_offset += index_bit_cur;

+    } else if (index_bit_cur <= (16 - bit_offset)) {

+        index_bit_use += (8 - bit_offset);

+        bit_offset = 0;

+        index_buf_len++;

+        if (index_buf_len == GIF_DATA_BLOCK) {

+            WriteBlock(dst_buf, dst_len, offset);

+        }

+        _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use, bit_offset);

+        bit_offset = index_bit_cur - index_bit_use;

+    } else {

+        index_bit_use += (8 - bit_offset);

+        bit_offset = 0;

+        index_buf_len++;

+        if (index_buf_len == GIF_DATA_BLOCK) {

+            WriteBlock(dst_buf, dst_len, offset);

+        }

+        _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use, bit_offset);

+        index_bit_use += 8;

+        bit_offset = 0;

+        index_buf_len++;

+        if (index_buf_len == GIF_DATA_BLOCK) {

+            WriteBlock(dst_buf, dst_len, offset);

+        }

+        _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use, bit_offset);

+        bit_offset = index_bit_cur - index_bit_use;

+    }

+    if (bit_offset == 8) {

+        bit_offset = 0;

+        index_buf_len++;

+        if (index_buf_len == GIF_DATA_BLOCK) {

+            WriteBlock(dst_buf, dst_len, offset);

+        }

+    }

+    if (index == code_end)	{

+        index_buf_len++;

+        WriteBlock(dst_buf, dst_len, offset);

+    }

+    if (index_num++ >> index_bit_cur) {

+        index_bit_cur++;

+    }

+}

+FX_BOOL CGifLZWEncoder::Encode( FX_LPCBYTE src_buf, FX_DWORD src_len, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset )

+{

+    FX_BYTE		suffix;

+    if (setjmp(jmp)) {

+        return FALSE;

+    }

+    while(src_bit_num < src_len) {

+        if (!LookUpInTable(src_buf, src_offset, src_bit_offset)) {

+            EncodeString(code_table[index_num].prefix, dst_buf, dst_len, offset);

+            if (index_num == GIF_MAX_LZW_CODE) {

+                suffix = code_table[index_num - 1].suffix;

+                EncodeString(code_clear, dst_buf, dst_len, offset);

+                ClearTable();

+                code_table[index_num].prefix = suffix;

+                code_table[index_num].suffix = _gif_cut_buf(src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num);

+            } else {

+                code_table[index_num].prefix = code_table[index_num - 1].suffix;

+                code_table[index_num].suffix = _gif_cut_buf(src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num);

+            }

+        }

+    }

+    src_offset = 0;

+    src_bit_offset = 0;

+    src_bit_num = 0;

+    return TRUE;

+}

+FX_BOOL CGifLZWEncoder::LookUpInTable( FX_LPCBYTE buf, FX_DWORD& offset, FX_BYTE& bit_offset )

+{

+    for (FX_WORD i = table_cur; i < index_num; i++) {

+        if (code_table[i].prefix == code_table[index_num].prefix &&

+                code_table[i].suffix == code_table[index_num].suffix) {

+            code_table[index_num].prefix = i;

+            code_table[index_num].suffix = _gif_cut_buf(buf, offset, src_bit_cut, bit_offset, src_bit_num);

+            table_cur = i;

+            return TRUE;

+        }

+    }

+    table_cur = code_end + 1;

+    return FALSE;

+}

+void CGifLZWEncoder::Finish(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset)

+{

+    EncodeString(code_table[index_num].prefix, dst_buf, dst_len, offset);

+    EncodeString(code_end, dst_buf, dst_len, offset);

+    bit_offset = 0;

+    ClearTable();

+}

+gif_decompress_struct_p _gif_create_decompress()

+{

+    gif_decompress_struct_p gif_ptr = (gif_decompress_struct*)FX_Alloc(FX_BYTE, sizeof(gif_decompress_struct));

+    if(gif_ptr == NULL) {

+        return NULL;

+    }

+    FXSYS_memset32(gif_ptr, 0, sizeof(gif_decompress_struct));

+    gif_ptr->decode_status = GIF_D_STATUS_SIG;

+    gif_ptr->img_ptr_arr_ptr = FX_NEW CFX_ArrayTemplate<GifImage*>;

+    if(gif_ptr->img_ptr_arr_ptr == NULL) {

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+#ifdef GIF_SUPPORT_COMMENT_EXTENSION

+    gif_ptr->cmt_data_ptr = FX_NEW CFX_ByteString;

+    if(gif_ptr->cmt_data_ptr == NULL) {

+        delete gif_ptr->img_ptr_arr_ptr;

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+#endif

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+    gif_ptr->pt_ptr_arr_ptr = FX_NEW CFX_ArrayTemplate<GifPlainText*>;

+    if(gif_ptr->pt_ptr_arr_ptr == NULL) {

+        delete(gif_ptr->cmt_data_ptr);

+        delete gif_ptr->img_ptr_arr_ptr;

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+#endif

+    return gif_ptr;

+}

+void _gif_destroy_decompress(gif_decompress_struct_pp gif_ptr_ptr)

+{

+    if(gif_ptr_ptr == NULL || *gif_ptr_ptr == NULL) {

+        return;

+    }

+    gif_decompress_struct_p gif_ptr = *gif_ptr_ptr;

+    *gif_ptr_ptr = NULL;

+    if(gif_ptr->global_pal_ptr != NULL) {

+        FX_Free(gif_ptr->global_pal_ptr);

+    }

+    if(gif_ptr->img_decoder_ptr != NULL) {

+        delete gif_ptr->img_decoder_ptr;

+    }

+    if(gif_ptr->img_ptr_arr_ptr != NULL) {

+        FX_INT32 size_img_arr = gif_ptr->img_ptr_arr_ptr->GetSize();

+        for (FX_INT32 i = 0; i < size_img_arr; i++) {

+            GifImage* p = gif_ptr->img_ptr_arr_ptr->GetAt(i);

+            if(p->image_info_ptr != NULL) {

+                FX_Free(p->image_info_ptr);

+            }

+            if(p->image_gce_ptr != NULL) {

+                FX_Free(p->image_gce_ptr);

+            }

+            if(p->image_row_buf != NULL) {

+                FX_Free(p->image_row_buf);

+            }

+            if(p->local_pal_ptr != NULL && p->local_pal_ptr != gif_ptr->global_pal_ptr) {

+                FX_Free(p->local_pal_ptr);

+            }

+            FX_Free(p);

+        }

+        gif_ptr->img_ptr_arr_ptr->RemoveAll();

+        delete gif_ptr->img_ptr_arr_ptr;

+    }

+#ifdef GIF_SUPPORT_APPLICATION_EXTENSION

+    if(gif_ptr->app_data != NULL) {

+        FX_Free(gif_ptr->app_data);

+    }

+#endif

+#ifdef GIF_SUPPORT_COMMENT_EXTENSION

+    if(gif_ptr->cmt_data_ptr != NULL) {

+        delete gif_ptr->cmt_data_ptr;

+    }

+#endif

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+    if(gif_ptr->gce_ptr != NULL) {

+        FX_Free(gif_ptr->gce_ptr);

+    }

+#endif

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+    if(gif_ptr->pt_ptr_arr_ptr != NULL) {

+        FX_INT32 size_pt_arr = gif_ptr->pt_ptr_arr_ptr->GetSize();

+        for (FX_INT32 i = 0; i < size_pt_arr; i++) {

+            GifPlainText* p = gif_ptr->pt_ptr_arr_ptr->GetAt(i);

+            if(p->gce_ptr != NULL) {

+                FX_Free(p->gce_ptr);

+            }

+            if(p->pte_ptr != NULL) {

+                FX_Free(p->pte_ptr);

+            }

+            if(p->string_ptr != NULL) {

+                delete p->string_ptr;

+            }

+        }

+        gif_ptr->pt_ptr_arr_ptr->RemoveAll();

+        delete gif_ptr->pt_ptr_arr_ptr;

+    }

+#endif

+    FX_Free(gif_ptr);

+}

+gif_compress_struct_p _gif_create_compress()

+{

+    gif_compress_struct_p gif_ptr = (gif_compress_struct*)FX_Alloc(FX_BYTE, sizeof(gif_compress_struct));

+    if (gif_ptr == NULL) {

+        return NULL;

+    }

+    FXSYS_memset32(gif_ptr, 0, sizeof(gif_compress_struct));

+    gif_ptr->img_encoder_ptr = FX_NEW CGifLZWEncoder;

+    if (gif_ptr->img_encoder_ptr == NULL) {

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+    gif_ptr->header_ptr = (GifHeader*)FX_Alloc(FX_BYTE, sizeof(GifHeader));

+    if (gif_ptr->header_ptr == NULL) {

+        delete(gif_ptr->img_encoder_ptr);

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+    FXSYS_memcpy32(gif_ptr->header_ptr->signature, GIF_SIGNATURE, 3);

+    FXSYS_memcpy32(gif_ptr->header_ptr->version, "89a", 3);

+    gif_ptr->lsd_ptr = (GifLSD*)FX_Alloc(FX_BYTE, sizeof(GifLSD));

+    if (gif_ptr->lsd_ptr == NULL) {

+        FX_Free(gif_ptr->header_ptr);

+        delete(gif_ptr->img_encoder_ptr);

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+    FXSYS_memset32(gif_ptr->lsd_ptr, 0, sizeof(GifLSD));

+    gif_ptr->image_info_ptr = (GifImageInfo*)FX_Alloc(FX_BYTE, sizeof(GifImageInfo));

+    if (gif_ptr->image_info_ptr == NULL) {

+        FX_Free(gif_ptr->lsd_ptr);

+        FX_Free(gif_ptr->header_ptr);

+        delete(gif_ptr->img_encoder_ptr);

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+    FXSYS_memset32(gif_ptr->image_info_ptr, 0, sizeof(GifImageInfo));

+#ifdef GIF_SUPPORT_APPLICATION_EXTENSION

+    FXSYS_memcpy32(gif_ptr->app_identify, "netscape", 8);

+    FXSYS_memcpy32(gif_ptr->app_authentication, "2.0", 3);

+#endif

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+    gif_ptr->gce_ptr = (GifGCE*)FX_Alloc(FX_BYTE, sizeof(GifGCE));

+    if (gif_ptr->gce_ptr == NULL) {

+        FX_Free(gif_ptr->image_info_ptr);

+        FX_Free(gif_ptr->lsd_ptr);

+        FX_Free(gif_ptr->header_ptr);

+        delete(gif_ptr->img_encoder_ptr);

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+#endif

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+    gif_ptr->pte_ptr = (GifPTE*)FX_Alloc(FX_BYTE, sizeof(GifPTE));

+    if (gif_ptr->pte_ptr == NULL) {

+        FX_Free(gif_ptr->gce_ptr);

+        FX_Free(gif_ptr->image_info_ptr);

+        FX_Free(gif_ptr->lsd_ptr);

+        FX_Free(gif_ptr->header_ptr);

+        delete(gif_ptr->img_encoder_ptr);

+        FX_Free(gif_ptr);

+        return NULL;

+    }

+    FXSYS_memset32(gif_ptr->pte_ptr, 0, sizeof(GifPTE));

+    gif_ptr->pte_ptr->block_size = 12;

+#endif

+    return gif_ptr;

+}

+void _gif_destroy_compress(gif_compress_struct_pp gif_ptr_ptr)

+{

+    if(gif_ptr_ptr == NULL || *gif_ptr_ptr == NULL) {

+        return;

+    }

+    gif_compress_struct_p gif_ptr = *gif_ptr_ptr;

+    *gif_ptr_ptr = NULL;

+    if(gif_ptr->header_ptr != NULL)	{

+        FX_Free(gif_ptr->header_ptr);

+    }

+    if(gif_ptr->lsd_ptr != NULL)	{

+        FX_Free(gif_ptr->lsd_ptr);

+    }

+    if(gif_ptr->global_pal != NULL)	{

+        FX_Free(gif_ptr->global_pal);

+    }

+    if(gif_ptr->image_info_ptr != NULL)	{

+        FX_Free(gif_ptr->image_info_ptr);

+    }

+    if(gif_ptr->local_pal != NULL)	{

+        FX_Free(gif_ptr->local_pal);

+    }

+    if(gif_ptr->img_encoder_ptr != NULL) {

+        delete gif_ptr->img_encoder_ptr;

+    }

+#ifdef GIF_SUPPORT_APPLICATION_EXTENSION

+    if(gif_ptr->app_data != NULL) {

+        FX_Free(gif_ptr->app_data);

+    }

+#endif

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+    if(gif_ptr->gce_ptr != NULL) {

+        FX_Free(gif_ptr->gce_ptr);

+    }

+#endif

+#ifdef GIF_SUPPORT_COMMENT_EXTENSION

+    if(gif_ptr->cmt_data_ptr != NULL) {

+        FX_Free(gif_ptr->cmt_data_ptr);

+    }

+#endif

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+    if(gif_ptr->pte_ptr != NULL) {

+        FX_Free(gif_ptr->pte_ptr);

+    }

+#endif

+    FX_Free(gif_ptr);

+}

+void _gif_error(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg)

+{

+    if(gif_ptr != NULL && gif_ptr->_gif_error_fn != NULL) {

+        gif_ptr->_gif_error_fn(gif_ptr, err_msg);

+    }

+}

+void _gif_warn(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg) {}

+FX_INT32 _gif_read_header(gif_decompress_struct_p gif_ptr)

+{

+    if(gif_ptr == NULL) {

+        return 0;

+    }

+    FX_DWORD skip_size_org = gif_ptr->skip_size;

+    ASSERT(sizeof(GifHeader) == 6);

+    GifHeader* gif_header_ptr = NULL;

+    if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_header_ptr, 6) == NULL) {

+        return 2;

+    }

+    if(FXSYS_strncmp(gif_header_ptr->signature, GIF_SIGNATURE, 3) != 0 ||

+            gif_header_ptr->version[0] != '8' ||

+            gif_header_ptr->version[2] != 'a') {

+        _gif_error(gif_ptr, "Not A Gif Image");

+        return 0;

+    }

+    ASSERT(sizeof(GifLSD) == 7);

+    GifLSD* gif_lsd_ptr = NULL;

+    if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_lsd_ptr, 7) == NULL) {

+        gif_ptr->skip_size = skip_size_org;

+        return 2;

+    }

+    if(((GifGF*)&gif_lsd_ptr->global_flag)->global_pal) {

+        gif_ptr->global_pal_num = 2 << ((GifGF*)&gif_lsd_ptr->global_flag)->pal_bits;

+        ASSERT(sizeof(GifPalette) == 3);

+        FX_INT32 global_pal_size = gif_ptr->global_pal_num * 3;

+        FX_LPBYTE global_pal_ptr = NULL;

+        if (_gif_read_data(gif_ptr, &global_pal_ptr, global_pal_size) == NULL) {

+            gif_ptr->skip_size = skip_size_org;

+            return 2;

+        }

+        gif_ptr->global_sort_flag = ((GifGF*)&gif_lsd_ptr->global_flag)->sort_flag;

+        gif_ptr->global_color_resolution = ((GifGF*)&gif_lsd_ptr->global_flag)->color_resolution;

+        if(gif_ptr->global_pal_ptr != NULL) {

+            FX_Free(gif_ptr->global_pal_ptr);

+        }

+        gif_ptr->global_pal_ptr = NULL;

+        gif_ptr->global_pal_ptr = (GifPalette*)FX_Alloc(FX_BYTE, global_pal_size);

+        GIF_PTR_NOT_NULL(gif_ptr->global_pal_ptr, gif_ptr);

+        FXSYS_memcpy32(gif_ptr->global_pal_ptr, global_pal_ptr, global_pal_size);

+    }

+    gif_ptr->width = (int)_GetWord_LSBFirst((FX_LPBYTE)&gif_lsd_ptr->width);

+    gif_ptr->height = (int)_GetWord_LSBFirst((FX_LPBYTE)&gif_lsd_ptr->height);

+    gif_ptr->bc_index = gif_lsd_ptr->bc_index;

+    gif_ptr->pixel_aspect = gif_lsd_ptr->pixel_aspect;

+    return 1;

+}

+FX_INT32 _gif_get_frame(gif_decompress_struct_p gif_ptr)

+{

+    if(gif_ptr == NULL) {

+        return 0;

+    }

+    FX_INT32 ret = 1;

+    while (TRUE) {

+        switch(gif_ptr->decode_status) {

+            case GIF_D_STATUS_TAIL:

+                return 1;

+            case GIF_D_STATUS_SIG: {

+                    FX_LPBYTE sig_ptr = NULL;

+                    if(_gif_read_data(gif_ptr, &sig_ptr, 1) == NULL) {

+                        return 2;

+                    }

+                    switch(*sig_ptr) {

+                        case GIF_SIG_EXTENSION:

+                            _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT);

+                            continue;

+                        case GIF_SIG_IMAGE:

+                            _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_INFO);

+                            continue;

+                        case GIF_SIG_TRAILER:

+                            _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);

+                            return 1;

+                        default:

+                            if (gif_ptr->avail_in) {

+                                _gif_warn(gif_ptr, "The Gif File has non_standard Tag!");

+                                _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG);

+                                continue;

+                            }

+                            _gif_warn(gif_ptr, "The Gif File Doesn't have Trailer Tag!");

+                            return 1;

+                    }

+                }

+            case GIF_D_STATUS_EXT: {

+                    FX_LPBYTE ext_ptr = NULL;

+                    if(_gif_read_data(gif_ptr, &ext_ptr, 1) == NULL) {

+                        return 2;

+                    }

+                    switch(*ext_ptr) {

+#ifdef GIF_SUPPORT_APPLICATION_EXTENSION

+                        case GIF_BLOCK_AE:

+                            _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_AE);

+                            continue;

+#endif

+#ifdef GIF_SUPPORT_COMMENT_EXTENSION

+                        case GIF_BLOCK_CE:

+                            _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_CE);

+                            continue;

+#endif

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+                        case GIF_BLOCK_GCE:

+                            _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_GCE);

+                            continue;

+#endif

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+                        case GIF_BLOCK_PTE:

+                            _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_PTE);

+                            continue;

+#endif

+                        default: {

+                                FX_INT32 status = GIF_D_STATUS_EXT_UNE;

+#ifndef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+                                if(*ext_ptr == GIF_BLOCK_PTE) {

+                                    status = GIF_D_STATUS_EXT_PTE;

+                                }

+#endif

+                                _gif_save_decoding_status(gif_ptr, status);

+                                continue;

+                            }

+                    }

+                }

+            case GIF_D_STATUS_IMG_INFO: {

+                    ret = _gif_decode_image_info(gif_ptr);

+                    if(ret != 1) {

+                        return ret;

+                    }

+                    continue;

+                }

+            case GIF_D_STATUS_IMG_DATA: {

+                    FX_LPBYTE data_size_ptr = NULL;

+                    FX_LPBYTE data_ptr = NULL;

+                    FX_DWORD skip_size_org = gif_ptr->skip_size;

+                    if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                        return 2;

+                    }

+                    while(*data_size_ptr != GIF_BLOCK_TERMINAL) {

+                        if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) {

+                            gif_ptr->skip_size = skip_size_org;

+                            return 2;

+                        }

+                        _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);

+                        skip_size_org = gif_ptr->skip_size;

+                        if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                            return 2;

+                        }

+                    }

+                    _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG);

+                    continue;

+                }

+            default: {

+                    ret = _gif_decode_extension(gif_ptr);

+                    if(ret != 1) {

+                        return ret;

+                    }

+                    continue;

+                }

+        }

+    }

+    return 1;

+}

+void _gif_takeover_gce_ptr(gif_decompress_struct_p gif_ptr, GifGCE** gce_ptr_ptr)

+{

+    *gce_ptr_ptr = NULL;

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+    if(gif_ptr->gce_ptr != NULL && gce_ptr_ptr != NULL) {

+        *gce_ptr_ptr = gif_ptr->gce_ptr;

+        gif_ptr->gce_ptr = NULL;

+    }

+#endif

+}

+FX_INT32 _gif_decode_extension(gif_decompress_struct_p gif_ptr)

+{

+    FX_LPBYTE data_size_ptr = NULL;

+    FX_LPBYTE data_ptr = NULL;

+    FX_DWORD skip_size_org = gif_ptr->skip_size;

+    switch(gif_ptr->decode_status) {

+#ifdef GIF_SUPPORT_APPLICATION_EXTENSION

+        case GIF_D_STATUS_EXT_AE: {

+                ASSERT(sizeof(GifAE) == 12);

+                GifAE* gif_ae_ptr = NULL;

+                if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_ae_ptr, 12) == NULL) {

+                    return 2;

+                }

+                CFX_ByteString gif_ae_data_str;

+                if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                    gif_ptr->skip_size = skip_size_org;

+                    return 2;

+                }

+                while(*data_size_ptr != GIF_BLOCK_TERMINAL) {

+                    FX_BYTE data_size = *data_size_ptr;

+                    if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL ||

+                            _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                        gif_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                    gif_ae_data_str += CFX_ByteString((FX_LPCBYTE)data_ptr, data_size);

+                }

+                FXSYS_memcpy32(gif_ptr->app_identify, gif_ae_ptr->app_identify, 8);

+                FXSYS_memcpy32(gif_ptr->app_authentication, gif_ae_ptr->app_authentication, 3);

+                gif_ptr->app_data_size = gif_ae_data_str.GetLength();

+                if(gif_ptr->app_data != NULL) {

+                    FX_Free(gif_ptr->app_data);

+                    gif_ptr->app_data = NULL;

+                }

+                gif_ptr->app_data = FX_Alloc(FX_BYTE, gif_ptr->app_data_size);

+                GIF_PTR_NOT_NULL(gif_ptr->app_data, gif_ptr);

+                FXSYS_memcpy32(gif_ptr->app_data, FX_LPCBYTE(gif_ae_data_str), gif_ptr->app_data_size);

+            }

+            break;

+#endif

+#ifdef GIF_SUPPORT_COMMENT_EXTENSION

+        case GIF_D_STATUS_EXT_CE: {

+                if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                    gif_ptr->skip_size = skip_size_org;

+                    return 2;

+                }

+                gif_ptr->cmt_data_ptr->Empty();

+                while(*data_size_ptr != GIF_BLOCK_TERMINAL) {

+                    FX_BYTE data_size = *data_size_ptr;

+                    if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL ||

+                            _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                        gif_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                    *(gif_ptr->cmt_data_ptr) += CFX_ByteString((FX_LPCSTR)data_ptr, data_size);

+                }

+            }

+            break;

+#endif

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+        case GIF_D_STATUS_EXT_PTE: {

+                ASSERT(sizeof(GifPTE) == 13);

+                GifPTE* gif_pte_ptr = NULL;

+                if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_pte_ptr, 13) == NULL) {

+                    return 2;

+                }

+                GifPlainText* gif_pt_ptr = FX_Alloc(GifPlainText, 1);

+                GIF_PTR_NOT_NULL(gif_pt_ptr, gif_ptr);

+                FXSYS_memset32(gif_pt_ptr, 0, sizeof(GifPlainText));

+                _gif_takeover_gce_ptr(gif_ptr, &gif_pt_ptr->gce_ptr);

+                gif_pt_ptr->pte_ptr = (GifPTE*)FX_Alloc(FX_BYTE, sizeof(GifPTE));

+                GIF_PTR_NOT_NULL(gif_pt_ptr->pte_ptr, gif_ptr);

+                gif_pt_ptr->string_ptr = FX_NEW CFX_ByteString;

+                GIF_PTR_NOT_NULL(gif_pt_ptr->string_ptr, gif_ptr);

+                gif_pt_ptr->pte_ptr->block_size = gif_pte_ptr->block_size;

+                gif_pt_ptr->pte_ptr->grid_left = _GetWord_LSBFirst((FX_LPBYTE)&gif_pte_ptr->grid_left);

+                gif_pt_ptr->pte_ptr->grid_top = _GetWord_LSBFirst((FX_LPBYTE)&gif_pte_ptr->grid_top);

+                gif_pt_ptr->pte_ptr->grid_width = _GetWord_LSBFirst((FX_LPBYTE)&gif_pte_ptr->grid_width);

+                gif_pt_ptr->pte_ptr->grid_height = _GetWord_LSBFirst((FX_LPBYTE)&gif_pte_ptr->grid_height);

+                gif_pt_ptr->pte_ptr->char_width = gif_pte_ptr->char_width;

+                gif_pt_ptr->pte_ptr->char_height = gif_pte_ptr->char_height;

+                gif_pt_ptr->pte_ptr->fc_index = gif_pte_ptr->fc_index;

+                gif_pt_ptr->pte_ptr->bc_index = gif_pte_ptr->bc_index;

+                if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                    gif_ptr->skip_size = skip_size_org;

+                    if(gif_pt_ptr != NULL) {

+                        if(gif_pt_ptr->gce_ptr != NULL) {

+                            FX_Free(gif_pt_ptr->gce_ptr);

+                        }

+                        if(gif_pt_ptr->pte_ptr != NULL) {

+                            FX_Free(gif_pt_ptr->pte_ptr);

+                        }

+                        if(gif_pt_ptr->string_ptr != NULL) {

+                            delete gif_pt_ptr->string_ptr;

+                        }

+                        FX_Free(gif_pt_ptr);

+                    }

+                    return 2;

+                }

+                while(*data_size_ptr != GIF_BLOCK_TERMINAL) {

+                    FX_BYTE data_size = *data_size_ptr;

+                    if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL ||

+                            _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                        gif_ptr->skip_size = skip_size_org;

+                        if(gif_pt_ptr != NULL) {

+                            if(gif_pt_ptr->gce_ptr != NULL) {

+                                FX_Free(gif_pt_ptr->gce_ptr);

+                            }

+                            if(gif_pt_ptr->pte_ptr != NULL) {

+                                FX_Free(gif_pt_ptr->pte_ptr);

+                            }

+                            if(gif_pt_ptr->string_ptr != NULL) {

+                                delete gif_pt_ptr->string_ptr;

+                            }

+                            FX_Free(gif_pt_ptr);

+                        }

+                        return 2;

+                    }

+                    *(gif_pt_ptr->string_ptr) += CFX_ByteString((FX_LPCSTR)data_ptr, data_size);

+                }

+                gif_ptr->pt_ptr_arr_ptr->Add(gif_pt_ptr);

+            }

+            break;

+#endif

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+        case GIF_D_STATUS_EXT_GCE: {

+                ASSERT(sizeof(GifGCE) == 5);

+                GifGCE* gif_gce_ptr = NULL;

+                if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_gce_ptr, 6) == NULL) {

+                    return 2;

+                }

+                if(gif_ptr->gce_ptr == NULL) {

+                    gif_ptr->gce_ptr = (GifGCE*)FX_Alloc(FX_BYTE, sizeof(GifGCE));

+                    GIF_PTR_NOT_NULL(gif_ptr->gce_ptr, gif_ptr);

+                }

+                gif_ptr->gce_ptr->block_size = gif_gce_ptr->block_size;

+                gif_ptr->gce_ptr->gce_flag = gif_gce_ptr->gce_flag;

+                gif_ptr->gce_ptr->delay_time = _GetWord_LSBFirst((FX_LPBYTE)&gif_gce_ptr->delay_time);

+                gif_ptr->gce_ptr->trans_index = gif_gce_ptr->trans_index;

+            }

+            break;

+#endif

+        default: {

+#ifndef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+                if(gif_ptr->decode_status == GIF_D_STATUS_EXT_PTE) {

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+                    if(gif_ptr->gce_ptr != NULL) {

+                        FX_Free(gif_ptr->gce_ptr);

+                        gif_ptr->gce_ptr = NULL;

+                    }

+#endif

+                }

+#endif

+                if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                    return 2;

+                }

+                while(*data_size_ptr != GIF_BLOCK_TERMINAL) {

+                    if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL ||

+                            _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL ) {

+                        gif_ptr->skip_size = skip_size_org;

+                        return 2;

+                    }

+                }

+            }

+    }

+    _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG);

+    return 1;

+}

+FX_INT32 _gif_decode_image_info(gif_decompress_struct_p gif_ptr)

+{

+    if(gif_ptr->width == 0 || gif_ptr->height == 0) {

+        _gif_error(gif_ptr, "No Image Header Info");

+        return 0;

+    }

+    FX_DWORD skip_size_org = gif_ptr->skip_size;

+    ASSERT(sizeof(GifImageInfo) == 9);

+    GifImageInfo* gif_img_info_ptr = NULL;

+    if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_img_info_ptr, 9) == NULL) {

+        return 2;

+    }

+    GifImage* gif_image_ptr = (GifImage*)FX_Alloc(FX_BYTE, sizeof(GifImage));

+    GIF_PTR_NOT_NULL(gif_image_ptr, gif_ptr);

+    FXSYS_memset32(gif_image_ptr, 0, sizeof(GifImage));

+    gif_image_ptr->image_info_ptr = (GifImageInfo*)FX_Alloc(FX_BYTE, sizeof(GifImageInfo));

+    GIF_PTR_NOT_NULL(gif_image_ptr->image_info_ptr, gif_ptr);

+    gif_image_ptr->image_info_ptr->left = _GetWord_LSBFirst((FX_LPBYTE)&gif_img_info_ptr->left);

+    gif_image_ptr->image_info_ptr->top = _GetWord_LSBFirst((FX_LPBYTE)&gif_img_info_ptr->top);

+    gif_image_ptr->image_info_ptr->width = _GetWord_LSBFirst((FX_LPBYTE)&gif_img_info_ptr->width);

+    gif_image_ptr->image_info_ptr->height = _GetWord_LSBFirst((FX_LPBYTE)&gif_img_info_ptr->height);

+    gif_image_ptr->image_info_ptr->local_flag = gif_img_info_ptr->local_flag;

+    if(gif_image_ptr->image_info_ptr->left + gif_image_ptr->image_info_ptr->width > gif_ptr->width ||

+            gif_image_ptr->image_info_ptr->top + gif_image_ptr->image_info_ptr->height > gif_ptr->height) {

+        if(gif_image_ptr->image_info_ptr != NULL) {

+            FX_Free(gif_image_ptr->image_info_ptr);

+        }

+        if(gif_image_ptr->image_row_buf != NULL) {

+            FX_Free(gif_image_ptr->image_row_buf);

+        }

+        FX_Free(gif_image_ptr);

+        _gif_error(gif_ptr, "Image Data Out Of LSD, The File May Be Corrupt");

+        return 0;

+    }

+    GifLF* gif_img_info_lf_ptr = (GifLF*)&gif_img_info_ptr->local_flag;

+    if(gif_img_info_lf_ptr->local_pal) {

+        ASSERT(sizeof(GifPalette) == 3);

+        FX_INT32 loc_pal_size = (2 << gif_img_info_lf_ptr->pal_bits) * 3;

+        FX_LPBYTE loc_pal_ptr = NULL;

+        if(_gif_read_data(gif_ptr, &loc_pal_ptr, loc_pal_size) == NULL) {

+            gif_ptr->skip_size = skip_size_org;

+            if(gif_image_ptr->image_info_ptr != NULL) {

+                FX_Free(gif_image_ptr->image_info_ptr);

+            }

+            if(gif_image_ptr->image_row_buf != NULL) {

+                FX_Free(gif_image_ptr->image_row_buf);

+            }

+            FX_Free(gif_image_ptr);

+            return 2;

+        }

+        gif_image_ptr->local_pal_ptr = (GifPalette*)gif_ptr->_gif_ask_buf_for_pal_fn(gif_ptr, loc_pal_size);

+        if(gif_image_ptr->local_pal_ptr != NULL) {

+            FXSYS_memcpy32((FX_LPBYTE)gif_image_ptr->local_pal_ptr, loc_pal_ptr, loc_pal_size);

+        }

+    }

+    FX_LPBYTE code_size_ptr = NULL;

+    if(_gif_read_data(gif_ptr, &code_size_ptr, 1) == NULL) {

+        gif_ptr->skip_size = skip_size_org;

+        if(gif_image_ptr->image_info_ptr != NULL) {

+            FX_Free(gif_image_ptr->image_info_ptr);

+        }

+        if(gif_image_ptr->local_pal_ptr != NULL) {

+            FX_Free(gif_image_ptr->local_pal_ptr);

+        }

+        if(gif_image_ptr->image_row_buf != NULL) {

+            FX_Free(gif_image_ptr->image_row_buf);

+        }

+        FX_Free(gif_image_ptr);

+        return 2;

+    }

+    gif_image_ptr->image_code_size = *code_size_ptr;

+    gif_ptr->_gif_record_current_position_fn(gif_ptr, &gif_image_ptr->image_data_pos);

+    gif_image_ptr->image_data_pos += gif_ptr->skip_size;

+    _gif_takeover_gce_ptr(gif_ptr, &gif_image_ptr->image_gce_ptr);

+    gif_ptr->img_ptr_arr_ptr->Add(gif_image_ptr);

+    _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);

+    return 1;

+}

+FX_INT32 _gif_load_frame(gif_decompress_struct_p gif_ptr, FX_INT32 frame_num)

+{

+    if(gif_ptr == NULL ||

+            frame_num < 0 ||

+            frame_num >= gif_ptr->img_ptr_arr_ptr->GetSize()

+      ) {

+        return 0;

+    }

+    FX_LPBYTE data_size_ptr = NULL;

+    FX_LPBYTE data_ptr = NULL;

+    FX_DWORD skip_size_org = gif_ptr->skip_size;

+    GifImage* gif_image_ptr = gif_ptr->img_ptr_arr_ptr->GetAt(frame_num);

+    FX_DWORD gif_img_row_bytes = gif_image_ptr->image_info_ptr->width;

+    if(gif_ptr->decode_status == GIF_D_STATUS_TAIL) {

+        if(gif_image_ptr->image_row_buf) {

+            FX_Free(gif_image_ptr->image_row_buf);

+            gif_image_ptr->image_row_buf = NULL;

+        }

+        gif_image_ptr->image_row_buf = FX_Alloc(FX_BYTE, gif_img_row_bytes);

+        GIF_PTR_NOT_NULL(gif_image_ptr->image_row_buf, gif_ptr);

+        GifGCE* gif_img_gce_ptr = gif_image_ptr->image_gce_ptr;

+        FX_INT32 loc_pal_num = ((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->local_pal ?

+                               (2 << ((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->pal_bits) : 0;

+        gif_ptr->avail_in = 0;

+        if(gif_img_gce_ptr == NULL) {

+            FX_BOOL bRes = gif_ptr->_gif_get_record_position_fn(gif_ptr, gif_image_ptr->image_data_pos,

+                           gif_image_ptr->image_info_ptr->left,

+                           gif_image_ptr->image_info_ptr->top,

+                           gif_image_ptr->image_info_ptr->width,

+                           gif_image_ptr->image_info_ptr->height,

+                           loc_pal_num, gif_image_ptr->local_pal_ptr,

+                           0, 0, -1, 0,

+                           (FX_BOOL)((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->interlace

+                                                               );

+            if(!bRes) {

+                FX_Free(gif_image_ptr->image_row_buf);

+                gif_image_ptr->image_row_buf = NULL;

+                _gif_error(gif_ptr, "Error Read Record Position Data");

+                return 0;

+            }

+        } else {

+            FX_BOOL bRes = gif_ptr->_gif_get_record_position_fn(gif_ptr, gif_image_ptr->image_data_pos,

+                           gif_image_ptr->image_info_ptr->left,

+                           gif_image_ptr->image_info_ptr->top,

+                           gif_image_ptr->image_info_ptr->width,

+                           gif_image_ptr->image_info_ptr->height,

+                           loc_pal_num, gif_image_ptr->local_pal_ptr,

+                           (FX_INT32)gif_image_ptr->image_gce_ptr->delay_time,

+                           (FX_BOOL)((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)->user_input,

+                           ((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)->transparency ?

+                           (FX_INT32)gif_image_ptr->image_gce_ptr->trans_index : -1,

+                           (FX_INT32)((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)->disposal_method,

+                           (FX_BOOL)((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->interlace

+                                                               );

+            if(!bRes) {

+                FX_Free(gif_image_ptr->image_row_buf);

+                gif_image_ptr->image_row_buf = NULL;

+                _gif_error(gif_ptr, "Error Read Record Position Data");

+                return 0;

+            }

+        }

+        if(gif_ptr->img_decoder_ptr == NULL) {

+            gif_ptr->img_decoder_ptr = FX_NEW CGifLZWDecoder(gif_ptr->err_ptr);

+            GIF_PTR_NOT_NULL(gif_ptr->img_decoder_ptr, gif_ptr);

+        }

+        gif_ptr->img_decoder_ptr->InitTable(gif_image_ptr->image_code_size);

+        gif_ptr->img_row_offset = 0;

+        gif_ptr->img_row_avail_size = 0;

+        gif_ptr->img_pass_num = 0;

+        gif_image_ptr->image_row_num = 0;

+        _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);

+    }

+    CGifLZWDecoder* img_decoder_ptr = gif_ptr->img_decoder_ptr;

+    if(gif_ptr->decode_status == GIF_D_STATUS_IMG_DATA) {

+        if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+            return 2;

+        }

+        if(*data_size_ptr != GIF_BLOCK_TERMINAL) {

+            if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) {

+                gif_ptr->skip_size = skip_size_org;

+                return 2;

+            }

+            img_decoder_ptr->Input(data_ptr, *data_size_ptr);

+            _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);

+            gif_ptr->img_row_offset += gif_ptr->img_row_avail_size;

+            gif_ptr->img_row_avail_size = gif_img_row_bytes - gif_ptr->img_row_offset;

+            FX_INT32 ret = img_decoder_ptr->Decode(gif_image_ptr->image_row_buf + gif_ptr->img_row_offset, gif_ptr->img_row_avail_size);

+            if(ret == 0) {

+                FX_Free(gif_image_ptr->image_row_buf);

+                gif_image_ptr->image_row_buf = NULL;

+                _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);

+                _gif_error(gif_ptr, "Decode Image Data Error");

+                return 0;

+            }

+            while (ret != 0) {

+                if(ret == 1) {

+                    gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num, gif_image_ptr->image_row_buf);

+                    FX_Free(gif_image_ptr->image_row_buf);

+                    gif_image_ptr->image_row_buf = NULL;

+                    _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);

+                    return 1;

+                }

+                if(ret == 2) {

+                    ASSERT(img_decoder_ptr->GetAvailInput() == 0);

+                    skip_size_org = gif_ptr->skip_size;

+                    if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {

+                        return 2;

+                    }

+                    if (*data_size_ptr != GIF_BLOCK_TERMINAL) {

+                        if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) {

+                            gif_ptr->skip_size = skip_size_org;

+                            return 2;

+                        }

+                        img_decoder_ptr->Input(data_ptr, *data_size_ptr);

+                        _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);

+                        gif_ptr->img_row_offset += gif_ptr->img_row_avail_size;

+                        gif_ptr->img_row_avail_size = gif_img_row_bytes - gif_ptr->img_row_offset;

+                        ret = img_decoder_ptr->Decode(gif_image_ptr->image_row_buf + gif_ptr->img_row_offset, gif_ptr->img_row_avail_size);

+                    }

+                }

+                if(ret == 3) {

+                    if(((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->interlace) {

+                        gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num, gif_image_ptr->image_row_buf);

+                        gif_image_ptr->image_row_num += s_gif_interlace_step[gif_ptr->img_pass_num];

+                        if(gif_image_ptr->image_row_num >= (FX_INT32)gif_image_ptr->image_info_ptr->height) {

+                            gif_ptr->img_pass_num++;

+                            gif_image_ptr->image_row_num = s_gif_interlace_step[gif_ptr->img_pass_num] / 2;

+                        }

+                    } else {

+                        gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num++, gif_image_ptr->image_row_buf);

+                    }

+                    gif_ptr->img_row_offset = 0;

+                    gif_ptr->img_row_avail_size = gif_img_row_bytes;

+                    ret = img_decoder_ptr->Decode(gif_image_ptr->image_row_buf + gif_ptr->img_row_offset, gif_ptr->img_row_avail_size);

+                }

+                if(ret == 0) {

+                    FX_Free(gif_image_ptr->image_row_buf);

+                    gif_image_ptr->image_row_buf = NULL;

+                    _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);

+                    _gif_error(gif_ptr, "Decode Image Data Error");

+                    return 0;

+                }

+            }

+        }

+        _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);

+    }

+    _gif_error(gif_ptr, "Decode Image Data Error");

+    return 0;

+}

+void _gif_save_decoding_status(gif_decompress_struct_p gif_ptr, FX_INT32 status)

+{

+    gif_ptr->decode_status = status;

+    gif_ptr->next_in += gif_ptr->skip_size;

+    gif_ptr->avail_in -= gif_ptr->skip_size;

+    gif_ptr->skip_size = 0;

+}

+FX_LPBYTE _gif_read_data(gif_decompress_struct_p gif_ptr, FX_LPBYTE* des_buf_pp, FX_DWORD data_size)

+{

+    if(gif_ptr == NULL ||

+            gif_ptr->avail_in < gif_ptr->skip_size + data_size) {

+        return NULL;

+    }

+    *des_buf_pp = gif_ptr->next_in + gif_ptr->skip_size;

+    gif_ptr->skip_size += data_size;

+    return *des_buf_pp;

+}

+void _gif_input_buffer(gif_decompress_struct_p gif_ptr, FX_LPBYTE src_buf, FX_DWORD src_size)

+{

+    gif_ptr->next_in = src_buf;

+    gif_ptr->avail_in = src_size;

+    gif_ptr->skip_size = 0;

+}

+FX_DWORD _gif_get_avail_input(gif_decompress_struct_p gif_ptr, FX_LPBYTE* avial_buf_ptr)

+{

+    if(avial_buf_ptr != NULL) {

+        *avial_buf_ptr = NULL;

+        if(gif_ptr->avail_in > 0) {

+            *avial_buf_ptr = gif_ptr->next_in;

+        }

+    }

+    return gif_ptr->avail_in;

+}

+FX_INT32 _gif_get_frame_num(gif_decompress_struct_p gif_ptr)

+{

+    return gif_ptr->img_ptr_arr_ptr->GetSize();

+}

+static FX_BOOL _gif_write_header( gif_compress_struct_p gif_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_len )

+{

+    if (gif_ptr->cur_offset) {

+        return TRUE;

+    }

+    dst_len = sizeof(GifHeader) + sizeof(GifLSD) + sizeof(GifGF);

+    dst_buf = FX_AllocNL(FX_BYTE, dst_len);

+    if (dst_buf == NULL)	{

+        return FALSE;

+    }

+    FXSYS_memset32(dst_buf, 0, dst_len);

+    FXSYS_memcpy32(dst_buf, gif_ptr->header_ptr, sizeof(GifHeader));

+    gif_ptr->cur_offset += sizeof(GifHeader);

+    _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->lsd_ptr->width);

+    gif_ptr->cur_offset += 2;

+    _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->lsd_ptr->height);

+    gif_ptr->cur_offset += 2;

+    dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->global_flag;

+    dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->bc_index;

+    dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->pixel_aspect;

+    if (gif_ptr->global_pal) {

+        FX_WORD size = sizeof(GifPalette) * gif_ptr->gpal_num;

+        if (!_gif_grow_buf(dst_buf, dst_len, gif_ptr->cur_offset + size)) {

+            return FALSE;

+        }

+        FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->global_pal, size);

+        gif_ptr->cur_offset += size;

+    }

+    return TRUE;

+}

+void interlace_buf(FX_LPCBYTE buf, FX_DWORD pitch, FX_DWORD height)

+{

+    CFX_ArrayTemplate<FX_LPBYTE> pass[4];

+    int i, j;

+    FX_DWORD row;

+    row = 0;

+    FX_LPBYTE temp;

+    while (row < height) {

+        if (row % 8 == 0) {

+            j = 0;

+        } else if (row % 4 == 0) {

+            j = 1;

+        } else if (row % 2 == 0) {

+            j = 2;

+        } else {

+            j = 3;

+        }

+        temp = FX_Alloc(FX_BYTE, pitch);

+        if (temp == NULL) {

+            return;

+        }

+        FXSYS_memcpy32(temp, &buf[pitch * row], pitch);

+        pass[j].Add(temp);

+        row ++;

+    }

+    for (i = 0, row = 0; i < 4; i++) {

+        for (j = 0; j < pass[i].GetSize(); j++, row++) {

+            FXSYS_memcpy32((FX_LPBYTE)&buf[pitch * row], pass[i].GetAt(j), pitch);

+            FX_Free(pass[i].GetAt(j));

+        }

+    }

+}

+static void _gif_write_block_data(FX_LPCBYTE src_buf, FX_DWORD src_len, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& dst_offset)

+{

+    FX_DWORD src_offset = 0;

+    while (src_len > GIF_DATA_BLOCK) {

+        dst_buf[dst_offset++] = GIF_DATA_BLOCK;

+        FXSYS_memcpy32(&dst_buf[dst_offset], &src_buf[src_offset], GIF_DATA_BLOCK);

+        dst_offset += GIF_DATA_BLOCK;

+        src_offset += GIF_DATA_BLOCK;

+        src_len -= GIF_DATA_BLOCK;

+    }

+    dst_buf[dst_offset++] = (FX_BYTE)src_len;

+    FXSYS_memcpy32(&dst_buf[dst_offset], &src_buf[src_offset], src_len);

+    dst_offset += src_len;

+}

+static FX_BOOL _gif_write_data( gif_compress_struct_p gif_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_len )

+{

+    if (!_gif_grow_buf(dst_buf, dst_len, gif_ptr->cur_offset + GIF_DATA_BLOCK)) {

+        return FALSE;

+    }

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+    if (FXSYS_memcmp32(gif_ptr->header_ptr->version, "89a", 3) == 0) {

+        dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION;

+        dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_GCE;

+        gif_ptr->gce_ptr->block_size = 4;

+        dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->block_size;

+        gif_ptr->gce_ptr->gce_flag = 0;

+        dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->gce_flag;

+        gif_ptr->gce_ptr->delay_time = 10;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->gce_ptr->delay_time);

+        gif_ptr->cur_offset += 2;

+        gif_ptr->gce_ptr->trans_index = 0;

+        dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->trans_index;

+        dst_buf[gif_ptr->cur_offset++] = 0;

+    }

+#endif

+    dst_buf[gif_ptr->cur_offset++] = GIF_SIG_IMAGE;

+    _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->image_info_ptr->left);

+    gif_ptr->cur_offset += 2;

+    _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->image_info_ptr->top);

+    gif_ptr->cur_offset += 2;

+    _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->image_info_ptr->width);

+    gif_ptr->cur_offset += 2;

+    _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->image_info_ptr->height);

+    gif_ptr->cur_offset += 2;

+    GifLF& lf = (GifLF&)gif_ptr->image_info_ptr->local_flag;

+    dst_buf[gif_ptr->cur_offset++] = gif_ptr->image_info_ptr->local_flag;

+    if (gif_ptr->local_pal) {

+        FX_DWORD pal_size = sizeof(GifPalette) * gif_ptr->lpal_num;

+        if (!_gif_grow_buf(dst_buf, dst_len, pal_size + gif_ptr->cur_offset)) {

+            return FALSE;

+        }

+        FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->local_pal, pal_size);

+        gif_ptr->cur_offset += pal_size;

+    }

+    if (lf.interlace) {

+        interlace_buf(gif_ptr->src_buf, gif_ptr->src_pitch, gif_ptr->image_info_ptr->height);

+    }

+    FX_BYTE code_bit = lf.pal_bits;

+    if (lf.local_pal == 0) {

+        GifGF& gf = (GifGF&)gif_ptr->lsd_ptr->global_flag;

+        code_bit = gf.pal_bits;

+    }

+    gif_ptr->img_encoder_ptr->Start(code_bit, gif_ptr->src_buf, dst_buf, gif_ptr->cur_offset);

+    FX_DWORD i;

+    for (i = 0; i < gif_ptr->src_row; i++) {

+        if (!gif_ptr->img_encoder_ptr->Encode(&gif_ptr->src_buf[i * gif_ptr->src_pitch], gif_ptr->src_width * (code_bit + 1),

+                                              dst_buf, dst_len, gif_ptr->cur_offset)) {

+            return FALSE;

+        }

+    }

+    gif_ptr->img_encoder_ptr->Finish(dst_buf, dst_len, gif_ptr->cur_offset);

+    dst_buf[gif_ptr->cur_offset++] = 0;

+#ifdef GIF_SUPPORT_COMMENT_EXTENSION

+    if (FXSYS_memcmp32(gif_ptr->header_ptr->version, "89a", 3) == 0 && gif_ptr->cmt_data_ptr) {

+        dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION;

+        dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_CE;

+        _gif_write_block_data(gif_ptr->cmt_data_ptr, gif_ptr->cmt_data_len, dst_buf, dst_len, gif_ptr->cur_offset);

+        dst_buf[gif_ptr->cur_offset++] = 0;

+    }

+#endif

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+    if (FXSYS_memcmp32(gif_ptr->header_ptr->version, "89a", 3) == 0 && gif_ptr->pte_data_ptr) {

+        dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION;

+        dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_PTE;

+        dst_buf[gif_ptr->cur_offset++] = gif_ptr->pte_ptr->block_size;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->grid_left);

+        gif_ptr->cur_offset += 2;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->grid_top);

+        gif_ptr->cur_offset += 2;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->grid_width);

+        gif_ptr->cur_offset += 2;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->grid_height);

+        gif_ptr->cur_offset += 2;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->char_width);

+        gif_ptr->cur_offset += 2;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->char_height);

+        gif_ptr->cur_offset += 2;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->fc_index);

+        gif_ptr->cur_offset += 2;

+        _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->bc_index);

+        gif_ptr->cur_offset += 2;

+        _gif_write_block_data(gif_ptr->pte_data_ptr, gif_ptr->pte_data_len, dst_buf, dst_len, gif_ptr->cur_offset);

+        gif_ptr->cur_offset += gif_ptr->pte_data_len;

+        dst_buf[gif_ptr->cur_offset++] = 0;

+    }

+#endif

+#ifdef GIF_SUPPORT_APPLICATION_EXTENSION

+    if (FXSYS_memcmp32(gif_ptr->header_ptr->version, "89a", 3) == 0 && gif_ptr->app_data) {

+        dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION;

+        dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_AE;

+        dst_buf[gif_ptr->cur_offset++] = 11;

+        FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_identify, 8);

+        gif_ptr->cur_offset += 8;

+        FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_authentication, 8);

+        gif_ptr->cur_offset += 3;

+        FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_data, gif_ptr->app_data_size);

+        gif_ptr->cur_offset += gif_ptr->app_data_size;

+        dst_buf[gif_ptr->cur_offset++] = 0;

+    }

+#endif

+    dst_buf[gif_ptr->cur_offset++] = GIF_SIG_TRAILER;

+    return TRUE;

+}

+FX_BOOL _gif_encode( gif_compress_struct_p gif_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_len )

+{

+    if (!_gif_write_header(gif_ptr, dst_buf, dst_len)) {

+        return FALSE;

+    }

+    FX_DWORD cur_offset = gif_ptr->cur_offset;

+    FX_BOOL res = TRUE;

+    if (gif_ptr->frames) {

+        gif_ptr->cur_offset--;

+    }

+    if (!_gif_write_data(gif_ptr, dst_buf, dst_len)) {

+        gif_ptr->cur_offset = cur_offset;

+        res = FALSE;

+    }

+    dst_len = gif_ptr->cur_offset;

+    dst_buf[dst_len - 1] = GIF_SIG_TRAILER;

+    if (res) {

+        gif_ptr->frames++;

+    }

+    return res;

+}

diff --git a/core/src/fxcodec/lgif/fx_gif.h b/core/src/fxcodec/lgif/fx_gif.h
new file mode 100644
index 0000000..b499a54
--- /dev/null
+++ b/core/src/fxcodec/lgif/fx_gif.h
@@ -0,0 +1,307 @@
+// Copyright 2014 PDFium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

+

+#ifndef _FX_BASIC_H_

+#include "../../../include/fxcrt/fx_basic.h"

+#endif

+extern FX_WORD _GetWord_LSBFirst(FX_LPBYTE p);

+extern void _SetWord_LSBFirst(FX_LPBYTE p, FX_WORD v);

+extern void _BpcConvert(FX_LPCBYTE src_buf, FX_DWORD src_len, FX_INT32 src_bpc, FX_INT32 dst_bpc,

+                        FX_LPBYTE& dst_buf, FX_DWORD& dst_len);

+#define GIF_SUPPORT_COMMENT_EXTENSION

+#define GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+#define GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+#define GIF_SIGNATURE		"GIF"

+#define GIF_SIG_EXTENSION	0x21

+#define GIF_SIG_IMAGE		0x2C

+#define GIF_SIG_TRAILER		0x3B

+#define GIF_BLOCK_GCE		0xF9

+#define GIF_BLOCK_PTE		0x01

+#define GIF_BLOCK_CE		0xFE

+#define GIF_BLOCK_AE		0xFF

+#define GIF_BLOCK_TERMINAL	0x00

+#define GIF_MAX_LZW_CODE	4096

+#define GIF_DATA_BLOCK		255

+#define GIF_MAX_ERROR_SIZE	256

+#define GIF_D_STATUS_SIG		0x01

+#define GIF_D_STATUS_TAIL		0x02

+#define GIF_D_STATUS_EXT		0x03

+#define GIF_D_STATUS_EXT_AE		0x04

+#define GIF_D_STATUS_EXT_CE		0x05

+#define GIF_D_STATUS_EXT_GCE	0x06

+#define GIF_D_STATUS_EXT_PTE	0x07

+#define GIF_D_STATUS_EXT_UNE	0x08

+#define GIF_D_STATUS_IMG_INFO	0x09

+#define GIF_D_STATUS_IMG_DATA	0x0A

+#pragma pack(1)

+typedef struct tagGifGF {

+    FX_BYTE pal_bits : 3;

+    FX_BYTE sort_flag : 1;

+    FX_BYTE color_resolution : 3;

+    FX_BYTE global_pal : 1;

+} GifGF;

+typedef struct tagGifLF {

+    FX_BYTE pal_bits : 3;

+    FX_BYTE reserved : 2;

+    FX_BYTE sort_flag : 1;

+    FX_BYTE interlace : 1;

+    FX_BYTE local_pal : 1;

+} GifLF;

+typedef struct tagGifHeader {

+    char signature[3];

+    char version[3];

+} GifHeader;

+typedef struct tagGifLSD {

+    FX_WORD	width;

+    FX_WORD height;

+    FX_BYTE	global_flag;

+    FX_BYTE bc_index;

+    FX_BYTE	pixel_aspect;

+} GifLSD;

+typedef struct tagGifImageInfo {

+    FX_WORD left;

+    FX_WORD top;

+    FX_WORD width;

+    FX_WORD height;

+

+    FX_BYTE	local_flag;

+} GifImageInfo;

+typedef struct tagGifCEF {

+    FX_BYTE transparency : 1;

+    FX_BYTE user_input : 1;

+    FX_BYTE disposal_method : 3;

+    FX_BYTE reserved : 3;

+} GifCEF;

+typedef struct tagGifGCE {

+    FX_BYTE block_size;

+    FX_BYTE	gce_flag;

+    FX_WORD delay_time;

+    FX_BYTE	trans_index;

+} GifGCE;

+typedef struct tagGifPTE {

+    FX_BYTE block_size;

+    FX_WORD	grid_left;

+    FX_WORD	grid_top;

+    FX_WORD grid_width;

+    FX_WORD	grid_height;

+

+    FX_BYTE char_width;

+    FX_BYTE char_height;

+

+    FX_BYTE fc_index;

+    FX_BYTE bc_index;

+} GifPTE;

+typedef struct tagGifAE {

+    FX_BYTE block_size;

+    FX_BYTE app_identify[8];

+    FX_BYTE	app_authentication[3];

+} GifAE;

+typedef struct tagGifPalette {

+    FX_BYTE r, g, b;

+} GifPalette;

+#pragma pack()

+typedef struct tagGifImage {

+    GifGCE*			image_gce_ptr;

+    GifPalette*		local_pal_ptr;

+    GifImageInfo*	image_info_ptr;

+    FX_BYTE			image_code_size;

+    FX_DWORD		image_data_pos;

+    FX_LPBYTE		image_row_buf;

+    FX_INT32		image_row_num;

+} GifImage;

+typedef struct tagGifPlainText {

+    GifGCE*			gce_ptr;

+    GifPTE*			pte_ptr;

+    CFX_ByteString* string_ptr;

+} GifPlainText;

+class CGifLZWDecoder : public CFX_Object

+{

+public:

+    struct tag_Table {

+        FX_WORD prefix;

+        FX_BYTE suffix;

+    };

+    CGifLZWDecoder(FX_LPSTR error_ptr = NULL)

+    {

+        err_msg_ptr = error_ptr;

+    }

+    void		InitTable(FX_BYTE code_len);

+

+    FX_INT32	Decode(FX_LPBYTE des_buf, FX_DWORD& des_size);

+

+    void		Input(FX_LPBYTE src_buf, FX_DWORD src_size);

+    FX_DWORD	GetAvailInput();

+

+private:

+    void		ClearTable();

+    void		AddCode(FX_WORD prefix_code, FX_BYTE append_char);

+    void		DecodeString(FX_WORD code);

+    FX_BYTE		code_size;

+    FX_BYTE		code_size_cur;

+    FX_WORD		code_clear;

+    FX_WORD		code_end;

+    FX_WORD		code_next;

+    FX_BYTE		code_first;

+    FX_BYTE		stack[GIF_MAX_LZW_CODE];

+    FX_WORD		stack_size;

+    tag_Table	code_table[GIF_MAX_LZW_CODE];

+    FX_WORD		code_old;

+

+    FX_LPBYTE	next_in;

+    FX_DWORD	avail_in;

+

+    FX_BYTE		bits_left;

+    FX_DWORD	code_store;

+

+    FX_LPSTR	err_msg_ptr;

+};

+class CGifLZWEncoder : public CFX_Object

+{

+public:

+    struct tag_Table {

+        FX_WORD		prefix;

+        FX_BYTE		suffix;

+    };

+    CGifLZWEncoder();

+    ~CGifLZWEncoder();

+    void		Start(FX_BYTE code_len, FX_LPCBYTE src_buf, FX_LPBYTE& dst_buf, FX_DWORD& offset);

+    FX_BOOL		Encode(FX_LPCBYTE src_buf, FX_DWORD src_len, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset);

+    void		Finish(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset);

+private:

+    void		ClearTable();

+    FX_BOOL		LookUpInTable(FX_LPCBYTE buf, FX_DWORD& offset, FX_BYTE& bit_offset);

+    void		EncodeString(FX_DWORD index, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset);

+    void		WriteBlock(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset);

+    jmp_buf		jmp;

+    FX_DWORD	src_offset;

+    FX_BYTE		src_bit_offset;

+    FX_BYTE		src_bit_cut;

+    FX_DWORD	src_bit_num;

+    FX_BYTE		code_size;

+    FX_WORD		code_clear;

+    FX_WORD		code_end;

+    FX_WORD		index_num;

+    FX_BYTE		bit_offset;

+    FX_BYTE		index_bit_cur;

+    FX_BYTE		index_buf[GIF_DATA_BLOCK];

+    FX_BYTE		index_buf_len;

+    tag_Table	code_table[GIF_MAX_LZW_CODE];

+    FX_WORD		table_cur;

+};

+typedef struct tag_gif_decompress_struct gif_decompress_struct;

+typedef gif_decompress_struct *gif_decompress_struct_p;

+typedef gif_decompress_struct_p *gif_decompress_struct_pp;

+static FX_INT32 s_gif_interlace_step[4] = {8, 8, 4, 2};

+struct tag_gif_decompress_struct {

+    jmp_buf			jmpbuf;

+    FX_LPSTR		err_ptr;

+    void			(*_gif_error_fn)(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg);

+    void*			context_ptr;

+    int				width;

+    int				height;

+    GifPalette*		global_pal_ptr;

+    FX_INT32		global_pal_num;

+    FX_BYTE			global_sort_flag;

+    FX_BYTE			global_color_resolution;

+

+    FX_BYTE			bc_index;

+    FX_BYTE			pixel_aspect;

+    CGifLZWDecoder*	img_decoder_ptr;

+    FX_DWORD		img_row_offset;

+    FX_DWORD		img_row_avail_size;

+    FX_BYTE			img_pass_num;

+    CFX_ArrayTemplate<GifImage*>* img_ptr_arr_ptr;

+    FX_LPBYTE		(*_gif_ask_buf_for_pal_fn)(gif_decompress_struct_p gif_ptr, FX_INT32 pal_size);

+    FX_LPBYTE		next_in;

+    FX_DWORD		avail_in;

+    FX_INT32		decode_status;

+    FX_DWORD		skip_size;

+    void			(*_gif_record_current_position_fn)(gif_decompress_struct_p gif_ptr, FX_DWORD* cur_pos_ptr);

+    void			(*_gif_get_row_fn)(gif_decompress_struct_p gif_ptr, FX_INT32 row_num, FX_LPBYTE row_buf);

+    FX_BOOL			(*_gif_get_record_position_fn)(gif_decompress_struct_p gif_ptr, FX_DWORD cur_pos,

+            FX_INT32 left, FX_INT32 top, FX_INT32 width, FX_INT32 height,

+            FX_INT32 pal_num, void* pal_ptr,

+            FX_INT32 delay_time, FX_BOOL user_input,

+            FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace);

+#ifdef GIF_SUPPORT_APPLICATION_EXTENSION

+    FX_BYTE			app_identify[8];

+    FX_BYTE			app_authentication[3];

+    FX_DWORD		app_data_size;

+    FX_LPBYTE		app_data;

+#endif

+#ifdef GIF_SUPPORT_COMMENT_EXTENSION

+    CFX_ByteString*	cmt_data_ptr;

+#endif

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+    GifGCE*			gce_ptr;

+#endif

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+    CFX_ArrayTemplate<GifPlainText*>* pt_ptr_arr_ptr;

+#endif

+};

+typedef struct tag_gif_compress_struct gif_compress_struct;

+typedef gif_compress_struct *gif_compress_struct_p;

+typedef gif_compress_struct_p *gif_compress_struct_pp;

+struct tag_gif_compress_struct {

+    FX_LPCBYTE		src_buf;

+    FX_DWORD		src_pitch;

+    FX_DWORD		src_width;

+    FX_DWORD		src_row;

+    FX_DWORD		cur_offset;

+    FX_DWORD		frames;

+    GifHeader*		header_ptr;

+    GifLSD*			lsd_ptr;

+    GifPalette*		global_pal;

+    FX_WORD			gpal_num;

+    GifPalette*		local_pal;

+    FX_WORD			lpal_num;

+    GifImageInfo*	image_info_ptr;

+    CGifLZWEncoder* img_encoder_ptr;

+#ifdef GIF_SUPPORT_APPLICATION_EXTENSION

+    FX_BYTE			app_identify[8];

+    FX_BYTE			app_authentication[3];

+    FX_DWORD		app_data_size;

+    FX_LPBYTE		app_data;

+#endif

+

+#ifdef GIF_SUPPORT_COMMENT_EXTENSION

+    FX_LPBYTE		cmt_data_ptr;

+    FX_DWORD		cmt_data_len;

+#endif

+

+#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION

+    GifGCE*			gce_ptr;

+#endif

+

+#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION

+    GifPTE*			pte_ptr;

+    FX_LPCBYTE		pte_data_ptr;

+    FX_DWORD		pte_data_len;

+#endif

+};

+void _gif_error(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg);

+void _gif_warn(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg);

+gif_decompress_struct_p _gif_create_decompress();

+void _gif_destroy_decompress(gif_decompress_struct_pp gif_ptr_ptr);

+gif_compress_struct_p _gif_create_compress();

+void _gif_destroy_compress(gif_compress_struct_pp gif_ptr_ptr);

+FX_INT32 _gif_read_header(gif_decompress_struct_p gif_ptr);

+FX_INT32 _gif_get_frame(gif_decompress_struct_p gif_ptr);

+FX_INT32 _gif_get_frame_num(gif_decompress_struct_p gif_ptr);

+FX_INT32 _gif_decode_extension(gif_decompress_struct_p gif_ptr);

+FX_INT32 _gif_decode_image_info(gif_decompress_struct_p gif_ptr);

+void _gif_takeover_gce_ptr(gif_decompress_struct_p gif_ptr, GifGCE** gce_ptr_ptr);

+FX_INT32 _gif_load_frame(gif_decompress_struct_p gif_ptr, FX_INT32 frame_num);

+FX_LPBYTE _gif_read_data(gif_decompress_struct_p gif_ptr, FX_LPBYTE* des_buf_pp, FX_DWORD data_size);

+void _gif_save_decoding_status(gif_decompress_struct_p gif_ptr, FX_INT32 status);

+void _gif_input_buffer(gif_decompress_struct_p gif_ptr, FX_LPBYTE src_buf, FX_DWORD src_size);

+FX_DWORD _gif_get_avail_input(gif_decompress_struct_p gif_ptr, FX_LPBYTE* avial_buf_ptr);

+void interlace_buf(FX_LPCBYTE buf, FX_DWORD width, FX_DWORD height);

+FX_BOOL _gif_encode( gif_compress_struct_p gif_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_len );

+#define GIF_PTR_NOT_NULL(ptr,gif_ptr)	if(ptr == NULL){						\

+        _gif_error(gif_ptr,"Out Of Memory");\

+        return 0;							\

+    }

diff --git a/core/src/fxcrt/extension.h b/core/src/fxcrt/extension.h
index c23a2e3..05aad67 100644
--- a/core/src/fxcrt/extension.h
+++ b/core/src/fxcrt/extension.h
@@ -26,6 +26,44 @@
     virtual FX_BOOL		Truncate(FX_FILESIZE szFile) = 0;
 };
 IFXCRT_FileAccess*	FXCRT_FileAccess_Create();
+class CFX_CRTFileAccess : public IFX_FileAccess, public CFX_Object
+{
+public:
+	CFX_CRTFileAccess() : m_RefCount(0) {}
+
+	virtual void				Release() 
+	{
+		if (--m_RefCount == 0)
+			delete this;
+	}
+
+	IFX_FileAccess*				Retain()
+	{
+		m_RefCount++;
+		return (IFX_FileAccess*)this;
+	}
+
+	virtual FX_BOOL				Init(FX_WSTR wsPath) 
+	{
+		m_path = wsPath;
+		m_RefCount = 1;
+		return TRUE;
+	}
+
+	virtual void				GetPath(CFX_WideString& wsPath)
+	{
+		wsPath = m_path;
+	}
+
+	virtual IFX_FileStream*		CreateFileStream(FX_DWORD dwModes)
+	{
+		return FX_CreateFileStream(m_path, dwModes);
+	}
+
+protected:
+	CFX_WideString		m_path;
+	FX_DWORD			m_RefCount;
+};
 class CFX_CRTFileStream FX_FINAL : public IFX_FileStream, public CFX_Object
 {
 public:
diff --git a/core/src/fxcrt/fx_arabic.cpp b/core/src/fxcrt/fx_arabic.cpp
index 583ce81..dd5d1d8 100644
--- a/core/src/fxcrt/fx_arabic.cpp
+++ b/core/src/fxcrt/fx_arabic.cpp
@@ -7,6 +7,1084 @@
 #include "../../include/fxcrt/fx_ext.h"
 #include "fx_arabic.h"
 extern const FX_DWORD gs_FX_TextLayout_CodeProperties[65536];
+#ifdef __cplusplus
+extern "C" {
+#endif
+static const FX_ARBFORMTABLE g_FX_ArabicFormTables[] = {
+    {0xFE81,	0xFE82,	0xFE81,	0xFE82},
+    {0xFE83,	0xFE84,	0xFE83,	0xFE84},
+    {0xFE85,	0xFE86,	0xFE85,	0xFE86},
+    {0xFE87,	0xFE88,	0xFE87,	0xFE88},
+    {0xFE89,	0xFE8A,	0xFE8B,	0xFE8C},
+    {0xFE8D,	0xFE8E,	0xFE8D,	0xFE8E},
+    {0xFE8F,	0xFE90,	0xFE91,	0xFE92},
+    {0xFE93,	0xFE94,	0xFE93,	0xFE94},
+    {0xFE95,	0xFE96,	0xFE97,	0xFE98},
+    {0xFE99,	0xFE9A,	0xFE9B,	0xFE9C},
+    {0xFE9D,	0xFE9E,	0xFE9F,	0xFEA0},
+    {0xFEA1,	0xFEA2,	0xFEA3,	0xFEA4},
+    {0xFEA5,	0xFEA6,	0xFEA7,	0xFEA8},
+    {0xFEA9,	0xFEAA,	0xFEA9,	0xFEAA},
+    {0xFEAB,	0xFEAC,	0xFEAB,	0xFEAC},
+    {0xFEAD,	0xFEAE,	0xFEAD,	0xFEAE},
+    {0xFEAF,	0xFEB0,	0xFEAF,	0xFEB0},
+    {0xFEB1,	0xFEB2,	0xFEB3,	0xFEB4},
+    {0xFEB5,	0xFEB6,	0xFEB7,	0xFEB8},
+    {0xFEB9,	0xFEBA,	0xFEBB,	0xFEBC},
+    {0xFEBD,	0xFEBE,	0xFEBF,	0xFEC0},
+    {0xFEC1,	0xFEC2,	0xFEC3,	0xFEC4},
+    {0xFEC5,	0xFEC6,	0xFEC7,	0xFEC8},
+    {0xFEC9,	0xFECA,	0xFECB,	0xFECC},
+    {0xFECD,	0xFECE,	0xFECF,	0xFED0},
+    {0x063B,	0x063B,	0x063B,	0x063B},
+    {0x063C,	0x063C,	0x063C,	0x063C},
+    {0x063D,	0x063D,	0x063D,	0x063D},
+    {0x063E,	0x063E,	0x063E,	0x063E},
+    {0x063F,	0x063F,	0x063F,	0x063F},
+    {0x0640,	0x0640,	0x0640,	0x0640},
+    {0xFED1,	0xFED2,	0xFED3,	0xFED4},
+    {0xFED5,	0xFED6,	0xFED7,	0xFED8},
+    {0xFED9,	0xFEDA,	0xFEDB,	0xFEDC},
+    {0xFEDD,	0xFEDE,	0xFEDF,	0xFEE0},
+    {0xFEE1,	0xFEE2,	0xFEE3,	0xFEE4},
+    {0xFEE5,	0xFEE6,	0xFEE7,	0xFEE8},
+    {0xFEE9,	0xFEEA,	0xFEEB,	0xFEEC},
+    {0xFEED,	0xFEEE,	0xFEED,	0xFEEE},
+    {0xFEEF,	0xFEF0,	0xFBFE,	0xFBFF},
+    {0xFEF1,	0xFEF2,	0xFEF3,	0xFEF4},
+    {0x064B,	0x064B,	0x064B,	0x064B},
+    {0x064C,	0x064C,	0x064C,	0x064C},
+    {0x064D,	0x064D,	0x064D,	0x064D},
+    {0x064E,	0x064E,	0x064E,	0x064E},
+    {0x064F,	0x064F,	0x064F,	0x064F},
+    {0x0650,	0x0650,	0x0650,	0x0650},
+    {0x0651,	0x0651,	0x0651,	0x0651},
+    {0x0652,	0x0652,	0x0652,	0x0652},
+    {0x0653,	0x0653,	0x0653,	0x0653},
+    {0x0654,	0x0654,	0x0654,	0x0654},
+    {0x0655,	0x0655,	0x0655,	0x0655},
+    {0x0656,	0x0656,	0x0656,	0x0656},
+    {0x0657,	0x0657,	0x0657,	0x0657},
+    {0x0658,	0x0658,	0x0658,	0x0658},
+    {0x0659,	0x0659,	0x0659,	0x0659},
+    {0x065A,	0x065A,	0x065A,	0x065A},
+    {0x065B,	0x065B,	0x065B,	0x065B},
+    {0x065C,	0x065C,	0x065C,	0x065C},
+    {0x065D,	0x065D,	0x065D,	0x065D},
+    {0x065E,	0x065E,	0x065E,	0x065E},
+    {0x065F,	0x065F,	0x065F,	0x065F},
+    {0x0660,	0x0660,	0x0660,	0x0660},
+    {0x0661,	0x0661,	0x0661,	0x0661},
+    {0x0662,	0x0662,	0x0662,	0x0662},
+    {0x0663,	0x0663,	0x0663,	0x0663},
+    {0x0664,	0x0664,	0x0664,	0x0664},
+    {0x0665,	0x0665,	0x0665,	0x0665},
+    {0x0666,	0x0666,	0x0666,	0x0666},
+    {0x0667,	0x0667,	0x0667,	0x0667},
+    {0x0668,	0x0668,	0x0668,	0x0668},
+    {0x0669,	0x0669,	0x0669,	0x0669},
+    {0x066A,	0x066A,	0x066A,	0x066A},
+    {0x066B,	0x066B,	0x066B,	0x066B},
+    {0x066C,	0x066C,	0x066C,	0x066C},
+    {0x066D,	0x066D,	0x066D,	0x066D},
+    {0x066E,	0x066E,	0x066E,	0x066E},
+    {0x066F,	0x066F,	0x066F,	0x066F},
+    {0x0670,	0x0670,	0x0670,	0x0670},
+    {0xFB50,	0xFB51,	0xFB50,	0xFB51},
+    {0x0672,	0x0672,	0x0672,	0x0672},
+    {0x0673,	0x0673,	0x0673,	0x0673},
+    {0x0674,	0x0674,	0x0674,	0x0674},
+    {0x0675,	0x0675,	0x0675,	0x0675},
+    {0x0676,	0x0676,	0x0676,	0x0676},
+    {0x0677,	0x0677,	0x0677,	0x0677},
+    {0x0678,	0x0678,	0x0678,	0x0678},
+    {0xFB66,	0xFB67,	0xFB68,	0xFB69},
+    {0xFB5E,	0xFB5F,	0xFB60,	0xFB61},
+    {0xFB52,	0xFB53,	0xFB54,	0xFB55},
+    {0x067C,	0x067C,	0x067C,	0x067C},
+    {0x067D,	0x067D,	0x067D,	0x067D},
+    {0xFB56,	0xFB57,	0xFB58,	0xFB59},
+    {0xFB62,	0xFB63,	0xFB64,	0xFB65},
+    {0xFB5A,	0xFB5B,	0xFB5C,	0xFB5D},
+    {0x0681,	0x0681,	0x0681,	0x0681},
+    {0x0682,	0x0682,	0x0682,	0x0682},
+    {0xFB76,	0xFB77,	0xFB78,	0xFB79},
+    {0xFB72,	0xFB73,	0xFB74,	0xFB75},
+    {0x0685,	0x0685,	0x0685,	0x0685},
+    {0xFB7A,	0xFB7B,	0xFB7C,	0xFB7D},
+    {0xFB7E,	0xFB7F,	0xFB80,	0xFB81},
+    {0xFB88,	0xFB89,	0xFB88,	0xFB89},
+    {0x0689,	0x0689,	0x0689,	0x0689},
+    {0x068A,	0x068A,	0x068A,	0x068A},
+    {0x068B,	0x068B,	0x068B,	0x068B},
+    {0xFB84,	0xFB85,	0xFB84,	0xFB85},
+    {0xFB82,	0xFB83,	0xFB82,	0xFB83},
+    {0xFB86,	0xFB87,	0xFB86,	0xFB87},
+    {0x068F,	0x068F,	0x068F,	0x068F},
+    {0x0690,	0x0690,	0x0690,	0x0690},
+    {0xFB8C,	0xFB8D,	0xFB8C,	0xFB8D},
+    {0x0692,	0x0692,	0x0692,	0x0692},
+    {0x0693,	0x0693,	0x0693,	0x0693},
+    {0x0694,	0x0694,	0x0694,	0x0694},
+    {0x0695,	0x0695,	0x0695,	0x0695},
+    {0x0696,	0x0696,	0x0696,	0x0696},
+    {0x0697,	0x0697,	0x0697,	0x0697},
+    {0xFB8A,	0xFB8B,	0xFB8A,	0xFB8B},
+    {0x0699,	0x0699,	0x0699,	0x0699},
+    {0x069A,	0x069A,	0x069A,	0x069A},
+    {0x069B,	0x069B,	0x069B,	0x069B},
+    {0x069C,	0x069C,	0x069C,	0x069C},
+    {0x069D,	0x069D,	0x069D,	0x069D},
+    {0x069E,	0x069E,	0x069E,	0x069E},
+    {0x069F,	0x069F,	0x069F,	0x069F},
+    {0x06A0,	0x06A0,	0x06A0,	0x06A0},
+    {0x06A1,	0x06A1,	0x06A1,	0x06A1},
+    {0x06A2,	0x06A2,	0x06A2,	0x06A2},
+    {0x06A3,	0x06A3,	0x06A3,	0x06A3},
+    {0xFB6A,	0xFB6B,	0xFB6C,	0xFB6D},
+    {0x06A5,	0x06A5,	0x06A5,	0x06A5},
+    {0xFB6E,	0xFB6F,	0xFB70,	0xFB71},
+    {0x06A7,	0x06A7,	0x06A7,	0x06A7},
+    {0x06A8,	0x06A8,	0x06A8,	0x06A8},
+    {0xFB8E,	0xFB8F,	0xFB90,	0xFB91},
+    {0x06AA,	0x06AA,	0x06AA,	0x06AA},
+    {0x06AB,	0x06AB,	0x06AB,	0x06AB},
+    {0x06AC,	0x06AC,	0x06AC,	0x06AC},
+    {0xFBD3,	0xFBD4,	0xFBD5,	0xFBD6},
+    {0x06AE,	0x06AE,	0x06AE,	0x06AE},
+    {0xFB92,	0xFB93,	0xFB94,	0xFB95},
+    {0x06B0,	0x06B0,	0x06B0,	0x06B0},
+    {0xFB9A,	0xFB9B,	0xFB9C,	0xFB9D},
+    {0x06B2,	0x06B2,	0x06B2,	0x06B2},
+    {0xFB96,	0xFB97,	0xFB98,	0xFB99},
+    {0x06B4,	0x06B4,	0x06B4,	0x06B4},
+    {0x06B5,	0x06B5,	0x06B5,	0x06B5},
+    {0x06B6,	0x06B6,	0x06B6,	0x06B6},
+    {0x06B7,	0x06B7,	0x06B7,	0x06B7},
+    {0x06B8,	0x06B8,	0x06B8,	0x06B8},
+    {0x06B9,	0x06B9,	0x06B9,	0x06B9},
+    {0xFB9E,	0xFB9F,	0xFBE8,	0xFBE9},
+    {0xFBA0,	0xFBA1,	0xFBA2,	0xFBA3},
+    {0x06BC,	0x06BC,	0x06BC,	0x06BC},
+    {0x06BD,	0x06BD,	0x06BD,	0x06BD},
+    {0xFBAA,	0xFBAB,	0xFBAC,	0xFBAD},
+    {0x06BF,	0x06BF,	0x06BF,	0x06BF},
+    {0xFBA4,	0xFBA5,	0xFBA4,	0xFBA5},
+    {0xFBA6,	0xFBA7,	0xFBA8,	0xFBA9},
+    {0x06C2,	0x06C2,	0x06C2,	0x06C2},
+    {0x06C3,	0x06C3,	0x06C3,	0x06C3},
+    {0x06C4,	0x06C4,	0x06C4,	0x06C4},
+    {0xFBE0,	0xFBE1,	0xFBE0,	0xFBE1},
+    {0xFBD9,	0xFBDA,	0xFBD9,	0xFBDA},
+    {0xFBD7,	0xFBD8,	0xFBD7,	0xFBD8},
+    {0xFBDB,	0xFBDC,	0xFBDB,	0xFBDC},
+    {0xFBE2,	0xFBE3,	0xFBE2,	0xFBE3},
+    {0x06CA,	0x06CA,	0x06CA,	0x06CA},
+    {0xFBDE,	0xFBDF,	0xFBDE,	0xFBDF},
+    {0xFBFC,	0xFBFD,	0xFBFE,	0xFBFF},
+    {0x06CD,	0x06CD,	0x06CD,	0x06CD},
+    {0x06CE,	0x06CE,	0x06CE,	0x06CE},
+    {0x06CF,	0x06CF,	0x06CF,	0x06CF},
+    {0xFBE4,	0xFBE5,	0xFBE6,	0xFBE7},
+    {0x06D1,	0x06D1,	0x06D1,	0x06D1},
+    {0xFBAE,	0xFBAF,	0xFBAE,	0xFBAF},
+    {0xFBB0,	0xFBB1,	0xFBB0,	0xFBB1},
+    {0x06D4,	0x06D4,	0x06D4,	0x06D4},
+    {0x06D5,	0x06D5,	0x06D5,	0x06D5},
+};
+static const FX_ARAALEF gs_FX_AlefTable[] = {
+    {0x0622, 0xFEF5},
+    {0x0623, 0xFEF7},
+    {0x0625, 0xFEF9},
+    {0x0627, 0xFEFB},
+};
+static const FX_ARASHADDA gs_FX_ShaddaTable[] = {
+    {0x064C,	0xFC5E},
+    {0x064D,	0xFC5F},
+    {0x064E,	0xFC60},
+    {0x064F,	0xFC61},
+    {0x0650,	0xFC62},
+};
+FX_LPCARBFORMTABLE FX_GetArabicFormTable(FX_WCHAR unicode)
+{
+    if (unicode < 0x622 || unicode > 0x6d5) {
+        return NULL;
+    }
+    return g_FX_ArabicFormTables + unicode - 0x622;
+}
+FX_WCHAR FX_GetArabicFromAlefTable(FX_WCHAR alef)
+{
+    static const FX_INT32 s_iAlefCount = sizeof(gs_FX_AlefTable) / sizeof(FX_ARAALEF);
+    for (FX_INT32 iStart = 0; iStart < s_iAlefCount; iStart ++) {
+        const FX_ARAALEF &v = gs_FX_AlefTable[iStart];
+        if (v.wAlef == alef) {
+            return v.wIsolated;
+        }
+    }
+    return alef;
+}
+FX_WCHAR FX_GetArabicFromShaddaTable(FX_WCHAR shadda)
+{
+    static const FX_INT32 s_iShaddaCount = sizeof(gs_FX_ShaddaTable) / sizeof(FX_ARASHADDA);
+    for (FX_INT32 iStart = 0; iStart < s_iShaddaCount; iStart ++) {
+        const FX_ARASHADDA &v = gs_FX_ShaddaTable[iStart];
+        if (v.wShadda == shadda) {
+            return v.wIsolated;
+        }
+    }
+    return shadda;
+}
+#ifdef __cplusplus
+};
+#endif
+IFX_ArabicChar* IFX_ArabicChar::Create()
+{
+    return FX_NEW CFX_ArabicChar;
+}
+FX_BOOL CFX_ArabicChar::IsArabicChar(FX_WCHAR wch) const
+{
+    FX_DWORD dwRet = (gs_FX_TextLayout_CodeProperties[(FX_WORD)wch] & FX_CHARTYPEBITSMASK);
+    return dwRet >= FX_CHARTYPE_ArabicAlef;
+}
+FX_BOOL CFX_ArabicChar::IsArabicFormChar(FX_WCHAR wch) const
+{
+    return (gs_FX_TextLayout_CodeProperties[(FX_WORD)wch] & FX_CHARTYPEBITSMASK) == FX_CHARTYPE_ArabicForm;
+}
+FX_WCHAR CFX_ArabicChar::GetFormChar(FX_WCHAR wch, FX_WCHAR prev, FX_WCHAR next) const
+{
+    CFX_Char c(wch, gs_FX_TextLayout_CodeProperties[(FX_WORD)wch]);
+    CFX_Char p(prev, gs_FX_TextLayout_CodeProperties[(FX_WORD)prev]);
+    CFX_Char n(next, gs_FX_TextLayout_CodeProperties[(FX_WORD)next]);
+    return GetFormChar(&c, &p, &n);
+}
+FX_WCHAR CFX_ArabicChar::GetFormChar(const CFX_Char *cur, const CFX_Char *prev, const CFX_Char *next) const
+{
+    FX_CHARTYPE eCur;
+    FX_WCHAR wCur;
+    FX_LPCARBFORMTABLE ft = ParseChar(cur, wCur, eCur);
+    if (eCur < FX_CHARTYPE_ArabicAlef || eCur >= FX_CHARTYPE_ArabicNormal) {
+        return wCur;
+    }
+    FX_CHARTYPE ePrev;
+    FX_WCHAR wPrev;
+    ParseChar(prev, wPrev, ePrev);
+    if (wPrev == 0x0644 && eCur == FX_CHARTYPE_ArabicAlef) {
+        return 0xFEFF;
+    }
+    FX_CHARTYPE eNext;
+    FX_WCHAR wNext;
+    ParseChar(next, wNext, eNext);
+    FX_BOOL bAlef = (eNext == FX_CHARTYPE_ArabicAlef && wCur == 0x644);
+    if (ePrev < FX_CHARTYPE_ArabicAlef) {
+        if (bAlef) {
+            return FX_GetArabicFromAlefTable(wNext);
+        } else {
+            return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wIsolated : ft->wInitial;
+        }
+    } else {
+        if (bAlef) {
+            wCur = FX_GetArabicFromAlefTable(wNext);
+            return (ePrev != FX_CHARTYPE_ArabicDistortion) ? wCur : ++ wCur;
+        } else if (ePrev == FX_CHARTYPE_ArabicAlef || ePrev == FX_CHARTYPE_ArabicSpecial) {
+            return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wIsolated : ft->wInitial;
+        } else {
+            return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wFinal : ft->wMedial;
+        }
+    }
+}
+FX_LPCARBFORMTABLE CFX_ArabicChar::ParseChar(const CFX_Char *pTC, FX_WCHAR &wChar, FX_CHARTYPE &eType) const
+{
+    if (pTC == NULL) {
+        eType = FX_CHARTYPE_Unknown;
+        wChar = 0xFEFF;
+        return NULL;
+    }
+    eType = (FX_CHARTYPE)pTC->GetCharType();
+    wChar = (FX_WCHAR)pTC->m_wCharCode;
+    FX_LPCARBFORMTABLE pFT = FX_GetArabicFormTable(wChar);
+    if (pFT == NULL || eType >= FX_CHARTYPE_ArabicNormal) {
+        eType = FX_CHARTYPE_Unknown;
+    }
+    return pFT;
+}
+void FX_BidiReverseString(CFX_WideString &wsText, FX_INT32 iStart, FX_INT32 iCount)
+{
+    FXSYS_assert(iStart > -1 && iStart < wsText.GetLength());
+    FXSYS_assert(iCount >= 0 && iStart + iCount <= wsText.GetLength());
+    FX_WCHAR wch;
+    FX_LPWSTR pStart = (FX_LPWSTR)(FX_LPCWSTR)wsText;
+    pStart += iStart;
+    FX_LPWSTR pEnd = pStart + iCount - 1;
+    while (pStart < pEnd) {
+        wch = *pStart;
+        *pStart ++ = *pEnd;
+        *pEnd -- = wch;
+    }
+}
+void FX_BidiSetDeferredRun(CFX_Int32Array &values, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iValue)
+{
+    FXSYS_assert(iStart > -1 && iStart <= values.GetSize());
+    FXSYS_assert(iStart - iCount > -1);
+    for (FX_INT32 i = iStart - 1; i >= iStart - iCount; i --) {
+        values.SetAt(i, iValue);
+    }
+}
+const FX_INT32 gc_FX_BidiNTypes[] = {
+    FX_BIDICLASS_N,
+    FX_BIDICLASS_L,
+    FX_BIDICLASS_R,
+    FX_BIDICLASS_AN,
+    FX_BIDICLASS_EN,
+    FX_BIDICLASS_AL,
+    FX_BIDICLASS_NSM,
+    FX_BIDICLASS_CS,
+    FX_BIDICLASS_ES,
+    FX_BIDICLASS_ET,
+    FX_BIDICLASS_BN,
+    FX_BIDICLASS_BN,
+    FX_BIDICLASS_N,
+    FX_BIDICLASS_B,
+    FX_BIDICLASS_RLO,
+    FX_BIDICLASS_RLE,
+    FX_BIDICLASS_LRO,
+    FX_BIDICLASS_LRE,
+    FX_BIDICLASS_PDF,
+    FX_BIDICLASS_ON,
+};
+void FX_BidiClassify(const CFX_WideString &wsText, CFX_Int32Array &classes, FX_BOOL bWS)
+{
+    FXSYS_assert(wsText.GetLength() == classes.GetSize());
+    FX_INT32 iCount = wsText.GetLength();
+    FX_LPCWSTR pwsStart = (FX_LPCWSTR)wsText;
+    FX_WCHAR wch;
+    FX_INT32 iCls;
+    if (bWS) {
+        for (FX_INT32 i = 0; i < iCount; i ++) {
+            wch = *pwsStart ++;
+            iCls = ((gs_FX_TextLayout_CodeProperties[(FX_WORD)wch] & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS);
+            classes.SetAt(i, iCls);
+        }
+    } else {
+        for (FX_INT32 i = 0; i < iCount; i ++) {
+            wch = *pwsStart ++;
+            iCls = ((gs_FX_TextLayout_CodeProperties[(FX_WORD)wch] & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS);
+            classes.SetAt(i, gc_FX_BidiNTypes[iCls]);
+        }
+    }
+}
+FX_INT32 FX_BidiResolveExplicit(FX_INT32 iBaseLevel, FX_INT32 iDirection, CFX_Int32Array &classes, CFX_Int32Array &levels, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iNest)
+{
+    FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL && iNest >= 0);
+    FXSYS_assert(classes.GetSize() == levels.GetSize());
+    FXSYS_assert(iStart >= 0 && iStart < classes.GetSize());
+    FXSYS_assert(iCount >= 0 && iStart + iCount <= classes.GetSize());
+    if (iCount < 1) {
+        return 0;
+    }
+#if 0
+    FX_INT32 iLastNest = iNest;
+#endif
+    FX_INT32 iSize = classes.GetSize();
+    FX_INT32 i = iStart, iCur, iCls;
+    for (; i < iSize && iCount > 0; i ++, iCount --) {
+        iCur = iCls = classes.GetAt(i);
+#if 0
+        switch (iCls) {
+            case FX_BIDICLASS_LRO:
+            case FX_BIDICLASS_LRE:
+                classes.SetAt(i, FX_BIDICLASS_BN);
+                iCls = FX_BIDICLASS_BN;
+                iNest ++;
+                if (FX_BidiGreaterEven(iBaseLevel) <= MAX_LEVEL) {
+                    FX_INT32 iLevel = FX_BidiGreaterEven(iBaseLevel);
+                    levels.SetAt(i, iLevel);
+                    i += FX_BidiResolveExplicit(iLevel,
+                                                (iCls == FX_BIDICLASS_LRE ? FX_BIDICLASS_N : FX_BIDICLASS_L),
+                                                classes,
+                                                levels,
+                                                i + 1,
+                                                iCount - 1,
+                                                iNest);
+                    iNest --;
+                    continue;
+                }
+                break;
+            case FX_BIDICLASS_RLO:
+            case FX_BIDICLASS_RLE:
+                classes.SetAt(i, FX_BIDICLASS_BN);
+                iCls = FX_BIDICLASS_BN;
+                iNest ++;
+                if (FX_BidiGreaterOdd(iBaseLevel) <= MAX_LEVEL) {
+                    FX_INT32 iLevel = FX_BidiGreaterOdd(iBaseLevel);
+                    levels.SetAt(i, iLevel);
+                    i += FX_BidiResolveExplicit(iLevel,
+                                                (iCls == FX_BIDICLASS_RLE ? FX_BIDICLASS_N : FX_BIDICLASS_R),
+                                                classes,
+                                                levels,
+                                                i + 1,
+                                                iCount - 1,
+                                                iNest);
+                    iNest --;
+                    continue;
+                }
+                break;
+            case FX_BIDICLASS_PDF:
+                classes.SetAt(i, FX_BIDICLASS_BN);
+                iCls = FX_BIDICLASS_BN;
+                if (iNest) {
+                    if (iLastNest < iNest) {
+                        iNest --;
+                    } else {
+                        iSize = i;
+                    }
+                }
+                break;
+        }
+        iCur = iCls;
+#endif
+        if (iDirection != FX_BIDICLASS_N) {
+            iCls = iDirection;
+        }
+        if (iCur != FX_BIDICLASS_BN) {
+            classes.SetAt(i, iCls);
+        }
+        levels.SetAt(i, iBaseLevel);
+    }
+    return i - iStart;
+}
+const FX_INT32 gc_FX_BidiWeakStates[][10] = {
+    {FX_BWSao,	FX_BWSxl,	FX_BWSxr,	FX_BWScn,	FX_BWScn,	FX_BWSxa,	FX_BWSxa,	FX_BWSao,	FX_BWSao,	FX_BWSao},
+    {FX_BWSro,	FX_BWSxl,	FX_BWSxr,	FX_BWSra,	FX_BWSre,	FX_BWSxa,	FX_BWSxr,	FX_BWSro,	FX_BWSro,	FX_BWSrt},
+    {FX_BWSlo,	FX_BWSxl,	FX_BWSxr,	FX_BWSla,	FX_BWSle,	FX_BWSxa,	FX_BWSxl,	FX_BWSlo,	FX_BWSlo,	FX_BWSlt},
+    {FX_BWSao,	FX_BWSxl,	FX_BWSxr,	FX_BWScn,	FX_BWScn,	FX_BWSxa,	FX_BWSao,	FX_BWSao,	FX_BWSao,	FX_BWSao},
+    {FX_BWSro,	FX_BWSxl,	FX_BWSxr,	FX_BWSra,	FX_BWSre,	FX_BWSxa,	FX_BWSro,	FX_BWSro,	FX_BWSro,	FX_BWSrt},
+    {FX_BWSlo,	FX_BWSxl,	FX_BWSxr,	FX_BWSla,	FX_BWSle,	FX_BWSxa,	FX_BWSlo,	FX_BWSlo,	FX_BWSlo,	FX_BWSlt},
+    {FX_BWSro,	FX_BWSxl,	FX_BWSxr,	FX_BWSra,	FX_BWSre,	FX_BWSxa,	FX_BWSrt,	FX_BWSro,	FX_BWSro,	FX_BWSrt},
+    {FX_BWSlo,	FX_BWSxl,	FX_BWSxr,	FX_BWSla,	FX_BWSle,	FX_BWSxa,	FX_BWSlt,	FX_BWSlo,	FX_BWSlo,	FX_BWSlt},
+    {FX_BWSao,	FX_BWSxl,	FX_BWSxr,	FX_BWScn,	FX_BWScn,	FX_BWSxa,	FX_BWScn,	FX_BWSac,	FX_BWSao,	FX_BWSao},
+    {FX_BWSro,	FX_BWSxl,	FX_BWSxr,	FX_BWSra,	FX_BWSre,	FX_BWSxa,	FX_BWSra,	FX_BWSrc,	FX_BWSro,	FX_BWSrt},
+    {FX_BWSro,	FX_BWSxl,	FX_BWSxr,	FX_BWSra,	FX_BWSre,	FX_BWSxa,	FX_BWSre,	FX_BWSrs,	FX_BWSrs,	FX_BWSret},
+    {FX_BWSlo,	FX_BWSxl,	FX_BWSxr,	FX_BWSla,	FX_BWSle,	FX_BWSxa,	FX_BWSla,	FX_BWSlc,	FX_BWSlo,	FX_BWSlt},
+    {FX_BWSlo,	FX_BWSxl,	FX_BWSxr,	FX_BWSla,	FX_BWSle,	FX_BWSxa,	FX_BWSle,	FX_BWSls,	FX_BWSls,	FX_BWSlet},
+    {FX_BWSao,	FX_BWSxl,	FX_BWSxr,	FX_BWScn,	FX_BWScn,	FX_BWSxa,	FX_BWSao,	FX_BWSao,	FX_BWSao,	FX_BWSao},
+    {FX_BWSro,	FX_BWSxl,	FX_BWSxr,	FX_BWSra,	FX_BWSre,	FX_BWSxa,	FX_BWSro,	FX_BWSro,	FX_BWSro,	FX_BWSrt},
+    {FX_BWSro,	FX_BWSxl,	FX_BWSxr,	FX_BWSra,	FX_BWSre,	FX_BWSxa,	FX_BWSro,	FX_BWSro,	FX_BWSro,	FX_BWSrt},
+    {FX_BWSlo,	FX_BWSxl,	FX_BWSxr,	FX_BWSla,	FX_BWSle,	FX_BWSxa,	FX_BWSlo,	FX_BWSlo,	FX_BWSlo,	FX_BWSlt},
+    {FX_BWSlo,	FX_BWSxl,	FX_BWSxr,	FX_BWSla,	FX_BWSle,	FX_BWSxa,	FX_BWSlo,	FX_BWSlo,	FX_BWSlo,	FX_BWSlt},
+    {FX_BWSro,	FX_BWSxl,	FX_BWSxr,	FX_BWSra,	FX_BWSre,	FX_BWSxa,	FX_BWSret,	FX_BWSro,	FX_BWSro,	FX_BWSret},
+    {FX_BWSlo,	FX_BWSxl,	FX_BWSxr,	FX_BWSla,	FX_BWSle,	FX_BWSxa,	FX_BWSlet,	FX_BWSlo,	FX_BWSlo,	FX_BWSlet},
+};
+const FX_INT32 gc_FX_BidiWeakActions[][10] = {
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWANxx,	FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR, FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx},
+    {FX_BWANxx,	FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR, FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR, FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxxN},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxE, FX_BWAxIx, FX_BWAxIx, FX_BWAxxE},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxL, FX_BWAxIx, FX_BWAxIx, FX_BWAxxL},
+    {FX_BWANxx,	FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWAAxA, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANxN},
+    {FX_BWANxx,	FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxE, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
+    {FX_BWANxx,	FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
+    {FX_BWANxx,	FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxL, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
+    {FX_BWANxx,	FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxE, FX_BWAxxN, FX_BWAxxN, FX_BWAxxE},
+    {FX_BWAxxx,	FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxxL},
+};
+void FX_BidiResolveWeak(FX_INT32 iBaseLevel, CFX_Int32Array &classes, CFX_Int32Array &levels)
+{
+    FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+    FXSYS_assert(classes.GetSize() == levels.GetSize());
+    FX_INT32 iSize = classes.GetSize();
+    if (iSize < 1) {
+        return;
+    }
+    iSize --;
+    FX_INT32 iLevelCur = iBaseLevel;
+    FX_INT32 iState = FX_IsOdd(iBaseLevel) ? FX_BWSxr : FX_BWSxl;
+    FX_INT32 i = 0, iCount = 0, iClsCur, iClsRun, iClsNew, iAction;
+    for (; i <= iSize; i ++) {
+        iClsCur = classes.GetAt(i);
+#if 0
+        if (iClsCur == FX_BIDICLASS_BN) {
+            levels.SetAt(i, iLevelCur);
+            if (i == iSize && iLevelCur != iBaseLevel) {
+                iClsCur = FX_BidiDirection(iLevelCur);
+                classes.SetAt(i, iClsCur);
+            } else if (i < iSize) {
+                FX_INT32 iLevelNext, iLevelNew;
+                iClsNew = classes.GetAt(i + 1);
+                iLevelNext = levels.GetAt(i + 1);
+                if (iClsNew != FX_BIDICLASS_BN && iLevelCur != iLevelNext) {
+                    iLevelNew = iLevelNext;
+                    if (iLevelCur > iLevelNew) {
+                        iLevelNew = iLevelCur;
+                    }
+                    levels.SetAt(i, iLevelNew);
+                    iClsCur = FX_BidiDirection(iLevelNew);
+                    classes.SetAt(i, iClsCur);
+                    iLevelCur = iLevelNext;
+                } else {
+                    if (iCount) {
+                        iCount ++;
+                    }
+                    continue;
+                }
+            } else {
+                if (iCount) {
+                    iCount ++;
+                }
+                continue;
+            }
+        }
+#endif
+        FXSYS_assert(iClsCur <= FX_BIDICLASS_BN);
+        iAction = gc_FX_BidiWeakActions[iState][iClsCur];
+        iClsRun = FX_BidiGetDeferredType(iAction);
+        if (iClsRun != FX_BIDIWEAKACTION_XX && iCount > 0) {
+            FX_BidiSetDeferredRun(classes, i, iCount, iClsRun);
+            iCount = 0;
+        }
+        iClsNew = FX_BidiGetResolvedType(iAction);
+        if (iClsNew != FX_BIDIWEAKACTION_XX) {
+            classes.SetAt(i, iClsNew);
+        }
+        if (FX_BIDIWEAKACTION_IX & iAction) {
+            iCount ++;
+        }
+        iState = gc_FX_BidiWeakStates[iState][iClsCur];
+    }
+    iClsCur = FX_BidiDirection(iLevelCur);
+    iClsRun = FX_BidiGetDeferredType(gc_FX_BidiWeakActions[iState][iClsCur]);
+    if (iClsRun != FX_BIDIWEAKACTION_XX && iCount > 0) {
+        FX_BidiSetDeferredRun(classes, i, iCount, iClsRun);
+    }
+}
+const FX_INT32 gc_FX_BidiNeutralStates[][5] = {
+    {FX_BNSrn,	FX_BNSl,	FX_BNSr,	FX_BNSr,	FX_BNSr},
+    {FX_BNSln,	FX_BNSl,	FX_BNSr,	FX_BNSa,	FX_BNSl},
+    {FX_BNSrn,	FX_BNSl,	FX_BNSr,	FX_BNSr,	FX_BNSr},
+    {FX_BNSln,	FX_BNSl,	FX_BNSr,	FX_BNSa,	FX_BNSl},
+    {FX_BNSna,	FX_BNSl,	FX_BNSr,	FX_BNSa,	FX_BNSl},
+    {FX_BNSna,	FX_BNSl,	FX_BNSr,	FX_BNSa,	FX_BNSl},
+};
+const FX_INT32 gc_FX_BidiNeutralActions[][5] = {
+    {FX_BNAIn,  0,			0,			0,			0			},
+    {FX_BNAIn,  0,			0,			0,			FX_BCL		},
+    {FX_BNAIn,	FX_BNAEn,	FX_BNARn,	FX_BNARn,	FX_BNARn	},
+    {FX_BNAIn,	FX_BNALn,	FX_BNAEn,	FX_BNAEn,	FX_BNALnL	},
+    {FX_BNAIn,  0,			0,			0,			FX_BCL		},
+    {FX_BNAIn,	FX_BNAEn,	FX_BNARn,	FX_BNARn,	FX_BNAEn	},
+};
+FX_INT32 FX_BidiGetDeferredNeutrals(FX_INT32 iAction, FX_INT32 iLevel)
+{
+    iAction = (iAction >> 4) & 0xF;
+    if (iAction == (FX_BIDINEUTRALACTION_En >> 4)) {
+        return FX_BidiDirection(iLevel);
+    } else {
+        return iAction;
+    }
+}
+FX_INT32 FX_BidiGetResolvedNeutrals(FX_INT32 iAction)
+{
+    iAction = (iAction & 0xF);
+    if (iAction == FX_BIDINEUTRALACTION_In) {
+        return 0;
+    } else {
+        return iAction;
+    }
+}
+void FX_BidiResolveNeutrals(FX_INT32 iBaseLevel, CFX_Int32Array &classes, const CFX_Int32Array &levels)
+{
+    FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+    FXSYS_assert(classes.GetSize() == levels.GetSize());
+    FX_INT32 iSize = classes.GetSize();
+    if (iSize < 1) {
+        return;
+    }
+    iSize --;
+    FX_INT32 iLevel = iBaseLevel;
+    FX_INT32 iState = FX_IsOdd(iBaseLevel) ? FX_BNSr : FX_BNSl;
+    FX_INT32 i = 0, iCount = 0, iClsCur, iClsRun, iClsNew, iAction;
+    for (; i <= iSize; i ++) {
+        iClsCur = classes.GetAt(i);
+        if (iClsCur == FX_BIDICLASS_BN) {
+            if (iCount) {
+                iCount ++;
+            }
+            continue;
+        }
+        FXSYS_assert(iClsCur < FX_BIDICLASS_AL);
+        iAction = gc_FX_BidiNeutralActions[iState][iClsCur];
+        iClsRun = FX_BidiGetDeferredNeutrals(iAction, iLevel);
+        if (iClsRun != FX_BIDICLASS_N && iCount > 0) {
+            FX_BidiSetDeferredRun(classes, i, iCount, iClsRun);
+            iCount = 0;
+        }
+        iClsNew = FX_BidiGetResolvedNeutrals(iAction);
+        if (iClsNew != FX_BIDICLASS_N) {
+            classes.SetAt(i, iClsNew);
+        }
+        if (FX_BIDINEUTRALACTION_In & iAction) {
+            iCount ++;
+        }
+        iState = gc_FX_BidiNeutralStates[iState][iClsCur];
+        iLevel = levels.GetAt(i);
+    }
+    iClsCur = FX_BidiDirection(iLevel);
+    iClsRun = FX_BidiGetDeferredNeutrals(gc_FX_BidiNeutralActions[iState][iClsCur], iLevel);
+    if (iClsRun != FX_BIDICLASS_N && iCount > 0) {
+        FX_BidiSetDeferredRun(classes, i, iCount, iClsRun);
+    }
+}
+const FX_INT32 gc_FX_BidiAddLevel[][4] = {
+    {0,  1,  2,  2},
+    {1,  0,  1,  1},
+};
+void FX_BidiResolveImplicit(const CFX_Int32Array &classes, CFX_Int32Array &levels)
+{
+    FXSYS_assert(classes.GetSize() == levels.GetSize());
+    FX_INT32 iSize = classes.GetSize();
+    if (iSize < 1) {
+        return;
+    }
+    iSize --;
+    FX_INT32 iCls, iLevel;
+    for (FX_INT32 i = 0; i <= iSize; i ++) {
+        iCls = classes.GetAt(i);
+        if (iCls == FX_BIDICLASS_BN) {
+            continue;
+        }
+        FXSYS_assert(iCls > FX_BIDICLASS_ON && iCls < FX_BIDICLASS_AL);
+        iLevel = levels.GetAt(i);
+        iLevel += gc_FX_BidiAddLevel[FX_IsOdd(iLevel)][iCls - 1];
+        levels.SetAt(i, iLevel);
+    }
+}
+void FX_BidiResolveWhitespace(FX_INT32 iBaseLevel, const CFX_Int32Array &classes, CFX_Int32Array &levels)
+{
+    FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+    FXSYS_assert(classes.GetSize() == levels.GetSize());
+    FX_INT32 iSize = classes.GetSize();
+    if (iSize < 1) {
+        return;
+    }
+    iSize --;
+    FX_INT32 iLevel = iBaseLevel;
+    FX_INT32 i = 0, iCount = 0;
+    for (; i <= iSize; i ++) {
+        switch(classes.GetAt(i)) {
+            case FX_BIDICLASS_WS:
+                iCount ++;
+                break;
+            case FX_BIDICLASS_RLE:
+            case FX_BIDICLASS_LRE:
+            case FX_BIDICLASS_LRO:
+            case FX_BIDICLASS_RLO:
+            case FX_BIDICLASS_PDF:
+            case FX_BIDICLASS_BN:
+                levels.SetAt(i, iLevel);
+                iCount ++;
+                break;
+            case FX_BIDICLASS_S:
+            case FX_BIDICLASS_B:
+                if (iCount > 0) {
+                    FX_BidiSetDeferredRun(levels, i, iCount, iBaseLevel);
+                }
+                levels.SetAt(i, iBaseLevel);
+                iCount = 0;
+                break;
+            default:
+                iCount = 0;
+                break;
+        }
+        iLevel = levels.GetAt(i);
+    }
+    if (iCount > 0) {
+        FX_BidiSetDeferredRun(levels, i, iCount, iBaseLevel);
+    }
+}
+FX_INT32 FX_BidiReorderLevel(FX_INT32 iBaseLevel, CFX_WideString &wsText, const CFX_Int32Array &levels, FX_INT32 iStart, FX_BOOL bReverse)
+{
+    FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+    FXSYS_assert(wsText.GetLength() == levels.GetSize());
+    FXSYS_assert(iStart >= 0 && iStart < wsText.GetLength());
+    FX_INT32 iSize = wsText.GetLength();
+    if (iSize < 1) {
+        return 0;
+    }
+    bReverse = bReverse || FX_IsOdd(iBaseLevel);
+    FX_INT32 i = iStart, iLevel;
+    for (; i < iSize; i ++) {
+        if ((iLevel = levels.GetAt(i)) == iBaseLevel) {
+            continue;
+        }
+        if (iLevel < iBaseLevel) {
+            break;
+        }
+        i += FX_BidiReorderLevel(iBaseLevel + 1, wsText, levels, i, bReverse) - 1;
+    }
+    FX_INT32 iCount = i - iStart;
+    if (bReverse && iCount > 1) {
+        FX_BidiReverseString(wsText, iStart, iCount);
+    }
+    return iCount;
+}
+void FX_BidiReorder(FX_INT32 iBaseLevel, CFX_WideString &wsText, const CFX_Int32Array &levels)
+{
+    FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+    FXSYS_assert(wsText.GetLength() == levels.GetSize());
+    FX_INT32 iSize = wsText.GetLength();
+    if (iSize < 1) {
+        return;
+    }
+    FX_INT32 i = 0;
+    while (i < iSize) {
+        i += FX_BidiReorderLevel(iBaseLevel, wsText, levels, i, FALSE);
+    }
+}
+void FX_BidiLine(CFX_WideString &wsText, FX_INT32 iBaseLevel)
+{
+    FX_INT32 iLength = wsText.GetLength();
+    if (iLength < 2) {
+        return;
+    }
+    CFX_Int32Array classes, levels;
+    classes.SetAtGrow(iLength - 1, 0);
+    levels.SetAtGrow(iLength - 1, 0);
+    FX_BidiClassify(wsText, classes, FALSE);
+    FX_BidiResolveExplicit(iBaseLevel, FX_BIDICLASS_N, classes, levels, 0, iLength, 0);
+    FX_BidiResolveWeak(iBaseLevel, classes, levels);
+    FX_BidiResolveNeutrals(iBaseLevel, classes, levels);
+    FX_BidiResolveImplicit(classes, levels);
+    FX_BidiClassify(wsText, classes, TRUE);
+    FX_BidiResolveWhitespace(iBaseLevel, classes, levels);
+    FX_BidiReorder(iBaseLevel, wsText, levels);
+    classes.RemoveAll();
+    levels.RemoveAll();
+}
+template<class baseType>
+class CFX_BidiLineTemplate
+{
+public:
+    void FX_BidiReverseString(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iStart, FX_INT32 iCount)
+    {
+        FXSYS_assert(iStart > -1 && iStart < chars.GetSize());
+        FXSYS_assert(iCount >= 0 && iStart + iCount <= chars.GetSize());
+        baseType *pStart, *pEnd;
+        FX_INT32 iEnd = iStart + iCount - 1, iTemp;
+        while (iStart < iEnd) {
+            pStart = chars.GetDataPtr(iStart ++);
+            pEnd = chars.GetDataPtr(iEnd --);
+            iTemp = pStart->m_iBidiPos;
+            pStart->m_iBidiPos = pEnd->m_iBidiPos;
+            pEnd->m_iBidiPos = iTemp;
+        }
+    }
+    void FX_BidiSetDeferredRun(CFX_ArrayTemplate<baseType> &chars, FX_BOOL bClass, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iValue)
+    {
+        FXSYS_assert(iStart > -1 && iStart <= chars.GetSize());
+        FXSYS_assert(iStart - iCount > -1);
+        baseType *pTC;
+        FX_INT32 iLast = iStart - iCount;
+        if (bClass) {
+            for (FX_INT32 i = iStart - 1; i >= iLast; i --) {
+                pTC = chars.GetDataPtr(i);
+                pTC->m_iBidiClass = (FX_INT16)iValue;
+            }
+        } else {
+            for (FX_INT32 i = iStart - 1; i >= iLast; i --) {
+                pTC = chars.GetDataPtr(i);
+                pTC->m_iBidiLevel = (FX_INT16)iValue;
+            }
+        }
+    }
+    void FX_BidiClassify(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount, FX_BOOL bWS)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        baseType *pTC;
+        if (bWS) {
+            for (FX_INT32 i = 0; i < iCount; i ++) {
+                pTC = chars.GetDataPtr(i);
+                pTC->m_iBidiClass = (FX_INT16)(pTC->m_dwCharProps & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS;
+            }
+        } else {
+            for (FX_INT32 i = 0; i < iCount; i ++) {
+                pTC = chars.GetDataPtr(i);
+                pTC->m_iBidiClass = (FX_INT16)gc_FX_BidiNTypes[(pTC->m_dwCharProps & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS];
+            }
+        }
+    }
+    void FX_BidiResolveExplicit(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount, FX_INT32 iBaseLevel)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+        if (iCount < 1) {
+            return;
+        }
+        baseType *pTC;
+        for (FX_INT32 i = 0; i < iCount; i ++) {
+            pTC = chars.GetDataPtr(i);
+            pTC->m_iBidiLevel = (FX_INT16)iBaseLevel;
+        }
+    }
+    void FX_BidiResolveWeak(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount, FX_INT32 iBaseLevel)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        iCount --;
+        if (iCount < 1) {
+            return;
+        }
+        baseType *pTC, *pTCNext;
+        FX_INT32 iLevelCur = iBaseLevel;
+        FX_INT32 iState = FX_IsOdd(iBaseLevel) ? FX_BWSxr : FX_BWSxl;
+        FX_INT32 i = 0, iNum = 0, iClsCur, iClsRun, iClsNew, iAction;
+        for (; i <= iCount; i ++) {
+            pTC = chars.GetDataPtr(i);
+            iClsCur = pTC->m_iBidiClass;
+            if (iClsCur == FX_BIDICLASS_BN) {
+                pTC->m_iBidiLevel = (FX_INT16)iLevelCur;
+                if (i == iCount && iLevelCur != iBaseLevel) {
+                    iClsCur = FX_BidiDirection(iLevelCur);
+                    pTC->m_iBidiClass = (FX_INT16)iClsCur;
+                } else if (i < iCount) {
+                    pTCNext = chars.GetDataPtr(i + 1);
+                    FX_INT32 iLevelNext, iLevelNew;
+                    iClsNew = pTCNext->m_iBidiClass;
+                    iLevelNext = pTCNext->m_iBidiLevel;
+                    if (iClsNew != FX_BIDICLASS_BN && iLevelCur != iLevelNext) {
+                        iLevelNew = iLevelNext;
+                        if (iLevelCur > iLevelNew) {
+                            iLevelNew = iLevelCur;
+                        }
+                        pTC->m_iBidiLevel = (FX_INT16)iLevelNew;
+                        iClsCur = FX_BidiDirection(iLevelNew);
+                        pTC->m_iBidiClass = (FX_INT16)iClsCur;
+                        iLevelCur = iLevelNext;
+                    } else {
+                        if (iNum > 0) {
+                            iNum ++;
+                        }
+                        continue;
+                    }
+                } else {
+                    if (iNum > 0) {
+                        iNum ++;
+                    }
+                    continue;
+                }
+            }
+            FXSYS_assert(iClsCur <= FX_BIDICLASS_BN);
+            iAction = gc_FX_BidiWeakActions[iState][iClsCur];
+            iClsRun = FX_BidiGetDeferredType(iAction);
+            if (iClsRun != FX_BIDIWEAKACTION_XX && iNum > 0) {
+                FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun);
+                iNum = 0;
+            }
+            iClsNew = FX_BidiGetResolvedType(iAction);
+            if (iClsNew != FX_BIDIWEAKACTION_XX) {
+                pTC->m_iBidiClass = (FX_INT16)iClsNew;
+            }
+            if (FX_BIDIWEAKACTION_IX & iAction) {
+                iNum ++;
+            }
+            iState = gc_FX_BidiWeakStates[iState][iClsCur];
+        }
+        if (iNum > 0) {
+            iClsCur = FX_BidiDirection(iBaseLevel);
+            iClsRun = FX_BidiGetDeferredType(gc_FX_BidiWeakActions[iState][iClsCur]);
+            if (iClsRun != FX_BIDIWEAKACTION_XX) {
+                FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun);
+            }
+        }
+    }
+    void FX_BidiResolveNeutrals(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount, FX_INT32 iBaseLevel)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+        iCount --;
+        if (iCount < 1) {
+            return;
+        }
+        baseType *pTC;
+        FX_INT32 iLevel = iBaseLevel;
+        FX_INT32 iState = FX_IsOdd(iBaseLevel) ? FX_BNSr : FX_BNSl;
+        FX_INT32 i = 0, iNum = 0, iClsCur, iClsRun, iClsNew, iAction;
+        for (; i <= iCount; i ++) {
+            pTC = chars.GetDataPtr(i);
+            iClsCur = pTC->m_iBidiClass;
+            if (iClsCur == FX_BIDICLASS_BN) {
+                if (iNum) {
+                    iNum ++;
+                }
+                continue;
+            }
+            FXSYS_assert(iClsCur < FX_BIDICLASS_AL);
+            iAction = gc_FX_BidiNeutralActions[iState][iClsCur];
+            iClsRun = FX_BidiGetDeferredNeutrals(iAction, iLevel);
+            if (iClsRun != FX_BIDICLASS_N && iNum > 0) {
+                FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun);
+                iNum = 0;
+            }
+            iClsNew = FX_BidiGetResolvedNeutrals(iAction);
+            if (iClsNew != FX_BIDICLASS_N) {
+                pTC->m_iBidiClass = (FX_INT16)iClsNew;
+            }
+            if (FX_BIDINEUTRALACTION_In & iAction) {
+                iNum ++;
+            }
+            iState = gc_FX_BidiNeutralStates[iState][iClsCur];
+            iLevel = pTC->m_iBidiLevel;
+        }
+        if (iNum > 0) {
+            iClsCur = FX_BidiDirection(iLevel);
+            iClsRun = FX_BidiGetDeferredNeutrals(gc_FX_BidiNeutralActions[iState][iClsCur], iLevel);
+            if (iClsRun != FX_BIDICLASS_N) {
+                FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun);
+            }
+        }
+    }
+    void FX_BidiResolveImplicit(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        baseType *pTC;
+        FX_INT32 iCls, iLevel;
+        for (FX_INT32 i = 0; i < iCount; i ++) {
+            pTC = chars.GetDataPtr(i);
+            iCls = pTC->m_iBidiClass;
+            if (iCls == FX_BIDICLASS_BN) {
+                continue;
+            }
+            FXSYS_assert(iCls > FX_BIDICLASS_ON && iCls < FX_BIDICLASS_AL);
+            iLevel = pTC->m_iBidiLevel;
+            iLevel += gc_FX_BidiAddLevel[FX_IsOdd(iLevel)][iCls - 1];
+            pTC->m_iBidiLevel = (FX_INT16)iLevel;
+        }
+    }
+    void FX_BidiResolveWhitespace(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount, FX_INT32 iBaseLevel)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+        if (iCount < 1) {
+            return;
+        }
+        iCount --;
+        FX_INT32 iLevel = iBaseLevel;
+        FX_INT32 i = 0, iNum = 0;
+        baseType *pTC;
+        for (; i <= iCount; i ++) {
+            pTC = chars.GetDataPtr(i);
+            switch(pTC->m_iBidiClass) {
+                case FX_BIDICLASS_WS:
+                    iNum ++;
+                    break;
+                case FX_BIDICLASS_RLE:
+                case FX_BIDICLASS_LRE:
+                case FX_BIDICLASS_LRO:
+                case FX_BIDICLASS_RLO:
+                case FX_BIDICLASS_PDF:
+                case FX_BIDICLASS_BN:
+                    pTC->m_iBidiLevel = (FX_INT16)iLevel;
+                    iNum ++;
+                    break;
+                case FX_BIDICLASS_S:
+                case FX_BIDICLASS_B:
+                    if (iNum > 0) {
+                        FX_BidiSetDeferredRun(chars, FALSE, i, iNum, iBaseLevel);
+                    }
+                    pTC->m_iBidiLevel = (FX_INT16)iBaseLevel;
+                    iNum = 0;
+                    break;
+                default:
+                    iNum = 0;
+                    break;
+            }
+            iLevel = pTC->m_iBidiLevel;
+        }
+        if (iNum > 0) {
+            FX_BidiSetDeferredRun(chars, FALSE, i, iNum, iBaseLevel);
+        }
+    }
+    FX_INT32 FX_BidiReorderLevel(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount, FX_INT32 iBaseLevel, FX_INT32 iStart, FX_BOOL bReverse)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+        FXSYS_assert(iStart >= 0 && iStart < iCount);
+        if (iCount < 1) {
+            return 0;
+        }
+        baseType *pTC;
+        bReverse = bReverse || FX_IsOdd(iBaseLevel);
+        FX_INT32 i = iStart, iLevel;
+        for (; i < iCount; i ++) {
+            pTC = chars.GetDataPtr(i);
+            if ((iLevel = pTC->m_iBidiLevel) == iBaseLevel) {
+                continue;
+            }
+            if (iLevel < iBaseLevel) {
+                break;
+            }
+            i += FX_BidiReorderLevel(chars, iCount, iBaseLevel + 1, i, bReverse) - 1;
+        }
+        FX_INT32 iNum = i - iStart;
+        if (bReverse && iNum > 1) {
+            FX_BidiReverseString(chars, iStart, iNum);
+        }
+        return iNum;
+    }
+    void FX_BidiReorder(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount, FX_INT32 iBaseLevel)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
+        FX_INT32 i = 0;
+        while (i < iCount) {
+            i += FX_BidiReorderLevel(chars, iCount, iBaseLevel, i, FALSE);
+        }
+    }
+    void FX_BidiPosition(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        baseType *pTC;
+        FX_INT32 i = 0;
+        while (i < iCount) {
+            pTC = chars.GetDataPtr(i);
+            pTC = chars.GetDataPtr(pTC->m_iBidiPos);
+            pTC->m_iBidiOrder = i ++;
+        }
+    }
+
+    void FX_BidiLine(CFX_ArrayTemplate<baseType> &chars, FX_INT32 iCount, FX_INT32 iBaseLevel)
+    {
+        FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
+        if (iCount < 2) {
+            return;
+        }
+        FX_BidiClassify(chars, iCount, FALSE);
+        FX_BidiResolveExplicit(chars, iCount, iBaseLevel);
+        FX_BidiResolveWeak(chars, iCount, iBaseLevel);
+        FX_BidiResolveNeutrals(chars, iCount, iBaseLevel);
+        FX_BidiResolveImplicit(chars, iCount);
+        FX_BidiClassify(chars, iCount, TRUE);
+        FX_BidiResolveWhitespace(chars, iCount, iBaseLevel);
+        FX_BidiReorder(chars, iCount, iBaseLevel);
+        FX_BidiPosition(chars, iCount);
+    }
+};
+void FX_BidiLine(CFX_TxtCharArray &chars, FX_INT32 iCount, FX_INT32 iBaseLevel)
+{
+    CFX_BidiLineTemplate<CFX_TxtChar> blt;
+    blt.FX_BidiLine(chars, iCount, iBaseLevel);
+}
+void FX_BidiLine(CFX_RTFCharArray &chars, FX_INT32 iCount, FX_INT32 iBaseLevel)
+{
+    CFX_BidiLineTemplate<CFX_RTFChar> blt;
+    blt.FX_BidiLine(chars, iCount, iBaseLevel);
+}
 IFX_BidiChar* IFX_BidiChar::Create()
 {
     return FX_NEW CFX_BidiChar;
diff --git a/core/src/fxcrt/fx_arabic.h b/core/src/fxcrt/fx_arabic.h
index c404449..e44bfb8 100644
--- a/core/src/fxcrt/fx_arabic.h
+++ b/core/src/fxcrt/fx_arabic.h
@@ -6,7 +6,180 @@
 
 #ifndef _FX_ARABIC_IMP
 #define _FX_ARABIC_IMP
-class CFX_BidiChar FX_FINAL : public IFX_BidiChar, public CFX_Object
+typedef struct _FX_ARABICCHARRANGE {
+    FX_WCHAR wStart;
+    FX_WCHAR wEnd;
+} FX_ARABICCHARRANGE;
+class CFX_ArabicChar : public IFX_ArabicChar, public CFX_Object
+{
+public:
+    virtual void		Release()
+    {
+        delete this;
+    }
+    virtual FX_BOOL		IsArabicChar(FX_WCHAR wch) const;
+    virtual FX_BOOL		IsArabicFormChar(FX_WCHAR wch) const;
+
+    virtual FX_WCHAR	GetFormChar(FX_WCHAR wch, FX_WCHAR prev = 0, FX_WCHAR next = 0) const;
+    virtual FX_WCHAR	GetFormChar(const CFX_Char *cur, const CFX_Char *prev, const CFX_Char *next) const;
+protected:
+    FX_LPCARBFORMTABLE ParseChar(const CFX_Char *pTC, FX_WCHAR &wChar, FX_CHARTYPE &eType) const;
+};
+void FX_BidiReverseString(CFX_WideString &wsText, FX_INT32 iStart, FX_INT32 iCount);
+void FX_BidiSetDeferredRun(CFX_Int32Array &values, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iValue);
+#define FX_BCON		FX_BIDICLASS_ON
+#define FX_BCL		FX_BIDICLASS_L
+#define FX_BCR		FX_BIDICLASS_R
+#define FX_BCAN		FX_BIDICLASS_AN
+#define FX_BCEN		FX_BIDICLASS_EN
+#define FX_BCAL		FX_BIDICLASS_AL
+#define FX_BCNSM	FX_BIDICLASS_NSM
+#define FX_BCCS		FX_BIDICLASS_CS
+#define FX_BCES		FX_BIDICLASS_ES
+#define FX_BCET		FX_BIDICLASS_ET
+#define FX_BCBN		FX_BIDICLASS_BN
+#define FX_BCS		FX_BIDICLASS_S
+#define FX_BCWS		FX_BIDICLASS_WS
+#define FX_BCB		FX_BIDICLASS_B
+#define FX_BCRLO	FX_BIDICLASS_RLO
+#define FX_BCRLE	FX_BIDICLASS_RLE
+#define FX_BCLRO	FX_BIDICLASS_LRO
+#define FX_BCLRE	FX_BIDICLASS_LRE
+#define FX_BCPDF	FX_BIDICLASS_PDF
+#define FX_BCN		FX_BIDICLASS_N
+void FX_BidiClassify(const CFX_WideString &wsText, CFX_Int32Array &classes, FX_BOOL bWS = FALSE);
+#define FX_BIDIMAXLEVEL			61
+#define FX_BidiGreaterEven(a)	(FX_IsOdd(a) ? ((a) + 1) : ((a) + 2))
+#define FX_BidiGreaterOdd(a)	(FX_IsOdd(a) ? ((a) + 2) : ((a) + 1))
+FX_INT32 FX_BidiResolveExplicit(FX_INT32 iBaseLevel, FX_INT32 iDirection, CFX_Int32Array &classes, CFX_Int32Array &levels, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iNest = 0);
+#define FX_BidiDirection(a)	(FX_IsOdd(a) ? FX_BIDICLASS_R : FX_BIDICLASS_L)
+enum FX_BIDIWEAKSTATE {
+    FX_BIDIWEAKSTATE_xa = 0,
+    FX_BIDIWEAKSTATE_xr,
+    FX_BIDIWEAKSTATE_xl,
+    FX_BIDIWEAKSTATE_ao,
+    FX_BIDIWEAKSTATE_ro,
+    FX_BIDIWEAKSTATE_lo,
+    FX_BIDIWEAKSTATE_rt,
+    FX_BIDIWEAKSTATE_lt,
+    FX_BIDIWEAKSTATE_cn,
+    FX_BIDIWEAKSTATE_ra,
+    FX_BIDIWEAKSTATE_re,
+    FX_BIDIWEAKSTATE_la,
+    FX_BIDIWEAKSTATE_le,
+    FX_BIDIWEAKSTATE_ac,
+    FX_BIDIWEAKSTATE_rc,
+    FX_BIDIWEAKSTATE_rs,
+    FX_BIDIWEAKSTATE_lc,
+    FX_BIDIWEAKSTATE_ls,
+    FX_BIDIWEAKSTATE_ret,
+    FX_BIDIWEAKSTATE_let,
+};
+#define FX_BWSxa	FX_BIDIWEAKSTATE_xa
+#define FX_BWSxr	FX_BIDIWEAKSTATE_xr
+#define FX_BWSxl	FX_BIDIWEAKSTATE_xl
+#define FX_BWSao	FX_BIDIWEAKSTATE_ao
+#define FX_BWSro	FX_BIDIWEAKSTATE_ro
+#define FX_BWSlo	FX_BIDIWEAKSTATE_lo
+#define FX_BWSrt	FX_BIDIWEAKSTATE_rt
+#define FX_BWSlt	FX_BIDIWEAKSTATE_lt
+#define FX_BWScn	FX_BIDIWEAKSTATE_cn
+#define FX_BWSra	FX_BIDIWEAKSTATE_ra
+#define FX_BWSre	FX_BIDIWEAKSTATE_re
+#define FX_BWSla	FX_BIDIWEAKSTATE_la
+#define FX_BWSle	FX_BIDIWEAKSTATE_le
+#define FX_BWSac	FX_BIDIWEAKSTATE_ac
+#define FX_BWSrc	FX_BIDIWEAKSTATE_rc
+#define FX_BWSrs	FX_BIDIWEAKSTATE_rs
+#define FX_BWSlc	FX_BIDIWEAKSTATE_lc
+#define FX_BWSls	FX_BIDIWEAKSTATE_ls
+#define FX_BWSret	FX_BIDIWEAKSTATE_ret
+#define FX_BWSlet	FX_BIDIWEAKSTATE_let
+enum FX_BIDIWEAKACTION {
+    FX_BIDIWEAKACTION_IX = 0x100,
+    FX_BIDIWEAKACTION_XX = 0x0F,
+    FX_BIDIWEAKACTION_xxx = (0x0F << 4) + 0x0F,
+    FX_BIDIWEAKACTION_xIx = 0x100 + FX_BIDIWEAKACTION_xxx,
+    FX_BIDIWEAKACTION_xxN = (0x0F << 4) + FX_BIDICLASS_ON,
+    FX_BIDIWEAKACTION_xxE = (0x0F << 4) + FX_BIDICLASS_EN,
+    FX_BIDIWEAKACTION_xxA = (0x0F << 4) + FX_BIDICLASS_AN,
+    FX_BIDIWEAKACTION_xxR = (0x0F << 4) + FX_BIDICLASS_R,
+    FX_BIDIWEAKACTION_xxL = (0x0F << 4) + FX_BIDICLASS_L,
+    FX_BIDIWEAKACTION_Nxx = (FX_BIDICLASS_ON << 4) + 0x0F,
+    FX_BIDIWEAKACTION_Axx = (FX_BIDICLASS_AN << 4) + 0x0F,
+    FX_BIDIWEAKACTION_ExE = (FX_BIDICLASS_EN << 4) + FX_BIDICLASS_EN,
+    FX_BIDIWEAKACTION_NIx = (FX_BIDICLASS_ON << 4) + 0x0F + 0x100,
+    FX_BIDIWEAKACTION_NxN = (FX_BIDICLASS_ON << 4) + FX_BIDICLASS_ON,
+    FX_BIDIWEAKACTION_NxR = (FX_BIDICLASS_ON << 4) + FX_BIDICLASS_R,
+    FX_BIDIWEAKACTION_NxE = (FX_BIDICLASS_ON << 4) + FX_BIDICLASS_EN,
+    FX_BIDIWEAKACTION_AxA = (FX_BIDICLASS_AN << 4) + FX_BIDICLASS_AN,
+    FX_BIDIWEAKACTION_NxL = (FX_BIDICLASS_ON << 4) + FX_BIDICLASS_L,
+    FX_BIDIWEAKACTION_LxL = (FX_BIDICLASS_L << 4) + FX_BIDICLASS_L,
+    FX_BIDIWEAKACTION_xIL = (0x0F << 4) + FX_BIDICLASS_L + 0x100,
+    FX_BIDIWEAKACTION_AxR = (FX_BIDICLASS_AN << 4) + FX_BIDICLASS_R,
+    FX_BIDIWEAKACTION_Lxx = (FX_BIDICLASS_L << 4) + 0x0F,
+};
+#define FX_BWAIX	FX_BIDIWEAKACTION_IX
+#define FX_BWAXX	FX_BIDIWEAKACTION_XX
+#define FX_BWAxxx	FX_BIDIWEAKACTION_xxx
+#define FX_BWAxIx	FX_BIDIWEAKACTION_xIx
+#define FX_BWAxxN	FX_BIDIWEAKACTION_xxN
+#define FX_BWAxxE	FX_BIDIWEAKACTION_xxE
+#define FX_BWAxxA	FX_BIDIWEAKACTION_xxA
+#define FX_BWAxxR	FX_BIDIWEAKACTION_xxR
+#define FX_BWAxxL	FX_BIDIWEAKACTION_xxL
+#define FX_BWANxx	FX_BIDIWEAKACTION_Nxx
+#define FX_BWAAxx	FX_BIDIWEAKACTION_Axx
+#define FX_BWAExE	FX_BIDIWEAKACTION_ExE
+#define FX_BWANIx	FX_BIDIWEAKACTION_NIx
+#define FX_BWANxN	FX_BIDIWEAKACTION_NxN
+#define FX_BWANxR	FX_BIDIWEAKACTION_NxR
+#define FX_BWANxE	FX_BIDIWEAKACTION_NxE
+#define FX_BWAAxA	FX_BIDIWEAKACTION_AxA
+#define FX_BWANxL	FX_BIDIWEAKACTION_NxL
+#define FX_BWALxL	FX_BIDIWEAKACTION_LxL
+#define FX_BWAxIL	FX_BIDIWEAKACTION_xIL
+#define FX_BWAAxR	FX_BIDIWEAKACTION_AxR
+#define FX_BWALxx	FX_BIDIWEAKACTION_Lxx
+#define FX_BidiGetDeferredType(a)	(((a) >> 4) & 0x0F)
+#define FX_BidiGetResolvedType(a)	((a) & 0x0F)
+void FX_BidiResolveWeak(FX_INT32 iBaseLevel, CFX_Int32Array &classes, CFX_Int32Array &levels);
+enum FX_BIDINEUTRALSTATE {
+    FX_BIDINEUTRALSTATE_r = 0,
+    FX_BIDINEUTRALSTATE_l,
+    FX_BIDINEUTRALSTATE_rn,
+    FX_BIDINEUTRALSTATE_ln,
+    FX_BIDINEUTRALSTATE_a,
+    FX_BIDINEUTRALSTATE_na,
+};
+#define FX_BNSr		FX_BIDINEUTRALSTATE_r
+#define FX_BNSl		FX_BIDINEUTRALSTATE_l
+#define FX_BNSrn	FX_BIDINEUTRALSTATE_rn
+#define FX_BNSln	FX_BIDINEUTRALSTATE_ln
+#define FX_BNSa		FX_BIDINEUTRALSTATE_a
+#define FX_BNSna	FX_BIDINEUTRALSTATE_na
+enum FX_BIDINEUTRALACTION {
+    FX_BIDINEUTRALACTION_nL = FX_BIDICLASS_L,
+    FX_BIDINEUTRALACTION_En = (FX_BIDICLASS_AN << 4),
+    FX_BIDINEUTRALACTION_Rn = (FX_BIDICLASS_R << 4),
+    FX_BIDINEUTRALACTION_Ln = (FX_BIDICLASS_L << 4),
+    FX_BIDINEUTRALACTION_In = FX_BIDIWEAKACTION_IX,
+    FX_BIDINEUTRALACTION_LnL = (FX_BIDICLASS_L << 4) + FX_BIDICLASS_L,
+};
+#define FX_BNAnL	FX_BIDINEUTRALACTION_nL
+#define FX_BNAEn	FX_BIDINEUTRALACTION_En
+#define FX_BNARn	FX_BIDINEUTRALACTION_Rn
+#define FX_BNALn	FX_BIDINEUTRALACTION_Ln
+#define FX_BNAIn	FX_BIDINEUTRALACTION_In
+#define FX_BNALnL	FX_BIDINEUTRALACTION_LnL
+FX_INT32 FX_BidiGetDeferredNeutrals(FX_INT32 iAction, FX_INT32 iLevel);
+FX_INT32 FX_BidiGetResolvedNeutrals(FX_INT32 iAction);
+void FX_BidiResolveNeutrals(FX_INT32 iBaseLevel, CFX_Int32Array &classes, const CFX_Int32Array &levels);
+void FX_BidiResolveImplicit(const CFX_Int32Array &classes, CFX_Int32Array &levels);
+void FX_BidiResolveWhitespace(FX_INT32 iBaseLevel, const CFX_Int32Array &classes, CFX_Int32Array &levels);
+FX_INT32 FX_BidiReorderLevel(FX_INT32 iBaseLevel, CFX_WideString &wsText, const CFX_Int32Array &levels, FX_INT32 iStart, FX_BOOL bReverse = FALSE);
+void FX_BidiReorder(FX_INT32 iBaseLevel, CFX_WideString &wsText, const CFX_Int32Array &levels);
+class CFX_BidiChar : public IFX_BidiChar, public CFX_Object
 {
 public:
     CFX_BidiChar();
diff --git a/core/src/fxcrt/fx_extension.cpp b/core/src/fxcrt/fx_extension.cpp
index 7ff6b06..330c675 100644
--- a/core/src/fxcrt/fx_extension.cpp
+++ b/core/src/fxcrt/fx_extension.cpp
@@ -80,6 +80,18 @@
     FXSYS_assert(hFile != NULL);
     return ((IFXCRT_FileAccess*)hFile)->Truncate(szFile);
 }
+IFX_FileAccess* FX_CreateDefaultFileAccess(FX_WSTR wsPath)

+{

+	if (wsPath.GetLength() == 0)

+		return NULL;

+

+	CFX_CRTFileAccess* pFA = NULL;

+	pFA = FX_NEW CFX_CRTFileAccess;

+	if (NULL == pFA) return NULL;

+

+	pFA->Init(wsPath);

+	return pFA;

+}

 IFX_FileStream* FX_CreateFileStream(FX_LPCSTR filename, FX_DWORD dwModes)
 {
     IFXCRT_FileAccess* pFA = FXCRT_FileAccess_Create();
@@ -383,3 +395,40 @@
 #ifdef __cplusplus
 }
 #endif
+#ifdef __cplusplus

+extern "C" {

+#endif

+void FX_GUID_CreateV4(FX_LPGUID pGUID)

+{

+#if (_FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_)

+#ifdef _FX_WINAPI_PARTITION_DESKTOP_

+    if (!FX_GenerateCryptoRandom((FX_LPDWORD)pGUID, 4)) {

+        FX_Random_GenerateMT((FX_LPDWORD)pGUID, 4);

+    }

+#else

+    FX_Random_GenerateMT((FX_LPDWORD)pGUID, 4);

+#endif

+#else

+    FX_Random_GenerateMT((FX_LPDWORD)pGUID, 4);

+#endif

+    FX_BYTE &b = ((FX_LPBYTE)pGUID)[6];

+    b = (b & 0x0F) | 0x40;

+}

+FX_LPCSTR gs_FX_pHexChars = "0123456789ABCDEF";

+void FX_GUID_ToString(FX_LPCGUID pGUID, CFX_ByteString &bsStr, FX_BOOL bSeparator)

+{

+    FX_LPSTR pBuf = bsStr.GetBuffer(40);

+    FX_BYTE b;

+    for (FX_INT32 i = 0; i < 16; i ++) {

+        b = ((FX_LPCBYTE)pGUID)[i];

+        *pBuf ++ = gs_FX_pHexChars[b >> 4];

+        *pBuf ++ = gs_FX_pHexChars[b & 0x0F];

+        if (bSeparator && (i == 3 || i == 5 || i == 7 || i == 9)) {

+            *pBuf ++ = L'-';

+        }

+    }

+    bsStr.ReleaseBuffer(bSeparator ? 36 : 32);

+}

+#ifdef __cplusplus

+}

+#endif

diff --git a/core/src/fxcrt/fx_xml_parser.cpp b/core/src/fxcrt/fx_xml_parser.cpp
index 05fc7d5..bd418b2 100644
--- a/core/src/fxcrt/fx_xml_parser.cpp
+++ b/core/src/fxcrt/fx_xml_parser.cpp
@@ -672,7 +672,7 @@
     FX_XML_SplitQualifiedName(name, bsSpace, bsName);
     const CFX_WideString* pValue = m_AttrMap.Lookup(bsSpace, bsName);
     if (pValue) {
-        attribute = CFX_WideString((FX_LPCWSTR)pValue, pValue->GetLength());
+        attribute = CFX_WideString((FX_LPCWSTR)*pValue, pValue->GetLength());
         return TRUE;
     }
     return FALSE;
@@ -681,7 +681,7 @@
 {
     const CFX_WideString* pValue = m_AttrMap.Lookup(space, name);
     if (pValue) {
-        attribute = CFX_WideString((FX_LPCWSTR)pValue, pValue->GetLength());
+        attribute = CFX_WideString((FX_LPCWSTR)*pValue, pValue->GetLength());
         return TRUE;
     }
     return FALSE;
diff --git a/core/src/fxge/ge/fx_ge_font.cpp b/core/src/fxge/ge/fx_ge_font.cpp
index 817f371..e3c68e0 100644
--- a/core/src/fxge/ge/fx_ge_font.cpp
+++ b/core/src/fxge/ge/fx_ge_font.cpp
@@ -25,6 +25,52 @@
     m_pDwFont = NULL;
     m_hHandle = NULL;
     m_bDwLoaded = FALSE;
+    m_bLogic = FALSE;

+}

+FX_BOOL CFX_Font::LoadClone(const CFX_Font* pFont)

+{

+    if (pFont == NULL) {

+        return FALSE;

+    }

+    m_bLogic = TRUE;

+    if (pFont->m_pSubstFont) {

+        m_pSubstFont = FX_NEW CFX_SubstFont;

+        if (!m_pSubstFont) {

+            return FALSE;

+        }

+        m_pSubstFont->m_Charset = pFont->m_pSubstFont->m_Charset;

+        m_pSubstFont->m_ExtHandle = pFont->m_pSubstFont->m_ExtHandle;

+        m_pSubstFont->m_SubstFlags = pFont->m_pSubstFont->m_SubstFlags;

+        m_pSubstFont->m_Weight = pFont->m_pSubstFont->m_Weight;

+        m_pSubstFont->m_Family = pFont->m_pSubstFont->m_Family;

+        m_pSubstFont->m_ItalicAngle = pFont->m_pSubstFont->m_ItalicAngle;

+    }

+    if (pFont->m_OtfFontData.GetSize()) {

+        m_OtfFontData.AttachData(pFont->m_OtfFontData.GetBuffer(), pFont->m_OtfFontData.GetSize());

+    }

+    m_Face = pFont->m_Face;

+    m_bEmbedded = pFont->m_bEmbedded;

+    m_bVertical = pFont->m_bVertical;

+    m_dwSize = pFont->m_dwSize;

+    m_pFontData = pFont->m_pFontData;

+    m_pGsubData = pFont->m_pGsubData;

+#ifdef FOXIT_CHROME_BUILD

+    if (pFont->m_pFontDataAllocation) {

+        m_pFontDataAllocation = FX_Alloc(FX_BYTE, m_dwSize);

+        if (!m_pFontDataAllocation) {

+            return FALSE;

+        }

+        m_pFontData = m_pFontDataAllocation;

+        FXSYS_memcpy32(m_pFontDataAllocation, pFont->m_pFontDataAllocation, m_dwSize);

+    }

+#endif

+    m_pPlatformFont = pFont->m_pPlatformFont;

+    m_pPlatformFontCollection = pFont->m_pPlatformFontCollection;

+    m_pDwFont = pFont->m_pDwFont;

+    m_hHandle = pFont->m_hHandle;

+    m_bDwLoaded = pFont->m_bDwLoaded;

+    m_pOwnedStream = pFont->m_pOwnedStream;

+    return TRUE;

 }
 CFX_Font::~CFX_Font()
 {
@@ -38,6 +84,10 @@
         m_pFontDataAllocation = NULL;
     }
 #endif
+    if (m_bLogic) {

+        m_OtfFontData.DetachBuffer();

+        return;

+    }

     if (m_Face) {
 #ifdef FOXIT_CHROME_BUILD
         if (FXFT_Get_Face_External_Stream(m_Face)) {
@@ -108,7 +158,7 @@
     {
     }
 };
-FX_BOOL _LoadFile(FXFT_Library library, FXFT_Face* Face, IFX_FileRead* pFile, FXFT_Stream* stream)
+FX_BOOL _LoadFile(FXFT_Library library, FXFT_Face* Face, IFX_FileRead* pFile, FXFT_Stream* stream, FX_INT32 faceIndex = 0)

 {
     FXFT_Stream stream1 = (FXFT_Stream)FX_Alloc(FX_BYTE, sizeof (FXFT_StreamRec));
     if (!stream1) {
@@ -123,7 +173,7 @@
     FXFT_Open_Args args;
     args.flags = FT_OPEN_STREAM;
     args.stream = stream1;
-    if (FXFT_Open_Face(library, &args, 0, Face)) {
+    if (FXFT_Open_Face(library, &args, faceIndex, Face)) {

         FX_Free(stream1);
         return FALSE;
     }
@@ -132,19 +182,21 @@
     }
     return TRUE;
 }
-FX_BOOL CFX_Font::LoadFile(IFX_FileRead* pFile)
+FX_BOOL CFX_Font::LoadFile(IFX_FileRead* pFile, int nFaceIndex, int* pFaceCount)

 {
     m_bEmbedded = FALSE;
     FXFT_Library library;
-    if (CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary == NULL) {
+    if (CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary == NULL)

         FXFT_Init_FreeType(&CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary);
-    }
     library = CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary;
     FXFT_Stream stream = NULL;
-    if (!_LoadFile(library, &m_Face, pFile, &stream)) {
+    if (!_LoadFile(library, &m_Face, pFile, &stream, nFaceIndex))

         return FALSE;
-    }
+    if (pFaceCount)

+        *pFaceCount = (int)m_Face->num_faces;

+#ifndef FOXIT_CHROME_BUILD

     m_pOwnedStream = stream;
+#endif

     FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
     return TRUE;
 }
@@ -455,3 +507,168 @@
     pEncoding = FX_NEW CFX_UnicodeEncoding(pFont);
     return pEncoding;
 }
+CFX_FontEncodingEX::CFX_FontEncodingEX()

+{

+    m_pFont = NULL;

+    m_nEncodingID = FXFM_ENCODING_NONE;

+}

+FX_BOOL CFX_FontEncodingEX::Init(CFX_Font* pFont, FX_DWORD EncodingID)

+{

+    if (!pFont) {

+        return FALSE;

+    }

+    m_pFont = pFont;

+    m_nEncodingID = EncodingID;

+    return TRUE;

+}

+FX_DWORD CFX_FontEncodingEX::GlyphFromCharCode(FX_DWORD charcode)

+{

+    FXFT_Face face = m_pFont->m_Face;

+    FT_UInt nIndex = FXFT_Get_Char_Index(face, charcode);

+    if (nIndex > 0) {

+        return nIndex;

+    }

+    int nmaps = FXFT_Get_Face_CharmapCount(face);

+    int m = 0;

+    while (m < nmaps) {

+        int nEncodingID = FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[m++]);

+        if (m_nEncodingID == nEncodingID) {

+            continue;

+        }

+        int error = FXFT_Select_Charmap(face, nEncodingID);

+        if (error) {

+            continue;

+        }

+        nIndex = FXFT_Get_Char_Index(face, charcode);

+        if (nIndex > 0) {

+            m_nEncodingID = nEncodingID;

+            return nIndex;

+        }

+    }

+    FXFT_Select_Charmap(face, m_nEncodingID);

+    return 0;

+}

+CFX_WideString CFX_FontEncodingEX::UnicodeFromCharCode(FX_DWORD charcode) const

+{

+    if (m_nEncodingID == FXFM_ENCODING_UNICODE) {

+        return CFX_WideString((FX_WCHAR)charcode);

+    }

+    return CFX_WideString((FX_WCHAR)0);

+}

+FX_DWORD CFX_FontEncodingEX::CharCodeFromUnicode(FX_WCHAR Unicode) const

+{

+    if (m_nEncodingID == FXFM_ENCODING_UNICODE || m_nEncodingID == FXFM_ENCODING_MS_SYMBOL) {

+        return Unicode;

+    }

+    FXFT_Face face = m_pFont->m_Face;

+    int nmaps = FXFT_Get_Face_CharmapCount(face);

+    for (int i = 0; i < nmaps; i++) {

+        int nEncodingID = FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[i]);

+        if (nEncodingID == FXFM_ENCODING_UNICODE || nEncodingID == FXFM_ENCODING_MS_SYMBOL) {

+            return Unicode;

+        }

+    }

+    return -1;

+}

+FX_BOOL CFX_FontEncodingEX::IsUnicodeCompatible() const

+{

+    return m_nEncodingID == FXFM_ENCODING_UNICODE;

+}

+FX_DWORD CFX_FontEncodingEX::GlyphIndexFromName(FX_LPCSTR pStrName)

+{

+    FXFT_Face face = m_pFont->m_Face;

+    return FT_Get_Name_Index(face, (FT_String*)pStrName);

+}

+CFX_ByteString CFX_FontEncodingEX::NameFromGlyphIndex(FX_DWORD dwGlyphIndex)

+{

+    FXFT_Face face = m_pFont->m_Face;

+    CFX_ByteString glyphName("                ");

+    if (FT_HAS_GLYPH_NAMES(((FT_Face)face))) {

+        if (FT_Get_Glyph_Name((FT_Face)face, dwGlyphIndex, (FT_Pointer)(FX_LPCSTR)glyphName, 16)) {

+            glyphName.Empty();

+            return glyphName;

+        }

+        return glyphName;

+    } else {

+        return glyphName;

+    }

+}

+FX_DWORD CFX_FontEncodingEX::CharCodeFromGlyphIndex(FX_DWORD dwGlyphIndex)

+{

+    FXFT_Face face = m_pFont->GetFace();

+    FX_DWORD  charcode;

+    FT_UInt  gid;

+    charcode = FT_Get_First_Char((FT_Face)face, &gid);

+    while (gid != 0) {

+        if (dwGlyphIndex == gid) {

+            return charcode;

+        }

+        charcode = FT_Get_Next_Char((FT_Face)face, charcode, &gid);

+    }

+    int nmaps = FXFT_Get_Face_CharmapCount(face);

+    int m = 0;

+    while (m < nmaps) {

+        int nEncodingID = FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[m++]);

+        if (m_nEncodingID == nEncodingID) {

+            continue;

+        }

+        int error = FXFT_Select_Charmap(face, nEncodingID);

+        if (error) {

+            continue;

+        }

+        charcode = FT_Get_First_Char((FT_Face)face, &gid);

+        while (gid != 0) {

+            if (dwGlyphIndex == gid) {

+                m_nEncodingID = nEncodingID;

+                return charcode;

+            }

+            charcode = FT_Get_Next_Char((FT_Face)face, charcode, &gid);

+        }

+    }

+    return (FX_DWORD) - 1;

+}

+static const FX_DWORD gs_EncodingID[] = {

+    FXFM_ENCODING_MS_SYMBOL,

+    FXFM_ENCODING_UNICODE,

+    FXFM_ENCODING_MS_SJIS,

+    FXFM_ENCODING_MS_GB2312,

+    FXFM_ENCODING_MS_BIG5,

+    FXFM_ENCODING_MS_WANSUNG,

+    FXFM_ENCODING_MS_JOHAB,

+    FXFM_ENCODING_ADOBE_STANDARD,

+    FXFM_ENCODING_ADOBE_EXPERT,

+    FXFM_ENCODING_ADOBE_CUSTOM,

+    FXFM_ENCODING_ADOBE_LATIN_1,

+    FXFM_ENCODING_OLD_LATIN_2,

+    FXFM_ENCODING_APPLE_ROMAN

+};

+static IFX_FontEncodingEx* _FXFM_CreateFontEncoding(CFX_Font* pFont, FX_DWORD nEncodingID)

+{

+    int error = FXFT_Select_Charmap(pFont->m_Face, nEncodingID);

+    if (error) {

+        return NULL;

+    }

+    CFX_FontEncodingEX* pFontEncoding = FX_NEW CFX_FontEncodingEX;

+    if (pFontEncoding && !pFontEncoding->Init(pFont, nEncodingID)) {

+        delete pFontEncoding;

+        pFontEncoding = NULL;

+    }

+    return pFontEncoding;

+}

+IFX_FontEncodingEx* FX_CreateFontEncodingEx(CFX_Font* pFont, FX_DWORD nEncodingID)

+{

+    if (!pFont || !pFont->m_Face) {

+        return NULL;

+    }

+    if (nEncodingID != FXFM_ENCODING_NONE) {

+        return _FXFM_CreateFontEncoding(pFont, nEncodingID);

+    }

+    static int s_count = sizeof(gs_EncodingID) / sizeof(FX_DWORD);

+    for (int i = 0; i < s_count; i++) {

+        IFX_FontEncodingEx* pFontEncoding = _FXFM_CreateFontEncoding(pFont, gs_EncodingID[i]);

+        if (pFontEncoding) {

+            return pFontEncoding;

+        }

+    }

+    return NULL;

+}

diff --git a/core/src/fxge/ge/fx_ge_fontmap.cpp b/core/src/fxge/ge/fx_ge_fontmap.cpp
index a5fa644..fe790d8 100644
--- a/core/src/fxge/ge/fx_ge_fontmap.cpp
+++ b/core/src/fxge/ge/fx_ge_fontmap.cpp
@@ -1156,6 +1156,9 @@
         pSubstFont->m_SubstFlags |= FXFONT_SUBST_EXACT;
     }
     if (hFont == NULL) {
+        if (flags & FXFONT_EXACTMATCH) {

+            return NULL;

+        }

         if (bCJK) {
             if (italic_angle != 0) {
                 bItalic = TRUE;
@@ -1284,6 +1287,68 @@
     m_pFontInfo->DeleteFont(hFont);
     return face;
 }
+FXFT_Face CFX_FontMapper::FindSubstFontByUnicode(FX_DWORD dwUnicode, FX_DWORD flags, int weight, int italic_angle)

+{

+    if (m_pFontInfo == NULL) {

+        return NULL;

+    }

+    FX_BOOL bItalic = (flags & FXFONT_ITALIC) != 0;

+    int PitchFamily = 0;

+    if (flags & FXFONT_SERIF) {

+        PitchFamily |= FXFONT_FF_ROMAN;

+    }

+    if (flags & FXFONT_SCRIPT) {

+        PitchFamily |= FXFONT_FF_SCRIPT;

+    }

+    if (flags & FXFONT_FIXED_PITCH) {

+        PitchFamily |= FXFONT_FF_FIXEDPITCH;

+    }

+    void* hFont = m_pFontInfo->MapFontByUnicode(dwUnicode, weight, bItalic, PitchFamily);

+    if (hFont == NULL) {

+        return NULL;

+    }

+    FX_DWORD ttc_size = m_pFontInfo->GetFontData(hFont, 0x74746366, NULL, 0);

+    FX_DWORD font_size = m_pFontInfo->GetFontData(hFont, 0, NULL, 0);

+    if(font_size == 0 && ttc_size == 0) {

+        m_pFontInfo->DeleteFont(hFont);

+        return NULL;

+    }

+    FXFT_Face face = NULL;

+    if (ttc_size) {

+        FX_BYTE temp[1024];

+        m_pFontInfo->GetFontData(hFont, 0x74746366, temp, 1024);

+        FX_DWORD checksum = 0;

+        for (int i = 0; i < 256; i ++) {

+            checksum += ((FX_DWORD*)temp)[i];

+        }

+        FX_LPBYTE pFontData;

+        face = m_pFontMgr->GetCachedTTCFace(ttc_size, checksum, ttc_size - font_size, pFontData);

+        if (face == NULL) {

+            pFontData = FX_Alloc(FX_BYTE, ttc_size);

+            if (pFontData) {

+                m_pFontInfo->GetFontData(hFont, 0x74746366, pFontData, ttc_size);

+                face = m_pFontMgr->AddCachedTTCFace(ttc_size, checksum, pFontData, ttc_size,

+                                                    ttc_size - font_size);

+            }

+        }

+    } else {

+        CFX_ByteString SubstName;

+        m_pFontInfo->GetFaceName(hFont, SubstName);

+        FX_LPBYTE pFontData;

+        face = m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, pFontData);

+        if (face == NULL) {

+            pFontData = FX_Alloc(FX_BYTE, font_size);

+            if (!pFontData) {

+                m_pFontInfo->DeleteFont(hFont);

+                return NULL;

+            }

+            m_pFontInfo->GetFontData(hFont, 0, pFontData, font_size);

+            face = m_pFontMgr->AddCachedFace(SubstName, weight, bItalic, pFontData, font_size, m_pFontInfo->GetFaceIndex(hFont));

+        }

+    }

+    m_pFontInfo->DeleteFont(hFont);

+    return face;

+}

 extern "C" {
     unsigned long _FTStreamRead(FXFT_Stream stream, unsigned long offset,
                                 unsigned char* buffer, unsigned long count);
@@ -1483,6 +1548,10 @@
 {
     return NULL;
 }
+void* CFX_FolderFontInfo::MapFontByUnicode(FX_DWORD dwUnicode, int weight, FX_BOOL bItalic, int pitch_family)

+{

+    return NULL;

+}

 void* CFX_FolderFontInfo::GetFont(FX_LPCSTR face)
 {
     FX_LPVOID p;
diff --git a/core/src/fxge/ge/text_int.h b/core/src/fxge/ge/text_int.h
index c8d5596..e51976f 100644
--- a/core/src/fxge/ge/text_int.h
+++ b/core/src/fxge/ge/text_int.h
@@ -101,5 +101,24 @@
     int					m_PitchFamily;
     CFX_ByteString		m_FontTables;
 };
-
+class CFX_FontEncodingEX : public IFX_FontEncodingEx

+{

+public:

+    CFX_FontEncodingEX();

+    FX_BOOL			Init(CFX_Font* pFont, FX_DWORD EncodingID);

+    virtual FX_DWORD		GlyphIndexFromName(FX_LPCSTR pStrName);

+    virtual CFX_ByteString	NameFromGlyphIndex(FX_DWORD dwGlyphIndex);

+    virtual FX_DWORD		CharCodeFromGlyphIndex(FX_DWORD dwGlyphIndex);

+    virtual FX_DWORD		GlyphFromCharCode(FX_DWORD charcode);

+    virtual CFX_WideString	UnicodeFromCharCode(FX_DWORD charcode) const;

+    virtual FX_DWORD		CharCodeFromUnicode(FX_WCHAR Unicode) const;

+    virtual FX_BOOL			IsUnicodeCompatible() const;

+    virtual FX_DWORD		GlyphFromCharCodeEx(FX_DWORD charcode, int encoding = ENCODING_UNICODE)

+    {

+        return GlyphFromCharCode(charcode);

+    }

+private:

+    CFX_Font* m_pFont;

+    FX_DWORD m_nEncodingID;

+};

 #endif  // _TEXT_INT_H_