/* Decrunches Sinclair QL 'CPT' files. */ /* (C) 2002 Kyzer/CSG */ #include #include #include #define MAXSRCLEN (64*1024) /* max length of crunched data */ #define MAXDESTLEN (128*1024) /* max length of unpacked data */ static unsigned char *inbuf, bitbuf; static int bitpos; int get_bit() { if (bitpos < 0) { bitpos = 7; bitbuf = *inbuf++; } return (bitbuf & (1<>1) | (get_bit() ? 0x80 : 0); return result; } struct node { unsigned char not_leaf[2], value[2]; }; static int nodenum; static struct node tree[256]; void read_node(struct node *node, int branch) { if ((node->not_leaf[branch] = get_bit())) { node->value[branch] = ++nodenum; if (nodenum >= 256) return; /* safety check */ node = &tree[nodenum]; read_node(node, 0); read_node(node, 1); } else { node->value[branch] = get_byte(); } } void decrunch(char *file, unsigned char *src, unsigned char *dest) { int inlen, outlen; FILE *fd; if ((fd = fopen(file, "rb"))) { inlen = fread(src, 1, MAXSRCLEN+2, fd); fclose(fd); if (src[5]) { outlen = (src[6]<<24) | (src[7]<<16) | (src[8]<<8) | (src[9]); inbuf = &src[6+8]; } else { outlen = (src[0]<<24) | (src[1]<<16) | (src[2]<<8) | (src[3]); inbuf = &src[6]; } if (outlen > MAXDESTLEN) { printf("%s: too large unpacked!\n", file); return; } bitpos = -1; if (get_bit()) { /* huffman compressed */ unsigned char *out = dest; int todo = outlen; nodenum = 0; read_node(&tree[0], 0); /* left of root node */ read_node(&tree[0], 1); /* right of root node */ while (todo--) { struct node *n = &tree[0]; unsigned char x, y=1; for (n = &tree[0]; y; n = &tree[x]) { int branch = get_bit(); x = n->value[branch]; y = n->not_leaf[branch]; } *out++ = x; } } else { /* not compressed */ int todo = outlen; unsigned char *out = dest; while (todo--) *out++ = get_byte(); } /* save file */ if ((fd = fopen(file, "wb"))) { int savelen = fwrite(dest, 1, outlen, fd); if (savelen > 0) printf("%s: saved as %d bytes\n", file, savelen); else printf("%s: write failed\n", file); fclose(fd); } } else { printf("%s: can't open file\n", file); } } int main(int argc, char *argv[]) { unsigned char *src, *dest; if (argc <= 1) { printf("Usage: %s \n", argv[0]); return 1; } src = (unsigned char *) malloc(MAXSRCLEN); dest = (unsigned char *) malloc(MAXDESTLEN); if (!src || !dest) { printf("not enough memory\n"); return 1; } argv++; while (*argv) decrunch(*argv++, src, dest); return 0; }