Home | History | Annotate | Download | only in tools
      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 }
    154