#include "xbcomm.h"


static VOIDPARM flipl( p )
byte *p;
{
    byte t; 
  
	t = p[ 0 ];  
	p[ 0 ] = p[ 3 ];  
	p[ 3 ] = t;
  
	t = p[ 1 ];  
	p[ 1 ] = p[ 2 ];  
	p[ 2 ] = t;
}

static int getbyte( fp )
FILE *fp;
{
    return( (int)getc( fp ) );
}

static u_int getword( fp )
FILE *fp;
{
    byte b1 = (byte)getc( fp );
    byte b2 = (byte)getc( fp );

    return( (u_int)(b1 + b2 * 256) );
}

static u_int getbeword( fp )
FILE *fp;
{
    byte b1 = (byte)getc( fp );
    byte b2 = (byte)getc( fp );

    return( (u_int)(b2 + b1 * 256) );
}

static int getint( fp, gotGarbage )
FILE *fp;
boolean *gotGarbage;
{
    int c, i;
    boolean notDone;

  	/* skip forward to start of next number */
  	c = getc( fp );
	notDone = TRUE;
	*gotGarbage = FALSE;
  	while ( notDone ) 
	{
    	    /* eat comments */
    	    if ( c IS POUNDSIGN ) 
		/* if we're at a comment, read to end of line */
      	        while ( c ISNT EOL AND c ISNT EOF) 
		    c = getc( fp );

    	    if ( c IS EOF ) 
		return( 0 );
    	    if ( c >= ZERO AND c <= NINE ) 
		/* we've found what we were looking for */
		notDone = FALSE;   
	    else if ( NOT ( ( c IS SPACE ) OR ( c IS TAB ) OR ( c IS CR ) OR 
		    ( c IS EOL ) OR ( c IS COMMA ) ) ) 
    	        /* see if we are getting garbage (non-whitespace) */
		*gotGarbage = TRUE;

	    if ( notDone )
    	        c = getc( fp );
  	}


  	/* we're at the start of a number, continue until we hit a non-number */
  	i = 0;
	notDone = TRUE;
  	while ( notDone ) 
        {
    	    i = ( i * 10 ) + ( c - ZERO );
    	    c = getc( fp );
    	    if ( c IS EOF ) 
		return( i );
    	    if ( ( c < ZERO ) OR ( c > NINE ) ) 
		notDone = FALSE;
  	}

  	return( i );
}


typedef struct 
{
    char type[ 6 ];
    unsigned short width, height;
    char planes;
} GIF_INFO;

static char *getGIFInfo( VOIDPARM )
{
    FILE *fp;
    GIF_INFO gi;
    boolean swapEm=FALSE;
    int cCnt;
    char c, *d;
    char resStr[ 32 ], tempStr[ 32 ];
    union {
	unsigned short theShort;
	char theChars[ 2 ];
    } byteOrder;

	byteOrder.theShort = ( 'A' SHL_ 8 ) + 'B';
        if ( byteOrder.theChars[ 0 ] IS 'A' ) 
	    swapEm = TRUE;
	fp = fopen( theFile, "r" );
	fread( (char *) &gi, sizeof( GIF_INFO ), 1, fp );
	gi.type[ 5 ] = NULLTERM;
	if ( swapEm )
	{
	    d = (char *) &(gi.width);
	    c = d[ 1 ];
	    d[ 1 ] = d[ 0 ];
	    d[ 0 ] = c;
	    d = (char *) &(gi.height);
	    c = d[ 1 ];
	    d[ 1 ] = d[ 0 ];
	    d[ 0 ] = c;
	}
	gi.planes = ( gi.planes AND_ 0x07 );
	sprintf( resStr, "[%dx%dx%dp]", gi.width, gi.height, gi.planes + 1 );
	picRes = copyString( resStr );
	sprintf( tempStr, "GIF {%s}", gi.type );
  	fclose( fp );
	return( copyString( tempStr ) );
}

/*
> Scan through and look for 0xff followed by either 0xc0, 0xc1 or 0xc9.
> Once you find those, skip a couple bytes and you can then pick up
> the precision, height, width and number of components as 1 byte,
> 2 byte, 2 byte and 1 byte integers respectively and in that order
> (the 2 byte guys are in big endian order).
> 
> The number of components roughly indiciates colour or grayscale (3 or 1).
> The precision is how big each component is (almost always 8 bits).
> Most files will have three, 8 bit components.
*/
static char *getJFIFInfo( VOIDPARM )
{
    FILE *fp;
    int oneByte;
    boolean gotMarker;
    int prec, comp, width, height;
    char resStr[ 32 ], tempStr[ 32 ];

	fp = fopen( theFile, "r" );
	oneByte = getbyte( fp );
	while ( oneByte ISNT EOF )
	{
	    if ( (u_int)oneByte IS 0xff )
	    {
		oneByte = (u_int)getbyte( fp );
		if ( ( oneByte IS 0xc0 ) OR ( oneByte IS 0xc1 ) OR
			( oneByte IS 0xc9 ) )
		{
		    /* ...ignore one word... */
		    height = getword( fp );
		    /* Next byte should be precision... */
		    prec = (u_int)getbyte( fp );
		    /* Next two bytes should be height... */
		    height = getbeword( fp );
		    /* Next two bytes should be width... */
		    width = getbeword( fp );
		    /* Next byte should be number of components... */
		    comp = (u_int)getbyte( fp );
		    sprintf( resStr, "[%dx%dx%dp]", width, height, 
			     ( comp * prec ) );
		    break;
		}
		else if ( (u_int)oneByte ISNT 0xff )
		    oneByte = getbyte( fp );
	    }
	    else
		oneByte = getbyte( fp );
	}
	fclose( fp );
	picRes = copyString( resStr );
	sprintf( tempStr, "JPEG/JFIF" );
	return( copyString( tempStr ) );
}

typedef struct {
	int	id;		/* Magic number for pm format files.	*/
	int	np;		/* Number of planes. Normally 1.	*/
	int	nrow;		/* Number of rows. 1 - MAXNELM.		*/
	int	ncol;		/* Number of columns. 1 - MAXNELM.	*/
	int	nband;		/* Number of bands.			*/
	int	form;		/* Pixel format.			*/
} PM_INFO;

#define	PM_MAGICNO	0x56494557		/* Hex for VIEW */
#define	PM_A		0x8000
#define	PM_C		0x8001
#define	PM_S		0x8002
#define	PM_I		0x8004
#define PM_F		0xc004

static char *getPMInfo( VOIDPARM )
{
    FILE *fp;
    PM_INFO pi;
    boolean flipit;
    char picType[ 5 ], resStr[ 32 ], tempStr[ 32 ];

	fp = fopen( theFile, "r" );
  	flipit = FALSE;
  	fread( (char *) &pi, sizeof( PM_INFO ), 1, fp );
	fclose( fp );
  	if ( pi.id ISNT PM_MAGICNO )
	{
    	    flipl( (byte *) &pi.id );
    	    if ( pi.id IS PM_MAGICNO ) 
		flipit = TRUE;
    	    else 
		flipl( (byte *) &pi.id );
  	}
  	if ( pi.id ISNT PM_MAGICNO ) 
	    return( "INVALID PM FILE!" );

  	if ( flipit ) 
	{
    	    flipl( (byte *) &pi.np );      
	    flipl( (byte *) &pi.nrow );
    	    flipl( (byte *) &pi.ncol );    
	    flipl( (byte *) &pi.nband );
    	    flipl( (byte *) &pi.form );
    	}

	if ( pi.form IS PM_A )
	    sprintf( picType, "PM_A" );
	else if ( pi.form IS PM_C )
	    sprintf( picType, "PM_C" );
	else if ( pi.form IS PM_S )
	    sprintf( picType, "PM_S" );
	else if ( pi.form IS PM_I )
	    sprintf( picType, "PM_I" );
	else if ( pi.form IS PM_F )
	    sprintf( picType, "PM_F" );
	sprintf( resStr, "[%dx%dx%dp]", pi.ncol, pi.nrow, pi.np );
	picRes = copyString( resStr );
	sprintf( tempStr, "PM {%s}", picType );
	return( copyString( tempStr ) );
}

static char *getPBMInfo( VOIDPARM )
{
    FILE *fp;
    /* char planes; */
    char resStr[ 32 ], tempStr[ 32 ];
    boolean garbage, intGarbage;
    int c, c1;
    int numBits, index;
    int w, h, maxv, planes;

  	garbage = FALSE;
	maxv = 0;

  	/* open the stream, if necesary */
  	fp = fopen( theFile, "r" );

  	/* read the first two bytes of the file to determine which format */
     	/* this file is.  "P1" = ascii bitmap, "P2" = ascii greymap, */
     	/* "P3" = ascii pixmap, "P4" = raw bitmap, "P5" = raw greymap, */
     	/* "P6" = raw pixmap */

  	c = getc( fp );  
	c1 = getc( fp );
  	if ( ( c ISNT 'P' ) OR ( c1 < ONE ) OR ( c1 > SIX ) ) 
	    sprintf( tempStr, "CORRUPT PBM FILE!" );
	else
	{
  	    /* read in header information */
  	    w = getint( fp, &intGarbage );
	    garbage = ( garbage OR intGarbage );
	    h = getint( fp, &intGarbage );
	    garbage = ( garbage OR intGarbage );

  	    /* if we're not reading a bitmap, read the 'max value' */
  	    if ( NOT ( ( c1 IS ONE ) OR ( c1 IS FOUR ) ) ) 
	    {
    	    	maxv = getint( fp, &intGarbage );
	        garbage = ( garbage OR intGarbage );
    	    	if ( maxv < 1 ) 
		    garbage = TRUE;    /* to avoid 'div by zero' probs */
  	    }

  	    if ( garbage ) 
	        sprintf( tempStr, "CORRUPT PBM FILE!" );
	    else
	    {
	        /* planes = ( ( maxv AND_ 0xfff0 ) SHR_ 4 ) + 1; */
		numBits = 4 * sizeof( int );
		planes = 1;
		for ( index = 1; index <= numBits; index++ )
		    if ( ( maxv SHR_ index ) AND_ 0x0001 )
			/* bit #index is used */
			planes = index + 1;
		sprintf( resStr, "[%dx%dx%dp]", w, h, planes );
		picRes = copyString( resStr );
		if ( c1 IS ONE )
		    sprintf( tempStr, "ASCII PBM" );
		if ( c1 IS TWO )
		    sprintf( tempStr, "ASCII PGM" );
		if ( c1 IS THREE )
		    sprintf( tempStr, "ASCII PPM" );
		if ( c1 IS FOUR )
		    sprintf( tempStr, "RAW PBM" );
		if ( c1 IS FIVE )
		    sprintf( tempStr, "RAW PGM" );
		if ( c1 IS SIX )
		    sprintf( tempStr, "RAW PPM" );
  	    }
	}
  	fclose( fp );
	return( copyString( tempStr ) );
}

static char *getXBMInfo( VOIDPARM )
{
    FILE *fp;
    boolean notDone, gotWidth;
    int w, h;
    char line[ 256 ], resStr[ 32 ], tempStr[ 32 ];

  	fp = fopen( theFile, "r" );
	gotWidth = FALSE;
  	/* read width:  skip lines until we hit a #define */
	notDone = TRUE;
  	while ( notDone ) 
	{
    	    if ( NOT fgets( line, 256, fp ) ) 
	    {
		sprintf( tempStr, "CORRUPT XBM FILE!" );
		notDone = FALSE;
	    }
	    else if ( strncmp( line, "#define", 7 ) IS 0 ) 
	    {
      		if ( sscanf( line, "#define %*s %d", &w ) ISNT 1 ) 
		    sprintf( tempStr, "CORRUPT XBM FILE!" );
		else
		    gotWidth = TRUE;
		notDone = FALSE;
	    }
  	}


  	/* read height:  skip lines until we hit another #define */
	notDone = gotWidth;
  	while ( notDone ) 
	{
    	    if ( NOT fgets( line, 256, fp ) ) 
	    {
		sprintf( tempStr, "CORRUPT XBM FILE!" );
		notDone = FALSE;
	    }
	    else if ( strncmp( line, "#define", 7 ) IS 0 ) 
	    {
      	    	if ( sscanf( line, "#define %*s %d", &h ) ISNT 1 ) 
		    sprintf( tempStr, "CORRUPT XBM FILE!" );
		else
		{
		    sprintf( resStr, "[%dx%dx1p]", w, h );
		    picRes = copyString( resStr );
		    sprintf( tempStr, "XBM" );
		}
		notDone = FALSE;
	    }
  	}
	fclose( fp );
	return( copyString( tempStr ) );
}

static char *getPICInfo( VOIDPARM )
{
    FILE *fp;
    int magic, ignored;
    byte bpp;
    int w, h;
    char planes;
    char resStr[ 32 ], tempStr[ 32 ];

  	fp = fopen( theFile, "r" );
    	magic = getword( fp );
    	if (magic != 0x1234) 
	{
	    w = getword( fp );
	    h = getword( fp );
	    planes = 1;
    	} 
	else 
	{
	    w = getword( fp );
	    h = getword( fp );
	    ignored = getword( fp );
	    ignored = getword( fp );
	    bpp = (u_int)getbyte( fp );
	    planes = ( ( bpp AND_ 0xf0 ) SHR_ 4 ) + 1;
    	}
	fclose( fp );
	sprintf( resStr, "[%dx%dx%dp]", w, h, planes );
	picRes = copyString( resStr );
	sprintf( tempStr, "PIC" );
	return( copyString( tempStr ) );
}


VOIDPARM getFileStats( VOIDPARM )
{
    FILE *fp;
    char magicno[ 8 ];    /* first 8 bytes of file */
    char *infoStr;

	fileType = UNKNOWN;

  	/* try to determine what type of file we've got by reading the */
     	/* first couple bytes and looking for a Magic Number */
  	fp = fopen( theFile, "r" );
  	if ( fp IS NULL ) 
	{
	    if ( verboseOutput )
	    	printf( "Can't open %s to determine file type!\n", theFile );
	    fileStats = copyString( "UNIDENTIFYABLE" );
	    return;
  	}

	if ( verboseOutput )
	{
	    printf( "...determining type/gathering statistics for %s...", 
		    theFile );
	    fflush( stdout );
	}
  	fread( magicno, 8, 1, fp );  
  	fclose( fp );
  	if ( strncmp( magicno, "GIF", 3 ) IS 0 ) 
	{
	    fileType = GIF;
	    fileStats = getGIFInfo();
	}
  	else if ( strncmp( magicno, "hsi1", 4 ) IS 0 ) 
	{
	    fileType = JFIF;
	    fileStats = copyString ( "HSI proprietary JPEG" );
	    picRes = copyString( "[unknown resolution]" );
	}
  	else if ( magicno[ 0 ] IS (char) -1 AND 
	   	magicno[ 1 ] IS (char) -40 AND 
	   	magicno[ 2 ] IS (char) -1 ) 
	{
	    fileType = JFIF;
	    fileStats = getJFIFInfo();
	}
  	else if ( strncmp( magicno, "VIEW", 4) IS 0 OR
	   	strncmp( magicno, "WEIV", 4) IS 0 ) 
	{
	    fileType = PM;
	    fileStats = getPMInfo();
	}
  	else if ( magicno[ 0 ] IS 'P' AND magicno[ 1 ] >= '1' AND 
	   	magicno[ 1 ] <= '6') 
	{
	    fileType = PBM;
	    fileStats = getPBMInfo();
	}
  	else if ( strncmp( magicno, "#define", 7 ) IS 0 ) 
	{
	    fileType = XBM;
	    fileStats = getXBMInfo();
	}
  	else if ( ( (u_int) magicno[ 0 ] IS 0x34 ) AND 
		( (u_int) magicno[ 1 ] IS 0x12 ) )
	{
    	    fileType = PIC;
	    fileStats = getPICInfo(); 
	}
	else
	    fileStats = copyString( "UNKNOWN" );
	if ( DEBUG_PROC )
	    printf( "File %s is of type %s...\n", theFile, fileStats );
	if ( verboseOutput )
	    printf( "done.\n" );
}


syntax highlighted by Code2HTML, v. 0.9.1