blob: eb18099fd6529537dbad25900635f7a2bbcda9fe [file] [log] [blame] [edit]
/** ************************************************************************* */
/* * For conditions of distribution and use, * */
/* * see copyright notice in libmng.h * */
/* ************************************************************************** */
/* * * */
/* * project : libmng * */
/* * file : libmng_chunk_io.c copyright (c) 2000-2007 G.Juyn * */
/* * version : 1.0.10 * */
/* * * */
/* * purpose : Chunk I/O routines (implementation) * */
/* * * */
/* * author : G.Juyn * */
/* * * */
/* * comment : implementation of chunk input/output routines * */
/* * * */
/* * changes : 0.5.1 - 05/01/2000 - G.Juyn * */
/* * - cleaned up left-over teststuff in the BACK chunk routine * */
/* * 0.5.1 - 05/04/2000 - G.Juyn * */
/* * - changed CRC initialization to use dynamic structure * */
/* * (wasn't thread-safe the old way !) * */
/* * 0.5.1 - 05/06/2000 - G.Juyn * */
/* * - filled in many missing sequence&length checks * */
/* * - filled in many missing chunk-store snippets * */
/* * 0.5.1 - 05/08/2000 - G.Juyn * */
/* * - added checks for running animations * */
/* * - filled some write routines * */
/* * - changed strict-ANSI stuff * */
/* * 0.5.1 - 05/10/2000 - G.Juyn * */
/* * - filled some more write routines * */
/* * 0.5.1 - 05/11/2000 - G.Juyn * */
/* * - filled remaining write routines * */
/* * - fixed read_pplt with regard to deltatype * */
/* * - added callback error-reporting support * */
/* * - added pre-draft48 support (short MHDR, frame_mode, LOOP) * */
/* * 0.5.1 - 05/12/2000 - G.Juyn * */
/* * - changed trace to macro for callback error-reporting * */
/* * - fixed chunk-storage bit in several routines * */
/* * 0.5.1 - 05/13/2000 - G.Juyn * */
/* * - added eMNGma hack (will be removed in 1.0.0 !!!) * */
/* * - added TERM animation object pointer (easier reference) * */
/* * - supplemented the SAVE & SEEK display processing * */
/* * * */
/* * 0.5.2 - 05/18/2000 - G.Juyn * */
/* * - B004 - fixed problem with MNG_SUPPORT_WRITE not defined * */
/* * also for MNG_SUPPORT_WRITE without MNG_INCLUDE_JNG * */
/* * 0.5.2 - 05/19/2000 - G.Juyn * */
/* * - cleaned up some code regarding mixed support * */
/* * 0.5.2 - 05/20/2000 - G.Juyn * */
/* * - implemented JNG support * */
/* * 0.5.2 - 05/24/2000 - G.Juyn * */
/* * - added support for global color-chunks in animation * */
/* * - added support for global PLTE,tRNS,bKGD in animation * */
/* * - added support for SAVE & SEEK in animation * */
/* * 0.5.2 - 05/29/2000 - G.Juyn * */
/* * - changed ani_create calls not returning object pointer * */
/* * - create ani objects always (not just inside TERM/LOOP) * */
/* * 0.5.2 - 05/30/2000 - G.Juyn * */
/* * - added support for delta-image processing * */
/* * 0.5.2 - 05/31/2000 - G.Juyn * */
/* * - fixed up punctuation (contributed by Tim Rowley) * */
/* * 0.5.2 - 06/02/2000 - G.Juyn * */
/* * - changed SWAP_ENDIAN to BIGENDIAN_SUPPORTED * */
/* * 0.5.2 - 06/03/2000 - G.Juyn * */
/* * - fixed makeup for Linux gcc compile * */
/* * * */
/* * 0.5.3 - 06/12/2000 - G.Juyn * */
/* * - added processing of color-info on delta-image * */
/* * 0.5.3 - 06/13/2000 - G.Juyn * */
/* * - fixed handling of empty SAVE chunk * */
/* * 0.5.3 - 06/17/2000 - G.Juyn * */
/* * - changed to support delta-images * */
/* * - added extra checks for delta-images * */
/* * 0.5.3 - 06/20/2000 - G.Juyn * */
/* * - fixed possible trouble if IEND display-process got * */
/* * broken up * */
/* * 0.5.3 - 06/21/2000 - G.Juyn * */
/* * - added processing of PLTE & tRNS for delta-images * */
/* * - added administration of imagelevel parameter * */
/* * 0.5.3 - 06/22/2000 - G.Juyn * */
/* * - implemented support for PPLT chunk * */
/* * 0.5.3 - 06/26/2000 - G.Juyn * */
/* * - added precaution against faulty iCCP chunks from PS * */
/* * 0.5.3 - 06/29/2000 - G.Juyn * */
/* * - fixed some 64-bit warnings * */
/* * * */
/* * 0.9.1 - 07/14/2000 - G.Juyn * */
/* * - changed pre-draft48 frame_mode=3 to frame_mode=1 * */
/* * 0.9.1 - 07/16/2000 - G.Juyn * */
/* * - fixed storage of images during mng_read() * */
/* * - fixed support for mng_display() after mng_read() * */
/* * 0.9.1 - 07/19/2000 - G.Juyn * */
/* * - fixed several chunk-writing routines * */
/* * 0.9.1 - 07/24/2000 - G.Juyn * */
/* * - fixed reading of still-images * */
/* * * */
/* * 0.9.2 - 08/05/2000 - G.Juyn * */
/* * - changed file-prefixes * */
/* * * */
/* * 0.9.3 - 08/07/2000 - G.Juyn * */
/* * - B111300 - fixup for improved portability * */
/* * 0.9.3 - 08/08/2000 - G.Juyn * */
/* * - fixed compiler-warnings from Mozilla * */
/* * 0.9.3 - 08/09/2000 - G.Juyn * */
/* * - added check for simplicity-bits in MHDR * */
/* * 0.9.3 - 08/12/2000 - G.Juyn * */
/* * - fixed check for simplicity-bits in MHDR (JNG) * */
/* * 0.9.3 - 08/12/2000 - G.Juyn * */
/* * - added workaround for faulty PhotoShop iCCP chunk * */
/* * 0.9.3 - 08/22/2000 - G.Juyn * */
/* * - fixed write-code for zTXt & iTXt * */
/* * - fixed read-code for iTXt * */
/* * 0.9.3 - 08/26/2000 - G.Juyn * */
/* * - added MAGN chunk * */
/* * 0.9.3 - 09/07/2000 - G.Juyn * */
/* * - added support for new filter_types * */
/* * 0.9.3 - 09/10/2000 - G.Juyn * */
/* * - fixed DEFI behavior * */
/* * 0.9.3 - 10/02/2000 - G.Juyn * */
/* * - fixed simplicity-check in compliance with draft 81/0.98a * */
/* * 0.9.3 - 10/10/2000 - G.Juyn * */
/* * - added support for alpha-depth prediction * */
/* * 0.9.3 - 10/11/2000 - G.Juyn * */
/* * - added support for nEED * */
/* * 0.9.3 - 10/16/2000 - G.Juyn * */
/* * - added support for JDAA * */
/* * 0.9.3 - 10/17/2000 - G.Juyn * */
/* * - fixed support for MAGN * */
/* * - implemented nEED "xxxx" (where "xxxx" is a chunkid) * */
/* * - added callback to process non-critical unknown chunks * */
/* * - fixed support for bKGD * */
/* * 0.9.3 - 10/23/2000 - G.Juyn * */
/* * - fixed bug in empty PLTE handling * */
/* * * */
/* * 0.9.4 - 11/20/2000 - G.Juyn * */
/* * - changed IHDR filter_method check for PNGs * */
/* * 0.9.4 - 1/18/2001 - G.Juyn * */
/* * - added errorchecking for MAGN methods * */
/* * - removed test filter-methods 1 & 65 * */
/* * * */
/* * 0.9.5 - 1/25/2001 - G.Juyn * */
/* * - fixed some small compiler warnings (thanks Nikki) * */
/* * * */
/* * 1.0.2 - 05/05/2000 - G.Juyn * */
/* * - B421427 - writes wrong format in bKGD and tRNS * */
/* * 1.0.2 - 06/20/2000 - G.Juyn * */
/* * - B434583 - compiler-warning if MNG_STORE_CHUNKS undefined * */
/* * * */
/* * 1.0.5 - 07/08/2002 - G.Juyn * */
/* * - B578572 - removed eMNGma hack (thanks Dimitri!) * */
/* * 1.0.5 - 08/07/2002 - G.Juyn * */
/* * - added test-option for PNG filter method 193 (=no filter) * */
/* * 1.0.5 - 08/15/2002 - G.Juyn * */
/* * - completed PROM support * */
/* * 1.0.5 - 08/19/2002 - G.Juyn * */
/* * - B597134 - libmng pollutes the linker namespace * */
/* * 1.0.5 - 09/07/2002 - G.Juyn * */
/* * - fixed reading of FRAM with just frame_mode and name * */
/* * 1.0.5 - 09/13/2002 - G.Juyn * */
/* * - fixed read/write of MAGN chunk * */
/* * 1.0.5 - 09/14/2002 - G.Juyn * */
/* * - added event handling for dynamic MNG * */
/* * 1.0.5 - 09/15/2002 - G.Juyn * */
/* * - fixed LOOP iteration=0 special case * */
/* * 1.0.5 - 09/19/2002 - G.Juyn * */
/* * - misplaced TERM is now treated as warning * */
/* * 1.0.5 - 09/20/2002 - G.Juyn * */
/* * - added support for PAST * */
/* * 1.0.5 - 10/03/2002 - G.Juyn * */
/* * - fixed chunk-storage for evNT chunk * */
/* * 1.0.5 - 10/07/2002 - G.Juyn * */
/* * - fixed DISC support * */
/* * - added another fix for misplaced TERM chunk * */
/* * 1.0.5 - 10/17/2002 - G.Juyn * */
/* * - fixed initializtion of pIds in dISC read routine * */
/* * 1.0.5 - 11/06/2002 - G.Juyn * */
/* * - added support for nEED "MNG 1.1" * */
/* * - added support for nEED "CACHEOFF" * */
/* * * */
/* * 1.0.6 - 05/25/2003 - G.R-P * */
/* * - added MNG_SKIPCHUNK_cHNK footprint optimizations * */
/* * 1.0.6 - 06/02/2003 - G.R-P * */
/* * - removed some redundant checks for iRawlen==0 * */
/* * 1.0.6 - 06/22/2003 - G.R-P * */
/* * - added MNG_NO_16BIT_SUPPORT, MNG_NO_DELTA_PNG reductions * */
/* * - optionally use zlib's crc32 function instead of * */
/* * local mng_update_crc * */
/* * 1.0.6 - 07/14/2003 - G.R-P * */
/* * - added MNG_NO_LOOP_SIGNALS_SUPPORTED conditional * */
/* * 1.0.6 - 07/29/2003 - G.R-P * */
/* * - added conditionals around PAST chunk support * */
/* * 1.0.6 - 08/17/2003 - G.R-P * */
/* * - added conditionals around non-VLC chunk support * */
/* * * */
/* * 1.0.7 - 10/29/2003 - G.R-P * */
/* * - revised JDAA and JDAT readers to avoid compiler bug * */
/* * 1.0.7 - 01/25/2004 - J.S * */
/* * - added premultiplied alpha canvas' for RGBA, ARGB, ABGR * */
/* * 1.0.7 - 01/27/2004 - J.S * */
/* * - fixed inclusion of IJNG chunk for non-JNG use * */
/* * 1.0.7 - 02/26/2004 - G.Juyn * */
/* * - fixed bug in chunk-storage of SHOW chunk (from == to) * */
/* * * */
/* * 1.0.8 - 04/02/2004 - G.Juyn * */
/* * - added CRC existence & checking flags * */
/* * 1.0.8 - 07/07/2004 - G.R-P * */
/* * - change worst-case iAlphadepth to 1 for standalone PNGs * */
/* * * */
/* * 1.0.9 - 09/28/2004 - G.R-P * */
/* * - improved handling of cheap transparency when 16-bit * */
/* * support is disabled * */
/* * 1.0.9 - 10/04/2004 - G.Juyn * */
/* * - fixed bug in writing sBIT for indexed color * */
/* * 1.0.9 - 10/10/2004 - G.R-P. * */
/* * - added MNG_NO_1_2_4BIT_SUPPORT * */
/* * 1.0.9 - 12/05/2004 - G.Juyn * */
/* * - added conditional MNG_OPTIMIZE_CHUNKINITFREE * */
/* * 1.0.9 - 12/06/2004 - G.Juyn * */
/* * - added conditional MNG_OPTIMIZE_CHUNKASSIGN * */
/* * 1.0.9 - 12/07/2004 - G.Juyn * */
/* * - added conditional MNG_OPTIMIZE_CHUNKREADER * */
/* * 1.0.9 - 12/11/2004 - G.Juyn * */
/* * - added conditional MNG_OPTIMIZE_DISPLAYCALLS * */
/* * 1.0.9 - 12/20/2004 - G.Juyn * */
/* * - cleaned up macro-invocations (thanks to D. Airlie) * */
/* * 1.0.9 - 01/17/2005 - G.Juyn * */
/* * - fixed problem with global PLTE/tRNS * */
/* * * */
/* * 1.0.10 - 02/07/2005 - G.Juyn * */
/* * - fixed display routines called twice for FULL_MNG * */
/* * support in mozlibmngconf.h * */
/* * 1.0.10 - 12/04/2005 - G.R-P. * */
/* * - #ifdef out use of mng_inflate_buffer when it is not * */
/* * available. * */
/* * 1.0.10 - 04/08/2007 - G.Juyn * */
/* * - added support for mPNG proposal * */
/* * 1.0.10 - 04/12/2007 - G.Juyn * */
/* * - added support for ANG proposal * */
/* * 1.0.10 - 05/02/2007 - G.Juyn * */
/* * - fixed inflate_buffer for extreme compression ratios * */
/* * * */
/* ************************************************************************** */
#include "libmng.h"
#include "libmng_data.h"
#include "libmng_error.h"
#include "libmng_trace.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "libmng_objects.h"
#include "libmng_object_prc.h"
#include "libmng_chunks.h"
#ifdef MNG_CHECK_BAD_ICCP
#include "libmng_chunk_prc.h"
#endif
#include "libmng_memory.h"
#include "libmng_display.h"
#include "libmng_zlib.h"
#include "libmng_pixels.h"
#include "libmng_chunk_io.h"
#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI)
#pragma option -A /* force ANSI-C */
#endif
/* ************************************************************************** */
/* * * */
/* * CRC - Cyclic Redundancy Check * */
/* * * */
/* * The code below is taken directly from the sample provided with the * */
/* * PNG specification. * */
/* * (it is only adapted to the library's internal data-definitions) * */
/* * * */
/* ************************************************************************** */
/* Make the table for a fast CRC. */
#ifndef MNG_USE_ZLIB_CRC
MNG_LOCAL void make_crc_table (mng_datap pData)
{
mng_uint32 iC;
mng_int32 iN, iK;
for (iN = 0; iN < 256; iN++)
{
iC = (mng_uint32) iN;
for (iK = 0; iK < 8; iK++)
{
if (iC & 1)
iC = 0xedb88320U ^ (iC >> 1);
else
iC = iC >> 1;
}
pData->aCRCtable [iN] = iC;
}
pData->bCRCcomputed = MNG_TRUE;
}
#endif
/* Update a running CRC with the bytes buf[0..len-1]--the CRC
should be initialized to all 1's, and the transmitted value
is the 1's complement of the final running CRC (see the
crc() routine below). */
MNG_LOCAL mng_uint32 update_crc (mng_datap pData,
mng_uint32 iCrc,
mng_uint8p pBuf,
mng_int32 iLen)
{
#ifdef MNG_USE_ZLIB_CRC
return crc32 (iCrc, pBuf, iLen);
#else
mng_uint32 iC = iCrc;
mng_int32 iN;
if (!pData->bCRCcomputed)
make_crc_table (pData);
for (iN = 0; iN < iLen; iN++)
iC = pData->aCRCtable [(iC ^ pBuf [iN]) & 0xff] ^ (iC >> 8);
return iC;
#endif
}
/* Return the CRC of the bytes buf[0..len-1]. */
mng_uint32 mng_crc (mng_datap pData,
mng_uint8p pBuf,
mng_int32 iLen)
{
#ifdef MNG_USE_ZLIB_CRC
return update_crc (pData, 0, pBuf, iLen);
#else
return update_crc (pData, 0xffffffffU, pBuf, iLen) ^ 0xffffffffU;
#endif
}
/* ************************************************************************** */
/* * * */
/* * Routines for swapping byte-order from and to graphic files * */
/* * (This code is adapted from the libpng package) * */
/* * * */
/* ************************************************************************** */
#ifndef MNG_BIGENDIAN_SUPPORTED
/* ************************************************************************** */
mng_uint32 mng_get_uint32 (mng_uint8p pBuf)
{
mng_uint32 i = ((mng_uint32)(*pBuf) << 24) +
((mng_uint32)(*(pBuf + 1)) << 16) +
((mng_uint32)(*(pBuf + 2)) << 8) +
(mng_uint32)(*(pBuf + 3));
return (i);
}
/* ************************************************************************** */
mng_int32 mng_get_int32 (mng_uint8p pBuf)
{
mng_int32 i = ((mng_int32)(*pBuf) << 24) +
((mng_int32)(*(pBuf + 1)) << 16) +
((mng_int32)(*(pBuf + 2)) << 8) +
(mng_int32)(*(pBuf + 3));
return (i);
}
/* ************************************************************************** */
mng_uint16 mng_get_uint16 (mng_uint8p pBuf)
{
mng_uint16 i = (mng_uint16)(((mng_uint16)(*pBuf) << 8) +
(mng_uint16)(*(pBuf + 1)));
return (i);
}
/* ************************************************************************** */
void mng_put_uint32 (mng_uint8p pBuf,
mng_uint32 i)
{
*pBuf = (mng_uint8)((i >> 24) & 0xff);
*(pBuf+1) = (mng_uint8)((i >> 16) & 0xff);
*(pBuf+2) = (mng_uint8)((i >> 8) & 0xff);
*(pBuf+3) = (mng_uint8)(i & 0xff);
}
/* ************************************************************************** */
void mng_put_int32 (mng_uint8p pBuf,
mng_int32 i)
{
*pBuf = (mng_uint8)((i >> 24) & 0xff);
*(pBuf+1) = (mng_uint8)((i >> 16) & 0xff);
*(pBuf+2) = (mng_uint8)((i >> 8) & 0xff);
*(pBuf+3) = (mng_uint8)(i & 0xff);
}
/* ************************************************************************** */
void mng_put_uint16 (mng_uint8p pBuf,
mng_uint16 i)
{
*pBuf = (mng_uint8)((i >> 8) & 0xff);
*(pBuf+1) = (mng_uint8)(i & 0xff);
}
/* ************************************************************************** */
#endif /* !MNG_BIGENDIAN_SUPPORTED */
/* ************************************************************************** */
/* * * */
/* * Helper routines to simplify chunk-data extraction * */
/* * * */
/* ************************************************************************** */
#ifdef MNG_INCLUDE_READ_PROCS
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
MNG_LOCAL mng_uint8p find_null (mng_uint8p pIn)
{
mng_uint8p pOut = pIn;
while (*pOut) /* the read_graphic routine has made sure there's */
pOut++; /* always at least 1 zero-byte in the buffer */
return pOut;
}
#endif
/* ************************************************************************** */
#if !defined(MNG_SKIPCHUNK_iCCP) || !defined(MNG_SKIPCHUNK_zTXt) || \
!defined(MNG_SKIPCHUNK_iTXt) || defined(MNG_INCLUDE_MPNG_PROPOSAL) || \
defined(MNG_INCLUDE_ANG_PROPOSAL)
mng_retcode mng_inflate_buffer (mng_datap pData,
mng_uint8p pInbuf,
mng_uint32 iInsize,
mng_uint8p *pOutbuf,
mng_uint32 *iOutsize,
mng_uint32 *iRealsize)
{
mng_retcode iRetcode = MNG_NOERROR;
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_INFLATE_BUFFER, MNG_LC_START);
#endif
if (iInsize) /* anything to do ? */
{
*iOutsize = iInsize * 3; /* estimate uncompressed size */
/* and allocate a temporary buffer */
MNG_ALLOC (pData, *pOutbuf, *iOutsize);
do
{
mngzlib_inflateinit (pData); /* initialize zlib */
/* let zlib know where to store the output */
pData->sZlib.next_out = *pOutbuf;
/* "size - 1" so we've got space for the
zero-termination of a possible string */
pData->sZlib.avail_out = *iOutsize - 1;
/* ok; let's inflate... */
iRetcode = mngzlib_inflatedata (pData, iInsize, pInbuf);
/* determine actual output size */
*iRealsize = (mng_uint32)pData->sZlib.total_out;
mngzlib_inflatefree (pData); /* zlib's done */
if (iRetcode == MNG_BUFOVERFLOW) /* not enough space ? */
{ /* then get some more */
MNG_FREEX (pData, *pOutbuf, *iOutsize);
*iOutsize = *iOutsize + *iOutsize;
MNG_ALLOC (pData, *pOutbuf, *iOutsize);
}
} /* repeat if we didn't have enough space */
while ((iRetcode == MNG_BUFOVERFLOW) &&
(*iOutsize < 200 * iInsize));
if (!iRetcode) /* if oke ? */
*((*pOutbuf) + *iRealsize) = 0; /* then put terminator zero */
}
else
{
*pOutbuf = 0; /* nothing to do; then there's no output */
*iOutsize = 0;
*iRealsize = 0;
}
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_INFLATE_BUFFER, MNG_LC_END);
#endif
return iRetcode;
}
#endif
/* ************************************************************************** */
#endif /* MNG_INCLUDE_READ_PROCS */
/* ************************************************************************** */
/* * * */
/* * Helper routines to simplify chunk writing * */
/* * * */
/* ************************************************************************** */
#ifdef MNG_INCLUDE_WRITE_PROCS
/* ************************************************************************** */
#if !defined(MNG_SKIPCHUNK_iCCP) || !defined(MNG_SKIPCHUNK_zTXt) || !defined(MNG_SKIPCHUNK_iTXt)
MNG_LOCAL mng_retcode deflate_buffer (mng_datap pData,
mng_uint8p pInbuf,
mng_uint32 iInsize,
mng_uint8p *pOutbuf,
mng_uint32 *iOutsize,
mng_uint32 *iRealsize)
{
mng_retcode iRetcode = MNG_NOERROR;
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_DEFLATE_BUFFER, MNG_LC_START);
#endif
if (iInsize) /* anything to do ? */
{
*iOutsize = (iInsize * 5) >> 2; /* estimate compressed size */
/* and allocate a temporary buffer */
MNG_ALLOC (pData, *pOutbuf, *iOutsize);
do
{
mngzlib_deflateinit (pData); /* initialize zlib */
/* let zlib know where to store the output */
pData->sZlib.next_out = *pOutbuf;
pData->sZlib.avail_out = *iOutsize;
/* ok; let's deflate... */
iRetcode = mngzlib_deflatedata (pData, iInsize, pInbuf);
/* determine actual output size */
*iRealsize = pData->sZlib.total_out;
mngzlib_deflatefree (pData); /* zlib's done */
if (iRetcode == MNG_BUFOVERFLOW) /* not enough space ? */
{ /* then get some more */
MNG_FREEX (pData, *pOutbuf, *iOutsize);
*iOutsize = *iOutsize + (iInsize >> 1);
MNG_ALLOC (pData, *pOutbuf, *iOutsize);
}
} /* repeat if we didn't have enough space */
while (iRetcode == MNG_BUFOVERFLOW);
}
else
{
*pOutbuf = 0; /* nothing to do; then there's no output */
*iOutsize = 0;
*iRealsize = 0;
}
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_DEFLATE_BUFFER, MNG_LC_END);
#endif
return iRetcode;
}
#endif
/* ************************************************************************** */
MNG_LOCAL mng_retcode write_raw_chunk (mng_datap pData,
mng_chunkid iChunkname,
mng_uint32 iRawlen,
mng_uint8p pRawdata)
{
mng_uint32 iCrc;
mng_uint32 iWritten;
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_WRITE_RAW_CHUNK, MNG_LC_START);
#endif
/* temporary buffer ? */
if ((pRawdata != 0) && (pRawdata != pData->pWritebuf+8))
{ /* store length & chunktype in default buffer */
mng_put_uint32 (pData->pWritebuf, iRawlen);
mng_put_uint32 (pData->pWritebuf+4, (mng_uint32)iChunkname);
if (pData->iCrcmode & MNG_CRC_OUTPUT)
{
if ((pData->iCrcmode & MNG_CRC_OUTPUT) == MNG_CRC_OUTPUT_GENERATE)
{ /* calculate the crc */
iCrc = update_crc (pData, 0xffffffffL, pData->pWritebuf+4, 4);
iCrc = update_crc (pData, iCrc, pRawdata, iRawlen) ^ 0xffffffffL;
} else {
iCrc = 0; /* dummy crc */
} /* store in default buffer */
mng_put_uint32 (pData->pWritebuf+8, iCrc);
}
/* write the length & chunktype */
if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, 8, &iWritten))
MNG_ERROR (pData, MNG_APPIOERROR);
if (iWritten != 8) /* disk full ? */
MNG_ERROR (pData, MNG_OUTPUTERROR);
/* write the temporary buffer */
if (!pData->fWritedata ((mng_handle)pData, pRawdata, iRawlen, &iWritten))
MNG_ERROR (pData, MNG_APPIOERROR);
if (iWritten != iRawlen) /* disk full ? */
MNG_ERROR (pData, MNG_OUTPUTERROR);
if (pData->iCrcmode & MNG_CRC_OUTPUT)
{ /* write the crc */
if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf+8, 4, &iWritten))
MNG_ERROR (pData, MNG_APPIOERROR);
if (iWritten != 4) /* disk full ? */
MNG_ERROR (pData, MNG_OUTPUTERROR);
}
}
else
{ /* prefix with length & chunktype */
mng_put_uint32 (pData->pWritebuf, iRawlen);
mng_put_uint32 (pData->pWritebuf+4, (mng_uint32)iChunkname);
if (pData->iCrcmode & MNG_CRC_OUTPUT)
{
if ((pData->iCrcmode & MNG_CRC_OUTPUT) == MNG_CRC_OUTPUT_GENERATE)
/* calculate the crc */
iCrc = mng_crc (pData, pData->pWritebuf+4, iRawlen + 4);
else
iCrc = 0; /* dummy crc */
/* add it to the buffer */
mng_put_uint32 (pData->pWritebuf + iRawlen + 8, iCrc);
/* write it in a single pass */
if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, iRawlen + 12, &iWritten))
MNG_ERROR (pData, MNG_APPIOERROR);
if (iWritten != iRawlen + 12) /* disk full ? */
MNG_ERROR (pData, MNG_OUTPUTERROR);
} else {
if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, iRawlen + 8, &iWritten))
MNG_ERROR (pData, MNG_APPIOERROR);
if (iWritten != iRawlen + 8) /* disk full ? */
MNG_ERROR (pData, MNG_OUTPUTERROR);
}
}
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_WRITE_RAW_CHUNK, MNG_LC_END);
#endif
return MNG_NOERROR;
}
/* ************************************************************************** */
/* B004 */
#endif /* MNG_INCLUDE_WRITE_PROCS */
/* B004 */
/* ************************************************************************** */
/* * * */
/* * chunk read functions * */
/* * * */
/* ************************************************************************** */
#ifdef MNG_INCLUDE_READ_PROCS
/* ************************************************************************** */
#ifdef MNG_OPTIMIZE_CHUNKREADER
/* ************************************************************************** */
MNG_LOCAL mng_retcode create_chunk_storage (mng_datap pData,
mng_chunkp pHeader,
mng_uint32 iRawlen,
mng_uint8p pRawdata,
mng_field_descp pField,
mng_uint16 iFields,
mng_chunkp* ppChunk,
mng_bool bWorkcopy)
{
mng_field_descp pTempfield = pField;
mng_uint16 iFieldcount = iFields;
mng_uint8p pTempdata = pRawdata;
mng_uint32 iTemplen = iRawlen;
mng_uint16 iLastgroup = 0;
mng_uint8p pChunkdata;
mng_uint32 iDatalen;
mng_uint8 iColortype;
mng_bool bProcess;
/* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
if (((mng_chunk_headerp)(*ppChunk))->iChunkname == MNG_UINT_HUH)
((mng_chunk_headerp)(*ppChunk))->iChunkname = pData->iChunkname;
if ((!bWorkcopy) ||
((((mng_chunk_headerp)pHeader)->iChunkname != MNG_UINT_IDAT) &&
(((mng_chunk_headerp)pHeader)->iChunkname != MNG_UINT_JDAT) &&
(((mng_chunk_headerp)pHeader)->iChunkname != MNG_UINT_JDAA) ))
{
pChunkdata = (mng_uint8p)(*ppChunk);
#ifdef MNG_INCLUDE_JNG /* determine current colortype */
if (pData->bHasJHDR)
iColortype = (mng_uint8)(pData->iJHDRcolortype - 8);
else
#endif /* MNG_INCLUDE_JNG */
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
iColortype = pData->iColortype;
else
iColortype = 6;
if (iTemplen) /* not empty ? */
{ /* then go fill the fields */
while ((iFieldcount) && (iTemplen))
{
if (pTempfield->iOffsetchunk)
{
if (pTempfield->iFlags & MNG_FIELD_PUTIMGTYPE)
{
*(pChunkdata+pTempfield->iOffsetchunk) = iColortype;
bProcess = MNG_FALSE;
}
else
if (pTempfield->iFlags & MNG_FIELD_IFIMGTYPES)
bProcess = (mng_bool)(((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE0) && (iColortype == 0)) ||
((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE2) && (iColortype == 2)) ||
((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE3) && (iColortype == 3)) ||
((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE4) && (iColortype == 4)) ||
((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE6) && (iColortype == 6)) );
else
bProcess = MNG_TRUE;
if (bProcess)
{
iLastgroup = (mng_uint16)(pTempfield->iFlags & MNG_FIELD_GROUPMASK);
/* numeric field ? */
if (pTempfield->iFlags & MNG_FIELD_INT)
{
if (iTemplen < pTempfield->iLengthmax)
MNG_ERROR (pData, MNG_INVALIDLENGTH);
switch (pTempfield->iLengthmax)
{
case 1 : { mng_uint8 iNum = *pTempdata;
if (((mng_uint16)iNum < pTempfield->iMinvalue) ||
((mng_uint16)iNum > pTempfield->iMaxvalue) )
MNG_ERROR (pData, MNG_INVALIDFIELDVAL);
*(pChunkdata+pTempfield->iOffsetchunk) = iNum;
break; }
case 2 : { mng_uint16 iNum = mng_get_uint16 (pTempdata);
if ((iNum < pTempfield->iMinvalue) || (iNum > pTempfield->iMaxvalue))
MNG_ERROR (pData, MNG_INVALIDFIELDVAL);
*((mng_uint16p)(pChunkdata+pTempfield->iOffsetchunk)) = iNum;
break; }
case 4 : { mng_uint32 iNum = mng_get_uint32 (pTempdata);
if ((iNum < pTempfield->iMinvalue) ||
((pTempfield->iFlags & MNG_FIELD_NOHIGHBIT) && (iNum & 0x80000000)) )
MNG_ERROR (pData, MNG_INVALIDFIELDVAL);
*((mng_uint32p)(pChunkdata+pTempfield->iOffsetchunk)) = iNum;
break; }
}
pTempdata += pTempfield->iLengthmax;
iTemplen -= pTempfield->iLengthmax;
} else { /* not numeric so it's a bunch of bytes */
if (!pTempfield->iOffsetchunklen) /* big fat NONO */
MNG_ERROR (pData, MNG_INTERNALERROR);
/* with terminating 0 ? */
if (pTempfield->iFlags & MNG_FIELD_TERMINATOR)
{
mng_uint8p pWork = pTempdata;
while (*pWork) /* find the zero */
pWork++;
iDatalen = (mng_uint32)(pWork - pTempdata);
} else { /* no terminator, so everything that's left ! */
iDatalen = iTemplen;
}
if ((pTempfield->iLengthmax) && (iDatalen > pTempfield->iLengthmax))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
#if !defined(MNG_SKIPCHUNK_iCCP) || !defined(MNG_SKIPCHUNK_zTXt) || \
!defined(MNG_SKIPCHUNK_iTXt) || defined(MNG_INCLUDE_MPNG_PROPOSAL) || \
defined(MNG_INCLUDE_ANG_PROPOSAL)
/* needs decompression ? */
if (pTempfield->iFlags & MNG_FIELD_DEFLATED)
{
mng_uint8p pBuf = 0;
mng_uint32 iBufsize = 0;
mng_uint32 iRealsize;
mng_ptr pWork;
iRetcode = mng_inflate_buffer (pData, pTempdata, iDatalen,
&pBuf, &iBufsize, &iRealsize);
#ifdef MNG_CHECK_BAD_ICCP /* Check for bad iCCP chunk */
if ((iRetcode) && (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_iCCP))
{
*((mng_ptr *)(pChunkdata+pTempfield->iOffsetchunk)) = MNG_NULL;
*((mng_uint32p)(pChunkdata+pTempfield->iOffsetchunklen)) = iDatalen;
}
else
#endif
{
if (iRetcode)
return iRetcode;
#if defined(MNG_INCLUDE_MPNG_PROPOSAL) || defined(MNG_INCLUDE_ANG_PROPOSAL)
if ( (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_mpNG) ||
(((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_adAT) )
{
MNG_ALLOC (pData, pWork, iRealsize);
}
else
{
#endif
/* don't forget to generate null terminator */
MNG_ALLOC (pData, pWork, iRealsize+1);
#if defined(MNG_INCLUDE_MPNG_PROPOSAL) || defined(MNG_INCLUDE_ANG_PROPOSAL)
}
#endif
MNG_COPY (pWork, pBuf, iRealsize);
*((mng_ptr *)(pChunkdata+pTempfield->iOffsetchunk)) = pWork;
*((mng_uint32p)(pChunkdata+pTempfield->iOffsetchunklen)) = iRealsize;
}
if (pBuf) /* free the temporary buffer */
MNG_FREEX (pData, pBuf, iBufsize);
} else
#endif
{ /* no decompression, so just copy */
mng_ptr pWork;
/* don't forget to generate null terminator */
MNG_ALLOC (pData, pWork, iDatalen+1);
MNG_COPY (pWork, pTempdata, iDatalen);
*((mng_ptr *)(pChunkdata+pTempfield->iOffsetchunk)) = pWork;
*((mng_uint32p)(pChunkdata+pTempfield->iOffsetchunklen)) = iDatalen;
}
if (pTempfield->iFlags & MNG_FIELD_TERMINATOR)
iDatalen++; /* skip the terminating zero as well !!! */
iTemplen -= iDatalen;
pTempdata += iDatalen;
}
/* need to set an indicator ? */
if (pTempfield->iOffsetchunkind)
*((mng_uint8p)(pChunkdata+pTempfield->iOffsetchunkind)) = MNG_TRUE;
}
}
if (pTempfield->pSpecialfunc) /* special function required ? */
{
iRetcode = pTempfield->pSpecialfunc(pData, *ppChunk, &iTemplen, &pTempdata);
if (iRetcode) /* on error bail out */
return iRetcode;
}
pTempfield++; /* Neeeeeeexxxtt */
iFieldcount--;
}
if (iTemplen) /* extra data ??? */
MNG_ERROR (pData, MNG_INVALIDLENGTH);
while (iFieldcount) /* not enough data ??? */
{
if (pTempfield->iFlags & MNG_FIELD_IFIMGTYPES)
bProcess = (mng_bool)(((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE0) && (iColortype == 0)) ||
((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE2) && (iColortype == 2)) ||
((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE3) && (iColortype == 3)) ||
((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE4) && (iColortype == 4)) ||
((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE6) && (iColortype == 6)) );
else
bProcess = MNG_TRUE;
if (bProcess)
{
if (!(pTempfield->iFlags & MNG_FIELD_OPTIONAL))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
if ((pTempfield->iFlags & MNG_FIELD_GROUPMASK) &&
((mng_uint16)(pTempfield->iFlags & MNG_FIELD_GROUPMASK) == iLastgroup))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
pTempfield++;
iFieldcount--;
}
}
}
return MNG_NOERROR;
}
/* ************************************************************************** */
READ_CHUNK (mng_read_general)
{
mng_retcode iRetcode = MNG_NOERROR;
mng_chunk_descp pDescr = ((mng_chunk_headerp)pHeader)->pChunkdescr;
mng_field_descp pField;
mng_uint16 iFields;
if (!pDescr) /* this is a bad booboo !!! */
MNG_ERROR (pData, MNG_INTERNALERROR);
pField = pDescr->pFielddesc;
iFields = pDescr->iFielddesc;
/* check chunk against signature */
if ((pDescr->eImgtype == mng_it_mng) && (pData->eSigtype != mng_it_mng))
MNG_ERROR (pData, MNG_CHUNKNOTALLOWED);
if ((pDescr->eImgtype == mng_it_jng) && (pData->eSigtype == mng_it_png))
MNG_ERROR (pData, MNG_CHUNKNOTALLOWED);
/* empties allowed ? */
if ((iRawlen == 0) && (!(pDescr->iAllowed & MNG_DESCR_EMPTY)))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
if ((pData->eImagetype != mng_it_mng) || (!(pDescr->iAllowed & MNG_DESCR_GLOBAL)))
{ /* *a* header required ? */
if ((pDescr->iMusthaves & MNG_DESCR_GenHDR) &&
#ifdef MNG_INCLUDE_JNG
(!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
(!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR))
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pDescr->iMusthaves & MNG_DESCR_JngHDR) &&
(!pData->bHasDHDR) && (!pData->bHasJHDR))
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#endif
}
/* specific chunk pre-requisite ? */
if (((pDescr->iMusthaves & MNG_DESCR_IHDR) && (!pData->bHasIHDR)) ||
#ifdef MNG_INCLUDE_JNG
((pDescr->iMusthaves & MNG_DESCR_JHDR) && (!pData->bHasJHDR)) ||
#endif
((pDescr->iMusthaves & MNG_DESCR_DHDR) && (!pData->bHasDHDR)) ||
((pDescr->iMusthaves & MNG_DESCR_LOOP) && (!pData->bHasLOOP)) ||
((pDescr->iMusthaves & MNG_DESCR_PLTE) && (!pData->bHasPLTE)) ||
((pDescr->iMusthaves & MNG_DESCR_MHDR) && (!pData->bHasMHDR)) ||
((pDescr->iMusthaves & MNG_DESCR_SAVE) && (!pData->bHasSAVE)) )
MNG_ERROR (pData, MNG_SEQUENCEERROR);
/* specific chunk undesired ? */
if (((pDescr->iMustNOThaves & MNG_DESCR_NOIHDR) && (pData->bHasIHDR)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOBASI) && (pData->bHasBASI)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NODHDR) && (pData->bHasDHDR)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOIDAT) && (pData->bHasIDAT)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOPLTE) && (pData->bHasPLTE)) ||
#ifdef MNG_INCLUDE_JNG
((pDescr->iMustNOThaves & MNG_DESCR_NOJHDR) && (pData->bHasJHDR)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOJDAT) && (pData->bHasJDAT)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOJDAA) && (pData->bHasJDAA)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOJSEP) && (pData->bHasJSEP)) ||
#endif
((pDescr->iMustNOThaves & MNG_DESCR_NOMHDR) && (pData->bHasMHDR)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOLOOP) && (pData->bHasLOOP)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOTERM) && (pData->bHasTERM)) ||
((pDescr->iMustNOThaves & MNG_DESCR_NOSAVE) && (pData->bHasSAVE)) )
MNG_ERROR (pData, MNG_SEQUENCEERROR);
if (pData->eSigtype == mng_it_mng) /* check global and embedded empty chunks */
{
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{
if ((iRawlen == 0) && (!(pDescr->iAllowed & MNG_DESCR_EMPTYEMBED)))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
} else {
if ((iRawlen == 0) && (!(pDescr->iAllowed & MNG_DESCR_EMPTYGLOBAL)))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
}
if (pDescr->pSpecialfunc) /* need special processing ? */
{
iRetcode = create_chunk_storage (pData, pHeader, iRawlen, pRawdata,
pField, iFields, ppChunk, MNG_TRUE);
if (iRetcode) /* on error bail out */
return iRetcode;
/* empty indicator ? */
if ((!iRawlen) && (pDescr->iOffsetempty))
*(((mng_uint8p)*ppChunk)+pDescr->iOffsetempty) = MNG_TRUE;
iRetcode = pDescr->pSpecialfunc(pData, *ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
if ((((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_IDAT) ||
(((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAT) ||
(((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAA) )
{
iRetcode = ((mng_chunk_headerp)*ppChunk)->fCleanup (pData, *ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
*ppChunk = MNG_NULL;
} else {
#ifdef MNG_STORE_CHUNKS
if (!pData->bStorechunks)
#endif
{
iRetcode = ((mng_chunk_headerp)*ppChunk)->fCleanup (pData, *ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
*ppChunk = MNG_NULL;
}
}
}
#ifdef MNG_SUPPORT_DISPLAY
if (iRawlen)
{
#ifdef MNG_OPTIMIZE_DISPLAYCALLS
pData->iRawlen = iRawlen;
pData->pRawdata = pRawdata;
#endif
/* display processing */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_IDAT)
iRetcode = mng_process_display_idat (pData, iRawlen, pRawdata);
#ifdef MNG_INCLUDE_JNG
else
if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAT)
iRetcode = mng_process_display_jdat (pData, iRawlen, pRawdata);
else
if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAA)
iRetcode = mng_process_display_jdaa (pData, iRawlen, pRawdata);
#endif
#else
if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_IDAT)
iRetcode = mng_process_display_idat (pData);
#ifdef MNG_INCLUDE_JNG
else
if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAT)
iRetcode = mng_process_display_jdat (pData);
else
if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAA)
iRetcode = mng_process_display_jdaa (pData);
#endif
#endif
if (iRetcode)
return iRetcode;
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if ((pData->bStorechunks) && (!(*ppChunk)))
{
iRetcode = create_chunk_storage (pData, pHeader, iRawlen, pRawdata,
pField, iFields, ppChunk, MNG_FALSE);
if (iRetcode) /* on error bail out */
return iRetcode;
/* empty indicator ? */
if ((!iRawlen) && (pDescr->iOffsetempty))
*(((mng_uint8p)*ppChunk)+pDescr->iOffsetempty) = MNG_TRUE;
}
#endif /* MNG_STORE_CHUNKS */
return MNG_NOERROR;
}
/* ************************************************************************** */
#endif /* MNG_OPTIMIZE_CHUNKREADER */
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
READ_CHUNK (mng_read_ihdr)
{
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_IHDR, MNG_LC_START);
#endif
if (iRawlen != 13) /* length oke ? */
MNG_ERROR (pData, MNG_INVALIDLENGTH);
/* only allowed inside PNG or MNG */
if ((pData->eSigtype != mng_it_png) && (pData->eSigtype != mng_it_mng))
MNG_ERROR (pData, MNG_CHUNKNOTALLOWED);
/* sequence checks */
if ((pData->eSigtype == mng_it_png) && (pData->iChunkseq > 1))
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasIDAT) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasIDAT))
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
pData->bHasIHDR = MNG_TRUE; /* indicate IHDR is present */
/* and store interesting fields */
if ((!pData->bHasDHDR) || (pData->iDeltatype == MNG_DELTATYPE_NOCHANGE))
{
pData->iDatawidth = mng_get_uint32 (pRawdata);
pData->iDataheight = mng_get_uint32 (pRawdata+4);
}
pData->iBitdepth = *(pRawdata+8);
pData->iColortype = *(pRawdata+9);
pData->iCompression = *(pRawdata+10);
pData->iFilter = *(pRawdata+11);
pData->iInterlace = *(pRawdata+12);
#if defined(MNG_NO_1_2_4BIT_SUPPORT) || defined(MNG_NO_16BIT_SUPPORT)
pData->iPNGmult = 1;
pData->iPNGdepth = pData->iBitdepth;
#endif
#ifdef MNG_NO_1_2_4BIT_SUPPORT
if (pData->iBitdepth < 8)
pData->iBitdepth = 8;
#endif
#ifdef MNG_NO_16BIT_SUPPORT
if (pData->iBitdepth > 8)
{
pData->iBitdepth = 8;
pData->iPNGmult = 2;
}
#endif
if ((pData->iBitdepth != 8) /* parameter validity checks */
#ifndef MNG_NO_1_2_4BIT_SUPPORT
&& (pData->iBitdepth != 1) &&
(pData->iBitdepth != 2) &&
(pData->iBitdepth != 4)
#endif
#ifndef MNG_NO_16BIT_SUPPORT
&& (pData->iBitdepth != 16)
#endif
)
MNG_ERROR (pData, MNG_INVALIDBITDEPTH);
if ((pData->iColortype != MNG_COLORTYPE_GRAY ) &&
(pData->iColortype != MNG_COLORTYPE_RGB ) &&
(pData->iColortype != MNG_COLORTYPE_INDEXED) &&
(pData->iColortype != MNG_COLORTYPE_GRAYA ) &&
(pData->iColortype != MNG_COLORTYPE_RGBA ) )
MNG_ERROR (pData, MNG_INVALIDCOLORTYPE);
if ((pData->iColortype == MNG_COLORTYPE_INDEXED) && (pData->iBitdepth > 8))
MNG_ERROR (pData, MNG_INVALIDBITDEPTH);
if (((pData->iColortype == MNG_COLORTYPE_RGB ) ||
(pData->iColortype == MNG_COLORTYPE_GRAYA ) ||
(pData->iColortype == MNG_COLORTYPE_RGBA ) ) &&
(pData->iBitdepth < 8 ) )
MNG_ERROR (pData, MNG_INVALIDBITDEPTH);
if (pData->iCompression != MNG_COMPRESSION_DEFLATE)
MNG_ERROR (pData, MNG_INVALIDCOMPRESS);
#if defined(FILTER192) || defined(FILTER193)
if ((pData->iFilter != MNG_FILTER_ADAPTIVE ) &&
#if defined(FILTER192) && defined(FILTER193)
(pData->iFilter != MNG_FILTER_DIFFERING) &&
(pData->iFilter != MNG_FILTER_NOFILTER ) )
#else
#ifdef FILTER192
(pData->iFilter != MNG_FILTER_DIFFERING) )
#else
(pData->iFilter != MNG_FILTER_NOFILTER ) )
#endif
#endif
MNG_ERROR (pData, MNG_INVALIDFILTER);
#else
if (pData->iFilter)
MNG_ERROR (pData, MNG_INVALIDFILTER);
#endif
if ((pData->iInterlace != MNG_INTERLACE_NONE ) &&
(pData->iInterlace != MNG_INTERLACE_ADAM7) )
MNG_ERROR (pData, MNG_INVALIDINTERLACE);
#ifdef MNG_SUPPORT_DISPLAY
#ifndef MNG_NO_DELTA_PNG
if (pData->bHasDHDR) /* check the colortype for delta-images ! */
{
mng_imagedatap pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf;
if (pData->iColortype != pBuf->iColortype)
{
if ( ( (pData->iColortype != MNG_COLORTYPE_INDEXED) ||
(pBuf->iColortype == MNG_COLORTYPE_GRAY ) ) &&
( (pData->iColortype != MNG_COLORTYPE_GRAY ) ||
(pBuf->iColortype == MNG_COLORTYPE_INDEXED) ) )
MNG_ERROR (pData, MNG_INVALIDCOLORTYPE);
}
}
#endif
#endif
if (!pData->bHasheader) /* first chunk ? */
{
pData->bHasheader = MNG_TRUE; /* we've got a header */
pData->eImagetype = mng_it_png; /* then this must be a PNG */
pData->iWidth = pData->iDatawidth;
pData->iHeight = pData->iDataheight;
/* predict alpha-depth ! */
if ((pData->iColortype == MNG_COLORTYPE_GRAYA ) ||
(pData->iColortype == MNG_COLORTYPE_RGBA ) )
pData->iAlphadepth = pData->iBitdepth;
else
if (pData->iColortype == MNG_COLORTYPE_INDEXED)
pData->iAlphadepth = 8; /* worst case scenario */
else
pData->iAlphadepth = 1; /* Possible tRNS cheap binary transparency */
/* fits on maximum canvas ? */
if ((pData->iWidth > pData->iMaxwidth) || (pData->iHeight > pData->iMaxheight))
MNG_WARNING (pData, MNG_IMAGETOOLARGE);
#if !defined(MNG_INCLUDE_MPNG_PROPOSAL) || !defined(MNG_SUPPORT_DISPLAY)
if (pData->fProcessheader) /* inform the app ? */
if (!pData->fProcessheader (((mng_handle)pData), pData->iWidth, pData->iHeight))
MNG_ERROR (pData, MNG_APPMISCERROR);
#endif
}
if (!pData->bHasDHDR)
pData->iImagelevel++; /* one level deeper */
#ifdef MNG_SUPPORT_DISPLAY
{
mng_retcode iRetcode = mng_process_display_ihdr (pData);
if (iRetcode) /* on error bail out */
return iRetcode;
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
/* fill the fields */
((mng_ihdrp)*ppChunk)->iWidth = mng_get_uint32 (pRawdata);
((mng_ihdrp)*ppChunk)->iHeight = mng_get_uint32 (pRawdata+4);
((mng_ihdrp)*ppChunk)->iBitdepth = pData->iBitdepth;
((mng_ihdrp)*ppChunk)->iColortype = pData->iColortype;
((mng_ihdrp)*ppChunk)->iCompression = pData->iCompression;
((mng_ihdrp)*ppChunk)->iFilter = pData->iFilter;
((mng_ihdrp)*ppChunk)->iInterlace = pData->iInterlace;
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_IHDR, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif /* MNG_OPTIMIZE_CHUNKREADER */
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
READ_CHUNK (mng_read_plte)
{
#if defined(MNG_SUPPORT_DISPLAY) || defined(MNG_STORE_CHUNKS)
mng_uint32 iX;
mng_uint8p pRawdata2;
#endif
#ifdef MNG_SUPPORT_DISPLAY
mng_uint32 iRawlen2;
#endif
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_PLTE, MNG_LC_START);
#endif
/* sequence checks */
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIDAT) || (pData->bHasJHDR))
#else
if (pData->bHasIDAT)
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
/* multiple PLTE only inside BASI */
if ((pData->bHasPLTE) && (!pData->bHasBASI))
MNG_ERROR (pData, MNG_MULTIPLEERROR);
/* length must be multiple of 3 */
if (((iRawlen % 3) != 0) || (iRawlen > 768))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
{ /* only allowed for indexed-color or
rgb(a)-color! */
if ((pData->iColortype != 2) && (pData->iColortype != 3) && (pData->iColortype != 6))
MNG_ERROR (pData, MNG_CHUNKNOTALLOWED);
/* empty only allowed if global present */
if ((iRawlen == 0) && (!pData->bHasglobalPLTE))
MNG_ERROR (pData, MNG_CANNOTBEEMPTY);
}
else
{
if (iRawlen == 0) /* cannot be empty as global! */
MNG_ERROR (pData, MNG_CANNOTBEEMPTY);
}
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
pData->bHasPLTE = MNG_TRUE; /* got it! */
else
pData->bHasglobalPLTE = MNG_TRUE;
pData->iPLTEcount = iRawlen / 3;
#ifdef MNG_SUPPORT_DISPLAY
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
{
mng_imagep pImage;
mng_imagedatap pBuf;
#ifndef MNG_NO_DELTA_PNG
if (pData->bHasDHDR) /* processing delta-image ? */
{ /* store in object 0 !!! */
pImage = (mng_imagep)pData->pObjzero;
pBuf = pImage->pImgbuf;
pBuf->bHasPLTE = MNG_TRUE; /* it's definitely got a PLTE now */
pBuf->iPLTEcount = iRawlen / 3; /* this is the exact length */
pRawdata2 = pRawdata; /* copy the entries */
for (iX = 0; iX < iRawlen / 3; iX++)
{
pBuf->aPLTEentries[iX].iRed = *pRawdata2;
pBuf->aPLTEentries[iX].iGreen = *(pRawdata2+1);
pBuf->aPLTEentries[iX].iBlue = *(pRawdata2+2);
pRawdata2 += 3;
}
}
else
#endif
{ /* get the current object */
pImage = (mng_imagep)pData->pCurrentobj;
if (!pImage) /* no object then dump it in obj 0 */
pImage = (mng_imagep)pData->pObjzero;
pBuf = pImage->pImgbuf; /* address the object buffer */
pBuf->bHasPLTE = MNG_TRUE; /* and tell it it's got a PLTE now */
if (!iRawlen) /* if empty, inherit from global */
{
pBuf->iPLTEcount = pData->iGlobalPLTEcount;
MNG_COPY (pBuf->aPLTEentries, pData->aGlobalPLTEentries,
sizeof (pBuf->aPLTEentries));
if (pData->bHasglobalTRNS) /* also copy global tRNS ? */
{ /* indicate tRNS available */
pBuf->bHasTRNS = MNG_TRUE;
iRawlen2 = pData->iGlobalTRNSrawlen;
pRawdata2 = (mng_uint8p)(pData->aGlobalTRNSrawdata);
/* global length oke ? */
if ((iRawlen2 == 0) || (iRawlen2 > pBuf->iPLTEcount))
MNG_ERROR (pData, MNG_GLOBALLENGTHERR);
/* copy it */
pBuf->iTRNScount = iRawlen2;
MNG_COPY (pBuf->aTRNSentries, pRawdata2, iRawlen2);
}
}
else
{ /* store fields for future reference */
pBuf->iPLTEcount = iRawlen / 3;
pRawdata2 = pRawdata;
for (iX = 0; iX < pBuf->iPLTEcount; iX++)
{
pBuf->aPLTEentries[iX].iRed = *pRawdata2;
pBuf->aPLTEentries[iX].iGreen = *(pRawdata2+1);
pBuf->aPLTEentries[iX].iBlue = *(pRawdata2+2);
pRawdata2 += 3;
}
}
}
}
else /* store as global */
{
pData->iGlobalPLTEcount = iRawlen / 3;
pRawdata2 = pRawdata;
for (iX = 0; iX < pData->iGlobalPLTEcount; iX++)
{
pData->aGlobalPLTEentries[iX].iRed = *pRawdata2;
pData->aGlobalPLTEentries[iX].iGreen = *(pRawdata2+1);
pData->aGlobalPLTEentries[iX].iBlue = *(pRawdata2+2);
pRawdata2 += 3;
}
{ /* create an animation object */
mng_retcode iRetcode = mng_create_ani_plte (pData, pData->iGlobalPLTEcount,
pData->aGlobalPLTEentries);
if (iRetcode) /* on error bail out */
return iRetcode;
}
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
/* store the fields */
((mng_pltep)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0);
((mng_pltep)*ppChunk)->iEntrycount = iRawlen / 3;
pRawdata2 = pRawdata;
for (iX = 0; iX < ((mng_pltep)*ppChunk)->iEntrycount; iX++)
{
((mng_pltep)*ppChunk)->aEntries[iX].iRed = *pRawdata2;
((mng_pltep)*ppChunk)->aEntries[iX].iGreen = *(pRawdata2+1);
((mng_pltep)*ppChunk)->aEntries[iX].iBlue = *(pRawdata2+2);
pRawdata2 += 3;
}
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_PLTE, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif /* MNG_OPTIMIZE_CHUNKREADER */
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
READ_CHUNK (mng_read_idat)
{
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_IDAT, MNG_LC_START);
#endif
#ifdef MNG_INCLUDE_JNG /* sequence checks */
if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR))
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasJHDR) &&
(pData->iJHDRalphacompression != MNG_COMPRESSION_DEFLATE))
MNG_ERROR (pData, MNG_SEQUENCEERROR);
if (pData->bHasJSEP)
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#endif
/* not allowed for deltatype NO_CHANGE */
#ifndef MNG_NO_DELTA_PNG
if ((pData->bHasDHDR) && ((pData->iDeltatype == MNG_DELTATYPE_NOCHANGE)))
MNG_ERROR (pData, MNG_CHUNKNOTALLOWED);
#endif
/* can only be empty in BASI-block! */
if ((iRawlen == 0) && (!pData->bHasBASI))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
/* indexed-color requires PLTE */
if ((pData->bHasIHDR) && (pData->iColortype == 3) && (!pData->bHasPLTE))
MNG_ERROR (pData, MNG_PLTEMISSING);
pData->bHasIDAT = MNG_TRUE; /* got some IDAT now, don't we */
#ifdef MNG_SUPPORT_DISPLAY
if (iRawlen)
{ /* display processing */
mng_retcode iRetcode = mng_process_display_idat (pData, iRawlen, pRawdata);
if (iRetcode) /* on error bail out */
return iRetcode;
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
/* store the fields */
((mng_idatp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0);
((mng_idatp)*ppChunk)->iDatasize = iRawlen;
if (iRawlen != 0) /* is there any data ? */
{
MNG_ALLOC (pData, ((mng_idatp)*ppChunk)->pData, iRawlen);
MNG_COPY (((mng_idatp)*ppChunk)->pData, pRawdata, iRawlen);
}
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_IDAT, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
READ_CHUNK (mng_read_iend)
{
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_IEND, MNG_LC_START);
#endif
if (iRawlen > 0) /* must not contain data! */
MNG_ERROR (pData, MNG_INVALIDLENGTH);
#ifdef MNG_INCLUDE_JNG /* sequence checks */
if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR))
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
/* IHDR-block requires IDAT */
if ((pData->bHasIHDR) && (!pData->bHasIDAT))
MNG_ERROR (pData, MNG_IDATMISSING);
pData->iImagelevel--; /* one level up */
#ifdef MNG_SUPPORT_DISPLAY
{ /* create an animation object */
mng_retcode iRetcode = mng_create_ani_image (pData);
if (iRetcode) /* on error bail out */
return iRetcode;
/* display processing */
iRetcode = mng_process_display_iend (pData);
if (iRetcode) /* on error bail out */
return iRetcode;
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_SUPPORT_DISPLAY
if (!pData->bTimerset) /* reset only if not broken !!! */
{
#endif
/* IEND signals the end for most ... */
pData->bHasIHDR = MNG_FALSE;
pData->bHasBASI = MNG_FALSE;
pData->bHasDHDR = MNG_FALSE;
#ifdef MNG_INCLUDE_JNG
pData->bHasJHDR = MNG_FALSE;
pData->bHasJSEP = MNG_FALSE;
pData->bHasJDAA = MNG_FALSE;
pData->bHasJDAT = MNG_FALSE;
#endif
pData->bHasPLTE = MNG_FALSE;
pData->bHasTRNS = MNG_FALSE;
pData->bHasGAMA = MNG_FALSE;
pData->bHasCHRM = MNG_FALSE;
pData->bHasSRGB = MNG_FALSE;
pData->bHasICCP = MNG_FALSE;
pData->bHasBKGD = MNG_FALSE;
pData->bHasIDAT = MNG_FALSE;
#ifdef MNG_SUPPORT_DISPLAY
}
#endif
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_IEND, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
READ_CHUNK (mng_read_trns)
{
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_TRNS, MNG_LC_START);
#endif
/* sequence checks */
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIDAT) || (pData->bHasJHDR))
#else
if (pData->bHasIDAT)
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
/* multiple tRNS only inside BASI */
if ((pData->bHasTRNS) && (!pData->bHasBASI))
MNG_ERROR (pData, MNG_MULTIPLEERROR);
if (iRawlen > 256) /* it just can't be bigger than that! */
MNG_ERROR (pData, MNG_INVALIDLENGTH);
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
{ /* not allowed with full alpha-channel */
if ((pData->iColortype == 4) || (pData->iColortype == 6))
MNG_ERROR (pData, MNG_CHUNKNOTALLOWED);
if (iRawlen != 0) /* filled ? */
{ /* length checks */
if ((pData->iColortype == 0) && (iRawlen != 2))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
if ((pData->iColortype == 2) && (iRawlen != 6))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
#ifdef MNG_SUPPORT_DISPLAY
if (pData->iColortype == 3)
{
mng_imagep pImage = (mng_imagep)pData->pCurrentobj;
mng_imagedatap pBuf;
if (!pImage) /* no object then check obj 0 */
pImage = (mng_imagep)pData->pObjzero;
pBuf = pImage->pImgbuf; /* address object buffer */
if (iRawlen > pBuf->iPLTEcount)
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
#endif
}
else /* if empty there must be global stuff! */
{
if (!pData->bHasglobalTRNS)
MNG_ERROR (pData, MNG_CANNOTBEEMPTY);
}
}
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
pData->bHasTRNS = MNG_TRUE; /* indicate tRNS available */
else
pData->bHasglobalTRNS = MNG_TRUE;
#ifdef MNG_SUPPORT_DISPLAY
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
{
mng_imagep pImage;
mng_imagedatap pBuf;
mng_uint8p pRawdata2;
mng_uint32 iRawlen2;
#ifndef MNG_NO_DELTA_PNG
if (pData->bHasDHDR) /* processing delta-image ? */
{ /* store in object 0 !!! */
pImage = (mng_imagep)pData->pObjzero;
pBuf = pImage->pImgbuf; /* address object buffer */
switch (pData->iColortype) /* store fields for future reference */
{
case 0: { /* gray */
#if defined(MNG_NO_1_2_4BIT_SUPPORT)
mng_uint8 multiplier[]={0,255,85,0,17,0,0,0,1,
0,0,0,0,0,0,0,1};
#endif
pBuf->iTRNSgray = mng_get_uint16 (pRawdata);
pBuf->iTRNSred = 0;
pBuf->iTRNSgreen = 0;
pBuf->iTRNSblue = 0;
pBuf->iTRNScount = 0;
#if defined(MNG_NO_1_2_4BIT_SUPPORT)
pBuf->iTRNSgray *= multiplier[pData->iPNGdepth];
#endif
#if defined(MNG_NO_16BIT_SUPPORT)
if (pData->iPNGmult == 2)
pBuf->iTRNSgray >>= 8;
#endif
break;
}
case 2: { /* rgb */
pBuf->iTRNSgray = 0;
pBuf->iTRNSred = mng_get_uint16 (pRawdata);
pBuf->iTRNSgreen = mng_get_uint16 (pRawdata+2);
pBuf->iTRNSblue = mng_get_uint16 (pRawdata+4);
pBuf->iTRNScount = 0;
#if defined(MNG_NO_16BIT_SUPPORT)
if (pData->iPNGmult == 2)
{
pBuf->iTRNSred >>= 8;
pBuf->iTRNSgreen >>= 8;
pBuf->iTRNSblue >>= 8;
}
#endif
break;
}
case 3: { /* indexed */
pBuf->iTRNSgray = 0;
pBuf->iTRNSred = 0;
pBuf->iTRNSgreen = 0;
pBuf->iTRNSblue = 0;
pBuf->iTRNScount = iRawlen;
MNG_COPY (pBuf->aTRNSentries, pRawdata, iRawlen);
break;
}
}
pBuf->bHasTRNS = MNG_TRUE; /* tell it it's got a tRNS now */
}
else
#endif
{ /* address current object */
pImage = (mng_imagep)pData->pCurrentobj;
if (!pImage) /* no object then dump it in obj 0 */
pImage = (mng_imagep)pData->pObjzero;
pBuf = pImage->pImgbuf; /* address object buffer */
pBuf->bHasTRNS = MNG_TRUE; /* and tell it it's got a tRNS now */
if (iRawlen == 0) /* if empty, inherit from global */
{
iRawlen2 = pData->iGlobalTRNSrawlen;
pRawdata2 = (mng_ptr)(pData->aGlobalTRNSrawdata);
/* global length oke ? */
if ((pData->iColortype == 0) && (iRawlen2 != 2))
MNG_ERROR (pData, MNG_GLOBALLENGTHERR);
if ((pData->iColortype == 2) && (iRawlen2 != 6))
MNG_ERROR (pData, MNG_GLOBALLENGTHERR);
if ((pData->iColortype == 3) && ((iRawlen2 == 0) || (iRawlen2 > pBuf->iPLTEcount)))
MNG_ERROR (pData, MNG_GLOBALLENGTHERR);
}
else
{
iRawlen2 = iRawlen;
pRawdata2 = pRawdata;
}
switch (pData->iColortype) /* store fields for future reference */
{
case 0: { /* gray */
pBuf->iTRNSgray = mng_get_uint16 (pRawdata2);
pBuf->iTRNSred = 0;
pBuf->iTRNSgreen = 0;
pBuf->iTRNSblue = 0;
pBuf->iTRNScount = 0;
#if defined(MNG_NO_16BIT_SUPPORT)
if (pData->iPNGmult == 2)
pBuf->iTRNSgray >>= 8;
#endif
break;
}
case 2: { /* rgb */
pBuf->iTRNSgray = 0;
pBuf->iTRNSred = mng_get_uint16 (pRawdata2);
pBuf->iTRNSgreen = mng_get_uint16 (pRawdata2+2);
pBuf->iTRNSblue = mng_get_uint16 (pRawdata2+4);
pBuf->iTRNScount = 0;
#if defined(MNG_NO_16BIT_SUPPORT)
if (pData->iPNGmult == 2)
{
pBuf->iTRNSred >>= 8;
pBuf->iTRNSgreen >>= 8;
pBuf->iTRNSblue >>= 8;
}
#endif
break;
}
case 3: { /* indexed */
pBuf->iTRNSgray = 0;
pBuf->iTRNSred = 0;
pBuf->iTRNSgreen = 0;
pBuf->iTRNSblue = 0;
pBuf->iTRNScount = iRawlen2;
MNG_COPY (pBuf->aTRNSentries, pRawdata2, iRawlen2);
break;
}
}
}
}
else /* store as global */
{
pData->iGlobalTRNSrawlen = iRawlen;
MNG_COPY (pData->aGlobalTRNSrawdata, pRawdata, iRawlen);
{ /* create an animation object */
mng_retcode iRetcode = mng_create_ani_trns (pData, pData->iGlobalTRNSrawlen,
pData->aGlobalTRNSrawdata);
if (iRetcode) /* on error bail out */
return iRetcode;
}
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
{ /* not global! */
((mng_trnsp)*ppChunk)->bGlobal = MNG_FALSE;
((mng_trnsp)*ppChunk)->iType = pData->iColortype;
if (iRawlen == 0) /* if empty, indicate so */
((mng_trnsp)*ppChunk)->bEmpty = MNG_TRUE;
else
{
((mng_trnsp)*ppChunk)->bEmpty = MNG_FALSE;
switch (pData->iColortype) /* store fields */
{
case 0: { /* gray */
((mng_trnsp)*ppChunk)->iGray = mng_get_uint16 (pRawdata);
break;
}
case 2: { /* rgb */
((mng_trnsp)*ppChunk)->iRed = mng_get_uint16 (pRawdata);
((mng_trnsp)*ppChunk)->iGreen = mng_get_uint16 (pRawdata+2);
((mng_trnsp)*ppChunk)->iBlue = mng_get_uint16 (pRawdata+4);
break;
}
case 3: { /* indexed */
((mng_trnsp)*ppChunk)->iCount = iRawlen;
MNG_COPY (((mng_trnsp)*ppChunk)->aEntries, pRawdata, iRawlen);
break;
}
}
}
}
else /* it's global! */
{
((mng_trnsp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0);
((mng_trnsp)*ppChunk)->bGlobal = MNG_TRUE;
((mng_trnsp)*ppChunk)->iType = 0;
((mng_trnsp)*ppChunk)->iRawlen = iRawlen;
MNG_COPY (((mng_trnsp)*ppChunk)->aRawdata, pRawdata, iRawlen);
}
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_TRNS, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
READ_CHUNK (mng_read_gama)
{
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_GAMA, MNG_LC_START);
#endif
/* sequence checks */
#ifdef MNG_INCLUDE_JNG
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIDAT) || (pData->bHasPLTE) || (pData->bHasJDAT) || (pData->bHasJDAA))
#else
if ((pData->bHasIDAT) || (pData->bHasPLTE))
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{ /* length must be exactly 4 */
if (iRawlen != 4)
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
else
{ /* length must be empty or exactly 4 */
if ((iRawlen != 0) && (iRawlen != 4))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
pData->bHasGAMA = MNG_TRUE; /* indicate we've got it */
else
pData->bHasglobalGAMA = (mng_bool)(iRawlen != 0);
#ifdef MNG_SUPPORT_DISPLAY
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{
mng_imagep pImage;
#ifndef MNG_NO_DELTA_PNG
if (pData->bHasDHDR) /* update delta image ? */
{ /* store in object 0 ! */
pImage = (mng_imagep)pData->pObjzero;
/* store for color-processing routines */
pImage->pImgbuf->iGamma = mng_get_uint32 (pRawdata);
pImage->pImgbuf->bHasGAMA = MNG_TRUE;
}
else
#endif
{
pImage = (mng_imagep)pData->pCurrentobj;
if (!pImage) /* no object then dump it in obj 0 */
pImage = (mng_imagep)pData->pObjzero;
/* store for color-processing routines */
pImage->pImgbuf->iGamma = mng_get_uint32 (pRawdata);
pImage->pImgbuf->bHasGAMA = MNG_TRUE;
}
}
else
{ /* store as global */
if (iRawlen != 0)
pData->iGlobalGamma = mng_get_uint32 (pRawdata);
{ /* create an animation object */
mng_retcode iRetcode = mng_create_ani_gama (pData, (mng_bool)(iRawlen == 0),
pData->iGlobalGamma);
if (iRetcode) /* on error bail out */
return iRetcode;
}
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
/* store the fields */
((mng_gamap)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0);
if (iRawlen)
((mng_gamap)*ppChunk)->iGamma = mng_get_uint32 (pRawdata);
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_GAMA, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
#ifndef MNG_SKIPCHUNK_cHRM
READ_CHUNK (mng_read_chrm)
{
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_CHRM, MNG_LC_START);
#endif
/* sequence checks */
#ifdef MNG_INCLUDE_JNG
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIDAT) || (pData->bHasPLTE) || (pData->bHasJDAT) || (pData->bHasJDAA))
#else
if ((pData->bHasIDAT) || (pData->bHasPLTE))
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{ /* length must be exactly 32 */
if (iRawlen != 32)
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
else
{ /* length must be empty or exactly 32 */
if ((iRawlen != 0) && (iRawlen != 32))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
pData->bHasCHRM = MNG_TRUE; /* indicate we've got it */
else
pData->bHasglobalCHRM = (mng_bool)(iRawlen != 0);
#ifdef MNG_SUPPORT_DISPLAY
{
mng_uint32 iWhitepointx, iWhitepointy;
mng_uint32 iPrimaryredx, iPrimaryredy;
mng_uint32 iPrimarygreenx, iPrimarygreeny;
mng_uint32 iPrimarybluex, iPrimarybluey;
iWhitepointx = mng_get_uint32 (pRawdata);
iWhitepointy = mng_get_uint32 (pRawdata+4);
iPrimaryredx = mng_get_uint32 (pRawdata+8);
iPrimaryredy = mng_get_uint32 (pRawdata+12);
iPrimarygreenx = mng_get_uint32 (pRawdata+16);
iPrimarygreeny = mng_get_uint32 (pRawdata+20);
iPrimarybluex = mng_get_uint32 (pRawdata+24);
iPrimarybluey = mng_get_uint32 (pRawdata+28);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{
mng_imagep pImage;
mng_imagedatap pBuf;
#ifndef MNG_NO_DELTA_PNG
if (pData->bHasDHDR) /* update delta image ? */
{ /* store it in object 0 ! */
pImage = (mng_imagep)pData->pObjzero;
pBuf = pImage->pImgbuf; /* address object buffer */
pBuf->bHasCHRM = MNG_TRUE; /* and tell it it's got a CHRM now */
/* store for color-processing routines */
pBuf->iWhitepointx = iWhitepointx;
pBuf->iWhitepointy = iWhitepointy;
pBuf->iPrimaryredx = iPrimaryredx;
pBuf->iPrimaryredy = iPrimaryredy;
pBuf->iPrimarygreenx = iPrimarygreenx;
pBuf->iPrimarygreeny = iPrimarygreeny;
pBuf->iPrimarybluex = iPrimarybluex;
pBuf->iPrimarybluey = iPrimarybluey;
}
else
#endif
{
pImage = (mng_imagep)pData->pCurrentobj;
if (!pImage) /* no object then dump it in obj 0 */
pImage = (mng_imagep)pData->pObjzero;
pBuf = pImage->pImgbuf; /* address object buffer */
pBuf->bHasCHRM = MNG_TRUE; /* and tell it it's got a CHRM now */
/* store for color-processing routines */
pBuf->iWhitepointx = iWhitepointx;
pBuf->iWhitepointy = iWhitepointy;
pBuf->iPrimaryredx = iPrimaryredx;
pBuf->iPrimaryredy = iPrimaryredy;
pBuf->iPrimarygreenx = iPrimarygreenx;
pBuf->iPrimarygreeny = iPrimarygreeny;
pBuf->iPrimarybluex = iPrimarybluex;
pBuf->iPrimarybluey = iPrimarybluey;
}
}
else
{ /* store as global */
if (iRawlen != 0)
{
pData->iGlobalWhitepointx = iWhitepointx;
pData->iGlobalWhitepointy = iWhitepointy;
pData->iGlobalPrimaryredx = iPrimaryredx;
pData->iGlobalPrimaryredy = iPrimaryredy;
pData->iGlobalPrimarygreenx = iPrimarygreenx;
pData->iGlobalPrimarygreeny = iPrimarygreeny;
pData->iGlobalPrimarybluex = iPrimarybluex;
pData->iGlobalPrimarybluey = iPrimarybluey;
}
{ /* create an animation object */
mng_retcode iRetcode = mng_create_ani_chrm (pData, (mng_bool)(iRawlen == 0),
iWhitepointx, iWhitepointy,
iPrimaryredx, iPrimaryredy,
iPrimarygreenx, iPrimarygreeny,
iPrimarybluex, iPrimarybluey);
if (iRetcode) /* on error bail out */
return iRetcode;
}
}
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
/* store the fields */
((mng_chrmp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0);
if (iRawlen)
{
((mng_chrmp)*ppChunk)->iWhitepointx = mng_get_uint32 (pRawdata);
((mng_chrmp)*ppChunk)->iWhitepointy = mng_get_uint32 (pRawdata+4);
((mng_chrmp)*ppChunk)->iRedx = mng_get_uint32 (pRawdata+8);
((mng_chrmp)*ppChunk)->iRedy = mng_get_uint32 (pRawdata+12);
((mng_chrmp)*ppChunk)->iGreenx = mng_get_uint32 (pRawdata+16);
((mng_chrmp)*ppChunk)->iGreeny = mng_get_uint32 (pRawdata+20);
((mng_chrmp)*ppChunk)->iBluex = mng_get_uint32 (pRawdata+24);
((mng_chrmp)*ppChunk)->iBluey = mng_get_uint32 (pRawdata+28);
}
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_CHRM, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
READ_CHUNK (mng_read_srgb)
{
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_SRGB, MNG_LC_START);
#endif
/* sequence checks */
#ifdef MNG_INCLUDE_JNG
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIDAT) || (pData->bHasPLTE) || (pData->bHasJDAT) || (pData->bHasJDAA))
#else
if ((pData->bHasIDAT) || (pData->bHasPLTE))
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{ /* length must be exactly 1 */
if (iRawlen != 1)
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
else
{ /* length must be empty or exactly 1 */
if ((iRawlen != 0) && (iRawlen != 1))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
pData->bHasSRGB = MNG_TRUE; /* indicate we've got it */
else
pData->bHasglobalSRGB = (mng_bool)(iRawlen != 0);
#ifdef MNG_SUPPORT_DISPLAY
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{
mng_imagep pImage;
#ifndef MNG_NO_DELTA_PNG
if (pData->bHasDHDR) /* update delta image ? */
{ /* store in object 0 ! */
pImage = (mng_imagep)pData->pObjzero;
/* store for color-processing routines */
pImage->pImgbuf->iRenderingintent = *pRawdata;
pImage->pImgbuf->bHasSRGB = MNG_TRUE;
}
else
#endif
{
pImage = (mng_imagep)pData->pCurrentobj;
if (!pImage) /* no object then dump it in obj 0 */
pImage = (mng_imagep)pData->pObjzero;
/* store for color-processing routines */
pImage->pImgbuf->iRenderingintent = *pRawdata;
pImage->pImgbuf->bHasSRGB = MNG_TRUE;
}
}
else
{ /* store as global */
if (iRawlen != 0)
pData->iGlobalRendintent = *pRawdata;
{ /* create an animation object */
mng_retcode iRetcode = mng_create_ani_srgb (pData, (mng_bool)(iRawlen == 0),
pData->iGlobalRendintent);
if (iRetcode) /* on error bail out */
return iRetcode;
}
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
/* store the fields */
((mng_srgbp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0);
if (iRawlen)
((mng_srgbp)*ppChunk)->iRenderingintent = *pRawdata;
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_SRGB, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
#ifndef MNG_SKIPCHUNK_iCCP
READ_CHUNK (mng_read_iccp)
{
mng_retcode iRetcode;
mng_uint8p pTemp;
mng_uint32 iCompressedsize;
mng_uint32 iProfilesize;
mng_uint32 iBufsize = 0;
mng_uint8p pBuf = 0;
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_ICCP, MNG_LC_START);
#endif
/* sequence checks */
#ifdef MNG_INCLUDE_JNG
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIDAT) || (pData->bHasPLTE) || (pData->bHasJDAT) || (pData->bHasJDAA))
#else
if ((pData->bHasIDAT) || (pData->bHasPLTE))
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{ /* length must be at least 2 */
if (iRawlen < 2)
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
else
{ /* length must be empty or at least 2 */
if ((iRawlen != 0) && (iRawlen < 2))
MNG_ERROR (pData, MNG_INVALIDLENGTH);
}
pTemp = find_null (pRawdata); /* find null-separator */
/* not found inside input-data ? */
if ((pTemp - pRawdata) > (mng_int32)iRawlen)
MNG_ERROR (pData, MNG_NULLNOTFOUND);
/* determine size of compressed profile */
iCompressedsize = (mng_uint32)(iRawlen - (pTemp - pRawdata) - 2);
/* decompress the profile */
iRetcode = mng_inflate_buffer (pData, pTemp+2, iCompressedsize,
&pBuf, &iBufsize, &iProfilesize);
#ifdef MNG_CHECK_BAD_ICCP /* Check for bad iCCP chunk */
if ((iRetcode) && (!strncmp ((char *)pRawdata, "Photoshop ICC profile", 21)))
{
if (iRawlen == 2615) /* is it the sRGB profile ? */
{
mng_chunk_header chunk_srgb =
#ifdef MNG_OPTIMIZE_CHUNKINITFREE
{MNG_UINT_sRGB, mng_init_general, mng_free_general, mng_read_srgb, mng_write_srgb, mng_assign_general, 0, 0, sizeof(mng_srgb)};
#else
{MNG_UINT_sRGB, mng_init_srgb, mng_free_srgb, mng_read_srgb, mng_write_srgb, mng_assign_srgb, 0, 0};
#endif
/* pretend it's an sRGB chunk then ! */
iRetcode = mng_read_srgb (pData, &chunk_srgb, 1, (mng_ptr)"0", ppChunk);
if (iRetcode) /* on error bail out */
{ /* don't forget to drop the temp buffer */
MNG_FREEX (pData, pBuf, iBufsize);
return iRetcode;
}
}
}
else
{
#endif /* MNG_CHECK_BAD_ICCP */
if (iRetcode) /* on error bail out */
{ /* don't forget to drop the temp buffer */
MNG_FREEX (pData, pBuf, iBufsize);
return iRetcode;
}
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
pData->bHasICCP = MNG_TRUE; /* indicate we've got it */
else
pData->bHasglobalICCP = (mng_bool)(iRawlen != 0);
#ifdef MNG_SUPPORT_DISPLAY
#ifdef MNG_INCLUDE_JNG
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR))
#else
if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR))
#endif
{
mng_imagep pImage;
#ifndef MNG_NO_DELTA_PNG
if (pData->bHasDHDR) /* update delta image ? */
{ /* store in object 0 ! */
pImage = (mng_imagep)pData->pObjzero;
if (pImage->pImgbuf->pProfile) /* profile existed ? */
MNG_FREEX (pData, pImage->pImgbuf->pProfile, pImage->pImgbuf->iProfilesize);
/* allocate a buffer & copy it */
MNG_ALLOC (pData, pImage->pImgbuf->pProfile, iProfilesize);
MNG_COPY (pImage->pImgbuf->pProfile, pBuf, iProfilesize);
/* store its length as well */
pImage->pImgbuf->iProfilesize = iProfilesize;
pImage->pImgbuf->bHasICCP = MNG_TRUE;
}
else
#endif
{
pImage = (mng_imagep)pData->pCurrentobj;
if (!pImage) /* no object then dump it in obj 0 */
pImage = (mng_imagep)pData->pObjzero;
if (pImage->pImgbuf->pProfile) /* profile existed ? */
MNG_FREEX (pData, pImage->pImgbuf->pProfile, pImage->pImgbuf->iProfilesize);
/* allocate a buffer & copy it */
MNG_ALLOC (pData, pImage->pImgbuf->pProfile, iProfilesize);
MNG_COPY (pImage->pImgbuf->pProfile, pBuf, iProfilesize);
/* store its length as well */
pImage->pImgbuf->iProfilesize = iProfilesize;
pImage->pImgbuf->bHasICCP = MNG_TRUE;
}
}
else
{ /* store as global */
if (iRawlen == 0) /* empty chunk ? */
{
if (pData->pGlobalProfile) /* did we have a global profile ? */
MNG_FREEX (pData, pData->pGlobalProfile, pData->iGlobalProfilesize);
pData->iGlobalProfilesize = 0; /* reset to null */
pData->pGlobalProfile = MNG_NULL;
}
else
{ /* allocate a global buffer & copy it */
MNG_ALLOC (pData, pData->pGlobalProfile, iProfilesize);
MNG_COPY (pData->pGlobalProfile, pBuf, iProfilesize);
/* store its length as well */
pData->iGlobalProfilesize = iProfilesize;
}
/* create an animation object */
iRetcode = mng_create_ani_iccp (pData, (mng_bool)(iRawlen == 0),
pData->iGlobalProfilesize,
pData->pGlobalProfile);
if (iRetcode) /* on error bail out */
return iRetcode;
}
#endif /* MNG_SUPPORT_DISPLAY */
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
{ /* don't forget to drop the temp buffer */
MNG_FREEX (pData, pBuf, iBufsize);
return iRetcode;
}
/* store the fields */
((mng_iccpp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0);
if (iRawlen) /* not empty ? */
{
if (!pBuf) /* hasn't been unpuzzled it yet ? */
{ /* find null-separator */
pTemp = find_null (pRawdata);
/* not found inside input-data ? */
if ((pTemp - pRawdata) > (mng_int32)iRawlen)
MNG_ERROR (pData, MNG_NULLNOTFOUND);
/* determine size of compressed profile */
iCompressedsize = iRawlen - (pTemp - pRawdata) - 2;
/* decompress the profile */
iRetcode = mng_inflate_buffer (pData, pTemp+2, iCompressedsize,
&pBuf, &iBufsize, &iProfilesize);
if (iRetcode) /* on error bail out */
{ /* don't forget to drop the temp buffer */
MNG_FREEX (pData, pBuf, iBufsize);
return iRetcode;
}
}
((mng_iccpp)*ppChunk)->iNamesize = (mng_uint32)(pTemp - pRawdata);
if (((mng_iccpp)*ppChunk)->iNamesize)
{
MNG_ALLOC (pData, ((mng_iccpp)*ppChunk)->zName,
((mng_iccpp)*ppChunk)->iNamesize + 1);
MNG_COPY (((mng_iccpp)*ppChunk)->zName, pRawdata,
((mng_iccpp)*ppChunk)->iNamesize);
}
((mng_iccpp)*ppChunk)->iCompression = *(pTemp+1);
((mng_iccpp)*ppChunk)->iProfilesize = iProfilesize;
MNG_ALLOC (pData, ((mng_iccpp)*ppChunk)->pProfile, iProfilesize);
MNG_COPY (((mng_iccpp)*ppChunk)->pProfile, pBuf, iProfilesize);
}
}
#endif /* MNG_STORE_CHUNKS */
if (pBuf) /* free the temporary buffer */
MNG_FREEX (pData, pBuf, iBufsize);
#ifdef MNG_CHECK_BAD_ICCP
}
#endif
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_ICCP, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
#ifndef MNG_SKIPCHUNK_tEXt
READ_CHUNK (mng_read_text)
{
mng_uint32 iKeywordlen, iTextlen;
mng_pchar zKeyword, zText;
mng_uint8p pTemp;
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_TEXT, MNG_LC_START);
#endif
/* sequence checks */
#ifdef MNG_INCLUDE_JNG
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
if (iRawlen < 2) /* length must be at least 2 */
MNG_ERROR (pData, MNG_INVALIDLENGTH);
pTemp = find_null (pRawdata); /* find the null separator */
/* not found inside input-data ? */
if ((pTemp - pRawdata) > (mng_int32)iRawlen)
MNG_ERROR (pData, MNG_NULLNOTFOUND);
if (pTemp == pRawdata) /* there must be at least 1 char for keyword */
MNG_ERROR (pData, MNG_KEYWORDNULL);
iKeywordlen = (mng_uint32)(pTemp - pRawdata);
iTextlen = iRawlen - iKeywordlen - 1;
if (pData->fProcesstext) /* inform the application ? */
{
mng_bool bOke;
MNG_ALLOC (pData, zKeyword, iKeywordlen + 1);
MNG_COPY (zKeyword, pRawdata, iKeywordlen);
MNG_ALLOCX (pData, zText, iTextlen + 1);
if (!zText) /* on error bail out */
{
MNG_FREEX (pData, zKeyword, iKeywordlen + 1);
MNG_ERROR (pData, MNG_OUTOFMEMORY);
}
if (iTextlen)
MNG_COPY (zText, pTemp+1, iTextlen);
bOke = pData->fProcesstext ((mng_handle)pData, MNG_TYPE_TEXT, zKeyword, zText, 0, 0);
MNG_FREEX (pData, zText, iTextlen + 1);
MNG_FREEX (pData, zKeyword, iKeywordlen + 1);
if (!bOke)
MNG_ERROR (pData, MNG_APPMISCERROR);
}
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
return iRetcode;
/* store the fields */
((mng_textp)*ppChunk)->iKeywordsize = iKeywordlen;
((mng_textp)*ppChunk)->iTextsize = iTextlen;
if (iKeywordlen)
{
MNG_ALLOC (pData, ((mng_textp)*ppChunk)->zKeyword, iKeywordlen+1);
MNG_COPY (((mng_textp)*ppChunk)->zKeyword, pRawdata, iKeywordlen);
}
if (iTextlen)
{
MNG_ALLOC (pData, ((mng_textp)*ppChunk)->zText, iTextlen+1);
MNG_COPY (((mng_textp)*ppChunk)->zText, pTemp+1, iTextlen);
}
}
#endif /* MNG_STORE_CHUNKS */
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_TEXT, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
#ifndef MNG_SKIPCHUNK_zTXt
READ_CHUNK (mng_read_ztxt)
{
mng_retcode iRetcode;
mng_uint32 iKeywordlen, iTextlen;
mng_pchar zKeyword;
mng_uint8p pTemp;
mng_uint32 iCompressedsize;
mng_uint32 iBufsize;
mng_uint8p pBuf;
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_ZTXT, MNG_LC_START);
#endif
/* sequence checks */
#ifdef MNG_INCLUDE_JNG
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
if (iRawlen < 3) /* length must be at least 3 */
MNG_ERROR (pData, MNG_INVALIDLENGTH);
pTemp = find_null (pRawdata); /* find the null separator */
/* not found inside input-data ? */
if ((pTemp - pRawdata) > (mng_int32)iRawlen)
MNG_ERROR (pData, MNG_NULLNOTFOUND);
if (pTemp == pRawdata) /* there must be at least 1 char for keyword */
MNG_ERROR (pData, MNG_KEYWORDNULL);
if (*(pTemp+1) != 0) /* only deflate compression-method allowed */
MNG_ERROR (pData, MNG_INVALIDCOMPRESS);
iKeywordlen = (mng_uint32)(pTemp - pRawdata);
iCompressedsize = (mng_uint32)(iRawlen - iKeywordlen - 2);
zKeyword = 0; /* there's no keyword buffer yet */
pBuf = 0; /* or a temporary buffer ! */
if (pData->fProcesstext) /* inform the application ? */
{ /* decompress the text */
iRetcode = mng_inflate_buffer (pData, pTemp+2, iCompressedsize,
&pBuf, &iBufsize, &iTextlen);
if (iRetcode) /* on error bail out */
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, pBuf, iBufsize);
return iRetcode;
}
MNG_ALLOCX (pData, zKeyword, iKeywordlen+1);
if (!zKeyword) /* on error bail out */
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, pBuf, iBufsize);
MNG_ERROR (pData, MNG_OUTOFMEMORY);
}
MNG_COPY (zKeyword, pRawdata, iKeywordlen);
if (!pData->fProcesstext ((mng_handle)pData, MNG_TYPE_ZTXT, zKeyword, (mng_pchar)pBuf, 0, 0))
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, pBuf, iBufsize);
MNG_FREEX (pData, zKeyword, iKeywordlen+1);
MNG_ERROR (pData, MNG_APPMISCERROR);
}
}
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)
{ /* initialize storage */
iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk);
if (iRetcode) /* on error bail out */
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, pBuf, iBufsize);
MNG_FREEX (pData, zKeyword, iKeywordlen+1);
return iRetcode;
}
/* store the fields */
((mng_ztxtp)*ppChunk)->iKeywordsize = iKeywordlen;
((mng_ztxtp)*ppChunk)->iCompression = *(pTemp+1);
if ((!pBuf) && (iCompressedsize)) /* did we not get a text-buffer yet ? */
{ /* decompress the text */
iRetcode = mng_inflate_buffer (pData, pTemp+2, iCompressedsize,
&pBuf, &iBufsize, &iTextlen);
if (iRetcode) /* on error bail out */
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, pBuf, iBufsize);
MNG_FREEX (pData, zKeyword, iKeywordlen+1);
return iRetcode;
}
}
MNG_ALLOCX (pData, ((mng_ztxtp)*ppChunk)->zKeyword, iKeywordlen + 1);
/* on error bail out */
if (!((mng_ztxtp)*ppChunk)->zKeyword)
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, pBuf, iBufsize);
MNG_FREEX (pData, zKeyword, iKeywordlen+1);
MNG_ERROR (pData, MNG_OUTOFMEMORY);
}
MNG_COPY (((mng_ztxtp)*ppChunk)->zKeyword, pRawdata, iKeywordlen);
((mng_ztxtp)*ppChunk)->iTextsize = iTextlen;
if (iCompressedsize)
{
MNG_ALLOCX (pData, ((mng_ztxtp)*ppChunk)->zText, iTextlen + 1);
/* on error bail out */
if (!((mng_ztxtp)*ppChunk)->zText)
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, pBuf, iBufsize);
MNG_FREEX (pData, zKeyword, iKeywordlen+1);
MNG_ERROR (pData, MNG_OUTOFMEMORY);
}
MNG_COPY (((mng_ztxtp)*ppChunk)->zText, pBuf, iTextlen);
}
}
#endif /* MNG_STORE_CHUNKS */
MNG_FREEX (pData, pBuf, iBufsize); /* free the temporary buffers */
MNG_FREEX (pData, zKeyword, iKeywordlen+1);
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_ZTXT, MNG_LC_END);
#endif
return MNG_NOERROR; /* done */
}
#endif
#endif
/* ************************************************************************** */
#ifndef MNG_OPTIMIZE_CHUNKREADER
#ifndef MNG_SKIPCHUNK_iTXt
READ_CHUNK (mng_read_itxt)
{
mng_retcode iRetcode;
mng_uint32 iKeywordlen, iTextlen, iLanguagelen, iTranslationlen;
mng_pchar zKeyword, zLanguage, zTranslation;
mng_uint8p pNull1, pNull2, pNull3;
mng_uint32 iCompressedsize;
mng_uint8 iCompressionflag;
mng_uint32 iBufsize;
mng_uint8p pBuf;
#ifdef MNG_SUPPORT_TRACE
MNG_TRACE (pData, MNG_FN_READ_ITXT, MNG_LC_START);
#endif
/* sequence checks */
#ifdef MNG_INCLUDE_JNG
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR))
#else
if ((!pData->bHasMHDR) && (!pData->bHasIHDR) &&
(!pData->bHasBASI) && (!pData->bHasDHDR) )
#endif
MNG_ERROR (pData, MNG_SEQUENCEERROR);
if (iRawlen < 6) /* length must be at least 6 */
MNG_ERROR (pData, MNG_INVALIDLENGTH);
pNull1 = find_null (pRawdata); /* find the null separators */
pNull2 = find_null (pNull1+3);
pNull3 = find_null (pNull2+1);
/* not found inside input-data ? */
if (((pNull1 - pRawdata) > (mng_int32)iRawlen) ||
((pNull2 - pRawdata) > (mng_int32)iRawlen) ||
((pNull3 - pRawdata) > (mng_int32)iRawlen) )
MNG_ERROR (pData, MNG_NULLNOTFOUND);
if (pNull1 == pRawdata) /* there must be at least 1 char for keyword */
MNG_ERROR (pData, MNG_KEYWORDNULL);
/* compression or not ? */
if ((*(pNull1+1) != 0) && (*(pNull1+1) != 1))
MNG_ERROR (pData, MNG_INVALIDCOMPRESS);
if (*(pNull1+2) != 0) /* only deflate compression-method allowed */
MNG_ERROR (pData, MNG_INVALIDCOMPRESS);
iKeywordlen = (mng_uint32)(pNull1 - pRawdata);
iLanguagelen = (mng_uint32)(pNull2 - pNull1 - 3);
iTranslationlen = (mng_uint32)(pNull3 - pNull2 - 1);
iCompressedsize = (mng_uint32)(iRawlen - iKeywordlen - iLanguagelen - iTranslationlen - 5);
iCompressionflag = *(pNull1+1);
zKeyword = 0; /* no buffers acquired yet */
zLanguage = 0;
zTranslation = 0;
pBuf = 0;
iTextlen = 0;
if (pData->fProcesstext) /* inform the application ? */
{
if (iCompressionflag) /* decompress the text ? */
{
iRetcode = mng_inflate_buffer (pData, pNull3+1, iCompressedsize,
&pBuf, &iBufsize, &iTextlen);
if (iRetcode) /* on error bail out */
{ /* don't forget to drop the temp buffer */
MNG_FREEX (pData, pBuf, iBufsize);
return iRetcode;
}
}
else
{
iTextlen = iCompressedsize;
iBufsize = iTextlen+1; /* plus 1 for terminator byte!!! */
MNG_ALLOC (pData, pBuf, iBufsize);
MNG_COPY (pBuf, pNull3+1, iTextlen);
}
MNG_ALLOCX (pData, zKeyword, iKeywordlen + 1);
MNG_ALLOCX (pData, zLanguage, iLanguagelen + 1);
MNG_ALLOCX (pData, zTranslation, iTranslationlen + 1);
/* on error bail out */
if ((!zKeyword) || (!zLanguage) || (!zTranslation))
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, zTranslation, iTranslationlen + 1);
MNG_FREEX (pData, zLanguage, iLanguagelen + 1);
MNG_FREEX (pData, zKeyword, iKeywordlen + 1);
MNG_FREEX (pData, pBuf, iBufsize);
MNG_ERROR (pData, MNG_OUTOFMEMORY);
}
MNG_COPY (zKeyword, pRawdata, iKeywordlen);
MNG_COPY (zLanguage, pNull1+3, iLanguagelen);
MNG_COPY (zTranslation, pNull2+1, iTranslationlen);
if (!pData->fProcesstext ((mng_handle)pData, MNG_TYPE_ITXT, zKeyword, (mng_pchar)pBuf,
zLanguage, zTranslation))
{ /* don't forget to drop the temp buffers */
MNG_FREEX (pData, zTranslation, iTranslationlen + 1);
MNG_FREEX (pData, zLanguage, iLanguagelen + 1);
MNG_FREEX (pData, zKeyword, iKeywordlen + 1);
MNG_FREEX (pData, pBuf, iBufsize);
MNG_ERROR (pData, MNG_APPMISCERROR);
}
}
#ifdef MNG_STORE_CHUNKS
if (pData->bStorechunks)