all repos — mgba @ 6882339f625b97f344c6464915c2038bc453ea3c

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 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}