|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* png-fix-itxt version 1.0.0
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* Copyright 2015 Glenn Randers-Pehrson
|
|
fukasawa |
e60969 |
* Last changed in libpng 1.6.18 [July 23, 2015]
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* This code is released under the libpng license.
|
|
fukasawa |
e60969 |
* For conditions of distribution and use, see the disclaimer
|
|
fukasawa |
e60969 |
* and license in png.h
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* Usage:
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* png-fix-itxt.exe < bad.png > good.png
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more
|
|
fukasawa |
e60969 |
* uncompressed iTXt chunks. Assumes that the actual length is greater
|
|
fukasawa |
e60969 |
* than or equal to the value in the length byte, and that the CRC is
|
|
fukasawa |
e60969 |
* correct for the actual length. This program hunts for the CRC and
|
|
fukasawa |
e60969 |
* adjusts the length byte accordingly. It is not an error to process a
|
|
fukasawa |
e60969 |
* PNG file that has no iTXt chunks or one that has valid iTXt chunks;
|
|
fukasawa |
e60969 |
* such files will simply be copied.
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* Requires zlib (for crc32 and Z_NULL); build with
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* gcc -O -o png-fix-itxt png-fix-itxt.c -lz
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* If you need to handle iTXt chunks larger than 500000 kbytes you must
|
|
fukasawa |
e60969 |
* rebuild png-fix-itxt with a larger values of MAX_LENGTH (or a smaller value
|
|
fukasawa |
e60969 |
* if you know you will never encounter such huge iTXt chunks).
|
|
fukasawa |
e60969 |
*/
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
#include <stdio.h></stdio.h>
|
|
fukasawa |
e60969 |
#include <zlib.h></zlib.h>
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
#define MAX_LENGTH 500000
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Read one character (inchar), also return octet (c), break if EOF */
|
|
fukasawa |
e60969 |
#define GETBREAK inchar=getchar(); \
|
|
fukasawa |
e60969 |
c=(inchar & 0xffU);\
|
|
fukasawa |
e60969 |
if (inchar != c) break
|
|
fukasawa |
e60969 |
int
|
|
fukasawa |
e60969 |
main(void)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
unsigned int i;
|
|
fukasawa |
e60969 |
unsigned char buf[MAX_LENGTH];
|
|
fukasawa |
e60969 |
unsigned long crc;
|
|
fukasawa |
e60969 |
unsigned char c;
|
|
fukasawa |
e60969 |
int inchar;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Skip 8-byte signature */
|
|
fukasawa |
e60969 |
for (i=8; i; i--)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
GETBREAK;
|
|
fukasawa |
e60969 |
putchar(c);
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
if (inchar == c) /* !EOF */
|
|
fukasawa |
e60969 |
for (;;)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
/* Read the length */
|
|
fukasawa |
e60969 |
unsigned long length; /* must be 32 bits! */
|
|
fukasawa |
e60969 |
GETBREAK; buf[0] = c; length = c; length <<= 8;
|
|
fukasawa |
e60969 |
GETBREAK; buf[1] = c; length += c; length <<= 8;
|
|
fukasawa |
e60969 |
GETBREAK; buf[2] = c; length += c; length <<= 8;
|
|
fukasawa |
e60969 |
GETBREAK; buf[3] = c; length += c;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Read the chunkname */
|
|
fukasawa |
e60969 |
GETBREAK; buf[4] = c;
|
|
fukasawa |
e60969 |
GETBREAK; buf[5] = c;
|
|
fukasawa |
e60969 |
GETBREAK; buf[6] = c;
|
|
fukasawa |
e60969 |
GETBREAK; buf[7] = c;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */
|
|
fukasawa |
e60969 |
if (buf[4] == 105 && buf[5] == 84 && buf[6] == 88 && buf[7] == 116)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
if (length >= MAX_LENGTH-12)
|
|
fukasawa |
e60969 |
break; /* To do: handle this more gracefully */
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Initialize the CRC */
|
|
fukasawa |
e60969 |
crc = crc32(0, Z_NULL, 0);
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Copy the data bytes */
|
|
fukasawa |
e60969 |
for (i=8; i < length + 12; i++)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
GETBREAK; buf[i] = c;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
if (inchar != c) /* EOF */
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Calculate the CRC */
|
|
fukasawa |
e60969 |
crc = crc32(crc, buf+4, (uInt)length+4);
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
for (;;)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
/* Check the CRC */
|
|
fukasawa |
e60969 |
if (((crc >> 24) & 0xffU) == buf[length+8] &&
|
|
fukasawa |
e60969 |
((crc >> 16) & 0xffU) == buf[length+9] &&
|
|
fukasawa |
e60969 |
((crc >> 8) & 0xffU) == buf[length+10] &&
|
|
fukasawa |
e60969 |
((crc ) & 0xffU) == buf[length+11])
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
length++;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
if (length >= MAX_LENGTH-12)
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
GETBREAK;
|
|
fukasawa |
e60969 |
buf[length+11] = c;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Update the CRC */
|
|
fukasawa |
e60969 |
crc = crc32(crc, buf+7+length, 1);
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
if (inchar != c) /* EOF */
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Update length bytes */
|
|
fukasawa |
e60969 |
buf[0] = (unsigned char)((length >> 24) & 0xffU);
|
|
fukasawa |
e60969 |
buf[1] = (unsigned char)((length >> 16) & 0xffU);
|
|
fukasawa |
e60969 |
buf[2] = (unsigned char)((length >> 8) & 0xffU);
|
|
fukasawa |
e60969 |
buf[3] = (unsigned char)((length ) & 0xffU);
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Write the fixed iTXt chunk (length, name, data, crc) */
|
|
fukasawa |
e60969 |
for (i=0; i
|
|
fukasawa |
e60969 |
putchar(buf[i]);
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
else
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
if (inchar != c) /* EOF */
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Copy bytes that were already read (length and chunk name) */
|
|
fukasawa |
e60969 |
for (i=0; i<8; i++)
|
|
fukasawa |
e60969 |
putchar(buf[i]);
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Copy data bytes and CRC */
|
|
fukasawa |
e60969 |
for (i=8; i< length+12; i++)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
GETBREAK;
|
|
fukasawa |
e60969 |
putchar(c);
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
if (inchar != c) /* EOF */
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* The IEND chunk type expressed as integers is (73, 69, 78, 68) */
|
|
fukasawa |
e60969 |
if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
if (inchar != c) /* EOF */
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
|
|
fukasawa |
e60969 |
break;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
return 0;
|
|
fukasawa |
e60969 |
}
|