home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / xbinWOS.lha / xbinppc / xbinunix.c < prev    next >
C/C++ Source or Header  |  1998-04-12  |  25KB  |  866 lines

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