jtn@potomac.ads.com (John T. Nelson) (06/08/90)
Asciify and binafy are a pair of programs for converting arbitrary format files into ASCII representation for later transmission through network mailers. These programs are superior to Binhex, Mcvert, xbin, et al in that no assumptions are made concerning the type of file being encoded. Also, Asciify and Binafy were written with ease of protability in mind. A Macintosh port is now underway. I welcome bug reports and suggestions for future improvement of this program. I may be reached at kzin!speaker@mimsy.umd.edu or jtn@potomac.ads.com. unzip here [O ]-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8- echo x - asciify mkdir asciify echo x - asciify/asciify.1 sed 's/^x//' >asciify/asciify.1 <<'!Funky!Stuff!' x.\" @(#)asciify.1 1.0 90/06/1 SMI; x.TH ASCIIFY 1 "01 June 1990" x.SH NAME x.LP xasciify \- convert file contents into asciified format x.LP xbinafy \- convert asciified file back to original format x.SH SYNOPSIS x.LP x.B asciify x[ x.IR -c x] x.IR file x[ x.IR asciified_file x] x.LP x.B binafy x.IR asciified_file x[ x.IR file x] x x.SH DESCRIPTION x.LP x.B Asciify xand x.B binafy xare a pair of programs for converting arbitrary format files into xASCII representation for later transmission through network mailers. xThis program is superior to Binhex, Mcvert, xbin, et al in that xno assumptions have been made concerning the type of file being encoded. xAlso, asciify and binafy were written for ease of porting xbetween different machine architectures and thus facilitating xa common interchange standard for files of any format. x xI believe this calls for some diabolical laughter... MWWAHHA HAH HAW xHA HA HA HA!!! x x.nf x.LP xHere's what an asciified file looks like: x x(This file must be decoded with Binafy) x!Asciify Version 1.00!File t!Chk! x7)GI;9*N*'3[;X7T*(+W>H[K=H>B:I+K;XCV$BK+=D#V<(6B;H_T;9/V*(_H*)3J!4327! x;4#P<8?J?"J,7XCC?$#K=8WQ>I3C=$#J:8[F*(_T*(7[;2J,2X_W=(2B;I+C=86B!4161! x . x . x . x?(C[*(;G:9+H?8RB>YGO=87V>IFa$d!2125! x!! x.fi x xAnything outside the parenthetical line and the final bangs are ignored. xAnything following the bang on each line is a checksum, used for error xdetection. Unlike Binhex, the binafy program will tell you which line xhad a checksum error if one occurs, although there isn't much that the xprogram can do to correct the error. x x.SH USING ASCIIFY x.LP xThe command line... x.IP x.B xexample% asciify binary_file asciified_file x.LP xconverts binary_file into the x.B xasciify xformat and puts it into file x.B xasciified_file. xIf no target file is specified then the output is placed onto xstandard output. x xThe command line... x.IP x.B xexample% binafy asciified_file file x.LP xconverts the asciified format file into its original format xand places it in x.B xfile. x xIf no target file is specified then the output is placed onto xstandard output so in the case of binafy you'll want to redirect output xsomeplace. For example: x.IP x.B xexample% binafy asciified_file > file x x.SH "SEE ALSO" x.BR binafy (1), x x.SH HOW IT WORKS x.LP xThree bytes of the original file are read and converted into 4 xcharacters representing 6 bits each of the original 3 bytes. Note that x6 divides into 12 ( 3 bytes times 8 bits per byte) quite evenly. The 64 xcharacters of the ASCII character set starting with the double quote x(hex 22) character are used. The exclamation point character is xreserved as a special delimeter. x xNote that we have used only 64 of the 94 some printable characters. x xIn case the number of bytes in a file is not evenly divisible by 3, a xspecial encoding is used to represent the remaining piece of the byte. xThe remaining pieces can be either 2 bits or 4 bits and thus consume 20 xmore ASCII printable characters. Because these characters are unique in xthe encoding we will know when the end of a file has arrived and, more ximportantly, we will know what these characters represent because they xare outside of the main encoding scheme. x xThis encoding scheme yields a 4 for 3 decompression which I consider to xbe fairly effecient. x x.SH INSTALLATION x.LP xJust type x.B make asciify xto build x.B asciify xand x.B make binafy xto build x.B binafy x xBoth should compile and generate binaries called x.B asciify xand x.B binafy xrespectively. x x.SH FUTURE ENHANCEMENTS x.LP xSupport binafying of multipart files. It's simple enough xto split files apart with the Unix "split" program. It would xbe nice if asciify and binafy split and assembled multiple files xautomagically. Note that the above example has a "part of" spec in the xheader. That's how binafy will know what order to assemble the files xin. x xThe file format is incompatible with Binhex and uuencode/uudecode xformats. I should probably provide compatibility and cross-conversion xfor these too, but since I can't find their source code you'll just xhave to use x.B asciify xformat for now. x xMagic strings. x x.SH BUGS x.LP xThe ANSI C standard actually makes no assumptions concerning xthe size of a character or byte, therefore this program will xprobably do the wrong thing on machines with 13-bit bytes. xThis should not be an immediate concern as most machines use 8 bit xbytes. x xAlso note that I have avoided the use of the fscanf/sscanf whenever xpossible. This is because the behavior of these library routines xvaries from implementation to implementation. x x.SH AUTHOR x.LP x.nf x=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= xORGANIZATION: Kzinti Embassy GEOGRAPHIC: McLean, VA xUUCP: kzin!speaker@mimsy.umd.edu INTERNET: jtn@potomac.ads.com xSPOKEN: Hey Stupid Cat! PHONE: (703) 356-6514 xPROJECT: The Conrail Locomotive/Harpsichord Fusion Program x=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= x.fi !Funky!Stuff! echo x - asciify/DOC cat >asciify/DOC <<'!Funky!Stuff!' ASCIIFY(1) USER COMMANDS ASCIIFY(1) NAME asciify - convert file contents into asciified format binafy - convert asciified file back to original format SYNOPSIS asciify [ -_c ] _f_i_l_e [ _a_s_c_i_i_f_i_e_d__f_i_l_e ] binafy _a_s_c_i_i_f_i_e_d__f_i_l_e [ _f_i_l_e ] DESCRIPTION Asciify and binafy are a pair of programs for converting arbitrary format files into ASCII representation for later transmission through network mailers. This program is supe- rior to Binhex, Mcvert, xbin, et al in that no assumptions have been made concerning the type of file being encoded. Also, asciify and binafy were written for ease of porting between different machine architectures and thus facilitat- ing a common interchange standard for files of any format. I believe this calls for some diabolical laughter... MWWAHHA HAH HAW HA HA HA HA!!! Here's what an asciified file looks like: (This file must be decoded with Binafy) !Asciify Version 1.00!File t!Chk! 7)GI;9*N*'3[;X7T*(+W>H[K=H>B:I+K;XCV$BK+=D#V<(6B;H_T;9/V*(_H*)3J!4327! ;4#P<8?J?"J,7XCC?$#K=8WQ>I3C=$#J:8[F*(_T*(7[;2J,2X_W=(2B;I+C=86B!4161! . . . ?(C[*(;G:9+H?8RB>YGO=87V>IFa$d!2125! !! Anything outside the parenthetical line and the final bangs are ignored. Anything following the bang on each line is a checksum, used for error detection. Unlike Binhex, the binafy program will tell you which line had a checksum error if one occurs, although there isn't much that the program can do to correct the error. USING ASCIIFY The command line... example% asciify binary_file asciified_file converts binary_file into the asciify format and puts it into file asciified_file. If no target file is specified Sun Release 4.0 Last change: 01 June 1990 1 ASCIIFY(1) USER COMMANDS ASCIIFY(1) then the output is placed onto standard output. The command line... example% binafy asciified_file file converts the asciified format file into its original format and places it in file. If no target file is specified then the output is placed onto standard output so in the case of binafy you'll want to redirect output someplace. For example: example% binafy asciified_file > file SEE ALSO binafy(1), HOW IT WORKS Three bytes of the original file are read and converted into 4 characters representing 6 bits each of the original 3 bytes. Note that 6 divides into 12 ( 3 bytes times 8 bits per byte) quite evenly. The 64 characters of the ASCII character set starting with the double quote (hex 22) char- acter are used. The exclamation point character is reserved as a special delimeter. Note that we have used only 64 of the 94 some printable characters. In case the number of bytes in a file is not evenly divisi- ble by 3, a special encoding is used to represent the remaining piece of the byte. The remaining pieces can be either 2 bits or 4 bits and thus consume 20 more ASCII printable characters. Because these characters are unique in the encoding we will know when the end of a file has arrived and, more importantly, we will know what these char- acters represent because they are outside of the main encod- ing scheme. This encoding scheme yields a 4 for 3 decompression which I consider to be fairly effecient. INSTALLATION Just type make asciify to build asciify and make binafy to build binafy Both should compile and generate binaries called asciify and binafy respectively. Sun Release 4.0 Last change: 01 June 1990 2 ASCIIFY(1) USER COMMANDS ASCIIFY(1) FUTURE ENHANCEMENTS Support binafying of multipart files. It's simple enough to split files apart with the Unix "split" program. It would be nice if asciify could assemble multiple files automagi- cally. Note that the above example has a "part of" spec in the header. That's how binafy will know what order to assemble the files in. The file format is incompatible with Binhex and uuencode/uudecode formats. I should probably provide compa- tibility and cross-conversion for these too, but since I can't find their source code you'll just have to use asciify format for now. Magic strings. BUGS The ANSI C standard actually makes no assumptions concerning the size of a character or byte, therefore this program will probably do the wrong thing on machines with 13-bit bytes. This should not be an immediate concern as most machines use 8 bit bytes. Also note that I have avoided the use of the fscanf/sscanf whenever possible. This is because the behavior of these library routines varies from implementation to implementa- tion. AUTHOR =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ORGANIZATION: Kzinti Embassy GEOGRAPHIC: McLean, VA UUCP: kzin!speaker@mimsy.umd.edu INTERNET: jtn@potomac.ads.com SPOKEN: Hey Stupid Cat! PHONE: (703) 356-6514 PROJECT: The Conrail Locomotive/Harpsichord Fusion Program =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Sun Release 4.0 Last change: 01 June 1990 3 !Funky!Stuff! echo x - asciify/Makefile cat >asciify/Makefile <<'!Funky!Stuff!' all: asciify binafy asciify: asciify.c globals.c asciifyCore.c definitions.h globals.h Makefile cc asciify.c globals.c asciifyCore.c -o asciify binafy: binafy.c globals.c binafyCore.c definitions.h globals.h Makefile cc binafy.c globals.c binafyCore.c -o binafy clean: rm -f *.o asciify binafy core #* !Funky!Stuff! echo x - asciify/README cat >asciify/README <<'!Funky!Stuff!' Asciify and binafy are a pair of programs for converting arbitrary format files into ASCII representation for later transmission through network mailers. These programs are superior to Binhex, Mcvert, xbin, et al in that no assumptions are made concerning the type of file being encoded. Also, Asciify and Binafy were written with ease of protability in mind. A Macintosh port is now underway. I welcome bug reports and suggestions for future improvement of this program. I may be reached at kzin!speaker@mimsy.umd.edu or jtn@potomac.ads.com. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ORGANIZATION: Advanced Decision Systems GEOGRAPHIC: Arlington, VA UUCP: kzin!speaker@mimsy.umd.edu INTERNET: jtn@potomac.ads.com SPOKEN: Yo... John! PHONE: (703) 243-1611 PROJECT: The Conrail Locomotive/Harpsichord Fusion Program =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= !Funky!Stuff! echo x - asciify/asciify.c cat >asciify/asciify.c <<'!Funky!Stuff!' #include <stdio.h> #include <fcntl.h> #include "definitions.h" #include "globals.h" /* This is "asciify", a program for converting files of arbitrary format into an ASCII encoding for later transmission through network mailers. The program "binafy" should be used to convert the ASCII encoding back into the original file. Usage: asciify [ -c ] <original file> [ <asciified file> ] -- John T. Nelson (a.k.a. Speaker-To-Animals) mimsy!kzin!speaker */ BOOLEAN parseFlags(argv) char *argv[]; { char *s; unsigned int k; if ( *argv[0] == '-' ) { k = 1; header.useCheck = FALSE; for ( s = argv[0] + 1; *s != '\0'; s++ ) { switch ( *s ) { case 'c': header.useCheck = TRUE; break; } k++; } return TRUE; } else return FALSE; } main(argc, argv) int argc; char *argv[]; { int fi; FILE *fo; unsigned int counter; int status; if ( argc == 1 ) { printf("Usage: asciify [ -c ] <original file> <target file>\n"); return; } argv++; if ( argc == 2 ) { if ( *argv[0] == '-' ) { printf("Usage: asciify [ -c ] <original file> <target file>\n"); return; } else { fi = open( *argv, O_RDONLY); fo = stdout; strcpy(header.fileName, "stdout"); } } if ( argc == 3 ) if ( parseFlags(argv) ) { argv++; fi = open( *argv, O_RDONLY); fo = stdout; strcpy(header.fileName, "stdout"); } else { fi = open( *argv, O_RDONLY); argv++; fo = fopen(*argv, "w"); strcpy(header.fileName, *argv); } if ( argc == 4 ) if ( parseFlags(argv) ) { argv++; fi = open( *argv, O_RDONLY); argv++; fo = fopen(*argv, "w"); strcpy(header.fileName, *argv); } else { printf("More than 2 file names - I'm quiting\n"); return; } if ( argc > 4 ) { printf("More than 2 file names - I'm quiting\n"); return; } asciify(fi, fo); } !Funky!Stuff! echo x - asciify/asciifyCore.c cat >asciify/asciifyCore.c <<'!Funky!Stuff!' #include <stdio.h> #include <fcntl.h> #include "definitions.h" #include "globals.h" asciify(fi, fo) int fi; FILE *fo; { unsigned int counter; int status; num = 0; cur = buffer; putHerald(fo); counter = 0; status = 0; while ( status != EOF ) { status = convertThree(fi, fo, header.useCheck); fflush(fo); } fputc(DELIMETER, fo); fputc(DELIMETER, fo); fprintf(fo, "\n"); fflush(fo); close(fi); fclose(fo); } errorCleanup(fi, fo) int fi; FILE *fo; { close(fi); fclose(fo); } /* No... don't look! It's EVIL! */ convertThree(fi, fo, check) int fi; FILE *fo; BOOLEAN check; { int status; unsigned int i; char byte1, byte2, byte3; char c; unsigned int checksum; i = 1; checksum = 0; status = SUCCESS; while (i < LINE_LENGTH && status != EOF) { status = getAbyte(fi, &byte1); if ( status == EOF ) { break; } checksum = checksum + (unsigned char) byte1; convert1(&byte1, &c); fputc(c, fo); i++; status = getAbyte(fi, &byte2); if ( status == EOF ) { putShortTwo(fo, byte1); break; } checksum = checksum + (unsigned char) byte2; convert2(&byte1, &byte2, &c); fputc(c, fo); i++; status = getAbyte(fi, &byte3); if ( status == EOF ) { putShortFour(fo, byte2); break; } checksum = checksum + (unsigned char) byte3; convert3(&byte2, &byte3, &c); fputc(c, fo); i++; convert4(&byte3, &c); fputc(c, fo); i++; byte1 = 0; byte2 = 0; byte3 = 0; } if ( i == 1 ) return EOF; putCheckSum(fo, checksum, check); return status; } putCheckSum(fo, checksum, check) FILE *fo; unsigned int checksum; BOOLEAN check; { if ( checksum < 0 ) check = check; if ( check == YES ) fprintf(fo,"%c%u%c\n", DELIMETER, checksum, DELIMETER); else { fputc(DELIMETER, fo); fputc('\n', fo); } } convert1(b1, c) char *c; char *b1; { char byte; byte = *b1; byte &= UPPER_SIX_BITS; byte = byte >> 2; byte &= LOWER_SIX_BITS; byte += CODING_START; *c = byte; return SUCCESS; } convert2(b1, b2, c) char *c; char *b1, *b2; { char byte1; char byte2; byte1 = *b1; byte2 = *b2; byte1 &= LOWER_TWO_BITS; byte2 &= UPPER_FOUR_BITS; byte1 = byte1 << 4; byte2 = byte2 >> 4; byte1 &= 0x30; byte2 &= LOWER_FOUR_BITS; byte1 |= byte2; byte1 &= LOWER_SIX_BITS; byte1 += CODING_START; *c = byte1; return SUCCESS; } convert3(b2, b3, c) char *c; char *b2, *b3; { char byte2; char byte3; byte2 = *b2; byte3 = *b3; byte2 &= LOWER_FOUR_BITS; byte3 &= UPPER_TWO_BITS; byte2 = byte2 << 2; byte3 = byte3 >> 6; byte2 &= 0x3C; byte3 &= LOWER_TWO_BITS; byte2 |= byte3; byte2 &= LOWER_SIX_BITS; byte2 += CODING_START; *c = byte2; return SUCCESS; } convert4(b3, c) char *c; char *b3; { char byte3; byte3 = *b3; byte3 &= LOWER_SIX_BITS; byte3 += CODING_START; *c = byte3; return SUCCESS; } processChecksum() { } getAbyte(fi, c) int fi; char *c; { if ( num == 0 ) { num = read(fi, buffer, BUFFER_SIZE); if ( num == 0 || num == EOF ) return EOF; cur = buffer; } *c = *cur; cur += 1; num -= 1; return SUCCESS; } putShortTwo(fo, b) FILE *fo; char b; { char byte; byte = b; byte &= LOWER_TWO_BITS; byte += START_TWO; fputc(byte, fo); } putShortFour(fo, b) FILE *fo; char b; { char byte; byte = b; byte &= LOWER_FOUR_BITS; byte += START_FOUR; fputc(byte, fo); } putHerald(fo) FILE *fo; { fprintf(fo, "\n%s", HERALD); fputc(DELIMETER, fo); fprintf(fo, VERSION_STRING, VERSION_NUM); fputc(DELIMETER, fo); fprintf(fo, FILE_STRING, header.fileName); if ( header.useCheck == YES ) { fputc(DELIMETER, fo); fprintf(fo, CHECKSUM_STRING); } fputc(DELIMETER, fo); fprintf(fo, "\n"); } !Funky!Stuff! echo x - asciify/binafy.c cat >asciify/binafy.c <<'!Funky!Stuff!' #include <stdio.h> #include <fcntl.h> #include "definitions.h" #include "globals.h" /* This is "binafy", a program for converting "asciified" files back into their original file formats. Usage: binafy <asciified file> <original file> -- John T. Nelson (a.k.a. Speaker-To-Animals) mimsy!kzin!speaker */ main(argc, argv) int argc; char *argv[]; { FILE *fi; int fo; if ( argc == 1 ) { printf("Usage: binafy <asciify'd file> <original file>\n"); return; } if ( argc == 2 ) { fo = STANDARD_OUTPUT_FD; /* Assume the shmuck knows what he wants */ } if ( argc == 2 || argc == 3) { argv++; fi = fopen( *argv, "r"); } if ( argc == 3 ) { argv++; #ifndef THINK_C fo = open(*argv, O_WRONLY | O_CREAT, 0640); #else fo = open(*argv, O_WRONLY | O_CREAT); #endif } if ( argc > 3 ) { printf("More than 2 arguments - I'm quiting\n"); return; } binafy(fi, fo); } !Funky!Stuff! echo x - asciify/binafyCore.c cat >asciify/binafyCore.c <<'!Funky!Stuff!' #include <stdio.h> #include <fcntl.h> #include "definitions.h" #include "globals.h" binafy(fi, fo) FILE *fi; int fo; { num = -1; header.line = 1; if ( flushHerald(fi) == FAILURE ) { fclose(fi); close(fo); exit(); } if ( readHeader(fi, header.header) == FAILURE ) { fclose(fi); close(fo); exit(); } parseHeader(&header); if ( header.useCheck == YES ) processWithChecksums(fi, fo); else processWithoutChecksums(fi, fo); fclose(fi); flushBuffer(fo); close(fo); } processWithChecksums(fi, fo) int fi; FILE *fo; { int status; status = SUCCESS; while ( status != EOF ) { status = processLine(fi, fo, &header); if ( status == FAILURE ) return; if ( checkChecksum(header) == FAILURE ) { printf("Checksum error detected on line %d!\n", header.line); return; } header.line += 1; } } processWithoutChecksums(fi, fo) int fi; FILE *fo; { int status; status = SUCCESS; while ( status != EOF ) { status = processLine(fi, fo, &header); if ( status == FAILURE ) return; header.line += 1; } } processLine(fi, fo, header) FILE *fi; int fo; struct HEADER_STRUCT *header; { char string[NUM_DATA_CHARS]; char errorChars[NUM_CHECKSUM_CHARS]; unsigned int i; unsigned int lastChar; unsigned int checksum; char byte1; char byte2; char byte3; int status; switch ( collectStrings(fi, string, errorChars) ) { case SUCCESS: break; case FAILURE: return FAILURE; case DOUBLE_DELIMS: return EOF; default: return FAILURE; }; i = 0; checksum = 0; lastChar = strlen(string) - 1; convertToNumber(errorChars, &(header -> checksumRead)); while( i <= lastChar ) { if ( string[i] == DELIMETER ) { header -> checksum = checksum; return SUCCESS; } status = SUCCESS; status = convert1(string[i], &byte1); if ( status == TRAILING_CHARS ) { printf("Byte 1 started with a short byte!\n"); return FAILURE; } i++; status = convert2(string[i], &byte1, &byte2); if ( status == TRAILING_FOUR ) { printf("Byte 1 decoded 4 bits not 2!\n"); return FAILURE; } checksum += (unsigned char) byte1; if ( status == TRAILING_TWO ) { putAchar(byte1, fo); status = EOF; break; } putAchar(byte1, fo); i++; status = convert3(string[i], &byte2, &byte3); if ( status == TRAILING_TWO ) { printf("Byte 2 decoded 2 bits not 4!\n"); return FAILURE; } checksum += (unsigned char) byte2; if ( status == TRAILING_FOUR ) { putAchar(byte2, fo); status = EOF; break; } putAchar(byte2, fo); i++; status = convert4(string[i], &byte3); if ( status == TRAILING_CHARS ) { printf("Byte 3 had a short byte!\n"); return FAILURE; } putAchar(byte3, fo); checksum += (unsigned char) byte3; i++; byte1 = 0; byte2 = 0; byte3 = 0; } header -> checksum = checksum; return SUCCESS; } convert1(c, b1) char c; char *b1; { char byte; if ( c >= SHORT_START ) return TRAILING_CHARS; byte = c - CODING_START; byte = byte << 2; byte &= UPPER_SIX_BITS; *b1 = byte; return SUCCESS; } convert2(c, b1, b2) char c; char *b1, *b2; { char byte1; char byte2; char byte; char cc; if ( c >= START_FOUR ) return TRAILING_FOUR; byte1 = *b1; if ( c >= START_TWO && c < START_FOUR ) { byte = c - SHORT_START; byte1 |= byte; *b1 = byte1; return TRAILING_TWO; } cc = c - CODING_START; byte = cc >> 4; /* Extract the upper 2 bits */ byte &= LOWER_TWO_BITS; byte1 |= byte; byte = cc << 4; /* The lower 4 bits */ byte2 = byte & UPPER_FOUR_BITS; *b1 = byte1; *b2 = byte2; return SUCCESS; } convert3(c, b2, b3) char c; char *b2, *b3; { char byte2; char byte3; char byte; char cc; if ( c < START_FOUR && c >= SHORT_START ) return TRAILING_TWO; byte2 = *b2; if ( c >= START_FOUR && c <= SHORT_STOP ) { byte = c - (SHORT_START + MASK_TWO); byte2 |= byte; *b2 = byte2; return TRAILING_FOUR; } cc = c - CODING_START; byte = cc >> 2; /* Extract the upper 4 bits */ byte &= LOWER_FOUR_BITS; byte2 |= byte; byte = cc << 6; /* The lower 2 bits */ byte3 = byte & UPPER_TWO_BITS; *b2 = byte2; *b3 = byte3; return SUCCESS; } convert4(c, b3) char c; char *b3; { char byte3; char byte; byte3 = SHORT_START; if ( c >= SHORT_START ) return TRAILING_CHARS; byte3 = *b3; byte = c - CODING_START; byte &= LOWER_SIX_BITS; byte3 |= byte; *b3 = byte3; return SUCCESS; } flushHerald(fi) FILE *fi; { char string[MAX_LINE_LENGTH]; while ( fgets(string, MAX_LINE_LENGTH, fi) != NULL ) { header.line++; if ( strcmp(string, HERALD) == 0 ) return SUCCESS; } printf("Geeze... I didn't even get to the herald!\n"); return FAILURE; } readHeader(fi, h) FILE *fi; char *h; { while ( fgets(h, MAX_LINE_LENGTH, fi) != NULL ) { header.line++; if ( h[0] == DELIMETER ) return SUCCESS; } printf("Couldn't find the header!\n"); return FAILURE; } putAchar(byte, fo) char byte; int fo; { num++; if ( num > BUFFER_SIZE - 1 ) { write(fo, buffer, BUFFER_SIZE); num = 0; } buffer[num] = byte; } flushBuffer(fo) int fo; { int n; if ( num > BUFFER_SIZE - 1 ) num = BUFFER_SIZE; else num++; while ( num > 0 ) { n = write(fo, buffer, num); num -= n; } } parseHeader(header) struct HEADER_STRUCT *header; { char *s; char h[MAX_LINE_LENGTH]; s = header -> header; header -> useCheck = FALSE; if ( *s != DELIMETER ) { printf("Bad header format!\n"); return FAILURE; } s++; while ( *s != '\n' && *s != '\0' ) { if ( headerExtract(&s, h) == FAILURE ) return FAILURE; if ( strcmp(h, CHECKSUM_STRING) == 0 ) header -> useCheck = TRUE; } } headerExtract(s, h) char **s; char *h; { while ( **s == DELIMETER || **s == '\n' ) (*s)++; while ( **s != DELIMETER ) { if ( **s == '\0' ) return FAILURE; *h = **s; h++; (*s)++; } *h = '\0'; return SUCCESS; } collectStrings(fi, s, e) FILE *fi; char *s; char *e; { char c; if ( getAchar(fi, &c) == EOF ) return FAILURE; while ( c != DELIMETER ) { *s = c; s++; if ( getAchar(fi, &c) == EOF ) return FAILURE; } *s = '\0'; if ( getAchar(fi, &c) == EOF ) return FAILURE; if ( c == DELIMETER && *s == '\0' ) return DOUBLE_DELIMS; if ( header.useCheck == NO ) { while ( c != '\n' ) { if ( getAchar(fi, &c) == EOF ) return FAILURE; } } else { if ( c == DELIMETER || c == '\n' ) { printf("So where's the checksum?\n"); return FAILURE; } while ( c != DELIMETER ) { *e = c; if ( getAchar(fi, &c) == EOF ) return FAILURE; e++; } if ( getAchar(fi, &c) == EOF ) return FAILURE; if ( c != '\n' ) { printf("Expected a new-line here\n"); return FAILURE; } } *e = '\0'; return SUCCESS; } checkChecksum(header) struct HEADER_STRUCT header; { if ( header.checksum != header.checksumRead ) return FAILURE; else return SUCCESS; } getAchar(fi, c) FILE *fi; char *c; { if ( (*c = fgetc(fi)) == EOF ) { printf("Premature EOF encountered\n"); return EOF; } } convertToNumber(errorChars, number) char *errorChars; unsigned int *number; { int s; int sum, n; unsigned int i; char c; s = strlen(errorChars) - 1; sum = 0; i = 0; while ( s >= 0 ) { c = errorChars[s]; n = atoi(&c); if ( i == 0 ) sum += n; else sum += (n * power(10, i)); s--; i++; } *number = (unsigned int) sum; } power(base, n) int base, n; { int i, p; p = 1; for ( i = 1; i <= n; ++i ) p = p * base; return p; } !Funky!Stuff! echo x - asciify/definitions.h cat >asciify/definitions.h <<'!Funky!Stuff!' #ifndef DEFINITIONS_DEFINED #define DEFINITIONS_DEFINED #define TRUE 1 #define FALSE 0 #define YES TRUE #define NO FALSE #define VERSION_NUM 1.0 #define VERSION_STRING "Asciify Version %1.2f" #define FILE_STRING "File %s" #define CHECKSUM_STRING "Chk" #define DELIMETER 0x21 #define CODING_START 0x22 #define BIT_SPAN 0x3F /* 6 bits worth */ #define SHORT_START (CODING_START + BIT_SPAN + 1) #define MASK_TWO 0x0003 #define MASK_FOUR 0x000F #define START_TWO SHORT_START #define START_FOUR (SHORT_START + MASK_TWO + 1) #define SHORT_STOP 0x7E #define LOWER_CHAR 0x00FF #define UPPER_CHAR 0xFF00 #define UPPER_TWO_BITS 0xC0 #define UPPER_FOUR_BITS 0xF0 #define UPPER_SIX_BITS 0xFC #define LOWER_TWO_BITS 0x03 #define LOWER_FOUR_BITS 0x0F; #define LOWER_SIX_BITS 0x3F #define FAILURE 0 #define SUCCESS 1 #define NO_TRAILING 1 #define TRAILING_CHARS 2 #define TRAILING_TWO 3 #define TRAILING_FOUR 4 #define DOUBLE_DELIMS 5 #define CHECKSUM 10 #define NO_CHECKSUM 11 #define BUFFER_SIZE 1024 #define MAX_LINE_LENGTH 80 #define LINE_LENGTH 64 #define NUM_CHECKSUM_CHARS 10 #define NUM_DATA_CHARS 80 #define HERALD "(This file must be decoded with Binafy)\n" typedef short BOOLEAN; typedef struct HEADER_STRUCT { char fileName[MAX_LINE_LENGTH]; char header[MAX_LINE_LENGTH]; BOOLEAN useCheck; unsigned int checksum; unsigned int checksumRead; unsigned int line; }; #define STANDARD_OUTPUT_FD 1 #endif !Funky!Stuff! echo x - asciify/globals.c cat >asciify/globals.c <<'!Funky!Stuff!' #include "definitions.h" char buffer[BUFFER_SIZE]; int num = 0; char *cur; struct HEADER_STRUCT header = { "", /* The file we are processing */ "", /* The line read */ NO, /* Perform checksums? */ 0, /* CHecksum calculated */ 0, /* Checksum read */ 0 /* Line */ }; !Funky!Stuff! echo x - asciify/globals.h cat >asciify/globals.h <<'!Funky!Stuff!' #include "definitions.h" extern char buffer[BUFFER_SIZE]; extern int num; extern char *cur; extern struct HEADER_STRUCT header; !Funky!Stuff! echo x - asciify/tyger cat >asciify/tyger <<'!Funky!Stuff!' Tyger, Tyger burning bright In the forest of the night What immortal hand or eye Could frame thy fearful symmetry? !Funky!Stuff!