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