/src/FreeImage/Source/LibMNG/libmng_chunk_io.c
C | 1459 lines | 942 code | 174 blank | 343 comment | 352 complexity | 7923962c84af202d068737fdfbf91ecd MD5 | raw file
1/** ************************************************************************* */ 2/* * For conditions of distribution and use, * */ 3/* * see copyright notice in libmng.h * */ 4/* ************************************************************************** */ 5/* * * */ 6/* * project : libmng * */ 7/* * file : libmng_chunk_io.c copyright (c) 2000-2007 G.Juyn * */ 8/* * version : 1.0.10 * */ 9/* * * */ 10/* * purpose : Chunk I/O routines (implementation) * */ 11/* * * */ 12/* * author : G.Juyn * */ 13/* * * */ 14/* * comment : implementation of chunk input/output routines * */ 15/* * * */ 16/* * changes : 0.5.1 - 05/01/2000 - G.Juyn * */ 17/* * - cleaned up left-over teststuff in the BACK chunk routine * */ 18/* * 0.5.1 - 05/04/2000 - G.Juyn * */ 19/* * - changed CRC initialization to use dynamic structure * */ 20/* * (wasn't thread-safe the old way !) * */ 21/* * 0.5.1 - 05/06/2000 - G.Juyn * */ 22/* * - filled in many missing sequence&length checks * */ 23/* * - filled in many missing chunk-store snippets * */ 24/* * 0.5.1 - 05/08/2000 - G.Juyn * */ 25/* * - added checks for running animations * */ 26/* * - filled some write routines * */ 27/* * - changed strict-ANSI stuff * */ 28/* * 0.5.1 - 05/10/2000 - G.Juyn * */ 29/* * - filled some more write routines * */ 30/* * 0.5.1 - 05/11/2000 - G.Juyn * */ 31/* * - filled remaining write routines * */ 32/* * - fixed read_pplt with regard to deltatype * */ 33/* * - added callback error-reporting support * */ 34/* * - added pre-draft48 support (short MHDR, frame_mode, LOOP) * */ 35/* * 0.5.1 - 05/12/2000 - G.Juyn * */ 36/* * - changed trace to macro for callback error-reporting * */ 37/* * - fixed chunk-storage bit in several routines * */ 38/* * 0.5.1 - 05/13/2000 - G.Juyn * */ 39/* * - added eMNGma hack (will be removed in 1.0.0 !!!) * */ 40/* * - added TERM animation object pointer (easier reference) * */ 41/* * - supplemented the SAVE & SEEK display processing * */ 42/* * * */ 43/* * 0.5.2 - 05/18/2000 - G.Juyn * */ 44/* * - B004 - fixed problem with MNG_SUPPORT_WRITE not defined * */ 45/* * also for MNG_SUPPORT_WRITE without MNG_INCLUDE_JNG * */ 46/* * 0.5.2 - 05/19/2000 - G.Juyn * */ 47/* * - cleaned up some code regarding mixed support * */ 48/* * 0.5.2 - 05/20/2000 - G.Juyn * */ 49/* * - implemented JNG support * */ 50/* * 0.5.2 - 05/24/2000 - G.Juyn * */ 51/* * - added support for global color-chunks in animation * */ 52/* * - added support for global PLTE,tRNS,bKGD in animation * */ 53/* * - added support for SAVE & SEEK in animation * */ 54/* * 0.5.2 - 05/29/2000 - G.Juyn * */ 55/* * - changed ani_create calls not returning object pointer * */ 56/* * - create ani objects always (not just inside TERM/LOOP) * */ 57/* * 0.5.2 - 05/30/2000 - G.Juyn * */ 58/* * - added support for delta-image processing * */ 59/* * 0.5.2 - 05/31/2000 - G.Juyn * */ 60/* * - fixed up punctuation (contributed by Tim Rowley) * */ 61/* * 0.5.2 - 06/02/2000 - G.Juyn * */ 62/* * - changed SWAP_ENDIAN to BIGENDIAN_SUPPORTED * */ 63/* * 0.5.2 - 06/03/2000 - G.Juyn * */ 64/* * - fixed makeup for Linux gcc compile * */ 65/* * * */ 66/* * 0.5.3 - 06/12/2000 - G.Juyn * */ 67/* * - added processing of color-info on delta-image * */ 68/* * 0.5.3 - 06/13/2000 - G.Juyn * */ 69/* * - fixed handling of empty SAVE chunk * */ 70/* * 0.5.3 - 06/17/2000 - G.Juyn * */ 71/* * - changed to support delta-images * */ 72/* * - added extra checks for delta-images * */ 73/* * 0.5.3 - 06/20/2000 - G.Juyn * */ 74/* * - fixed possible trouble if IEND display-process got * */ 75/* * broken up * */ 76/* * 0.5.3 - 06/21/2000 - G.Juyn * */ 77/* * - added processing of PLTE & tRNS for delta-images * */ 78/* * - added administration of imagelevel parameter * */ 79/* * 0.5.3 - 06/22/2000 - G.Juyn * */ 80/* * - implemented support for PPLT chunk * */ 81/* * 0.5.3 - 06/26/2000 - G.Juyn * */ 82/* * - added precaution against faulty iCCP chunks from PS * */ 83/* * 0.5.3 - 06/29/2000 - G.Juyn * */ 84/* * - fixed some 64-bit warnings * */ 85/* * * */ 86/* * 0.9.1 - 07/14/2000 - G.Juyn * */ 87/* * - changed pre-draft48 frame_mode=3 to frame_mode=1 * */ 88/* * 0.9.1 - 07/16/2000 - G.Juyn * */ 89/* * - fixed storage of images during mng_read() * */ 90/* * - fixed support for mng_display() after mng_read() * */ 91/* * 0.9.1 - 07/19/2000 - G.Juyn * */ 92/* * - fixed several chunk-writing routines * */ 93/* * 0.9.1 - 07/24/2000 - G.Juyn * */ 94/* * - fixed reading of still-images * */ 95/* * * */ 96/* * 0.9.2 - 08/05/2000 - G.Juyn * */ 97/* * - changed file-prefixes * */ 98/* * * */ 99/* * 0.9.3 - 08/07/2000 - G.Juyn * */ 100/* * - B111300 - fixup for improved portability * */ 101/* * 0.9.3 - 08/08/2000 - G.Juyn * */ 102/* * - fixed compiler-warnings from Mozilla * */ 103/* * 0.9.3 - 08/09/2000 - G.Juyn * */ 104/* * - added check for simplicity-bits in MHDR * */ 105/* * 0.9.3 - 08/12/2000 - G.Juyn * */ 106/* * - fixed check for simplicity-bits in MHDR (JNG) * */ 107/* * 0.9.3 - 08/12/2000 - G.Juyn * */ 108/* * - added workaround for faulty PhotoShop iCCP chunk * */ 109/* * 0.9.3 - 08/22/2000 - G.Juyn * */ 110/* * - fixed write-code for zTXt & iTXt * */ 111/* * - fixed read-code for iTXt * */ 112/* * 0.9.3 - 08/26/2000 - G.Juyn * */ 113/* * - added MAGN chunk * */ 114/* * 0.9.3 - 09/07/2000 - G.Juyn * */ 115/* * - added support for new filter_types * */ 116/* * 0.9.3 - 09/10/2000 - G.Juyn * */ 117/* * - fixed DEFI behavior * */ 118/* * 0.9.3 - 10/02/2000 - G.Juyn * */ 119/* * - fixed simplicity-check in compliance with draft 81/0.98a * */ 120/* * 0.9.3 - 10/10/2000 - G.Juyn * */ 121/* * - added support for alpha-depth prediction * */ 122/* * 0.9.3 - 10/11/2000 - G.Juyn * */ 123/* * - added support for nEED * */ 124/* * 0.9.3 - 10/16/2000 - G.Juyn * */ 125/* * - added support for JDAA * */ 126/* * 0.9.3 - 10/17/2000 - G.Juyn * */ 127/* * - fixed support for MAGN * */ 128/* * - implemented nEED "xxxx" (where "xxxx" is a chunkid) * */ 129/* * - added callback to process non-critical unknown chunks * */ 130/* * - fixed support for bKGD * */ 131/* * 0.9.3 - 10/23/2000 - G.Juyn * */ 132/* * - fixed bug in empty PLTE handling * */ 133/* * * */ 134/* * 0.9.4 - 11/20/2000 - G.Juyn * */ 135/* * - changed IHDR filter_method check for PNGs * */ 136/* * 0.9.4 - 1/18/2001 - G.Juyn * */ 137/* * - added errorchecking for MAGN methods * */ 138/* * - removed test filter-methods 1 & 65 * */ 139/* * * */ 140/* * 0.9.5 - 1/25/2001 - G.Juyn * */ 141/* * - fixed some small compiler warnings (thanks Nikki) * */ 142/* * * */ 143/* * 1.0.2 - 05/05/2000 - G.Juyn * */ 144/* * - B421427 - writes wrong format in bKGD and tRNS * */ 145/* * 1.0.2 - 06/20/2000 - G.Juyn * */ 146/* * - B434583 - compiler-warning if MNG_STORE_CHUNKS undefined * */ 147/* * * */ 148/* * 1.0.5 - 07/08/2002 - G.Juyn * */ 149/* * - B578572 - removed eMNGma hack (thanks Dimitri!) * */ 150/* * 1.0.5 - 08/07/2002 - G.Juyn * */ 151/* * - added test-option for PNG filter method 193 (=no filter) * */ 152/* * 1.0.5 - 08/15/2002 - G.Juyn * */ 153/* * - completed PROM support * */ 154/* * 1.0.5 - 08/19/2002 - G.Juyn * */ 155/* * - B597134 - libmng pollutes the linker namespace * */ 156/* * 1.0.5 - 09/07/2002 - G.Juyn * */ 157/* * - fixed reading of FRAM with just frame_mode and name * */ 158/* * 1.0.5 - 09/13/2002 - G.Juyn * */ 159/* * - fixed read/write of MAGN chunk * */ 160/* * 1.0.5 - 09/14/2002 - G.Juyn * */ 161/* * - added event handling for dynamic MNG * */ 162/* * 1.0.5 - 09/15/2002 - G.Juyn * */ 163/* * - fixed LOOP iteration=0 special case * */ 164/* * 1.0.5 - 09/19/2002 - G.Juyn * */ 165/* * - misplaced TERM is now treated as warning * */ 166/* * 1.0.5 - 09/20/2002 - G.Juyn * */ 167/* * - added support for PAST * */ 168/* * 1.0.5 - 10/03/2002 - G.Juyn * */ 169/* * - fixed chunk-storage for evNT chunk * */ 170/* * 1.0.5 - 10/07/2002 - G.Juyn * */ 171/* * - fixed DISC support * */ 172/* * - added another fix for misplaced TERM chunk * */ 173/* * 1.0.5 - 10/17/2002 - G.Juyn * */ 174/* * - fixed initializtion of pIds in dISC read routine * */ 175/* * 1.0.5 - 11/06/2002 - G.Juyn * */ 176/* * - added support for nEED "MNG 1.1" * */ 177/* * - added support for nEED "CACHEOFF" * */ 178/* * * */ 179/* * 1.0.6 - 05/25/2003 - G.R-P * */ 180/* * - added MNG_SKIPCHUNK_cHNK footprint optimizations * */ 181/* * 1.0.6 - 06/02/2003 - G.R-P * */ 182/* * - removed some redundant checks for iRawlen==0 * */ 183/* * 1.0.6 - 06/22/2003 - G.R-P * */ 184/* * - added MNG_NO_16BIT_SUPPORT, MNG_NO_DELTA_PNG reductions * */ 185/* * - optionally use zlib's crc32 function instead of * */ 186/* * local mng_update_crc * */ 187/* * 1.0.6 - 07/14/2003 - G.R-P * */ 188/* * - added MNG_NO_LOOP_SIGNALS_SUPPORTED conditional * */ 189/* * 1.0.6 - 07/29/2003 - G.R-P * */ 190/* * - added conditionals around PAST chunk support * */ 191/* * 1.0.6 - 08/17/2003 - G.R-P * */ 192/* * - added conditionals around non-VLC chunk support * */ 193/* * * */ 194/* * 1.0.7 - 10/29/2003 - G.R-P * */ 195/* * - revised JDAA and JDAT readers to avoid compiler bug * */ 196/* * 1.0.7 - 01/25/2004 - J.S * */ 197/* * - added premultiplied alpha canvas' for RGBA, ARGB, ABGR * */ 198/* * 1.0.7 - 01/27/2004 - J.S * */ 199/* * - fixed inclusion of IJNG chunk for non-JNG use * */ 200/* * 1.0.7 - 02/26/2004 - G.Juyn * */ 201/* * - fixed bug in chunk-storage of SHOW chunk (from == to) * */ 202/* * * */ 203/* * 1.0.8 - 04/02/2004 - G.Juyn * */ 204/* * - added CRC existence & checking flags * */ 205/* * 1.0.8 - 07/07/2004 - G.R-P * */ 206/* * - change worst-case iAlphadepth to 1 for standalone PNGs * */ 207/* * * */ 208/* * 1.0.9 - 09/28/2004 - G.R-P * */ 209/* * - improved handling of cheap transparency when 16-bit * */ 210/* * support is disabled * */ 211/* * 1.0.9 - 10/04/2004 - G.Juyn * */ 212/* * - fixed bug in writing sBIT for indexed color * */ 213/* * 1.0.9 - 10/10/2004 - G.R-P. * */ 214/* * - added MNG_NO_1_2_4BIT_SUPPORT * */ 215/* * 1.0.9 - 12/05/2004 - G.Juyn * */ 216/* * - added conditional MNG_OPTIMIZE_CHUNKINITFREE * */ 217/* * 1.0.9 - 12/06/2004 - G.Juyn * */ 218/* * - added conditional MNG_OPTIMIZE_CHUNKASSIGN * */ 219/* * 1.0.9 - 12/07/2004 - G.Juyn * */ 220/* * - added conditional MNG_OPTIMIZE_CHUNKREADER * */ 221/* * 1.0.9 - 12/11/2004 - G.Juyn * */ 222/* * - added conditional MNG_OPTIMIZE_DISPLAYCALLS * */ 223/* * 1.0.9 - 12/20/2004 - G.Juyn * */ 224/* * - cleaned up macro-invocations (thanks to D. Airlie) * */ 225/* * 1.0.9 - 01/17/2005 - G.Juyn * */ 226/* * - fixed problem with global PLTE/tRNS * */ 227/* * * */ 228/* * 1.0.10 - 02/07/2005 - G.Juyn * */ 229/* * - fixed display routines called twice for FULL_MNG * */ 230/* * support in mozlibmngconf.h * */ 231/* * 1.0.10 - 12/04/2005 - G.R-P. * */ 232/* * - #ifdef out use of mng_inflate_buffer when it is not * */ 233/* * available. * */ 234/* * 1.0.10 - 04/08/2007 - G.Juyn * */ 235/* * - added support for mPNG proposal * */ 236/* * 1.0.10 - 04/12/2007 - G.Juyn * */ 237/* * - added support for ANG proposal * */ 238/* * 1.0.10 - 05/02/2007 - G.Juyn * */ 239/* * - fixed inflate_buffer for extreme compression ratios * */ 240/* * * */ 241/* ************************************************************************** */ 242 243#include "libmng.h" 244#include "libmng_data.h" 245#include "libmng_error.h" 246#include "libmng_trace.h" 247#ifdef __BORLANDC__ 248#pragma hdrstop 249#endif 250#include "libmng_objects.h" 251#include "libmng_object_prc.h" 252#include "libmng_chunks.h" 253#ifdef MNG_CHECK_BAD_ICCP 254#include "libmng_chunk_prc.h" 255#endif 256#include "libmng_memory.h" 257#include "libmng_display.h" 258#include "libmng_zlib.h" 259#include "libmng_pixels.h" 260#include "libmng_chunk_io.h" 261 262#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) 263#pragma option -A /* force ANSI-C */ 264#endif 265 266/* ************************************************************************** */ 267/* * * */ 268/* * CRC - Cyclic Redundancy Check * */ 269/* * * */ 270/* * The code below is taken directly from the sample provided with the * */ 271/* * PNG specification. * */ 272/* * (it is only adapted to the library's internal data-definitions) * */ 273/* * * */ 274/* ************************************************************************** */ 275/* Make the table for a fast CRC. */ 276#ifndef MNG_USE_ZLIB_CRC 277MNG_LOCAL void make_crc_table (mng_datap pData) 278{ 279 mng_uint32 iC; 280 mng_int32 iN, iK; 281 282 for (iN = 0; iN < 256; iN++) 283 { 284 iC = (mng_uint32) iN; 285 286 for (iK = 0; iK < 8; iK++) 287 { 288 if (iC & 1) 289 iC = 0xedb88320U ^ (iC >> 1); 290 else 291 iC = iC >> 1; 292 } 293 294 pData->aCRCtable [iN] = iC; 295 } 296 297 pData->bCRCcomputed = MNG_TRUE; 298} 299#endif 300 301/* Update a running CRC with the bytes buf[0..len-1]--the CRC 302 should be initialized to all 1's, and the transmitted value 303 is the 1's complement of the final running CRC (see the 304 crc() routine below). */ 305 306MNG_LOCAL mng_uint32 update_crc (mng_datap pData, 307 mng_uint32 iCrc, 308 mng_uint8p pBuf, 309 mng_int32 iLen) 310{ 311#ifdef MNG_USE_ZLIB_CRC 312 return crc32 (iCrc, pBuf, iLen); 313#else 314 mng_uint32 iC = iCrc; 315 mng_int32 iN; 316 317 if (!pData->bCRCcomputed) 318 make_crc_table (pData); 319 320 for (iN = 0; iN < iLen; iN++) 321 iC = pData->aCRCtable [(iC ^ pBuf [iN]) & 0xff] ^ (iC >> 8); 322 323 return iC; 324#endif 325} 326 327/* Return the CRC of the bytes buf[0..len-1]. */ 328mng_uint32 mng_crc (mng_datap pData, 329 mng_uint8p pBuf, 330 mng_int32 iLen) 331{ 332#ifdef MNG_USE_ZLIB_CRC 333 return update_crc (pData, 0, pBuf, iLen); 334#else 335 return update_crc (pData, 0xffffffffU, pBuf, iLen) ^ 0xffffffffU; 336#endif 337} 338 339/* ************************************************************************** */ 340/* * * */ 341/* * Routines for swapping byte-order from and to graphic files * */ 342/* * (This code is adapted from the libpng package) * */ 343/* * * */ 344/* ************************************************************************** */ 345 346#ifndef MNG_BIGENDIAN_SUPPORTED 347 348/* ************************************************************************** */ 349 350mng_uint32 mng_get_uint32 (mng_uint8p pBuf) 351{ 352 mng_uint32 i = ((mng_uint32)(*pBuf) << 24) + 353 ((mng_uint32)(*(pBuf + 1)) << 16) + 354 ((mng_uint32)(*(pBuf + 2)) << 8) + 355 (mng_uint32)(*(pBuf + 3)); 356 return (i); 357} 358 359/* ************************************************************************** */ 360 361mng_int32 mng_get_int32 (mng_uint8p pBuf) 362{ 363 mng_int32 i = ((mng_int32)(*pBuf) << 24) + 364 ((mng_int32)(*(pBuf + 1)) << 16) + 365 ((mng_int32)(*(pBuf + 2)) << 8) + 366 (mng_int32)(*(pBuf + 3)); 367 return (i); 368} 369 370/* ************************************************************************** */ 371 372mng_uint16 mng_get_uint16 (mng_uint8p pBuf) 373{ 374 mng_uint16 i = (mng_uint16)(((mng_uint16)(*pBuf) << 8) + 375 (mng_uint16)(*(pBuf + 1))); 376 return (i); 377} 378 379/* ************************************************************************** */ 380 381void mng_put_uint32 (mng_uint8p pBuf, 382 mng_uint32 i) 383{ 384 *pBuf = (mng_uint8)((i >> 24) & 0xff); 385 *(pBuf+1) = (mng_uint8)((i >> 16) & 0xff); 386 *(pBuf+2) = (mng_uint8)((i >> 8) & 0xff); 387 *(pBuf+3) = (mng_uint8)(i & 0xff); 388} 389 390/* ************************************************************************** */ 391 392void mng_put_int32 (mng_uint8p pBuf, 393 mng_int32 i) 394{ 395 *pBuf = (mng_uint8)((i >> 24) & 0xff); 396 *(pBuf+1) = (mng_uint8)((i >> 16) & 0xff); 397 *(pBuf+2) = (mng_uint8)((i >> 8) & 0xff); 398 *(pBuf+3) = (mng_uint8)(i & 0xff); 399} 400 401/* ************************************************************************** */ 402 403void mng_put_uint16 (mng_uint8p pBuf, 404 mng_uint16 i) 405{ 406 *pBuf = (mng_uint8)((i >> 8) & 0xff); 407 *(pBuf+1) = (mng_uint8)(i & 0xff); 408} 409 410/* ************************************************************************** */ 411 412#endif /* !MNG_BIGENDIAN_SUPPORTED */ 413 414/* ************************************************************************** */ 415/* * * */ 416/* * Helper routines to simplify chunk-data extraction * */ 417/* * * */ 418/* ************************************************************************** */ 419 420#ifdef MNG_INCLUDE_READ_PROCS 421 422/* ************************************************************************** */ 423 424#ifndef MNG_OPTIMIZE_CHUNKREADER 425MNG_LOCAL mng_uint8p find_null (mng_uint8p pIn) 426{ 427 mng_uint8p pOut = pIn; 428 while (*pOut) /* the read_graphic routine has made sure there's */ 429 pOut++; /* always at least 1 zero-byte in the buffer */ 430 return pOut; 431} 432#endif 433 434/* ************************************************************************** */ 435 436#if !defined(MNG_SKIPCHUNK_iCCP) || !defined(MNG_SKIPCHUNK_zTXt) || \ 437 !defined(MNG_SKIPCHUNK_iTXt) || defined(MNG_INCLUDE_MPNG_PROPOSAL) || \ 438 defined(MNG_INCLUDE_ANG_PROPOSAL) 439mng_retcode mng_inflate_buffer (mng_datap pData, 440 mng_uint8p pInbuf, 441 mng_uint32 iInsize, 442 mng_uint8p *pOutbuf, 443 mng_uint32 *iOutsize, 444 mng_uint32 *iRealsize) 445{ 446 mng_retcode iRetcode = MNG_NOERROR; 447 448#ifdef MNG_SUPPORT_TRACE 449 MNG_TRACE (pData, MNG_FN_INFLATE_BUFFER, MNG_LC_START); 450#endif 451 452 if (iInsize) /* anything to do ? */ 453 { 454 *iOutsize = iInsize * 3; /* estimate uncompressed size */ 455 /* and allocate a temporary buffer */ 456 MNG_ALLOC (pData, *pOutbuf, *iOutsize); 457 458 do 459 { 460 mngzlib_inflateinit (pData); /* initialize zlib */ 461 /* let zlib know where to store the output */ 462 pData->sZlib.next_out = *pOutbuf; 463 /* "size - 1" so we've got space for the 464 zero-termination of a possible string */ 465 pData->sZlib.avail_out = *iOutsize - 1; 466 /* ok; let's inflate... */ 467 iRetcode = mngzlib_inflatedata (pData, iInsize, pInbuf); 468 /* determine actual output size */ 469 *iRealsize = (mng_uint32)pData->sZlib.total_out; 470 471 mngzlib_inflatefree (pData); /* zlib's done */ 472 473 if (iRetcode == MNG_BUFOVERFLOW) /* not enough space ? */ 474 { /* then get some more */ 475 MNG_FREEX (pData, *pOutbuf, *iOutsize); 476 *iOutsize = *iOutsize + *iOutsize; 477 MNG_ALLOC (pData, *pOutbuf, *iOutsize); 478 } 479 } /* repeat if we didn't have enough space */ 480 while ((iRetcode == MNG_BUFOVERFLOW) && 481 (*iOutsize < 200 * iInsize)); 482 483 if (!iRetcode) /* if oke ? */ 484 *((*pOutbuf) + *iRealsize) = 0; /* then put terminator zero */ 485 486 } 487 else 488 { 489 *pOutbuf = 0; /* nothing to do; then there's no output */ 490 *iOutsize = 0; 491 *iRealsize = 0; 492 } 493 494#ifdef MNG_SUPPORT_TRACE 495 MNG_TRACE (pData, MNG_FN_INFLATE_BUFFER, MNG_LC_END); 496#endif 497 498 return iRetcode; 499} 500#endif 501 502/* ************************************************************************** */ 503 504#endif /* MNG_INCLUDE_READ_PROCS */ 505 506/* ************************************************************************** */ 507/* * * */ 508/* * Helper routines to simplify chunk writing * */ 509/* * * */ 510/* ************************************************************************** */ 511#ifdef MNG_INCLUDE_WRITE_PROCS 512/* ************************************************************************** */ 513 514#if !defined(MNG_SKIPCHUNK_iCCP) || !defined(MNG_SKIPCHUNK_zTXt) || !defined(MNG_SKIPCHUNK_iTXt) 515MNG_LOCAL mng_retcode deflate_buffer (mng_datap pData, 516 mng_uint8p pInbuf, 517 mng_uint32 iInsize, 518 mng_uint8p *pOutbuf, 519 mng_uint32 *iOutsize, 520 mng_uint32 *iRealsize) 521{ 522 mng_retcode iRetcode = MNG_NOERROR; 523 524#ifdef MNG_SUPPORT_TRACE 525 MNG_TRACE (pData, MNG_FN_DEFLATE_BUFFER, MNG_LC_START); 526#endif 527 528 if (iInsize) /* anything to do ? */ 529 { 530 *iOutsize = (iInsize * 5) >> 2; /* estimate compressed size */ 531 /* and allocate a temporary buffer */ 532 MNG_ALLOC (pData, *pOutbuf, *iOutsize); 533 534 do 535 { 536 mngzlib_deflateinit (pData); /* initialize zlib */ 537 /* let zlib know where to store the output */ 538 pData->sZlib.next_out = *pOutbuf; 539 pData->sZlib.avail_out = *iOutsize; 540 /* ok; let's deflate... */ 541 iRetcode = mngzlib_deflatedata (pData, iInsize, pInbuf); 542 /* determine actual output size */ 543 *iRealsize = pData->sZlib.total_out; 544 545 mngzlib_deflatefree (pData); /* zlib's done */ 546 547 if (iRetcode == MNG_BUFOVERFLOW) /* not enough space ? */ 548 { /* then get some more */ 549 MNG_FREEX (pData, *pOutbuf, *iOutsize); 550 *iOutsize = *iOutsize + (iInsize >> 1); 551 MNG_ALLOC (pData, *pOutbuf, *iOutsize); 552 } 553 } /* repeat if we didn't have enough space */ 554 while (iRetcode == MNG_BUFOVERFLOW); 555 } 556 else 557 { 558 *pOutbuf = 0; /* nothing to do; then there's no output */ 559 *iOutsize = 0; 560 *iRealsize = 0; 561 } 562 563#ifdef MNG_SUPPORT_TRACE 564 MNG_TRACE (pData, MNG_FN_DEFLATE_BUFFER, MNG_LC_END); 565#endif 566 567 return iRetcode; 568} 569#endif 570 571/* ************************************************************************** */ 572 573MNG_LOCAL mng_retcode write_raw_chunk (mng_datap pData, 574 mng_chunkid iChunkname, 575 mng_uint32 iRawlen, 576 mng_uint8p pRawdata) 577{ 578 mng_uint32 iCrc; 579 mng_uint32 iWritten; 580 581#ifdef MNG_SUPPORT_TRACE 582 MNG_TRACE (pData, MNG_FN_WRITE_RAW_CHUNK, MNG_LC_START); 583#endif 584 /* temporary buffer ? */ 585 if ((pRawdata != 0) && (pRawdata != pData->pWritebuf+8)) 586 { /* store length & chunktype in default buffer */ 587 mng_put_uint32 (pData->pWritebuf, iRawlen); 588 mng_put_uint32 (pData->pWritebuf+4, (mng_uint32)iChunkname); 589 590 if (pData->iCrcmode & MNG_CRC_OUTPUT) 591 { 592 if ((pData->iCrcmode & MNG_CRC_OUTPUT) == MNG_CRC_OUTPUT_GENERATE) 593 { /* calculate the crc */ 594 iCrc = update_crc (pData, 0xffffffffL, pData->pWritebuf+4, 4); 595 iCrc = update_crc (pData, iCrc, pRawdata, iRawlen) ^ 0xffffffffL; 596 } else { 597 iCrc = 0; /* dummy crc */ 598 } /* store in default buffer */ 599 mng_put_uint32 (pData->pWritebuf+8, iCrc); 600 } 601 /* write the length & chunktype */ 602 if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, 8, &iWritten)) 603 MNG_ERROR (pData, MNG_APPIOERROR); 604 605 if (iWritten != 8) /* disk full ? */ 606 MNG_ERROR (pData, MNG_OUTPUTERROR); 607 /* write the temporary buffer */ 608 if (!pData->fWritedata ((mng_handle)pData, pRawdata, iRawlen, &iWritten)) 609 MNG_ERROR (pData, MNG_APPIOERROR); 610 611 if (iWritten != iRawlen) /* disk full ? */ 612 MNG_ERROR (pData, MNG_OUTPUTERROR); 613 614 if (pData->iCrcmode & MNG_CRC_OUTPUT) 615 { /* write the crc */ 616 if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf+8, 4, &iWritten)) 617 MNG_ERROR (pData, MNG_APPIOERROR); 618 619 if (iWritten != 4) /* disk full ? */ 620 MNG_ERROR (pData, MNG_OUTPUTERROR); 621 } 622 } 623 else 624 { /* prefix with length & chunktype */ 625 mng_put_uint32 (pData->pWritebuf, iRawlen); 626 mng_put_uint32 (pData->pWritebuf+4, (mng_uint32)iChunkname); 627 628 if (pData->iCrcmode & MNG_CRC_OUTPUT) 629 { 630 if ((pData->iCrcmode & MNG_CRC_OUTPUT) == MNG_CRC_OUTPUT_GENERATE) 631 /* calculate the crc */ 632 iCrc = mng_crc (pData, pData->pWritebuf+4, iRawlen + 4); 633 else 634 iCrc = 0; /* dummy crc */ 635 /* add it to the buffer */ 636 mng_put_uint32 (pData->pWritebuf + iRawlen + 8, iCrc); 637 /* write it in a single pass */ 638 if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, iRawlen + 12, &iWritten)) 639 MNG_ERROR (pData, MNG_APPIOERROR); 640 641 if (iWritten != iRawlen + 12) /* disk full ? */ 642 MNG_ERROR (pData, MNG_OUTPUTERROR); 643 } else { 644 if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, iRawlen + 8, &iWritten)) 645 MNG_ERROR (pData, MNG_APPIOERROR); 646 647 if (iWritten != iRawlen + 8) /* disk full ? */ 648 MNG_ERROR (pData, MNG_OUTPUTERROR); 649 } 650 } 651 652#ifdef MNG_SUPPORT_TRACE 653 MNG_TRACE (pData, MNG_FN_WRITE_RAW_CHUNK, MNG_LC_END); 654#endif 655 656 return MNG_NOERROR; 657} 658 659/* ************************************************************************** */ 660/* B004 */ 661#endif /* MNG_INCLUDE_WRITE_PROCS */ 662/* B004 */ 663/* ************************************************************************** */ 664/* * * */ 665/* * chunk read functions * */ 666/* * * */ 667/* ************************************************************************** */ 668 669#ifdef MNG_INCLUDE_READ_PROCS 670 671/* ************************************************************************** */ 672 673#ifdef MNG_OPTIMIZE_CHUNKREADER 674 675/* ************************************************************************** */ 676 677MNG_LOCAL mng_retcode create_chunk_storage (mng_datap pData, 678 mng_chunkp pHeader, 679 mng_uint32 iRawlen, 680 mng_uint8p pRawdata, 681 mng_field_descp pField, 682 mng_uint16 iFields, 683 mng_chunkp* ppChunk, 684 mng_bool bWorkcopy) 685{ 686 mng_field_descp pTempfield = pField; 687 mng_uint16 iFieldcount = iFields; 688 mng_uint8p pTempdata = pRawdata; 689 mng_uint32 iTemplen = iRawlen; 690 mng_uint16 iLastgroup = 0; 691 mng_uint8p pChunkdata; 692 mng_uint32 iDatalen; 693 mng_uint8 iColortype; 694 mng_bool bProcess; 695 /* initialize storage */ 696 mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); 697 if (iRetcode) /* on error bail out */ 698 return iRetcode; 699 700 if (((mng_chunk_headerp)(*ppChunk))->iChunkname == MNG_UINT_HUH) 701 ((mng_chunk_headerp)(*ppChunk))->iChunkname = pData->iChunkname; 702 703 if ((!bWorkcopy) || 704 ((((mng_chunk_headerp)pHeader)->iChunkname != MNG_UINT_IDAT) && 705 (((mng_chunk_headerp)pHeader)->iChunkname != MNG_UINT_JDAT) && 706 (((mng_chunk_headerp)pHeader)->iChunkname != MNG_UINT_JDAA) )) 707 { 708 pChunkdata = (mng_uint8p)(*ppChunk); 709 710#ifdef MNG_INCLUDE_JNG /* determine current colortype */ 711 if (pData->bHasJHDR) 712 iColortype = (mng_uint8)(pData->iJHDRcolortype - 8); 713 else 714#endif /* MNG_INCLUDE_JNG */ 715 if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) 716 iColortype = pData->iColortype; 717 else 718 iColortype = 6; 719 720 if (iTemplen) /* not empty ? */ 721 { /* then go fill the fields */ 722 while ((iFieldcount) && (iTemplen)) 723 { 724 if (pTempfield->iOffsetchunk) 725 { 726 if (pTempfield->iFlags & MNG_FIELD_PUTIMGTYPE) 727 { 728 *(pChunkdata+pTempfield->iOffsetchunk) = iColortype; 729 bProcess = MNG_FALSE; 730 } 731 else 732 if (pTempfield->iFlags & MNG_FIELD_IFIMGTYPES) 733 bProcess = (mng_bool)(((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE0) && (iColortype == 0)) || 734 ((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE2) && (iColortype == 2)) || 735 ((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE3) && (iColortype == 3)) || 736 ((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE4) && (iColortype == 4)) || 737 ((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE6) && (iColortype == 6)) ); 738 else 739 bProcess = MNG_TRUE; 740 741 if (bProcess) 742 { 743 iLastgroup = (mng_uint16)(pTempfield->iFlags & MNG_FIELD_GROUPMASK); 744 /* numeric field ? */ 745 if (pTempfield->iFlags & MNG_FIELD_INT) 746 { 747 if (iTemplen < pTempfield->iLengthmax) 748 MNG_ERROR (pData, MNG_INVALIDLENGTH); 749 750 switch (pTempfield->iLengthmax) 751 { 752 case 1 : { mng_uint8 iNum = *pTempdata; 753 if (((mng_uint16)iNum < pTempfield->iMinvalue) || 754 ((mng_uint16)iNum > pTempfield->iMaxvalue) ) 755 MNG_ERROR (pData, MNG_INVALIDFIELDVAL); 756 *(pChunkdata+pTempfield->iOffsetchunk) = iNum; 757 break; } 758 case 2 : { mng_uint16 iNum = mng_get_uint16 (pTempdata); 759 if ((iNum < pTempfield->iMinvalue) || (iNum > pTempfield->iMaxvalue)) 760 MNG_ERROR (pData, MNG_INVALIDFIELDVAL); 761 *((mng_uint16p)(pChunkdata+pTempfield->iOffsetchunk)) = iNum; 762 break; } 763 case 4 : { mng_uint32 iNum = mng_get_uint32 (pTempdata); 764 if ((iNum < pTempfield->iMinvalue) || 765 ((pTempfield->iFlags & MNG_FIELD_NOHIGHBIT) && (iNum & 0x80000000)) ) 766 MNG_ERROR (pData, MNG_INVALIDFIELDVAL); 767 *((mng_uint32p)(pChunkdata+pTempfield->iOffsetchunk)) = iNum; 768 break; } 769 } 770 771 pTempdata += pTempfield->iLengthmax; 772 iTemplen -= pTempfield->iLengthmax; 773 774 } else { /* not numeric so it's a bunch of bytes */ 775 776 if (!pTempfield->iOffsetchunklen) /* big fat NONO */ 777 MNG_ERROR (pData, MNG_INTERNALERROR); 778 /* with terminating 0 ? */ 779 if (pTempfield->iFlags & MNG_FIELD_TERMINATOR) 780 { 781 mng_uint8p pWork = pTempdata; 782 while (*pWork) /* find the zero */ 783 pWork++; 784 iDatalen = (mng_uint32)(pWork - pTempdata); 785 } else { /* no terminator, so everything that's left ! */ 786 iDatalen = iTemplen; 787 } 788 789 if ((pTempfield->iLengthmax) && (iDatalen > pTempfield->iLengthmax)) 790 MNG_ERROR (pData, MNG_INVALIDLENGTH); 791#if !defined(MNG_SKIPCHUNK_iCCP) || !defined(MNG_SKIPCHUNK_zTXt) || \ 792 !defined(MNG_SKIPCHUNK_iTXt) || defined(MNG_INCLUDE_MPNG_PROPOSAL) || \ 793 defined(MNG_INCLUDE_ANG_PROPOSAL) 794 /* needs decompression ? */ 795 if (pTempfield->iFlags & MNG_FIELD_DEFLATED) 796 { 797 mng_uint8p pBuf = 0; 798 mng_uint32 iBufsize = 0; 799 mng_uint32 iRealsize; 800 mng_ptr pWork; 801 802 iRetcode = mng_inflate_buffer (pData, pTempdata, iDatalen, 803 &pBuf, &iBufsize, &iRealsize); 804 805#ifdef MNG_CHECK_BAD_ICCP /* Check for bad iCCP chunk */ 806 if ((iRetcode) && (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_iCCP)) 807 { 808 *((mng_ptr *)(pChunkdata+pTempfield->iOffsetchunk)) = MNG_NULL; 809 *((mng_uint32p)(pChunkdata+pTempfield->iOffsetchunklen)) = iDatalen; 810 } 811 else 812#endif 813 { 814 if (iRetcode) 815 return iRetcode; 816 817#if defined(MNG_INCLUDE_MPNG_PROPOSAL) || defined(MNG_INCLUDE_ANG_PROPOSAL) 818 if ( (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_mpNG) || 819 (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_adAT) ) 820 { 821 MNG_ALLOC (pData, pWork, iRealsize); 822 } 823 else 824 { 825#endif 826 /* don't forget to generate null terminator */ 827 MNG_ALLOC (pData, pWork, iRealsize+1); 828#if defined(MNG_INCLUDE_MPNG_PROPOSAL) || defined(MNG_INCLUDE_ANG_PROPOSAL) 829 } 830#endif 831 MNG_COPY (pWork, pBuf, iRealsize); 832 833 *((mng_ptr *)(pChunkdata+pTempfield->iOffsetchunk)) = pWork; 834 *((mng_uint32p)(pChunkdata+pTempfield->iOffsetchunklen)) = iRealsize; 835 } 836 837 if (pBuf) /* free the temporary buffer */ 838 MNG_FREEX (pData, pBuf, iBufsize); 839 840 } else 841#endif 842 { /* no decompression, so just copy */ 843 844 mng_ptr pWork; 845 /* don't forget to generate null terminator */ 846 MNG_ALLOC (pData, pWork, iDatalen+1); 847 MNG_COPY (pWork, pTempdata, iDatalen); 848 849 *((mng_ptr *)(pChunkdata+pTempfield->iOffsetchunk)) = pWork; 850 *((mng_uint32p)(pChunkdata+pTempfield->iOffsetchunklen)) = iDatalen; 851 } 852 853 if (pTempfield->iFlags & MNG_FIELD_TERMINATOR) 854 iDatalen++; /* skip the terminating zero as well !!! */ 855 856 iTemplen -= iDatalen; 857 pTempdata += iDatalen; 858 } 859 /* need to set an indicator ? */ 860 if (pTempfield->iOffsetchunkind) 861 *((mng_uint8p)(pChunkdata+pTempfield->iOffsetchunkind)) = MNG_TRUE; 862 } 863 } 864 865 if (pTempfield->pSpecialfunc) /* special function required ? */ 866 { 867 iRetcode = pTempfield->pSpecialfunc(pData, *ppChunk, &iTemplen, &pTempdata); 868 if (iRetcode) /* on error bail out */ 869 return iRetcode; 870 } 871 872 pTempfield++; /* Neeeeeeexxxtt */ 873 iFieldcount--; 874 } 875 876 if (iTemplen) /* extra data ??? */ 877 MNG_ERROR (pData, MNG_INVALIDLENGTH); 878 879 while (iFieldcount) /* not enough data ??? */ 880 { 881 if (pTempfield->iFlags & MNG_FIELD_IFIMGTYPES) 882 bProcess = (mng_bool)(((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE0) && (iColortype == 0)) || 883 ((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE2) && (iColortype == 2)) || 884 ((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE3) && (iColortype == 3)) || 885 ((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE4) && (iColortype == 4)) || 886 ((pTempfield->iFlags & MNG_FIELD_IFIMGTYPE6) && (iColortype == 6)) ); 887 else 888 bProcess = MNG_TRUE; 889 890 if (bProcess) 891 { 892 if (!(pTempfield->iFlags & MNG_FIELD_OPTIONAL)) 893 MNG_ERROR (pData, MNG_INVALIDLENGTH); 894 if ((pTempfield->iFlags & MNG_FIELD_GROUPMASK) && 895 ((mng_uint16)(pTempfield->iFlags & MNG_FIELD_GROUPMASK) == iLastgroup)) 896 MNG_ERROR (pData, MNG_INVALIDLENGTH); 897 } 898 899 pTempfield++; 900 iFieldcount--; 901 } 902 } 903 } 904 905 return MNG_NOERROR; 906} 907 908/* ************************************************************************** */ 909 910READ_CHUNK (mng_read_general) 911{ 912 mng_retcode iRetcode = MNG_NOERROR; 913 mng_chunk_descp pDescr = ((mng_chunk_headerp)pHeader)->pChunkdescr; 914 mng_field_descp pField; 915 mng_uint16 iFields; 916 917 if (!pDescr) /* this is a bad booboo !!! */ 918 MNG_ERROR (pData, MNG_INTERNALERROR); 919 920 pField = pDescr->pFielddesc; 921 iFields = pDescr->iFielddesc; 922 /* check chunk against signature */ 923 if ((pDescr->eImgtype == mng_it_mng) && (pData->eSigtype != mng_it_mng)) 924 MNG_ERROR (pData, MNG_CHUNKNOTALLOWED); 925 926 if ((pDescr->eImgtype == mng_it_jng) && (pData->eSigtype == mng_it_png)) 927 MNG_ERROR (pData, MNG_CHUNKNOTALLOWED); 928 /* empties allowed ? */ 929 if ((iRawlen == 0) && (!(pDescr->iAllowed & MNG_DESCR_EMPTY))) 930 MNG_ERROR (pData, MNG_INVALIDLENGTH); 931 932 if ((pData->eImagetype != mng_it_mng) || (!(pDescr->iAllowed & MNG_DESCR_GLOBAL))) 933 { /* *a* header required ? */ 934 if ((pDescr->iMusthaves & MNG_DESCR_GenHDR) && 935#ifdef MNG_INCLUDE_JNG 936 (!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) 937#else 938 (!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR)) 939#endif 940 MNG_ERROR (pData, MNG_SEQUENCEERROR); 941 942#ifdef MNG_INCLUDE_JNG 943 if ((pDescr->iMusthaves & MNG_DESCR_JngHDR) && 944 (!pData->bHasDHDR) && (!pData->bHasJHDR)) 945 MNG_ERROR (pData, MNG_SEQUENCEERROR); 946#endif 947 } 948 /* specific chunk pre-requisite ? */ 949 if (((pDescr->iMusthaves & MNG_DESCR_IHDR) && (!pData->bHasIHDR)) || 950#ifdef MNG_INCLUDE_JNG 951 ((pDescr->iMusthaves & MNG_DESCR_JHDR) && (!pData->bHasJHDR)) || 952#endif 953 ((pDescr->iMusthaves & MNG_DESCR_DHDR) && (!pData->bHasDHDR)) || 954 ((pDescr->iMusthaves & MNG_DESCR_LOOP) && (!pData->bHasLOOP)) || 955 ((pDescr->iMusthaves & MNG_DESCR_PLTE) && (!pData->bHasPLTE)) || 956 ((pDescr->iMusthaves & MNG_DESCR_MHDR) && (!pData->bHasMHDR)) || 957 ((pDescr->iMusthaves & MNG_DESCR_SAVE) && (!pData->bHasSAVE)) ) 958 MNG_ERROR (pData, MNG_SEQUENCEERROR); 959 /* specific chunk undesired ? */ 960 if (((pDescr->iMustNOThaves & MNG_DESCR_NOIHDR) && (pData->bHasIHDR)) || 961 ((pDescr->iMustNOThaves & MNG_DESCR_NOBASI) && (pData->bHasBASI)) || 962 ((pDescr->iMustNOThaves & MNG_DESCR_NODHDR) && (pData->bHasDHDR)) || 963 ((pDescr->iMustNOThaves & MNG_DESCR_NOIDAT) && (pData->bHasIDAT)) || 964 ((pDescr->iMustNOThaves & MNG_DESCR_NOPLTE) && (pData->bHasPLTE)) || 965#ifdef MNG_INCLUDE_JNG 966 ((pDescr->iMustNOThaves & MNG_DESCR_NOJHDR) && (pData->bHasJHDR)) || 967 ((pDescr->iMustNOThaves & MNG_DESCR_NOJDAT) && (pData->bHasJDAT)) || 968 ((pDescr->iMustNOThaves & MNG_DESCR_NOJDAA) && (pData->bHasJDAA)) || 969 ((pDescr->iMustNOThaves & MNG_DESCR_NOJSEP) && (pData->bHasJSEP)) || 970#endif 971 ((pDescr->iMustNOThaves & MNG_DESCR_NOMHDR) && (pData->bHasMHDR)) || 972 ((pDescr->iMustNOThaves & MNG_DESCR_NOLOOP) && (pData->bHasLOOP)) || 973 ((pDescr->iMustNOThaves & MNG_DESCR_NOTERM) && (pData->bHasTERM)) || 974 ((pDescr->iMustNOThaves & MNG_DESCR_NOSAVE) && (pData->bHasSAVE)) ) 975 MNG_ERROR (pData, MNG_SEQUENCEERROR); 976 977 if (pData->eSigtype == mng_it_mng) /* check global and embedded empty chunks */ 978 { 979#ifdef MNG_INCLUDE_JNG 980 if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) 981#else 982 if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) 983#endif 984 { 985 if ((iRawlen == 0) && (!(pDescr->iAllowed & MNG_DESCR_EMPTYEMBED))) 986 MNG_ERROR (pData, MNG_INVALIDLENGTH); 987 } else { 988 if ((iRawlen == 0) && (!(pDescr->iAllowed & MNG_DESCR_EMPTYGLOBAL))) 989 MNG_ERROR (pData, MNG_INVALIDLENGTH); 990 } 991 } 992 993 if (pDescr->pSpecialfunc) /* need special processing ? */ 994 { 995 iRetcode = create_chunk_storage (pData, pHeader, iRawlen, pRawdata, 996 pField, iFields, ppChunk, MNG_TRUE); 997 if (iRetcode) /* on error bail out */ 998 return iRetcode; 999 /* empty indicator ? */ 1000 if ((!iRawlen) && (pDescr->iOffsetempty)) 1001 *(((mng_uint8p)*ppChunk)+pDescr->iOffsetempty) = MNG_TRUE; 1002 1003 iRetcode = pDescr->pSpecialfunc(pData, *ppChunk); 1004 if (iRetcode) /* on error bail out */ 1005 return iRetcode; 1006 1007 if ((((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_IDAT) || 1008 (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAT) || 1009 (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAA) ) 1010 { 1011 iRetcode = ((mng_chunk_headerp)*ppChunk)->fCleanup (pData, *ppChunk); 1012 if (iRetcode) /* on error bail out */ 1013 return iRetcode; 1014 *ppChunk = MNG_NULL; 1015 } else { 1016#ifdef MNG_STORE_CHUNKS 1017 if (!pData->bStorechunks) 1018#endif 1019 { 1020 iRetcode = ((mng_chunk_headerp)*ppChunk)->fCleanup (pData, *ppChunk); 1021 if (iRetcode) /* on error bail out */ 1022 return iRetcode; 1023 *ppChunk = MNG_NULL; 1024 } 1025 } 1026 } 1027 1028#ifdef MNG_SUPPORT_DISPLAY 1029 if (iRawlen) 1030 { 1031#ifdef MNG_OPTIMIZE_DISPLAYCALLS 1032 pData->iRawlen = iRawlen; 1033 pData->pRawdata = pRawdata; 1034#endif 1035 1036 /* display processing */ 1037#ifndef MNG_OPTIMIZE_DISPLAYCALLS 1038 if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_IDAT) 1039 iRetcode = mng_process_display_idat (pData, iRawlen, pRawdata); 1040#ifdef MNG_INCLUDE_JNG 1041 else 1042 if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAT) 1043 iRetcode = mng_process_display_jdat (pData, iRawlen, pRawdata); 1044 else 1045 if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAA) 1046 iRetcode = mng_process_display_jdaa (pData, iRawlen, pRawdata); 1047#endif 1048#else 1049 if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_IDAT) 1050 iRetcode = mng_process_display_idat (pData); 1051#ifdef MNG_INCLUDE_JNG 1052 else 1053 if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAT) 1054 iRetcode = mng_process_display_jdat (pData); 1055 else 1056 if (((mng_chunk_headerp)pHeader)->iChunkname == MNG_UINT_JDAA) 1057 iRetcode = mng_process_display_jdaa (pData); 1058#endif 1059#endif 1060 1061 if (iRetcode) 1062 return iRetcode; 1063 } 1064#endif /* MNG_SUPPORT_DISPLAY */ 1065 1066#ifdef MNG_STORE_CHUNKS 1067 if ((pData->bStorechunks) && (!(*ppChunk))) 1068 { 1069 iRetcode = create_chunk_storage (pData, pHeader, iRawlen, pRawdata, 1070 pField, iFields, ppChunk, MNG_FALSE); 1071 if (iRetcode) /* on error bail out */ 1072 return iRetcode; 1073 /* empty indicator ? */ 1074 if ((!iRawlen) && (pDescr->iOffsetempty)) 1075 *(((mng_uint8p)*ppChunk)+pDescr->iOffsetempty) = MNG_TRUE; 1076 } 1077#endif /* MNG_STORE_CHUNKS */ 1078 1079 return MNG_NOERROR; 1080} 1081 1082/* ************************************************************************** */ 1083 1084#endif /* MNG_OPTIMIZE_CHUNKREADER */ 1085 1086/* ************************************************************************** */ 1087 1088#ifndef MNG_OPTIMIZE_CHUNKREADER 1089READ_CHUNK (mng_read_ihdr) 1090{ 1091#ifdef MNG_SUPPORT_TRACE 1092 MNG_TRACE (pData, MNG_FN_READ_IHDR, MNG_LC_START); 1093#endif 1094 1095 if (iRawlen != 13) /* length oke ? */ 1096 MNG_ERROR (pData, MNG_INVALIDLENGTH); 1097 /* only allowed inside PNG or MNG */ 1098 if ((pData->eSigtype != mng_it_png) && (pData->eSigtype != mng_it_mng)) 1099 MNG_ERROR (pData, MNG_CHUNKNOTALLOWED); 1100 /* sequence checks */ 1101 if ((pData->eSigtype == mng_it_png) && (pData->iChunkseq > 1)) 1102 MNG_ERROR (pData, MNG_SEQUENCEERROR); 1103 1104#ifdef MNG_INCLUDE_JNG 1105 if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasIDAT) || (pData->bHasJHDR)) 1106#else 1107 if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasIDAT)) 1108#endif 1109 MNG_ERROR (pData, MNG_SEQUENCEERROR); 1110 1111 pData->bHasIHDR = MNG_TRUE; /* indicate IHDR is present */ 1112 /* and store interesting fields */ 1113 if ((!pData->bHasDHDR) || (pData->iDeltatype == MNG_DELTATYPE_NOCHANGE)) 1114 { 1115 pData->iDatawidth = mng_get_uint32 (pRawdata); 1116 pData->iDataheight = mng_get_uint32 (pRawdata+4); 1117 } 1118 1119 pData->iBitdepth = *(pRawdata+8); 1120 pData->iColortype = *(pRawdata+9); 1121 pData->iCompression = *(pRawdata+10); 1122 pData->iFilter = *(pRawdata+11); 1123 pData->iInterlace = *(pRawdata+12); 1124 1125#if defined(MNG_NO_1_2_4BIT_SUPPORT) || defined(MNG_NO_16BIT_SUPPORT) 1126 pData->iPNGmult = 1; 1127 pData->iPNGdepth = pData->iBitdepth; 1128#endif 1129 1130#ifdef MNG_NO_1_2_4BIT_SUPPORT 1131 if (pData->iBitdepth < 8) 1132 pData->iBitdepth = 8; 1133#endif 1134 1135#ifdef MNG_NO_16BIT_SUPPORT 1136 if (pData->iBitdepth > 8) 1137 { 1138 pData->iBitdepth = 8; 1139 pData->iPNGmult = 2; 1140 } 1141#endif 1142 1143 if ((pData->iBitdepth != 8) /* parameter validity checks */ 1144#ifndef MNG_NO_1_2_4BIT_SUPPORT 1145 && (pData->iBitdepth != 1) && 1146 (pData->iBitdepth != 2) && 1147 (pData->iBitdepth != 4) 1148#endif 1149#ifndef MNG_NO_16BIT_SUPPORT 1150 && (pData->iBitdepth != 16) 1151#endif 1152 ) 1153 MNG_ERROR (pData, MNG_INVALIDBITDEPTH); 1154 1155 if ((pData->iColortype != MNG_COLORTYPE_GRAY ) && 1156 (pData->iColortype != MNG_COLORTYPE_RGB ) && 1157 (pData->iColortype != MNG_COLORTYPE_INDEXED) && 1158 (pData->iColortype != MNG_COLORTYPE_GRAYA ) && 1159 (pData->iColortype != MNG_COLORTYPE_RGBA ) ) 1160 MNG_ERROR (pData, MNG_INVALIDCOLORTYPE); 1161 1162 if ((pData->iColortype == MNG_COLORTYPE_INDEXED) && (pData->iBitdepth > 8)) 1163 MNG_ERROR (pData, MNG_INVALIDBITDEPTH); 1164 1165 if (((pData->iColortype == MNG_COLORTYPE_RGB ) || 1166 (pData->iColortype == MNG_COLORTYPE_GRAYA ) || 1167 (pData->iColortype == MNG_COLORTYPE_RGBA ) ) && 1168 (pData->iBitdepth < 8 ) ) 1169 MNG_ERROR (pData, MNG_INVALIDBITDEPTH); 1170 1171 if (pData->iCompression != MNG_COMPRESSION_DEFLATE) 1172 MNG_ERROR (pData, MNG_INVALIDCOMPRESS); 1173 1174#if defined(FILTER192) || defined(FILTER193) 1175 if ((pData->iFilter != MNG_FILTER_ADAPTIVE ) && 1176#if defined(FILTER192) && defined(FILTER193) 1177 (pData->iFilter != MNG_FILTER_DIFFERING) && 1178 (pData->iFilter != MNG_FILTER_NOFILTER ) ) 1179#else 1180#ifdef FILTER192 1181 (pData->iFilter != MNG_FILTER_DIFFERING) ) 1182#else 1183 (pData->iFilter != MNG_FILTER_NOFILTER ) ) 1184#endif 1185#endif 1186 MNG_ERROR (pData, MNG_INVALIDFILTER); 1187#else 1188 if (pData->iFilter) 1189 MNG_ERROR (pData, MNG_INVALIDFILTER); 1190#endif 1191 1192 if ((pData->iInterlace != MNG_INTERLACE_NONE ) && 1193 (pData->iInterlace != MNG_INTERLACE_ADAM7) ) 1194 MNG_ERROR (pData, MNG_INVALIDINTERLACE); 1195 1196#ifdef MNG_SUPPORT_DISPLAY 1197#ifndef MNG_NO_DELTA_PNG 1198 if (pData->bHasDHDR) /* check the colortype for delta-images ! */ 1199 { 1200 mng_imagedatap pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; 1201 1202 if (pData->iColortype != pBuf->iColortype) 1203 { 1204 if ( ( (pData->iColortype != MNG_COLORTYPE_INDEXED) || 1205 (pBuf->iColortype == MNG_COLORTYPE_GRAY ) ) && 1206 ( (pData->iColortype != MNG_COLORTYPE_GRAY ) || 1207 (pBuf->iColortype == MNG_COLORTYPE_INDEXED) ) ) 1208 MNG_ERROR (pData, MNG_INVALIDCOLORTYPE); 1209 } 1210 } 1211#endif 1212#endif 1213 1214 if (!pData->bHasheader) /* first chunk ? */ 1215 { 1216 pData->bHasheader = MNG_TRUE; /* we've got a header */ 1217 pData->eImagetype = mng_it_png; /* then this must be a PNG */ 1218 pData->iWidth = pData->iDatawidth; 1219 pData->iHeight = pData->iDataheight; 1220 /* predict alpha-depth ! */ 1221 if ((pData->iColortype == MNG_COLORTYPE_GRAYA ) || 1222 (pData->iColortype == MNG_COLORTYPE_RGBA ) ) 1223 pData->iAlphadepth = pData->iBitdepth; 1224 else 1225 if (pData->iColortype == MNG_COLORTYPE_INDEXED) 1226 pData->iAlphadepth = 8; /* worst case scenario */ 1227 else 1228 pData->iAlphadepth = 1; /* Possible tRNS cheap binary transparency */ 1229 /* fits on maximum canvas ? */ 1230 if ((pData->iWidth > pData->iMaxwidth) || (pData->iHeight > pData->iMaxheight)) 1231 MNG_WARNING (pData, MNG_IMAGETOOLARGE); 1232 1233#if !defined(MNG_INCLUDE_MPNG_PROPOSAL) || !defined(MNG_SUPPORT_DISPLAY) 1234 if (pData->fProcessheader) /* inform the app ? */ 1235 if (!pData->fProcessheader (((mng_handle)pData), pData->iWidth, pData->iHeight)) 1236 MNG_ERROR (pData, MNG_APPMISCERROR); 1237#endif 1238 } 1239 1240 if (!pData->bHasDHDR) 1241 pData->iImagelevel++; /* one level deeper */ 1242 1243#ifdef MNG_SUPPORT_DISPLAY 1244 { 1245 mng_retcode iRetcode = mng_process_display_ihdr (pData); 1246 1247 if (iRetcode) /* on error bail out */ 1248 return iRetcode; 1249 } 1250#endif /* MNG_SUPPORT_DISPLAY */ 1251 1252#ifdef MNG_STORE_CHUNKS 1253 if (pData->bStorechunks) 1254 { /* initialize storage */ 1255 mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); 1256 1257 if (iRetcode) /* on error bail out */ 1258 return iRetcode; 1259 /* fill the fields */ 1260 ((mng_ihdrp)*ppChunk)->iWidth = mng_get_uint32 (pRawdata); 1261 ((mng_ihdrp)*ppChunk)->iHeight = mng_get_uint32 (pRawdata+4); 1262 ((mng_ihdrp)*ppChunk)->iBitdepth = pData->iBitdepth; 1263 ((mng_ihdrp)*ppChunk)->iColortype = pData->iColortype; 1264 ((mng_ihdrp)*ppChunk)->iCompression = pData->iCompression; 1265 ((mng_ihdrp)*ppChunk)->iFilter = pData->iFilter; 1266 ((mng_ihdrp)*ppChunk)->iInterlace = pData->iInterlace; 1267 } 1268#endif /* MNG_STORE_CHUNKS */ 1269 1270#ifdef MNG_SUPPORT_TRACE 1271 MNG_TRACE (pData, MNG_FN_READ_IHDR, MNG_LC_END); 1272#endif 1273 1274 return MNG_NOERROR; /* done */ 1275} 1276#endif /* MNG_OPTIMIZE_CHUNKREADER */ 1277 1278/* ************************************************************************** */ 1279 1280#ifndef MNG_OPTIMIZE_CHUNKREADER 1281READ_CHUNK (mng_read_plte) 1282{ 1283#if defined(MNG_SUPPORT_DISPLAY) || defined(MNG_STORE_CHUNKS) 1284 mng_uint32 iX; 1285 mng_uint8p pRawdata2; 1286#endif 1287#ifdef MNG_SUPPORT_DISPLAY 1288 mng_uint32 iRawlen2; 1289#endif 1290 1291#ifdef MNG_SUPPORT_TRACE 1292 MNG_TRACE (pData, MNG_FN_READ_PLTE, MNG_LC_START); 1293#endif 1294 /* sequence checks */ 1295 if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && 1296 (!pData->bHasBASI) && (!pData->bHasDHDR) ) 1297 MNG_ERROR (pData, MNG_SEQUENCEERROR); 1298 1299#ifdef MNG_INCLUDE_JNG 1300 if ((pData->bHasIDAT) || (pData->bHasJHDR)) 1301#else 1302 if (pData->bHasIDAT) 1303#endif 1304 MNG_ERROR (pData, MNG_SEQUENCEERROR); 1305 /* multiple PLTE only inside BASI */ 1306 if ((pData->bHasPLTE) && (!pData->bHasBASI)) 1307 MNG_ERROR (pData, MNG_MULTIPLEERROR); 1308 /* length must be multiple of 3 */ 1309 if (((iRawlen % 3) != 0) || (iRawlen > 768)) 1310 MNG_ERROR (pData, MNG_INVALIDLENGTH); 1311 1312 if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) 1313 { /* only allowed for indexed-color or 1314 rgb(a)-color! */ 1315 if ((pData->iColortype != 2) && (pData->iColortype != 3) && (pData->iColortype != 6)) 1316 MNG_ERROR (pData, MNG_CHUNKNOTALLOWED); 1317 /* empty only allowed if global present */ 1318 if ((iRawlen == 0) && (!pData->bHasglobalPLTE)) 1319 MNG_ERROR (pData, MNG_CANNOTBEEMPTY); 1320 } 1321 else 1322 { 1323 if (iRawlen == 0) /* cannot be empty as global! */ 1324 MNG_ERROR (pData, MNG_CANNOTBEEMPTY); 1325 } 1326 1327 if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) 1328 pData->bHasPLTE = MNG_TRUE; /* got it! */ 1329 else 1330 pData->bHasglobalPLTE = MNG_TRUE; 1331 1332 pData->iPLTEcount = iRawlen / 3; 1333 1334#ifdef MNG_SUPPORT_DISPLAY 1335 if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) 1336 { 1337 mng_imagep pImage; 1338 mng_imagedatap pBuf; 1339 1340#ifndef MNG_NO_DELTA_PNG 1341 if (pData->bHasDHDR) /* processing delta-image ? */ 1342 { /* store in object 0 !!! */ 1343 pImage = (mng_imagep)pData->pObjzero; 1344 pBuf = pImage->pImgbuf; 1345 pBuf->bHasPLTE = MNG_TRUE; /* it's definitely got a PLTE now */ 1346 pBuf->iPLTEcount = iRawlen / 3; /* this is the exact length */ 1347 pRawdata2 = pRawdata; /* copy the entries */ 1348 1349 for (iX = 0; iX < iRawlen / 3; iX++) 1350 { 1351 pBuf->aPLTEentries[iX].iRed = *pRawdata2; 1352 pBuf->aPLTEentries[iX].iGreen = *(pRawdata2+1); 1353 pBuf->aPLTEentries[iX].iBlue = *(pRawdata2+2); 1354 1355 pRawdata2 += 3; 1356 } 1357 } 1358 else 1359#endif 1360 { /* get the current object */ 1361 pImage = (mng_imagep)pData->pCurrentobj; 1362 1363 if (!pImage) /* no object then dump it in obj 0 */ 1364 pImage = (mng_imagep)pData->pObjzero; 1365 1366 pBuf = pImage->pImgbuf; /* address the object buffer */ 1367 pBuf->bHasPLTE = MNG_TRUE; /* and tell it it's got a PLTE now */ 1368 1369 if (!iRawlen) /* if empty, inherit from global */ 1370 { 1371 pBuf->iPLTEcount = pData->iGlobalPLTEcount; 1372 MNG_COPY (pBuf->aPLTEentries, pData->aGlobalPLTEentries, 1373 sizeof (pBuf->aPLTEentries)); 1374 1375 if (pData->bHasglobalTRNS) /* also copy global tRNS ? */ 1376 { /* indicate tRNS available */ 1377 pBuf->bHasTRNS = MNG_TRUE; 1378 1379 iRawlen2 = pData->iGlobalTRNSrawlen; 1380 pRawdata2 = (mng_uint8p)(pData->aGlobalTRNSrawdata); 1381 /* global length oke ? */ 1382 if ((iRawlen2 == 0) || (iRawlen2 > pBuf->iPLTEcount)) 1383 MNG_ERROR (pData, MNG_GLOBALLENGTHERR); 1384 /* copy it */ 1385 pBuf->iTRNScount = iRawlen2; 1386 MNG_COPY (pBuf->aTRNSentries, pRawdata2, iRawlen2); 1387 } 1388 } 1389 else 1390 { /* store fields for future reference */ 1391 pBuf->iPLTEcount = iRawlen / 3; 1392 pRawdata2 = pRawdata; 1393 1394 for (iX = 0; iX < pBuf->iPLTEcount; iX++) 1395 { 1396 pBuf->aPLTEentries[iX].iRed = *pRawdata2; 1397 pBuf->aPLTEentries[iX].iGreen = *(pRawdata2+1); 1398 pBuf->aPLTEentries[iX].iBlue = *(pRawdata2+2); 1399 1400 pRawdata2 += 3; 1401 } 1402 } 1403 } 1404 } 1405 else /* store as global */ 1406 { 1407 pData->iGlobalPLTEcount = iRawlen / 3; 1408 pRawdata2 = pRawdata; 1409 1410 for (iX = 0; iX < pData->iGlobalPLTEcount; iX++) 1411 { 1412 pData->aGlobalPLTEentries[iX].iRed = *pRawdata2; 1413 pData->aGlobalPLTEentries[iX].iGreen = *(pRawdata2+1); 1414 pData->aGlobalPLTEentries[iX].iBlue = *(pRawdata2+2); 1415 1416 pRawdata2 += 3; 1417 } 1418 1419 { /* create an animation object */ 1420 mng_retcode iRetcode = mng_create_ani_plte (pData, pData->iGlobalPLTEcount, 1421 pData->aGlobalPLTEentries); 1422 if (iRetcode) /* on error bail out */ 1423 return iRetcode; 1424 } 1425 } 1426#endif /* MNG_SUPPORT_DISPLAY */ 1427 1428#ifdef MNG_STORE_CHUNKS 1429 if (pData->bStorechunks) 1430 { /* initialize storage */ 1431 mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); 1432 1433 if (iRetcode) /* on error bail out */ 1434 return iRetcode; 1435 /* store the fields */ 1436 ((mng_pltep)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); 1437 ((mng_pltep)*ppChunk)->iEntrycount = iRawlen / 3; 1438 pRawdata2 = pRawdata; 1439 1440 for (iX = 0; iX < ((mng_pltep)*ppChunk)->iEntrycount; iX++) 1441 { 1442 ((mng_pltep)*ppChunk)->aEntries[iX].iRed = *pRawdata2; 1443 ((mng_pltep)*ppChunk)->aEntries[iX].iGreen = *(pRawdata2+1); 1444 ((mng_pltep)*ppChunk)->aEntries[iX].iBlue = *(pRawdata2+2); 1445 1446 pRawdata2 += 3; 1447 } 1448 } 1449#endif /* MNG_STORE_CHUNKS */ 1450 1451#ifdef MNG_SUPPORT_TRACE 1452 MNG_TRACE (pData, MNG_FN_READ_PLTE, MNG_LC_END); 1453#endif 1454 1455 return MNG_NOERROR; /* done */ 1456} 1457#endif /* MNG_OPTIMIZE_CHUNKREADER */ 1458 1459/* *******************