home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 28 / amigaformatcd28.iso / -seriously_amiga- / archivers / mpackppc-wos / src / macbhex.c < prev    next >
C/C++ Source or Header  |  1998-04-27  |  9KB  |  311 lines

  1. /* macbhex.c -- simple binhex decoding routine */
  2. /* (C) Copyright 1993,1994 by Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  *
  5.  * Permission to use, copy, modify, distribute, and sell this software
  6.  * and its documentation for any purpose is hereby granted without
  7.  * fee, provided that the above copyright notice appear in all copies
  8.  * and that both that copyright notice and this permission notice
  9.  * appear in supporting documentation, and that the name of Carnegie
  10.  * Mellon University not be used in advertising or publicity
  11.  * pertaining to distribution of the software without specific,
  12.  * written prior permission.  Carnegie Mellon University makes no
  13.  * representations about the suitability of this software for any
  14.  * purpose.  It is provided "as is" without express or implied
  15.  * warranty.
  16.  *
  17.  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  18.  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  19.  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  20.  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  21.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  22.  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  23.  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  24.  * SOFTWARE.
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <ctype.h>
  29. #include <memory.h>
  30. #include "part.h"
  31. #include "macnapp.h"
  32. #include "macmpack.h"
  33.  
  34. /* from macos.c: */
  35. extern void renameDescFile(char *, short, long);
  36.  
  37. char binhex_decode[256] = {
  38.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  39.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  40.     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, -1, -1,
  41.     13, 14, 15, 16, 17, 18, 19, -1, 20, 21, -1, -1, -1, -1, -1, -1,
  42.     22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1,
  43.     37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, -1, -1, -1, -1,
  44.     48, 49, 50, 51, 52, 53, 54, -1, 55, 56, 57, 58, 59, 60, -1, -1,
  45.     61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  46.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  47.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  48.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  49.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  50.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  51.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  52.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  53.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  54. };
  55. #define BHEXVAL(c) (binhex_decode[(unsigned char) c])
  56.  
  57. typedef union {
  58.     unsigned char c[4];
  59.     unsigned long val;
  60. } longbuf;
  61.  
  62. typedef struct {
  63.     OSType type, creator;
  64.     unsigned short flags;
  65.     long dlen, rlen;
  66. } binhex_header;
  67.  
  68. #define STATE_START  0
  69. #define STATE_FNAME  1
  70. #define STATE_HEADER 2
  71. #define STATE_HCRC   3
  72. #define STATE_DFORK  4
  73. #define STATE_DCRC   5
  74. #define STATE_RFORK  6
  75. #define STATE_RCRC   7
  76. #define STATE_DONE   8
  77. #define STATE_ERROR  9
  78.  
  79. typedef struct binhex_state {
  80.     short state;            /* current state */
  81.     short part;                /* current part number */
  82.     unsigned short CRC;        /* cumulative CRC */
  83.     unsigned short fileCRC;    /* CRC value from file */
  84.     longbuf octetbuf;        /* buffer for decoded 6-bit values */
  85.     short octetin;            /* current input position in octetbuf */
  86.     short donepos;            /* ending position in octetbuf */
  87.     short inCRC;            /* flag set when reading a CRC */
  88.     long count;                /* generic counter */
  89.     FILE *outfile;            /* output file */
  90.     short marker;            /* flag indicating maker */
  91.     unsigned char rlebuf;    /* buffer for last run length encoding value */
  92.     PCstr namebuf[65];        /* buffer for binhex filename */
  93.     binhex_header head;        /* buffer for header */
  94.     FSSpec fspec;            /* output file */
  95. } binhex_state;
  96.  
  97. /* global state */
  98. static binhex_state bh;
  99.  
  100. /* process a binhex character
  101.  */
  102. static void binhex_process(struct part *inpart)
  103. {
  104.     unsigned short tmpcrc, cval;
  105.     unsigned char ctmp, c = bh.rlebuf;
  106.     StandardFileReply reply;
  107.     FInfo finfo;
  108.     char buf[256];
  109.     
  110.     /* do CRC */
  111.     ctmp = bh.inCRC ? c : 0;
  112.     cval = bh.CRC & 0xf000;
  113.     tmpcrc = ((unsigned short) (bh.CRC << 4) | (ctmp >> 4))
  114.             ^ (cval | (cval >> 7) | (cval >> 12));
  115.     cval = tmpcrc & 0xf000;
  116.     bh.CRC = ((unsigned short) (tmpcrc << 4) | (ctmp & 0x0f))
  117.             ^ (cval | (cval >> 7) | (cval >> 12));
  118.  
  119.     /* handle state */
  120.     switch (bh.state) {
  121.         case STATE_START:
  122.             bh.state = STATE_FNAME;
  123.             bh.count = 1;
  124.             *bh.namebuf = (c & 63);
  125.             break;
  126.         case STATE_FNAME:
  127.             bh.namebuf[bh.count] = c;
  128.             if (bh.count++ > *bh.namebuf) {
  129.                 bh.state = STATE_HEADER;
  130.                 bh.count = 0;
  131.             }
  132.             break;
  133.         case STATE_HEADER:
  134.             ((char *)&bh.head)[bh.count] = c;
  135.             if (++bh.count == 18) {
  136.                 bh.state = STATE_HCRC;
  137.                 bh.inCRC = 1;
  138.                 bh.count = 0;
  139.             }
  140.             break;
  141.         case STATE_DFORK:
  142.         case STATE_RFORK:
  143.             putc(c, bh.outfile);
  144.             if (--bh.count == 0) {
  145.                 fclose(bh.outfile);
  146.                 bh.outfile = NULL;
  147.                 ++bh.state;
  148.                 bh.inCRC = 1;
  149.             }
  150.             break;
  151.         case STATE_HCRC:
  152.         case STATE_DCRC:
  153.         case STATE_RCRC:
  154.             if (!bh.count++) {
  155.                 bh.fileCRC = (unsigned short) c << 8;
  156.             } else {
  157.                 if ((bh.fileCRC | c) != bh.CRC) {
  158.                     if (bh.state > STATE_HCRC) {
  159.                         HDelete(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name);
  160.                         SetCursor(&arrow);
  161.                         yell("BinHex file corrupted in transit");
  162.                         SetCursor(&watch);
  163.                     }
  164.                     bh.state = STATE_ERROR;
  165.                     break;
  166.                 }
  167.                 bh.CRC = 0;
  168.                 if (++bh.state == STATE_DONE) {
  169.                     finfo.fdType = bh.head.type;
  170.                     finfo.fdCreator = bh.head.creator;
  171.                     finfo.fdFlags = bh.head.flags & 0xf800;
  172.                     HSetFInfo(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name, &finfo);
  173.                     PtoCstr(bh.fspec.name);
  174.                     renameDescFile((char *)bh.fspec.name, bh.fspec.vRefNum, bh.fspec.parID);
  175.                     break;
  176.                 }
  177.                 bh.count = bh.head.rlen;
  178.                 if (bh.state == STATE_DFORK) {
  179.                     /* prompt user */
  180.                     sprintf(buf, "Saving BinHex file %s", C(bh.namebuf));
  181.                     chat(buf);
  182.                     SetCursor(&arrow);
  183.                     NAputFile("\pSave decoded BinHex file as:", P(bh.namebuf), &reply);
  184.                     SetCursor(&watch);
  185.                     statrefresh();
  186.                     if (!reply.sfGood) {
  187.                         didchat = -1;
  188.                         bh.state = STATE_ERROR;
  189.                     } else {
  190.                         bh.fspec = reply.sfFile;
  191.                         HCreate(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name,
  192.                             bh.head.creator, bh.head.type);
  193.                         bh.count = bh.head.dlen;
  194.                     }
  195.                 }
  196.                 if (bh.count) {
  197.                     bh.inCRC = 0;
  198.                     bh.outfile = Macopen(inpart->infile, bh.fspec.name, bh.fspec.vRefNum,
  199.                         bh.fspec.parID, 1, bh.state == STATE_DFORK ? 0 : 1, fsWrPerm);
  200.                     if (!bh.outfile) {
  201.                         bh.state = STATE_ERROR;
  202.                         HDelete(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name);
  203.                         SetCursor(&arrow);
  204.                         yell("Failed to open file for writing");
  205.                         SetCursor(&watch);
  206.                     }
  207.                 } else {
  208.                     ++bh.state;
  209.                 }
  210.             }
  211.             break;
  212.     }
  213. }
  214.  
  215. /*
  216.  * decode a binhex file
  217.  *  returns -1 on fatal error, 0 for continue, 1 for done
  218.  */
  219. int os_binhex(struct part *inpart, int part, int nparts)
  220. {
  221.     long val;
  222.     int c;
  223.     char *bptr;
  224.     short octetpos;
  225.     static char buf[1024];
  226.     
  227.     /* reset state */
  228.     if (part == 1) {
  229.         bh.state = STATE_START;
  230.         bh.part = 0;
  231.         bh.CRC = 0;
  232.         bh.octetbuf.val = 0;
  233.         bh.octetin = 26;
  234.         bh.donepos = 3;
  235.         bh.inCRC = 0;
  236.         bh.outfile = NULL;
  237.         bh.marker = 0;
  238.     }
  239.     if (++bh.part != part) bh.state = STATE_ERROR;
  240.     
  241.     /* do nothing on error/completion */
  242.     if (!inpart) {
  243.         if (bh.state < STATE_DONE) bh.state = STATE_ERROR;
  244.     } else {
  245.         /* skip blank lines */
  246.         do {
  247.             if (part_gets(buf, sizeof (buf), inpart) == NULL) return (0);
  248.         } while (*buf == '\n');
  249.         bptr = buf;
  250.         if (part == 1 && *bptr++ != ':') bh.state = STATE_ERROR;
  251.         
  252.         /* line reading loop */
  253.         do {
  254.             /* check line for separator */
  255.             if (!strncmp(buf, "--- ", 4)) break;
  256.             buf[strlen(buf) - 1] = '\0';
  257.             
  258.             /* loop through line of binhex charaters */
  259.             while (bh.state < STATE_DONE) {
  260.                 /* fill in octetbuf */
  261.                 do {
  262.                     if ((val = BHEXVAL(*bptr++)) == -1) {
  263.                         if (bptr[-1]) {
  264.                             --bh.donepos;
  265.                             if (bh.octetin >= 14) --bh.donepos;
  266.                             if (bh.octetin >= 20) --bh.donepos;
  267.                         }
  268.                         break;
  269.                     }
  270.                     bh.octetbuf.val |= val << bh.octetin;
  271.                 } while ((bh.octetin -= 6) > 2);
  272.                 if (!bptr[-1]) break;
  273.                 
  274.                 /* handle decoded characters -- run length encoding (rle) detection */
  275.                 for (octetpos = 0; octetpos < bh.donepos; ++octetpos) {
  276.                     /* get character & handle rle */
  277.                     c = bh.octetbuf.c[octetpos];
  278.                     if (c == 0x90 && !bh.marker++) continue;
  279.                     if (bh.marker) {
  280.                         if (c == 0) {
  281.                             bh.rlebuf = 0x90;
  282.                             binhex_process(inpart);
  283.                         } else {
  284.                             while (--c > 0) {
  285.                                 binhex_process(inpart);
  286.                             }
  287.                         }
  288.                         bh.marker = 0;
  289.                     } else {
  290.                         bh.rlebuf = (unsigned char) c;
  291.                         binhex_process(inpart);
  292.                     }
  293.                     if (bh.state >= STATE_DONE) break;
  294.                 }
  295.                 if (bh.donepos < 3 && bh.state < STATE_DONE) bh.state = STATE_ERROR;
  296.                 bh.octetin = 26;
  297.                 bh.octetbuf.val = 0;
  298.             }
  299.         } while (bh.state < STATE_DONE && part_gets(bptr = buf, sizeof (buf), inpart) != NULL);
  300.     }
  301.     
  302.     /* error clean up */
  303.     if (bh.state == STATE_ERROR && bh.outfile) {
  304.         fclose(bh.outfile);
  305.         bh.outfile = NULL;
  306.         HDelete(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name);
  307.     }
  308.     
  309.     return (bh.state == STATE_ERROR ? 1 : 0);
  310. }
  311.