1ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 2ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* png-fix-itxt version 1.0.0 3ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 4ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Copyright 2013 Glenn Randers-Pehrson 5ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Last changed in libpng 1.6.3 [July 18, 2013] 6ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 7ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * This code is released under the libpng license. 8ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * For conditions of distribution and use, see the disclaimer 9ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * and license in png.h 10ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 11ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Usage: 12ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 13ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * png-fix-itxt.exe < bad.png > good.png 14ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 15ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more 16ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * uncompressed iTXt chunks. Assumes that the actual length is greater 17ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * than or equal to the value in the length byte, and that the CRC is 18ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * correct for the actual length. This program hunts for the CRC and 19ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * adjusts the length byte accordingly. It is not an error to process a 20ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * PNG file that has no iTXt chunks or one that has valid iTXt chunks; 21ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * such files will simply be copied. 22ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 23ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Requires zlib (for crc32 and Z_NULL); build with 24ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 25ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * gcc -O -o png-fix-itxt png-fix-itxt.c -lz 26ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 27ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * If you need to handle iTXt chunks larger than 500000 kbytes you must 28ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * rebuild png-fix-itxt with a larger values of MAX_LENGTH (or a smaller value 29ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * if you know you will never encounter such huge iTXt chunks). 30ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */ 31ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 32ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <stdio.h> 33ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <zlib.h> 34ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 35ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define MAX_LENGTH 500000 36ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 37ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define GETBREAK ((unsigned char)(inchar=getchar())); if (inchar == EOF) break 38ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 39ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikint 40ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikmain(void) 41ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{ 42ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik unsigned int i; 43ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik unsigned char buf[MAX_LENGTH]; 44ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik unsigned long crc; 45ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik unsigned char c; 46ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik int inchar; 47ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 48ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* Skip 8-byte signature */ 49ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik for (i=8; i; i--) 50ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik { 51ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; 52ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik putchar(c); 53ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik } 54ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 55ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikif (inchar != EOF) 56ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikfor (;;) 57ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik { 58ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Read the length */ 59ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik unsigned long length; /* must be 32 bits! */ 60ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[0] = c; length = c; length <<= 8; 61ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[1] = c; length += c; length <<= 8; 62ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[2] = c; length += c; length <<= 8; 63ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[3] = c; length += c; 64ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 65ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Read the chunkname */ 66ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[4] = c; 67ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[5] = c; 68ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[6] = c; 69ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[7] = c; 70ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 71ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 72ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */ 73ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik if (buf[4] == 105 && buf[5] == 84 && buf[6] == 88 && buf[7] == 116) 74ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik { 75ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik if (length >= MAX_LENGTH-12) 76ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik break; /* To do: handle this more gracefully */ 77ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 78ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Initialize the CRC */ 79ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik crc = crc32(0, Z_NULL, 0); 80ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 81ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Copy the data bytes */ 82ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik for (i=8; i < length + 12; i++) 83ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik { 84ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; buf[i] = c; 85ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik } 86ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 87ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Calculate the CRC */ 88ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik crc = crc32(crc, buf+4, (uInt)length+4); 89ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 90ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik for (;;) 91ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik { 92ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Check the CRC */ 93ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik if (((crc >> 24) & 0xff) == buf[length+8] && 94ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik ((crc >> 16) & 0xff) == buf[length+9] && 95ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik ((crc >> 8) & 0xff) == buf[length+10] && 96ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik ((crc ) & 0xff) == buf[length+11]) 97ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik break; 98ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 99ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik length++; 100ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 101ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik if (length >= MAX_LENGTH-12) 102ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik break; 103ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 104ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; 105ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik buf[length+11]=c; 106ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 107ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Update the CRC */ 108ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik crc = crc32(crc, buf+7+length, 1); 109ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik } 110ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 111ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Update length bytes */ 112ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik buf[0] = (unsigned char)((length << 24) & 0xff); 113ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik buf[1] = (unsigned char)((length << 16) & 0xff); 114ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik buf[2] = (unsigned char)((length << 8) & 0xff); 115ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik buf[3] = (unsigned char)((length ) & 0xff); 116ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 117ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Write the fixed iTXt chunk (length, name, data, crc) */ 118ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik for (i=0; i<length+12; i++) 119ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik putchar(buf[i]); 120ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik } 121ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 122ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik else 123ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik { 124ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Copy bytes that were already read (length and chunk name) */ 125ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik for (i=0; i<8; i++) 126ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik putchar(buf[i]); 127ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 128ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* Copy data bytes and CRC */ 129ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik for (i=8; i< length+12; i++) 130ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik { 131ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik c=GETBREAK; 132ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik putchar(c); 133ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik } 134ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 135ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik if (inchar == EOF) 136ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik { 137ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik break; 138ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik } 139ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 140ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik /* The IEND chunk type expressed as integers is (73, 69, 78, 68) */ 141ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68) 142ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik break; 143ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik } 144ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 145ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik if (inchar == EOF) 146ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik break; 147ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 148ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68) 149ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik break; 150ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik } 151ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik 152ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik return 0; 153ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik} 154