dcw@goldilocks.lcs.mit.edu (08/27/90)
I've ahd a few requests for this, so here it is. Note that this is not the latest version to come by here, but it works fine. The newer version has encoding but it only compiles under APW. This is intended for Unix boxes and it only decodes. This was not written by me and is therefore not supported by me. It does appear to work... /* @(#) 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<outputfile>] <infiles> ** ** ** ** -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 <sys/types.h> #include <stdio.h> #include <sys/stat.h> #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 %3s aux: %04X ", outfilename, filetypes[filetype], auxtype); putchar(access & READ ? 'r' : '-'); putchar(access & WRITE ? 'w' : '-'); putchar(access & RENAME ? 'n' : '-'); putchar(access & DESTROY ? 'd' : '-'); putchar(access & BACKUP ? 'b' : '-'); switch (stortype) { case 0x0F : printf(" voldir"); break; case 0x0D : printf(" dir"); break; case 0x01 : printf(" seed"); break; case 0x02 : printf(" sap"); break; case 0x03 : printf(" tree"); break; default : printf(" ???"); break; } printf(" %02d/%02d/%02d(%02d:%02d) -", modmonth, modday, modyear, modhour, modmin); printf(" %02d/%02d/%02d(%02d:%02d)\n", cremonth, creday, creyear, crehour, cremin); printf("Part %4d of %4d,", startbyte / 0x3000 + 1, (filesize + 0x2FFF) / 0x3000); printf(" bytes %7d to %7d of %7d bytes, %5d blocks\n", startbyte, startbyte+segmentlen, filesize, numblocks); } 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<outputfile>] <infiles>\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 */ -- Dave Whitney | I wrote Z-Link and BinSCII. Send me bug MIT 1990 Computer Science | reports. I need a job. Send me an offer. dcw@goldilocks.lcs.mit.edu | My opinions, you hear? MINE! dcw@athena.mit.edu | Are you sure you know what you're doing?