[comp.sys.mac] Mass de-binhexing

ll12+@andrew.cmu.edu (Laura Ann Lemay) (05/08/89)

Hi.

I'm graduating from college soon (2 weeks!!!), and as a result, I've been
furiously FTP-ing everything in sight so I don't have to pay huge dial-up
fees after I graduate....

The problemis that after I spent acouple hours downloading and ftping, I
end upwith a couple hundred files that I need to debinhex.  I go into
Stuffit (or binhex, depending on my mood), select "decode file", select
the file, and wait a bit.  Then I do it again.
BOOORRRRING.

Doing this for a couple megs worth of files is UGLY.  Real ugly.  Major
ugly.  Getting the init that freezes the SFthingy to the current place helped,
but not much.

What I need is some sort of simple utilitiy that will take a folder of files
and massively de-binhex them.  Errors would be recorded, so I could go back
afterwards and fix the files that went bad, but otherwise everything would
just be automates.

Anyone know of any utility like this?  Anyone want to write one?  :-)
And while you're at it, a mass unstuffit would be nice, too, since stuffit
is the de facto utility now for downloading files....


thanx --

Laura Lemay


ll12+@andrew.cmu.edu

bskendig@phoenix.Princeton.EDU (Brian Scott Kendig) (05/09/89)

Having to break apart downloaded files is a real drag.  Especially when
there are a LOT of files to process.  As Laura Ann Lemay (ll12+@andrew.cmu.edu)
put it in article <wYNPz6y00WB44PDUoC@andrew.cmu.edu>,
>The problem is that after I spent a couple hours downloading and ftping, I
>end up with a couple hundred files that I need to debinhex.  I go into
>Stuffit (or binhex, depending on my mood), select "decode file", select
>the file, and wait a bit.  Then I do it again.
>BOOORRRRING.
>
>Doing this for a couple megs worth of files is UGLY.  Real ugly.  Major
>ugly.  Getting the init that freezes the SFthingy to the current place helped,
>but not much.
>
>What I need is some sort of simple utility that will take a folder of files
>and massively de-binhex them.  Errors would be recorded, so I could go back
>afterwards and fix the files that went bad, but otherwise everything would
>just be automated.
>
>Anyone know of any utility like this?  Anyone want to write one?  :-)
>And while you're at it, a mass unstuffit would be nice, too, since stuffit
>is the de facto utility now for downloading files....

Laura, I know your dilemma.  Every now and then I go on a downloading spree,
when I transfer pretty much everything in sight to my machine.   Having to
deBinHex and unStuff each file is annoying at best, but I figure it's the price
I must pay to have so much great software literally at my fingertips.

However, one of these days, I'd like to download the entire set of PostScript
fonts from Sumex, but I've been putting it off because I don't particularly
relish the idea of having to prepare each of those files one-by-one for use.

I'll expand on the general request here: Does anyone know of any mass-deBinHex
or mass-unStuffIt utilities that exist for either the Mac or any Unix systems?
I can use my CMS system here to de-BinHex a file before I download it, making
it smaller and more quickly downloaded, but I hesitate to do that on each of
dozens of files at once manually.

And it would be REALLY nice if I could take a BinHexed, Stuffed file on my
Unix system and, in one fell swoop, download it to each of its constituent
files on my Mac, each file ready to go with no further action!  (Dream on...)

Any leads whatsoever are more than welcome!

     << Brian Kendig >>

syap@cc.rochester.edu (James Fitzwilliam) (05/09/89)

I asked about this some time ago and was directed to several utilites available
ftp on sumex, in the "unix" directory.  Some were more complete than others,
but I could not get any of them to correctly debinhex Stuffit files.  That is,
uncompressed files and files compressed with Packit would de-hqx correctly
online, but Stuffit files would turn out to be corrupt if I converted them
first and then downloaded them.  Your mileage may vary.

There is a mass-unstuff available, however.  If you select all of the files you
wish to decompress, and hold down the Shift key after opening them, Stuffit
will convert them all, and save all items from all files in the same folder
with the Stuffit application.

Having a multi-debinhex in Stuffit would be a dream come true.

James

syap@vera.cc.rochester.edu
...!rochester!vera!syap
GEnie: FITZWILLIAM

kenk@tellab5.tellabs.CHI.IL.US (Ken Konecki) (05/09/89)

This seems to be a pretty popular topic, especially recently. In light
of that, I sent off the following source code to comp.sources.mac
several (about 6 to be a tad more precise) weeks ago, but alas no
response was heard from the moderator and no posting ever showed up.
Since I am quite impatient by nature, I grew tired of waiting long ago
and so here is the source code for a wonderful little program called
mcvert. It is a mac<->unix file converter, and in my humble opinion
(IMHO for all you acronym junkies) it is the best one out there. It
was written by Doug Moore of Cornell (who gave me permission to post),
so comments should be directed to him (his address is in the shar
file). About the only thing it doesn't do for you is un-stuff stuffit
archives. Enjoy it, everybody.

--- Delete this line and everything above it -----
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# mcvert.c
# hqxify.c
# unpack.c
# mactypes.h
# Makefile
# mcvert.1
if test -f mcvert.c
then
echo shar: will not overwrite existing file " mcvert.c "
else
cat >mcvert.c <<'------ EOF ------'
/* mcvert.c - version 1.0 - March 30, 1989
 * Written by Doug Moore - Cornell University - moore@cs.cornell.edu - April '87
 * Sun bug fixes, assorted stuff - Jim Sasaki, March '89
 *
 * This program may be freely distributed for non-profit purposes.  It may not
 * be sold, by itself or as part of a collection of software.  It may be freely
 * modified as long as no modified version is distributed.  Modifications of
 * interest to all can be incorporated into the program by sending them to me
 * for distribution.  Parts of the code can be used in other programs.  I am not
 * responsible for any damage caused by this program.  I hope you enjoy it.
 */

#include "mactypes.h"

#define HQX 0
#define TEXT 1
#define DATA 2
#define RSRC 3
#define FORWARDS 0
#define BACKWARDS 1

FILE *verbose;
char **hqxnames, **hqxnames_left;
char *dir, *ext, *text_author;
char *maxlines_str;
int maxlines;

main(argc, argv)
int argc;
char **argv;
{   char *flags, *getenv();
    int direction, mode, unpit_flag;

    argv++;
    argc--;
    verbose = stderr;
    direction = FORWARDS;
    mode = HQX;
    unpit_flag = 0;

    if ((text_author = getenv("MAC_EDITOR"))    == NULL)    text_author = "MACA";
    if ((ext =         getenv("MAC_EXT"))       == NULL)    ext = ".bin";
    if ((dir =         getenv("MAC_DLOAD_DIR")) == NULL)    dir = ".";
    if ((maxlines_str = getenv("MAC_LINE_LIMIT")) == NULL)  maxlines = 2000;
    else										 maxlines = atoi(maxlines_str);
    
    /* Make command line arguments globally accessible */
    hqxnames = (char **) calloc(argc+1, sizeof(char *));
    hqxnames_left = hqxnames;
    while (argc--)  *hqxnames_left++ = *argv++;
    *hqxnames_left = "-";
    hqxnames_left = hqxnames;

    while (strcmp(*hqxnames_left, "-")) {
        if (hqxnames_left[0][0] == '-') {
            flags = *hqxnames_left++;
            while (*++flags)
                switch (*flags) {
                case 'x':
                    mode = HQX;
                    break;
                case 'u':
                    mode = TEXT;
                    break;
                case 'd':
                    mode = DATA;
                    break;
                case 'r':
                    mode = RSRC;
                    break;
                case 'D':
                    direction = FORWARDS;
                    break;
                case 'U':
                    direction = BACKWARDS;
                    break;
                case 'q':
                    unpit_flag = 0;
                    break;
                case 'p':
                    unpit_flag = 1;
                    break;
                case 's':
                    verbose = fopen("/dev/null", "w");
                    break;
                case 'v':
                    verbose = stderr;
                    break;
                default:
                    error(
                    "Usage: mcvert [ -[r|d|u|x] [D|U] [p|q] [s|v] ] filename...",
                    NULL);
                    }
            }

        if (direction == BACKWARDS)
            if (mode == HQX && unpit_flag) re_hqx();/* no re_pit() yet */
            else if (mode == HQX) re_hqx();
            else re_other(mode);
        else
            if (mode == HQX) un_hqx(unpit_flag);
            else un_other(mode);
        }
    }

/* An array useful for CRC calculations that use 0x1021 as the "seed" */
word magic[] = {
    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
    };

/* Report a fatal error */
error(msg, name)
char msg[], name[];
{   fprintf(stderr, msg, name);
    putc('\n', stderr);
    exit(1);
    }

/* replace illegal Unix characters in file name */
/* make sure host file name doesn't get truncated beyond recognition */
unixify(np)
register byte *np;
{   register ulong c;
    c = strlen(np);
    if (c > SYSNAMELEN - 4) c = SYSNAMELEN - 4;
    np[c] = '\0';
    np--;
    while (c = *++np)
        if (c <= ' ' || c == '/' || c > '~') *np = '_';
    }

/* Convert Unix time (GMT since 1-1-1970) to Mac
                                    time (local since 1-1-1904) */
#define MACTIMEDIFF 0x7c25b080 /* Mac time of 00:00:00 GMT, Jan 1, 1970 */

ulong time2mac(time)
ulong time;
{   struct timeb tp;
    ftime(&tp);
    return long2mac(time + MACTIMEDIFF
                    - 60 * (tp.timezone - 60 * tp.dstflag));
    }


/* This procedure copies the input file to the output file, basically, although
    in TEXT mode it changes LF's to CR's and in any mode it forges a Mac info 
    header.  Author type for TEXT mode can come from the MAC_EDITOR environ-
    ment variable if it is defined. */

un_other(mode)
int mode;
{   register ulong b;
    register ulong nchars;
    char txtfname[BINNAMELEN], binfname[BINNAMELEN];
    FILE *txtfile, *binfile; 
    char *suffix;
    struct stat stbuf;
    info_header info;
    int extra_chars;
    ulong dlen, rlen, mtim, ctim;

    if (mode == DATA) suffix = ".data";
    else if (mode == RSRC) suffix = ".rsrc";
    else suffix = ".text";

    while (hqxnames_left[0][0] != '-') {

        strcpy(txtfname, *hqxnames_left++);
        if (!(txtfile = fopen(txtfname, "r"))) {
            /* Maybe we are supposed to figure out the suffix ourselves? */
            strcat(txtfname, suffix);
            if (!(txtfile = fopen(txtfname, "r")))
                error("Cannot open %s", txtfname);
            }

        if (stat(txtfname, &stbuf))
            error("Cannot read %s", txtfname);

        /* stuff header data into the info header */
        bzero(&info, sizeof(info_header));
        info.nlen = strlen(txtfname);
        info.nlen = (info.nlen > NAMELEN) ? NAMELEN : info.nlen;
	info.name[info.nlen] = '\0';
        strcpy(info.name, txtfname);           /* name */
        mtim = time2mac(stbuf.st_mtime);
        ctim = time2mac(stbuf.st_ctime);
        bcopy(&mtim, info.mtim, 4);
        bcopy(&ctim, info.ctim, 4);

        if (mode == RSRC) {
            /* dlen is already zero */
            rlen = long2mac(stbuf.st_size);
            bcopy(&rlen, info.rlen, 4);
            bcopy("APPL", info.type, 4);
            bcopy("CCOM", info.auth, 4);
            }
        else {
            dlen = long2mac(stbuf.st_size);
            bcopy(&dlen, info.dlen, 4);
            /* rlen is already zero */
            bcopy("TEXT", info.type, 4);
            if (mode == DATA) bcopy("????", info.auth, 4);
            else bcopy(text_author, info.auth, 4);
            }

        /* Create the .bin file and write the info to it */
        sprintf(binfname, "%s/%s%s", dir, txtfname, ext);
        if ((binfile = fopen(binfname, "w")) == NULL)
            error("Cannot open %s", binfname);
        fprintf(verbose,
                "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
                txtfname, info.type, info.auth);
        fwrite(&info, sizeof(info), 1, binfile);

        nchars = stbuf.st_size;
        extra_chars = 127 - (nchars+127) % 128;
        if (mode == TEXT) while (nchars--) {
            b = getc(txtfile);
            if (b == LF) b = CR;
            putc(b, binfile);
            }
        else while (nchars--) putc(getc(txtfile), binfile);

        while (extra_chars--) putc(0, binfile);
        fclose(binfile);
        fclose(txtfile);
        }
    }

/* This procedure copies the input file to the output file, basically, although
    in TEXT mode it changes CR's to LF's and in any mode it skips over the Mac
    info header. */

re_other(mode)
int mode;
{   register ulong b;
    register ulong nchars;
    char txtfname[BINNAMELEN], binfname[BINNAMELEN];
    FILE *txtfile, *binfile; 
    char *suffix;
    info_header info;

    if (mode == DATA) suffix = ".data";
    else if (mode == RSRC) suffix = ".rsrc";
    else suffix = ".text";

    while (hqxnames_left[0][0] != '-') {

        strcpy(binfname, *hqxnames_left++);
        if ((binfile = fopen(binfname, "r")) == NULL) {
            /* Maybe we are supposed to figure out the suffix ourselves? */
            strcat(binfname, ext);
            if (!(binfile = fopen(binfname, "r")))
                error("Cannot open %s", binfname);
            }

        /* Read the info from the .bin file, create the output file */
        fread(&info, sizeof(info), 1, binfile);
        strncpy(txtfname, info.name, info.nlen);
	txtfname[info.nlen] = '\0';
        fprintf(verbose,
                "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
                txtfname, info.type, info.auth);
        if ((txtfile = fopen(txtfname, "r")) == NULL) {
            if ((txtfile = fopen(txtfname, "w")) == NULL)
                error("Cannot open %s", txtfname);
            }
        else {
            fclose(txtfile);
            strcat(txtfname, suffix);
            if ((txtfile = fopen(txtfname, "w")) == NULL)
                error("Cannot open %s", txtfname);
            }

        nchars = mac2long(* (ulong *) info.dlen);
        if (mode == TEXT) while (nchars--) {
            b = getc(binfile);
            if (b == CR) b = LF;
            putc(b, txtfile);
            }
        else if (mode == DATA) while (nchars--)
            putc(getc(binfile), txtfile);
        else {
            while (nchars--) getc(binfile);
            nchars = mac2long(* (ulong *) info.rlen);
            while (nchars--) putc(getc(binfile), txtfile);
            }

        fclose(binfile);
        fclose(txtfile);
        }
    }
------ EOF ------
ls -l mcvert.c
fi # End mcvert.c
if test -f hqxify.c
then
echo shar: will not overwrite existing file " hqxify.c "
else
cat >hqxify.c <<'------ EOF ------'
#include "mactypes.h"

#define HQXBUFLEN 512
byte hqxbuf[HQXBUFLEN+1], *buf_ptr, *buf_end, *buf_start=hqxbuf+1;

#define MAXLINE 255
byte line[MAXLINE+1], *line_ptr, *line_end, *line_start=line+1;

int line_count, file_count;
int save_state, total_bytes, save_run_length;
word save_nibble;
char binfname[BINNAMELEN], hqxfname[BINNAMELEN];
FILE *hqxfile, *binfile;

/* This routine reads the header of a hqxed file and appropriately twiddles it,
    determines if it has CRC problems, creates the .bin file, and puts the info
    into the .bin file.
    Output is hqx_datalen, hqx_rsrclen, type, binfname, binfile */

hqx_to_bin_hdr(type, hqx_datalen, hqx_rsrclen)
char *type;
ulong *hqx_datalen, *hqx_rsrclen;
{   register byte *hqx_ptr, *hqx_end;
    register ulong calc_crc;
    hqx_buf *hqx_block;
    hqx_header *hqx;
    info_header info;
    ulong mtim;
    extern word magic[];
    extern FILE *verbose;
    extern char *dir, *ext;

    /* read the hqx header, assuming that I won't exhaust hqxbuf in so doing */
    fill_hqxbuf();
    hqx_block = (hqx_buf *) buf_ptr;
    hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen);
    hqx_ptr = buf_ptr;
    hqx_end = (byte *) hqx + sizeof(hqx_header);
    calc_crc = 0;
    while (hqx_ptr < hqx_end)
        calc_crc = (((calc_crc&0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
    calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
    calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
    buf_ptr = hqx_ptr;

    /* stuff the hqx header data into the info header */
    bzero(&info, sizeof(info_header));
    info.nlen = hqx_block->nlen;
    strncpy(info.name, hqx_block->name, info.nlen);     /* name */
    bcopy(hqx->type, info.type, 9);             /* type, author, flag */
    info.flags  &= 0x7e;                        /* reset lock bit, init bit */
    if (hqx->protect & 0x40) info.protect = 1;  /* copy protect bit */
    bcopy(hqx->dlen, info.dlen, 8);             /* dlen, rlen */
    mtim = time2mac(time(0));
    bcopy(&mtim, info.mtim, 4);
    bcopy(&mtim, info.ctim, 4);

    /* Create the .bin file and write the info to it */
    unixify(hqx_block->name);
    sprintf(binfname, "%s/%s%s", dir, hqx_block->name, ext);
    fprintf(verbose,
        "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
        hqx_block->name, info.type, info.auth);
    if ((binfile = fopen(binfname, "w")) == NULL)
        error("Cannot open %s", binfname);
    check_hqx_crc(calc_crc, "File header CRC mismatch in %s", binfname);
    fwrite(&info, sizeof(info), 1, binfile);

    /* Get a couple of items we'll need later */
    bcopy(info.dlen, hqx_datalen, 4);
    *hqx_datalen = mac2long(*hqx_datalen);
    bcopy(info.rlen, hqx_rsrclen, 4);
    *hqx_rsrclen = mac2long(*hqx_rsrclen);
    bcopy(info.type, type, 4);
    }

/* This routine reads the header of a bin file and appropriately twiddles it,
    creates the .hqx file, and puts the info into the .hqx file.
    Output is hqx_datalen, hqx_rsrclen, type, hqxfname, hqxfile */

bin_to_hqx_hdr(hqx_datalen, hqx_rsrclen)
ulong *hqx_datalen, *hqx_rsrclen;
{   register byte *hqx_ptr, *hqx_end;
    register ulong calc_crc;
    hqx_buf *hqx_block;
    hqx_header *hqx;
    info_header info;
    extern word magic[];
    extern FILE *verbose;
    extern char **hqxnames_left;
    extern char *ext;

    strcpy(binfname, *hqxnames_left++);
    if (!(binfile = fopen(binfname, "r"))) {
        /* Maybe we are supposed to figure out the suffix ourselves? */
        strcat(binfname, ext);
        if (!(binfile = fopen(binfname, "r")))
            error("Cannot open %s", binfname);
        }
    if (!fread(&info, sizeof(info), 1, binfile))
        error("Unexpected EOF in header of %s", binfname);

    /* stuff the info header into the hqx header */
    hqx_block = (hqx_buf *) buf_ptr;
    hqx_block->nlen = info.nlen;
    strncpy(hqx_block->name, info.name, info.nlen);
    hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen);
    hqx->version  = 0;
    bcopy(info.type, hqx->type, 9);             /* type, author, flags */
    if (info.protect = 1) hqx->protect = 0;     /* protect bit: 0x40 */
    else hqx->protect = 0;
    bcopy(info.dlen, hqx->dlen, 8);             /* dlen, rlen */

    /* Create the .hqx file and write the info to it */
    strncpy(hqxfname, info.name, info.nlen);
    unixify(hqxfname);
    fprintf(verbose,
        "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
        hqxfname, info.type, info.auth);

    calc_crc = 0;
    hqx_ptr = (byte *) hqx_block;
    hqx_end = hqx_ptr + 1 + hqx_block->nlen + sizeof(hqx_header);
    while (hqx_ptr < hqx_end)
        calc_crc = (((calc_crc&0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
    calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
    calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
    buf_ptr = hqx_end;
    write_hqx_crc(calc_crc);

    /* Get a couple of items we'll need later */
    bcopy(info.dlen, hqx_datalen, 4);
    *hqx_datalen = mac2long(*hqx_datalen);
    bcopy(info.rlen, hqx_rsrclen, 4);
    *hqx_rsrclen = mac2long(*hqx_rsrclen);
    }


/* This routine copies bytes from the decoded input stream to the output.  
    It also pads to a multiple of 128 bytes on the output, which is part
    of the .bin format */
word hqx_to_bin_fork(nbytes)
register ulong nbytes;
{   register byte *c;
    register ulong calc_crc;
    register int c_length;
    ulong extra_bytes;
    extern word magic[];

    extra_bytes = 127 - (nbytes+127)%128; /* pad fork to mult of 128 bytes */
    calc_crc = 0;
    for (;;) {
        c = buf_ptr;
        c_length = (c + nbytes > buf_end) ? buf_end - c : nbytes;
        nbytes -= c_length;
        fwrite(c, sizeof(byte), c_length, binfile);
        while (c_length--)
            calc_crc = (((calc_crc&0xff) << 8) | *c++) ^ magic[calc_crc >> 8];
        if (!nbytes) break;
        fill_hqxbuf();
        }
    buf_ptr = c;
    while (extra_bytes--) putc(0, binfile);
    calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
    calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
    return (word) calc_crc;
    }

/* This routine copies bytes from the input stream to the encoded output.  
    It also pads to a multiple of 128 bytes on the input, which is part
    of the .bin format */
word bin_to_hqx_fork(nbytes)
register ulong nbytes;
{   register byte *c;
    register ulong calc_crc;
    register int c_length;
    ulong extra_bytes;
    extern word magic[];

    extra_bytes = 127 - (nbytes+127)%128; /* pad fork to mult of 128 bytes */
    calc_crc = 0;
    for (;;) {
        c = buf_ptr;
        c_length = (c + nbytes > buf_end) ? buf_end - c : nbytes;
        nbytes -= c_length;
        fread(c, sizeof(byte), c_length, binfile);
        buf_ptr += c_length;
        while (c_length--)
            calc_crc = (((calc_crc&0xff) << 8) | *c++) ^ magic[calc_crc >> 8];
        if (!nbytes) break;
        empty_hqxbuf();
        }
    buf_ptr = c;

    fseek(binfile, extra_bytes, 1);
    calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
    calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
    return (word) calc_crc;
    }

/* Essentials for Binhex 8to6 run length encoding */
#define RUNCHAR 0x90
#define MAXRUN 255
#define IS_LEGAL <0x40
#define ISNT_LEGAL >0x3f
#define DONE 0x7F /* tr68[':'] = DONE, since Binhex terminator is ':' */
#define SKIP 0x7E /* tr68['\n'|'\r'] = SKIP, i. e. end of line char.  */
#define FAIL 0x7D /* character illegal in binhex file */

byte tr86[] =
        "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; 
byte tr68[] = {
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, SKIP, FAIL, FAIL, SKIP, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, FAIL, FAIL,
    0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, FAIL,
    0x14, 0x15, DONE, FAIL, FAIL, FAIL, FAIL, FAIL,
    0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
    0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, FAIL,
    0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, FAIL,
    0x2C, 0x2D, 0x2E, 0x2F, FAIL, FAIL, FAIL, FAIL,
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, FAIL,
    0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, FAIL, FAIL,
    0x3D, 0x3E, 0x3F, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
    };

/*
 *  This procedure transparently reads and decodes the hqx input.  It does run 
 *  length and 6 to 8 decoding.
 */
#define READING 0
#define SKIPPING 1
#define FIND_START_COLON 2

fill_hqxbuf()
{   register ulong c, nibble;
    register int not_in_a_run = TRUE, state68;
    register byte *fast_buf, *fast_line;
    static int status = FIND_START_COLON;

    buf_ptr = fast_buf = buf_start;
    fast_line = line_ptr;
    state68 = save_state;
    nibble = save_nibble;
    if (save_run_length > 0) {
        c = save_run_length;
        save_run_length = 0;
        goto continue_run;
        }
    while (fast_buf < buf_end) {
        next_char:
        if ((c = *fast_line++) ISNT_LEGAL) {
            if (c == DONE) break;
            next_line:
            if (!fgets(line_start, MAXLINE, hqxfile) && !new_in_hqx_file())
                error("Premature EOF in %s\n", hqxfname);
            line_ptr = line_start;
            scan_line:
            fast_line = line_ptr;
            while ((*fast_line++ = tr68[*fast_line]) IS_LEGAL);
            c = *--fast_line;
            switch (status) {
            case READING:
                if (c == SKIP && fast_line == line_end) break;
                if (c == DONE) {
                    status = FIND_START_COLON;
                    break;
                    }
                status = SKIPPING;
                goto next_line;
            case SKIPPING:
                if (c == SKIP && fast_line == line_end) {
                    status = READING;
                    break;
                    }
                goto next_line;
            case FIND_START_COLON:
                if (*line_start == DONE) {
                    status = READING;
                    line_ptr++;
                    goto scan_line;
                    }
                goto next_line;
                }
            fast_line = line_ptr;
            c = *fast_line++;
            }

        /* Finally, we have the next 6 bits worth of data */
        switch (state68++) {
        case 0:
            nibble = c;
            goto next_char;
        case 1:
            nibble = (nibble << 6) | c;
            c = nibble >> 4;
            break;
        case 2:
            nibble = (nibble << 6) | c;
            c = (nibble >> 2) & 0xff;
            break;
        case 3:
            c = (nibble << 6) & 0xff | c;
            state68 = 0;
            break;
            }
        if (not_in_a_run)
            if (c != RUNCHAR) *fast_buf++ = c;
            else {not_in_a_run = FALSE; goto next_char;}
        else {
            if (c--) {
                not_in_a_run = buf_end - fast_buf;
                if (c > not_in_a_run) {
                    save_run_length = c - not_in_a_run;
                    c = not_in_a_run;
                    }
                continue_run:
                not_in_a_run = fast_buf[-1];
                while (c--) *fast_buf++ = not_in_a_run;
                }
            else *fast_buf++ = RUNCHAR;
            not_in_a_run = TRUE;
            }
        }
    total_bytes += fast_buf - buf_ptr;
    buf_start[-1] = fast_buf[-1];
    line_ptr = fast_line;
    save_state = state68;
    save_nibble = nibble;
    }


new_in_hqx_file()
{   char *hqx_ext;
    extern char **hqxnames_left;
    if (*hqxnames_left[0] == '\0' || *hqxnames_left[0] == '-') return FALSE;
    strcpy(hqxfname, *hqxnames_left++);
    hqx_ext = hqxfname + strlen(hqxfname) - 4;
    if (!strcmp(hqx_ext, ".hqx"))
        if (!freopen(hqxfname, "r", hqxfile))
            error("Cannot open %s\n", hqxfname);
            else;
    else {
        if (!freopen(hqxfname, "r", hqxfile)) {
            hqx_ext += 4;
            strcpy(hqx_ext, ".hqx");
            if (!freopen(hqxfname, "r", hqxfile)) {
                error("Cannot find %s\n", hqxfname);
            }
        }
      }
    fgets(line_start, MAXLINE, hqxfile);
	return TRUE;
    }

/*
 *  This procedure transparently encodes and writes the hqx output.  
 *  It does run length and 8 to 6 encoding.
 */
empty_hqxbuf()
{   register ulong c, nibble, last_c;
    register byte *fast_buf, *fast_line;
    register int state86, dont_look_for_runs = FALSE, run_length;
    extern int maxlines;

    run_length = save_run_length;
    last_c = buf_start[-1];
    fast_buf = buf_start;
    fast_line = line_ptr;
    state86 = save_state;
    nibble = save_nibble;
    while (fast_buf < buf_ptr) {
        c = *fast_buf++;
        if (dont_look_for_runs) dont_look_for_runs = FALSE;
        else if (last_c == c &&  run_length < MAXRUN) {run_length++; continue;}
        else {
            if (run_length >1) {
                --fast_buf;
                if (run_length == 2 && last_c != RUNCHAR) c = last_c;
                else {
                    c = RUNCHAR;
                    *--fast_buf = run_length;
                    dont_look_for_runs = TRUE;
                    }
                run_length = 1;
                }
            else last_c = c;
            if (c == RUNCHAR && !dont_look_for_runs) {
                *--fast_buf = 0;
                dont_look_for_runs = TRUE;
                }
            }

        if (fast_line == line_end) {
            if (line_count++ == maxlines) new_out_hqx_file();
            fputs(line_start, hqxfile);
            fast_line = line_start;
            }

        switch (state86++) {
        case 0:
            *fast_line++ = tr86[ c >> 2 ];
            nibble = (c << 4) & 0x3f;
            break;
        case 1:
            *fast_line++ = tr86[ (c >> 4) | nibble ];
            nibble = (c << 2) & 0x3f;
            break;
        case 2:
            *fast_line++ = tr86[ (c >> 6) | nibble ];
            if (fast_line == line_end) {
                if (line_count++ == maxlines) new_out_hqx_file();
                fputs(line_start, hqxfile);
                fast_line = line_start;
                }
            *fast_line++ = tr86[ c & 0x3f ];
            state86 = 0;
            break;
            }
        }
    save_run_length = run_length;
    buf_start[-1] = last_c;
    buf_ptr = buf_start;
    line_ptr = fast_line;
    save_state = state86;
    save_nibble = nibble;
    }

new_out_hqx_file()
{   char filename[NAMELEN + 7];
    extern int maxlines;
    fprintf(hqxfile, "<<< End of Part %2d >>>\n", file_count);
    fclose(hqxfile);
    file_count++;
    if (maxlines) sprintf(filename, "%s%02d.hqx", hqxfname, file_count);
    else sprintf(filename, "%s.hqx", hqxfname);
    if ((hqxfile = fopen(filename, "w")) == NULL)
        error("Can't create %s", filename);
    if (file_count > 1)
        fprintf(hqxfile, "<<< Start of Part %2d >>>\n", file_count);
    else fprintf(hqxfile, "(This file must be converted with BinHex 4.0)\n\n");
    line_count = 3;
    }

check_hqx_crc(calc_crc, msg, name)
word calc_crc;
char msg[], name[];
{   word read_crc;
    if (buf_ptr >= buf_end) fill_hqxbuf();
    read_crc = *buf_ptr++ << 8;
    if (buf_ptr >= buf_end) fill_hqxbuf();
    read_crc |= *buf_ptr++;
    if (read_crc != calc_crc) error(msg, name);
    }

write_hqx_crc(calc_crc)
word calc_crc;
{   if (buf_ptr == buf_end) empty_hqxbuf();
    *buf_ptr++ = calc_crc >> 8;
    if (buf_ptr == buf_end) empty_hqxbuf();
    *buf_ptr++ = calc_crc;
    }

un_hqx(unpit_flag)
int unpit_flag;
{   char type[4];
    ulong hqx_datalen, hqx_rsrclen;
    word un_pit();
    int unpitting, bytes_read;
    word calc_crc;
    extern char **hqxnames_left;

    hqxfile = fopen("/dev/null", "r");
    line_end = line_start + HQXLINELEN;
    buf_end = buf_start + HQXBUFLEN;
    while (*hqxnames_left[0] != '-') {
        total_bytes = 0;
        line_ptr = line_start;
        line_ptr[0] = SKIP;
        save_state = 0;
        save_run_length = 0;

        hqx_to_bin_hdr(type, &hqx_datalen, &hqx_rsrclen); /* binfname */

        unpitting = unpit_flag && !strcmp(type, "PIT ");
        if (unpitting) {
            fclose(binfile);
            unlink(binfname);
            bytes_read = total_bytes - (buf_end - buf_ptr);
            calc_crc = un_pit();
            bytes_read = total_bytes - (buf_end - buf_ptr) - bytes_read;
            if (bytes_read != hqx_datalen)
                fprintf(stderr,
                  "Warning - Extraneous characters ignored in %s\n", binfname);
            }
        else calc_crc = hqx_to_bin_fork(hqx_datalen);
        check_hqx_crc(calc_crc, "File data CRC mismatch in %s", binfname);

        calc_crc = hqx_to_bin_fork(hqx_rsrclen);
        check_hqx_crc(calc_crc, "File rsrc CRC mismatch in %s", binfname);

        if (!unpitting) fclose(binfile);
        }
    }

re_hqx()
{   word calc_crc;
    ulong hqx_datalen, hqx_rsrclen;
    extern char **hqxnames_left;
    extern int maxlines;
    line_end = line_start + HQXLINELEN;
    buf_end = buf_start + HQXBUFLEN;
    while (*hqxnames_left[0] != '-') {
        hqxfile = fopen("/dev/null", "w");
        line_count = maxlines;
        file_count = 0;
        line_ptr = line_start;
        *line_ptr++ = ':';
        strcpy(line_end, "\n");
        buf_ptr = buf_start;
        save_state = 0;
        save_run_length = 1;

        bin_to_hqx_hdr(&hqx_datalen, &hqx_rsrclen);   /* calculates hqxfname */

        calc_crc = bin_to_hqx_fork(hqx_datalen);
        write_hqx_crc(calc_crc);

        calc_crc = bin_to_hqx_fork(hqx_rsrclen);
        write_hqx_crc(calc_crc);

        *buf_ptr++ = !buf_ptr[-1];      /* To end a run and to get the last */
        empty_hqxbuf();                 /* stray bits, temporarily add a char */
        if (save_state != 2) --line_ptr;
        if (line_ptr == line_end) {
            fputs(line_start, hqxfile);
            line_ptr = line_start;
            }
        strcpy(line_ptr, ":\n");
        fputs(line_start, hqxfile);
        fclose(hqxfile);
        }
    }
------ EOF ------
ls -l hqxify.c
fi # End hqxify.c
if test -f unpack.c
then
echo shar: will not overwrite existing file " unpack.c "
else
cat >unpack.c <<'------ EOF ------'
#include "mactypes.h"

extern word magic[];
extern FILE *verbose;
extern char *dir, *ext;

ulong pit_datalen, pit_rsrclen;
word hqx_crc, write_pit_fork(); 
char pitfname[BINNAMELEN];              /* name of file being unpacked */
FILE *pitfile;                          /* output file */

branch branchlist[255], *branchptr, *read_tree();
leaf leaflist[256], *leafptr;
word Huff_nibble, Huff_bit_count;
byte (*read_char)(), get_crc_byte(), getHuffbyte();

word un_pit()
{   char PitId[4];
    int i;
    word pit_crc;

    hqx_crc = 0;
    /* Read and unpack until the PackIt End message is read */
    for (;;) {
        read_char = get_crc_byte;
        for (i = 0; i < 4; i++) PitId[i] = (char) get_crc_byte();
        if (!strncmp(PitId, "PEnd", 4)) break;

        if (strncmp(PitId, "PMag", 4) && strncmp(PitId, "PMa4", 4))
            error("Unrecognized Packit format message %s", PitId);

        if (PitId[3] == '4') {          /* if this file is compressed */
            branchptr = branchlist;     /* read the Huffman decoding  */
            leafptr = leaflist;         /* tree that is on the input  */
            Huff_bit_count = 0;         /* and use Huffman decoding   */
            read_tree();                /* subsequently               */
            read_char = getHuffbyte;
            }

        read_pit_hdr();     /* also calculates datalen, rsrclen,
                               pitfile, pitfname */
        pit_crc = write_pit_fork(pit_datalen, 0);
        pit_crc = write_pit_fork(pit_rsrclen, pit_crc);
        check_pit_crc(pit_crc, "  File data/rsrc CRC mismatch in %s", pitfname);
        fclose(pitfile);
        }
    hqx_crc = (hqx_crc << 8) ^ magic[hqx_crc >> 8];
    hqx_crc = (hqx_crc << 8) ^ magic[hqx_crc >> 8];
    return hqx_crc;
    }

check_pit_crc(calc_crc, msg, name)
word calc_crc;
char msg[], name[];
{   word read_crc;
    read_crc = (*read_char)() << 8;
    read_crc |= (*read_char)();
    if (read_crc != calc_crc) error(msg, name);
    }

/* This routine reads the header of a packed file and appropriately twiddles it,
    determines if it has CRC problems, creates the .bin file, and puts the info
    into the .bin file.
    Output is pit_datalen, pit_rsrclen, pitfname, pitfile */
read_pit_hdr()
{   register int n;
    register byte *pit_byte;
    register ulong pit_crc;
    pit_header pit;
    info_header info;

    /* read the pit header and compute the CRC */
    pit_crc = 0;
    pit_byte = (byte *) &pit;
    for (n = 0; n < sizeof(pit_header); n++) {
        *pit_byte = (*read_char)();
        pit_crc = ((pit_crc & 0xff) << 8)
                    ^ magic[*pit_byte++ ^ (pit_crc >> 8)];
        }

    /* stuff the pit header data into the info header */
    bzero(&info, sizeof(info_header));
    info.nlen = pit.nlen;
    strncpy(info.name, pit.name, pit.nlen);     /* name */
    bcopy(pit.type, info.type, 9);              /* type, author, flag */
    bcopy(pit.dlen, info.dlen, 16);             /* (d,r)len, (c,m)tim */
    info.flags  &= 0x7e;                        /* reset lock bit, init bit */
    if (pit.protect & 0x40) info.protect = 1;   /* copy protect bit */

    /* Create the .bin file and write the info to it */
    pit.name[pit.nlen] = '\0';
    unixify(pit.name);
    sprintf(pitfname, "%s/%s%s", dir, pit.name, ext);
    fprintf(verbose,
        " %-14s%-30s type = \"%4.4s\", author = \"%4.4s\"\n",
        (read_char == get_crc_byte) ? "Unpacking" : "Decompressing",
        pit.name, pit.type, pit.auth);
    if ((pitfile = fopen(pitfname, "w")) == NULL)
        error("  Cannot open %s", pitfname);
    check_pit_crc(pit_crc, "  File header CRC mismatch in %s", pitfname);
    fwrite(&info, sizeof(info_header), 1, pitfile);

    /* Get a couple of items we'll need later */
    bcopy(pit.dlen, &pit_datalen, 4);
    pit_datalen = mac2long(pit_datalen);
    bcopy(pit.rlen, &pit_rsrclen, 4);
    pit_rsrclen = mac2long(pit_rsrclen);
    }

/* This routine copies bytes from the decoded input stream to the output
    and calculates the CRC.  It also pads to a multiple of 128 bytes on the
    output, which is part of the .bin format */
word write_pit_fork(nbytes, calc_crc)
register ulong nbytes;
register ulong calc_crc;
{   register ulong b;
    int extra_bytes;

    extra_bytes = 127 - (nbytes+127)%128; /* pad fork to mult of 128 bytes */
    while (nbytes--) {
        b = (*read_char)();
        calc_crc = ((calc_crc & 0xff) << 8) ^ magic[b ^ (calc_crc >> 8)];
        putc(b, pitfile);
        }
    while (extra_bytes--) putc(0, pitfile);
    return (word) calc_crc;
    }

/* This routine recursively reads the compression decoding data.
   It appears to be Huffman compression.  Every leaf is represented
   by a 1 bit, then the byte it represents.  A branch is represented
   by a 0 bit, then its zero and one sons */
branch *read_tree()
{   register branch *branchp;
    register leaf *leafp;
    register ulong b;
    if (!Huff_bit_count--) {
        Huff_nibble = get_crc_byte();
        Huff_bit_count = 7;
        }
    if ((Huff_nibble<<=1) & 0x0100) {
        leafp = leafptr++;
        leafp->flag = 1;
        b = get_crc_byte();
        leafp->data = Huff_nibble | (b >> Huff_bit_count);
        Huff_nibble = b << (8 - Huff_bit_count);
        return (branch *) leafp;
        }
    else {
        branchp = branchptr++;
        branchp->flag = 0;
        branchp->zero = read_tree();
        branchp->one  = read_tree();
        return branchp;
        }
    }

/* This routine returns the next 8 bits.  It finds the byte in the
   Huffman decoding tree based on the bits from the input stream. */
byte getHuffbyte()
{   register branch *branchp;
    branchp = branchlist;
    while (!branchp->flag) {
        if (!Huff_bit_count--) {
            Huff_nibble = get_crc_byte();
            Huff_bit_count = 7;
            }
        branchp = ((Huff_nibble<<=1) & 0x0100) ? branchp->one : branchp->zero;
        }
    return ((leaf *) branchp)->data;
    }

/* This routine returns the next byte on the .hqx input stream, hiding
    most file system details at a lower level.  .hqx CRC is maintained
    here */
byte get_crc_byte()
{   register ulong c;
    extern byte *buf_ptr, *buf_end;
    if (buf_ptr == buf_end) fill_hqxbuf();
    c = *buf_ptr++;
    hqx_crc = ((hqx_crc << 8) | c) ^ magic[hqx_crc >> 8];
    return (byte) c;
    }
------ EOF ------
ls -l unpack.c
fi # End unpack.c
if test -f mactypes.h
then
echo shar: will not overwrite existing file " mactypes.h "
else
cat >mactypes.h <<'------ EOF ------'
#include <stdio.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <sys/timeb.h>

/* Useful, though not particularly Mac related, values */
typedef unsigned char byte;     /* one byte, obviously */
typedef unsigned short word;    /* must be 2 bytes */
typedef unsigned long ulong;    /* 4 bytes */
#define TRUE  1
#define FALSE 0
#define CR 0x0d
#define LF 0x0a

/* Compatibility issues */
#ifdef BSD
#define mac2word (word) ntohs
#define mac2long (ulong) ntohl
#define word2mac (word) htons
#define long2mac (ulong) htonl
#else
#define mac2word
#define mac2long
#define word2mac
#define long2mac
#endif

#ifdef MAXNAMLEN/* 4.2 BSD, stdio.h */
#define SYSNAMELEN MAXNAMLEN
#else
#define SYSNAMELEN DIRSIZ
#endif

#define NAMELEN 63              /* maximum legal Mac file name length */
#define BINNAMELEN 68           /* NAMELEN + len(".bin\0") */

/* Format of a bin file:
A bin file is composed of 128 byte blocks.  The first block is the
info_header (see below).  Then comes the data fork, null padded to fill the
last block.  Then comes the resource fork, padded to fill the last block.  A
proposal to follow with the text of the Get Info box has not been implemented,
to the best of my knowledge.  Version, zero1 and zero2 are what the receiving
program looks at to determine if a MacBinary transfer is being initiated.
*/ 
typedef struct {     /* info file header (128 bytes). Unfortunately, these
                        longs don't align to word boundaries */
            byte version;           /* there is only a version 0 at this time */
            byte nlen;              /* Length of filename. */
            byte name[NAMELEN];     /* Filename (only 1st nlen are significant)*/
            byte type[4];           /* File type. */
            byte auth[4];           /* File creator. */
            byte flags;             /* file flags: LkIvBnSyBzByChIt */
            byte zero1;             /* Locked, Invisible,Bundle, System */
                                    /* Bozo, Busy, Changed, Init */
            byte icon_vert[2];      /* Vertical icon position within window */
            byte icon_horiz[2];     /* Horizontal icon postion in window */
            byte window_id[2];      /* Window or folder ID. */
            byte protect;           /* = 1 for protected file, 0 otherwise */
            byte zero2;
            byte dlen[4];           /* Data Fork length (bytes) -   most sig.  */
            byte rlen[4];           /* Resource Fork length         byte first */
            byte ctim[4];           /* File's creation date. */
            byte mtim[4];           /* File's "last modified" date. */
            byte ilen[2];           /* (Proposed) GetInfo message length */
            byte unused[27];
            } info_header;

/* The *.info file of a MacTerminal file transfer either has exactly this
structure or has the protect bit in bit 6 (near the sign bit) of byte zero1.
The code I have for macbin suggests the difference, but I'm not so sure */

/* Format of a hqx file:
It begins with a line that begins "(This file
and the rest is 64 character lines (except possibly the last, and not
including newlines) where the first begins and the last ends with a colon.
The characters between colons should be only from the set in tr86, below,
each of which corresponds to 6 bits of data.  Once that is translated to
8 bit bytes, you have the real data, except that the byte 0x90 may 
indicate, if the following character is nonzero, that the previous
byte is to be repeated 1 to 255 times.  The byte 0x90 is represented by
0x9000.  The information in the file is the hqx_buf (see below),
a CRC word, the data fork, a CRC word, the resource fork, and a CRC word.
There is considerable confusion about the flags.  An official looking document
unclearly states that the init bit is always clear, as is the following byte.
The experience of others suggests, however, that this is not the case.
*/

#define HQXLINELEN 64
typedef struct {
            byte version;           /* there is only a version 0 at this time */
            byte type[4];           /* File type. */
            byte auth[4];           /* File creator. */
            byte flags;             /* file flags: LkIvBnSyBzByChIt */
            byte protect;           /* ?Pr??????, don't know what ? bits mean */
            byte dlen[4];           /* Data Fork length (bytes) -   most sig.  */
            byte rlen[4];           /* Resource Fork length         byte first */
            } hqx_header;
typedef struct {     /* hqx file header buffer (includes file name) */
            byte nlen;              /* Length of filename. */
            byte name[NAMELEN];     /* Filename: only nlen actually appear */
            hqx_header all_the_rest;/* and all the rest follows immediately */
            } hqx_buf;

/* Format of a Packit file:
Repeat the following sequence for each file in the Packit file:
    4 byte identifier ("PMag" = not compressed, "Pma4" = compressed)
    320 byte compression data (if compressed file)
        = preorder transversal of Huffman tree
        255 0 bits corresponding to nonleaf nodes
        256 1 bits corresponding to leaf nodes
        256 bytes associating leaf nodes with bytes
        1   completely wasted bit
    92 byte header (see pit_header below) *
    2 bytes CRC word for header *
    data fork (length from header) *
    resource fork (length from header) *
    2 bytes CRC word for forks *

Last file is followed by the 4 byte Ascii string, "Pend", and then the EOF.
The CRC calculations differ from those in the binhex format.

* these are in compressed form if compression is on for the file

*/

typedef struct {     /* Packit file header (92 bytes) */
            byte nlen;              /* Length of filename. */
            byte name[NAMELEN];     /* Filename (only 1st nlen are significant)*/
            byte type[4];           /* File type. */
            byte auth[4];           /* File creator. */
            byte flags;             /* file flags: LkIvBnSyBzByChIt */
            byte zero1;
            byte protect;           /* = 1 for protected file, 0 otherwise */
            byte zero2;
            byte dlen[4];           /* Data Fork length (bytes) -   most sig.  */
            byte rlen[4];           /* Resource Fork length         byte first */
            byte ctim[4];           /* File's creation date. */
            byte mtim[4];           /* File's "last modified" date. */
            } pit_header;

/* types for constructing the Huffman tree */
typedef struct branch_st {
            byte flag;
            struct branch_st *one, *zero;
            } branch;

typedef struct leaf_st {
            byte flag;
            byte data;
            } leaf;
------ EOF ------
ls -l mactypes.h
fi # End mactypes.h
if test -f Makefile
then
echo shar: will not overwrite existing file " Makefile "
else
cat >Makefile <<'------ EOF ------'
CSOURCES = mcvert.c hqxify.c unpack.c
SOURCES = mcvert.c hqxify.c unpack.c mactypes.h Makefile
OBJECTS = mcvert.o hqxify.o unpack.o
BIN = /mu/moore/mac/bin
CFLAGS = -O -DBSD

mcvert: $(OBJECTS)
	cc $(CFLAGS) $(OBJECTS) -s -o $(BIN)/mcvert

$(OBJECTS): mactypes.h

print: 
	lpr -p -Pvmslp $(SOURCES)

shar:
	shar -v -o mcvert.shar $(SOURCES) mcvert.1

clean:
	rm -f mcvert $(OBJECTS)

debug:
	cc -g -DBSD -o dbvert $(CSOURCES)

profile:
	cc -p $(CFLAGS) -o prvert $(CSOURCES)

------ EOF ------
ls -l Makefile
fi # End Makefile
if test -f mcvert.1
then
echo shar: will not overwrite existing file " mcvert.1 "
else
cat >mcvert.1 <<'------ EOF ------'
.TH MCVERT LOCAL "May 5, 1987"
.UC 4.2
.SH NAME
mcvert \- BinHex 4.0 to MacBinary file conversion utility
.SH SYNOPSIS
.B mcvert
[-options] name... [[-options] name...]...
.br
.SH DESCRIPTION
The
.I mcvert
program translates MacIntosh files from one format to another.
The primary formats in which MacIntosh files are represented on non-Macs are:
.TP
.B MacBinary:
An eight bit wide representation of the data and resource forks of a Mac
file and of relevant Finder information, MacBinary files are recognized
as "special" by several MacIntosh terminal emulators.  These emulators,
using Kermit or Xmodem or any other file transfer protocol, can separate
the incoming file into forks and appropriately modify the Desktop to display
icons, types, creation dates, and the like.
.TP
.B BinHex 4.0:
A seven bit wide representation of a Mac file with CRC error checking,
BinHex 4.0 files are designed for communication of Mac files over long
distance, possibly noisy, seven bit wide paths.
.TP
.B PackIt:
PackIt files are actually representations of collections of Mac files, possibly
Huffman compressed.  Packing many small related files together before
a MacBinary transfer or a translation to BinHex 4.0 is common practice.
.TP
.B Text:
A MacIntosh ends each line of a plain text file with a carriage return
character (^M), rather than the newline character (^J) that some systems
seem to prefer.  Moreover, a MacBinary file has prepended Finder information
that non-MacIntoshes don't need.
.TP
.B Data, Rsrc:
A Data or Rsrc file is the exact copy of the data or resource fork of a
MacIntosh file.
.PP
It is the purpose of this program to convert to the MacBinary format
files in other of the above formats, and vice versa.
.PP
.SH PARAMETERS
Exactly one of the following operations may be specified for an input name:
.TP
.B x
BinHex 4.0 - files in the MacBinary format are translated to BinHex
files, or vice versa.  The name argument may be the name of a file to be
converted or a basename to which an appropriate suffix must be appended
to get a filename.  If the conversion is from Binhex 4.0 to MacBinary,
several files may comprise the BinHex representation of the Mac file.
Rather than manually concatenate the files and manually delete mail
headers and other extraneous garbage, one may specify the names of the
files in order and
.I mcvert
will do the concatenating and deleting.  Conversely, in converting
a MacBinary file to BinHex 4.0 format for mailing over long distances,
one may be restricted to mail messages of no greater that some fixed
length.  In this case,
.I mcvert
can automatically divide the BinHex file into pieces and label each
piece appropriately.
Option 'x' is selected by default.
.TP
.B r
Resource - files in the MacBinary format with empty data forks
and nonempty resource forks are made from ordinary data files, or vice versa.
.TP
.B d
Data - files in the MacBinary format with nonempty data forks
and empty resource forks are made from ordinary data files, or vice versa.
.TP
.B u
Text - files in the MacBinary format with nonempty data forks
and empty resource forks are made from ordinary data files, or vice versa.
Unix newline
characters are interchanged with MacIntosh carriage return
characters, and a newly created MacBinary file has creator field given by
the MAC_EDITOR environment variable.
.PP
.SH OPTIONS
.TP
.B p | q
If a BinHex to MacBinary conversion is taking place and option 'p' is selected,
any file of type "PIT "
will be unpacked into its constituent parts.  This option does not recursively
unpack "PIT " files packed in "PIT " files.
If a MacBinary to BinHex conversion is taking place, this option is currently
ignored.  By default, option 'q' is selected.
.TP
.B U | D
When option 'U' is selected, the conversion that takes place is the one suitable
for Uploading files.  That is, the conversion is from MacBinary to something
else when 'U' is selected.  Conversely, option 'D', as in Download,
converts from something to MacBinary.  Option 'D' is the default.
.TP
.B s | v
Normally,
.I mcvert
prints to stderr information about the files it is creating.  Selecting
option 's', as in silent, disables this reporting.  Option 'v', for verbose,
is the default.
.SH "ENVIRONMENT VARIABLES"
There are four environment variables one may use to customize 
the behavior of
.I mcvert
slightly.
.TP
.B MAC_EDITOR
The creator of MacBinary text files produced with options -uD.  
The default is MACA, the creator type of MacWrite.
.TP
.B MAC_DLOAD_DIR
The MacBinary files created when option -D is selected are placed in this
directory.  The default is ".", the current working directory.
.TP
.B MAC_EXT
The MacBinary files created when option -D is selected are named according
to the filename field stored in the file header, with the name extended by
this suffix.  The default is ".bin".
.TP
.B MAC_LINE_LIMIT
The BinHex files created when option -U is selected may be no longer than
this many lines long.  Files that would otherwise exceed this line limit
are broken up into several files with numbers embedded into their file 
names to show their order.  Each such file has "Start of part x" and "End
of part x" messages included where appropriate.
.SH BUGS
It should be possible to discard bad input now and successfully translate
good input later, but bad input mostly just causes immediate termination.
.PP
A more diligent person would support BinHex 3.0 and BinHex 2.0 and BinHex
5000.0 B. C., but I've never seen anyone use them in three years.  A
more diligent person would also do something for users of macget and
macput, but hopefully someone will make those programs support the
MacBinary file protocol.
.SH SEE ALSO
xbin(1), macget(1), macput(1), xmodem(1), kermit(1)
.SH AUTHOR
Doug Moore, Cornell University Computer Science.  Based upon
.I xbin
by Dave Johnson, Brown University, as modified by Guido van Rossum, and upon
.I unpit
by Allan G. Weber, as well as upon correspondence with several helpful
readers of USENET.

------ EOF ------
ls -l mcvert.1
fi # End mcvert.1
echo '***** End of' mcvert.shar '*****'
exit 0
-- 
Ken Konecki
"A squeegee by any other name wouldn't sound as funny"
e-mail:kenk@tellab5.UUCP    -or-    ...!uunet!tellab5!kenk	
U.S. Mail: 1271 Portchester Circle, Carol Stream, IL 60188

levin@bbn.com (Joel B Levin) (05/09/89)

In article <8230@phoenix.Princeton.EDU> bskendig@phoenix.Princeton.EDU (Brian Scott Kendig) writes:
|I'll expand on the general request here: Does anyone know of any mass-deBinHex
|or mass-unStuffIt utilities that exist for either the Mac or any Unix systems?
|I can use my CMS system here to de-BinHex a file before I download it, making
|it smaller and more quickly downloaded, but I hesitate to do that on each of
|dozens of files at once manually.
|
|And it would be REALLY nice if I could take a BinHexed, Stuffed file on my
|Unix system and, in one fell swoop, download it to each of its constituent
|files on my Mac, each file ready to go with no further action!  (Dream on...)

I use xbin, unstuff, and macput on my Sun workstation (or I can use
them on the VAX with Ultrix), and VersaTerm at 19200 via the Sun's
serial port (or the VAX at 9600 over our terminal controller).  I put
all the .hqx files in a directory.  I use a program called comb to
extract the junk from a combined multi-part .binaries item.

	xbin -v *.hqx
(I examine the names of the unpacked files; almost always the stuffit
archives match *xsit.* or *xSIT.*)

	foreach a (*xsit.data)
	unsit -v $a
	end				(C-shell)
or
	for a in *xsit.data
	do unsit -v $a
	done				(Other shell (if I remember right))

Then after deleting the used *.hqx and *xsit.* files:

	foreach a (*.info)
	macput `basename $a .info`
	end				(C-shell; make appropriate
					 changes for other shells)

Some possible gotchas:
  Even with the latest changes, some characters
  in filenames break xbin.  I don't bother; I generally ship the .hqx
  file to the Mac and do it by hand.

  If you do a lot of files at once, a later file with the same name as
  an earlier file could wipe the earlier one out (e.g. two files named
  READ_ME).  READ_ME and Read_Me would co-exist on the Unix system OK
  but could be a problem on the Mac (I forget what Versaterm does).
  This is why I use the -v(erbose) options above.

This is what works for me.  I could make it more automated, but I
don't do it often enough to make it worth while.

	/JBL
UUCP:     {backbone}!bbn!levin		POTS: (617) 873-3463
INTERNET: levin@bbn.com

john@trigraph.UUCP (John Chew) (05/10/89)

In artcile <wYNPz6y00WB44PDUoC@andrew.cmu.edu> ll12+@andrew.cmu.edu
  (Laura Ann Lemay) writes: 
>What I need is some sort of simple utility that will take a folder of files
>and massively de-binhex them.  Errors would be recorded, so I could go back
>afterwards and fix the files that went bad, but otherwise everything would
>just be automated.
>
>Anyone know of any utility like this?  Anyone want to write one?  :-)
>And while you're at it, a mass unstuffit would be nice, too, since stuffit
>is the de facto utility now for downloading files....

In article <8230@phoenix.Princeton.EDU> bskendig@phoenix.Princeton.EDU 
  (Brian Scott Kendig) writes:
>I'll expand on the general request here: Does anyone know of any mass-deBinHex
>or mass-unStuffIt utilities that exist for either the Mac or any Unix systems?
>I can use my CMS system here to de-BinHex a file before I download it, making
>it smaller and more quickly downloaded, but I hesitate to do that on each of
>dozens of files at once manually.
>
>And it would be REALLY nice if I could take a BinHexed, Stuffed file on my
>Unix system and, in one fell swoop, download it to each of its constituent
>files on my Mac, each file ready to go with no further action!  (Dream on...)

I went away on vacation a few weeks ago and, paranoid that I might
miss some gem of a posting to comp.binaries.mac, I finally got
around to finishing off my c.b.m archiver.  I have a (Ksh) script
to rescue the individual articles out of the news area, a lex
program that parses Subject: lines in order to rename articles by
posting title and part number, a C program that strips out news
wrappers and assembles multi-part postings, and then a modified
version of Dave Johnson's xbin utility (our source here is dated
09/30/85 -- there's no doubt a more recent version) patched by
me to generate AUFS files instead of MacBinary files.  The end
result is that I no longer need to read c.b.m: I just connect
to the CAP/AUFS server and do a view by date to see what's new.

I suppose I could go one step further and use unsit to uncompress
any StuffIt archives, but I prefer to leave them compressed to
save server disk space.

To get back to your problem though, if you are using a Unix system,
I'd suggest you get a copy of xbin and do your unbinhexing under
Unix.  Uncompressing StuffIt archives on the Mac is easy enough:
just select all the archives you want to uncompress, double click
to launch StuffIt, and hold down the shift key until it starts
uncompressing.

If you're interested in any of the things I mentioned above, the
following caveats apply: the lex Subject parser is still subject
(:-) to periodic tweaking whenever someone posts an article in
some bizarre new format, and I have seen other similar utilities
advertised; the C program that strips out news gunk is trivial
enough that you can probably write it yourself in the time it
would take me to send it to you; and I am unwilling to distribute
patches to xbin without knowing what the most recent general
release of it is.

John



-- 
john j. chew, iii   		  phone: +1 416 425 3818     AppleLink: CDA0329
trigraph, inc., toronto, canada   {uunet!utai!utcsri,utgpu,utzoo}!trigraph!john
dept. of math., u. of toronto     poslfit@{utorgpu.bitnet,gpu.utcs.utoronto.ca}

robinson@prism.gatech.EDU (Stephen M. Robinson) (05/10/89)

First, the method I have been using.  Get "mcvert" from sumex or elsewhere
and use it on your unix box to convert hqx files (it handles part?.hqx
pieces without any intervention) to SIT, PIT, etc bin files.  Download
those binary files with a macbinary xmodem, ftp, etc and then use stuffit's
multiple file unstuffing capability.

Today I wrote the following c-shell "prog" to create "ready to go" binary
files from hqx files.  Problem 1: hqx files have to be joined if they
are in parts.  Problem 2: some icons are not making it on applications; I
don't know why.  Problem 3:  It handles only SIT files.  OF course, you
must have xbin, unsit, unxbin and mcvert from sumex!  Use at your own risk!!  
===cut here====
#!/bin/csh
foreach f ($*)
	echo "Running xbin on file "$f
	xbin $f
	echo "Completed xbin on "$f
	foreach g (*[S,s][I,i][T,t].data)
		echo "Running unsit on file "$g
		unsit $g
		echo "Completed unsit on "$g
		rm -f $g:r.*
	end
	foreach g (*data)
		echo "Running unxbin and mcvert on file "$g
		unxbin $g:r
		mcvert $g:r.hqx
		echo "Completed unxbin and mcvert on file" $g
		rm -f $g:r.data $g:r.info $g:r.rsrc $g:r.hqx
	end
	echo "Completed file "$f
end
echo "Completed all hqx files"
======
Stephen M. Robinson, AI Group, School of Information and Computer Science
Georgia Institute of Technology, Atlanta Georgia, 30332-0280  404-894-8932
uucp:     ...!{allegra,amd,hplabs,ut-ngp}!gatech!prism!robinson
Internet: robinson@prism.gatech.edu
-- 
Stephen M. Robinson, AI Group, School of Information and Computer Science
Georgia Institute of Technology, Atlanta Georgia, 30332-0280  404-894-8932
uucp:     ...!{allegra,amd,hplabs,ut-ngp}!gatech!prism!robinson
Internet: robinson@prism.gatech.edu

chet@arc.UUCP (Chet Wood) (05/10/89)

In article <1333@tellab5.tellabs.CHI.IL.US>, kenk@tellab5 (Ken Konecki) writes:
>here is the source code for a wonderful little program called mcvert.

I got a copy of mcvert a few weeks ago. It is a very good program. But
it would really be nice if it could undecode Stuffit archives. For
instance, last week I downloaded a MacIntosh Technical Note over a
2400 baud link. When I unarchived it, I discovered that it comprised 3
files: a MacWrite, a Word, and a FullWrite version of the same
document. What a waste. If I had a utility to unsit the file on unix,
I could just download what I need. 

In article <39671@bbn.COM>, levin@bbn (Joel B Levin) writes:
>I use xbin, unstuff, and macput on my Sun workstation...

Where does one get these utilities if one doesn't have ftp access? Do
anonymous UUCP archives exist for the Macintosh-related stuff?

Thank you,

Chet Wood                       ~                         (408)727-3357
     arc!chet@apple.COM         .  Advansoft Research Corporation
          chet@arc.UUCP         .       4301 Great America Parkway
               apple!arc!chet   .            Santa Clara, CA 95054, USA

moore@svax.cs.cornell.edu (Doug Moore) (05/10/89)

In article <1333@tellab5.tellabs.CHI.IL.US> kenk@tellab5.UUCP (Ken Konecki) writes:
in praise of mcvert.

Thanks Ken.  Unfortunately, since I gave you permission to post, all the mail
I've sent to you has bounced back to me, which is why I haven't been able to
tell you that:

Mcvert appeared on sumex-aim about a month ago and I quickly learned that
there was a bug affecting Sun 3/60's.  I fixed it and have been unable to
get the update to you.  So I guess I'll get it to you now.  It follows this
message.  You can divide the stuff that follows into four parts, one for
each file updated, and run "patch" on each one to update the source files.

I agree with those who say that it would be nice if mcvert could decode
stuffit archives.  When I wrote it two years ago, Packit was hot and I included
unpacking capability.  Now, I don't have a lot of time for it.  Sorry.  Others
are welcome to improve it as they wish.

If anyone says that it would be nice if mcvert could produce .data, .rsrc and
.info files compatible with macput and macget, I disagree.  It's macput and
macget that should be changed.  But I'm not going to do that anytime soon
either.

Doug Moore (moore@cs.cornell.edu)

mcvert patches

*** Makefile	Wed May 10 00:23:59 1989
--- ../Makefile	Wed Apr 12 13:50:14 1989
***************
*** 1,7 ****
  CSOURCES = mcvert.c hqxify.c unpack.c
  SOURCES = mcvert.c hqxify.c unpack.c mactypes.h Makefile
  OBJECTS = mcvert.o hqxify.o unpack.o
! BIN = /mu/moore/mac/bin
  CFLAGS = -O -DBSD
  
  mcvert: $(OBJECTS)
--- 1,7 ----
  CSOURCES = mcvert.c hqxify.c unpack.c
  SOURCES = mcvert.c hqxify.c unpack.c mactypes.h Makefile
  OBJECTS = mcvert.o hqxify.o unpack.o
! BIN = .
  CFLAGS = -O -DBSD
  
  mcvert: $(OBJECTS)
***************
*** 17,26 ****
  
  clean:
  	rm -f mcvert $(OBJECTS)
- 
- debug:
- 	cc -g -DBSD -o dbvert $(CSOURCES)
- 
- profile:
- 	cc -p $(CFLAGS) -o prvert $(CSOURCES)
- 
--- 17,19 ----
*** hqxify.c	Wed May 10 00:23:54 1989
--- ../hqxify.c	Wed Apr 12 00:39:57 1989
***************
*** 35,41 ****
      hqx_block = (hqx_buf *) buf_ptr;
      hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen);
      hqx_ptr = buf_ptr;
!     hqx_end = (byte *) hqx + sizeof(hqx_header);
      calc_crc = 0;
      while (hqx_ptr < hqx_end)
          calc_crc = (((calc_crc&0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
--- 35,41 ----
      hqx_block = (hqx_buf *) buf_ptr;
      hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen);
      hqx_ptr = buf_ptr;
!     hqx_end = (byte *) hqx + sizeof(hqx_header) - 1;
      calc_crc = 0;
      while (hqx_ptr < hqx_end)
          calc_crc = (((calc_crc&0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
***************
*** 113,118 ****
--- 113,119 ----
  
      /* Create the .hqx file and write the info to it */
      strncpy(hqxfname, info.name, info.nlen);
+ 	hqxfname[info.nlen] = '\0';
      unixify(hqxfname);
      fprintf(verbose,
          "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
***************
*** 120,126 ****
  
      calc_crc = 0;
      hqx_ptr = (byte *) hqx_block;
!     hqx_end = hqx_ptr + 1 + hqx_block->nlen + sizeof(hqx_header);
      while (hqx_ptr < hqx_end)
          calc_crc = (((calc_crc&0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
      calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
--- 121,127 ----
  
      calc_crc = 0;
      hqx_ptr = (byte *) hqx_block;
!     hqx_end = hqx_ptr + hqx_block->nlen + sizeof(hqx_header);
      while (hqx_ptr < hqx_end)
          calc_crc = (((calc_crc&0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
      calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
***************
*** 277,284 ****
              line_ptr = line_start;
              scan_line:
              fast_line = line_ptr;
!             while ((*fast_line++ = tr68[*fast_line]) IS_LEGAL);
!             c = *--fast_line;
              switch (status) {
              case READING:
                  if (c == SKIP && fast_line == line_end) break;
--- 278,285 ----
              line_ptr = line_start;
              scan_line:
              fast_line = line_ptr;
! 			while ((*fast_line = tr68[*fast_line]) IS_LEGAL) fast_line++;
! 			c = *fast_line;
              switch (status) {
              case READING:
                  if (c == SKIP && fast_line == line_end) break;
***************
*** 548,555 ****
  
          calc_crc = bin_to_hqx_fork(hqx_rsrclen);
          write_hqx_crc(calc_crc);
! 
!         *buf_ptr++ = !buf_ptr[-1];      /* To end a run and to get the last */
          empty_hqxbuf();                 /* stray bits, temporarily add a char */
          if (save_state != 2) --line_ptr;
          if (line_ptr == line_end) {
--- 549,556 ----
  
          calc_crc = bin_to_hqx_fork(hqx_rsrclen);
          write_hqx_crc(calc_crc);
! 		*buf_ptr = !buf_ptr[-1];      /* To end a run and to get the last */
! 		buf_ptr++;
          empty_hqxbuf();                 /* stray bits, temporarily add a char */
          if (save_state != 2) --line_ptr;
          if (line_ptr == line_end) {
*** mactypes.h	Wed May 10 00:23:58 1989
--- ../mactypes.h	Tue Apr 11 18:26:49 1989
***************
*** 95,100 ****
--- 95,103 ----
              byte protect;           /* ?Pr??????, don't know what ? bits mean */
              byte dlen[4];           /* Data Fork length (bytes) -   most sig.  */
              byte rlen[4];           /* Resource Fork length         byte first */
+             byte bugblank;             /* to fix obscure sun 3/60 problem
+                                           that always makes sizeof(hqx_header
+                                           even */
              } hqx_header;
  typedef struct {     /* hqx file header buffer (includes file name) */
              byte nlen;              /* Length of filename. */
*** mcvert.c	Wed May 10 00:23:50 1989
--- ../mcvert.c	Tue Apr 11 18:26:55 1989
***************
*** 1,6 ****
! /* mcvert.c - version 1.0 - March 30, 1989
   * Written by Doug Moore - Cornell University - moore@cs.cornell.edu - April '87
   * Sun bug fixes, assorted stuff - Jim Sasaki, March '89
   *
   * This program may be freely distributed for non-profit purposes.  It may not
   * be sold, by itself or as part of a collection of software.  It may be freely
--- 1,9 ----
! /* mcvert.c - version 1.02 - April 11, 1989
   * Written by Doug Moore - Cornell University - moore@cs.cornell.edu - April '87
   * Sun bug fixes, assorted stuff - Jim Sasaki, March '89
+  * Changed default max_line_size from 2000 to unlimited - Doug Moore, April, '89
+  * Sun 3/60 doesn't like odd-sized structs.  Bug fixed - Doug Moore, April, '89
+  *                                              - aided by Spencer W. Thomas
   *
   * This program may be freely distributed for non-profit purposes.  It may not
   * be sold, by itself or as part of a collection of software.  It may be freely
***************
*** 41,47 ****
      if ((text_author = getenv("MAC_EDITOR"))    == NULL)    text_author = "MACA";
      if ((ext =         getenv("MAC_EXT"))       == NULL)    ext = ".bin";
      if ((dir =         getenv("MAC_DLOAD_DIR")) == NULL)    dir = ".";
!     if ((maxlines_str = getenv("MAC_LINE_LIMIT")) == NULL)  maxlines = 2000;
      else										 maxlines = atoi(maxlines_str);
      
      /* Make command line arguments globally accessible */
--- 44,50 ----
      if ((text_author = getenv("MAC_EDITOR"))    == NULL)    text_author = "MACA";
      if ((ext =         getenv("MAC_EXT"))       == NULL)    ext = ".bin";
      if ((dir =         getenv("MAC_DLOAD_DIR")) == NULL)    dir = ".";
!     if ((maxlines_str = getenv("MAC_LINE_LIMIT")) == NULL)  maxlines = 0;
      else										 maxlines = atoi(maxlines_str);
      
      /* Make command line arguments globally accessible */

okamoto@hpccc.HP.COM (Jeff Okamoto) (05/11/89)

kenk@tellab5.tellabs.CHI.IL.US (Ken Konecki) writes:

> so here is the source code for a wonderful little program called
> mcvert. It is a mac<->unix file converter...

> /* mcvert.c - version 1.0 - March 30, 1989

The latest version on wsmr-simtel20.army.mil (or sumex-aim.stanford.edu,
I don't remember which one) is version 1.02, dated April 11, 1989.  I
don't know what differences there are between the two versions.

-- 
 \      oo	The New Number Who,
  \____|\mm	Jeff Okamoto
  //_//\ \_\	HP Corporate Computing Center
 /K-9/  \/_/	okamoto%hpccc@hplabs.hp.com
/___/_____\	..!hplabs!hpccc!okamoto
-----------	(415) 857-6236

Bernard.Aboba@f444.n204.z1.FIDONET.ORG (Bernard Aboba) (05/15/89)

I have the OPPOSITE request:
I'm looking for a MASS STUFFING AND BINHEXING PROGRAM!
 
This is a major bane for sysops like myself who have to continuously 
stuff large numbers of files.



--  
-------------------------------------------------------------
FidoNet:  1:161/445      UUCP: sun!apple!bmug!<User.Name>
INTERNET:  bmug!<User.Name>@apple.COM or <User.Name>@bmug.fidonet.org
USNAIL:   BMUG, 1442A Walnut St. #62, Berkeley, CA 94709-1496
-------------------------------------------------------------
BMUG Newsletter articles due June 15!  Authors get free membership.
Send articles to:  pub@bmug.fidonet.org

postmaster@mailcom.FIDONET.ORG (Bernard Aboba) (05/15/89)

I have the OPPOSITE request:
I'm looking for a MASS STUFFING AND BINHEXING PROGRAM!
 
This is a major bane for sysops like myself who have to continuously 
stuff large numbers of files.



--  
Sometimes when I've got the blues,
And woo the shape I'm in,
At least I'm not
A tubby crooner with a voice of tin.
== From "Elvis didn't die(t) in vain"
Via  apple!mailcom, Jailhouse Rock BBS, Fido 1:204/444