/* @(#) sciibin.c 1.20 1 Nov 89 */ /************************************************************************* ** ** ** Name : sciibin ** ** Author : Marcel J.E. Mol ** ** Date : 6 Mar 89 (first release) ** ** Version : 1.20 ** ** Files : sciibin.c Main source file ** ** ** ** ------------------------- Revision List ------------------------- ** ** Ver Date Name Remarks ** ** 1.00 06 Mar 89 Marcel Mol First release ** ** 1.10 27 Mar 89 Marcel Mol Finished things up, error ** ** routine, linecount, ** ** all info fields filled in, ** ** changed info layout. ** ** 1.20 01 Nov 89 Dave Whitney Fixed a bug that caused it ** ** to not process more than 1 ** ** segment in any file. ** ** Also fixed CRE/MOD order. ** ** ================================================================= ** ** ** ** Compile as follows: cc sciibin.c -O -s -o sciibin ** ** ** ** Usage: sciibin [-hvtc] [-o] ** ** ** ** -v show only info on file, do not create output. ** ** -t test file, do not create output. ** ** -c do not check checksums. ** ** -o create given filename instead of the one in ** ** binscii file. Use this only if the input files ** ** contain only one output file. ** ** -h help. ** ** ** ** ** ** Defining DEBUG gives some debug information. ** ** Defining DEBUGALL gives input and output of the decode ** ** routine. ** ** ** ** This software is freeware. I can not be held responsible to ** ** any damage this program may cause you or anyone or anything else. ** ** ** ************************************************************************/ #include #include #define BUFLEN 256 /* * Global variables */ char buf[BUFLEN+1]; unsigned char dec[BUFLEN+1]; char alphabet[BUFLEN+1]; char outfilename[BUFLEN+1]; int outflag = 0; /* the -o option */ int crcflag = 0; /* the -c option */ int infoflag = 0; /* the -v option */ int testflag = 0; /* the -t option */ int makeoutput; /* !-t & !-v */ int crcok; /* -t | -c */ FILE *outfp; /* output file */ int namlen, filetype, numblocks; long filesize, startbyte, segmentlen; int modyear, modmonth, modday, modhour, modmin; int creyear, cremonth, creday, crehour, cremin; int auxtype, stortype, access; char * infilename; int linecount; char * progname; /* * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. * NOTE: First argument must be in range 0 to 255. * Second argument is referenced twice. * * Programmers may incorporate any or all code into their programs, * giving proper credit within the source. Publication of the * source routines is permitted so long as proper credit is given * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, * Omen Technology. */ /* #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) */ #define updcrc(cp, crc) ( (crctab[((crc >> 8) & 0xFF) ^ cp] ^ (crc << 8)) & 0xFFFF) /* crctab calculated by Mark G. Mendel, Network Systems Corporation */ static unsigned short crctab[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; char * filetypes[] = { "$00", "bad", "pcd", "ptx", "txt", "pda", "bin", "fnt", "fot", "ba3", "da3", "wpf", "sos", "$0D", "$0E", "dir", "rpd", "rpi", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "adb", "awp", "asp", "$1C", "$1D", "$1E", "$1F", "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$2A", "$2B", "$2C", "$2D", "$2E", "$2F", "$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39", "$3A", "$3B", "$3C", "$3D", "$3E", "$3F", "$40", "$41", "$42", "$43", "$44", "$45", "$46", "$47", "$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F", "$50", "$51", "$52", "$53", "$54", "$55", "$56", "$57", "$58", "$59", "$5A", "$5B", "$5C", "$5D", "$5E", "$5F", "$60", "$61", "$62", "$63", "$64", "$65", "$66", "$67", "$68", "$69", "$6A", "$6B", "$6C", "$6D", "$6E", "$6F", "$70", "$71", "$72", "$73", "$74", "$75", "$76", "$77", "$78", "$79", "$7A", "$7B", "$7C", "$7D", "$7E", "$7F", "$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87", "$88", "$89", "$8A", "$8B", "$8C", "$8D", "$8E", "$8F", "$90", "$91", "$92", "$93", "$94", "$95", "$96", "$97", "$98", "$99", "$9A", "$9B", "$9C", "$9D", "$9E", "$9F", "$A0", "$A1", "$A2", "$A3", "$A4", "$A5", "$A6", "$A7", "$A8", "$A9", "$AA", "$AB", "$AC", "$AD", "$AE", "$AF", "src", "obj", "lib", "s16", "rtl", "exe", "str", "tsf", "nda", "cda", "tol", "drv", "$BC", "$BD", "$BE", "doc", "pnt", "pic", "$C2", "$C3", "$C4", "$C5", "$C6", "$C7", "fon", "$C9", "$CA", "$CB", "$CC", "$CD", "$CE", "$CF", "$D0", "$D1", "$D2", "$D3", "$D4", "$D5", "$D6", "$D7", "$D8", "$D9", "$DA", "$DB", "$DC", "$DD", "$DE", "$DF", "$E0", "$E1", "$E2", "$E3", "$E4", "$E5", "$E6", "$E7", "$E8", "$E9", "$EA", "$EB", "$EC", "$ED", "$EE", "pas", "cmd", "$F1", "$F2", "$F3", "$F4", "$F5", "$F6", "$F7", "$F8", "p16", "int", "ivr", "bas", "var", "rel", "sys", }; /* ProDOS Filetypes Num Name OS Meaning $00 typeless $01 BAD both BAD blocks file $02 PCD SOS Pascal CoDe file $03 PTX SOS Pascal TeXt file $04 TXT both ASCII text file $05 PDA SOS Pascal DAta file $06 BIN both BINary file $07 CHR SOS CHaRacter font file $08 PIC both PICture file $09 BA3 SOS Business BASIC (SOS) program file $0A DA3 SOS Business BASIC (SOS) data file $0B WPD SOS Word Processor Document $0C SOS SOS system file $0D SOS SOS reserved file type $0E SOS SOS reserved file type $0F DIR Both subDIRectory file $10 RPD SOS RPS data file $11 RPI SOS RPS index file $12 SOS Applefile diskcard file $13 SOS Applefile model file $14 SOS Applefile report format file $15 SOS Screen library file $16 SOS SOS reserved file type $17 SOS SOS reserved file type $18 SOS SOS reserved file type $19 ADB ProDOS AppleWorks Database file $1A AWP ProDOS AppleWorks WordProcessing file $1B ASP ProDOS AppleWorks Spreadsheet file $1C-$5F Reserved $60-$6F ProDOS PC Transporter (Applied Engineering) reserved filetypes $60 PRE ProDOS ProDOS preboot driver $61-$6A ProDOS Reserved $6B NIO ProDOS PC Transporter BIOS and drivers $6C ProDOS Reserved $6D DVR ProDOS PC Transporter device drivers $6E ProDOS Reserved $6F HDV ProDOS MSDOS HardDisk Volume $70-$9F Reserved $A0 WPF ProDOS WordPerfect document file $A1 MAC ProDOS Macrofile $A2 HLP ProDOS Help File $A3 DAT ProDOS Data File $A4 Reserved $A5 LEX ProDOS Spelling dictionary $A6-$AB Reserved $AC ARC ProDOS General Purpose Archive file $AD-$AF Reserved $B0 SRC ProDOS ORCA/M & APW source file $B1 OBJ ProDOS ORCA/M & APW object file $B2 LIB ProDOS ORCA/M & APW library file $B3 S16 ProDOS ProDOS16 system file $B4 RTL ProDOS ProDOS16 runtime library $B5 EXE ProDOS APW shell command file $B6 STR ProDOS ProDOS16 startup init file $B7 TSF ProDOS ProDOS16 temporary init file $B8 NDA ProDOS ProDOS16 new desk accessory $B9 CDA ProDOS ProDOS16 classic desk accessory $BA TOL ProDOS ProDOS16 toolset file $BB DRV ProDOS ProDOS16 driver file $BC-$BE Reserved for ProDOS16 load file $BF DOC ProDOS document file $C0 PNT ProDOS //gs paint document $C1 SCR ProDOS //gs screen file $C2-$C7 Reserved $C8 FNT ProDOS Printer font file $C9 ProDOS finder files $CA ProDOS finder icons $CB-$DF Reserved $E0 LBR ProDOS Apple archive library file $E1 Unknown (unlisted) $E2 ATI ProDOS Appletalk init file $E3-$EE Reserved $EF PAS ProDOS ProDOS Pascal file $F0 CMD ProDOS added command file $F1-$F8 ProDOS User defined filetypes (popular ones include:) $F1 OVL ProDOS Overlay file $F2 DBF ProDOS Database file $F3 PAD ProDOS MouseWrite file $F4 MCR ProDOS AE Pro macro file $F5 ECP ProDOS ECP batch file $F6 DSC ProDOS description file $F7 TMP ProDOS temporary work file $F8 RSX ProDOS linkable object module $F9 IMG ProDOS ProDOS image file $FA INT ProDOS Integer BASIC program $FB IVR ProDOS Integer BASIC variables file $FC BAS ProDOS AppleSoft BASIC program $FD VAR ProDOS AppleSoft BASIC variables file $FE REL ProDOS ProDOS EDASM relocatable object module file $FF SYS ProDOS ProDOS8 system file */ /* * function declarations */ sciibin(); getheader(); decode(); decodestring(); char *myfgets(); void usage(); void error(); char * copyright = "@(#) sciibin.c 1.1 27/03/89 (c) M.J.E. Mol"; main(argc, argv) int argc; char **argv; { FILE *fp; int c; extern int optind; /* For getopt */ extern char *optarg; /* For getopt */ int flag; /* Flag for getopt */ progname = *argv; while ((flag = getopt(argc, argv, "hvcto:")) != EOF) { /* Process options */ switch (flag) { case 'v': infoflag = 1; /* Want only info of file */ break; case 'h': usage(); /* Give help */ exit(0); case 'c': crcflag = 1; break; case 't': testflag = 1; break; case 'o': strcpy(outfilename, optarg); outflag = 1; break; default : fprintf(stderr, "%s: skipping unkown flag %c, use -h.\n", progname, flag); break; } } makeoutput = !(testflag | infoflag); crcok = testflag | crcflag; #if defined(DEBUG) fprintf(stderr, "make output: %d, crcok: %d\n", makeoutput, crcok); #endif if (optind >= argc) { /* No files given, use stdin */ infilename = "stdin"; linecount = 0; sciibin(stdin); } else while (optind < argc) { infilename = argv[optind]; optind++; if ((fp = fopen(infilename, "r")) == NULL) { perror(infilename); continue; } linecount = 0; sciibin(fp); fclose(fp); } exit(0); } /* main */ /* * Walk over the file processing all segments in it */ sciibin(fp) FILE *fp; { int processed = 0; /* number of processed binscii segments */ int status = 0; /* return codes of calls to decode */ while (myfgets(buf, BUFLEN, fp) != NULL) { #if defined(DEBUG) fprintf(stderr, "(%s) get start:%s", infilename, buf); #endif if (!strncmp(buf, "FiLeStArTfIlEsTaRt",18)) { if (!getheader(fp) && !infoflag) /* if header ok and not -v flag */ status |= decode(fp); processed++; } } if (processed == 0) { error("not a binscii file"); return 1; } return status; } /* sciibin */ /* * Build the alphabet, get the output file info and open output file * if necessary. * Still contains lots of debug code to find out the header structure. * (every bit is known now...) */ getheader(fp) FILE *fp; { register int i, j; register int crc = 0; struct stat statbuf; /* must know if file exists */ char *iomod; /* write or readwrite a file */ /* * Get the alphabet */ if (myfgets(buf, BUFLEN, fp) == NULL) { error("reading alphabet: unexpected end of file"); return 1; } #if defined(DEBUG) fprintf(stderr, "(%s) alphabet:%s", infilename, buf); #endif if (strlen(buf) != 65) { error("alphabet corrupted"); return 1; } /* * Process the alphabet */ for (i = 0; i < 255; i++) alphabet[i] = 0x7f; for (i = 0; i < 64; i++) { j = buf[i]; if (alphabet[j] != 0x7f) error("Warning: double character in alphabet"); alphabet[j] = i; } #if defined(DEBUG) for (i = 0; i < BUFLEN; i+=16) { fprintf(stderr, "(%s) alphabet[%3d] =", infilename, i); for (j = 0; j < 16; j++) fprintf(stderr, " %02X", alphabet[i+j]); putc('\n', stderr); } #endif /* * Get the file header */ if (myfgets(buf, BUFLEN, fp) == NULL) { error("reading fileheader: unexpected end of file"); return 1; } #if defined(DEBUG) fprintf(stderr, "(%s) fileheader:%s", infilename, buf); #endif /* * Strip output filename if needed */ if (!outflag) { namlen = *buf - 'A' + 1; strncpy(outfilename, buf+1, namlen); outfilename[namlen] = '\0'; } #if defined(DEBUG) fprintf(stderr, "(%s) filename:**%s**\n", infilename, outfilename); fprintf(stderr, "(%s) fileinfo:**%s**", infilename, buf+16); #endif /* * Decode and process the file header information */ if ((i = decodestring(buf+16, dec)) != 27) error("warning: corrupted file header length"); for (i = 0; i < 24; i++) crc = updcrc(dec[i], crc); if (crc != (dec[24] | (dec[25] << 8))) { if (crcok) error("warning: CRC error in file header"); else { error("error: CRC error in file header"); return 1; } } filesize = dec[0] + (dec[1]<<8) + (dec[2]<<16);/* Calculate file length */ startbyte = dec[3] + (dec[4]<<8) + (dec[5]<<16); access = dec[6]; filetype = dec[7]; auxtype = dec[8] + (dec[9] << 8); stortype = dec[10]; numblocks = dec[11] + (dec[12]<<8); #define MOD 13 #define CRE 17 creday = dec[CRE] & 0x1f; cremonth = ((dec[CRE+1] & 0x01) << 3) | (dec[CRE] >> 5); creyear = dec[CRE+1] >>1; cremin = dec[CRE+2] & 0x3f; crehour = dec[CRE+3] & 0x1f; modday = dec[MOD] & 0x1f; modmonth = ((dec[MOD+1] & 0x01) << 3) | (dec[MOD] >> 5); modyear = dec[MOD+1] >>1; modmin = dec[MOD+2] & 0x3f; modhour = dec[MOD+3] & 0x1f; segmentlen = dec[21] + (dec[22]<<8) + (dec[23]<<16); #define READ 0x01 #define WRITE 0x02 #define BACKUP 0x20 #define RENAME 0x40 #define DESTROY 0x80 if (infoflag) { printf("%-15s : %4d of %4d : ", outfilename,startbyte / 0x3000 + 1, (filesize + 0x2FFF) / 0x3000); printf("%s (%d)\n",infilename,linecount); } if (makeoutput) { iomod = (stat(outfilename, &statbuf) == 0) ? "r+" : "w"; if ((outfp = fopen(outfilename, iomod)) == NULL) { error("unable to open output file"); perror(outfilename); return 1; } fseek(outfp, startbyte, 0); } return 0; } /* getheader */ /* * Do the actual decoding of the bin data. */ decode(fp) FILE *fp; { register int i; register int crc = 0; int len; crc = 0; while (segmentlen > 0) { if (myfgets(buf, BUFLEN, fp) == NULL) { error("reading file: unexpected end of file"); return 1; } #if defined(DEBUG) fprintf(stderr, "(%s) data:%s", infilename, buf); #endif if ((len = decodestring(buf, dec)) != 48) error("warning: corrupted line length"); for (i = 0; i < 48; i++) crc = updcrc(dec[i], crc); if (makeoutput) for (i = 0; (i < len) && (segmentlen > 0); i++, segmentlen--) putc(dec[i], outfp); /* COULD CR/NL TXT FILES */ else segmentlen -= len; #if defined(DEBUG) fprintf(stderr, "(%s) still need %d bytes\n", infilename, segmentlen); #endif } /* * must be at end of segment now, with one remaining line containing * the crc check. */ if (myfgets(buf, BUFLEN, fp) == NULL) { error("reading file crc: unexpected end of file"); return 1; } #if defined(DEBUG) fprintf(stderr, "(%s) crc:%s", infilename, buf); #endif if ((len = decodestring(buf, dec)) != 3) error("warning: corrupted crc length"); if (crc != (dec[0] | (dec[1] << 8))) { if (crcok) error("warning: CRC error in file data"); else { error("error: CRC error in file data"); return 1; } } fclose(outfp); return 0; } /* decode */ /* * Decode one string off scii characters to binary data, meanwhile * calculating crc. */ decodestring(in, out) register char *in; register unsigned char *out; { register int len = 0; #if defined(DEBUGALL) char *b; fprintf(stderr, "(%s) decode in: %s\n", infilename, in); b = in; while (*b) fprintf(stderr, ".%02X", alphabet[*b++]); putc('\n', stderr); b = out; #endif while (strlen(in) > 3) { *out++ = ((alphabet[in[3]] << 2) | (alphabet[in[2]] >> 4)) & 0xFF; *out++ = ((alphabet[in[2]] << 4) | (alphabet[in[1]] >> 2)) & 0xFF; *out++ = ((alphabet[in[1]] << 6) | (alphabet[in[0]])) & 0xFF; len += 3; in += 4; } *out = '\0'; if (*in != '\0' && *in != '\n') error("warning: line not ended by NULL or NEWLINE"); #if defined(DEBUGALL) fprintf(stderr, "(%s) decode out:\n", infilename); while (b != out) fprintf(stderr, ".%02X", *b++); putc('\n', stderr); #endif return len; } /* decodestring */ char *myfgets(buf, len, fp) char *buf; int len; FILE *fp; { linecount++; return fgets(buf, len, fp); } /* myfgets */ void usage() { fprintf(stderr, "Usage: sciibin [-vtc] [-o] \n\n"); fprintf(stderr, " -v show only info on file, do not create output.\n"); fprintf(stderr, " -t test file, do not create output.\n"); fprintf(stderr, " -c do not check checksums.\n"); fprintf(stderr, " -o create given filename instead of the one in\n"); fprintf(stderr, " binscii file. Use this only if the input files\n"); fprintf(stderr, " contain only one output file.\n"); fprintf(stderr, " -h this help message.\n"); } /* usage */ void error(str) char *str; { fprintf(stderr, "%s (%s, %d): %s\n", progname, infilename, linecount, str); } /* error */