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