home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / xbin_25.shr / xbin.c < prev    next >
C/C++ Source or Header  |  1991-05-20  |  20KB  |  998 lines

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