| /** ************************************************************************* */ |
| /* * 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) |
|