home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / bin / msvv90sea.exe / MSBOOFLS.EXE / MSBMKB.C < prev    next >
C/C++ Source or Header  |  1992-07-30  |  10KB  |  294 lines

  1. /* MSBMKB.C
  2.  *
  3.  * Translates a binary file into a file composed only of printable characters,
  4.  * called a "BOO file", which can be decoded by the MSBPCT program.  The file
  5.  * is encoded by taking three consecutive eight bit bytes and dividing them
  6.  * into four six-bit bytes.  An ASCII zero is then added to the resulting four
  7.  * bytes to make them printable ASCII characters in the range of the character
  8.  * zero to the character underscore.  To reduce the size of the encoded file,
  9.  * runs of up to 78 consecutive NULs (ASCII 0) are compressed into only two
  10.  * characters, tilde (~) followed by the number of NULs + "0".  Because of the
  11.  * four-for-three encoding, runs of NULs can only start with the first
  12.  * character of a triplet.
  13.  *
  14.  * This will compile automatically on an MS-DOS system if the compiler
  15.  * has the symbol MSDOS predefined (as does Microsoft C).  If the symbol
  16.  * MS-DOS is not defined, it will compile automatically for UNIX.
  17.  */     
  18.  
  19. /* Update history:
  20.  *
  21.  * 1/25/92 - Christian Hemsing. OS-9 support. Added one or two ~0 at end
  22.  * to decide whether one or two nulls should be removed from end. Old BOO
  23.  * decoders should not be bothered.  (Idea from Charles Lasner.)
  24.  *
  25.  * 6/10/90 - Frank da Cruz.  Remove TOPS-20 code, make it work automatically
  26.  * under UNIX.
  27.  * 
  28.  * 1/27/89 - Frank da Cruz.  Fix up #ifdef's for MSDOS.
  29.  *
  30.  * 1/01/88 - Frank da Cruz.  Add exit(0); to end of main() to give good
  31.  * return code upon success.
  32.  *
  33.  * 3/11/86 - Howie Kaye, Columbia University:
  34.  *  . Added UNIX and Microsoft C compatibility.
  35.  *  . Changed I/O to be buffered.
  36.  * Note: There is a bug built into the EOF handling which causes the 
  37.  * output file to grow every time a file is packed/unpacked.  This is 
  38.  * because 2 nulls and a space are added at the end of each run.  Since
  39.  * the data is past the end of the file, it does not affect the program
  40.  * produced.
  41.  *
  42.  * Original by Bill Catchings, Columbia University, July 1984.
  43.  */
  44.  
  45. #include <stdio.h>        /* Standard C i/o definitions */
  46.  
  47. #ifdef MSDOS
  48. #include <fcntl.h>
  49. #else
  50. #ifdef OSK
  51. #include <modes.h>
  52. #else
  53. #include <sys/file.h>
  54. #endif
  55. #endif
  56.  
  57. /* Symbol Definitions */
  58.  
  59. #define MAXPACK     80    /* Maximum record (line) size */
  60.  
  61. #define MYRPTQ        '~'     /* Repeat count prefix */
  62. #define DATALEN     MAXPACK-3    /* Length of data buffer - \r,\n,\0*/
  63.  
  64. #define TRUE        -1    /* Boolean constants */
  65. #define FALSE        0
  66.  
  67. /* Macros */
  68.  
  69. #define tochar(ch)  ((ch) + '0')
  70.  
  71. /* Global Variables */
  72.  
  73. int    maxsize,            /* Max size for data field */
  74.     fd,                /* File descriptor of output file */
  75.     ofd,                /* File descriptor of input file */
  76.     otot,                /* Current character number */
  77.     rpt,                /* Repeat count */
  78.     rptq,                /* Repeat quote */
  79.     rptflg,                /* Repeat processing flag */
  80.     size,                /* Size of present record (line) */
  81.     t,                /* Current character value as int */
  82.     eoflag;                /* Set when file is empty. */
  83.  
  84. long    nc,                /* Number of input characters */
  85.     oc;                /* Number of output characters */
  86.  
  87. char    one,                /* First character of triplet */
  88.     two,                /* Second character of triplet */
  89.     three,                /* Third character of triplet */
  90.     *filnam,            /* Input file name */
  91.     *ofile,                /* Output file name */
  92.     packet[MAXPACK];        /* Output record buffer */
  93.  
  94. main(argc,argv) int argc; char **argv; {
  95.  
  96.     char sfile();            /* Send file routine & ret code */
  97.  
  98.     if (--argc != 2) usage();        /* Make sure there's a command line. */
  99.     rptq = MYRPTQ;            /* Repeat Quote */
  100.     rptflg = TRUE;            /* Repeat Count Processing Flag */
  101.  
  102.     filnam = *++argv;            /* Get file to send */
  103.     ofile = *++argv;            /* Output file to create */
  104.     sfile();
  105.     printf("\
  106.       Done, in: %ld, out: %ld, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
  107.     exit(0);
  108. }
  109.  
  110. /*
  111.    S F I L E - Encode a whole file
  112. */
  113.  
  114. char sfile() {
  115.     char *i;
  116.  
  117. #ifdef MSDOS
  118. #ifndef O_RAW
  119. #define O_RAW O_BINARY
  120. #endif /* O_RAW */
  121. #else
  122. #define O_RAW 0
  123. #endif /* MSDOS */
  124.  
  125. #ifdef OSK
  126.     fd = open(filnam,S_IREAD);
  127. #else
  128.     fd = open(filnam,O_RDONLY | O_RAW,0x1ff);
  129. #endif
  130.     if (fd < 0) {            /* Report any errors */
  131.     printf("\n?Error opening file \"%s\"\n",filnam);
  132.     exit(1);
  133.     }
  134. #ifdef MSDOS
  135.     ofd = open(ofile,O_CREAT|O_WRONLY|O_TRUNC|O_RAW,0x1ff);
  136. #else
  137. #ifdef OSK
  138.     ofd = creat(ofile,S_IWRITE);
  139. #else
  140.     ofd = open(ofile,O_CREAT|O_WRONLY|O_TRUNC|O_RAW,0664);
  141. #endif /* OSK */
  142. #endif /* MSDOS */
  143.     if (ofd < 0) {
  144.     printf("\n?error opening file \"%s\"\n",ofile);
  145.     exit(1);
  146.     }
  147.     oc = strlen(filnam);        /* Filename string length. */
  148.     for (i=filnam; *i != '\0'; i++)     /* Uppercase the file name. */
  149.       if (*i >= 'a' && *i <= 'z') *i ^= 040;
  150.     write(ofd,filnam,oc);        /* Write the file name in the file. */
  151. #ifdef MSDOS
  152.     write(ofd,"\r\n",2);
  153. #else
  154.     write(ofd,"\n",1);
  155. #endif /* MSDOS */
  156.     maxsize = DATALEN - 8;  /* 4 bytes (last triplet) + twice ~0 */
  157.     rpt = 0;                /* Zero the repeat count. */
  158.     oc = nc = 0;            /* Output & input character counts. */
  159.     otot = 1;                /* Start with first char of triplet. */
  160.     while (getbuf() > 0) {        /* While not EOF, get a packet. */
  161. #ifdef MSDOS
  162.     packet[size++] = '\r';          /* Explicit CRLF for DOS */
  163. #endif /* MSDOS */
  164.     packet[size++] = '\n';
  165.     packet[size] = '\0';
  166.     oc += size;            /* Count output record size. */
  167.     write(ofd,packet,size);     /* Write the record to the file. */
  168. #ifdef DEBUG
  169.         printf("%d: %s",size,packet);   /* Print on the screen for testing. */
  170. #endif /* DEBUG */
  171.     }
  172.     close(fd);                /* Close the files neatly */
  173.     close(ofd);
  174. }
  175.  
  176. /*
  177.    G E T B U F -- Do one record.
  178. */
  179.  
  180. getbuf() {                /* Fill one record buffer. */
  181.     if (eoflag != 0) return(-1);    /* If at the end of file, stop. */
  182.     size = 0;                /* Current position in record. */
  183.     while((t = getch()) >= 0) {        /* t == -1 means EOF. */
  184.     nc++;                /* Count the character. */
  185.     process(t);            /* Process the character. */
  186.     if (size >= maxsize) {        /* If the packet is full, */
  187.         return(size);
  188.     }
  189.     }
  190.     eoflag = -1;            /* Say we hit the end of the file. */
  191.  
  192.     if (otot == 3) {            /* Only one left in triplet?  Add ~0 */
  193.     process(0);            /* Pad the triplet with null */
  194.     packet[size++] = rptq;        /* Put in null repeat char and */
  195.     packet[size++] = tochar(0);    /* indicate one trailing null */
  196.     } else {
  197.     process(0);             /* Clean out any remaining chars. */
  198.     process(0);
  199.     process(' ');
  200.     packet[size++] = rptq;        /* Put in null repeat char and */
  201.     packet[size++] = tochar(0);    /* indicate two trailing nulls */
  202.     packet[size++] = rptq;
  203.     packet[size++] = tochar(0);
  204.     }
  205.     return(size);
  206. }
  207.  
  208. /* P R O C E S S -- Do one character. */
  209.  
  210. process(a) char a; {
  211.     if (otot == 1) {            /* Is this the first of three chars? */
  212.     if (a == 0) {            /* Is it a null? */
  213.         if (++rpt < 78)        /* Below max nulls, just count. */
  214.         return;
  215.         else if (rpt == 78) {     /* Reached max number, must output. */
  216.         packet[size++] = rptq;    /* Put in null repeat char and */
  217.         packet[size++] = tochar(rpt); /* number of nulls. */
  218.         packet[size] = '\0';
  219.         rpt = 0;
  220.         return;
  221.         }
  222.     } else {
  223.         if (rpt == 1) {        /* Just one null? */
  224.         one = 0;        /* Say the first char was a null. */
  225.         two = a;        /* This char is the second one. */
  226.         otot = 3;        /* Look for the third char. */
  227.         rpt = 0;        /* Restart null count. */
  228.         return;
  229.         }
  230.         if (rpt > 1) {        /* Some number of nulls? */
  231.         packet[size++] = rptq;    /* Insert the repeat prefix */
  232.         packet[size++] = tochar(rpt); /* and count. */
  233.         packet[size] = '\0';
  234.         rpt = 0;        /* Reset repeat counter. */
  235.         }
  236.         one = a;            /* Set first character. */
  237.         otot = 2;            /* Say we are at the second char. */
  238.     }
  239.     } else if (otot == 2) {
  240.     two = a;            /* Set second character. */
  241.     otot = 3;            /* Say we are at the third char. */
  242.     } else {
  243.     three = a;
  244.     otot = 1;            /* Start over at one. */
  245.     pack(one,two,three);        /* Pack in the three characters. */
  246.     }
  247. }
  248.  
  249. /* This routine does the actual three character to four character encoding.
  250.  * The concept is relatively straight forward.    The first output character
  251.  * consists of the first (high order or most significant) six bits of the
  252.  * first input character.  The second output character is made from the
  253.  * remaining two low order bits of the first input character and the first
  254.  * four high order bits of the second input character.    The third output
  255.  * character is built from the last four low order bits of the second input
  256.  * character and the two high order bits of the third input character.    The
  257.  * fourth and last output character consists of the six low order bit of
  258.  * the third input character.  In this way the three eight bit input char-
  259.  * acters (for a total of 24 bits) are divided into four six bit output
  260.  * characters (also for a total of 24 bits).  In order to make the four
  261.  * output characters printable an ASCII zero is then added to each of them.
  262.  */
  263. pack(x,y,z) char x,y,z; {
  264.     packet[size++] = tochar((x >> 2) & 077);
  265.     packet[size++] = tochar(((x & 003) << 4) | ((y >> 4) & 017));
  266.     packet[size++] = tochar(((y & 017) << 2) | ((z >> 6) & 003));
  267.     packet[size++] = tochar(z & 077);
  268.     packet[size] = '\0';
  269. }
  270.  
  271. int
  272. getch() {                 /* Get next (or pushed) char. */
  273. #ifndef BSIZE
  274. #define BSIZE 500
  275. #endif
  276.     static int index = 0, count = 0;
  277.     static char buf[BSIZE];
  278.  
  279.     if (count == 0) {
  280.     count = read(fd,buf,BSIZE);
  281.     if (count <= 0) return(-1);
  282.     index = 0;
  283.     }
  284.     count--;
  285.     return(buf[index++]&0xff);
  286. }
  287.  
  288. /* Usage message */
  289.  
  290. usage() {
  291.     fprintf(stderr,"usage: msbmkb inputfile outputfile\n");
  292.     exit(1);
  293. }
  294.