Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

iSilo.cpp

Go to the documentation of this file.
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 /* read num bits from the file descriptor */
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; /* n bytes of 0 */ 
00202       memset(h->size + i, 0, n); 
00203       i += n;
00204       break;
00205     case HM_LONG:
00206       n = get_swapped(7) + 11; /* n bytes of 0 */
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; /* n+1 bytes of ls */
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 /* return size or -1 for error */
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); /* flush buffer */
00253   /* This is a Table record so we reload the tables */
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); /* FIXME */
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       /* process text */
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           /* This is a Data record so we decode text using the table */
00386           get_bits(0);
00387           bsize = read_text();
00388         } /* end of text processing */
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       //      qDebug("File end at record %u", cur_rec);
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       //      qDebug("Handling attr:%x at pos:%u", a, filepos);
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 //   'ToGo'
00520       || head.type != 0x6F476F54) // 'ToGo')
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   //  qDebug("read_attr:<%u, %u, %u>", attr_rec, attr_start, attr_end);
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       //      last_value = attr[attr_num-1].value;
00589       //      qDebug("Next attr:%u (%u)", attr[current_attr].offset, filepos);
00590       //      qDebug("Next attr:%x (%x)", attr[current_attr].offset, filepos);
00591     }
00592 }
00593 
00594 void iSilo::locate(unsigned int n)
00595 {
00596   //  qDebug("Locating %u", n);
00597   if (n >= textsize) n = 0;
00598   pos = 0;
00599   buffer_size = 4096;
00600   current_pos = 0;
00601   bsize = 0;
00602   /* Brute force
00603   cur_rec = 0;
00604   filepos = 0;
00605   */ // Fast
00606   filepos = n - n % (8*buffer_size);
00607   cur_rec = 9*(n/(8*buffer_size));
00608   // End of fast
00609   pos_hi = 0xffff;
00610   last_pos = 0xffff;
00611   last_value = 0xffff;
00612   attr_rec = attr_start;
00613   read_attr();
00614   // While loop added for fast locate
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       if (!process_record()) return EOF;
00628       current_pos = 0;
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 }

Generated on Sat Nov 5 16:16:55 2005 for OPIE by  doxygen 1.4.2