[net.sources.mac] unxbin - convert .{info,data,rsrc} to .Hqx

unilog@g.cs.cmu.edu.UUCP (07/14/86)

[Go ahead, eat my line.]

Here's a improved version of unxbin which was first posted to this group
last year.  I've lost the name of the original poster so I'll thank him
here.

This version is a complete rewrite.  The original was a series of small
programs run by a shell script.  This new version is a C program with
several improvements (besides speed), notably run-length compression.

There's no man page, but usage is straight-forward.  Assuming fred.info,
fred.data, and fred.rsrc exist, typing "unxbin fred" produces fred.Hqx.  The
program will warn you if any of the files are missing but should do the
right thing.

Hope this is useful.  Please let me know of any bugs you find or
improvements you make.

						Dave Gentzel
						Unilogic, Ltd.
						unilog@g.cs.cmu.edu
						allegra!seismo!cmu-cs-g!unilog
-------- Oh!  Oh!  Cut me!  Please! --------
#! /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:
#	Makefile
#	unxbin.c
#	8to6.c
#	crc.c
#	gethead.c
#	run.c
# This archive created: Mon Jul 14 01:55:11 1986
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Makefile'" '(305 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
XCFLAGS=	-O -Dstrrchr=rindex
XLFLAGS=
XCFILES=	unxbin.c gethead.c crc.c run.c 8to6.c
XOFILES=	unxbin.o gethead.o crc.o run.o 8to6.o
X
Xunxbin:	$(OFILES)
X	cc -o unxbin $(OFILES)
X
Xunxbin.o:	Makefile
Xgethead.o:	Makefile
X
Xdebug:
X	cc -o unxbind -g $(CFILES)
X
Xlint:
X	lint $(LFLAGS) $(CFILES)
X
Xclean:
X	rm -f $(OFILES)
SHAR_EOF
if test 305 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 305 characters)'
fi
fi
echo shar: "extracting 'unxbin.c'" '(3174 characters)'
if test -f 'unxbin.c'
then
	echo shar: "will not over-write existing file 'unxbin.c'"
else
sed 's/^X//' << \SHAR_EOF > 'unxbin.c'
X/*
X * unxbin -- convert files generated by xbin or macget into BinHex 4.0 format.
X *
X * David Gentzel, Lexeme Corporation
X *
X * (c) 1985 David Gentzel
X * may be used but not sold without permission
X *
X * This is based on a Unix(tm) program with the same name and function written
X * by ????.  Original was a series of small programs (8to6, crc, etc.) piped
X * together and run by a shell script.  I completely rewrote the system as a
X * C program (speeding it up considerably, needless to say), added run-length
X * compression, and bullet-proofed (at least partly) the thing.  Unfortunately,
X * I have lost the name of the original poster (to net.sources.mac) without
X * whom this would never have appeared.
X *
X * created dbg 09/10/85 -- Version 1.0
X */
X
X#include <stdio.h>
X
X#ifdef VMS
X# define PROGRAMNAME	"unxbin"
X# define EXIT_ERROR	((1 << 28) | 2)
X# ifndef MAXNAMLEN
X#  define MAXNAMLEN	127
X#  define MAXBASENAME	63
X# endif
X#else
X# include <sys/types.h>
X# include <sys/dir.h>
X# define PROGRAMNAME	(argv[0])
X# define EXIT_ERROR	1
X# ifndef MAXNAMLEN
X#  ifdef DIRSIZ
X#   define MAXNAMLEN	DIRSIZ
X#  else
X#   define MAXNAMLEN	14
X#  endif
X# endif
X# define MAXBASENAME	(MAXNAMLEN - 2)
X#endif
X
Xextern char *sprintf(), *strrchr();
Xextern void gethead(), fakehead(), make_buffer_crc(), make_file_crc(),
X	    putchar_run();
X
Xmain(argc, argv)
Xint argc;
Xregister char *argv[];
X{
X    register FILE *rsrc, *data, *info;
X    char fbuf[256], infobuf[128];
X    register char *file;
X
X    if (argc != 2)
X    {
X	fprintf(stderr, "Usage: %s file\n", PROGRAMNAME);
X	exit(EXIT_ERROR);
X    }
X#ifdef VMS
X    if ((file = strrchr(argv[1], ']')) == NULL)
X	file = strrchr(argv[1], ':');
X#else
X    file = strrchr(argv[1], '/');
X#endif
X    if (file)
X	file++;
X    else
X	file = argv[1];
X    if (strlen(file) > MAXBASENAME)
X	file[MAXBASENAME] = '\0';
X    file = argv[1];
X    (void) sprintf(fbuf, "%s.rsrc", file);
X    fbuf[MAXNAMLEN] = '\0';
X    rsrc = fopen(fbuf, "r");
X    (void) sprintf(fbuf, "%s.data", file);
X    fbuf[MAXNAMLEN] = '\0';
X    data = fopen(fbuf, "r");
X    if (rsrc == NULL && data == NULL)
X    {
X	fprintf(stderr, "No resource or data forks for %s\n", argv[1]);
X	exit(EXIT_ERROR);
X    }
X    if (rsrc == NULL)
X	fprintf(stderr, "Warning: no resource file %s\n", fbuf);
X    if (data == NULL)
X	fprintf(stderr, "Warning: no data file %s\n", fbuf);
X    (void) sprintf(fbuf, "%s.info", file);
X    fbuf[MAXNAMLEN] = '\0';
X    info = fopen(fbuf, "r");
X    if (info == NULL)
X	fprintf(stderr, "Warning: no info file %s\n", fbuf);
X    (void) sprintf(fbuf, "%s.Hqx", file);
X    fbuf[MAXNAMLEN] = '\0';
X    if (freopen(fbuf, "w", stdout) == NULL)
X    {
X	fputs("Couldn't open output file.\n", stderr);
X	exit(EXIT_ERROR);
X    }
X    puts("(This file must be converted with BinHex 4.0)\n:");
X    if (info != NULL)
X    {
X	(void) fread(fbuf, 128, 1, info);
X	(void) fclose(info);
X	gethead(fbuf, infobuf);
X    }
X    else
X	fakehead(file, rsrc, data, infobuf);
X    make_buffer_crc(infobuf, 20 + infobuf[0]);
X    make_file_crc(data);
X    if (data != NULL)
X	(void) fclose(data);
X    make_file_crc(rsrc);
X    if (rsrc != NULL)
X	(void) fclose(rsrc);
X    putchar_run(EOF);
X    puts(":");
X    (void) fclose(stdout);
X}
SHAR_EOF
if test 3174 -ne "`wc -c < 'unxbin.c'`"
then
	echo shar: "error transmitting 'unxbin.c'" '(should have been 3174 characters)'
fi
fi
echo shar: "extracting '8to6.c'" '(1210 characters)'
if test -f '8to6.c'
then
	echo shar: "will not over-write existing file '8to6.c'"
else
sed 's/^X//' << \SHAR_EOF > '8to6.c'
X/*
X * convert 8 bit data stream into 6 bit data stream
X *
X * David Gentzel, Lexeme Corporation
X */
X
X#include <stdio.h>
X
X#define MAXLINELEN	62
X
Xstatic
Xchar tr[]="!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
X
X/*
X * Output a character to the current output file converting from 8 bit to 6 bit
X * representation.  When called with EOF, flush all pending output.
X */
Xvoid putchar_6(c)
Xint c;
X{
X    static unsigned char buf[3];
X    static unsigned int num_bytes = 0;
X
X    if (c == EOF)	/* flush buffer on EOF */
X    {
X	while (num_bytes != 0)
X	    putchar_6(0);
X	return;
X    }
X
X    buf[num_bytes++] = c;
X    if (num_bytes == 3)
X    {
X	static count = 1;	/* # of characters on current line */
X				/* start at 1 to include colon */
X
X	num_bytes = 0;
X	putchar(tr[buf[0] >> 2]);
X	if (count++ > MAXLINELEN)
X	{
X	    count = 0;
X	    putchar('\n');
X	}
X	putchar(tr[((buf[0] & 0x03) << 4) | (buf[1] >> 4)]);
X	if (count++ > MAXLINELEN)
X	{
X	    count = 0;
X	    putchar('\n');
X	}
X	putchar(tr[((buf[1] & 0x0F) << 2) | (buf[2] >> 6)]);
X	if (count++ > MAXLINELEN)
X	{
X	    count = 0;
X	    putchar('\n');
X	}
X	putchar(tr[buf[2] & 0x3F]);
X	if (count++ > MAXLINELEN)
X	{
X	    count = 0;
X	    putchar('\n');
X	}
X    }
X}
SHAR_EOF
if test 1210 -ne "`wc -c < '8to6.c'`"
then
	echo shar: "error transmitting '8to6.c'" '(should have been 1210 characters)'
fi
fi
echo shar: "extracting 'crc.c'" '(1488 characters)'
if test -f 'crc.c'
then
	echo shar: "will not over-write existing file 'crc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'crc.c'
X/*
X * compute the crc used in .hqx files for unxbin
X *
X * David Gentzel, Lexeme Corporation
X *
X * Based on crc code in xbin.c by Darin Adler of TMQ Software.
X */
X
X#include <stdio.h>
X
X#define BYTEMASK	0xFF
X#define WORDMASK	0xFFFF
X#define WORDBIT		0x10000
X
X#define CRCCONSTANT	0x1021
X
Xstatic unsigned int crc;
X
Xextern void putchar_run();
X
X/*
X * Update the crc.
X */
Xstatic void docrc(c)
Xregister unsigned int c;
X{
X    register int i;
X    register unsigned long temp = crc;
X
X    for (i = 0; i < 8; i++)
X    {
X	c <<= 1;
X	if ((temp <<= 1) & WORDBIT)
X	    temp = (temp & WORDMASK) ^ CRCCONSTANT;
X	temp ^= (c >> 8);
X	c &= BYTEMASK;
X    }
X    crc = temp;
X}
X
X/*
X * Copy all characters from file in to the current output file computing a crc
X * as we go.  Append 2 byte crc to the output.  in may be NULL (empty file).
X */
Xvoid make_file_crc(in)
Xregister FILE *in;
X{
X    register int c;
X
X    crc = 0;
X    if (in != NULL)
X	while ((c = getc(in)) != EOF)
X	{
X	    putchar_run(c);
X	    docrc(c);
X	}
X    docrc(0);
X    docrc(0);
X    putchar_run((crc >> 8) & BYTEMASK);
X    putchar_run(crc & BYTEMASK);
X}
X
X/*
X * Copy count characters from buffer in to the current output file computing a
X * crc as we go.  Append 2 byte crc to the output.
X */
Xvoid make_buffer_crc(in, count)
Xregister unsigned char *in;
Xregister int count;
X{
X    crc = 0;
X    while (count--)
X    {
X	putchar_run(*in);
X	docrc(*in++);
X    }
X    docrc(0);
X    docrc(0);
X    putchar_run((crc >> 8) & BYTEMASK);
X    putchar_run(crc & BYTEMASK);
X}
SHAR_EOF
if test 1488 -ne "`wc -c < 'crc.c'`"
then
	echo shar: "error transmitting 'crc.c'" '(should have been 1488 characters)'
fi
fi
echo shar: "extracting 'gethead.c'" '(3031 characters)'
if test -f 'gethead.c'
then
	echo shar: "will not over-write existing file 'gethead.c'"
else
sed 's/^X//' << \SHAR_EOF > 'gethead.c'
X/*
X * Change a .info file into a proper header for a .hqx file
X *
X * David Gentzel, Lexeme Corporation
X *
X * Based on code written by ????.
X */
X
X#include <stdio.h>
X#ifdef VMS
X# include <types.h>
X# include <stat.h>
X#else
X# include <sys/types.h>
X# include <sys/stat.h>
X#endif
X
X#define NAMEBYTES 63
X#define H_NLENOFF 1
X#define H_NAMEOFF 2
X
X/* 65 <-> 80 is the FInfo structure */
X#define H_TYPEOFF 65
X#define H_AUTHOFF 69
X#define H_FLAGOFF 73
X
X#define H_LOCKOFF 81
X#define H_DLENOFF 83
X#define H_RLENOFF 87
X#define H_CTIMOFF 91
X#define H_MTIMOFF 95
X
X/* Append cnt bytes to the output buffer starting at head[offset]. */
X#define put(cnt, offset) \
X{ \
X    register char *a = &head[(int) offset]; \
X    register int b = (int) (cnt); \
X \
X    while (b--) \
X	*out++ = *a++; \
X}
X
X/* Build a usable header out of the .info information.  head is the text from
X   the .info file, out is an output buffer. */
Xvoid gethead(head, out)
Xregister char *head, *out;
X{
X    put(1, H_NLENOFF);		/* Name length */
X    put(head[1], H_NAMEOFF);	/* Name */
X    put(1, 0);			/* NULL */
X    put(4, H_TYPEOFF);		/* Type */
X    put(4, H_AUTHOFF);		/* Author */
X    put(2, H_FLAGOFF);		/* Flags */
X    put(4, H_DLENOFF);		/* Data length */
X    put(4, H_RLENOFF);		/* Resource length */
X}
X
X/* Append cnt bytes to the output buffer starting at string. */
X#define put2(cnt, string) \
X{ \
X    register int b = (int) (cnt); \
X    register char *a = (char *) (string); \
X \
X    while (b--) \
X	*out++ = *a++; \
X}
X
X/* Append cnt bytes to the output buffer starting at string + (cnt - 1) and
X   working backwards. */
X#define put2rev(cnt, string) \
X{ \
X    register int b = (int) (cnt); \
X    register char *a = (char *) (string) + b; \
X \
X    while (b--) \
X	*out++ = *--a; \
X}
X
X/* Fake a usable header (there was no .info file). */
X/* VMS NOTE:
X	It is possible that the use of fstat to figure the sizes of the
X	.data and .rsrc files will not work correctly if they are not
X	Stream_LF files.  Not easy to get around, but not very common either
X	(will only cause problem if .info file is missing and either .data
X	or .rsrc is not Stream_LF, and xbin creates Stream_LF files).
X*/
Xvoid fakehead(file, rsrc, data, out)
Xchar *file;
XFILE *rsrc, *data;
Xregister char *out;
X{
X    unsigned char flen;
X    long rlen, dlen;
X    char flags[2];
X    struct stat st;
X
X    flen = (unsigned char) strlen(file);
X    if (rsrc != NULL)
X    {
X	(void) fstat(fileno(rsrc), &st);
X	rlen = (long) st.st_size;
X    }
X    else
X	rlen = 0L;
X    if (data != NULL)
X    {
X	(void) fstat(fileno(data), &st);
X	dlen = (long) st.st_size;
X    }
X    else
X	dlen = 0L;
X    flags[0] = '\0';
X    flags[1] = '\0';
X
X    put2(1, &flen);		/* Name length */
X    put2(flen, file);		/* Name */
X    put2(1, "");		/* NULL */
X    put2(4, "TEXT");		/* Type */
X    put2(4, "????");		/* Author */
X    put2(2, flags);		/* Flags */
X#ifdef DONTSWAPINT
X    put2(4, dlen);		/* Data length */
X    put2(4, rlen);		/* Resource length */
X#else
X    put2rev(4, dlen);		/* Data length */
X    put2rev(4, rlen);		/* Resource length */
X#endif
X}
SHAR_EOF
if test 3031 -ne "`wc -c < 'gethead.c'`"
then
	echo shar: "error transmitting 'gethead.c'" '(should have been 3031 characters)'
fi
fi
echo shar: "extracting 'run.c'" '(1175 characters)'
if test -f 'run.c'
then
	echo shar: "will not over-write existing file 'run.c'"
else
sed 's/^X//' << \SHAR_EOF > 'run.c'
X/*
X * do run length compression for unxbin
X *
X * David Gentzel, Lexeme Corporation
X */
X
X#include <stdio.h>
X
X#define RUNCHAR	0x90
X#define MAXREP	255
X
Xextern void putchar_6();
X
X/*
X * Output a character to the current output file generating run length
X * compression on the fly.  All output goes through putchar_6 to do conversion
X * from 8 bit to 6 bit format.  When c == EOF, call putchar_6 with EOF to flush
X * pending output.
X */
Xvoid putchar_run(c)
Xregister int c;
X{
X    static unsigned int rep = 1;	/* # of repititions of lastc seen */
X    static int lastc = EOF;		/* last character passed to us */
X
X    if (c == lastc)	/* increment rep */
X    {
X	/* repetition count limited to MAXREP */
X	if (++rep == MAXREP)
X	{
X	    putchar_6(RUNCHAR);
X	    putchar_6(MAXREP);
X	    rep = 1;
X	    lastc = EOF;
X	}
X    }
X    else
X    {
X	switch (rep)
X	{
X	    case 2:	/* not worth running for only 2 reps... */
X		putchar_6(lastc);
X		if (lastc == RUNCHAR)
X		    putchar_6(0);
X		break;
X	    case 1:
X		break;
X	    default:
X		putchar_6(RUNCHAR);
X		putchar_6(rep);
X		break;
X	}
X	putchar_6(c);	/* output character (EOF flushes) */
X	rep = 1;
X	if (c == RUNCHAR)
X	    putchar_6(0);
X	lastc = c;
X    }
X}
SHAR_EOF
if test 1175 -ne "`wc -c < 'run.c'`"
then
	echo shar: "error transmitting 'run.c'" '(should have been 1175 characters)'
fi
fi
exit 0
#	End of shell archive