fukasawa e60969
fukasawa e60969
/* png-fix-itxt version 1.0.0
fukasawa e60969
 *
fukasawa e60969
 * Copyright 2015 Glenn Randers-Pehrson
fukasawa e60969
 * Last changed in libpng 1.6.18 [July 23, 2015]
fukasawa e60969
 *
fukasawa e60969
 * This code is released under the libpng license.
fukasawa e60969
 * For conditions of distribution and use, see the disclaimer
fukasawa e60969
 * and license in png.h
fukasawa e60969
 *
fukasawa e60969
 * Usage:
fukasawa e60969
 *
fukasawa e60969
 *     png-fix-itxt.exe < bad.png > good.png
fukasawa e60969
 *
fukasawa e60969
 * Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more
fukasawa e60969
 * uncompressed iTXt chunks.  Assumes that the actual length is greater
fukasawa e60969
 * than or equal to the value in the length byte, and that the CRC is
fukasawa e60969
 * correct for the actual length.  This program hunts for the CRC and
fukasawa e60969
 * adjusts the length byte accordingly.  It is not an error to process a
fukasawa e60969
 * PNG file that has no iTXt chunks or one that has valid iTXt chunks;
fukasawa e60969
 * such files will simply be copied.
fukasawa e60969
 *
fukasawa e60969
 * Requires zlib (for crc32 and Z_NULL); build with
fukasawa e60969
 *
fukasawa e60969
 *     gcc -O -o png-fix-itxt png-fix-itxt.c -lz
fukasawa e60969
 *
fukasawa e60969
 * If you need to handle iTXt chunks larger than 500000 kbytes you must
fukasawa e60969
 * rebuild png-fix-itxt with a larger values of MAX_LENGTH (or a smaller value
fukasawa e60969
 * if you know you will never encounter such huge iTXt chunks).
fukasawa e60969
 */
fukasawa e60969
fukasawa e60969
#include <stdio.h></stdio.h>
fukasawa e60969
#include <zlib.h></zlib.h>
fukasawa e60969
fukasawa e60969
#define MAX_LENGTH 500000
fukasawa e60969
fukasawa e60969
/* Read one character (inchar), also return octet (c), break if EOF */
fukasawa e60969
#define GETBREAK inchar=getchar(); \
fukasawa e60969
                 c=(inchar & 0xffU);\
fukasawa e60969
                 if (inchar != c) break
fukasawa e60969
int
fukasawa e60969
main(void)
fukasawa e60969
{
fukasawa e60969
   unsigned int i;
fukasawa e60969
   unsigned char buf[MAX_LENGTH];
fukasawa e60969
   unsigned long crc;
fukasawa e60969
   unsigned char c;
fukasawa e60969
   int inchar;
fukasawa e60969
fukasawa e60969
/* Skip 8-byte signature */
fukasawa e60969
   for (i=8; i; i--)
fukasawa e60969
   {
fukasawa e60969
      GETBREAK;
fukasawa e60969
      putchar(c);
fukasawa e60969
   }
fukasawa e60969
fukasawa e60969
if (inchar == c) /* !EOF */
fukasawa e60969
for (;;)
fukasawa e60969
 {
fukasawa e60969
   /* Read the length */
fukasawa e60969
   unsigned long length; /* must be 32 bits! */
fukasawa e60969
   GETBREAK; buf[0] = c; length  = c; length <<= 8;
fukasawa e60969
   GETBREAK; buf[1] = c; length += c; length <<= 8;
fukasawa e60969
   GETBREAK; buf[2] = c; length += c; length <<= 8;
fukasawa e60969
   GETBREAK; buf[3] = c; length += c;
fukasawa e60969
fukasawa e60969
   /* Read the chunkname */
fukasawa e60969
   GETBREAK; buf[4] = c;
fukasawa e60969
   GETBREAK; buf[5] = c;
fukasawa e60969
   GETBREAK; buf[6] = c;
fukasawa e60969
   GETBREAK; buf[7] = c;
fukasawa e60969
fukasawa e60969
fukasawa e60969
   /* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */
fukasawa e60969
   if (buf[4] == 105 && buf[5] == 84 && buf[6] == 88 && buf[7] == 116)
fukasawa e60969
   {
fukasawa e60969
      if (length >= MAX_LENGTH-12)
fukasawa e60969
         break;  /* To do: handle this more gracefully */
fukasawa e60969
fukasawa e60969
      /* Initialize the CRC */
fukasawa e60969
      crc = crc32(0, Z_NULL, 0);
fukasawa e60969
fukasawa e60969
      /* Copy the data bytes */
fukasawa e60969
      for (i=8; i < length + 12; i++)
fukasawa e60969
      {
fukasawa e60969
         GETBREAK; buf[i] = c;
fukasawa e60969
      }
fukasawa e60969
fukasawa e60969
      if (inchar != c) /* EOF */
fukasawa e60969
         break;
fukasawa e60969
fukasawa e60969
      /* Calculate the CRC */
fukasawa e60969
      crc = crc32(crc, buf+4, (uInt)length+4);
fukasawa e60969
fukasawa e60969
      for (;;)
fukasawa e60969
      {
fukasawa e60969
        /* Check the CRC */
fukasawa e60969
        if (((crc >> 24) & 0xffU) == buf[length+8] &&
fukasawa e60969
            ((crc >> 16) & 0xffU) == buf[length+9] &&
fukasawa e60969
            ((crc >>  8) & 0xffU) == buf[length+10] &&
fukasawa e60969
            ((crc      ) & 0xffU) == buf[length+11])
fukasawa e60969
           break;
fukasawa e60969
fukasawa e60969
        length++;
fukasawa e60969
fukasawa e60969
        if (length >= MAX_LENGTH-12)
fukasawa e60969
           break;
fukasawa e60969
fukasawa e60969
        GETBREAK;
fukasawa e60969
        buf[length+11] = c;
fukasawa e60969
fukasawa e60969
        /* Update the CRC */
fukasawa e60969
        crc = crc32(crc, buf+7+length, 1);
fukasawa e60969
      }
fukasawa e60969
fukasawa e60969
      if (inchar != c) /* EOF */
fukasawa e60969
         break;
fukasawa e60969
fukasawa e60969
      /* Update length bytes */
fukasawa e60969
      buf[0] = (unsigned char)((length >> 24) & 0xffU);
fukasawa e60969
      buf[1] = (unsigned char)((length >> 16) & 0xffU);
fukasawa e60969
      buf[2] = (unsigned char)((length >>  8) & 0xffU);
fukasawa e60969
      buf[3] = (unsigned char)((length      ) & 0xffU);
fukasawa e60969
fukasawa e60969
      /* Write the fixed iTXt chunk (length, name, data, crc) */
fukasawa e60969
      for (i=0; i
fukasawa e60969
         putchar(buf[i]);
fukasawa e60969
   }
fukasawa e60969
fukasawa e60969
   else
fukasawa e60969
   {
fukasawa e60969
      if (inchar != c) /* EOF */
fukasawa e60969
         break;
fukasawa e60969
fukasawa e60969
      /* Copy bytes that were already read (length and chunk name) */
fukasawa e60969
      for (i=0; i<8; i++)
fukasawa e60969
         putchar(buf[i]);
fukasawa e60969
fukasawa e60969
      /* Copy data bytes and CRC */
fukasawa e60969
      for (i=8; i< length+12; i++)
fukasawa e60969
      {
fukasawa e60969
         GETBREAK;
fukasawa e60969
         putchar(c);
fukasawa e60969
      }
fukasawa e60969
fukasawa e60969
      if (inchar != c) /* EOF */
fukasawa e60969
      {
fukasawa e60969
         break;
fukasawa e60969
      }
fukasawa e60969
fukasawa e60969
   /* The IEND chunk type expressed as integers is (73, 69, 78, 68) */
fukasawa e60969
      if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
fukasawa e60969
         break;
fukasawa e60969
   }
fukasawa e60969
fukasawa e60969
   if (inchar != c) /* EOF */
fukasawa e60969
      break;
fukasawa e60969
fukasawa e60969
   if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
fukasawa e60969
     break;
fukasawa e60969
 }
fukasawa e60969
fukasawa e60969
 return 0;
fukasawa e60969
}