178 lines
3.9 KiB
C
178 lines
3.9 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <zlib.h>
|
|
|
|
uint32_t endianswap( uint32_t n )
|
|
{
|
|
// if we're in a big endian system, we don't need this
|
|
uint16_t testme = 0x1234;
|
|
if ( *(uint8_t*)(&testme) == 0x12 ) return n;
|
|
uint32_t on;
|
|
for ( int i=0; i<4; i++ )
|
|
*(((uint8_t*)(&on))+i) = *(((uint8_t*)(&n))+(3-i));
|
|
return on;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
uint8_t highbitcheck;
|
|
char sig[3];
|
|
char crlf[2];
|
|
char dosstop;
|
|
char lf;
|
|
} pnghead_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t length;
|
|
char type[4];
|
|
uint8_t *data;
|
|
uint32_t crc;
|
|
} pngchunk_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t width, height;
|
|
uint8_t depth, type, compression, filter, interlace;
|
|
} ihdr_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t xppu, yppu;
|
|
uint8_t unit;
|
|
} phys_t;
|
|
|
|
int exitval = 0;
|
|
FILE *f = 0;
|
|
int nchunk = 0;
|
|
pnghead_t hdr = {0,0,0,0,0};
|
|
pngchunk_t chk = {0,0,0,0}; // make sure this is null at the very start
|
|
uint32_t curcrc = 0;
|
|
int validcrc = 0;
|
|
uint8_t *tdat = 0; // accumulated data for all IDAT chunks
|
|
uint32_t tdatsiz = 0; // size of it
|
|
|
|
void readIHDR( ihdr_t* ihdr )
|
|
{
|
|
printf(" width: %u\n height: %u\n depth: %u\n type: %u\n compression: %u\n filter: %u\n interlace: %u\n",
|
|
endianswap(ihdr->width),endianswap(ihdr->height),ihdr->depth,ihdr->type,ihdr->compression,ihdr->filter,ihdr->interlace);
|
|
}
|
|
|
|
// read up a stream chunk
|
|
void readIDAT( uint8_t* dat, uint32_t len )
|
|
{
|
|
if ( tdat ) tdat = realloc(tdat,tdatsiz+len);
|
|
else tdat = malloc(len);
|
|
memcpy(tdat+tdatsiz,dat,len);
|
|
tdatsiz += len;
|
|
}
|
|
|
|
// process the whole thing
|
|
void processIDAT( void )
|
|
{
|
|
}
|
|
|
|
void readpHYs( phys_t* phys )
|
|
{
|
|
printf(" xppu: %u\n yppu: %u\n unit: %u\n",endianswap(phys->xppu),endianswap(phys->yppu),phys->unit);
|
|
}
|
|
|
|
void readtEXt( uint8_t* data, uint32_t len )
|
|
{
|
|
uint8_t *key = data;
|
|
uint8_t *val = data+strlen(data)+1;
|
|
uint32_t vallen = len-(val-key);
|
|
printf(" '%s' :: '%.*s'\n",key,vallen,val);
|
|
}
|
|
|
|
void readchunkdata( pngchunk_t* chk )
|
|
{
|
|
if ( !strncmp(chk->type,"IHDR",4) )
|
|
readIHDR((ihdr_t*)chk->data);
|
|
else if ( !strncmp(chk->type,"pHYs",4) )
|
|
readpHYs((phys_t*)chk->data);
|
|
else if ( !strncmp(chk->type,"tEXt",4) )
|
|
readtEXt(chk->data,chk->length);
|
|
}
|
|
|
|
|
|
int main( int argc, char **argv )
|
|
{
|
|
if ( argc < 2 )
|
|
{
|
|
printf("No file supplied.\n");
|
|
exitval = 0;
|
|
goto endmii;
|
|
}
|
|
f = fopen(argv[1],"rb");
|
|
if ( !f )
|
|
{
|
|
printf("Failed to open file.\n");
|
|
exitval = 1;
|
|
goto endmii;
|
|
}
|
|
fread(&hdr,1,sizeof(hdr),f);
|
|
if ( hdr.highbitcheck != 0x89 )
|
|
{
|
|
printf("High bit check failed.\n");
|
|
exitval = 2;
|
|
goto endmii;
|
|
}
|
|
if ( strncmp(hdr.sig,"PNG",3) )
|
|
{
|
|
printf("PNG signature check failed.\n");
|
|
exitval = 4;
|
|
goto endmii;
|
|
}
|
|
if ( strncmp(hdr.crlf,"\r\n",2) )
|
|
{
|
|
printf("CRLF check failed.\n");
|
|
exitval = 8;
|
|
goto endmii;
|
|
}
|
|
if ( hdr.dosstop != '\032' )
|
|
{
|
|
printf("EOF check failed.\n");
|
|
exitval = 16;
|
|
goto endmii;
|
|
}
|
|
if ( hdr.lf != '\n' )
|
|
{
|
|
printf("LF check failed.\n");
|
|
exitval = 32;
|
|
goto endmii;
|
|
}
|
|
readchunk:
|
|
fread(&chk,1,8,f); // read size and type first
|
|
chk.length = endianswap(chk.length); // swap from BE
|
|
if ( (nchunk == 0) && strncmp(chk.type,"IHDR",4) )
|
|
{
|
|
printf("First chunk is not IHDR.\n");
|
|
exitval = 64;
|
|
goto endmii;
|
|
}
|
|
// (re)allocate data
|
|
if ( chk.data ) chk.data = realloc(chk.data,chk.length);
|
|
else chk.data = malloc(chk.length);
|
|
fread(chk.data,1,chk.length,f); // read data
|
|
fread(&(chk.crc),1,4,f); // read CRC
|
|
chk.crc = endianswap(chk.crc);
|
|
curcrc = crc32(0,chk.type,4);
|
|
if ( chk.length ) curcrc = crc32(curcrc,chk.data,chk.length);
|
|
validcrc = (curcrc == chk.crc);
|
|
printf("%.4s chunk of length %u (CRC32: %08X, %s).\n",chk.type,chk.length,chk.crc,validcrc?"OK":"FAILED");
|
|
if ( !validcrc ) printf(" CRC32 ACTUAL: %08X\n",curcrc);
|
|
else readchunkdata(&chk);
|
|
nchunk++;
|
|
if ( strncmp(chk.type,"IEND",4) ) goto readchunk;
|
|
long cpos = ftell(f);
|
|
fseek(f,0,SEEK_END);
|
|
long epos = ftell(f);
|
|
if ( epos > cpos ) printf("%lu bytes of extra data after IEND.\n",epos-cpos);
|
|
endmii:
|
|
if ( f ) fclose(f);
|
|
if ( chk.data ) free(chk.data);
|
|
return exitval;
|
|
}
|