PageRenderTime 94ms CodeModel.GetById 2ms app.highlight 63ms RepoModel.GetById 1ms app.codeStats 1ms

/pngdefry.c

https://github.com/appurify/pngdefry
C | 1514 lines | 1277 code | 117 blank | 120 comment | 292 complexity | b798eea2465999bddbd867f1a23f2fe0 MD5 | raw file
   1/* pngdefry.c v1.1 - public domain PNG reading/writing/modification, PNG writing
   2   See "unlicense" statement at the end of this file.
   3
   4	[Jongware], 21-Jan-2012
   5
   6	Attempts to repair -iphone "optimized" PNG images by removing the invalid chunk "CgBI",
   7	swapping pixel order from BGR(A) to RGB(A), and removing pre-multiplied alpha.
   8
   9	Use with care. No guarantees.
  10
  11	This program uses miniz.c (http://code.google.com/p/miniz/) by Rich Geldreich
  12	(Rich Geldreich <richgel99@gmail.com>, last updated May 27, 2011)
  13	Version used is included in the original file package.
  14
  15	No-License Agreement
  16	====================
  17	This program is hereby put into the public domain, no limitations at all. Do with this code
  18	whatever you want, I don't care. (Well, replacing my name with yours and leaving everything
  19	else unchanged would be pretty lame.)
  20*/
  21
  22#include <stdio.h>
  23#include <stdlib.h>
  24#include <string.h>
  25#include <strings.h>
  26#include <sys/types.h>
  27
  28#include "miniz.c"
  29
  30
  31/** Global flags, set on the command line **/
  32int flag_Verbose = 0;
  33int flag_Process_Anyway = 0;
  34int flag_List_Chunks = 0;
  35int flag_Debug = 0;
  36int flag_UpdateAlpha = 1;
  37int repack_IDAT_size = 524288;	/* 512K -- seems a bit much to me, axually, but have seen this used */
  38
  39int flag_Rewrite = 0;
  40
  41char *suffix = NULL;
  42char *outputPath = NULL;
  43
  44unsigned char png_magic_bytes[] = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
  45
  46/** Chunk data comes here **/
  47
  48struct chunk_t {
  49	unsigned int length;
  50	unsigned int id;
  51	unsigned char *data;
  52	unsigned int crc32;
  53};
  54
  55int num_chunks = 0;
  56int max_chunks = 0;
  57
  58struct chunk_t *pngChunks = NULL;
  59
  60
  61/** CRC32 generator for a block of data, thanks to Marc Autret
  62	(he wrote this original code in Javascript for use in InDesign!) **/
  63
  64unsigned int CRC_256[] = {
  65	0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
  66	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
  67	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
  68	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
  69	0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,
  70	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
  71	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
  72	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
  73	0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,
  74	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
  75	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
  76	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
  77	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,
  78	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
  79	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
  80	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
  81};
  82
  83int crc32s (unsigned char *buf, int buf_length)
  84{
  85	unsigned int c = 0xffffffff;
  86	int i;
  87	for (i=0; i < buf_length; i++ )
  88		c = CRC_256[(c ^ buf[i]) & 0xff] ^ (c >> 8);
  89
  90	return (c ^ 0xffffffff);
  91};
  92
  93int get_long (FILE *f)
  94{
  95	return (fgetc(f)<<24) + (fgetc(f)<<16) + (fgetc(f)<<8) + fgetc(f);
  96}
  97
  98int get_short (FILE *f)
  99{
 100	return (fgetc(f)<<8) + fgetc(f);
 101}
 102
 103int read_long (void *src)
 104{
 105	return (((unsigned char *)src)[0]<<24) + (((unsigned char *)src)[1]<<16) + (((unsigned char *)src)[2]<<8) + ((unsigned char *)src)[3];
 106}
 107
 108
 109int init_chunk (FILE *f, unsigned int filelength)
 110{
 111	struct chunk_t one_chunk;
 112	unsigned char buf[8];
 113	
 114	if (fread (buf, 1,4, f) != 4)
 115	{
 116		if (feof(f))
 117			return 0;
 118		if (flag_Debug)
 119			printf ("    informational : failed to read chunk length\n");
 120		return -3;
 121	}
 122
 123	one_chunk.length = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
 124	
 125	if (one_chunk.length > filelength-4)
 126	{
 127		if (flag_Debug)
 128			printf ("    informational : chunk length %u larger than file\n", one_chunk.length);
 129		return -1;
 130	}
 131	
 132	one_chunk.data = (unsigned char *)malloc (one_chunk.length+4);
 133	if (one_chunk.data == NULL)
 134	{
 135		if (flag_Debug)
 136			printf ("    informational : no memory for chunk length %u\n", one_chunk.length);
 137		return -2;
 138	}
 139	if (fread (one_chunk.data, 1, one_chunk.length+4, f) != one_chunk.length+4)
 140	{
 141		if (flag_Debug)
 142			printf ("    informational : failed to read chunk length %u\n", one_chunk.length);
 143		return -3;
 144	}
 145	one_chunk.id = (one_chunk.data[0] << 24) + (one_chunk.data[1] << 16) + (one_chunk.data[2] << 8) + one_chunk.data[3];
 146
 147	if (fread (buf, 1,4, f) != 4)
 148	{
 149		if (flag_Debug)
 150			printf ("    informational : failed to read chunk crc32\n");
 151		return -3;
 152	}
 153	one_chunk.crc32 = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
 154
 155	if (num_chunks >= max_chunks)
 156	{
 157		max_chunks += 8;
 158		if (pngChunks == NULL)
 159			pngChunks = (struct chunk_t *)malloc (max_chunks * sizeof(struct chunk_t));
 160		else
 161			pngChunks = (struct chunk_t *)realloc (pngChunks, max_chunks * sizeof(struct chunk_t));
 162	}
 163	pngChunks[num_chunks].id = one_chunk.id;
 164	pngChunks[num_chunks].length = one_chunk.length;
 165	pngChunks[num_chunks].data = one_chunk.data;
 166	pngChunks[num_chunks].crc32 = one_chunk.crc32;
 167	num_chunks++;
 168
 169	return 0;
 170}
 171
 172void reset_chunks (void)
 173{
 174	int i;
 175
 176	for (i=0; i<num_chunks; i++)
 177	{
 178		if (pngChunks[i].length && pngChunks[i].data)
 179		{
 180			free (pngChunks[i].data);
 181			pngChunks[i].data = NULL;
 182		}
 183	}
 184	num_chunks = 0;
 185}
 186
 187void demultiplyAlpha (int wide, int high, unsigned char *data)
 188{
 189	int x,y;
 190	unsigned char *srcPtr;
 191
 192	srcPtr = data;
 193
 194	for (y=0; y<high; y++)
 195	{
 196		/* skip rowfilter -- it's assumed to be 0 here anyway! */
 197		srcPtr++;
 198		for (x=0; x<4*wide; x+=4)
 199		{
 200			if (srcPtr[x+3])
 201			{
 202				srcPtr[x] = (srcPtr[x]*255+(srcPtr[x+3]>>1))/srcPtr[x+3];
 203				srcPtr[x+1] = (srcPtr[x+1]*255+(srcPtr[x+3]>>1))/srcPtr[x+3];
 204				srcPtr[x+2] = (srcPtr[x+2]*255+(srcPtr[x+3]>>1))/srcPtr[x+3];
 205			}
 206		}
 207		srcPtr += 4*wide;
 208	}
 209}
 210
 211void removeRowFilters (int wide, int high, unsigned char *data)
 212{
 213	int x,y, rowfilter;
 214	unsigned char *srcPtr, *upPtr;
 215
 216	srcPtr = data;
 217
 218	for (y=0; y<high; y++)
 219	{
 220		rowfilter = *srcPtr;
 221		/*	Need to save original filter for re-applying! */
 222		/*	*srcPtr = 0; */
 223		srcPtr++;
 224		switch (rowfilter)
 225		{
 226			case 0:	// None
 227				break;
 228			case 1:	// Sub
 229				for (x=4; x<4*wide; x++)
 230				{
 231					srcPtr[x] += srcPtr[x-4];
 232				}
 233				break;
 234			case 2:	// Up
 235				upPtr = srcPtr - 4*wide - 1;
 236				if (y > 0)
 237				{
 238					for (x=0; x<4*wide; x++)
 239					{
 240						srcPtr[x] += upPtr[x];
 241					}
 242				}
 243				break;
 244			case 3:	// Average
 245				upPtr = srcPtr - 4*wide - 1;
 246				if (y == 0)
 247				{
 248					for (x=4; x<4*wide; x++)
 249					{
 250						srcPtr[x] += (srcPtr[x-4]>>1);
 251					}
 252				} else
 253				{
 254					srcPtr[0] += (upPtr[x]>>1);
 255					for (x=4; x<4*wide; x++)
 256					{
 257						srcPtr[x] += ((upPtr[x] + srcPtr[x-4])>>1);
 258					}
 259				}
 260				break;
 261			case 4:	// Paeth
 262				upPtr = srcPtr - 4*wide - 1;
 263				{
 264					int p,pa,pb,pc,value;
 265					int leftpix,toppix,topleftpix;
 266
 267					for (x=0; x<4*wide; x++)
 268					{
 269						leftpix = 0;
 270						toppix = 0;
 271						topleftpix = 0;
 272						if (x > 0)
 273							leftpix = srcPtr[x-4];
 274						if (y > 0)
 275						{
 276							toppix = upPtr[x];
 277							if (x >= 4)
 278								topleftpix = upPtr[x-4];
 279						}
 280						p = leftpix + toppix - topleftpix;
 281						pa = p - leftpix; if (pa < 0) pa = -pa;
 282						pb = p - toppix; if (pb < 0) pb = -pb;
 283						pc = p - topleftpix; if (pc < 0) pc = -pc;
 284						if (pa <= pb && pa <= pc)
 285							value = leftpix;
 286						else if (pb <= pc)
 287							value = toppix;
 288						else
 289							value = topleftpix;
 290
 291						srcPtr[x] += value;
 292					}
 293				}
 294				break;
 295			default:
 296				printf ("removerowfilter() : Unknown row filter %d\n", rowfilter);
 297		}
 298		srcPtr += 4*wide;
 299	}
 300}
 301
 302void applyRowFilters (int wide, int high, unsigned char *data)
 303{
 304	int x,y, rowfilter;
 305	unsigned char *srcPtr, *upPtr;
 306
 307	srcPtr = data;
 308
 309	for (y=0; y<high; y++)
 310	{
 311		rowfilter = *srcPtr;
 312		srcPtr++;
 313		switch (rowfilter)
 314		{
 315			case 0:	// None
 316				break;
 317			case 1:	// Sub
 318				for (x=4*wide-1; x>=4; x--)
 319				{
 320					srcPtr[x] -= srcPtr[x-4];
 321				}
 322				break;
 323			case 2:	// Up
 324				if (y > 0)
 325				{
 326					upPtr = srcPtr - 1;
 327					for (x=4*wide-1; x>=0; x--)
 328					{
 329						srcPtr[x] -= upPtr[x];
 330					}
 331				}
 332				break;
 333			case 3:	// Average
 334				upPtr = srcPtr - 4*wide - 1;
 335				if (y == 0)
 336				{
 337					for (x=4*wide-1; x>=4; x--)
 338					{
 339						srcPtr[x] -= (srcPtr[x-4]>>1);
 340					}
 341				} else
 342				{
 343					srcPtr[0] -= (upPtr[x]>>1);
 344					for (x=4*wide-1; x>=4; x--)
 345					{
 346						srcPtr[x] -= ((upPtr[x] + srcPtr[x-4])>>1);
 347					}
 348				}
 349				break;
 350			case 4:	// Paeth
 351				upPtr = srcPtr - 1;
 352				{
 353					int p,pa,pb,pc,value;
 354					int leftpix,toppix,topleftpix;
 355
 356					for (x=4*wide-1; x>=0; x--)
 357					{
 358						leftpix = 0;
 359						toppix = 0;
 360						topleftpix = 0;
 361						if (x > 0)
 362							leftpix = srcPtr[x-4];
 363						if (y > 0)
 364						{
 365							toppix = upPtr[x];
 366							if (x >= 4)
 367								topleftpix = upPtr[x-4];
 368						}
 369						p = leftpix + toppix - topleftpix;
 370						pa = p - leftpix; if (pa < 0) pa = -pa;
 371						pb = p - toppix; if (pb < 0) pb = -pb;
 372						pc = p - topleftpix; if (pc < 0) pc = -pc;
 373						if (pa <= pb && pa <= pc)
 374							value = leftpix;
 375						else if (pb <= pc)
 376							value = toppix;
 377						else
 378							value = topleftpix;
 379
 380						srcPtr[x] -= value;
 381					}
 382				}
 383				break;
 384			default:
 385				printf ("applyrowfilter : Unknown row filter %d\n", rowfilter);
 386		}
 387		srcPtr += 4*wide;
 388	}
 389}
 390
 391int process (char *filename)
 392{
 393	FILE *f;
 394	unsigned int length;
 395	int i;
 396	unsigned char buf[16];
 397
 398/* This is what we're looking for */
 399	int isPhoney = 0;
 400
 401/* Standard IHDR items: */
 402	unsigned int imgwidth, imgheight, bitdepth,colortype, compression, filter, interlace;
 403/* Derived IHRD items: */
 404	unsigned int bitspp;
 405	unsigned int bytespp;
 406	unsigned int bytespline;
 407
 408	struct chunk_t *ihdr_chunk = NULL;
 409	int idat_first_index = 0;
 410	unsigned char *all_idat = NULL;
 411	unsigned int total_idat_size = 0;
 412
 413/* Adam7 interlacing information */
 414	int Starting_Row [] =  { 0, 0, 4, 0, 2, 0, 1 };
 415	int Starting_Col [] =  { 0, 4, 0, 2, 0, 1, 0 };
 416	int Row_Increment [] = { 8, 8, 8, 4, 4, 2, 2 };
 417	int Col_Increment [] = { 8, 8, 4, 4, 2, 2, 1 };
 418	int row_filter_bytes = 0;
 419
 420/* Needed for unpacking/repacking */
 421	unsigned char *data_out;
 422	int out_length;
 423	unsigned char *data_repack = NULL;
 424	int repack_size, repack_length;
 425
 426/* New file name comes here */
 427	char *write_file_name = NULL;
 428	FILE *write_file;
 429	int write_block_size;
 430
 431/*	int i,j,b;
 432	int blocklength, blockid;
 433	unsigned int filterbytes;
 434	int isInterlaced = 0; */
 435
 436	int didShowName = 0;
 437
 438	int crc, result;
 439
 440	f = fopen (filename, "rb");
 441	if (!f)
 442	{
 443		printf ("%s : not found or could not be opened\n", filename);
 444		return 0;
 445	}
 446
 447	fseek (f, 0, SEEK_END);
 448	length = ftell (f);
 449	fseek (f, 0, SEEK_SET);
 450
 451	i = 0;
 452	
 453	fread (buf,1,8, f); i += 8;
 454	if (memcmp (buf, png_magic_bytes, 8))
 455	{
 456		printf ("%s : not a PNG file\n", filename);
 457		fclose (f);
 458		return 0;
 459	}
 460	result = init_chunk (f, length);
 461	if (result < 0)
 462	{
 463		fclose (f);
 464		switch (result)
 465		{
 466			case -1: printf ("%s : invalid chunk size\n", filename); break;
 467			case -2: printf ("%s : out of memory\n", filename); break;
 468			case -3: printf ("%s : premature end of file\n", filename); break;
 469		}
 470		reset_chunks ();
 471		return 0;
 472	}
 473
 474	isPhoney = 1;
 475	if (pngChunks[0].id != 0x43674249)	/* "CgBI" */
 476	{
 477		isPhoney = 0;
 478		printf ("%s : not an -iphone crushed PNG file\n", filename);
 479		if (!flag_Process_Anyway)
 480		{
 481			fclose (f);
 482			reset_chunks ();
 483			return 0;
 484		}
 485		didShowName = 1;
 486	}
 487
 488	do
 489	{
 490		result = init_chunk (f, length);
 491		if (result < 0)
 492		{
 493			fclose (f);
 494
 495			if (didShowName)
 496				printf ("    ");
 497			else
 498			{
 499				didShowName = 1;
 500				printf ("%s : ", filename);
 501			}
 502			switch (result)
 503			{
 504				case -1: printf ("invalid chunk size\n"); break;
 505				case -2: printf ("out of memory\n"); break;
 506				case -3: printf ("premature end of file\n"); break;
 507				default: printf ("error code %d\n", result);
 508			}
 509			reset_chunks ();
 510			return 0;
 511		}
 512		if (num_chunks > 0 && pngChunks[num_chunks-1].id == 0x49454E44)	/* "IEND" */
 513			break;
 514	} while (!feof(f));
 515
 516	if (pngChunks[num_chunks-1].id != 0x49454E44)	/* "IEND" */
 517	{
 518		fclose (f);
 519
 520		if (didShowName)
 521			printf ("    ");
 522		else
 523		{
 524			didShowName = 1;
 525			printf ("%s : ", filename);
 526		}
 527		printf ("missing IEND chunk\n");
 528		reset_chunks ();
 529		return 0;
 530	}
 531
 532	if (fgetc (f) != EOF)
 533	{
 534		if (didShowName)
 535			printf ("    ");
 536		else
 537		{
 538			didShowName = 1;
 539			printf ("%s : ", filename);
 540		}
 541		printf ("Extra data after IEND, very suspicious! Excluded from conversion\n");
 542	}
 543	fclose (f);
 544
 545	if (flag_List_Chunks)
 546	{
 547		for (i=0; i<num_chunks; i++)
 548		{
 549			if (!didShowName)
 550			{
 551				didShowName = 1;
 552				printf ("%s :\n", filename);
 553			}
 554			printf ("    chunk : %c%c%c%c  length %6u  CRC32 %08X", (pngChunks[i].id >> 24) & 0xff,(pngChunks[i].id >> 16) & 0xff, (pngChunks[i].id >> 8) & 0xff,pngChunks[i].id & 0xff, pngChunks[i].length, pngChunks[i].crc32);
 555			crc = crc32s (pngChunks[i].data, pngChunks[i].length+4);
 556			if (pngChunks[i].crc32 != crc)
 557				printf (" --> CRC32 check invalid! Should be %08X", crc);
 558			printf ("\n");
 559		}
 560	} else
 561	{
 562		for (i=0; i<num_chunks; i++)
 563		{
 564			crc = crc32s (pngChunks[i].data, pngChunks[i].length+4);
 565			if (pngChunks[i].crc32 != crc)
 566			{
 567				if (!didShowName)
 568				{
 569					didShowName = 1;
 570					printf ("%s :\n", filename);
 571				}
 572				printf ("    chunk : %c%c%c%c  length %6u  CRC32 %08X", (pngChunks[i].id >> 24) & 0xff,(pngChunks[i].id >> 16) & 0xff, (pngChunks[i].id >> 8) & 0xff,pngChunks[i].id & 0xff, pngChunks[i].length, pngChunks[i].crc32);
 573				printf (" -> invalid, changed to %08X\n", crc);
 574				pngChunks[i].crc32 = crc;
 575			}
 576		}
 577	}
 578
 579	if (pngChunks[0].id == 0x43674249)	/* "CgBI" */
 580	{
 581		if (num_chunks > 0 && pngChunks[1].id == 0x49484452)	/* "IHDR" */
 582			ihdr_chunk = &pngChunks[1];
 583	} else
 584	{
 585		if (pngChunks[0].id == 0x49484452)	/* "IHDR" */
 586			ihdr_chunk = &pngChunks[0];
 587	}
 588
 589	if (ihdr_chunk == NULL)
 590	{
 591		if (didShowName)
 592			printf ("    ");
 593		else
 594		{
 595			didShowName = 1;
 596			printf ("%s : ", filename);
 597		}
 598		printf ("no IHDR chunk found\n");
 599		reset_chunks ();
 600		return 0;
 601	}
 602	if (ihdr_chunk->length != 13)
 603	{
 604		if (didShowName)
 605			printf ("    ");
 606		else
 607		{
 608			didShowName = 1;
 609			printf ("%s : ", filename);
 610		}
 611		printf ("IHDR chunk length incorrect\n");
 612		reset_chunks ();
 613		return 0;
 614	}
 615	imgwidth = read_long (&ihdr_chunk->data[4]);
 616	imgheight = read_long (&ihdr_chunk->data[8]);
 617	bitdepth = ihdr_chunk->data[12];
 618	colortype = ihdr_chunk->data[13];
 619	compression = ihdr_chunk->data[14];
 620	filter = ihdr_chunk->data[15];
 621	interlace = ihdr_chunk->data[16];
 622
 623	if (imgwidth == 0 || imgheight == 0 || imgwidth > 2147483647 || imgheight > 2147483647)
 624	{
 625		if (didShowName)
 626			printf ("    ");
 627		else
 628		{
 629			didShowName = 1;
 630			printf ("%s : ", filename);
 631		}
 632		printf ("image dimensions invalid\n");
 633		reset_chunks ();
 634		return 0;
 635	}
 636	if (compression != 0)
 637	{
 638		if (didShowName)
 639			printf ("    ");
 640		else
 641		{
 642			didShowName = 1;
 643			printf ("%s : ", filename);
 644		}
 645		printf ("unknown compression type %d\n", compression);
 646		reset_chunks ();
 647		return 0;
 648	}
 649	if (filter != 0)
 650	{
 651		if (didShowName)
 652			printf ("    ");
 653		else
 654		{
 655			didShowName = 1;
 656			printf ("%s : ", filename);
 657		}
 658		printf ("unknown filter type %d\n", filter);
 659		reset_chunks ();
 660		return 0;
 661	}
 662	if (interlace != 0 && interlace != 1)
 663	{
 664		if (didShowName)
 665			printf ("    ");
 666		else
 667		{
 668			didShowName = 1;
 669			printf ("%s : ", filename);
 670		}
 671		printf ("unknown interlace type %d\n", interlace);
 672		reset_chunks ();
 673		return 0;
 674	}
 675
 676/***  From PNG Specs, http://www.w3.org/TR/PNG-Chunks.html
 677   Color    Allowed    Interpretation
 678   Type    Bit Depths
 679   ------  ----------  ----------------------------------
 680   0       1,2,4,8,16  Each pixel is a grayscale sample.
 681   
 682   2       8,16        Each pixel is an R,G,B triple.
 683   
 684   3       1,2,4,8     Each pixel is a palette index;
 685                       a PLTE chunk must appear.
 686   
 687   4       8,16        Each pixel is a grayscale sample,
 688                       followed by an alpha sample.
 689   
 690   6       8,16        Each pixel is an R,G,B triple,
 691                       followed by an alpha sample.
 692***/
 693
 694	i = 0;
 695
 696	switch (colortype)
 697	{
 698		case 0:
 699			if (bitdepth == 1 ||
 700				bitdepth == 2 ||
 701				bitdepth == 4 ||
 702				bitdepth == 8 ||
 703				bitdepth == 16)
 704				i = 1;
 705				bitspp = bitdepth;
 706			break;
 707		case 2:
 708			if (bitdepth == 8 ||
 709				bitdepth == 16)
 710				i = 1;
 711			bitspp = 3*bitdepth;
 712			break;
 713		case 3:
 714			if (bitdepth == 1 ||
 715				bitdepth == 2 ||
 716				bitdepth == 4 ||
 717				bitdepth == 8)
 718				i = 1;
 719			bitspp = bitdepth;
 720			break;
 721		case 4:
 722			if (bitdepth == 8 ||
 723				bitdepth == 16)
 724				i = 1;
 725			bitspp = 2*bitdepth;
 726			break;
 727		case 6:
 728			if (bitdepth == 8 ||
 729				bitdepth == 16)
 730				i = 1;
 731			bitspp = 4*bitdepth;
 732			break;
 733		default:
 734			if (didShowName)
 735				printf ("    ");
 736			else
 737			{
 738				didShowName = 1;
 739				printf ("%s : ", filename);
 740			}
 741			printf ("unknown color type %d\n", colortype);
 742			reset_chunks ();
 743			return 0;
 744	}
 745	if (!i)
 746	{
 747		if (didShowName)
 748			printf ("    ");
 749		else
 750		{
 751			didShowName = 1;
 752			printf ("%s : ", filename);
 753		}
 754		printf ("invalid bit depth %d for color type %d\n", bitdepth, colortype);
 755		reset_chunks ();
 756		return 0;
 757	}
 758
 759	bytespline = (imgwidth*bitspp+7)/8;
 760 /*	Warning!
 761 	This value is only valid for 8/16 bit images! */
 762	bytespp = (bitspp+7)/8;
 763
 764	if (flag_Verbose)
 765	{
 766		if (!didShowName)
 767		{
 768			didShowName = 1;
 769			printf ("%s :\n", filename);
 770		}
 771		printf ("    image width        : %u\n", imgwidth);
 772		printf ("    image height       : %u\n", imgheight);
 773		printf ("    bit depth          : %u\n", bitdepth);
 774		printf ("    color type         : %u\n", colortype);
 775		printf ("    compression        : %u\n", compression);
 776		printf ("    filter             : %u\n", filter);
 777		printf ("    interlace          : %u\n", interlace);
 778		printf ("    bits per pixel     : %d\n", bitspp);
 779		printf ("    bytes per line     : %d\n", bytespline);
 780	}
 781
 782	row_filter_bytes = imgheight;
 783	if (interlace == 1)
 784	{
 785		int w,h,pass;
 786
 787		if (flag_Verbose)
 788			printf ("    Adam7 interlacing:\n");
 789
 790		row_filter_bytes = 0;
 791		for (pass=0; pass<7; pass++)
 792		{
 793			/* Formula taken from pngcheck ! */
 794			w = (imgwidth - Starting_Col[pass] + Col_Increment[pass] - 1)/Col_Increment[pass];
 795			h = (imgheight - Starting_Row[pass] + Row_Increment[pass] - 1)/Row_Increment[pass];
 796			if (flag_Verbose)
 797				printf ("      pass %d: %d x %d\n", pass, w, h);
 798			row_filter_bytes += h;
 799		}
 800	}
 801	if (flag_Verbose)
 802	{
 803		printf ("    row filter bytes   : %u\n", row_filter_bytes);
 804		printf ("    expected data size : %u bytes\n", bytespline * imgheight + row_filter_bytes);
 805	}
 806
 807	for (i=0; i<num_chunks; i++)
 808	{
 809		if (pngChunks[i].id == 0x49444154)	/* "IDAT" */
 810		{
 811			idat_first_index = i;
 812			break;
 813		}
 814	}
 815	if (i == num_chunks)
 816	{
 817		if (didShowName)
 818			printf ("    ");
 819		else
 820		{
 821			didShowName = 1;
 822			printf ("%s : ", filename);
 823		}
 824		printf ("no IDAT chunks found\n");
 825		reset_chunks ();
 826		return 0;
 827	}
 828/** Test for consecutive IDAT chunks */
 829	/* continue where we left off */
 830	while (i < num_chunks)
 831	{
 832		if (pngChunks[i].id != 0x49444154)	/* "IDAT" */
 833			break;
 834		total_idat_size += pngChunks[i].length;
 835		i++;
 836	}
 837	/* test the remaining chunks */
 838	while (i < num_chunks)
 839	{
 840		if (pngChunks[i].id == 0x49444154)	/* "IDAT" */
 841			break;
 842		i++;
 843	}
 844	if (i != num_chunks)
 845	{
 846		if (didShowName)
 847			printf ("    ");
 848		else
 849		{
 850			didShowName = 1;
 851			printf ("%s : ", filename);
 852		}
 853		printf ("IDAT chunks are not consecutive\n");
 854		reset_chunks ();
 855		return 0;
 856	}
 857
 858	if (total_idat_size == 0)
 859	{
 860		if (didShowName)
 861			printf ("    ");
 862		else
 863		{
 864			didShowName = 1;
 865			printf ("%s : ", filename);
 866		}
 867		printf ("all IDAT chunks are empty\n");
 868		reset_chunks ();
 869		return 0;
 870	}
 871
 872/*	Only need to re-write the image data for -phone 8 bit RGB and RGBA images */
 873/*	Note To Self: Is that true? What about 16 bit images? What about palette images? */
 874/*	Okay -- checked the above, it appears these two do NOT get fried. */
 875
 876/*	Swap BGR to RGB, BGRA to RGBA */
 877	if (bitdepth == 8 &&
 878		(colortype == 2 ||		/* Each pixel is an R,G,B triple (8 or 16 bits) */
 879		colortype == 6))		/* Each pixel is an R,G,B triple, followed by an alpha sample (8 or 16 bits) */
 880	{
 881		if (isPhoney && flag_Verbose)
 882			printf ("    swapping BGR(A) to RGB(A)\n");
 883
 884	/*** Gather all IDATs into one ***/
 885		if (flag_Debug)
 886			printf ("    informational : total idat size: %u\n", total_idat_size);
 887		all_idat = (unsigned char *)malloc (total_idat_size);
 888		if (all_idat == NULL)
 889		{
 890			if (didShowName)
 891				printf ("    ");
 892			else
 893			{
 894				didShowName = 1;
 895				printf ("%s : ", filename);
 896			}
 897			printf ("out of memory\n");
 898			reset_chunks ();
 899			return 0;
 900		}
 901		i = idat_first_index;
 902		total_idat_size = 0;
 903		while (i < num_chunks && pngChunks[i].id == 0x49444154)	/* "IDAT" */
 904		{
 905			memcpy (all_idat+total_idat_size, pngChunks[i].data+4, pngChunks[i].length);
 906			total_idat_size += pngChunks[i].length;
 907			i++;
 908		}
 909	
 910	/*** So far everything appears to check out. Let's try uncompressing the IDAT chunks. ***/
 911		data_out = (unsigned char *)malloc (bytespline * imgheight + row_filter_bytes);
 912		if (data_out == NULL)
 913		{
 914			free (all_idat);
 915			if (didShowName)
 916				printf ("    ");
 917			else
 918			{
 919				didShowName = 1;
 920				printf ("%s : ", filename);
 921			}
 922			printf ("out of memory\n");
 923			reset_chunks ();
 924			return 0;
 925		}
 926
 927		if (isPhoney)
 928			out_length = tinfl_decompress_mem_to_mem(data_out, bytespline * imgheight + row_filter_bytes, all_idat, total_idat_size, 0);
 929		else
 930			out_length = tinfl_decompress_mem_to_mem(data_out, bytespline * imgheight + row_filter_bytes, all_idat, total_idat_size, TINFL_FLAG_PARSE_ZLIB_HEADER);
 931
 932		free (all_idat);
 933		all_idat = NULL;
 934	
 935		if (out_length <= 0)
 936		{
 937			free (data_out);
 938			if (didShowName)
 939				printf ("    ");
 940			else
 941			{
 942				didShowName = 1;
 943				printf ("%s : ", filename);
 944			}
 945			printf ("unspecified decompression error\n");
 946			reset_chunks ();
 947			return 0;
 948		}
 949	
 950		if (out_length != imgheight*bytespline + row_filter_bytes)
 951		{
 952			if (didShowName)
 953				printf ("    ");
 954			else
 955			{
 956				didShowName = 1;
 957				printf ("%s : ", filename);
 958			}
 959			printf ("decompression error, expected %u but got %u bytes\n", imgheight*bytespline + row_filter_bytes, out_length);
 960			free (data_out);
 961			reset_chunks ();
 962			return 0;
 963		}
 964		if (flag_Verbose)
 965			printf ("    uncompressed size  : %u bytes\n", bytespline * imgheight + row_filter_bytes);
 966
 967		if (isPhoney || flag_Process_Anyway)
 968		{
 969			if (interlace == 1)		/* needs Adam7 unpacking! */
 970			{
 971				int x,y, b, row;
 972				int pass, w,h;
 973				int startat;
 974
 975			/*	check if all row filters are okay */
 976				y = 0;
 977				for (pass=0; pass<7; pass++)
 978				{
 979					w = (imgwidth - Starting_Col[pass] + Col_Increment[pass] - 1)/Col_Increment[pass];
 980					h = (imgheight - Starting_Row[pass] + Row_Increment[pass] - 1)/Row_Increment[pass];
 981					row=0;
 982					while (row < h)
 983					{
 984						if (data_out[y] > 4)
 985						{
 986							free (data_out);
 987							if (didShowName)
 988								printf ("    ");
 989							else
 990							{
 991								didShowName = 1;
 992								printf ("%s : ", filename);
 993							}
 994							printf ("unknown row filter type (%d)\n", data_out[y]);
 995							reset_chunks ();
 996							return 0;
 997						}
 998						/* skip row filter byte */
 999						y++;
1000						/* skip rest of row */
1001						y += w * bytespp;
1002						row++;
1003					}
1004				}
1005
1006
1007				y = 0;
1008				for (pass=0; pass<7; pass++)
1009				{
1010					/* Formula taken from pngcheck ! */
1011					w = (imgwidth - Starting_Col[pass] + Col_Increment[pass] - 1)/Col_Increment[pass];
1012					h = (imgheight - Starting_Row[pass] + Row_Increment[pass] - 1)/Row_Increment[pass];
1013					startat = y;
1014					row=0;
1015					while (row < h)
1016					{
1017						/* skip row filter byte */
1018						y++;
1019						/* swap all bytes in this row */
1020						x = 0;
1021						while (x < w)
1022						{
1023							b = data_out[y+2];
1024							data_out[y+2] = data_out[y];
1025							data_out[y] = b;
1026							y += bytespp;
1027							x++;
1028						}
1029						row++;
1030					}
1031					if (isPhoney && flag_UpdateAlpha && colortype == 6)	// RGBA
1032					{
1033						removeRowFilters (w, h, data_out+startat);
1034						demultiplyAlpha (w, h, data_out+startat);
1035						applyRowFilters (w, h, data_out+startat);
1036					}
1037				}
1038			} else
1039			{
1040				int x,y, b;
1041
1042				/* check row filters */
1043				y = 0;
1044				while (y < bytespline * imgheight + row_filter_bytes)
1045				{
1046					if (data_out[y] > 4)
1047					{
1048						free (data_out);
1049						if (didShowName)
1050							printf ("    ");
1051						else
1052						{
1053							didShowName = 1;
1054							printf ("%s : ", filename);
1055						}
1056						printf ("unknown row filter type (%d)\n", data_out[y]);
1057						reset_chunks ();
1058						return 0;
1059					}
1060					/* skip row filter byte */
1061					y++;
1062					/* skip entire row */
1063					y += bytespline;
1064				}
1065
1066				y = 0;
1067				while (y < bytespline * imgheight + row_filter_bytes)
1068				{
1069					/* skip row filter byte */
1070					y++;
1071					/* swap all bytes in this row */
1072					x = 0;
1073					while (x < imgwidth)
1074					{
1075						b = data_out[y+2];
1076						data_out[y+2] = data_out[y];
1077						data_out[y] = b;
1078						y += bytespp;
1079						x++;
1080					}
1081				}
1082				if (isPhoney && flag_UpdateAlpha && colortype == 6)	// RGBA
1083				{
1084					removeRowFilters (imgwidth, imgheight, data_out);
1085					demultiplyAlpha (imgwidth, imgheight, data_out);
1086					applyRowFilters (imgwidth, imgheight, data_out);
1087				}
1088			}
1089		}
1090
1091	/*	Force VERY conservative repacking size ... */		
1092		repack_size = 2*(bytespline * imgheight + row_filter_bytes);
1093		data_repack = (unsigned char *)malloc (repack_size);
1094		if (data_repack == NULL)
1095		{
1096			free (data_out);
1097			if (didShowName)
1098				printf ("    ");
1099			else
1100			{
1101				didShowName = 1;
1102				printf ("%s : ", filename);
1103			}
1104			printf ("out of memory\n");
1105			reset_chunks ();
1106			return 0;
1107		}
1108
1109		/* ouch -- reserve 4 bytes at the start to put "IDAT" in! */
1110		/* yeah well, it beats having to re-allocate each block on writing ... */
1111		repack_length = tdefl_compress_mem_to_mem(data_repack+4, repack_size-4, data_out, out_length, TDEFL_WRITE_ZLIB_HEADER);
1112		if (repack_length == 0)
1113		{
1114			free (data_out);
1115			free (data_repack);
1116			if (didShowName)
1117				printf ("    ");
1118			else
1119			{
1120				didShowName = 1;
1121				printf ("%s : ", filename);
1122			}
1123			printf ("unspecified compression error\n");
1124			reset_chunks ();
1125			return 0;
1126		}
1127
1128		if (flag_Verbose)
1129			printf ("    repacked size: %u bytes\n", repack_length);
1130
1131		free (data_out);
1132	}
1133
1134	if (flag_Rewrite)
1135	{
1136		if (outputPath && outputPath[0])
1137		{
1138			char *clipOffPath;
1139			clipOffPath = strrchr (filename, '/');
1140			if (clipOffPath)
1141				clipOffPath++;
1142			else
1143				clipOffPath = filename;
1144
1145			if (suffix && suffix[0])
1146				write_file_name = (char *)malloc (strlen(outputPath)+strlen(clipOffPath)+strlen(suffix)+8);
1147			else
1148				write_file_name = (char *)malloc (strlen(outputPath)+strlen(clipOffPath)+8);
1149			if (write_file_name == NULL)
1150			{
1151				if (didShowName)
1152					printf ("    ");
1153				else
1154				{
1155					didShowName = 1;
1156					printf ("%s : ", filename);
1157				}
1158				printf ("failed to allocate memory for output file name ...\n");
1159				reset_chunks ();
1160				return 0;
1161			}
1162			strcpy (write_file_name, outputPath);
1163			strcat (write_file_name, "/");
1164			strcat (write_file_name, clipOffPath);
1165		} else
1166		{
1167			write_file_name = (char *)malloc (strlen(filename)+strlen(suffix)+8);
1168			if (write_file_name == NULL)
1169			{
1170				if (didShowName)
1171					printf ("    ");
1172				else
1173				{
1174					didShowName = 1;
1175					printf ("%s : ", filename);
1176				}
1177				printf ("failed to allocate memory for output file name ...\n");
1178				reset_chunks ();
1179				return 0;
1180			}
1181			strcpy (write_file_name, filename);
1182		}
1183		if (suffix && suffix[0])
1184		{
1185			if (!strcasecmp (write_file_name+strlen(write_file_name)-4, ".png"))
1186				strcpy (write_file_name+strlen(write_file_name)-4, suffix);
1187			else
1188				strcat (write_file_name, suffix);
1189			strcat (write_file_name, ".png");
1190		}
1191	
1192		if (!didShowName)
1193		{
1194			printf ("%s : ", filename);
1195		}
1196		printf ("writing to file %s\n", write_file_name);
1197	
1198		write_file = fopen (write_file_name, "wb");
1199		if (!write_file)
1200		{
1201			printf ("    failed to create output file!\n");
1202			reset_chunks ();
1203			return 0;
1204		}
1205	
1206		fwrite (png_magic_bytes, 1, 8, write_file);
1207	
1208		i = 0;
1209		/* need to skip first bogus chunk */
1210		/* at this point, I expect the first one to be IHDR! */
1211		if (pngChunks[0].id == 0x43674249)	/* "CgBI" */
1212			i++;
1213		while (i < num_chunks && pngChunks[i].id != 0x49444154)	/* "IDAT" */
1214		{
1215			fputc ( (pngChunks[i].length >> 24) & 0xff, write_file);
1216			fputc ( (pngChunks[i].length >> 16) & 0xff, write_file);
1217			fputc ( (pngChunks[i].length >>  8) & 0xff, write_file);
1218			fputc ( (pngChunks[i].length      ) & 0xff, write_file);
1219			fwrite (pngChunks[i].data, pngChunks[i].length+4, 1, write_file);
1220			fputc ( (pngChunks[i].crc32 >> 24) & 0xff, write_file);
1221			fputc ( (pngChunks[i].crc32 >> 16) & 0xff, write_file);
1222			fputc ( (pngChunks[i].crc32 >>  8) & 0xff, write_file);
1223			fputc ( (pngChunks[i].crc32      ) & 0xff, write_file);
1224			i++;
1225		}
1226
1227	/* Did we repack the data, or do we just need to rewrite the file? */
1228		if (data_repack)
1229		{
1230			write_block_size = 0;
1231			while (write_block_size < repack_length)
1232			{
1233				data_repack[4+write_block_size-4] = 'I';
1234				data_repack[4+write_block_size-3] = 'D';
1235				data_repack[4+write_block_size-2] = 'A';
1236				data_repack[4+write_block_size-1] = 'T';
1237				if (repack_length-write_block_size > repack_IDAT_size)
1238				{
1239					fputc ( (repack_IDAT_size >> 24) & 0xff, write_file);
1240					fputc ( (repack_IDAT_size >> 16) & 0xff, write_file);
1241					fputc ( (repack_IDAT_size >>  8) & 0xff, write_file);
1242					fputc ( (repack_IDAT_size      ) & 0xff, write_file);
1243					fwrite ( data_repack+write_block_size, repack_IDAT_size+4,1, write_file);
1244					crc = crc32s (data_repack+write_block_size, repack_IDAT_size+4);
1245					fputc ( (crc >> 24) & 0xff, write_file);
1246					fputc ( (crc >> 16) & 0xff, write_file);
1247					fputc ( (crc >>  8) & 0xff, write_file);
1248					fputc ( (crc      ) & 0xff, write_file);
1249					write_block_size += repack_IDAT_size;
1250				} else
1251				{
1252					fputc ( ((repack_length-write_block_size) >> 24) & 0xff, write_file);
1253					fputc ( ((repack_length-write_block_size) >> 16) & 0xff, write_file);
1254					fputc ( ((repack_length-write_block_size) >>  8) & 0xff, write_file);
1255					fputc ( ((repack_length-write_block_size)      ) & 0xff, write_file);
1256					fwrite ( data_repack+write_block_size, (repack_length-write_block_size)+4,1, write_file);
1257					crc = crc32s (data_repack+write_block_size, (repack_length-write_block_size)+4);
1258					fputc ( (crc >> 24) & 0xff, write_file);
1259					fputc ( (crc >> 16) & 0xff, write_file);
1260					fputc ( (crc >>  8) & 0xff, write_file);
1261					fputc ( (crc      ) & 0xff, write_file);
1262					write_block_size = repack_length;
1263				}
1264			}
1265		
1266			/* skip original IDAT chunks */
1267			while (i < num_chunks && pngChunks[i].id == 0x49444154)	/* "IDAT" */
1268				i++;
1269
1270			free (data_repack);
1271		} else
1272		{
1273			/* image was not repacked */
1274			/* output original IDAT chunks */
1275			while (i < num_chunks && pngChunks[i].id == 0x49444154)	/* "IDAT" */
1276			{
1277				fputc ( (pngChunks[i].length >> 24) & 0xff, write_file);
1278				fputc ( (pngChunks[i].length >> 16) & 0xff, write_file);
1279				fputc ( (pngChunks[i].length >>  8) & 0xff, write_file);
1280				fputc ( (pngChunks[i].length      ) & 0xff, write_file);
1281				fwrite (pngChunks[i].data, pngChunks[i].length+4, 1, write_file);
1282				fputc ( (pngChunks[i].crc32 >> 24) & 0xff, write_file);
1283				fputc ( (pngChunks[i].crc32 >> 16) & 0xff, write_file);
1284				fputc ( (pngChunks[i].crc32 >>  8) & 0xff, write_file);
1285				fputc ( (pngChunks[i].crc32      ) & 0xff, write_file);
1286				i++;
1287			}
1288		}
1289	
1290		/* output remaining chunks */
1291		while (i < num_chunks)
1292		{
1293			fputc ( (pngChunks[i].length >> 24) & 0xff, write_file);
1294			fputc ( (pngChunks[i].length >> 16) & 0xff, write_file);
1295			fputc ( (pngChunks[i].length >>  8) & 0xff, write_file);
1296			fputc ( (pngChunks[i].length      ) & 0xff, write_file);
1297			fwrite (pngChunks[i].data, pngChunks[i].length+4, 1, write_file);
1298			fputc ( (pngChunks[i].crc32 >> 24) & 0xff, write_file);
1299			fputc ( (pngChunks[i].crc32 >> 16) & 0xff, write_file);
1300			fputc ( (pngChunks[i].crc32 >>  8) & 0xff, write_file);
1301			fputc ( (pngChunks[i].crc32      ) & 0xff, write_file);
1302			i++;
1303		}
1304		fclose (write_file);
1305		free (write_file_name);
1306		reset_chunks ();
1307
1308		return 1;
1309	}
1310
1311/* We come here if nothing was written */
1312/* Just show the name and go away */
1313	if (!didShowName)
1314	{
1315		printf ("%s\n", filename);
1316	}
1317
1318	if (data_repack)
1319		free (data_repack);
1320
1321	reset_chunks ();
1322	return 0;
1323}
1324
1325int main (int argc, char **argv)
1326{
1327	int i, nomoreoptions;
1328	int seenFiles = 0, processedFiles = 0;
1329
1330	if (argc == 1)
1331	{
1332		printf ("PNGdefry version 1.1 by [Jongware], 21-Jan-2012\n");
1333		printf ("\n");
1334		printf ("Removes -iphone specific data chunk, reverses colors from BGRA to RGBA, and de-multiplies alpha\n");
1335		printf ("\n");
1336		printf ("usage: pngdefry [-soaplvid] file.png [...]\n");
1337		printf ("\n");
1338		printf ("Options:\n");
1339		printf ("  -          use this if your first input file starts with an '-'\n");
1340		printf ("  -s(suffix) append suffix to output file name\n");
1341		printf ("  -o(path)   write output file(s) to path\n");
1342		printf ("             Note: without -s or -o, NO output will be created.\n");
1343		printf ("  -a         do NOT de-multiply alpha\n");
1344		printf ("  -l         list all chunks\n");
1345		printf ("  -v         verbose processing\n");
1346		printf ("  -i(value)  max IDAT chunk size in bytes (minimum: 1024; default: %u)\n", repack_IDAT_size);
1347		printf ("  -p         process all files, not just -iphone ones (for debugging purposed only)\n");
1348		printf ("  -d         very verbose processing (for debugging purposes only)\n");
1349		return 0;
1350	}
1351
1352	nomoreoptions = 0;
1353	for (i=1; i<argc; i++)
1354	{
1355		if (argv[i][0] != '-')
1356			break;
1357		switch (argv[i][1])
1358		{
1359			case 0:
1360				nomoreoptions = 1;
1361				break;
1362			case 'd': flag_Debug = 1; flag_Verbose = 1; flag_List_Chunks = 1; break;
1363			case 'a': flag_UpdateAlpha = 0; break;
1364			case 'l': flag_List_Chunks = 1; break;
1365			case 'p': flag_Process_Anyway = 1; break;
1366			case 'v': flag_Verbose = 1; break;
1367			case 's':
1368				if (argv[i][2])
1369				{
1370					suffix = (char *)malloc(strlen(argv[i])+2);
1371					if (suffix == NULL)
1372					{
1373						printf ("pngdefry : unexpected memory allocation error on line %d\n", __LINE__);
1374						return -1;
1375					}
1376					strcpy (suffix, argv[i]+2);
1377				} else
1378				{
1379                    suffix = "";
1380				}
1381				argv[i][2] = 0;
1382				flag_Rewrite = 1;
1383				break;
1384			case 'o':
1385				if (argv[i][2])
1386				{
1387					outputPath = (char *)malloc(strlen(argv[i])+2);
1388					if (outputPath == NULL)
1389					{
1390						printf ("pngdefry : unexpected memory allocation error on line %d\n", __LINE__);
1391						return -1;
1392					}
1393					strcpy (outputPath, argv[i]+2);
1394				} else
1395				{
1396					if (i < argc-1)
1397					{
1398						i++;
1399						outputPath = (char *)malloc(strlen(argv[i])+2);
1400						if (outputPath == NULL)
1401						{
1402							printf ("pngdefry : unexpected memory allocation error on line %d\n", __LINE__);
1403							return -1;
1404						}
1405						strcpy (outputPath, argv[i]);
1406					} else
1407					{
1408						printf ("pngdefry : -o is missing output path\n");
1409						return -1;
1410					}
1411				}
1412				argv[i][2] = 0;
1413				flag_Rewrite = 1;
1414				break;
1415			case 'i':
1416				if (argv[i][2])
1417				{
1418					char *endptr;
1419					repack_IDAT_size = strtol(argv[i]+2, &endptr, 10);
1420					if (*endptr || repack_IDAT_size < 1024)
1421					{
1422						printf ("pngdefry : invalid repack size '%s'\n", argv[i]+2);
1423						return -1;
1424					}
1425					/* yuck. it does circumvent problems down later, thouh, and an extra flag to set/check :( */
1426					argv[i][2] = 0;
1427					break;
1428				} else
1429				{
1430					if (i < argc-1)
1431					{
1432						char *endptr;
1433						i++;
1434						repack_IDAT_size = strtol(argv[i], &endptr, 10);
1435						if (*endptr || repack_IDAT_size < 1024)
1436						{
1437							printf ("pngdefry : invalid repack size '%s'\n", argv[i]);
1438							return -1;
1439						}
1440						/* yuck. it does circumvent problems down later, thouh, and an extra flag to set/check :( */
1441						argv[i][2] = 0;
1442					} else
1443					{
1444						printf ("pngdefry : -i is missing repack size\n");
1445						return -1;
1446					}
1447				}
1448				break;
1449			default:
1450				printf ("pngdefry : unknown option '%s'\n", argv[i]);
1451				return -1;
1452		}
1453
1454		/* was the last option seen '-' ? */
1455		if (nomoreoptions)
1456		{
1457			i++;
1458			break;
1459		}
1460
1461		if (argv[i][2] != 0)
1462		{
1463			printf ("pngdefry : unknown option '%s'\n", argv[i]);
1464			return -1;
1465		}
1466	}
1467	if (i == argc)
1468	{
1469		printf ("pngdefry : no file name(s) provided\n");
1470		return -1;
1471	}
1472/*	if (flag_Rewrite == 0)
1473		printf ("pngdefry : no -s(suffix) or -o(path) provided, files will be processed but not written\n"); */
1474
1475	for (; i<argc; i++)
1476	{
1477		seenFiles++;
1478		if (process (argv[i]))
1479			processedFiles++;
1480	}
1481	if (flag_Rewrite)
1482		printf ("pngdefry : seen %d file(s), wrote %d file(s)\n", seenFiles, processedFiles);
1483	else
1484		printf ("pngdefry : seen %d file(s), processed %d file(s)\n", seenFiles, processedFiles);
1485	return 0;
1486}
1487
1488
1489/*
1490  This is free and unencumbered software released into the public domain.
1491
1492  Anyone is free to copy, modify, publish, use, compile, sell, or
1493  distribute this software, either in source code form or as a compiled
1494  binary, for any purpose, commercial or non-commercial, and by any
1495  means.
1496
1497  In jurisdictions that recognize copyright laws, the author or authors
1498  of this software dedicate any and all copyright interest in the
1499  software to the public domain. We make this dedication for the benefit
1500  of the public at large and to the detriment of our heirs and
1501  successors. We intend this dedication to be an overt act of
1502  relinquishment in perpetuity of all present and future rights to this
1503  software under copyright law.
1504
1505  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1506  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1507  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1508  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1509  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1510  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1511  OTHER DEALINGS IN THE SOFTWARE.
1512
1513  For more information, please refer to <http://unlicense.org/>
1514*/