(root)/
libpng-1.6.40/
contrib/
tools/
png-fix-itxt.c
       1  /* png-fix-itxt
       2   *
       3   * Copyright 2015 Glenn Randers-Pehrson
       4   *
       5   * This code is released under the libpng license.
       6   * For conditions of distribution and use, see the disclaimer
       7   * and license in png.h
       8   *
       9   * Usage:
      10   *
      11   *     png-fix-itxt < bad.png > good.png
      12   *
      13   * Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more
      14   * uncompressed iTXt chunks.  Assumes that the actual length is greater
      15   * than or equal to the value in the length byte, and that the CRC is
      16   * correct for the actual length.  This program hunts for the CRC and
      17   * adjusts the length byte accordingly.  It is not an error to process a
      18   * PNG file that has no iTXt chunks or one that has valid iTXt chunks;
      19   * such files will simply be copied.
      20   *
      21   * Requires zlib (for crc32 and Z_NULL); build with
      22   *
      23   *     gcc -O -o png-fix-itxt png-fix-itxt.c -lz
      24   *
      25   * If you need to handle iTXt chunks larger than 500000 kbytes you must
      26   * rebuild png-fix-itxt with a larger values of MAX_LENGTH (or a smaller value
      27   * if you know you will never encounter such huge iTXt chunks).
      28   */
      29  
      30  #include <stdio.h>
      31  #include <zlib.h>
      32  
      33  #define MAX_LENGTH 500000
      34  
      35  /* Read one character (inchar), also return octet (c), break if EOF */
      36  #define GETBREAK inchar=getchar(); \
      37                   c=(inchar & 0xffU);\
      38                   if (inchar != c) break
      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        GETBREAK;
      52        putchar(c);
      53     }
      54  
      55  if (inchar == c) /* !EOF */
      56  for (;;)
      57   {
      58     /* Read the length */
      59     unsigned long length; /* must be 32 bits! */
      60     GETBREAK; buf[0] = c; length  = c; length <<= 8;
      61     GETBREAK; buf[1] = c; length += c; length <<= 8;
      62     GETBREAK; buf[2] = c; length += c; length <<= 8;
      63     GETBREAK; buf[3] = c; length += c;
      64  
      65     /* Read the chunkname */
      66     GETBREAK; buf[4] = c;
      67     GETBREAK; buf[5] = c;
      68     GETBREAK; buf[6] = c;
      69     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           GETBREAK; buf[i] = c;
      85        }
      86  
      87        if (inchar != c) /* EOF */
      88           break;
      89  
      90        /* Calculate the CRC */
      91        crc = crc32(crc, buf+4, (uInt)length+4);
      92  
      93        for (;;)
      94        {
      95          /* Check the CRC */
      96          if (((crc >> 24) & 0xffU) == buf[length+8] &&
      97              ((crc >> 16) & 0xffU) == buf[length+9] &&
      98              ((crc >>  8) & 0xffU) == buf[length+10] &&
      99              ((crc      ) & 0xffU) == buf[length+11])
     100             break;
     101  
     102          length++;
     103  
     104          if (length >= MAX_LENGTH-12)
     105             break;
     106  
     107          GETBREAK;
     108          buf[length+11] = c;
     109  
     110          /* Update the CRC */
     111          crc = crc32(crc, buf+7+length, 1);
     112        }
     113  
     114        if (inchar != c) /* EOF */
     115           break;
     116  
     117        /* Update length bytes */
     118        buf[0] = (unsigned char)((length >> 24) & 0xffU);
     119        buf[1] = (unsigned char)((length >> 16) & 0xffU);
     120        buf[2] = (unsigned char)((length >>  8) & 0xffU);
     121        buf[3] = (unsigned char)((length      ) & 0xffU);
     122  
     123        /* Write the fixed iTXt chunk (length, name, data, crc) */
     124        for (i=0; i<length+12; i++)
     125           putchar(buf[i]);
     126     }
     127  
     128     else
     129     {
     130        if (inchar != c) /* EOF */
     131           break;
     132  
     133        /* Copy bytes that were already read (length and chunk name) */
     134        for (i=0; i<8; i++)
     135           putchar(buf[i]);
     136  
     137        /* Copy data bytes and CRC */
     138        for (i=8; i< length+12; i++)
     139        {
     140           GETBREAK;
     141           putchar(c);
     142        }
     143  
     144        if (inchar != c) /* EOF */
     145        {
     146           break;
     147        }
     148  
     149     /* The IEND chunk type expressed as integers is (73, 69, 78, 68) */
     150        if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
     151           break;
     152     }
     153  
     154     if (inchar != c) /* EOF */
     155        break;
     156  
     157     if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
     158       break;
     159   }
     160  
     161   return 0;
     162  }