Imported Upstream version 1.6.13
[platform/upstream/libpng.git] / contrib / tools / png-fix-itxt.c
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
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       c=GETBREAK;
52       putchar(c);
53    }
54
55 if (inchar != EOF)
56 for (;;)
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 }