home *** CD-ROM | disk | FTP | other *** search
- /*
- * DMS-check: by ????????, the unknown programmer
- *
- * This is a program for checking "dms" files on unix systems.
- * Its usage is:
- dmscheck <option> files ...
- *
- * Options are:
- -h or -? : little help
- -s : silent mode. No output at all, only status returned.
- -v : verbose mode. Gives the content of the file.
- -d : debug mode. Very verbose.
-
- * In standart mode, you only get a message "FILE GOOD" or "FILE BAD"
- * for each file you specify.
- * The code is pretty basic Unix, there should be no compiling problem,
- * just do "cc dmscheck.c -o dmscheck" to get the executable.
- * Care was taken to read and use the data as char arrays to avoid
- * alignement problems inside structures (a main portability nuisance).
- *
- * NB: People with little endian machines should define LITTLEINDIAN below.
- * If you're not sure then try out normally. If it fails/coredumps, try with
- * debug flag (-d) and see if CRC's are backwards. If yes: define it.
- * [little-endian compatibility by Geoff C. Wing (gwing@mullauna.cs.mu.oz.au)]
- * that's right, blame it on me if it doesn't work anymore for big-endians :-)
- *
- * TODO: a bit more error checking, I reckon.
- */
- /* #define LITTLEINDIAN /* for little-endian machines */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/file.h>
-
- #define BOXSIZE 5
-
- #define MAXTRACKS 85
-
- typedef char BYTE;
- typedef unsigned char UBYTE;
- typedef short SHORT;
- typedef unsigned short USHORT;
- typedef long LONG;
- typedef unsigned long ULONG;
-
- #define SILENT 0
- #define NORMAL 1
- #define VERBOSE 2
- #define DEBUG 3
-
- int MessageLevel = NORMAL ;
-
- #define NOERROR 0
- #define NONFATAL 1
- #define FATAL 2
-
- int BadFileFlag = 0 ;
- int GlobalStatus = 0 ;
-
- int FirstTrack = 0 ;
- int LastTrack = 0 ;
-
- char Tracks[MAXTRACKS] ;
-
- char IoBuf[60000] ;
- USHORT Crc ;
-
- /* Format of a simple DMS file:
-
- Ident File_Head CRC Track_Head CRC Data Track_Head CRC Data ....
-
- */
-
- char Ident[6] ; /* "DMS!" */
-
- /*
- These macros are used to access the file header components
- with no concern about the alignement requirements of each machine.
- */
-
- #ifdef LITTLEINDIAN
- #define little_swap_short(a) (((a & 0x00ff) << 8) \
- + ((a & 0xff00) >> 8))
- #define little_swap_long(a) (((a & 0x000000ff) << 24) \
- + ((a & 0x0000ff00) << 8) \
- + ((a & 0x00ff0000) >> 8) \
- + ((a & 0xff000000) >> 24))
- #else /* not LITTLEINDIAN */
- #define little_swap_short(a) (a)
- #define little_swap_long(a) (a)
- #endif /* not LITTLEINDIAN */
-
- #define DHEAD_FROM(tab) (SHORT)little_swap_short(*((SHORT *) (tab+12)))
- #define DHEAD_TO(tab) (SHORT)little_swap_short(*((SHORT *) (tab+14)))
- #define DHEAD_CSIZE(tab) (ULONG)little_swap_long(*((ULONG *) (tab+16)))
- #define DHEAD_SIZE(tab) (ULONG)little_swap_long(*((ULONG *) (tab+20)))
- #define DHEAD_MODE(tab) (SHORT)little_swap_short(*((SHORT *) (tab+48)))
-
- char DHeader[50] ;
-
- struct File_Head /*offset - sizeof(File_Head) = 50 */
- {
- long u1 ; /* 0 - ???? */
- long u2 ; /* 4 - ???? */
- long date ; /* 8 - Creation date of file */
- short from ; /*12 - index of first track */
- short to ; /*14 - index of last track */
- ULONG size_after ; /*16 - total size of data after compression */
- ULONG size_before ; /*20 - total size of data before compression */
- long u3 ; /*24 - 0 */
- short cpu ; /*28 - Cpu type ( 1:68000, 2:68010, ... ) */
- short copross ; /*30 - Cpu coprocessor ( 1:68881 ) */
- short machine ; /*32 - Machine used ( 1:Amiga, 2:PC, ...) */
- short u4 ; /*34 - ??? */
- short cpu_speed ; /*36 - */
- long time ; /*38 - Time to create archive in sec. */
- short c_version ; /*42 - Version of creator (66, 67, 68) */
- short n_version ; /*44 - Version needed to extract */
- short disk_type ; /*46 - Disktype of archive */
- short cmode ; /*48 - compression mode 0-4 */
- } ;
-
- char THeader[18] ;
-
- #define THEAD_IDENT(tab) (USHORT)little_swap_short(*((USHORT *) (tab+0 )))
- #define THEAD_TNUM(tab) (SHORT)little_swap_short(*((SHORT *) (tab+2 )))
- #define THEAD_SIZE(tab) (ULONG)little_swap_long(*((ULONG *) (tab+4 )))
- #define THEAD_DCRC(tab) (USHORT)little_swap_short(*((USHORT *) (tab+16)))
-
- struct Track_Head /*offset - sizeof(Track_Head) = 18 */
- {
- short delim ; /* 0 - delimiter, 0x5452, is 'TR' */
- short number ; /* 2 - track number, -1 if text */
- ULONG size ; /* 4 - size of data part */
- USHORT plength ; /* 8 - length of non-encoded data */
- USHORT ulength ; /*10 - length of encoded data */
- short mode ; /*12 - encryption mode(0: simple, 102: quick)*/
- USHORT usum ; /*14 - raw data checksum */
- USHORT dcrc ; /*16 - data CRC */
- } ;
-
-
- static USHORT CRCTab[256]=
- {
- 0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
- 0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
- 0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
- 0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
- 0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
- 0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
- 0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
- 0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
- 0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
- 0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
- 0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
- 0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
- 0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
- 0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
- 0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
- 0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
- 0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
- 0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
- 0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
- 0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
- 0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
- 0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
- 0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
- 0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
- 0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
- 0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
- 0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
- 0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
- 0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
- 0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
- 0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
- 0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
- };
-
- USHORT DoBlockCRC(Mem, Size)
- UBYTE* Mem;
- int Size ;
- {
- register USHORT CRC = 0;
-
- while(Size--)
- CRC = CRCTab[((CRC ^ *Mem++) & 255)] ^ ((CRC >> 8) & 255);
-
- return (CRC) ;
- }
-
- #define MAXFILES 250
-
- char * ListOfFiles[MAXFILES] ;
- int NumberOfFiles ;
-
- static void AppendFileName(f)
- char * f;
- {
- if ( NumberOfFiles >= MAXFILES )
- {
- printf("\tToo many files. Max is %d\n",MAXFILES) ;
- exit(1) ;
- }
- else
- {
- ListOfFiles[NumberOfFiles++] = f ;
- }
- }
-
- static void ReadError(s,n)
- char* s;
- int n;
- {
- if ( MessageLevel >= VERBOSE )
- printf("\tError reading %s (%d char read)\n",s,n) ;
- }
-
- static void WhereInFile(fd,s)
- int fd ;
- char *s;
- {
- int init;
-
- init = lseek(fd, 0L, L_INCR) ;
- if ( MessageLevel >= DEBUG )
- printf("\tStarting read of %s at offset %d\n",s,(int) init ) ;
- }
-
- /*
- * Handling track data
- *
- */
-
- static void ReadTrackHeader(fd)
- int fd ;
- {
- int n_read ;
-
- WhereInFile(fd,"Track header") ;
-
- n_read = read(fd, THeader, sizeof(THeader) ) ;
- if ( n_read != sizeof(THeader) )
- {
- ReadError("Theader DATA",n_read) ;
- BadFileFlag = FATAL;
- return;
- }
-
- n_read = read(fd, (char *) &Crc, 2) ;
- if ( n_read != 2 )
- {
- ReadError("THeader CRC",n_read) ;
- BadFileFlag = FATAL;
- }
- Crc = little_swap_short(Crc);
- }
-
- static void VerifyTrackHeader()
- {
- USHORT crc ;
-
- if ( THEAD_IDENT(THeader) != 0x5452 ) /* Magic string "TR" */
- {
- if ( MessageLevel >= VERBOSE )
- printf("\tBAD THeader identifier: %4x\n",
- (int) THEAD_IDENT(THeader) );
-
- BadFileFlag = FATAL ;
- return ;
- }
-
- crc = DoBlockCRC( THeader, sizeof(THeader) ) ;
-
- if ( crc != Crc )
- {
- if ( MessageLevel >= VERBOSE )
- printf("\tBAD THeader checksum. Read %4x, computed %4x\n",
- (int) Crc, (int) crc ) ;
- BadFileFlag = FATAL ; /* size is not sure */
- }
- else if ( MessageLevel >= DEBUG )
- printf("\tTrack Header checksum OK (%4x)\n",(int) crc ) ;
- }
-
- static void ReadTrackData(fd)
- int fd ;
- {
- int n_read ;
-
- if ( MessageLevel >= DEBUG )
- printf("\tSize of track data: %d\n", (int) THEAD_SIZE(THeader) );
-
- n_read = read(fd, IoBuf, (int) THEAD_SIZE(THeader)) ;
- if ( n_read != THEAD_SIZE(THeader) )
- {
- ReadError("track data",n_read) ;
- BadFileFlag = FATAL ;
- return;
- }
- }
-
-
- static void VerifyTrackData()
- {
- USHORT crc ;
-
- crc = DoBlockCRC( IoBuf, (int) THEAD_SIZE(THeader) );
-
- if ( crc != THEAD_DCRC(THeader) )
- {
- if ( MessageLevel >= VERBOSE )
- {
- printf("\tTrack: %2d ", (int) THEAD_TNUM(THeader)) ;
- printf("-BAD CRC: read %4x, computed %4x\n",
- (int) THEAD_DCRC(THeader), (int) crc ) ;
- }
- BadFileFlag = NONFATAL ;
- }
- else if ( MessageLevel >= VERBOSE )
- {
- printf("\tTrack: %2d ", (int) THEAD_TNUM(THeader)) ;
- printf("-GOOD CRC: %4x\n",(int) crc ) ;
- }
- }
-
- static void UpdateTrackCount()
- {
- Tracks[(int) THEAD_TNUM(THeader)] = 1 ;
- }
-
- static void TreatTrackHunk(fd)
- int fd ;
- {
- ReadTrackHeader(fd) ;
-
- if ( BadFileFlag != FATAL )
- VerifyTrackHeader() ;
-
- if ( BadFileFlag != FATAL )
- ReadTrackData(fd) ;
-
- if ( BadFileFlag != FATAL )
- VerifyTrackData() ;
-
- if ( BadFileFlag != FATAL )
- UpdateTrackCount() ;
- }
-
- static int MoreTrackToRead()
- {
- return (( Tracks[LastTrack] ) ? 0 : 1) ;
- }
-
- static void TreatTracks(fd)
- int fd ;
- {
- while ( BadFileFlag != FATAL && MoreTrackToRead() )
- TreatTrackHunk(fd) ;
- }
-
- static void InitialiseTrackData()
- {
- int i;
-
- BadFileFlag = 0 ;
-
- for ( i= 0; i< MAXTRACKS; i++ )
- Tracks[i] = 0 ;
- }
-
- /*
- * Handling one file dms header
- *
- */
-
- void VerifyDHeader()
- {
- USHORT crc ;
-
- if ( strncmp(Ident, "DMS!", 4 ) )
- {
- if ( MessageLevel >= NORMAL )
- printf("\tThis is *not* a dms archive\n") ;
- BadFileFlag = FATAL ;
- return;
- }
-
- crc = DoBlockCRC(DHeader, sizeof(DHeader) ) ;
-
- if ( crc != Crc )
- {
- if ( MessageLevel >= VERBOSE )
- printf("\tBAD file header checksum. Read %4x, computed %4x\n",
- (int) Crc, (int) crc) ;
- BadFileFlag = FATAL ;
- }
- else if ( MessageLevel >= DEBUG )
- printf("\tDms Header checksum OK (%4x = %4x)\n",
- (int) crc, (int) Crc );
- }
-
- static void UpdateFileData()
- {
-
- if ( MessageLevel >= VERBOSE )
- {
- printf("\tContains tracks: %d to %d\n",
- (int) DHEAD_FROM(DHeader), (int) DHEAD_TO(DHeader) );
-
- printf("\tCompression mode: %d\n", (int) DHEAD_MODE(DHeader)) ;
- printf("\tData sizes: raw: %d compressed: %d\n",
- (int) DHEAD_SIZE(DHeader), (int) DHEAD_CSIZE(DHeader));
- }
-
- FirstTrack = (int) DHEAD_FROM(DHeader) ;
- LastTrack = (int) DHEAD_TO(DHeader) ;
- }
-
- void ReadDHeader(fd)
- int fd ;
- {
- int n_read ;
-
- WhereInFile(fd,"Ident") ;
-
- n_read = read(fd, Ident, 4) ;
- if ( n_read < 4 )
- {
- ReadError("Ident",n_read) ;
- BadFileFlag = FATAL ;
- return ;
- }
-
- WhereInFile(fd,"DHeader") ;
-
- n_read = read(fd, DHeader, sizeof(DHeader)) ;
- if ( n_read < sizeof(DHeader) )
- {
- ReadError("DHeader DATA",n_read) ;
- BadFileFlag = FATAL ;
- return ;
- }
-
- n_read = read(fd, (char *) &Crc, 2) ;
- if ( n_read < 2 )
- {
- ReadError("DHeader CRC",n_read) ;
- BadFileFlag = FATAL ;
- }
- Crc = little_swap_short(Crc);
- }
-
- void TreatDHeader(fd)
- int fd ;
- {
- ReadDHeader(fd) ;
-
- if ( BadFileFlag != FATAL )
- VerifyDHeader() ;
-
- if ( BadFileFlag != FATAL )
- UpdateFileData() ;
- }
-
- /*
- * Handling one file
- *
- */
-
- static void TreatFile(file_)
- char * file_ ;
- {
- int fd ;
-
- if ( (fd = open(file_, 0)) == -1 )
- {
- fprintf(stderr,"\tError opening file: %s\n", file_) ;
- return ;
- }
-
- if ( NumberOfFiles > 1 && MessageLevel >= NORMAL )
- printf("Treating file: %s\n", file_ ) ;
-
- InitialiseTrackData() ;
-
- TreatDHeader(fd) ;
-
- if ( BadFileFlag != FATAL )
- TreatTracks(fd) ;
-
- if ( BadFileFlag )
- {
- if ( MessageLevel >= NORMAL )
- printf("\t>>> FILE BAD\n") ;
- GlobalStatus = 1 ;
- }
- else if ( MessageLevel >= NORMAL )
- printf("\t>>> FILE GOOD\n" ) ;
-
- close(fd) ;
- }
-
- /*
- * Various intialisations and command line handle
- *
- */
-
- static PrintHelp()
- {
- puts("Valid options are:") ;
- puts("\t-s : silent") ;
- puts("\t-v : verbose") ;
- puts("\t-d : debug (very verbose)") ;
- puts("\t-h,-? : help") ;
-
- exit(0) ;
- }
-
- static int DecodeOption(argv, arg)
- char * argv[] ;
- int arg ;
- {
- char *argp = argv[arg]+1 ;
-
- switch ( *argp )
- {
- case 's':
- MessageLevel = SILENT ;
- return (arg+1) ;
-
- case 'v':
- MessageLevel = VERBOSE ;
- return (arg+1) ;
-
- case 'd':
- MessageLevel = DEBUG ;
- return (arg+1) ;
-
- case 'h':
- case '?':
- default:
- PrintHelp() ;
- return (arg+1) ; /* Not executed */
-
- }
- }
-
-
- void DecodeArgLine(argc, argv)
- int argc ;
- char * argv[] ;
- {
- int arg ;
-
- if ( argc <= 1)
- {
- PrintHelp() ;
- }
-
- for ( arg = 1; arg < argc ; )
- {
- if ( *argv[arg] != '-' )
- {
- AppendFileName(argv[arg]) ;
- arg += 1 ;
- }
- else
- arg = DecodeOption(argv,arg) ;
- }
- }
-
- /*
- * Main part
- *
- */
-
- int main(argc,argv)
- int argc ;
- char ** argv ;
- {
- int i;
-
- DecodeArgLine(argc, argv) ;
-
- for ( i=0 ; i< NumberOfFiles; i++ )
- {
- TreatFile(ListOfFiles[i]) ;
- }
-
- return ( GlobalStatus ) ;
- }
-