all repos — mgba @ 9de8f084ba55460b02d300c1dd8b8e6c56f691d5

mGBA Game Boy Advance Emulator

src/third-party/libpng/contrib/tools/png-fix-itxt.c (view raw)

  1
  2/* png-fix-itxt version 1.0.0
  3 *
  4 * Copyright 2015 Glenn Randers-Pehrson
  5 * Last changed in libpng 1.6.18 [July 23, 2015]
  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/* Read one character (inchar), also return octet (c), break if EOF */
 38#define GETBREAK inchar=getchar(); \
 39                 c=(inchar & 0xffU);\
 40                 if (inchar != c) break
 41int
 42main(void)
 43{
 44   unsigned int i;
 45   unsigned char buf[MAX_LENGTH];
 46   unsigned long crc;
 47   unsigned char c;
 48   int inchar;
 49
 50/* Skip 8-byte signature */
 51   for (i=8; i; i--)
 52   {
 53      GETBREAK;
 54      putchar(c);
 55   }
 56
 57if (inchar == c) /* !EOF */
 58for (;;)
 59 {
 60   /* Read the length */
 61   unsigned long length; /* must be 32 bits! */
 62   GETBREAK; buf[0] = c; length  = c; length <<= 8;
 63   GETBREAK; buf[1] = c; length += c; length <<= 8;
 64   GETBREAK; buf[2] = c; length += c; length <<= 8;
 65   GETBREAK; buf[3] = c; length += c;
 66
 67   /* Read the chunkname */
 68   GETBREAK; buf[4] = c;
 69   GETBREAK; buf[5] = c;
 70   GETBREAK; buf[6] = c;
 71   GETBREAK; buf[7] = c;
 72
 73
 74   /* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */
 75   if (buf[4] == 105 && buf[5] == 84 && buf[6] == 88 && buf[7] == 116)
 76   {
 77      if (length >= MAX_LENGTH-12)
 78         break;  /* To do: handle this more gracefully */
 79
 80      /* Initialize the CRC */
 81      crc = crc32(0, Z_NULL, 0);
 82
 83      /* Copy the data bytes */
 84      for (i=8; i < length + 12; i++)
 85      {
 86         GETBREAK; buf[i] = c;
 87      }
 88
 89      if (inchar != c) /* EOF */
 90         break;
 91
 92      /* Calculate the CRC */
 93      crc = crc32(crc, buf+4, (uInt)length+4);
 94
 95      for (;;)
 96      {
 97        /* Check the CRC */
 98        if (((crc >> 24) & 0xffU) == buf[length+8] &&
 99            ((crc >> 16) & 0xffU) == buf[length+9] &&
100            ((crc >>  8) & 0xffU) == buf[length+10] &&
101            ((crc      ) & 0xffU) == buf[length+11])
102           break;
103
104        length++;
105
106        if (length >= MAX_LENGTH-12)
107           break;
108
109        GETBREAK;
110        buf[length+11] = c;
111
112        /* Update the CRC */
113        crc = crc32(crc, buf+7+length, 1);
114      }
115
116      if (inchar != c) /* EOF */
117         break;
118
119      /* Update length bytes */
120      buf[0] = (unsigned char)((length >> 24) & 0xffU);
121      buf[1] = (unsigned char)((length >> 16) & 0xffU);
122      buf[2] = (unsigned char)((length >>  8) & 0xffU);
123      buf[3] = (unsigned char)((length      ) & 0xffU);
124
125      /* Write the fixed iTXt chunk (length, name, data, crc) */
126      for (i=0; i<length+12; i++)
127         putchar(buf[i]);
128   }
129
130   else
131   {
132      if (inchar != c) /* EOF */
133         break;
134
135      /* Copy bytes that were already read (length and chunk name) */
136      for (i=0; i<8; i++)
137         putchar(buf[i]);
138
139      /* Copy data bytes and CRC */
140      for (i=8; i< length+12; i++)
141      {
142         GETBREAK;
143         putchar(c);
144      }
145
146      if (inchar != c) /* EOF */
147      {
148         break;
149      }
150
151   /* The IEND chunk type expressed as integers is (73, 69, 78, 68) */
152      if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
153         break;
154   }
155
156   if (inchar != c) /* EOF */
157      break;
158
159   if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
160     break;
161 }
162
163 return 0;
164}