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