home *** CD-ROM | disk | FTP | other *** search
/ Compressed Image File Formats / CompressedImageFileFormatsJohnMiano.iso / pc / Library / PNGDump / pngdump.bak < prev    next >
Encoding:
Text File  |  1998-12-17  |  7.9 KB  |  297 lines

  1. #include <fstream>
  2. #include <errno>
  3. #include <string>
  4. #include <except>
  5.  
  6. #include "datatype.h"
  7. #include "pngpvt.h"
  8.  
  9. UBYTE4 CrcTable [256] ;
  10. UBYTE4 Register ;
  11.  
  12. UBYTE1 CurrentChunkType [5] ;
  13. UBYTE1 *ChunkData ;
  14. UBYTE4 ChunkDataLength ;
  15. UBYTE4 ChunkBufferSize ;
  16. unsigned int ChunkCount ;
  17. bool IENDReached ;
  18. bool PLTEReached ;
  19. unsigned int LastIDATChunk ;
  20.  
  21. PngImageHeader ImageHeader ;
  22.  
  23. unsigned long CrcRegister ;
  24. void CrcByte (unsigned char data)
  25. {
  26.   unsigned int index = (CrcRegister ^ data) & 0xFF ;
  27.   CrcRegister = CrcTable [index] ^ ((CrcRegister >> 8) & 0x00FFFFFF) ;
  28.   return ;
  29. }
  30.  
  31. unsigned long Crc (BYTE1 type [5], UBYTE1 buffer [], unsigned int length)
  32. {
  33.   CrcRegister = 0xFFFFFFFFL ;
  34.   for (unsigned int ii = 0 ; ii < 4 ; ++ ii)
  35.     CrcByte (type [ii]) ;
  36.  
  37.   for (unsigned int ii = 0 ; ii < length ; ++ ii)
  38.     CrcByte (buffer [ii]) ;
  39.  
  40.   return ~CrcRegister ;
  41. }
  42.  
  43. void MakeCrcTable ()
  44. {
  45.   for (unsigned int ii = 0 ; ii < 256 ; ++ ii)
  46.   {
  47.     CrcTable [ii] = ii ;
  48.     for (unsigned int jj = 0 ; jj < 8 ; ++ jj)
  49.     {
  50.       if ((CrcTable [ii] & 0x1) == 0)
  51.         CrcTable [ii] >>= 1 ;
  52.       else
  53.         CrcTable [ii] = 0xEDB88320L ^ (CrcTable [ii] >> 1) ;
  54.     }
  55.   }
  56.   return ;
  57. }
  58.  
  59. UBYTE4 ReadLong (istream &strm)
  60. {
  61.   UBYTE4 data ;
  62.   strm.read ((char *) &data, sizeof (data)) ;
  63.   return BigEndianToSystem (data) ;
  64. }
  65.  
  66. void ReadSignature (istream &strm)
  67. {
  68.   static const int sigsize = 8 ;
  69.   static const unsigned char signature [sigsize] = { 137, 80, 78, 71, 13,
  70.                                                      10, 26, 10, } ;
  71.   unsigned char sigbuf [sigsize] ;
  72.  
  73.   strm.read (sigbuf, sigsize) ;
  74.   if (memcmp (sigbuf, signature, sigsize) != 0)
  75.     cout << "*** PNG Signature Invalid ***" << endl ;
  76.   return ;
  77. }
  78.  
  79. void ProcessHeader (istream &strm)
  80. {
  81.   PngImageHeader *header = (PngImageHeader *) ChunkData ;
  82.   ImageHeader = *header ;
  83.  
  84.   if (ChunkCount != 0)
  85.     cout << "*** IHDR must be the first chunk ***" << endl ;
  86.   if (ChunkDataLength != sizeof (PngImageHeader))
  87.     cout << "*** Invalid IHDR Chunk Length ***" << endl ;
  88.  
  89.   cout << "  Image Size: " << dec << BigEndianToSystem (header->height)
  90.        << " x " << dec << BigEndianToSystem (header->width) << endl ;
  91.   cout << "  Bit Depth: " << (int) header->bitdepth << endl ;
  92.   switch (header->colortype)
  93.   {
  94.   case 0:
  95.     cout << "  Color Type: Grayscale" << endl ;
  96.     switch (header->bitdepth)
  97.     {
  98.     case 1: case 2: case 4: case 8: case 16: break ;
  99.     default:
  100.       cout << "Bad Bitdepth (" << header->bitdepth << ") for Color Type" << endl ;
  101.     }
  102.     break ;
  103.   case 2:
  104.     cout << "  Color Type: RGB Triple" << endl ;
  105.     if (header->bitdepth != 8 && header->bitdepth != 16)
  106.       cout << "*** Bad Bitdepth for Color Type ***" << endl ;
  107.     break ;
  108.   case 3:
  109.     cout << "  Color Type: Palette Index" << endl ;
  110.     switch (header->bitdepth)
  111.     {
  112.     case 1: case 2: case 4: case 8: break ;
  113.     default:
  114.       cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
  115.            << endl ;
  116.     }
  117.     break ;
  118.   case 4:
  119.     cout << "  Color Type: Grayscale/Alpha" << endl ;
  120.     if (header->bitdepth != 8 && header->bitdepth != 16)
  121.       cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
  122.            << endl ;
  123.     break ;
  124.   case 6:
  125.     cout << " Color Type: RGB/Alpha" << endl ;
  126.     if (header->bitdepth != 8 && header->bitdepth != 16)
  127.       cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
  128.            << endl ;
  129.     break ;
  130.   default:
  131.     cout << "*** Invalid Color Type (" << header->colortype << ") ***" << endl ;
  132.   }
  133.   if (header->compressionmethod == 0)
  134.   {
  135.     cout << "  Compression Method: deflate/inflate - 32k Sliding Window"
  136.          << endl ;
  137.   }
  138.   else
  139.   {
  140.     cerr << "Invalid Compression Method (" << header->compressionmethod << ")" << endl ;
  141.   }
  142.  
  143.   if (header->filtermethod == 0)
  144.   {
  145.     cout << "  Filter Method: adaptive" << endl ;
  146.   }
  147.   else
  148.   {
  149.     cout << "*** Invalid Filter Method (" << header->filtermethod << ") ***"
  150.          << endl ;
  151.   }
  152.  
  153.   switch (header->interlacemethod)
  154.   {
  155.   case 0:
  156.     cout << "  Interlace Method:  none" << endl ;
  157.     break ;
  158.   case 1:
  159.     cout << "  Interlace Method:  Adam7" << endl ;
  160.     break ;
  161.   default:
  162.     cout << "*** Invalid Interlace Method ("
  163.          << header->interlacemethod << ") ***" << endl ;
  164.   }
  165.   return ;
  166. }
  167.  
  168. void ProcessIDAT (istream &strm)
  169. {
  170.   if (LastIDATChunk != 0 && LastIDATChunk != ChunkCount - 1)
  171.     cout << "*** IDAT blocks are not consecutive. ***" << endl ;
  172.   if (ImageHeader.colortype == Palette && ! PLTEReached)
  173.     cout << "*** IDAT requires PLTE chunk for this color type. ***" << endl ;
  174.   LastIDATChunk = ChunkCount ;
  175.   return ;
  176. }
  177.  
  178. void ProcessPalette (istream &strm)
  179. {
  180.   if (PLTEReached)
  181.     cout << "*** File contains multiple PLTE Chunks ***" << endl ;
  182.   if (ChunkDataLength % 3 != 0)
  183.     cout << "*** PLTE Block length not divisible by 3 ***" << endl ;
  184.   if (ChunkDataLength > 3 * (1 << ImageHeader.bitdepth) ||
  185.       ChunkDataLength > 256 * 3)
  186.     cout << "*** PLTE Block length too large ***" << endl ;
  187.   if (LastIDATChunk != 0)
  188.     cout << "*** PLTE May not occur after the first IDAT chunk ***" << endl ;
  189.   if (ImageHeader.colortype == Grayscale
  190.       || ImageHeader.colortype == GrayscaleAlpha)
  191.     cout << "*** PLTE May not occur with Grayscale or Grayscale"
  192.          << " with Alpha Channel. ***" << endl ;
  193.  
  194.   PLTEReached = true ;
  195.   struct PaletteEntry
  196.   {
  197.     UBYTE1 red ;
  198.     UBYTE1 green ;
  199.     UBYTE1 blue ;
  200.   } palette [256] ;
  201.  
  202.   unsigned int colorcount = ChunkDataLength / 3 ;
  203.  
  204.   cout << "  Palette Color Count: " << colorcount << endl ;
  205.   memcpy (palette, ChunkData, colorcount * sizeof (PaletteEntry));
  206.   return ;
  207. }
  208.  
  209. void ReadBlock (istream &strm)
  210. {
  211.   ChunkDataLength = ReadLong (strm) ;
  212.   if (strm.eof ())
  213.     return ;
  214.   if (ChunkDataLength > ChunkBufferSize)
  215.   {
  216.     ChunkBufferSize = ChunkDataLength ;
  217.  
  218.     delete [] ChunkData ;
  219.     ChunkData = new UBYTE1 [ChunkBufferSize] ;
  220.   }
  221.   strm.read ((char*) CurrentChunkType, 4) ;
  222.   strm.read ((char*) ChunkData, ChunkDataLength) ;
  223.  
  224.  
  225.   UBYTE4 datacrc = Crc (CurrentChunkType, ChunkData, ChunkDataLength) ;
  226.   UBYTE4 filecrc = ReadLong (strm) ;
  227.  
  228.   cout << "{ " << CurrentChunkType << endl ;
  229.   cout << "  Data Length: " << ChunkDataLength << endl ;
  230.   cout << "  Data CRC:    " << hex << datacrc << endl ;
  231.   cout << "  File CRC:    " << hex << filecrc << endl ;
  232.   if (filecrc != datacrc)
  233.     cout << "*** Chunk CRC is Incorrect ***" << endl ;
  234.  
  235.   UBYTE4 numericcode = ChunkType (CurrentChunkType) ;
  236.   if (ChunkCount == 0 && numericcode != ChunkType ("IHDR"))
  237.     cout << "*** First chunk is not IHDR ***" << endl ;
  238.   if (IENDReached)
  239.     cout << "*** Chunk follows IEND ***" << endl ;
  240.  
  241.   if (numericcode == ChunkType ("IHDR"))
  242.   {
  243.     ProcessHeader (strm) ;
  244.   }
  245.   else if (numericcode == ChunkType ("IDAT"))
  246.   {
  247.     ProcessIDAT (strm) ;
  248.   }
  249.   else if (numericcode == ChunkType ("PLTE"))
  250.   {
  251.     ProcessPalette (strm) ;
  252.   }
  253.   else if (numericcode == ChunkType ("IEND"))
  254.   {
  255.     IENDReached = true ;
  256.     if (LastIDATChunk == 0)
  257.       cout << "*** Image Contains No IDAT chunks ***" << endl ;
  258.     if (ChunkDataLength != 0)
  259.       cout << "*** IEND Chunk may not contain data ***" << endl ;
  260.   }
  261.   else
  262.   {
  263.   }
  264.   cout << "}" << endl ;
  265.   return ;
  266. }
  267.  
  268. main (int argc, char *argv [])
  269. {
  270.   if (argc != 2)
  271.   {
  272.     cerr << "Usage: " << argv [0] << " filename" << endl ;
  273.     return 1 ;
  274.   }
  275.  
  276.   ifstream in (argv [1], ios::binary) ;
  277.   if (! in)
  278.   {
  279.     cerr << "Can't open file " << argv [1] << endl ;
  280.     cerr << strerror (errno) << endl ;
  281.     return errno ;
  282.   }
  283.  
  284.   MakeCrcTable () ;
  285.   try
  286.   {
  287.     ReadSignature (in) ;
  288.     for (ChunkCount = 0 ; ! in.eof () ; ++ ChunkCount)
  289.       ReadBlock (in) ;
  290.   }
  291.   catch (exception &ee)
  292.   {
  293.     cerr << ee.what () << endl ;
  294.   }
  295.   return 0 ;
  296. }
  297.