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