summaryrefslogtreecommitdiff
path: root/noncore/apps/opie-reader/iSilo.cpp
Unidiff
Diffstat (limited to 'noncore/apps/opie-reader/iSilo.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/apps/opie-reader/iSilo.cpp638
1 files changed, 638 insertions, 0 deletions
diff --git a/noncore/apps/opie-reader/iSilo.cpp b/noncore/apps/opie-reader/iSilo.cpp
new file mode 100644
index 0000000..5f14b96
--- a/dev/null
+++ b/noncore/apps/opie-reader/iSilo.cpp
@@ -0,0 +1,638 @@
1#include "iSilo.h"
2#ifdef _WINDOWS
3#include <winsock.h>
4#endif
5u_int8_t *rodata = (u_int8_t *)
6 "\x10\x11\x12\x00\x08\x07\x09\x06\x0a\x05\x0b\x04\x0c\x03\x0d\x02\x0e\x01\x0f";
7
8u_int16_t *rsize_min = (u_int16_t *)
9 "\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08\x00\x09\x00\x0a\x00\x0b\x00\x0d"
10"\x00\x0f\x00\x11\x00\x13\x00\x17\x00\x1b\x00\x1f\x00\x23\x00\x2b\x00\x33\x00"
11"\x3b\x00\x43\x00\x53\x00\x63\x00\x73\x00\x83\x00\xa3\x00\xc3\x00\xe3\x00\x02"
12"\x01";
13
14u_int8_t *rsize_delta = (u_int8_t *)
15 "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x02\x02\x02\x02\x03\x03\x03"
16"\x03\x04\x04\x04\x04\x05\x05\x05\x05\x00";
17
18u_int16_t *rpos_min = (u_int16_t *)
19 "\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x07\x00\x09\x00\x0d\x00\x11\x00\x19"
20"\x00\x21\x00\x31\x00\x41\x00\x61\x00\x81\x00\xc1\x00\x01\x01\x81\x01\x01\x02"
21"\x01\x03\x01\x04\x01\x06\x01\x08\x01\x0c\x01\x10\x01\x18\x01\x20\x01\x30\x01"
22"\x40\x01\x60";
23
24u_int8_t *rpos_delta = (u_int8_t *)
25 "\x00\x00\x00\x00\x01\x01\x02\x02\x03\x03\x04\x04\x05\x05\x06\x06\x07\x07"
26"\x08\x08\x09\x09\x0a\x0a\x0b\x0b\x0c\x0c\x0d\x0d";
27
28void iSilo::init_tables(void)
29{
30 int i;
31 u_int16_t j;
32 return;
33 for (i = 0; i < 3; i++)
34 rodata[i] = 0x10 + i;
35 rodata[3] = 0;
36 for (i = 4; i < 19; i = i + 2)
37 rodata[i] = 8 + (i-4)/2;
38 for (i = 5; i < 19; i = i + 2)
39 rodata[i] = 7 - (i-5)/2;
40
41 memset(rsize_delta, 0, 29);
42 for (i = 4; i < 29; i++) {
43 rsize_delta[i] = (i - 4) >> 2;
44 }
45 memset(rpos_delta, 0, 30);
46 for (i = 2; i < 30; i++) {
47 rpos_delta[i] = (i - 2) >> 1;
48 }
49 j = 3;
50 for (i = 0; i < 29; i++) {
51 rsize_min[i] = j;
52 j += 1 << rsize_delta[i];
53 }
54 j = 1;
55 for (i = 0; i < 30; i++) {
56 rpos_min[i] = j;
57 j += 1 << rpos_delta[i];
58 }
59}
60
61/* read num bits from the file descriptor */
62
63int iSilo::code2tree(struct s_huffman *h) {
64 struct s_tree *t, *tmp;
65 u_int32_t i;
66 int j, b;
67
68 t = new s_tree();
69 h->tree = t;
70 if (t == NULL) return -1;
71 memset(t, 0, sizeof(struct s_tree));
72 t->value = (u_int32_t)-1;
73 for (i = 0; i < h->num; i++) {
74 tmp = t;
75 for (j = 0; j < h->size[i]; j++) {
76 b = (h->code[i] >> j) & 1;
77 if (tmp->branch[b] == NULL) {
78 tmp->branch[b] =new s_tree();
79 if (tmp->branch[b] == NULL) return(-1);
80 memset(tmp->branch[b], 0, sizeof(struct s_tree));
81 tmp->value = (u_int32_t)-1;
82 }
83 tmp = tmp->branch[b];
84 }
85 if (h->size[i] > 0) tmp->value = i;
86 }
87 return (0);
88}
89
90u_int32_t iSilo::swap_bits(u_int32_t n, int num) {
91 n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
92 n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
93 n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
94 n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
95 n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
96 n >>= (32 - num);
97 return(n);
98}
99
100
101u_int32_t *iSilo::huffman_get(struct s_huffman *h)
102{
103 int b;
104 struct s_tree *t = h->tree;
105
106 while (t->value == -1) {
107 b = get_bits(1);
108 if (t->branch[b] == NULL) {
109 return(NULL);
110 }
111 t = t->branch[b];
112 }
113 return (&t->value);
114}
115
116int iSilo::size2code(struct s_huffman *h) {
117 u_int8_t i, sk, max = 0;
118 u_int16_t sc, c;
119 u_int32_t j, k, l;
120 int skip;
121
122 for (l = 0; l < h->num; l++) {
123 if (h->size[l] > max) max = h->size[l];
124 }
125
126 for (i = 1; i <= max; i++) {
127 sc = 0;
128 c = 0;
129 for (j = 0; j < h->num; j++) {
130 if (h->size[j] == i) {
131 do {
132 skip = 0;
133 for (k = 0; k < h->num; k++) {
134 sk = h->size[k];
135
136 if ((sk < i) && (sk != 0) && !((h->code[k] ^ c) & ((1 << sk)-1))) {
137 if ((c + 1) == (1 << i)) {
138 return -1;
139 }
140 sc += 1 << (i-sk);
141 c = swap_bits(sc, i);
142 skip = 1;
143 break;
144 }
145 }
146 } while (skip);
147 h->code[j] = c;
148 sc++;
149 c = swap_bits(sc, i);
150 }
151 }
152 }
153 return(0);
154}
155
156
157struct s_huffman *iSilo::huffman_create(u_int32_t num) {
158 struct s_huffman *h;
159 h = new s_huffman();
160 h->tree = new s_tree();
161 memset(h->tree, 0, sizeof(struct s_tree));
162 h->tree->value = (u_int32_t)-1;
163 h->num = num;
164 h->code = new u_int16_t[num];
165 h->size = new u_int8_t[num];
166 memset(h->size, 0, num);
167 memset(h->code, 0, num*2);
168 return (h);
169}
170
171void iSilo::kill_tree(struct s_tree *tree) {
172 if (tree == NULL) {
173 return;
174 }
175 kill_tree(tree->branch[0]);
176 kill_tree(tree->branch[1]);
177 delete tree;
178}
179
180void iSilo::kill_huffman(struct s_huffman *h) {
181 if (h == NULL) {
182 return;
183 }
184 kill_tree(h->tree);
185 delete h->code;
186 delete h->size;
187 delete h;
188}
189
190int iSilo::read_size(struct s_huffman *prev, struct s_huffman *h) {
191 u_int32_t *j;
192 u_int32_t i, n;
193 int s_ok = 0, ls = 0;
194
195 for (i = 0;i < h->num;) {
196 j = huffman_get(prev);
197 if (j == NULL)
198 return(-1);
199 switch(*j) {
200 case HM_MEDIUM:
201 n = get_swapped(3) + 3; /* n bytes of 0 */
202 memset(h->size + i, 0, n);
203 i += n;
204 break;
205 case HM_LONG:
206 n = get_swapped(7) + 11; /* n bytes of 0 */
207 memset(h->size + i, 0, n);
208 i += n;
209 break;
210 case HM_SHORT:
211 if (!s_ok) {
212 return(-1);
213 }
214 n = get_swapped(2) + 3; /* n+1 bytes of ls */
215 memset(h->size + i, ls, n);
216 i += n;
217 break;
218 default:
219 h->size[i] = *j;
220 ls = *j;
221 i++;
222 break;
223 }
224 if ((*j == HM_LONG) || (*j == HM_MEDIUM)) {
225 s_ok = 0;
226 } else {
227 s_ok = 1;
228 }
229 }
230 return(0);
231}
232
233void iSilo::mymemcpy(u_int8_t *dst, u_int8_t *src, u_int32_t num) {
234 u_int32_t i;
235 for (i = 0; i < num; i++) {
236 dst[i] = src[i];
237 }
238}
239/* return size or -1 for error */
240
241int iSilo::read_tree(struct s_huffman *prev, struct s_huffman *curr) {
242 if (read_size(prev, curr) == -1)
243 return(-1);
244 if (size2code(curr) == -1)
245 return(-1);
246 if (code2tree(curr) == -1)
247 return(-1);
248 return(0);
249}
250bool iSilo::reset_trees()
251{
252 get_bits(0); /* flush buffer */
253 /* This is a Table record so we reload the tables */
254 kill_huffman(lz);
255 kill_huffman(text);
256 kill_huffman(master);
257
258 master = huffman_create(19);
259 text = huffman_create(get_swapped(5) + 257);
260 lz = huffman_create(get_swapped(5) + 1);
261 int rdmax = get_swapped(4) + 4;
262
263 for (int i = 0; i < rdmax; i++)
264 {
265 master->size[rodata[i]] = get_swapped(3);
266 }
267
268 if (size2code(master) == -1) {
269 qDebug("size2code(master) error: size-table is incompatible");
270 return false;
271 }
272
273 code2tree(master);
274
275 if (read_tree(master, text) == -1) {
276 qDebug("read_tree() failed (format incorrect?)");
277 return false;
278 }
279
280 if (read_tree(master, lz) == -1) {
281 qDebug("read_tree() failed (format incorrect?)");
282 return false;;
283 }
284 return true;
285}
286u_int32_t iSilo::get_bits(int num) {
287 int i, r;
288 u_int32_t result = 0;
289
290 if (num == 0) {
291 pos = 0;
292 return(0);
293 }
294
295 for (i = 0; i < num; i++) {
296 if (pos == 0) {
297 r = fread(buf, sizeof(u_int32_t), 256, fin);
298 if (r <= 0) {
299 qDebug("ERROR: Unexpected end of file");
300 exit(-1); /* FIXME */
301 }
302 pos = 32*256;
303 }
304
305 pos--;
306 result <<= 1;
307 result |= (ntohl(buf[255 - (pos/32)]) >> (31-(pos % 32))) & 1;
308 }
309 return(result);
310}
311u_int32_t iSilo::get_swapped(int num) {
312 return(swap_bits(get_bits(num),num));
313}
314int iSilo::read_text() {
315 u_int32_t *j;
316 u_int32_t k, l, bp, idx;
317 for (bp = 0; bp < buffer_size;) {
318 j = huffman_get(text);
319 if (j == NULL)
320 return(-1);
321 if (*j == 256) {
322 break;
323 }
324 if (*j >= 257) {
325 idx = *j - 257;
326 k = rsize_min[idx];
327 if (rsize_delta[idx] != 0) {
328 k += get_swapped(rsize_delta[idx]);
329 }
330 j = huffman_get(lz);
331 if (j == NULL)
332 return(-1);
333 l = rpos_min[*j];
334 if (rpos_delta[*j] != 0) {
335 l += get_swapped(rpos_delta[*j]);
336 }
337 if (k <= l) {
338 memcpy(buffer + bp, buffer + bp - l, k);
339 } else {
340 mymemcpy(buffer + bp, buffer + bp - l, k);
341 }
342 bp += k;
343 } else {
344 buffer[bp] = *j;
345 bp++;
346 }
347 }
348 return(bp);
349}
350u_int32_t iSilo::getreccode()
351{
352 u_int32_t offset, rec_code;
353 gotorecordnumber(cur_rec);
354 if (fread(&rec_code, sizeof(rec_code), 1, fin) != 1)
355 {
356 qDebug("short read");
357 return 0xff;
358 }
359 return rec_code;
360}
361bool iSilo::process_record()
362{
363 u_int32_t rec_code = getreccode();
364 if (((rec_code & 0xFF) == 0) && (cur_rec != 0))
365 {
366 return false;
367 }
368 else
369 {
370 /* process text */
371 if ((cur_rec % 9) == 1)
372 {
373 bsize = 0;
374 if (!reset_trees()) return false;
375 cur_rec++;
376 rec_code = getreccode();
377 if (((rec_code & 0xFF) == 0) && (cur_rec != 0))
378 {
379 return false;
380 }
381 }
382 if (cur_rec != 0)
383 {
384 /* This is a Data record so we decode text using the table */
385 get_bits(0);
386 bsize = read_text();
387 } /* end of text processing */
388 }
389 return true;
390}
391iSilo::~iSilo()
392{
393 kill_huffman(master);
394 kill_huffman(lz);
395 kill_huffman(text);
396 if (attr != NULL)
397 {
398 delete [] attr;
399 attr = NULL;
400 }
401}
402int iSilo::getch()
403{
404 if (filepos >= textsize)
405 {
406 // qDebug("File end at record %u", cur_rec);
407 return EOF;
408 }
409 if (current_pos >= bsize)
410 {
411 cur_rec++;
412 if (!process_record()) return EOF;
413 current_pos = 0;
414 }
415 filepos++;
416 while (attr != NULL && filepos > attr[current_attr].offset)
417 {
418 mystyle.unset();
419 u_int16_t a = attr[current_attr].value;
420 // qDebug("Handling attr:%x at pos:%u", a, filepos);
421 if ((a & 0x1) != 0)
422 {
423 mystyle.setBold();
424 }
425 if ((a & 0xe) != 0)
426 {
427 qDebug("Unknown attribute:%x (%x)", a & 0xe, a);
428 }
429 if ((a & 0x10) != 0)
430 {
431 mystyle.setCentreJustify();
432 }
433 else if ((a & 0x20) != 0)
434 {
435 mystyle.setRightJustify();
436 }
437 else
438 {
439 mystyle.setLeftJustify();
440 }
441 if ((a & 0x40) != 0)
442 {
443 qDebug("Unknown attribute:%x (%x)", a & 0x40, a);
444 }
445 if ((a & 0x80) != 0)
446 {
447 mystyle.setLeftMargin(10);
448 mystyle.setRightMargin(10);
449 }
450 switch (a & 0xf00)
451 {
452 case 0x300:
453 mystyle.setFontSize(0);
454 break;
455 case 0xd00:
456 mystyle.setFontSize(1);
457 break;
458 case 0xe00:
459 mystyle.setFontSize(2);
460 break;
461 case 0xf00:
462 mystyle.setFontSize(3);
463 break;
464 default:
465 mystyle.setFontSize(0);
466 qDebug("Not sure of font size:%x (%x)", a & 0xf00, a);
467 break;
468 }
469 if ((a & 0x1000) != 0)
470 {
471 mystyle.setMono();
472 }
473 if ((a & 0x2000) != 0)
474 {
475 mystyle.setItalic();
476 }
477 if ((a & 0x4000) != 0)
478 {
479 qDebug("Unknown attribute:%x (%x)", a & 0x4000, a);
480 }
481 if ((a & 0x8000) != 0)
482 {
483 mystyle.setUnderline();
484 }
485 current_attr++;
486 if (current_attr >= attr_num)
487 {
488 attr_rec++;
489 read_attr();
490 }
491 }
492 return buffer[current_pos++];
493}
494
495void iSilo::getch(tchar& ch, CStyle& sty, unsigned long& pos)
496{
497 pos = filepos;
498 ch = getch();
499 sty = mystyle;
500}
501
502int iSilo::OpenFile(const char* src)
503{
504 struct stat _stat;
505 stat(src,&_stat);
506 filesize = _stat.st_size;
507 pos = 0;
508 cur_rec = 0;
509 buffer_size = 4096;
510 current_pos = 0;
511 bsize = 0;
512 filepos = 0;
513
514 if (!Cpdb::openpdbfile(src))
515 {
516 return -1;
517 }
518 if (head.creator != 0x6F476F54 // 'ToGo'
519 || head.type != 0x6F476F54) // 'ToGo')
520 {
521 return -1;
522 }
523 qDebug("There is %u records in this PDB file", ntohs(head.recordList.numRecords));
524 init_tables();
525 gotorecordnumber(0);
526 fread(buffer,1,12,fin);
527 fread(&textsize, sizeof(textsize), 1, fin);
528 textsize = ntohl(textsize);
529 fread(buffer,1,4,fin);
530 fread(&attr_start,sizeof(attr_start),1,fin);
531 attr_start = ntohs(attr_start);
532 fread(buffer,1,2,fin);
533 fread(&attr_end,sizeof(attr_end),1,fin);
534 attr_end = ntohs(attr_end);
535 attr_rec = attr_start;
536 attr = NULL;
537 pos_hi = 0xffff;
538 last_pos = 0xffff;
539 last_value = 0xffff;
540 read_attr();
541 return 0;
542}
543
544void iSilo::read_attr()
545{
546 // qDebug("read_attr:<%u, %u, %u>", attr_rec, attr_start, attr_end);
547 current_attr = 0;
548 if (attr != NULL)
549 {
550 delete [] attr;
551 attr = NULL;
552 }
553 if (attr_rec >= attr_start && attr_rec < attr_end)
554 {
555 gotorecordnumber(attr_rec);
556 fread(buffer, 1, 4, fin);
557 fread(&attr_num, sizeof(attr_num), 1, fin);
558 attr_num = ntohs(attr_num)+1;
559 attr = new s_attrib[attr_num];
560 for (int j = 0; j < attr_num; j++)
561 {
562 fread(&attr[j].offset, 2, 1, fin);
563 attr[j].offset = htons(attr[j].offset);
564 }
565#ifdef _WINDOWS
566 for (j = 0; j < attr_num; j++)
567#else
568 for (int j = 0; j < attr_num; j++)
569#endif
570 {
571 fread(&attr[j].value, 2, 1, fin);
572 if (attr[j].offset < last_pos)
573 {
574 pos_hi++;
575 }
576
577 if ((attr[j].offset == last_pos) && (attr[j].value == last_value))
578 {
579 pos_hi++;
580 }
581
582 last_pos = attr[j].offset;
583 attr[j].offset |= ((u_int32_t)pos_hi) << 16;
584 last_value = attr[j].value;
585 }
586 current_attr = 0;
587 // last_value = attr[attr_num-1].value;
588 // qDebug("Next attr:%u (%u)", attr[current_attr].offset, filepos);
589 // qDebug("Next attr:%x (%x)", attr[current_attr].offset, filepos);
590 }
591}
592
593void iSilo::locate(unsigned int n)
594{
595 // qDebug("Locating %u", n);
596 if (n >= textsize) n = 0;
597 pos = 0;
598 buffer_size = 4096;
599 current_pos = 0;
600 bsize = 0;
601 /* Brute force
602 cur_rec = 0;
603 filepos = 0;
604 */ // Fast
605 filepos = n - n % (8*buffer_size);
606 cur_rec = 9*(n/(8*buffer_size));
607 // End of fast
608 pos_hi = 0xffff;
609 last_pos = 0xffff;
610 last_value = 0xffff;
611 attr_rec = attr_start;
612 read_attr();
613 // While loop added for fast locate
614 while (attr != NULL && attr[attr_num-1].offset < filepos)
615 {
616 attr_rec++;
617 read_attr();
618 }
619
620 while (filepos < n)
621 {
622 getch();
623 }
624}
625/*
626 if (!process_record()) return EOF;
627 current_pos = 0;
628*/
629
630QString iSilo::about()
631{
632 return QString("iSilo codec (c) Tim Wentford, based on code supplied by an anonymous donor");
633}
634
635extern "C"
636{
637 CExpander* newcodec() { return new iSilo; }
638}