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