User:Steven/flip frame decode.c

From DSiBrew
Jump to navigation Jump to search

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", (int)ptr->fileSize, (unsigned int)ptr->fileSize );
    printf( "Audio offset    : %d (%08X)\n", (int)ptr->audioOffset, (unsigned int)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", (int)frmBuf );
		return;
	}

	frmOffset = getFrameOffset( frmBuf, 1 );

	printf( "Frame #%d offset %08X\n", frmNum, (unsigned int)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, (unsigned int)byteUse, (unsigned int)frmOffset + 0x6a0 );
				break;
			case 1: // Coded
				byteUse = getu32inv( &frmBuf[ frmOffset ] );
				printf( "Line %3d(%04X), Layer 1, Coded      [%08X]\toffset %08X\n", lnePos, lnePos, (unsigned int)byteUse, (unsigned int)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, (unsigned int)byteUse, (unsigned int)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, (unsigned int)byteUse, (unsigned int)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;
}