home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / unix / xbinold.sha / xbin.c < prev    next >
C/C++ Source or Header  |  1985-03-28  |  16KB  |  867 lines

  1. #ifndef lint
  2. static char version[] = "xbin.c Version 2.1 03/26/85";
  3. #endif lint
  4.  
  5. #include <stdio.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <sys/dir.h>
  9.  
  10. #ifdef MAXNAMLEN    /* 4.2 BSD */
  11. #define FNAMELEN MAXNAMLEN
  12. #else
  13. #define FNAMELEN DIRSIZ
  14. #endif
  15.  
  16. #ifdef BSD
  17. #include <sys/time.h>
  18. #include <sys/timeb.h>
  19. #define search_last rindex
  20. extern char *rindex();
  21. #else
  22. #include <time.h>
  23. extern long timezone;
  24. #define search_last strrchr
  25. extern char *strrchr();
  26. #endif
  27.  
  28. /* Mac time of 00:00:00 GMT, Jan 1, 1970 */
  29. #define TIMEDIFF 0x7c25b080
  30.  
  31. #define DATABYTES 128
  32.  
  33. #define BYTEMASK 0xff
  34. #define BYTEBIT 0x100
  35. #define WORDMASK 0xffff
  36. #define WORDBIT 0x10000
  37.  
  38. #define NAMEBYTES 63
  39. #define H_NLENOFF 1
  40. #define H_NAMEOFF 2
  41.  
  42. /* 65 <-> 80 is the FInfo structure */
  43. #define H_TYPEOFF 65
  44. #define H_AUTHOFF 69
  45. #define H_FLAGOFF 73
  46.  
  47. #define H_LOCKOFF 81
  48. #define H_DLENOFF 83
  49. #define H_RLENOFF 87
  50. #define H_CTIMOFF 91
  51. #define H_MTIMOFF 95
  52.  
  53. #define H_OLD_DLENOFF 81
  54. #define H_OLD_RLENOFF 85
  55.  
  56. #define F_BUNDLE 0x2000
  57. #define F_LOCKED 0x8000
  58.  
  59. struct macheader {
  60.     char m_name[NAMEBYTES+1];
  61.     char m_type[4];
  62.     char m_author[4];
  63.     short m_flags;
  64.     long m_datalen;
  65.     long m_rsrclen;
  66.     long m_createtime;
  67.     long m_modifytime;
  68. } mh;
  69.  
  70. struct filenames {
  71.     char f_info[256];
  72.     char f_data[256];
  73.     char f_rsrc[256];
  74. } files;
  75.  
  76. int pre_beta;    /* options */
  77. int listmode;
  78. int verbose;
  79.  
  80. int compressed;    /* state variables */
  81. int qformat;
  82. FILE *ifp;
  83.  
  84. /*
  85.  * xbin -- unpack BinHex format file into suitable
  86.  * format for downloading with macput
  87.  * Dave Johnson, Brown University Computer Science
  88.  *
  89.  * checksum code by Darin Adler, TMQ Software
  90.  *
  91.  * (c) 1984 Brown University 
  92.  * may be used but not sold without permission
  93.  *
  94.  * created ddj 12/16/84 
  95.  * revised ddj 03/10/85 -- version 4.0 compatibility, other minor mods
  96.  * revised ddj 03/11/85 -- strip LOCKED bit from m_flags
  97.  * revised ahm 03/12/85 -- System V compatibility
  98.  * revised dba 03/16/85 -- 4.0 EOF fixed, 4.0 checksum added
  99.  * revised ddj 03/17/85 -- extend new features to older formats: -l, stdin
  100.  * revised ddj 03/24/85 -- check for filename truncation, allow multiple files
  101.  * revised ddj 03/26/85 -- fixed USG botches, many problems w/multiple files
  102.  */
  103. char usage[] = "usage: \"xbin [-v] [-l] [-o] [-n name] [-] filename\"\n";
  104.  
  105. main(ac, av)
  106. char **av;
  107. {
  108.     char *filename, *macname;
  109.  
  110.     filename = ""; macname = "";
  111.     ac--; av++;
  112.     while (ac) {
  113.         if (av[0][0] == '-') {
  114.             switch (av[0][1]) {
  115.             case '\0':
  116.                 filename = "-";
  117.                 break;
  118.             case 'v':
  119.                 verbose++;
  120.                 break;
  121.             case 'l':
  122.                 listmode++;
  123.                 break;
  124.             case 'o':
  125.                 pre_beta++;
  126.                 break;
  127.             case 'n':
  128.                 if (ac > 1) {
  129.                     ac--; av++;
  130.                     macname = av[0];
  131.                     filename = "";
  132.                     break;
  133.                 }
  134.                 else
  135.                     goto bad_usage;
  136.             default:
  137.                 goto bad_usage;
  138.             }
  139.         }
  140.         else
  141.             filename = av[0];
  142.         if (filename[0] != '\0') {
  143.             setup_files(filename, macname);
  144.             if (listmode) {
  145.                 print_header();
  146.             }
  147.             else {
  148.                 process_forks();
  149.                 /* now that we know the size of the forks */
  150.                 forge_info();
  151.             }
  152.             if (ifp != stdin)
  153.                 fclose(ifp);
  154.             macname = "";
  155.             ifp = NULL;        /* reset state */
  156.             qformat = 0;
  157.             compressed = 0;
  158.         }
  159.         ac--; av++;
  160.     }
  161.     if (*filename == '\0') {
  162. bad_usage:
  163.         fprintf(stderr, usage);
  164.         exit(1);
  165.     }
  166. }
  167.  
  168. static char *extensions[] = {
  169.     ".hqx",
  170.     ".hcx",
  171.     ".hex",
  172.     "",
  173.     NULL
  174. };
  175.  
  176. setup_files(filename, macname)
  177. char *filename;        /* input file name -- extension optional */
  178. char *macname;        /* name to use on the mac side of things */
  179. {
  180.     char namebuf[256], *np;
  181.     char **ep;
  182.     int n;
  183.     struct stat stbuf;
  184.     long curtime;
  185.  
  186.     if (filename[0] == '-') {
  187.         ifp = stdin;
  188.         filename = "stdin";
  189.     }
  190.     else {
  191.         /* find input file and open it */
  192.         for (ep = extensions; *ep != NULL; ep++) {
  193.             sprintf(namebuf, "%s%s", filename, *ep);
  194.             if (stat(namebuf, &stbuf) == 0)
  195.                 break;
  196.         }
  197.         if (*ep == NULL) {
  198.             perror(namebuf);
  199.             exit(-1);
  200.         }
  201.         ifp = fopen(namebuf, "r");
  202.         if (ifp == NULL) {
  203.             perror(namebuf);
  204.             exit(-1);
  205.         }
  206.     }
  207.     if (ifp == stdin) {
  208.         curtime = time(0);
  209.         mh.m_createtime = curtime;
  210.         mh.m_modifytime = curtime;
  211.     }
  212.     else {
  213.         mh.m_createtime = stbuf.st_mtime;
  214.         mh.m_modifytime = stbuf.st_mtime;
  215.     }
  216.     if (listmode || verbose) {
  217.         fprintf(stderr, "%s %s%s",
  218.             listmode ? "\nListing" : "Converting",
  219.             namebuf, listmode ? ":\n" : " ");
  220.     }
  221.  
  222.     qformat = find_header(); /* eat mailer header &cetera, intuit format */
  223.  
  224.     if (qformat)
  225.         do_q_header(macname);
  226.     else
  227.         do_o_header(macname, filename);
  228.  
  229.     /* make sure host file name doesn't get truncated beyond recognition */
  230.     n = strlen(mh.m_name);
  231.     if (n > FNAMELEN - 2)
  232.         n = FNAMELEN - 2;
  233.     strncpy(namebuf, mh.m_name, n);
  234.     namebuf[n] = '\0';
  235.  
  236.     /* get rid of troublesome characters */
  237.     for (np = namebuf; *np; np++)
  238.         if (*np == ' ' || *np == '/')
  239.             *np = '_';
  240.  
  241.     sprintf(files.f_data, "%s.data", namebuf);
  242.     sprintf(files.f_rsrc, "%s.rsrc", namebuf);
  243.     sprintf(files.f_info, "%s.info", namebuf);
  244.     if (verbose)
  245.         fprintf(stderr, "==> %s.{info,data,rsrc}\n", namebuf);
  246. }
  247.  
  248. /* print out header information in human-readable format */
  249. print_header()
  250. {
  251.     char *ctime();
  252.  
  253.     printf("macname: %s\n", mh.m_name);
  254.     printf("filetype: %.4s, ", mh.m_type);
  255.     printf("author: %.4s, ", mh.m_author);
  256.     printf("flags: 0x%x\n", mh.m_flags);
  257.     if (qformat) {
  258.         printf("data length: %d, ", mh.m_datalen);
  259.         printf("rsrc length: %d\n", mh.m_rsrclen);
  260.     }
  261.     if (!pre_beta) {
  262.         printf("create time: %s", ctime(&mh.m_createtime));
  263.     }
  264. }
  265.  
  266. process_forks()
  267. {
  268.     if (qformat) {
  269.         /* read data and resource forks of .hqx file */
  270.         do_q_fork(files.f_data, mh.m_datalen);
  271.         do_q_fork(files.f_rsrc, mh.m_rsrclen);
  272.     }
  273.     else
  274.         do_o_forks();
  275. }
  276.  
  277. /* write out .info file from information in the mh structure */
  278. forge_info()
  279. {
  280.     static char buf[DATABYTES];
  281.     char *np;
  282.     FILE *fp;
  283.     int n, tdiff;
  284.     struct tm *tp;
  285. #ifdef BSD
  286.     struct timeb tbuf;
  287. #else
  288.     long bs;
  289. #endif
  290.  
  291.     for (np = mh.m_name; *np; np++)
  292.         if (*np == '_') *np = ' ';
  293.  
  294.     buf[H_NLENOFF] = n = np - mh.m_name;
  295.     strncpy(buf + H_NAMEOFF, mh.m_name, n);
  296.     strncpy(buf + H_TYPEOFF, mh.m_type, 4);
  297.     strncpy(buf + H_AUTHOFF, mh.m_author, 4);
  298.     put2(buf + H_FLAGOFF, mh.m_flags & ~F_LOCKED);
  299.     if (pre_beta) {
  300.         put4(buf + H_OLD_DLENOFF, mh.m_datalen);
  301.         put4(buf + H_OLD_RLENOFF, mh.m_rsrclen);
  302.     }
  303.     else {
  304.         put4(buf + H_DLENOFF, mh.m_datalen);
  305.         put4(buf + H_RLENOFF, mh.m_rsrclen);
  306.  
  307.         /* convert unix file time to mac time format */
  308. #ifdef BSD
  309.         ftime(&tbuf);
  310.         tp = localtime(&tbuf.time);
  311.         tdiff = TIMEDIFF - tbuf.timezone * 60;
  312.         if (tp->tm_isdst)
  313.             tdiff += 60 * 60;
  314. #else
  315.         /* I hope this is right! -andy */
  316.         time(&bs);
  317.         tp = localtime(&bs);
  318.         tdiff = TIMEDIFF - timezone;
  319.         if (tp->tm_isdst)
  320.             tdiff += 60 * 60;
  321. #endif
  322.         put4(buf + H_CTIMOFF, mh.m_createtime + tdiff);
  323.         put4(buf + H_MTIMOFF, mh.m_modifytime + tdiff);
  324.     }
  325.     fp = fopen(files.f_info, "w");
  326.     if (fp == NULL) {
  327.         perror("info file");
  328.         exit(-1);
  329.     }
  330.     fwrite(buf, 1, DATABYTES, fp);
  331.     fclose(fp);
  332. }
  333.  
  334. /* eat characters until header detected, return which format */ 
  335. find_header()
  336. {
  337.     int c, n, at_bol;
  338.     char ibuf[BUFSIZ];
  339.  
  340.     /* look for "(This file ...)" line */
  341.     while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
  342.         if (strncmp(ibuf, "(This file", 10) == 0)
  343.             break;
  344.     }
  345.     at_bol = 1;
  346.     while ((c = getc(ifp)) != EOF) {
  347.         switch (c) {
  348.         case '\n':
  349.         case '\r':
  350.             at_bol = 1;
  351.             break;
  352.         case ':':
  353.             if (at_bol)    /* q format */
  354.                 return 1;
  355.             break;
  356.         case '#':
  357.             if (at_bol) {    /* old format */
  358.                 ungetc(c, ifp);
  359.                 return 0;
  360.             }
  361.             break;
  362.         default:
  363.             at_bol = 0;
  364.             break;
  365.         }
  366.     }
  367.  
  368.     fprintf(stderr, "unexpected EOF\n");
  369.     exit(2);
  370. }
  371.  
  372. static unsigned int crc;
  373.  
  374. short get2q();
  375. long get4q();
  376.  
  377. /* read header of .hqx file */
  378. do_q_header(macname)
  379. char *macname;
  380. {
  381.     char namebuf[256];        /* big enough for both att & bsd */
  382.     int n;
  383.     int calc_crc, file_crc;
  384.  
  385.     crc = 0;            /* compute a crc for the header */
  386.     q_init();            /* reset static variables */
  387.  
  388.     n = getq();            /* namelength */
  389.     n++;                /* must read trailing null also */
  390.     getqbuf(namebuf, n);        /* read name */
  391.     if (macname[0] == '\0')
  392.         macname = namebuf;
  393.  
  394.     n = strlen(macname);
  395.     if (n > NAMEBYTES)
  396.         n = NAMEBYTES;
  397.     strncpy(mh.m_name, macname, n);
  398.     mh.m_name[n] = '\0';
  399.  
  400.     getqbuf(mh.m_type, 4);
  401.     getqbuf(mh.m_author, 4);
  402.     mh.m_flags = get2q();
  403.     mh.m_datalen = get4q();
  404.     mh.m_rsrclen = get4q();
  405.  
  406.     comp_q_crc(0);
  407.     comp_q_crc(0);
  408.     calc_crc = crc;
  409.     file_crc = get2q();
  410.     verify_crc(calc_crc, file_crc);
  411. }
  412.  
  413. do_q_fork(fname, len)
  414. char *fname;
  415. register int len;
  416. {
  417.     FILE *outf;
  418.     register int c, i;
  419.     int calc_crc, file_crc;
  420.  
  421.     outf = fopen(fname, "w");
  422.     if (outf == NULL) {
  423.         perror(fname);
  424.         exit(-1);
  425.     }
  426.  
  427.     crc = 0;    /* compute a crc for a fork */
  428.  
  429.     if (len)
  430.         for (i = 0; i < len; i++) {
  431.             if ((c = getq()) == EOF) {
  432.                 fprintf(stderr, "unexpected EOF\n");
  433.                 exit(2);
  434.             }
  435.             putc(c, outf);
  436.         }
  437.  
  438.     comp_q_crc(0);
  439.     comp_q_crc(0);
  440.     calc_crc = crc;
  441.     file_crc = get2q();
  442.     verify_crc(calc_crc, file_crc);
  443.     fclose(outf);
  444. }
  445.  
  446. /* verify_crc(); -- check if crc's check out */
  447. verify_crc(calc_crc, file_crc)
  448. unsigned int calc_crc, file_crc;
  449. {
  450.     calc_crc &= WORDMASK;
  451.     file_crc &= WORDMASK;
  452.  
  453.     if (calc_crc != file_crc) {
  454.         fprintf(stderr, "CRC error\n---------\n");
  455.         fprintf(stderr, "CRC in file:\t0x%x\n", file_crc);
  456.         fprintf(stderr, "calculated CRC:\t0x%x\n", calc_crc);
  457.         exit(3);
  458.     }
  459. }
  460.  
  461. static int eof;
  462. static char obuf[3];
  463. static char *op, *oend;
  464.  
  465. /* initialize static variables for q format input */
  466. q_init()
  467. {
  468.     eof = 0;
  469.     op = obuf;
  470.     oend = obuf + sizeof obuf;
  471. }
  472.  
  473. /* get2q(); q format -- read 2 bytes from input, return short */
  474. short
  475. get2q()
  476. {
  477.     register int c;
  478.     short value = 0;
  479.  
  480.     c = getq();
  481.     value = (c & BYTEMASK) << 8;
  482.     c = getq();
  483.     value |= (c & BYTEMASK);
  484.  
  485.     return value;
  486. }
  487.  
  488. /* get4q(); q format -- read 4 bytes from input, return long */
  489. long
  490. get4q()
  491. {
  492.     register int c, i;
  493.     long value = 0;
  494.  
  495.     for (i = 0; i < 4; i++) {
  496.         c = getq();
  497.         value <<= 8;
  498.         value |= (c & BYTEMASK);
  499.     }
  500.     return value;
  501. }
  502.  
  503. /* getqbuf(); q format -- read n characters from input into buf */
  504. /*        All or nothing -- no partial buffer allowed */
  505. getqbuf(buf, n)
  506. register char *buf;
  507. register int n;
  508. {
  509.     register int c, i;
  510.     
  511.     for (i = 0; i < n; i++) {
  512.         if ((c = getq()) == EOF)
  513.             return EOF;
  514.         *buf++ = c;
  515.     }
  516.     return 0;
  517. }
  518.  
  519. #define RUNCHAR 0x90
  520.  
  521. /* q format -- return one byte per call, keeping track of run codes */
  522. getq()
  523. {
  524.     register int c;
  525.  
  526.     if ((c = getq_nocrc()) == EOF)
  527.         return EOF;
  528.     comp_q_crc(c);
  529.     return c;
  530. }
  531.  
  532. getq_nocrc()
  533. {
  534.     static int rep, lastc;
  535.     int c;
  536.  
  537.     if (rep) {
  538.         rep--;
  539.         return lastc;
  540.     }
  541.     if ((c = getq_raw()) == EOF) {
  542.         return EOF;
  543.         }
  544.     if (c == RUNCHAR) {
  545.         if ((rep = getq_raw()) == EOF)
  546.             return EOF;
  547.         if (rep == 0) {
  548.             return RUNCHAR;
  549.         }
  550.         else {
  551.             /* already returned one, about to return another */
  552.             rep -= 2;
  553.             return lastc;
  554.         }
  555.     }
  556.     else {
  557.         lastc = c;
  558.         return c;
  559.     }
  560. }
  561.  
  562. /* q format -- return next 8 bits from file without interpreting run codes */
  563. getq_raw()
  564. {
  565.     char ibuf[4];
  566.     register char *ip = ibuf, *iend = ibuf + sizeof ibuf;
  567.     int c;
  568.  
  569.     if (op == obuf) {
  570.         for (ip = ibuf; ip < iend; ip++) {
  571.             if ((c = get6bits()) == EOF)
  572.                 if (ip <= &ibuf[1])
  573.                     return EOF;
  574.                 else if (ip == &ibuf[2])
  575.                     eof = 1;
  576.                 else
  577.                     eof = 2;
  578.             *ip = c;
  579.         }
  580.         obuf[0] = (ibuf[0] << 2 | ibuf[1] >> 4);
  581.         obuf[1] = (ibuf[1] << 4 | ibuf[2] >> 2);
  582.         obuf[2] = (ibuf[2] << 6 | ibuf[3]);
  583.     }
  584.     if ((eof) & (op >= &obuf[eof]))
  585.         return EOF;
  586.     c = *op++;
  587.     if (op >= oend)
  588.         op = obuf;
  589.     return (c & BYTEMASK);
  590. }
  591.  
  592. char tr[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
  593.  
  594. /* q format -- decode one byte into 6 bit binary */
  595. get6bits()
  596. {
  597.     register int c;
  598.     register char *where;
  599.  
  600.     while (1) {
  601.         c = getc(ifp);
  602.         switch (c) {
  603.         case '\n':
  604.         case '\r':
  605.             continue;
  606.         case ':':
  607.         case EOF:
  608.             return EOF;
  609.         default:
  610.             where = tr;
  611.             while (*where != '\0' && *where != c) 
  612.                 where++;
  613.             if (*where == c)
  614.                 return (where - tr);
  615.             else {
  616.                 fprintf(stderr, "bad char\n");
  617.                 return EOF;
  618.             }
  619.         }
  620.     }
  621. }
  622.  
  623. #define CRCCONSTANT 0x1021
  624.  
  625. comp_q_crc(c)
  626. register unsigned int c;
  627. {
  628.     register int i;
  629.     register unsigned int temp = crc;
  630.  
  631.     for (i=0; i<8; i++) {
  632.         c <<= 1;
  633.         if ((temp <<= 1) & WORDBIT)
  634.             temp = (temp & WORDMASK) ^ CRCCONSTANT;
  635.         temp ^= (c >> 8);
  636.         c &= BYTEMASK;
  637.     }
  638.     crc = temp;
  639. }
  640.  
  641. /* old format -- process .hex and .hcx files */
  642. do_o_header(macname, filename)
  643. char *macname, *filename;
  644. {
  645.     char namebuf[256];        /* big enough for both att & bsd */
  646.     char ibuf[BUFSIZ];
  647.     int n;
  648.  
  649.     /* set up name for output files */
  650.     if (macname[0] == '\0') {
  651.         strcpy(namebuf, filename);
  652.  
  653.         /* strip directories */
  654.         macname = search_last(namebuf, '/');
  655.         if (macname == NULL)
  656.             macname = namebuf;
  657.         else
  658.             macname++;
  659.  
  660.         /* strip extension */
  661.         n = strlen(macname);
  662.         if (n > 4) {
  663.             n -= 4;
  664.             if (macname[n] == '.' && macname[n+1] == 'h'
  665.                         && macname[n+3] == 'x')
  666.                 macname[n] = '\0';
  667.         }
  668.     }
  669.     n = strlen(macname);
  670.     if (n > NAMEBYTES)
  671.         n = NAMEBYTES;
  672.     strncpy(mh.m_name, macname, n);
  673.     mh.m_name[n] = '\0';
  674.  
  675.     /* read "#TYPEAUTH$flag"  line */
  676.     if (fgets(ibuf, BUFSIZ, ifp) == NULL) {
  677.         fprintf(stderr, "unexpected EOF\n");
  678.         exit(2);
  679.     }
  680.     n = strlen(ibuf);
  681.     if (n >= 7 && ibuf[0] == '#' && ibuf[n-6] == '$') {
  682.         if (n >= 11) 
  683.             strncpy(mh.m_type, &ibuf[1], 4);
  684.         if (n >= 15)
  685.             strncpy(mh.m_author, &ibuf[5], 4);
  686.         sscanf(&ibuf[n-5], "%4hx", &mh.m_flags);
  687.     }
  688. }
  689.  
  690. do_o_forks()
  691. {
  692.     char ibuf[BUFSIZ];
  693.     int forks = 0, found_crc = 0;
  694.     int calc_crc, file_crc;
  695.     int n;
  696.  
  697.     crc = 0;    /* calculate a crc for both forks */
  698.  
  699.     /* create empty files ahead of time */
  700.     close(creat(files.f_data, 0666));
  701.     close(creat(files.f_rsrc, 0666));
  702.  
  703.     while (!found_crc && fgets(ibuf, BUFSIZ, ifp) != NULL) {
  704.         if (forks == 0 && strncmp(ibuf, "***COMPRESSED", 13) == 0) {
  705.             compressed++;
  706.             continue;
  707.         }
  708.         if (strncmp(ibuf, "***DATA", 7) == 0) {
  709.             mh.m_datalen = make_file(files.f_data, compressed);
  710.             forks++;
  711.             continue;
  712.         }
  713.         if (strncmp(ibuf, "***RESOURCE", 11) == 0) {
  714.             mh.m_rsrclen = make_file(files.f_rsrc, compressed);
  715.             forks++;
  716.             continue;
  717.         }
  718.         if (compressed && strncmp(ibuf, "***CRC:", 7) == 0) {
  719.             found_crc++;
  720.             calc_crc = crc;
  721.             sscanf(&ibuf[7], "%x", &file_crc);
  722.             break;
  723.         }
  724.         if (!compressed && strncmp(ibuf, "***CHECKSUM:", 12) == 0) {
  725.             found_crc++;
  726.             calc_crc = crc & BYTEMASK;
  727.             sscanf(&ibuf[12], "%x", &file_crc);
  728.             file_crc &= BYTEMASK;
  729.             break;
  730.         }
  731.     }
  732.  
  733.     if (found_crc)
  734.         verify_crc(calc_crc, file_crc);
  735.     else {
  736.         fprintf(stderr, "missing CRC\n");
  737.         exit(3);
  738.     }
  739. }
  740.  
  741. make_file(fname, compressed)
  742. char *fname;
  743. int compressed;
  744. {
  745.     register int n;
  746.     char ibuf[BUFSIZ];
  747.     FILE *outf;
  748.     int nbytes = 0;
  749.  
  750.     outf = fopen(fname, "w");
  751.     if (outf == NULL) {
  752.         perror(fname);
  753.         exit(-1);
  754.     }
  755.  
  756.     while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
  757.         if (strncmp(ibuf, "***END", 6) == 0)
  758.             break;
  759.         if (compressed)
  760.             nbytes += comp_to_bin(ibuf, outf);
  761.         else
  762.             nbytes += hex_to_bin(ibuf, outf);
  763.     }
  764.  
  765.     fclose(outf);
  766.     return nbytes;
  767. }
  768.  
  769. comp_c_crc(c)
  770. unsigned char c;
  771. {
  772.     crc = (crc + c) & WORDMASK;
  773.     crc = ((crc << 3) & WORDMASK) | (crc >> 13);
  774. }
  775.  
  776. comp_e_crc(c)
  777. unsigned char c;
  778. {
  779.     crc += c;
  780. }
  781.  
  782. #define SIXB(c) (((c)-0x20) & 0x3f)
  783.  
  784. comp_to_bin(ibuf, outf)
  785. char ibuf[];
  786. FILE *outf;
  787. {
  788.     char obuf[BUFSIZ];
  789.     register char *ip = ibuf;
  790.     register char *op = obuf;
  791.     register int n, outcount;
  792.     int numread, incount;
  793.  
  794.     numread = strlen(ibuf);
  795.     ip[numread-1] = ' ';        /* zap out the newline */
  796.     outcount = (SIXB(ip[0]) << 2) | (SIXB(ip[1]) >> 4);
  797.     incount = ((outcount / 3) + 1) * 4;
  798.     for (n = numread; n < incount; n++)    /* restore lost spaces */
  799.         ibuf[n] = ' ';
  800.  
  801.     n = 0;
  802.     while (n <= outcount) {
  803.         *op++ = SIXB(ip[0]) << 2 | SIXB(ip[1]) >> 4;
  804.         *op++ = SIXB(ip[1]) << 4 | SIXB(ip[2]) >> 2;
  805.         *op++ = SIXB(ip[2]) << 6 | SIXB(ip[3]);
  806.         ip += 4;
  807.         n += 3;
  808.     }
  809.  
  810.     for (n=1; n <= outcount; n++)
  811.         comp_c_crc(obuf[n]);
  812.  
  813.     fwrite(obuf+1, 1, outcount, outf);
  814.     return outcount;
  815. }
  816.  
  817. hex_to_bin(ibuf, outf)
  818. char ibuf[];
  819. FILE *outf;
  820. {
  821.     register char *ip = ibuf;
  822.     register int n, outcount;
  823.     int c;
  824.  
  825.     n = strlen(ibuf) - 1;
  826.     outcount = n / 2;
  827.     for (n = 0; n < outcount; n++) {
  828.         c = hexit(*ip++);
  829.         comp_e_crc(c = (c << 4) | hexit(*ip++));
  830.         fputc(c, outf);
  831.     }
  832.     return outcount;
  833. }
  834.  
  835. hexit(c)
  836. int c;
  837. {
  838.     if ('0' <= c && c <= '9')
  839.         return c - '0';
  840.     if ('A' <= c && c <= 'F')
  841.         return c - 'A' + 10;
  842.  
  843.     fprintf(stderr, "illegal hex digit: %c", c);
  844.     exit(4);
  845. }
  846.  
  847. put2(bp, value)
  848. char *bp;
  849. short value;
  850. {
  851.     *bp++ = (value >> 8) & BYTEMASK;
  852.     *bp++ = value & BYTEMASK;
  853. }
  854.  
  855. put4(bp, value)
  856. char *bp;
  857. long value;
  858. {
  859.     register int i, c;
  860.  
  861.     for (i = 0; i < 4; i++) {
  862.         c = (value >> 24) & BYTEMASK;
  863.         value <<= 8;
  864.         *bp++ = c;
  865.     }
  866. }
  867.