home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / xbin23.zip / XBINUNIX.C < prev    next >
C/C++ Source or Header  |  1989-03-03  |  19KB  |  892 lines

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