home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / xbin21.zip / xbin.c < prev    next >
C/C++ Source or Header  |  1994-08-31  |  22KB  |  921 lines

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