User:Steven/flip frame decode.c
< User:Steven
Jump to navigation
Jump to search
Revision as of 12:52, 21 August 2009 by Steven (talk | contribs) (\flip frame decode.c moved to Steven/flip frame decode.c: I'm too used to MS-DOS slashes...)
Please note that there is very little comments and this application just outputs to the text console at the moment, but the code used here can be expanded to produce any other image file formats you wanted. I'm still working on the sound format and as such there is no functions for the sound yet.
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
// Disable MS VC's "unsecure / depricated" code warning
#pragma warning( disable : 4996 )
// setup some file types for set sizes
typedef signed char s8;
typedef signed short s16;
typedef signed long s32;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef struct PPM_HEADER
{
u8 magic[4];
u32 fileSize;
u32 audioOffset;
u16 numberOfFrames;
u16 unk0;
u16 flags;
u16 previewFrameNumber;
u16 originalAuthorName[11];
u16 authorName[11];
u16 userName[11];
u8 originalAuthorID[8];
u8 editAuthorID[8];
u8 originalFileName[18];
u8 fileName[18];
u8 authorID[8];
u8 unk1[8];
u8 unk2[6];
u8 previewBitmap[1536];
} ppmHeader;
int flength(FILE *f)
{
int pos,end;
pos = ftell (f);
fseek (f, 0, SEEK_END);
end = ftell (f);
fseek (f, pos, SEEK_SET);
return end;
}
char *idFromStr( u8 is[8] )
{
static char retVal[32];
int i;
memset( retVal, 0, 32 );
for( i = 7; i >= 0; i -- )
sprintf( retVal, "%s%02X", retVal, ( is[ i ] & 0xFF ) );
return retVal;
}
char *filenameFromStr( u8 fn[18] )
{
static char retVal[64];
int i;
memset( retVal, 0, 32 );
for( i = 0; i < 3; i ++ )
sprintf( retVal, "%s%02X", retVal, ( fn[ i ] & 0xFF ) );
strcat( retVal, "_" );
for( i = 3; i < 16; i ++ )
sprintf( retVal, "%s%c", retVal, ( fn[ i ] & 0xFF ) );
sprintf( retVal, "%s_%03d", retVal, ( fn[ 16 ] & 0xFF ) + ( ( fn[ 17 ] & 0xFF ) << 8 ) );
return retVal;
}
char *hexFromStr( u8 is[8], int len )
{
static char retVal[256];
int i;
memset( retVal, 0, 256 );
for( i = 0; i < len; i ++ )
sprintf( retVal, "%s%02X ", retVal, ( is[ i ] & 0xFF ) );
return retVal;
}
void printHeaderInfo( ppmHeader *ptr )
{
printf( "Magic Number : %c%c%c%c\n", ptr->magic[0], ptr->magic[1], ptr->magic[2], ptr->magic[3] );
printf( "File Size : %d (%08X)\n", ptr->fileSize, ptr->fileSize );
printf( "Audio offset : %d (%08X)\n", ptr->audioOffset, ptr->audioOffset );
printf( "# Frames : %d\n", ptr->numberOfFrames );
printf( "Unknown : 0x%04X\n", ptr->unk0 );
printf( "Flags? : 0x%04X - 0 = open, 1 = locked\n", ptr->flags );
printf( "Preview Frame # : %d\n", ptr->previewFrameNumber );
printf( "Orig Author : UCS-2 string \n" );
printf( "Author : UCS-2 string \n" );
printf( "Edit Author : UCS-2 string \n" );
printf( "Orig Author ID : %s\n", idFromStr( ptr->originalAuthorID ) );
printf( "Edit Author ID : %s\n", idFromStr( ptr->editAuthorID ) );
printf( "Orig Filename : %s\n", filenameFromStr( ptr->originalFileName ) );
printf( "Curr Filename : %s\n", filenameFromStr( ptr->fileName ) );
printf( "Author ID : %s\n", idFromStr( ptr->authorID ) );
printf( "Unknown 8 bytes : %s\n", hexFromStr( ptr->unk1, 8 ) ) ;
printf( "Unknown 6 bytes : %s\n", hexFromStr( ptr->unk2, 6 ) ) ;
}
static char outPreviewG[] = { ' ', 176, 219, 178, 'r', 'R', 'p', 'X', 'B', 'P', 'b', 'x', 'M', '.', '.', '.' };
static char outFrameG0[] = { 32, 219, 176, 178 };
static char outFrameG1[] = { 219, 32, 176, 178 };
void displayPreviewImage( u8 img[1536] )
{
int x, y, cellOffset;
int xp, xc;
u8 c;
for( y = 0; y < 48; y ++ )
{
cellOffset = ( ( y >> 3 ) * 256 ) + ( ( y & 0x7 ) << 2 );
for( x = 0; x < 64; x ++ )
{
xp = ( x & 7 ) >> 1;
xc = ( ( x >> 3 ) << 5 );
c = img[ cellOffset + xp + xc ];
printf( "%c", outPreviewG[ ( x & 1 ? c >> 4 : c ) & 0xF ] );
}
printf( "\n" );
}
}
u32 getu32( u8 *buf )
{
u32 retVal = 0;
retVal = retVal | ( buf[ 0 ] << 0 );
retVal = retVal | ( buf[ 1 ] << 8 );
retVal = retVal | ( buf[ 2 ] << 16 );
retVal = retVal | ( buf[ 3 ] << 24 );
return retVal;
}
u32 getu32inv( u8 *buf )
{
u32 retVal = 0;
retVal = retVal | ( buf[ 3 ] << 0 );
retVal = retVal | ( buf[ 2 ] << 8 );
retVal = retVal | ( buf[ 1 ] << 16 );
retVal = retVal | ( buf[ 0 ] << 24 );
return retVal;
}
u32 getFrameOffset( u8 *buf, u16 frm )
{
u32 numBytes;
numBytes = getu32( buf );
if( frm > ( numBytes >> 2 ) )
return 0;
return ( getu32( &buf[ 4 + ( frm << 2 ) ] ) + 8 + numBytes );
}
u32 decodeLine( u8 *outB, u8 *inB, u32 useByte, u8 paper, u8 pen, u8 invflag )
{
u32 offset = 0;
u16 x = 0, i;
u8 data;
if( useByte == 0 ) // Set the full line to the current paper colour
memset( outB, paper, 256 );
else // Bytes in this line, read and deal with them
{
while( useByte != 0 )
{
if( ( useByte & 0x80000000 ) == 0x80000000 )
{
// This byte exists...
data = inB[ offset++ ];
for( i = 0; i < 8; i ++ )
{
if( ( data & 0x01 ) == 0x01 )
outB[ x ] = invflag == 0 ? pen : paper;
else
outB[ x ] = invflag == 0 ? paper : pen;
x ++;
data >>= 1;
}
}
else
{
memset( &outB[ x ], paper, 8 );
x += 8;
}
useByte <<= 1;
}
if( x < 256 )
memset( &outB[ x ], paper, 256 - x );
}
return offset;
}
void displayFrame( u8 *frmBuf, u16 frmNum )
{
u8 colPaper, colLayer1, colLayer2;
u32 frmOffset;
u8 lEnc[192];
u8 *buf;
u8 lnePos, lneCount;
u8 *outFrameG;
u16 x, y;
u32 byteUse;
buf = (u8*) malloc( 256 * 192 );
if( buf == NULL )
{
printf( "Error unable to allocate buffer for frame %d\n", frmBuf );
return;
}
frmOffset = getFrameOffset( frmBuf, 1 );
printf( "Frame #%d offset %08X\n", frmNum, frmOffset );
colPaper = frmBuf[ frmOffset ] & 0x01;
colLayer1 = ( frmBuf[ frmOffset ] >> 1 ) & 0x03;
colLayer2 = ( frmBuf[ frmOffset ] >> 3 ) & 0x03;
printf( "Paper colour: %s\n", ( colPaper == 0 ? "Black" : "White" ) );
printf( "Layer 1 colour: %d\n", colLayer1 );
printf( "Layer 2 colour: %d\n", colLayer2 );
if( colPaper == 0 )
outFrameG = outFrameG0;
else
outFrameG = outFrameG1;
memset( buf, outFrameG[0], 192 << 8 );
lnePos = 0;
frmOffset ++;
// Read layer 1 line information into lower nibble
for( lneCount = 0; lneCount < 48; lneCount ++ )
{
lEnc[ lnePos++ ] = ( frmBuf[ frmOffset ] >> 0 ) & 0x03;
lEnc[ lnePos++ ] = ( frmBuf[ frmOffset ] >> 2 ) & 0x03;
lEnc[ lnePos++ ] = ( frmBuf[ frmOffset ] >> 4 ) & 0x03;
lEnc[ lnePos++ ] = ( frmBuf[ frmOffset ] >> 6 ) & 0x03;
frmOffset ++;
}
lnePos = 0;
// Read layer 2 line information into upper nibble
for( lneCount = 0; lneCount < 48; lneCount ++ )
{
lEnc[ lnePos++ ] |= ( frmBuf[ frmOffset ] << 4 ) & 0x30;
lEnc[ lnePos++ ] |= ( frmBuf[ frmOffset ] << 2 ) & 0x30;
lEnc[ lnePos++ ] |= ( frmBuf[ frmOffset ] >> 0 ) & 0x30;
lEnc[ lnePos++ ] |= ( frmBuf[ frmOffset ] >> 2 ) & 0x30;
frmOffset ++;
}
//read frame here...
// First read layer 1.
lnePos = 0;
while( lnePos < 192 )
{
switch( lEnc[ lnePos ] & 0x03 )
{
case 0: // Skip this line
byteUse = 0;
printf( "Line %3d(%04X), Layer 1, Skip Frame [%08X]\toffset %08X\n", lnePos, lnePos, byteUse, frmOffset + 0x6a0 );
break;
case 1: // Coded
byteUse = getu32inv( &frmBuf[ frmOffset ] );
printf( "Line %3d(%04X), Layer 1, Coded [%08X]\toffset %08X\n", lnePos, lnePos, byteUse, frmOffset + 0x6a0 );
frmOffset += 4;
frmOffset += decodeLine( &buf[ lnePos << 8 ], &frmBuf[ frmOffset ], byteUse, outFrameG[ 0 ], outFrameG[ colLayer1 ], 0 );
break;
case 2: // Inv Coded
byteUse = getu32inv( &frmBuf[ frmOffset ] );
printf( "Line %3d(%04X), Layer 1, Inv Coded [%08X]\toffset %08X\n", lnePos, lnePos, byteUse, frmOffset + 0x6a0 );
frmOffset += 4;
frmOffset += decodeLine( &buf[ lnePos << 8 ], &frmBuf[ frmOffset ], byteUse, outFrameG[ colLayer1 ], outFrameG[ 0 ], 1 );
break;
case 3: // Full Line
byteUse = 0xFFFFFFFF;
printf( "Line %3d(%04X), Layer 1, Full Frame [%08X]\toffset %08X\n", lnePos, lnePos, byteUse, frmOffset + 0x6a0 );
frmOffset += decodeLine( &buf[ lnePos << 8 ], &frmBuf[ frmOffset ], byteUse, outFrameG[ 0 ], outFrameG[ colLayer1 ], 0 );
break;
}
lnePos ++;
}
//output frame here...
for( y = 0; y < 192; y ++ )
{
for( x = 0; x < 256; x ++ )
{
printf( "%c", buf[ x + ( y << 8 ) ] );
}
printf( "\n" );
}
}
void hexOut( char *buf, int len )
{
int i;
for( i = 0 ; i < len ; i ++ )
{
printf( "%02X ", buf[i] & 0xFF );
if( ( i & 0xF ) == 0xF )
printf( "\n" );
}
}
int main(int argc, char* argv[])
{
ppmHeader *pHead;
FILE *fp;
int f_len;
char *f_buf;
if(argc != 2)
{
printf("usage: %s <anim.ppm>\n", argv[0]);
exit(0);
}
fp = fopen(argv[1],"rb");
if(fp == NULL)
{
printf("input file not found\n");
exit(1);
}
f_len = flength(fp);
f_buf = malloc(f_len);
if(f_buf == NULL)
{
fprintf(stderr, "not enough memory\n");
exit(1);
}
if(fread(f_buf, f_len, 1, fp) != 1)
{
fprintf(stderr, "file read failure\n");
exit(1);
}
pHead = (ppmHeader *) f_buf;
printHeaderInfo( pHead );
displayPreviewImage( pHead->previewBitmap );
printf( "\n" );
displayFrame( &f_buf[ 0x6a0 ], 1 );
printf( "\n" );
hexOut( &f_buf[ 0x6a0 ], 256 );
printf( "\n" );
hexOut( &f_buf[ f_len - 256 ], 256 );
printf("finished..\n");
free( f_buf);
fclose(fp);
return 0;
}