00001 #include "iSilo.h"
00002 #ifdef _WINDOWS
00003 #include <winsock.h>
00004 #endif
00005 u_int8_t *rodata = (u_int8_t *)
00006 "\x10\x11\x12\x00\x08\x07\x09\x06\x0a\x05\x0b\x04\x0c\x03\x0d\x02\x0e\x01\x0f";
00007
00008 u_int16_t *rsize_min = (u_int16_t *)
00009 "\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08\x00\x09\x00\x0a\x00\x0b\x00\x0d"
00010 "\x00\x0f\x00\x11\x00\x13\x00\x17\x00\x1b\x00\x1f\x00\x23\x00\x2b\x00\x33\x00"
00011 "\x3b\x00\x43\x00\x53\x00\x63\x00\x73\x00\x83\x00\xa3\x00\xc3\x00\xe3\x00\x02"
00012 "\x01";
00013
00014 u_int8_t *rsize_delta = (u_int8_t *)
00015 "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x02\x02\x02\x02\x03\x03\x03"
00016 "\x03\x04\x04\x04\x04\x05\x05\x05\x05\x00";
00017
00018 u_int16_t *rpos_min = (u_int16_t *)
00019 "\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x07\x00\x09\x00\x0d\x00\x11\x00\x19"
00020 "\x00\x21\x00\x31\x00\x41\x00\x61\x00\x81\x00\xc1\x00\x01\x01\x81\x01\x01\x02"
00021 "\x01\x03\x01\x04\x01\x06\x01\x08\x01\x0c\x01\x10\x01\x18\x01\x20\x01\x30\x01"
00022 "\x40\x01\x60";
00023
00024 u_int8_t *rpos_delta = (u_int8_t *)
00025 "\x00\x00\x00\x00\x01\x01\x02\x02\x03\x03\x04\x04\x05\x05\x06\x06\x07\x07"
00026 "\x08\x08\x09\x09\x0a\x0a\x0b\x0b\x0c\x0c\x0d\x0d";
00027
00028 void iSilo::init_tables(void)
00029 {
00030 int i;
00031 u_int16_t j;
00032 return;
00033 for (i = 0; i < 3; i++)
00034 rodata[i] = 0x10 + i;
00035 rodata[3] = 0;
00036 for (i = 4; i < 19; i = i + 2)
00037 rodata[i] = 8 + (i-4)/2;
00038 for (i = 5; i < 19; i = i + 2)
00039 rodata[i] = 7 - (i-5)/2;
00040
00041 memset(rsize_delta, 0, 29);
00042 for (i = 4; i < 29; i++) {
00043 rsize_delta[i] = (i - 4) >> 2;
00044 }
00045 memset(rpos_delta, 0, 30);
00046 for (i = 2; i < 30; i++) {
00047 rpos_delta[i] = (i - 2) >> 1;
00048 }
00049 j = 3;
00050 for (i = 0; i < 29; i++) {
00051 rsize_min[i] = j;
00052 j += 1 << rsize_delta[i];
00053 }
00054 j = 1;
00055 for (i = 0; i < 30; i++) {
00056 rpos_min[i] = j;
00057 j += 1 << rpos_delta[i];
00058 }
00059 }
00060
00061
00062
00063 int iSilo::code2tree(struct s_huffman *h) {
00064 struct s_tree *t, *tmp;
00065 u_int32_t i;
00066 int j, b;
00067
00068 t = new s_tree();
00069 h->tree = t;
00070 if (t == NULL) return -1;
00071 memset(t, 0, sizeof(struct s_tree));
00072 t->value = (u_int32_t)-1;
00073 for (i = 0; i < h->num; i++) {
00074 tmp = t;
00075 for (j = 0; j < h->size[i]; j++) {
00076 b = (h->code[i] >> j) & 1;
00077 if (tmp->branch[b] == NULL) {
00078 tmp->branch[b] =new s_tree();
00079 if (tmp->branch[b] == NULL) return(-1);
00080 memset(tmp->branch[b], 0, sizeof(struct s_tree));
00081 tmp->value = (u_int32_t)-1;
00082 }
00083 tmp = tmp->branch[b];
00084 }
00085 if (h->size[i] > 0) tmp->value = i;
00086 }
00087 return (0);
00088 }
00089
00090 u_int32_t iSilo::swap_bits(u_int32_t n, int num) {
00091 n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
00092 n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
00093 n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
00094 n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
00095 n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
00096 n >>= (32 - num);
00097 return(n);
00098 }
00099
00100
00101 u_int32_t *iSilo::huffman_get(struct s_huffman *h)
00102 {
00103 int b;
00104 struct s_tree *t = h->tree;
00105
00106 while (t->value == -1) {
00107 b = get_bits(1);
00108 if (t->branch[b] == NULL) {
00109 return(NULL);
00110 }
00111 t = t->branch[b];
00112 }
00113 return (&t->value);
00114 }
00115
00116 int iSilo::size2code(struct s_huffman *h) {
00117 u_int8_t i, sk, max = 0;
00118 u_int16_t sc, c;
00119 u_int32_t j, k, l;
00120 int skip;
00121
00122 for (l = 0; l < h->num; l++) {
00123 if (h->size[l] > max) max = h->size[l];
00124 }
00125
00126 for (i = 1; i <= max; i++) {
00127 sc = 0;
00128 c = 0;
00129 for (j = 0; j < h->num; j++) {
00130 if (h->size[j] == i) {
00131 do {
00132 skip = 0;
00133 for (k = 0; k < h->num; k++) {
00134 sk = h->size[k];
00135
00136 if ((sk < i) && (sk != 0) && !((h->code[k] ^ c) & ((1 << sk)-1))) {
00137 if ((c + 1) == (1 << i)) {
00138 return -1;
00139 }
00140 sc += 1 << (i-sk);
00141 c = swap_bits(sc, i);
00142 skip = 1;
00143 break;
00144 }
00145 }
00146 } while (skip);
00147 h->code[j] = c;
00148 sc++;
00149 c = swap_bits(sc, i);
00150 }
00151 }
00152 }
00153 return(0);
00154 }
00155
00156
00157 struct s_huffman *iSilo::huffman_create(u_int32_t num) {
00158 struct s_huffman *h;
00159 h = new s_huffman();
00160 h->tree = new s_tree();
00161 memset(h->tree, 0, sizeof(struct s_tree));
00162 h->tree->value = (u_int32_t)-1;
00163 h->num = num;
00164 h->code = new u_int16_t[num];
00165 h->size = new u_int8_t[num];
00166 memset(h->size, 0, num);
00167 memset(h->code, 0, num*2);
00168 return (h);
00169 }
00170
00171 void iSilo::kill_tree(struct s_tree *tree) {
00172 if (tree == NULL) {
00173 return;
00174 }
00175 kill_tree(tree->branch[0]);
00176 kill_tree(tree->branch[1]);
00177 delete tree;
00178 }
00179
00180 void iSilo::kill_huffman(struct s_huffman *h) {
00181 if (h == NULL) {
00182 return;
00183 }
00184 kill_tree(h->tree);
00185 delete h->code;
00186 delete h->size;
00187 delete h;
00188 }
00189
00190 int iSilo::read_size(struct s_huffman *prev, struct s_huffman *h) {
00191 u_int32_t *j;
00192 u_int32_t i, n;
00193 int s_ok = 0, ls = 0;
00194
00195 for (i = 0;i < h->num;) {
00196 j = huffman_get(prev);
00197 if (j == NULL)
00198 return(-1);
00199 switch(*j) {
00200 case HM_MEDIUM:
00201 n = get_swapped(3) + 3;
00202 memset(h->size + i, 0, n);
00203 i += n;
00204 break;
00205 case HM_LONG:
00206 n = get_swapped(7) + 11;
00207 memset(h->size + i, 0, n);
00208 i += n;
00209 break;
00210 case HM_SHORT:
00211 if (!s_ok) {
00212 return(-1);
00213 }
00214 n = get_swapped(2) + 3;
00215 memset(h->size + i, ls, n);
00216 i += n;
00217 break;
00218 default:
00219 h->size[i] = *j;
00220 ls = *j;
00221 i++;
00222 break;
00223 }
00224 if ((*j == HM_LONG) || (*j == HM_MEDIUM)) {
00225 s_ok = 0;
00226 } else {
00227 s_ok = 1;
00228 }
00229 }
00230 return(0);
00231 }
00232
00233 void iSilo::mymemcpy(u_int8_t *dst, u_int8_t *src, u_int32_t num) {
00234 u_int32_t i;
00235 for (i = 0; i < num; i++) {
00236 dst[i] = src[i];
00237 }
00238 }
00239
00240
00241 int iSilo::read_tree(struct s_huffman *prev, struct s_huffman *curr) {
00242 if (read_size(prev, curr) == -1)
00243 return(-1);
00244 if (size2code(curr) == -1)
00245 return(-1);
00246 if (code2tree(curr) == -1)
00247 return(-1);
00248 return(0);
00249 }
00250 bool iSilo::reset_trees()
00251 {
00252 get_bits(0);
00253
00254 kill_huffman(lz);
00255 kill_huffman(text);
00256 kill_huffman(master);
00257
00258 master = huffman_create(19);
00259 text = huffman_create(get_swapped(5) + 257);
00260 lz = huffman_create(get_swapped(5) + 1);
00261 int rdmax = get_swapped(4) + 4;
00262
00263 for (int i = 0; i < rdmax; i++)
00264 {
00265 master->size[rodata[i]] = get_swapped(3);
00266 }
00267
00268 if (size2code(master) == -1) {
00269 qDebug("size2code(master) error: size-table is incompatible");
00270 return false;
00271 }
00272
00273 code2tree(master);
00274
00275 if (read_tree(master, text) == -1) {
00276 qDebug("read_tree() failed (format incorrect?)");
00277 return false;
00278 }
00279
00280 if (read_tree(master, lz) == -1) {
00281 qDebug("read_tree() failed (format incorrect?)");
00282 return false;;
00283 }
00284 return true;
00285 }
00286 u_int32_t iSilo::get_bits(int num) {
00287 int i, r;
00288 u_int32_t result = 0;
00289
00290 if (num == 0) {
00291 pos = 0;
00292 return(0);
00293 }
00294
00295 for (i = 0; i < num; i++) {
00296 if (pos == 0) {
00297 unsuspend();
00298 r = fread(buf, sizeof(u_int32_t), 256, fin);
00299 if (r <= 0) {
00300 qDebug("ERROR: Unexpected end of file");
00301 exit(-1);
00302 }
00303 pos = 32*256;
00304 }
00305
00306 pos--;
00307 result <<= 1;
00308 result |= (ntohl(buf[255 - (pos/32)]) >> (31-(pos % 32))) & 1;
00309 }
00310 return(result);
00311 }
00312 u_int32_t iSilo::get_swapped(int num) {
00313 return(swap_bits(get_bits(num),num));
00314 }
00315 int iSilo::read_text() {
00316 u_int32_t *j;
00317 u_int32_t k, l, bp, idx;
00318 for (bp = 0; bp < buffer_size;) {
00319 j = huffman_get(text);
00320 if (j == NULL)
00321 return(-1);
00322 if (*j == 256) {
00323 break;
00324 }
00325 if (*j >= 257) {
00326 idx = *j - 257;
00327 k = rsize_min[idx];
00328 if (rsize_delta[idx] != 0) {
00329 k += get_swapped(rsize_delta[idx]);
00330 }
00331 j = huffman_get(lz);
00332 if (j == NULL)
00333 return(-1);
00334 l = rpos_min[*j];
00335 if (rpos_delta[*j] != 0) {
00336 l += get_swapped(rpos_delta[*j]);
00337 }
00338 if (k <= l) {
00339 memcpy(buffer + bp, buffer + bp - l, k);
00340 } else {
00341 mymemcpy(buffer + bp, buffer + bp - l, k);
00342 }
00343 bp += k;
00344 } else {
00345 buffer[bp] = *j;
00346 bp++;
00347 }
00348 }
00349 return(bp);
00350 }
00351 u_int32_t iSilo::getreccode()
00352 {
00353 u_int32_t offset, rec_code;
00354 gotorecordnumber(cur_rec);
00355 if (fread(&rec_code, sizeof(rec_code), 1, fin) != 1)
00356 {
00357 qDebug("short read");
00358 return 0xff;
00359 }
00360 return rec_code;
00361 }
00362 bool iSilo::process_record()
00363 {
00364 u_int32_t rec_code = getreccode();
00365 if (((rec_code & 0xFF) == 0) && (cur_rec != 0))
00366 {
00367 return false;
00368 }
00369 else
00370 {
00371
00372 if ((cur_rec % 9) == 1)
00373 {
00374 bsize = 0;
00375 if (!reset_trees()) return false;
00376 cur_rec++;
00377 rec_code = getreccode();
00378 if (((rec_code & 0xFF) == 0) && (cur_rec != 0))
00379 {
00380 return false;
00381 }
00382 }
00383 if (cur_rec != 0)
00384 {
00385
00386 get_bits(0);
00387 bsize = read_text();
00388 }
00389 }
00390 return true;
00391 }
00392 iSilo::~iSilo()
00393 {
00394 kill_huffman(master);
00395 kill_huffman(lz);
00396 kill_huffman(text);
00397 if (attr != NULL)
00398 {
00399 delete [] attr;
00400 attr = NULL;
00401 }
00402 }
00403 int iSilo::getch()
00404 {
00405 if (filepos >= textsize)
00406 {
00407
00408 return EOF;
00409 }
00410 if (current_pos >= bsize)
00411 {
00412 cur_rec++;
00413 if (!process_record()) return EOF;
00414 current_pos = 0;
00415 }
00416 filepos++;
00417 while (attr != NULL && filepos > attr[current_attr].offset)
00418 {
00419 mystyle.unset();
00420 u_int16_t a = attr[current_attr].value;
00421
00422 if ((a & 0x1) != 0)
00423 {
00424 mystyle.setBold();
00425 }
00426 if ((a & 0xe) != 0)
00427 {
00428 qDebug("Unknown attribute:%x (%x)", a & 0xe, a);
00429 }
00430 if ((a & 0x10) != 0)
00431 {
00432 mystyle.setCentreJustify();
00433 }
00434 else if ((a & 0x20) != 0)
00435 {
00436 mystyle.setRightJustify();
00437 }
00438 else
00439 {
00440 mystyle.setLeftJustify();
00441 }
00442 if ((a & 0x40) != 0)
00443 {
00444 qDebug("Unknown attribute:%x (%x)", a & 0x40, a);
00445 }
00446 if ((a & 0x80) != 0)
00447 {
00448 mystyle.setLeftMargin(10);
00449 mystyle.setRightMargin(10);
00450 }
00451 switch (a & 0xf00)
00452 {
00453 case 0x300:
00454 mystyle.setFontSize(0);
00455 break;
00456 case 0xd00:
00457 mystyle.setFontSize(1);
00458 break;
00459 case 0xe00:
00460 mystyle.setFontSize(2);
00461 break;
00462 case 0xf00:
00463 mystyle.setFontSize(3);
00464 break;
00465 default:
00466 mystyle.setFontSize(0);
00467 qDebug("Not sure of font size:%x (%x)", a & 0xf00, a);
00468 break;
00469 }
00470 if ((a & 0x1000) != 0)
00471 {
00472 mystyle.setMono();
00473 }
00474 if ((a & 0x2000) != 0)
00475 {
00476 mystyle.setItalic();
00477 }
00478 if ((a & 0x4000) != 0)
00479 {
00480 qDebug("Unknown attribute:%x (%x)", a & 0x4000, a);
00481 }
00482 if ((a & 0x8000) != 0)
00483 {
00484 mystyle.setUnderline();
00485 }
00486 current_attr++;
00487 if (current_attr >= attr_num)
00488 {
00489 attr_rec++;
00490 read_attr();
00491 }
00492 }
00493 return buffer[current_pos++];
00494 }
00495
00496 void iSilo::getch(tchar& ch, CStyle& sty, unsigned long& pos)
00497 {
00498 pos = filepos;
00499 ch = getch();
00500 sty = mystyle;
00501 }
00502
00503 int iSilo::OpenFile(const char* src)
00504 {
00505 struct stat _stat;
00506 stat(src,&_stat);
00507 filesize = _stat.st_size;
00508 pos = 0;
00509 cur_rec = 0;
00510 buffer_size = 4096;
00511 current_pos = 0;
00512 bsize = 0;
00513 filepos = 0;
00514
00515 if (!Cpdb::openpdbfile(src))
00516 {
00517 return -1;
00518 }
00519 if (head.creator != 0x6F476F54
00520 || head.type != 0x6F476F54)
00521 {
00522 return -1;
00523 }
00524 qDebug("There is %u records in this PDB file", ntohs(head.recordList.numRecords));
00525 init_tables();
00526 gotorecordnumber(0);
00527 fread(buffer,1,12,fin);
00528 fread(&textsize, sizeof(textsize), 1, fin);
00529 textsize = ntohl(textsize);
00530 fread(buffer,1,4,fin);
00531 fread(&attr_start,sizeof(attr_start),1,fin);
00532 attr_start = ntohs(attr_start);
00533 fread(buffer,1,2,fin);
00534 fread(&attr_end,sizeof(attr_end),1,fin);
00535 attr_end = ntohs(attr_end);
00536 attr_rec = attr_start;
00537 attr = NULL;
00538 pos_hi = 0xffff;
00539 last_pos = 0xffff;
00540 last_value = 0xffff;
00541 read_attr();
00542 return 0;
00543 }
00544
00545 void iSilo::read_attr()
00546 {
00547
00548 current_attr = 0;
00549 if (attr != NULL)
00550 {
00551 delete [] attr;
00552 attr = NULL;
00553 }
00554 if (attr_rec >= attr_start && attr_rec < attr_end)
00555 {
00556 gotorecordnumber(attr_rec);
00557 fread(buffer, 1, 4, fin);
00558 fread(&attr_num, sizeof(attr_num), 1, fin);
00559 attr_num = ntohs(attr_num)+1;
00560 attr = new s_attrib[attr_num];
00561 for (int j = 0; j < attr_num; j++)
00562 {
00563 fread(&attr[j].offset, 2, 1, fin);
00564 attr[j].offset = htons(attr[j].offset);
00565 }
00566 #ifdef _WINDOWS
00567 for (j = 0; j < attr_num; j++)
00568 #else
00569 for (int j = 0; j < attr_num; j++)
00570 #endif
00571 {
00572 fread(&attr[j].value, 2, 1, fin);
00573 if (attr[j].offset < last_pos)
00574 {
00575 pos_hi++;
00576 }
00577
00578 if ((attr[j].offset == last_pos) && (attr[j].value == last_value))
00579 {
00580 pos_hi++;
00581 }
00582
00583 last_pos = attr[j].offset;
00584 attr[j].offset |= ((u_int32_t)pos_hi) << 16;
00585 last_value = attr[j].value;
00586 }
00587 current_attr = 0;
00588
00589
00590
00591 }
00592 }
00593
00594 void iSilo::locate(unsigned int n)
00595 {
00596
00597 if (n >= textsize) n = 0;
00598 pos = 0;
00599 buffer_size = 4096;
00600 current_pos = 0;
00601 bsize = 0;
00602
00603
00604
00605
00606 filepos = n - n % (8*buffer_size);
00607 cur_rec = 9*(n/(8*buffer_size));
00608
00609 pos_hi = 0xffff;
00610 last_pos = 0xffff;
00611 last_value = 0xffff;
00612 attr_rec = attr_start;
00613 read_attr();
00614
00615 while (attr != NULL && attr[attr_num-1].offset < filepos)
00616 {
00617 attr_rec++;
00618 read_attr();
00619 }
00620
00621 while (filepos < n)
00622 {
00623 getch();
00624 }
00625 }
00626
00627
00628
00629
00630
00631 QString iSilo::about()
00632 {
00633 return QString("iSilo codec (c) Tim Wentford, based on code supplied by an anonymous donor");
00634 }
00635
00636 extern "C"
00637 {
00638 CExpander* newcodec() { return new iSilo; }
00639 }