[net.sources.mac] Program for unpacking PackIt files

weber@brand.UUCP (Allan G. Weber) (01/25/86)

-------------------------- cut here ---------------------------------
/*

		unpit - Macintosh PackIt file unpacker

This program will unpack a Macintosh PackIt file into separate files.  The
data fork of a PackIt file contains both the data and resource forks of the
packed files.  The program will unpack each Mac file into separate .data,
.rsrc., and .info files that can be downloaded to a Mac using macput.

The program syntax is much like macput/macget:

	unpit [-rdu] packit-file.data

The  -r and -d flags will cause only the resource and data forks to be
written.  The -u flag will cause only the data fork to be written and
to have carriage return characters changed to Unix newline characters.

Some of the program is borrowed from the macput.c/macget.c programs.

	Author: Allan G. Weber, (Weber%Brand@USC-ECL)		
	Date:   September 30, 1985
	Revised: January 24, 1986 - added CRC checking
/*
/*
Format of a Packit file:

Repeat the following sequence for each file in the Packit file:

	96 byte header (see struct pit_header below)
	2 bytes CRC number
	data fork (length from header)
	resource fork (length from header)
	2 bytes CRC number

Last file is followed by the 4 byte Ascii string, "Pend", and then the EOF.

*/

/* #define DEBUG */

#include <stdio.h>

typedef char byte;
typedef short word;

struct pit_header {	/* Packit file header (92 bytes)
	byte id[4];	/* "PMag" */
	byte nlen;	/* number of characters in packed file name */
	byte name[63];	/* name of packed file */
	byte type[4];	/* file type */
	byte auth[4];	/* file creator */
	word flags;	/* file flags (?) */
	word lock;	/* unknown */
	long dlen;	/* number of bytes in data fork */
	long rlen;	/* number of bytes in resource fork */
	long ctim;	/* file creation time */
	long mtim;	/* file modified time */
};

#define HDRBYTES  96
#define INFOBYTES 128

#define BYTEMASK 0xff

#define H_NAMELEN 63

#define H_NLENOFF 4
#define H_NAMEOFF 5
#define H_TYPEOFF 68
#define H_AUTHOFF 72
#define	H_LOCKOFF 74
#define H_FLAGOFF 76
#define H_DLENOFF 80
#define H_RLENOFF 84
#define H_CTIMOFF 88
#define H_MTIMOFF 92

#define I_NAMELEN 69	/* H_NAMELEN + strlen(".info") + 1 */

/* The following are copied out of macput.c/macget.c */
#define I_NLENOFF 1
#define I_NAMEOFF 2
/* 65 <-> 80 is the FInfo structure */
#define I_TYPEOFF 65
#define I_AUTHOFF 69
#define I_FLAGOFF 73
#define I_LOCKOFF 81
#define I_DLENOFF 83
#define I_RLENOFF 87
#define I_CTIMOFF 91
#define I_MTIMOFF 95

#define TEXT 0
#define DATA 1
#define RSRC 2
#define FULL 3

char f_info[I_NAMELEN];
char f_data[I_NAMELEN];
char f_rsrc[I_NAMELEN];

char hdr[HDRBYTES];
char info[INFOBYTES];
char text[H_NAMELEN+1];

int mode, txtmode;
int datalen, rsrclen;

char usage[] = "usage: unpit [-rdu] filename\n";

main(ac, av)
int ac;
char **av;
{
	char temp[4], *name;
	int crc, data_crc;

	mode = FULL;
	name = "";
	ac--; av++;
	while (ac) {
		if (av[0][0] == '-') {
			switch (av[0][1]) {
			case 'r':
				mode = RSRC;
				break;
			case 'd':
				mode = DATA;
				break;
			case 'u':
				mode = TEXT;
				break;
			case '\0':
				name = av[0];
				break;
			default:
				fprintf(stderr, usage);
				exit(1);
			}
		}
		else {
			name = av[0];
		}
		ac--; av++;
	}

	if (strlen(name) == 0) {
		fprintf(stderr, usage);
		exit(1);
	}
	else {
		if (freopen(name,"r",stdin) == NULL) {
			fprintf(stderr,"Can't open input file \"%s\"\n",name);
			exit(1);
		}
	}

	while (1) {
		fread(temp, 1, 4, stdin);
		if (strncmp(temp, "PMag", 4) == 0) {
			data_crc = read_hdr();
			crc = getcrc();
			if (crc != data_crc) {
				fprintf(stderr, "File header CRC mismatch\n");
				exit(1);
			}
			txtmode = (mode == TEXT);
			data_crc = write_file(f_data, datalen, 0);
			txtmode = 0;
			data_crc = write_file(f_rsrc, rsrclen, data_crc);
			crc = getcrc();
			if (crc != data_crc) {
				fprintf(stderr,
					"File data/rsrc CRC mismatch\n");
				exit(1);
			}
		}
		else if (strncmp(temp, "PEnd", 4) == 0)
			break;
		else {
			fprintf(stderr, "Bad Packit file\n");
			exit(1);
		}
	}
}

read_hdr()
{
	long get4();
	register int i, n, crc;
	FILE *fp;
	char *np;

	for (n = 0; n < INFOBYTES; n++)
		info[n] = '\0';

	fread(hdr+4, 1, HDRBYTES-4, stdin);
	crc = 0;
	for (n = 0; n < HDRBYTES; n++) {
		crc = crc ^ ((int)hdr[n] << 8);
		for (i = 0; i < 8; i++)
			if (crc & 0x8000)
				crc = (crc << 1) ^ 0x1021;
			else
				crc <<= 1;
	}

	n = hdr[H_NLENOFF] & BYTEMASK;
	if (n > H_NAMELEN)
		n = H_NAMELEN;
	info[I_NLENOFF] = n;
	copy(info + I_NAMEOFF, hdr + H_NAMEOFF, n);
	strncpy(text, hdr + H_NAMEOFF, n);
	text[n] = '\0';
	for (np = text; *np; np++)
		if (*np == ' ' || *np == '/')
			*np = '_';
	datalen = get4(hdr + H_DLENOFF);
	rsrclen = get4(hdr + H_RLENOFF);
#ifdef DEBUG
	printf("type=%4.4s, author=%4.4s, data=%ld, rsrc=%ld\n",
	hdr + H_TYPEOFF, hdr + H_AUTHOFF, datalen, rsrclen);
#endif
	if (mode == FULL) {
		sprintf(f_info, "%s.info", text);
		sprintf(f_data, "%s.data", text);
		sprintf(f_rsrc, "%s.rsrc", text);

		copy(info + I_TYPEOFF, hdr + H_TYPEOFF, 4);
		copy(info + I_AUTHOFF, hdr + H_AUTHOFF, 4);
		copy(info + I_FLAGOFF, hdr + H_FLAGOFF, 2);
		copy(info + I_LOCKOFF, hdr + H_LOCKOFF, 2);
		copy(info + I_DLENOFF, hdr + H_DLENOFF, 4);
		copy(info + I_RLENOFF, hdr + H_RLENOFF, 4);
		copy(info + I_CTIMOFF, hdr + H_CTIMOFF, 4);
		copy(info + I_MTIMOFF, hdr + H_MTIMOFF, 4);

		fp = fopen(f_info, "w");
		if (fp == NULL) {
			perror(f_info);
			exit(1);
		}
		fwrite(info, 1, INFOBYTES, fp);
		fclose(fp);
	}
	else if (mode == RSRC) {
			sprintf(f_data, "/dev/null");
			sprintf(f_rsrc, "%s.rsrc", text);
	}
	else {
			sprintf(f_data, "%s", text);
			sprintf(f_rsrc, "/dev/null");
	}
	return(crc & 0xffff);
}

write_file(fname, bytes, crc)
char *fname;
long bytes;
register int crc;
{
	register int b, i;
	FILE *outf;

	outf = fopen(fname, "w");
	if (outf == NULL) {
		perror(fname);
		exit(1);
	}
	while (bytes-- > 0) {
		b = getc(stdin);
		crc = crc ^ (b << 8);
		for (i = 0; i < 8; i++)
			if (crc & 0x8000)
				crc = (crc << 1) ^ 0x1021;
			else
				crc <<= 1;
		if (txtmode && (b & BYTEMASK) == '\r')
			b = '\n';
		putc(b, outf);
	}
	fclose(outf);
	return(crc & 0xffff);
}

long
get4(bp)
char *bp;
{
	register int i;
	long value = 0;

	for (i = 0; i < 4; i++) {
		value <<= 8;
		value |= (*bp & BYTEMASK);
		bp++;
	}
	return(value);
}

getcrc()
{
	int value;
	value = getc(stdin) & BYTEMASK;
	return( value << 8 | (getc(stdin) & BYTEMASK) );
}

copy(p1, p2, n)
char *p1, *p2;
int n;
{
	while (n-- > 0)
		*p1++ = *p2++;
}
--------------------- end ------------------------------

bart@reed.UUCP (Bart Massey) (01/28/86)

	Thank You, Thank You, THANK YOU for this one, Mr. Weber!  I at
least greatly appreciate it!

					Bart Massey
					..tektronix!reed!bart