#include #include #include #include #include #include #include #define VERSION "deSilo version 0.4a by Clement" /* u_int8_t rodata[19]; u_int16_t rsize_min[29]; u_int8_t rsize_delta[29]; u_int16_t rpos_min[30]; u_int8_t rpos_delta[30]; */ #include "desilo.h" struct s_tree { struct s_tree *branch[2]; u_int32_t value; }; struct s_attrib { u_int32_t offset; u_int16_t value; }; struct s_huffman { struct s_tree *tree; u_int8_t *size; u_int16_t *code; u_int32_t num; }; struct rec_header { u_int32_t offset; u_int32_t useless; } __attribute__ ((packed)); struct pdb_header { u_int8_t name[32]; u_int16_t flags; u_int16_t version; u_int32_t time1; u_int32_t time2; u_int32_t time3; u_int32_t mod; u_int8_t useless1[8]; u_int32_t type; u_int32_t cid; u_int8_t useless2[8]; u_int16_t numrec; } __attribute__ ((packed)); #define HM_SHORT 0x10 #define HM_MEDIUM 0x11 #define HM_LONG 0x12 void init_tables(void) { int i; u_int16_t j; return; for (i = 0; i < 3; i++) rodata[i] = 0x10 + i; rodata[3] = 0; for (i = 4; i < 19; i = i + 2) rodata[i] = 8 + (i-4)/2; for (i = 5; i < 19; i = i + 2) rodata[i] = 7 - (i-5)/2; memset(rsize_delta, 0, 29); for (i = 4; i < 29; i++) { rsize_delta[i] = (i - 4) >> 2; } memset(rpos_delta, 0, 30); for (i = 2; i < 30; i++) { rpos_delta[i] = (i - 2) >> 1; } j = 3; for (i = 0; i < 29; i++) { rsize_min[i] = j; j += 1 << rsize_delta[i]; } j = 1; for (i = 0; i < 30; i++) { rpos_min[i] = j; j += 1 << rpos_delta[i]; } } /* read num bits from the file descriptor */ u_int32_t get_bits(int fd, int num) { static int pos = 0; static u_int32_t buf[256]; int i, r; u_int32_t result = 0; if (num == 0) { pos = 0; return(0); } for (i = 0; i < num; i++) { if (pos == 0) { r = read(fd, buf, 1024); if (r <= 0) { printf("ERROR: Unexpected end of file\n"); exit(-1); /* FIXME */ } pos = 32*256; } pos--; result <<= 1; result |= (htonl(buf[255 - (pos/32)]) >> (31-(pos % 32))) & 1; } return(result); } int code2tree(struct s_huffman *h) { struct s_tree *t, *tmp; u_int32_t i; int j, b; t = (void*) malloc(sizeof(struct s_tree)); h->tree = t; if (t == NULL) return -1; memset(t, 0, sizeof(struct s_tree)); t->value = -1; for (i = 0; i < h->num; i++) { tmp = t; for (j = 0; j < h->size[i]; j++) { b = (h->code[i] >> j) & 1; if (tmp->branch[b] == NULL) { tmp->branch[b] = (void*) malloc(sizeof(struct s_tree)); if (tmp->branch[b] == NULL) return(-1); memset(tmp->branch[b], 0, sizeof(struct s_tree)); tmp->value = -1; } tmp = tmp->branch[b]; } if (h->size[i] > 0) tmp->value = i; } return (0); } u_int32_t swap_bits(u_int32_t n, int num) { n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa); n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc); n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0); n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00); n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000); n >>= (32 - num); return(n); } u_int32_t get_swapped(int fd, int num) { return(swap_bits(get_bits(fd,num),num)); } u_int32_t *huffman_get(int fd, struct s_huffman *h) { int b; struct s_tree *t = h->tree; while (t->value == -1) { b = get_bits(fd, 1); if (t->branch[b] == NULL) { return(NULL); } t = t->branch[b]; } return (&t->value); } int size2code(struct s_huffman *h) { u_int8_t i, sk, max = 0; u_int16_t sc, c; u_int32_t j, k, l; int skip; for (l = 0; l < h->num; l++) { if (h->size[l] > max) max = h->size[l]; } for (i = 1; i <= max; i++) { sc = 0; c = 0; for (j = 0; j < h->num; j++) { if (h->size[j] == i) { do { skip = 0; for (k = 0; k < h->num; k++) { sk = h->size[k]; if ((sk < i) && (sk != 0) && !((h->code[k] ^ c) & ((1 << sk)-1))) { if ((c + 1) == (1 << i)) { return -1; } sc += 1 << (i-sk); c = swap_bits(sc, i); skip = 1; break; } } } while (skip); h->code[j] = c; sc++; c = swap_bits(sc, i); } } } return(0); } struct s_huffman *huffman_create(u_int32_t num) { struct s_huffman *h; h = (void*) malloc(sizeof(struct s_huffman)); h->tree = (void*) malloc(sizeof(struct s_tree)); memset(h->tree, 0, sizeof(struct s_tree)); h->tree->value = -1; h->num = num; h->code = (void*) malloc(2*num); h->size = (void*) malloc(num); memset(h->size, 0, num); memset(h->code, 0, num*2); return (h); } void kill_tree(struct s_tree *tree) { if (tree == NULL) { return; } kill_tree(tree->branch[0]); kill_tree(tree->branch[1]); free (tree); } void kill_huffman(struct s_huffman *h) { if (h == NULL) { return; } kill_tree(h->tree); free(h->code); free(h->size); free(h); } int read_size(int fd, struct s_huffman *prev, struct s_huffman *h) { u_int32_t *j; u_int32_t i, n; int s_ok = 0, ls = 0; for (i = 0;i < h->num;) { j = huffman_get(fd, prev); if (j == NULL) return(-1); switch(*j) { case HM_MEDIUM: n = get_swapped(fd, 3) + 3; /* n bytes of 0 */ memset(h->size + i, 0, n); i += n; break; case HM_LONG: n = get_swapped(fd, 7) + 11; /* n bytes of 0 */ memset(h->size + i, 0, n); i += n; break; case HM_SHORT: if (!s_ok) { return(-1); } n = get_swapped(fd, 2) + 3; /* n+1 bytes of ls */ memset(h->size + i, ls, n); i += n; break; default: h->size[i] = *j; ls = *j; i++; break; } if ((*j == HM_LONG) || (*j == HM_MEDIUM)) { s_ok = 0; } else { s_ok = 1; } } return(0); } void mymemcpy(u_int8_t *dst, u_int8_t *src, u_int32_t num) { u_int32_t i; for (i = 0; i < num; i++) { dst[i] = src[i]; } } /* return size or -1 for error */ int read_text(int fd, u_int8_t *buf, u_int32_t size, struct s_huffman *text, struct s_huffman *lz) { u_int32_t *j; u_int32_t k, l, bp, idx; for (bp = 0; bp < size;) { j = huffman_get(fd, text); if (j == NULL) return(-1); if (*j == 256) { break; } if (*j >= 257) { idx = *j - 257; k = rsize_min[idx]; if (rsize_delta[idx] != 0) { k += get_swapped(fd, rsize_delta[idx]); } j = huffman_get(fd, lz); if (j == NULL) return(-1); l = rpos_min[*j]; if (rpos_delta[*j] != 0) { l += get_swapped(fd, rpos_delta[*j]); } if (k <= l) { memcpy(buf + bp, buf + bp - l, k); } else { mymemcpy(buf + bp, buf + bp - l, k); } bp += k; } else { buf[bp] = *j; bp++; } } return(bp); } int read_tree(int fd, struct s_huffman *prev, struct s_huffman *curr) { if (read_size(fd, prev, curr) == -1) return(-1); if (size2code(curr) == -1) return(-1); if (code2tree(curr) == -1) return(-1); return(0); } int main(int argc, char **argv) { u_int8_t buf[65536]; u_int32_t bsize, i, offset, cur_rec, rec_code; struct rec_header *rechdr = NULL; int rdmax, fd = -1, outfd = -1, atrfd = -1, text_ok = 0 ; struct s_huffman *master = NULL, *lz = NULL, *text = NULL; struct pdb_header pdbhdr; u_int16_t last_value = 0xFFFF, last_pos = 0xFFFF; u_int16_t pos_hi = 0xFFFF; u_int16_t attr_num; u_int32_t filepos; struct s_attrib *attr = NULL; u_int32_t j, r, text_end; printf("\n%s\n\n", VERSION); if (argc != 4) { printf("usage: %s \n", argv[0]); exit(-1); } init_tables(); fd = open(argv[1], O_RDONLY); outfd = creat(argv[2], S_IRWXO | S_IRWXG | S_IRWXU); if (fd == -1) { perror("open infile"); exit(-1); } if (outfd == -1) { perror("open outfile"); exit(-1); } if (read(fd, &pdbhdr, sizeof(pdbhdr)) == -1) { perror("reading PDB header"); exit(-1); } printf("There is %u records in this PDB file\n", htons(pdbhdr.numrec)); rechdr = (void*) malloc(htons(pdbhdr.numrec)*8); if (read(fd, rechdr, htons(pdbhdr.numrec)*8) != htons(pdbhdr.numrec)*8) { perror("read"); exit(-1); } printf("Processing..."); fflush(stdout); for (cur_rec = 0; cur_rec < htons(pdbhdr.numrec); cur_rec++) { offset = htonl(rechdr[cur_rec].offset); /* printf("."); */ printf("Processing record: %u\n", cur_rec); fflush(stdout); if (lseek(fd, offset, SEEK_SET) != offset) { perror("lseek"); break; } if (read(fd, &rec_code, 4) != 4) { printf("short read"); break; } printf("code = %x\n", rec_code); if (!(text_ok) && ((rec_code & 0xFF) == 0) && (cur_rec != 0)) { text_ok = 1; printf("Done processing text\n"); text_end = lseek(outfd, 0, SEEK_CUR); close(outfd); outfd = open(argv[2], O_RDONLY); atrfd = creat(argv[3], S_IRWXO | S_IRWXG | S_IRWXU); filepos = 0; } if (text_ok) { /* process attributes */ if (read(fd, &attr_num, 2) != 2) { printf("short read"); break; } attr_num = htons(attr_num) + 1; printf("Processing attribute record %u\n", cur_rec); printf("There is %u attributes in this record\n", attr_num); free(attr); attr = (void*) malloc(attr_num * sizeof(struct s_attrib)); printf("Reading attribute offsets\n"); for (j = 0; j < attr_num; j++) { read(fd, &attr[j].offset, 2); attr[j].offset = htons(attr[j].offset); if (attr[j].offset < last_pos) { pos_hi++; /* stupid attr. offset encoding */ } if ((attr[j].offset == last_pos) && (attr[j].value == last_value)) { pos_hi++; /* very stupid attr. offset encoding */ } last_pos = attr[j].offset; attr[j].offset |= pos_hi << 16; } printf("Reading attribute values\n"); for (j = 0; j < attr_num; j++) { read(fd, &attr[j].value, 2); } for (j = 0 ; j < attr_num; j++) { if (attr[j].offset > filepos) { printf("Moving block from %u to %u\n", filepos, attr[j].offset); r = read(outfd, buf, attr[j].offset - filepos); if (r <= 0) break; /* FIXME */ write(atrfd, buf, r); filepos = attr[j].offset; if (filepos == text_end) { /* "normal" end of file */ printf("End of file....%u %u\n", filepos, text_end); break; pos_hi = 0xFFFF; } } if (1) { printf("At pos: 0x%08x attribute 0x%04x\n", attr[j].offset, attr[j].value); last_value = attr[j].value; sprintf(buf, "<%04x>", attr[j].value); write(atrfd, buf, 6); } } if (filepos == text_end) { break; } } else { /* process text */ if ((cur_rec % 9) == 1) { get_bits(fd, 0); /* flush buffer */ /* This is a Table record so we reload the tables */ kill_huffman(lz); kill_huffman(text); kill_huffman(master); master = huffman_create(19); text = huffman_create(get_swapped(fd, 5) + 257); lz = huffman_create(get_swapped(fd, 5) + 1); rdmax = get_swapped(fd, 4) + 4; for (i = 0; i < rdmax; i++) master->size[rodata[i]] = get_swapped(fd, 3); if (size2code(master) == -1) { printf("size2code(master) error: size-table is incompatible\n"); break; } code2tree(master); if (read_tree(fd, master, text) == -1) { printf("read_tree() failed (format incorrect?)\n"); break; } if (read_tree(fd, master, lz) == -1) { printf("read_tree() failed (format incorrect?)\n"); break; } } else if (cur_rec != 0) { /* This is a Data record so we decode text using the table */ if (lseek(fd, offset + 4, SEEK_SET) != offset + 4) { perror("lseek"); break; } get_bits(fd, 0); bsize = read_text(fd, buf, 32768, text, lz); write(outfd, buf, bsize); } /* end of text processing */ } } kill_huffman(master); kill_huffman(lz); kill_huffman(text); printf("done.\n"); text_ok = 0; if (text_ok) { for (;;) { j = read(outfd, buf, 65536); if (j <= 0) { break; } write(atrfd, buf, j); } } if (fd != -1) close(fd); if (outfd != -1) close(outfd); if (atrfd != -1) close(atrfd); exit(0); }