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