/*
    C source file to access the IDE SIMS data files.

    A file named c_code.c is avaiable in case of
    download difficulties.

    Author: Klaus G. Paul
	    kpaul@qm.aif.ncsu.edu AND kpaul@asterix.lrt.mw.tu-muenchen.de
	    (the second address has forwarding to my actual current address)

    Purpose: Access and dump IDE SIMS data file from IDE SIMS database

    Language: Plain C (more ANSI than K&R)

    Runs on: Tested on the following platforms:
	     - DOS-PC 486 [cl]
	     - SUN IPX/ELC, SunOS [used gcc, cc had a problem]
	     - DECstation 3100,Ultrix 4.3 (MIPS) [cc and gcc]
	     - DEC Alpha AXP,OSF/1.3 [cc]
	     - HP 730 HP-UX [c89, cc -a]
	     ... and it worked *WITHOUT* *ANY* changes on all of them.

    Notes: * All data is in Intel data format. Nevertheless, machine-in-
	     dependent conversion routines are supplied.

	   * The compiler used for creation of the database inserted some
	     filler bytes into the structures I used. See the header file
	     for reading (and skipping) these bytes.

	   * This program dumps all stored parameters to the screen and
	     creates data files for the mass data containing x, y and z
	     triplet lines ready to plot e.g. with GNU plot.

	   * Excuse the lack of comments. I feel that the program is quite
	     straightforward. The only two things that are of concern are
	     data type conversion from Intel to machine type, which is
	     documented in ALMOST EVERY book on Intel processors; the RLE-
	     type conversion is documented in the subroutine (yes, my back-
	     ground is FORTRAN) void UncompressImage.
*/
/* 
	USE POSIX/ANSI compliant C-compiler

					  compiler          tested
	DECstation 3100 MIPS Ultrix 4.3   cc, gcc           4/9/94
        HP 730 HP-UX                      c89, cc -a        4/9/94
        DEC Alpha OSF/1.3                 cc                4/9/94
        Sun IPX/ELC SunOS                 gcc               4/9/94
*/
#include <memory.h>
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

#ifndef max
#define max(a,b) (((a)>(b))?(a):(b))
#endif
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif

#define I80x86WORD_SIZE  (2)
#define I80x86INT_SIZE	 (2)
#define I80x86DWORD_SIZE (4)
#define I80x86FLOAT_SIZE (4)

typedef unsigned char	  CHAR;
typedef unsigned int	  WORD;
typedef int		  INT;
typedef unsigned long int DWORD;
typedef float		  FLOAT;

typedef unsigned char	   i80x86CHAR;
typedef unsigned short int i80x86WORD;
typedef short int	   i80x86INT;
typedef unsigned long int  i80x86DWORD;
typedef DWORD		   i80x86FLOAT;

int iINTSize, iWORDSize, iDWORDSize, iFLOATSize;

CHAR i80x86CHAR_to_CHAR ( i80x86CHAR c )
{
    return ((CHAR) c );
}

INT i80x86INT_to_INT ( i80x86INT w )
{
    INT integer;
    unsigned char *p;

    p = (unsigned char *) &w;
    integer = ((WORD) *p) + ((WORD) (*(p+1) << 8));
    return (integer);
}

WORD i80x86WORD_to_WORD ( i80x86WORD w )
{
    WORD word;
    unsigned char *p;

    p = (unsigned char *) &w;
    word = ((WORD) *p) + ((WORD)(*(p+1) << 8));
    return (word);
}

DWORD i80x86DWORD_to_DWORD ( i80x86DWORD dw )
{
    DWORD dword;
    unsigned char *p;

    p = (unsigned char *) &dw;
    dword = ((DWORD) *p) +
            ((DWORD)(*(p+1) << 8L)) +
            ((DWORD)(*(p+2) << 16L)) +
            ((DWORD)(*(p+3) << 24L));
    return (dword);
}


FLOAT i80x86FLOAT_to_FLOAT  ( i80x86FLOAT f )
{
    int sign = 0;
    FLOAT mantissa = 0;
    int exponent = 0;
    int i;
    DWORD j;

    if ( f == 0 )
	return ( 0.0 );

    f = i80x86DWORD_to_DWORD ( f );

    sign     = (f & 0x80000000)? -1 : 1;

    for ( i = 23, j = 1 ; i <= 30 ; i++, j <<= 1 )
        if (f & (1L << i))
	    exponent += j;
    exponent = exponent-127;

    for ( i = 22, j = 2 ; i >= 0 ; i--, j <<= 1 )
        if (f & (1L << i))
	    mantissa += 1.0 / j;
    mantissa += 1;

    return ( sign * mantissa * ( 1L << exponent ) );
}

int DumpHeader ( FILE *IDEFile )
{
    i80x86INT	iPrimaryIonsUsed;
    i80x86INT	iPrimaryIonPolarity;
    i80x86INT	iSecondaryIonPolarity;
    i80x86INT	iPrimaryBeamCurrent;
    i80x86INT	iAccelerationVoltage;
    i80x86INT	iPrimaryAccelVoltage;
    i80x86INT	iRasterSize;
    i80x86INT	iTransferOpticsSetting;
    i80x86INT	iEnergySlitSetting;
    i80x86INT	iEnergySlitTranslation;
    i80x86FLOAT fEntranceSlitSetting;
    i80x86FLOAT fExitSlitSetting;
    i80x86INT	iFieldAperture;
    i80x86INT	iContrastAperture;
    i80x86INT	iRasterPotSetting;
    i80x86INT	iXDimension;
    i80x86INT	iYDimension;
    i80x86INT	iNImages;
    i80x86INT	iDate;
    CHAR	szInstrument[50];
    CHAR	szFeatureName[40];
    i80x86FLOAT fXCoordinate;
    i80x86FLOAT fXCoordinateError;
    i80x86FLOAT fYCoordinate;
    i80x86FLOAT fYCoordinateError;
    CHAR	cBay;
    i80x86INT	iRow;
    CHAR	szAnnotations[3*80];
    i80x86WORD	wDetectorID;
    i80x86WORD	wFeatureNum;
    CHAR	szFeatureTypeCode[5];
    CHAR	szDetectorTypeDesc[50];
    CHAR	szFeatureTypeDesc[50];
    CHAR	szFeatureOriginCode[5];
    CHAR	szFeatureOriginDesc[50];
    CHAR	szJSCCode[15];
    i80x86WORD	wCentralCraterDiameterX;
    i80x86WORD	wCentralCraterDiameterY;
    i80x86WORD	wDisChargeDiameterX;
    i80x86WORD	wDisChargeDiameterY;
    i80x86WORD	wCentralCraterFusedX;
    i80x86WORD	wCentralCraterFusedY;
    i80x86WORD	wInnerSpall;
    i80x86WORD	wOuterSpall;
    i80x86WORD	wPhotoCode;
    i80x86WORD	wAnalysesCode;
    i80x86DWORD dwMosaicXRefCode;
    CHAR	szEDSFileName[100];
    CHAR	szAESFileName[100];
    CHAR	szPROFileName[100];
    CHAR	szBRGFileName[100];
    CHAR	szRATFileName[100];
    CHAR	szExperimentName[10];
    CHAR	bReserved[1000-715];
    char cFill;

    fread ( &iPrimaryIonsUsed, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iPrimaryIonsUsed %i\n", i80x86INT_to_INT ( iPrimaryIonsUsed ) );

    fread ( &iPrimaryIonPolarity, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iPrimaryIonPolarity %i\n", i80x86INT_to_INT ( iPrimaryIonPolarity ) );

    fread ( &iSecondaryIonPolarity, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iSecondaryIonPolarity %i\n", i80x86INT_to_INT ( iSecondaryIonPolarity ) );

    fread ( &iPrimaryBeamCurrent, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iPrimaryBeamCurrent %i\n", i80x86INT_to_INT ( iPrimaryBeamCurrent ) );

    fread ( &iAccelerationVoltage, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iAccelerationVoltage %i\n", i80x86INT_to_INT ( iAccelerationVoltage ) );

    fread ( &iPrimaryAccelVoltage, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iPrimaryAccelVoltage %i\n", i80x86INT_to_INT ( iPrimaryAccelVoltage ) );

    fread ( &iRasterSize, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iRasterSize %i\n", i80x86INT_to_INT ( iRasterSize ) );

    fread ( &iTransferOpticsSetting, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iTransferOpticsSetting %i\n", i80x86INT_to_INT ( iTransferOpticsSetting ) );

    fread ( &iEnergySlitSetting, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iEnergySlitSetting %i\n", i80x86INT_to_INT ( iEnergySlitSetting ) );

    fread ( &iEnergySlitTranslation, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iEnergySlitTranslation %i\n", i80x86INT_to_INT ( iEnergySlitTranslation ) );

    fread ( &fEntranceSlitSetting, I80x86FLOAT_SIZE, 1, IDEFile );
    printf ( "fEntranceSlitSetting %f\n", i80x86FLOAT_to_FLOAT	( fEntranceSlitSetting ) );

    fread ( &fExitSlitSetting, I80x86FLOAT_SIZE, 1, IDEFile );
    printf ( "fExitSlitSetting %f\n", i80x86FLOAT_to_FLOAT  ( fExitSlitSetting ) );

    fread ( &iFieldAperture, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iFieldAperture %i\n", i80x86INT_to_INT ( iFieldAperture ) );

    fread ( &iContrastAperture, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iContrastAperture %i\n", i80x86INT_to_INT ( iContrastAperture ) );

    fread ( &iRasterPotSetting, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iRasterPotSetting %i\n", i80x86INT_to_INT ( iRasterPotSetting ) );

    fread ( &iXDimension, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iXDimension %i\n", i80x86INT_to_INT ( iXDimension ) );

    fread ( &iYDimension, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iYDimension %i\n", i80x86INT_to_INT ( iYDimension ) );

    fread ( &iNImages, I80x86INT_SIZE, 1, IDEFile );
    iNImages = i80x86INT_to_INT ( iNImages );
    printf ( "iNImages %i\n", iNImages );

    fread ( &iDate, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iDate %i\n", i80x86INT_to_INT ( iDate ) );

    fread ( szInstrument, sizeof (szInstrument ), 1, IDEFile );
    printf ( "szInstrument %s\n", szInstrument );

    fread ( szFeatureName, sizeof (szFeatureName ), 1, IDEFile );
    printf ( "szFeatureName %s\n", szFeatureName );

    fread ( &fXCoordinate, I80x86FLOAT_SIZE, 1, IDEFile );
    printf ( "fXCoordinate %f\n", i80x86FLOAT_to_FLOAT	( fXCoordinate ) );

    fread ( &fXCoordinateError, I80x86FLOAT_SIZE, 1, IDEFile );
    printf ( "fXCoordinateError %f\n", i80x86FLOAT_to_FLOAT  ( fXCoordinateError ) );

    fread ( &fYCoordinate, I80x86FLOAT_SIZE, 1, IDEFile );
    printf ( "fYCoordinate %f\n", i80x86FLOAT_to_FLOAT	( fYCoordinate ) );

    fread ( &fYCoordinateError, I80x86FLOAT_SIZE, 1, IDEFile );
    printf ( "fYCoordinateError %f\n", i80x86FLOAT_to_FLOAT  ( fYCoordinateError ) );

    fread ( &cBay, 1, 1, IDEFile );
    printf ( "cBay %c\n", cBay );

    /* !!!!!!!!!!!!! */
    fread ( &cFill, 1, 1, IDEFile );

    fread ( &iRow, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iRow %i\n", i80x86INT_to_INT ( iRow ) );

    fread ( szAnnotations, sizeof (szAnnotations ), 1, IDEFile );
    printf ( "szAnnotations %s\n", szAnnotations );

    fread ( &wDetectorID, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wDetectorID %u\n", i80x86WORD_to_WORD ( wDetectorID ) );

    fread ( &wFeatureNum, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wFeatureNum %u\n", i80x86WORD_to_WORD ( wFeatureNum ) );

    fread ( szFeatureTypeCode, sizeof (szFeatureTypeCode ), 1, IDEFile );
    printf ( "szFeatureTypeCode %s\n", szFeatureTypeCode );

    fread ( szDetectorTypeDesc, sizeof (szDetectorTypeDesc ), 1, IDEFile );
    printf ( "szDetectorTypeDesc %s\n", szDetectorTypeDesc );

    fread ( szFeatureTypeDesc, sizeof (szFeatureTypeDesc ), 1, IDEFile );
    printf ( "szFeatureTypeDesc %s\n", szFeatureTypeDesc );

    fread ( szFeatureOriginCode, sizeof (szFeatureOriginCode ), 1, IDEFile );
    printf ( "szFeatureOriginCode %s\n", szFeatureOriginCode );

    fread ( szFeatureOriginDesc, sizeof (szFeatureOriginDesc ), 1, IDEFile );
    printf ( "szFeatureOriginDesc \n", szFeatureOriginDesc );

    fread ( szJSCCode, sizeof (szJSCCode ), 1, IDEFile );
    printf ( "szJSCCode %s\n", szJSCCode );

    /* !!!!!!!!!!!!! */
    fread ( &cFill, 1, 1, IDEFile );

    fread ( &wCentralCraterDiameterX, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wCentralCraterDiameterX %u\n", i80x86WORD_to_WORD ( wCentralCraterDiameterX ) );

    fread ( &wCentralCraterDiameterY, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wCentralCraterDiameterY %u\n", i80x86WORD_to_WORD ( wCentralCraterDiameterY ) );

    fread ( &wDisChargeDiameterX, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wDisChargeDiameterX %u\n", i80x86WORD_to_WORD ( wDisChargeDiameterX ) );

    fread ( &wDisChargeDiameterY, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wDisChargeDiameterY %u\n", i80x86WORD_to_WORD ( wDisChargeDiameterY ) );

    fread ( &wCentralCraterFusedX, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wCentralCraterFusedX %u\n", i80x86WORD_to_WORD ( wCentralCraterFusedX ) );

    fread ( &wCentralCraterFusedY, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wCentralCraterFusedY %u\n", i80x86WORD_to_WORD ( wCentralCraterFusedY ) );

    fread ( &wInnerSpall, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wInnerSpall %u\n", i80x86WORD_to_WORD ( wInnerSpall ) );

    fread ( &wOuterSpall, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wOuterSpall %u\n", i80x86WORD_to_WORD ( wOuterSpall ) );

    fread ( &wPhotoCode, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wPhotoCode %u\n", i80x86WORD_to_WORD ( wPhotoCode ) );

    fread ( &wAnalysesCode, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wAnalysesCode %u\n", i80x86WORD_to_WORD ( wAnalysesCode ) );

    fread ( &dwMosaicXRefCode, I80x86DWORD_SIZE, 1, IDEFile );
    printf ( "dwMosaicXRefCode %lu\n", i80x86DWORD_to_DWORD ( dwMosaicXRefCode ) );

    fread ( szEDSFileName, sizeof (szEDSFileName ), 1, IDEFile );
    printf ( "szEDSFileName %s\n", szEDSFileName );

    fread ( szAESFileName, sizeof (szAESFileName ), 1, IDEFile );
    printf ( "szAESFileName %s\n", szAESFileName );

    fread ( szPROFileName, sizeof (szPROFileName ), 1, IDEFile );
    printf ( "szPROFileName %s\n", szPROFileName );

    fread ( szBRGFileName, sizeof (szBRGFileName ), 1, IDEFile );
    printf ( "szBRGFileName %s\n", szBRGFileName );

    fread ( szRATFileName, sizeof (szRATFileName ), 1, IDEFile );
    printf ( "szRATFileName %s\n", szRATFileName );

    fread ( szExperimentName, sizeof (szExperimentName ), 1, IDEFile );
    printf ( "szExperimentName %s\n", szExperimentName );

    fread ( bReserved, sizeof (bReserved), 1, IDEFile );

    /* !!!!!!!!!!!!! */
    fread ( &cFill, 1, 1, IDEFile );

    return ( iNImages );
}

/*
    The image data occupies 256*256 16-bit values. Since most of the
    pixels, i.e. data values, are black, i.e. 0, a primitive run-length
    encoder saved tens of megabytes in the IDE database. Instead of storing a
    black pixel as a 0 word, all black values are combined and stored as
    a word containing a 0 and a word containing a repeat factor.

    Example:

    IDE RLE-compressed image data:
    12 0 5 42 554 0 7 2 55 4455 12 0 312 3 ....

    would decompress as
    12 0 0 0 0 0 42 554 0 0 0 0 0 0 0 2 55 4455 12 0 0 0 0 0 0 0 0 0 0 0 0.....
       (5 zeroes)	  (7 zeroes)

    All data values are 16-bit words, unsigned
*/
void UncompressImage ( FILE *IDEFile, int iNum, INT iMass,
		       DWORD dwCompressedImageSize,
		       INT iXShift, INT iYShift )
{
    unsigned long m = 0, n = 0;
    WORD data = 0, count = 0, k = 0;
    int x = 0, y = 0;
    char szBuffer[255];
    FILE *f;

    sprintf ( szBuffer, "im%02u-%03u", iNum , iMass );
    f = fopen ( szBuffer, "w+t" );

    for ( n = 0, m = 0 ; n < dwCompressedImageSize ; n++ )
    {
        fread ( &data, I80x86WORD_SIZE, 1, IDEFile );
        data = i80x86DWORD_to_DWORD ( data );
	if ( data == 0 )
	{
            fread ( &count, I80x86WORD_SIZE, 1, IDEFile );
            count = i80x86DWORD_to_DWORD ( count );
	    n++;
            for ( k = 0 ; k < count ; k++, m++ )
	    {
		x = m % 256 + iXShift;
		x = max ( x , 0 );
		x = min ( x , 255 );
		y = m / 256 + iYShift;
		y = max ( y , 0 );
		y = min ( y , 255 );

		fprintf ( f, "%i %i 0\n", x, y, data );
	    }
	}
	else
	{
	    x = m % 256 + iXShift;
	    y = m / 256 + iYShift;
	    fprintf ( f, "%i %i %u\n", x, y, data );
            m++;
	}
    }

    fclose ( f );
}


void DumpImage ( FILE *IDEFile, int iNum )
{
    i80x86FLOAT fCpGain;
    i80x86INT	iNFrames;
    i80x86INT	iMass;
    i80x86INT	iImageNumber;
    i80x86DWORD dwCompressedImageSize;
    i80x86DWORD dwTotalCount;
    i80x86WORD	wMaxCount;
    i80x86INT	iXShift;
    i80x86INT	iYShift;
    CHAR	szElementName[20];
    i80x86INT	iElementID;
    i80x86FLOAT fRSF;
    i80x86INT	iQualityElementClassification;
    i80x86INT	iObsolete1;
    i80x86INT	iObsolete2;
    i80x86INT	iObsolete3;
    i80x86INT	iObsolete4;

    printf ( "\n" );

    fread ( &fCpGain, I80x86FLOAT_SIZE, 1, IDEFile );
    printf ( "fCpGain %f\n", i80x86FLOAT_to_FLOAT ( fCpGain ) );

    fread ( &iNFrames, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iNFrames %i\n", i80x86INT_to_INT ( iNFrames ) );

    fread ( &iMass, I80x86INT_SIZE, 1, IDEFile );
    iMass = i80x86INT_to_INT ( iMass );
    printf ( "iMass %i\n", iMass );

    fread ( &iImageNumber, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iImageNumber %i\n", i80x86INT_to_INT ( iImageNumber ) );

    fread ( &dwCompressedImageSize, I80x86DWORD_SIZE, 1, IDEFile );
    dwCompressedImageSize = i80x86DWORD_to_DWORD ( dwCompressedImageSize );
    printf ( "dwCompressedImageSize %lu\n", dwCompressedImageSize );

    fread ( &dwTotalCount, I80x86DWORD_SIZE, 1, IDEFile );
    printf ( "dwTotalCount %lu\n", i80x86DWORD_to_DWORD ( dwTotalCount ) );

    fread ( &wMaxCount, I80x86WORD_SIZE, 1, IDEFile );
    printf ( "wMaxCount %u\n", i80x86WORD_to_WORD ( wMaxCount ) );

    fread ( &iXShift, I80x86INT_SIZE, 1, IDEFile );
    iXShift = i80x86INT_to_INT ( iXShift );
    printf ( "iXShift %i\n", iXShift );

    fread ( &iYShift, I80x86INT_SIZE, 1, IDEFile );
    iYShift = i80x86INT_to_INT ( iYShift );
    printf ( "iYShift %i\n", i80x86INT_to_INT ( iYShift ) );

    fread ( szElementName, sizeof (szElementName), 1, IDEFile );
    printf ( "szElementName %s\n", szElementName );

    fread ( &iElementID, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iElementID %i\n", i80x86INT_to_INT ( iElementID ) );

    fread ( &fRSF, I80x86FLOAT_SIZE, 1, IDEFile );
    printf ( "fRSF %f\n", i80x86FLOAT_to_FLOAT ( fRSF ) );

    fread ( &iQualityElementClassification, I80x86INT_SIZE, 1, IDEFile );
    printf ( "iQualityElementClassification %i\n", i80x86INT_to_INT ( iQualityElementClassification ) );

    fread ( &iObsolete1, I80x86INT_SIZE, 1, IDEFile );
    fread ( &iObsolete2, I80x86INT_SIZE, 1, IDEFile );
    fread ( &iObsolete3, I80x86INT_SIZE, 1, IDEFile );
    fread ( &iObsolete4, I80x86INT_SIZE, 1, IDEFile );

    UncompressImage ( IDEFile, iNum, iMass, dwCompressedImageSize,
		      iXShift, iYShift );
}

main ( int argc, char **argv )
{
    FILE *IDEFile;
    int   i, iNumImages;

    if ( argc != 2 )
    {
        fprintf ( stderr, "Usage: dumpdata.c <IDE-FILENAME>\n" );
	exit ( 1 );
    }

    if ( ( IDEFile = fopen ( argv[1], "rb" ) ) == NULL )
    {
	fprintf ( stderr, "Unable to access IDE file %s\n", argv[1] );
	exit ( 1 );
    }

    iNumImages = DumpHeader ( IDEFile );

    for ( i = 0 ; i < iNumImages ; i++ )
	DumpImage ( IDEFile, i );

    exit ( 0 );
}