mirror of
https://github.com/wnayes/macutils.git
synced 2025-01-10 16:29:18 +00:00
1041 lines
24 KiB
C
1041 lines
24 KiB
C
#include "macunpack.h"
|
|
#ifdef DD
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "globals.h"
|
|
#include "dd.h"
|
|
#include "crc.h"
|
|
#include "../fileio/machdr.h"
|
|
#include "../fileio/wrfile.h"
|
|
#include "../fileio/fileglob.h"
|
|
#include "../util/masks.h"
|
|
#include "../util/util.h"
|
|
|
|
extern void cpt_wrfile1();
|
|
extern void core_compress();
|
|
extern void de_compress();
|
|
|
|
static void dd_name();
|
|
static int dd_filehdr();
|
|
static void dd_cfilehdr();
|
|
static int dd_valid();
|
|
static int dd_valid1();
|
|
static char *dd_methname();
|
|
static unsigned long dd_checksum();
|
|
static void dd_chksum();
|
|
static unsigned long dd_checkor();
|
|
static void dd_do_delta();
|
|
static void dd_delta();
|
|
static void dd_delta3();
|
|
static void dd_copy();
|
|
static void dd_copyfile();
|
|
static void dd_expand();
|
|
static void dd_expandfile();
|
|
static void dd_nocomp();
|
|
static void dd_lzc();
|
|
#ifdef UNTESTED
|
|
static void dd_rle();
|
|
#ifdef NOTIMPLEMENTED
|
|
static void dd_huffman();
|
|
#endif /* NOTIMPLEMENTED */
|
|
static void dd_lzss();
|
|
static int dd_getbits();
|
|
#endif /* UNTESTED */
|
|
static void dd_cpt_compat();
|
|
|
|
typedef struct methodinfo {
|
|
char *name;
|
|
int number;
|
|
} methodinfo;
|
|
|
|
static struct methodinfo methods[] = {
|
|
{"NoComp", nocomp},
|
|
{"LZC", lzc},
|
|
{"???", method2},
|
|
{"RLE", rle},
|
|
{"Huffman", huffman},
|
|
{"???", method5},
|
|
{"???", method6},
|
|
{"LZSS", lzss},
|
|
{"RLE/LZH", cpt_compat},
|
|
{"???", method9},
|
|
};
|
|
static unsigned char *dd_archive;
|
|
static unsigned char *dd_data_ptr;
|
|
static int dd_archive_size;
|
|
static int dd_max_archive_size;
|
|
static unsigned char *dd_dirst;
|
|
static int dd_dirstptr;
|
|
static int dd_dirstmax;
|
|
static int dd_xor;
|
|
static long dd_bitbuf;
|
|
static int dd_bitcount;
|
|
static unsigned char *dd_bitptr;
|
|
static char dd_LZbuff[2048];
|
|
|
|
void dd_file(bin_hdr)
|
|
unsigned char *bin_hdr;
|
|
{
|
|
unsigned long data_size;
|
|
int i;
|
|
struct fileCHdr cf;
|
|
char ftype[5], fauth[5];
|
|
|
|
updcrc = binhex_updcrc;
|
|
crcinit = binhex_crcinit;
|
|
dd_name(bin_hdr);
|
|
for(i = 0; i < INFOBYTES; i++) {
|
|
info[i] = bin_hdr[i];
|
|
}
|
|
transname(info + I_NAMEOFF + 1, text, (int)info[I_NAMEOFF] & BYTEMASK);
|
|
data_size = get4(info + I_DLENOFF);
|
|
if(data_size > dd_max_archive_size) {
|
|
if(dd_max_archive_size == 0) {
|
|
dd_archive = (unsigned char *)malloc((unsigned)data_size);
|
|
} else {
|
|
dd_archive = (unsigned char *)realloc((char *)dd_archive,
|
|
(unsigned)data_size);
|
|
}
|
|
dd_max_archive_size = data_size;
|
|
if(dd_archive == NULL) {
|
|
(void)fprintf(stderr, "Insufficient memory.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
dd_archive_size = data_size;
|
|
if(fread((char *)dd_archive, 1, (int)data_size, infp) != data_size) {
|
|
(void)fprintf(stderr, "Premature EOF\n");
|
|
#ifdef SCAN
|
|
do_error("Premature EOF");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
dd_data_ptr = dd_archive;
|
|
dd_cfilehdr(&cf);
|
|
write_it = 1;
|
|
if(list) {
|
|
do_indent(indent);
|
|
transname(info + I_TYPEOFF, ftype, 4);
|
|
transname(info + I_AUTHOFF, fauth, 4);
|
|
(void)fprintf(stderr,
|
|
"name=\"%s\", type=%4.4s, author=%4.4s, data=%ld, rsrc=%ld",
|
|
text, ftype, fauth,
|
|
(long)get4(info + I_DLENOFF), (long)get4(info + I_RLENOFF));
|
|
if(info_only) {
|
|
write_it = 0;
|
|
}
|
|
if(query) {
|
|
write_it = do_query();
|
|
} else {
|
|
(void)fputc('\n', stderr);
|
|
}
|
|
}
|
|
if(!dd_valid((int)cf.datamethod, (int)cf.rsrcmethod)) {
|
|
(void)fprintf(stderr, "\tUnimplemented method found: %d %d\n",
|
|
cf.datamethod, cf.rsrcmethod);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Unimplemented method found");
|
|
#endif /* SCAN */
|
|
return;
|
|
}
|
|
|
|
if(write_it) {
|
|
define_name(text);
|
|
}
|
|
if(write_it || list) {
|
|
dd_expand(cf, dd_data_ptr);
|
|
}
|
|
}
|
|
|
|
void dd_arch(bin_hdr)
|
|
unsigned char *bin_hdr;
|
|
{
|
|
unsigned long data_size;
|
|
unsigned long crc, filecrc;
|
|
struct fileHdr f;
|
|
struct fileCHdr cf;
|
|
char locname[64];
|
|
int i, nlength;
|
|
|
|
updcrc = binhex_updcrc;
|
|
crcinit = binhex_crcinit;
|
|
data_size = get4((char *)bin_hdr + I_DLENOFF);
|
|
if(data_size > dd_max_archive_size) {
|
|
if(dd_max_archive_size == 0) {
|
|
dd_archive = (unsigned char *)malloc((unsigned)data_size);
|
|
} else {
|
|
dd_archive = (unsigned char *)realloc((char *)dd_archive,
|
|
(unsigned)data_size);
|
|
}
|
|
dd_max_archive_size = data_size;
|
|
}
|
|
dd_archive_size = data_size;
|
|
if(fread((char *)dd_archive, 1, (int)data_size, infp) != data_size) {
|
|
(void)fprintf(stderr, "Insufficient memory.\n");
|
|
exit(1);
|
|
}
|
|
dd_name(bin_hdr);
|
|
nlength = bin_hdr[I_NAMEOFF];
|
|
for(i = 0; i < INFOBYTES; i++) {
|
|
info[i] = 0;
|
|
}
|
|
info[I_NAMEOFF] = nlength;
|
|
for(i = 1; i <= nlength; i++) {
|
|
info[I_NAMEOFF + i] = bin_hdr[I_NAMEOFF + i];
|
|
}
|
|
transname(info + I_NAMEOFF + 1, text, nlength);
|
|
(void)strcpy(locname, text);
|
|
if(list) {
|
|
do_indent(indent);
|
|
(void)fprintf(stderr, "folder=\"%s\"", text);
|
|
if(query) {
|
|
if(!do_query()) {
|
|
return;
|
|
}
|
|
} else {
|
|
(void)fputc('\n', stderr);
|
|
}
|
|
indent++;
|
|
}
|
|
if(!info_only) {
|
|
do_mkdir(text, info);
|
|
}
|
|
|
|
if(strncmp((char *)dd_archive, "DDAR", 4)) {
|
|
(void)fprintf(stderr, "Magic archive header error\n");
|
|
#ifdef SCAN
|
|
do_error("macunpack: Magic archive header error");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
crc = (*updcrc)(crcinit, dd_archive, ARCHHDRSIZE - 2);
|
|
filecrc = get2((char *)dd_archive + ARCHHDRCRC);
|
|
if(crc != filecrc) {
|
|
(void)fprintf(stderr, "Header CRC mismatch: got 0x%02x, need 0x%02x\n",
|
|
(int)crc, (int)filecrc);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Header CRC mismatch");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
dd_data_ptr = dd_archive + ARCHHDRSIZE;
|
|
while(dd_data_ptr < dd_archive + data_size) {
|
|
switch(dd_filehdr(&f, &cf, dir_skip)) {
|
|
case DD_FILE:
|
|
dd_chksum(f, dd_data_ptr);
|
|
dd_expand(cf, dd_data_ptr);
|
|
case DD_IVAL:
|
|
dd_data_ptr += f.dataLength - CFILEHDRSIZE;
|
|
break;
|
|
case DD_COPY:
|
|
dd_copy(f, dd_data_ptr);
|
|
dd_data_ptr += f.dataLength + f.rsrcLength;
|
|
break;
|
|
case DD_SDIR:
|
|
if(write_it || info_only) {
|
|
if(write_it) {
|
|
do_mkdir(text, info);
|
|
}
|
|
if(dd_dirstptr == dd_dirstmax) {
|
|
if(dd_dirstmax == 0) {
|
|
dd_dirst = (unsigned char *)malloc(64);
|
|
} else {
|
|
dd_dirst = (unsigned char *)realloc((char *)dd_dirst,
|
|
(unsigned)dd_dirstmax + 64);
|
|
}
|
|
dd_dirstmax += 64;
|
|
}
|
|
for(i = 0; i < 64; i++) {
|
|
dd_dirst[dd_dirstptr + i] = text[i];
|
|
}
|
|
dd_dirst += 64;
|
|
indent++;
|
|
} else {
|
|
dir_skip++;
|
|
}
|
|
break;
|
|
case DD_EDIR:
|
|
if(dir_skip) {
|
|
dir_skip--;
|
|
} else {
|
|
dd_dirst -= 64;
|
|
indent--;
|
|
if(list) {
|
|
do_indent(indent);
|
|
(void)fprintf(stderr, "leaving folder \"%s\"\n",
|
|
dd_dirst + dd_dirstptr);
|
|
}
|
|
if(!info_only) {
|
|
enddir();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(!info_only) {
|
|
enddir();
|
|
}
|
|
if(list) {
|
|
indent--;
|
|
do_indent(indent);
|
|
(void)fprintf(stderr, "leaving folder \"%s\"\n", locname);
|
|
}
|
|
}
|
|
|
|
static void dd_name(bin_hdr)
|
|
unsigned char *bin_hdr;
|
|
{
|
|
int nlength;
|
|
unsigned char *extptr;
|
|
|
|
nlength = bin_hdr[I_NAMEOFF] & BYTEMASK;
|
|
extptr = bin_hdr + I_NAMEOFF + nlength - 3;
|
|
if(!strncmp((char *)extptr, ".sea", 4) ||
|
|
!strncmp((char *)extptr, ".Sea", 4) ||
|
|
!strncmp((char *)extptr, ".SEA", 4)) {
|
|
nlength -= 4;
|
|
extptr[0] = 0;
|
|
extptr[1] = 0;
|
|
extptr[2] = 0;
|
|
extptr[3] = 0;
|
|
bin_hdr[I_NAMEOFF] = nlength;
|
|
return;
|
|
}
|
|
extptr++;
|
|
if(!strncmp((char *)extptr, ".dd", 3)) {
|
|
nlength -=3;
|
|
extptr[0] = 0;
|
|
extptr[1] = 0;
|
|
extptr[2] = 0;
|
|
bin_hdr[I_NAMEOFF] = nlength;
|
|
return;
|
|
}
|
|
if(nlength < 31) {
|
|
nlength++;
|
|
}
|
|
bin_hdr[I_NAMEOFF + nlength] = 0xA5;
|
|
bin_hdr[I_NAMEOFF] = nlength;
|
|
}
|
|
|
|
static int dd_filehdr(f, cf, skip)
|
|
struct fileHdr *f;
|
|
struct fileCHdr *cf;
|
|
int skip;
|
|
{
|
|
register int i;
|
|
unsigned long crc;
|
|
int n, to_uncompress;
|
|
unsigned char *hdr;
|
|
char ftype[5], fauth[5];
|
|
unsigned long datalength, rsrclength;
|
|
|
|
to_uncompress = DD_COPY;
|
|
hdr = dd_data_ptr;
|
|
dd_data_ptr += FILEHDRSIZE;
|
|
for(i = 0; i < INFOBYTES; i++) {
|
|
info[i] = '\0';
|
|
}
|
|
crc = INIT_CRC;
|
|
crc = (*updcrc)(crc, hdr, FILEHDRSIZE - 2);
|
|
|
|
f->hdrcrc = get2((char *)hdr + D_HDRCRC);
|
|
if(f->hdrcrc != crc) {
|
|
(void)fprintf(stderr, "Header CRC mismatch: got 0x%04x, need 0x%04x\n",
|
|
f->hdrcrc & WORDMASK, (int)crc);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Header CRC mismatch");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
|
|
n = hdr[D_FNAME] & BYTEMASK;
|
|
if(n > F_NAMELEN) {
|
|
n = F_NAMELEN;
|
|
}
|
|
info[I_NAMEOFF] = n;
|
|
copy(info + I_NAMEOFF + 1, (char *)hdr + D_FNAME + 1, n);
|
|
transname((char *)hdr + D_FNAME + 1, text, n);
|
|
|
|
if(!hdr[D_ISDIR]) {
|
|
f->datacrc = get2((char *)hdr + D_DATACRC);
|
|
f->rsrccrc = get2((char *)hdr + D_RSRCCRC);
|
|
f->dataLength = get4((char *)hdr + D_DATALENGTH);
|
|
f->rsrcLength = get4((char *)hdr + D_RSRCLENGTH);
|
|
copy(info + I_DLENOFF, (char *)hdr + D_DATALENGTH, 4);
|
|
copy(info + I_RLENOFF, (char *)hdr + D_RSRCLENGTH, 4);
|
|
copy(info + I_CTIMOFF, (char *)hdr + D_CTIME, 4);
|
|
copy(info + I_MTIMOFF, (char *)hdr + D_MTIME, 4);
|
|
copy(info + I_TYPEOFF, (char *)hdr + D_FTYPE, 4);
|
|
copy(info + I_AUTHOFF, (char *)hdr + D_CREATOR, 4);
|
|
copy(info + I_FLAGOFF, (char *)hdr + D_FNDRFLAGS, 2);
|
|
}
|
|
|
|
if(hdr[D_ISDIR]) {
|
|
to_uncompress = DD_SDIR;
|
|
} else if(hdr[D_ENDDIR]) {
|
|
to_uncompress = DD_EDIR;
|
|
} else if(!no_dd && ((hdr[D_FNDRFLAGS] & 0x80) == 0)) {
|
|
dd_cfilehdr(cf);
|
|
to_uncompress = DD_FILE;
|
|
datalength = cf->dataLength;
|
|
rsrclength = cf->rsrcLength;
|
|
} else {
|
|
datalength = f->dataLength;
|
|
rsrclength = f->rsrcLength;
|
|
}
|
|
hdr[D_FNDRFLAGS] &= 0x7f;
|
|
write_it = !skip;
|
|
if(list && !skip) {
|
|
if(to_uncompress != DD_EDIR) {
|
|
do_indent(indent);
|
|
}
|
|
if(to_uncompress == DD_SDIR) {
|
|
(void)fprintf(stderr, "folder=\"%s\"", text);
|
|
} else if(to_uncompress != DD_EDIR) {
|
|
transname(info + I_TYPEOFF, ftype, 4);
|
|
transname(info + I_AUTHOFF, fauth, 4);
|
|
(void)fprintf(stderr,
|
|
"name=\"%s\", type=%4.4s, author=%4.4s, data=%ld, rsrc=%ld",
|
|
text, ftype, fauth, (long)datalength, (long)rsrclength);
|
|
}
|
|
if(info_only) {
|
|
write_it = 0;
|
|
}
|
|
if(to_uncompress != DD_EDIR) {
|
|
if(query) {
|
|
write_it = do_query();
|
|
} else {
|
|
(void)fputc('\n', stderr);
|
|
}
|
|
}
|
|
if(to_uncompress == DD_FILE) {
|
|
if(!dd_valid((int)cf->datamethod, (int)cf->rsrcmethod)) {
|
|
(void)fprintf(stderr, "\tUnimplemented method found: %d %d\n",
|
|
cf->datamethod, cf->rsrcmethod);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Unimplemented method found");
|
|
#endif /* SCAN */
|
|
return DD_IVAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(write_it) {
|
|
define_name(text);
|
|
}
|
|
return to_uncompress;
|
|
}
|
|
|
|
static void dd_cfilehdr(f)
|
|
struct fileCHdr *f;
|
|
{
|
|
unsigned long crc;
|
|
unsigned char *hdr;
|
|
|
|
hdr = dd_data_ptr;
|
|
dd_data_ptr += CFILEHDRSIZE;
|
|
crc = INIT_CRC;
|
|
crc = (*updcrc)(crc, hdr, CFILEHDRSIZE - 2);
|
|
|
|
f->hdrcrc = get2((char *)hdr + C_HDRCRC);
|
|
if(f->hdrcrc != crc) {
|
|
(void)fprintf(stderr, "Header CRC mismatch: got 0x%04x, need 0x%04x\n",
|
|
f->hdrcrc & WORDMASK, (int)crc);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Header CRC mismatch");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
|
|
f->dataLength = get4((char *)hdr + C_DATALENGTH);
|
|
f->dataCLength = get4((char *)hdr + C_DATACLENGTH);
|
|
f->rsrcLength = get4((char *)hdr + C_RSRCLENGTH);
|
|
f->rsrcCLength = get4((char *)hdr + C_RSRCCLENGTH);
|
|
f->datamethod = hdr[C_DATAMETHOD];
|
|
f->rsrcmethod = hdr[C_RSRCMETHOD];
|
|
f->datacrc = get2((char *)hdr + C_DATACRC);
|
|
f->rsrccrc = get2((char *)hdr + C_RSRCCRC);
|
|
f->datainfo = get2((char *)hdr + C_DATAINFO);
|
|
f->rsrcinfo = get2((char *)hdr + C_RSRCINFO);
|
|
f->datacrc2 = get2((char *)hdr + C_DATACRC2);
|
|
f->rsrccrc2 = get2((char *)hdr + C_RSRCCRC2);
|
|
f->info1 = hdr[C_INFO1];
|
|
f->info2 = hdr[C_INFO2];
|
|
copy(info + I_DLENOFF, (char *)hdr + C_DATALENGTH, 4);
|
|
copy(info + I_RLENOFF, (char *)hdr + C_RSRCLENGTH, 4);
|
|
copy(info + I_CTIMOFF, (char *)hdr + C_CTIME, 4);
|
|
copy(info + I_MTIMOFF, (char *)hdr + C_MTIME, 4);
|
|
copy(info + I_TYPEOFF, (char *)hdr + C_FTYPE, 4);
|
|
copy(info + I_AUTHOFF, (char *)hdr + C_CREATOR, 4);
|
|
copy(info + I_FLAGOFF, (char *)hdr + C_FNDRFLAGS, 2);
|
|
if(f->info1 >= 0x2a && (f->info2 & 0x80) == 0) {
|
|
dd_xor = 0x5a;
|
|
} else {
|
|
dd_xor = 0;
|
|
}
|
|
}
|
|
|
|
static int dd_valid(dmethod, rmethod)
|
|
int dmethod, rmethod;
|
|
{
|
|
return dd_valid1(dmethod) | dd_valid1(rmethod);
|
|
}
|
|
|
|
static int dd_valid1(method)
|
|
int method;
|
|
{
|
|
switch(method) {
|
|
case nocomp:
|
|
case lzc:
|
|
#ifdef UNTESTED
|
|
case rle:
|
|
#ifdef NOTIMPLEMENTED
|
|
case huffman:
|
|
#endif /* NOTIMPLEMENTED */
|
|
case lzss:
|
|
#endif /* UNTESTED */
|
|
case cpt_compat:
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char *dd_methname(n)
|
|
int n;
|
|
{
|
|
int i, nmeths;
|
|
nmeths = sizeof(methods) / sizeof(struct methodinfo);
|
|
for(i = 0; i < nmeths; i++) {
|
|
if(methods[i].number == n) {
|
|
return methods[i].name;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static unsigned long dd_checksum(init, buffer, length)
|
|
unsigned long init;
|
|
char *buffer;
|
|
unsigned long length;
|
|
{
|
|
int i;
|
|
unsigned long cks;
|
|
|
|
cks = init;
|
|
for(i = 0; i < length; i++) {
|
|
cks += *buffer++ & BYTEMASK;
|
|
}
|
|
return cks & WORDMASK;
|
|
}
|
|
|
|
static void dd_chksum(hdr, data)
|
|
struct fileHdr hdr;
|
|
unsigned char *data;
|
|
{
|
|
unsigned long cks;
|
|
|
|
if(write_it) {
|
|
cks = dd_checksum(INIT_CRC, (char *)data - CFILEHDRSIZE,
|
|
hdr.dataLength);
|
|
if(hdr.datacrc != cks) {
|
|
(void)fprintf(stderr,
|
|
"Checksum error on compressed file: need 0x%04x, got 0x%04x\n",
|
|
hdr.datacrc, (int)cks);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Checksum error on compressed file");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static unsigned long dd_checkor(init, buffer, length)
|
|
unsigned long init;
|
|
char *buffer;
|
|
unsigned long length;
|
|
{
|
|
int i;
|
|
unsigned long cks;
|
|
|
|
cks = init;
|
|
for(i = 0; i < length; i++) {
|
|
cks ^= *buffer++ & BYTEMASK;
|
|
}
|
|
return cks & WORDMASK;
|
|
}
|
|
|
|
static void dd_do_delta(out_ptr, nbytes, kind)
|
|
char *out_ptr;
|
|
unsigned long nbytes;
|
|
int kind;
|
|
{
|
|
switch(kind) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
dd_delta(out_ptr, nbytes);
|
|
break;
|
|
case 2:
|
|
dd_delta3(out_ptr, nbytes);
|
|
break;
|
|
default:
|
|
(void)fprintf(stderr, "Illegal kind value found: %d\n", kind);
|
|
#ifdef SCAN
|
|
do_error("Illegal kind value found");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static void dd_delta(out_ptr, nbytes)
|
|
char *out_ptr;
|
|
unsigned long nbytes;
|
|
{
|
|
int i, sum = 0;
|
|
|
|
for(i = 0; i < nbytes; i++) {
|
|
sum = (sum + *out_ptr) & BYTEMASK;
|
|
*out_ptr++ = sum;
|
|
}
|
|
}
|
|
|
|
static void dd_delta3(out_ptr, nbytes)
|
|
char *out_ptr;
|
|
unsigned long nbytes;
|
|
{
|
|
int i, sum1 = 0, sum2 = 0, sum3 = 0;
|
|
|
|
for(i = 0; i < nbytes; i += 3) {
|
|
sum1 = (sum1 + *out_ptr) & BYTEMASK;
|
|
*out_ptr++ = sum1;
|
|
if(i < nbytes - 1) {
|
|
sum2 = (sum2 + *out_ptr) & BYTEMASK;
|
|
*out_ptr++ = sum2;
|
|
if(i < nbytes) {
|
|
sum3 = (sum3 + *out_ptr) & BYTEMASK;
|
|
*out_ptr++ = sum3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Archive only, no compression */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void dd_copy(hdr, data)
|
|
struct fileHdr hdr;
|
|
unsigned char *data;
|
|
{
|
|
unsigned long cks;
|
|
|
|
if(write_it) {
|
|
start_info(info, hdr.rsrcLength, hdr.dataLength);
|
|
}
|
|
if(verbose) {
|
|
(void)fprintf(stderr, "\tNo compression");
|
|
}
|
|
if(write_it) {
|
|
start_data();
|
|
}
|
|
dd_copyfile(hdr.dataLength, data);
|
|
data += hdr.dataLength;
|
|
if(write_it) {
|
|
cks = dd_checksum(INIT_CRC, out_buffer, hdr.dataLength);
|
|
if(hdr.datacrc != cks) {
|
|
(void)fprintf(stderr,
|
|
"Checksum error on data fork: need 0x%04x, got 0x%04x\n",
|
|
hdr.datacrc, (int)cks);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Checksum error on data fork");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
}
|
|
if(write_it) {
|
|
start_rsrc();
|
|
}
|
|
dd_copyfile(hdr.rsrcLength, data);
|
|
data += hdr.rsrcLength;
|
|
if(write_it) {
|
|
cks = dd_checksum(INIT_CRC, out_buffer, hdr.rsrcLength);
|
|
if(hdr.rsrccrc != cks) {
|
|
(void)fprintf(stderr,
|
|
"Checksum error on resource fork: need 0x%04x, got 0x%04x\n",
|
|
hdr.rsrccrc, (int)cks);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Checksum error on resource fork");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
end_file();
|
|
}
|
|
if(verbose) {
|
|
(void)fprintf(stderr, ".\n");
|
|
}
|
|
}
|
|
|
|
static void dd_copyfile(obytes, data)
|
|
unsigned long obytes;
|
|
unsigned char *data;
|
|
{
|
|
if(obytes == 0) {
|
|
return;
|
|
}
|
|
if(write_it) {
|
|
copy(out_ptr, (char *)data, (int)obytes);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Possible compression, and perhaps in an archive */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void dd_expand(hdr, data)
|
|
struct fileCHdr hdr;
|
|
unsigned char *data;
|
|
{
|
|
unsigned long cks;
|
|
char *out_buf;
|
|
|
|
if(write_it) {
|
|
start_info(info, hdr.rsrcLength, hdr.dataLength);
|
|
}
|
|
if(verbose) {
|
|
(void)fprintf(stderr, "\tData: ");
|
|
}
|
|
if(write_it) {
|
|
start_data();
|
|
}
|
|
out_buf = out_buffer;
|
|
dd_expandfile(hdr.dataLength, hdr.dataCLength, (int)hdr.datamethod,
|
|
(int)hdr.datainfo, data, (unsigned long)hdr.datacrc);
|
|
data += hdr.dataCLength;
|
|
if(write_it) {
|
|
if((hdr.info2 & 0x40) && (hdr.dataLength != 0)) {
|
|
cks = arc_updcrc(INIT_CRC, (unsigned char *)out_buf,
|
|
(int)hdr.dataLength);
|
|
if(cks != hdr.datacrc2) {
|
|
(void)fprintf(stderr,
|
|
"Checksum error on data fork: need 0x%04x, got 0x%04x\n",
|
|
(int)hdr.datacrc2, (int)cks);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Checksum error on data fork");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
if(verbose) {
|
|
(void)fprintf(stderr, ", Rsrc: ");
|
|
}
|
|
if(write_it) {
|
|
start_rsrc();
|
|
}
|
|
out_buf = out_buffer;
|
|
dd_expandfile(hdr.rsrcLength, hdr.rsrcCLength, (int)hdr.rsrcmethod,
|
|
(int)hdr.rsrcinfo, data, (unsigned long)hdr.rsrccrc);
|
|
data += hdr.rsrcCLength;
|
|
if(write_it) {
|
|
if((hdr.info2 & 0x40) && (hdr.rsrcLength != 0)) {
|
|
cks = arc_updcrc(INIT_CRC, (unsigned char *)out_buf,
|
|
(int)hdr.rsrcLength);
|
|
if(cks != hdr.rsrccrc2) {
|
|
(void)fprintf(stderr,
|
|
"Checksum error on resource fork: need 0x%04x, got 0x%04x\n",
|
|
(int)hdr.rsrccrc2, (int)cks);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Checksum error on resource fork");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
}
|
|
end_file();
|
|
}
|
|
if(verbose) {
|
|
(void)fprintf(stderr, ".\n");
|
|
}
|
|
}
|
|
|
|
static void dd_expandfile(obytes, ibytes, method, kind, data, chksum)
|
|
unsigned long obytes, ibytes, chksum;
|
|
int method, kind;
|
|
unsigned char *data;
|
|
{
|
|
int sub_method, m1, m2;
|
|
char *optr = out_ptr;
|
|
unsigned long cksinit;
|
|
|
|
if(obytes == 0) {
|
|
if(verbose) {
|
|
(void)fprintf(stderr, "empty");
|
|
}
|
|
return;
|
|
}
|
|
switch(method & 0x7f) {
|
|
case nocomp:
|
|
if(verbose) {
|
|
(void)fprintf(stderr, "No compression");
|
|
}
|
|
if(write_it) {
|
|
dd_nocomp(obytes, data);
|
|
}
|
|
break;
|
|
case lzc:
|
|
m1 = (*data++ & BYTEMASK) ^ dd_xor;
|
|
m2 = (*data++ & BYTEMASK) ^ dd_xor;
|
|
sub_method = (*data++ & BYTEMASK) ^ dd_xor;
|
|
cksinit = m1 + m2 + sub_method;
|
|
sub_method = sub_method & 0x1f;
|
|
if(verbose) {
|
|
(void)fprintf(stderr, "LZC(%d) compressed (%4.1f%%)",
|
|
sub_method, 100.0 * ibytes / obytes);
|
|
}
|
|
if(write_it) {
|
|
dd_lzc(ibytes - 3, obytes, data, sub_method, chksum, cksinit);
|
|
}
|
|
break;
|
|
#ifdef UNTESTED
|
|
case rle:
|
|
if(verbose) {
|
|
(void)fprintf(stderr, "RLE compressed (%4.1f%%)",
|
|
100.0 * ibytes / obytes);
|
|
}
|
|
if(write_it) {
|
|
dd_rle(ibytes, data);
|
|
}
|
|
break;
|
|
#ifdef NOTIMPLEMENTED
|
|
case huffman:
|
|
if(verbose) {
|
|
(void)fprintf(stderr, "Huffman compressed (%4.1f%%)",
|
|
100.0 * ibytes / obytes);
|
|
}
|
|
if(write_it) {
|
|
dd_huffman(ibytes, data);
|
|
}
|
|
break;
|
|
#endif /* NOTIMPLEMENTED */
|
|
case lzss:
|
|
if(verbose) {
|
|
(void)fprintf(stderr, "LZSS compressed (%4.1f%%)",
|
|
100.0 * ibytes / obytes);
|
|
}
|
|
if(write_it) {
|
|
dd_lzss(data, chksum);
|
|
}
|
|
break;
|
|
#endif /* UNTESTED */
|
|
case cpt_compat:
|
|
sub_method = get2((char *)data);
|
|
data += 16;
|
|
if(sub_method != 0) {
|
|
sub_method = 0;
|
|
} else {
|
|
sub_method = 1;
|
|
}
|
|
if(verbose) {
|
|
if(!sub_method) {
|
|
(void)fprintf(stderr, "RLE compressed (%4.1f%%)",
|
|
100.0 * ibytes / obytes);
|
|
} else {
|
|
(void)fprintf(stderr, "RLE/LZH compressed (%4.1f%%)",
|
|
100.0 * ibytes / obytes);
|
|
}
|
|
}
|
|
if(write_it) {
|
|
dd_cpt_compat(ibytes, obytes, data, sub_method, chksum);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if(write_it) {
|
|
dd_do_delta(optr, obytes, kind);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Method 0: no compression */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void dd_nocomp(obytes, data)
|
|
unsigned char *data;
|
|
unsigned long obytes;
|
|
{
|
|
copy(out_ptr, (char *)data, (int)obytes);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Method 1: LZC compressed */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void dd_lzc(ibytes, obytes, data, mb, chksum, ckinit)
|
|
unsigned char *data;
|
|
unsigned long ibytes, obytes, chksum, ckinit;
|
|
int mb;
|
|
{
|
|
int i;
|
|
char *out_buf;
|
|
unsigned long cks;
|
|
|
|
out_buf = out_buffer;
|
|
core_compress((char *)data);
|
|
de_compress(ibytes, mb);
|
|
out_buffer = out_buf;
|
|
if(dd_xor != 0) {
|
|
for(i = 0; i < obytes; i++) {
|
|
*out_buf++ ^= dd_xor;
|
|
}
|
|
}
|
|
cks = dd_checksum(ckinit, out_buffer, obytes);
|
|
if(chksum != cks) {
|
|
(void)fprintf(stderr,
|
|
"Checksum error on fork: need 0x%04x, got 0x%04x\n",
|
|
(int)chksum, (int)cks);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Checksum error on fork");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
#ifdef UNTESTED
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Method 3: Run length encoding */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void dd_rle(ibytes, data)
|
|
unsigned char *data;
|
|
unsigned long ibytes;
|
|
{
|
|
int ch, lastch, n, i;
|
|
|
|
while(ibytes != 0) {
|
|
ch = *data++;
|
|
ibytes--;
|
|
if(ch == ESC) {
|
|
n = *data++ - 1;
|
|
ibytes--;
|
|
if(n < 0) {
|
|
*out_ptr++ = ESC;
|
|
lastch = ESC;
|
|
} else {
|
|
for(i = 0; i < n; i++) {
|
|
*out_ptr++ = lastch;
|
|
}
|
|
}
|
|
} else {
|
|
*out_ptr++ = ch;
|
|
lastch = ch;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef NOTIMPLEMENTED
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Method 4: Huffman encoding */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void dd_huffman(ibytes, data)
|
|
unsigned char *data;
|
|
unsigned long ibytes;
|
|
{
|
|
}
|
|
#endif /* NOTIMPLEMENTED */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Method 7: Slightly improved LZSS */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void dd_lzss(data, chksum)
|
|
unsigned char *data;
|
|
unsigned long chksum;
|
|
{
|
|
int i, LZptr, LZbptr, LZlength;
|
|
char *optr = out_ptr;
|
|
unsigned char cks;
|
|
|
|
data += get4((char *)data + 6);
|
|
LZptr = 0;
|
|
while(1) {
|
|
if(dd_getbits(1) == 0) {
|
|
*out_ptr++ = dd_LZbuff[LZptr++] = dd_getbits(8);
|
|
LZptr &= 0x7ff;
|
|
} else {
|
|
if(dd_getbits(1) == 0) {
|
|
LZbptr = dd_getbits(11);
|
|
} else {
|
|
LZbptr = dd_getbits(7);
|
|
}
|
|
if(LZbptr == 0) {
|
|
break;
|
|
}
|
|
LZbptr = (LZptr - LZbptr) & 0x7ff;
|
|
LZlength = dd_getbits(2);
|
|
if(LZlength == 3) {
|
|
LZlength += dd_getbits(2);
|
|
if(LZlength == 6) {
|
|
do {
|
|
i = dd_getbits(4);
|
|
LZlength += i;
|
|
} while(i == 15);
|
|
}
|
|
}
|
|
LZlength += 2;
|
|
for(i = 0; i < LZlength; i++) {
|
|
*out_ptr++ = dd_LZbuff[LZptr++] = dd_LZbuff[LZbptr++];
|
|
LZptr &= 0x7ff;
|
|
LZbptr &= 0x7ff;
|
|
}
|
|
}
|
|
}
|
|
cks = dd_checkor(INIT_CRC, optr, (unsigned long)(out_ptr - optr));
|
|
if(chksum != cks) {
|
|
(void)fprintf(stderr,
|
|
"Checksum error on fork: need 0x%04x, got 0x%04x\n",
|
|
(int)chksum, (int)cks);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Checksum error on fork");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static int dd_getbits(n)
|
|
int n;
|
|
{
|
|
int r;
|
|
|
|
while(dd_bitcount < n) {
|
|
dd_bitbuf = (dd_bitbuf << 8) | (~(*dd_bitptr++) & BYTEMASK);
|
|
dd_bitcount += 8;
|
|
}
|
|
dd_bitcount -= n;
|
|
r = (dd_bitbuf >> dd_bitcount);
|
|
dd_bitbuf ^= (r << dd_bitcount);
|
|
return r;
|
|
}
|
|
|
|
#endif /* UNTESTED */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Method 8: Compactor compatible compression */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void dd_cpt_compat(ibytes, obytes, data, sub_method, chksum)
|
|
unsigned char *data;
|
|
unsigned long ibytes, obytes, chksum;
|
|
int sub_method;
|
|
{
|
|
unsigned long cks;
|
|
char *optr = out_buffer;
|
|
|
|
cpt_wrfile1(data, ibytes, obytes, sub_method, (unsigned long)0x0fff0);
|
|
cks = arc_updcrc(INIT_CRC, (unsigned char *)optr, (int)obytes);
|
|
if(chksum != cks) {
|
|
(void)fprintf(stderr,
|
|
"Checksum error on fork: need 0x%04x, got 0x%04x\n",
|
|
(int)chksum, (int)cks);
|
|
#ifdef SCAN
|
|
do_error("macunpack: Checksum error on fork");
|
|
#endif /* SCAN */
|
|
exit(1);
|
|
}
|
|
}
|
|
#else /* DD */
|
|
int dd; /* keep lint and some compilers happy */
|
|
#endif /* DD */
|
|
|