home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 September / PCWorld_2002-09_cd.bin / Software / Vyzkuste / helpdeco / HELPDEC1.C < prev    next >
C/C++ Source or Header  |  1996-12-07  |  25KB  |  1,018 lines

  1. /* HELPDEC1.C - HELPDECO supporting functions */
  2.  
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <stdarg.h>
  6. #include <string.h>
  7. #include <conio.h>
  8. #include <ctype.h>
  9. #include "helpdeco.h"
  10.  
  11. extern BOOL overwrite; /* ugly: declared in HELPDECO.C */
  12.  
  13. void error(char *format,...)
  14. {
  15.     va_list arg;
  16.  
  17.     fputs("\n",stderr);
  18.     va_start(arg,format);
  19.     vfprintf(stderr,format,arg);
  20.     va_end(arg);
  21.     fputs("\nPress CR to continue at your own risk, any other key to exit.\n",stderr);
  22.     if(getch()!='\r') exit(1);
  23. }
  24.  
  25. size_t strlcpy(char *dest,char *src,size_t len) /* limited string copy */
  26. {
  27.     size_t i;
  28.  
  29.     if(!dest) return 0;
  30.     for(i=0;i<len-1&&src&&src[i];i++) dest[i]=src[i];
  31.     dest[i]='\0';
  32.     return i;
  33. }
  34.  
  35. void *my_malloc(long bytes) /* save malloc function */
  36. {
  37.     void *ptr;
  38.  
  39.     if(bytes<1L||((size_t)bytes!=bytes)||(ptr=malloc((size_t)bytes))==NULL)
  40.     {
  41.     fprintf(stderr,"Allocation of %ld bytes failed. File too big.\n",bytes);
  42.     exit(1);
  43.     }
  44.     return ptr;
  45. }
  46.  
  47. void *my_realloc(void *ptr,long bytes) /* save realloc function */
  48. {
  49.     if(!ptr) return my_malloc(bytes);
  50.     if(bytes<1L||bytes!=(size_t)bytes||(ptr=realloc(ptr,(size_t)bytes))==NULL)
  51.     {
  52.     fprintf(stderr,"Reallocation to %ld bytes failed. File too big.\n",bytes);
  53.     exit(1);
  54.     }
  55.     return ptr;
  56. }
  57.  
  58. char *my_strdup(char *ptr) /* save strdup function */
  59. {
  60.     size_t len;
  61.     char *dup;
  62.  
  63.     if(!ptr) return NULL;
  64.     len=strlen(ptr);
  65.     dup=my_malloc(len+1);
  66.     strcpy(dup,ptr);
  67.     return dup;
  68. }
  69.  
  70. size_t my_fread(void *ptr,long bytes,FILE *f) /* save fread function */
  71. {
  72.     size_t result;
  73.  
  74.     if(bytes==0) return 0;
  75.     if(bytes<0||bytes!=(size_t)bytes||(result=fread(ptr,1,(size_t)bytes,f))!=bytes)
  76.     {
  77.     error("my_fread(%ld) at %ld failed",bytes,ftell(f));
  78.     }
  79.     return result;
  80. }
  81.  
  82. size_t my_gets(char *ptr,size_t size,FILE *f)  /* read nul terminated string from regular file */
  83. {
  84.     size_t i;
  85.     int c;
  86.  
  87.     i=0;
  88.     while((c=getc(f))>0)
  89.     {
  90.     if(i>=size-1)
  91.     {
  92.         fputs("String length exceeds decompiler limit.\n",stderr);
  93.         exit(1);
  94.     }
  95.     ptr[i++]=c;
  96.     }
  97.     ptr[i]='\0';
  98.     return i;
  99. }
  100.  
  101. void my_fclose(FILE *f) /* checks if disk is full */
  102. {
  103.     if(ferror(f)!=0)
  104.     {
  105.     fputs("File write error. Program aborted.\n",stderr);
  106.     exit(2);
  107.     }
  108.     fclose(f);
  109. }
  110.  
  111. FILE *my_fopen(const char *filename,const char *mode) /* save fopen function */
  112. {
  113.     FILE *f;
  114.     char ch;
  115.  
  116.     if(!overwrite)
  117.     {
  118.     f=fopen(filename,"rb");
  119.     if(f)
  120.     {
  121.         fclose(f);
  122.         fprintf(stderr,"File %s already exists. Overwrite (Y/N/All/Quit) ? Y\b",filename);
  123.         do
  124.         {
  125.         ch=toupper(getch());
  126.         if(ch=='\r') ch='Y'; else if(ch=='\x1B') ch='N';
  127.         }
  128.         while(ch!='Q'&&ch!='A'&&ch!='Y'&&ch!='N');
  129.         printf("%c\n",ch);
  130.         if(ch=='Q') exit(0);
  131.         if(ch=='A') overwrite=TRUE;
  132.         if(ch=='N') return NULL;
  133.     }
  134.     }
  135.     f=fopen(filename,mode);
  136.     if(!f)
  137.     {
  138.     error("Can not create '%s'.",filename);
  139.     }
  140.     else
  141.     {
  142.     fprintf(stderr,"Creating %s...\n",filename);
  143.     }
  144.     return f;
  145. }
  146.  
  147. unsigned short my_getw(FILE *f) /* get 16 bit quantity */
  148. {
  149.     int ch;
  150.  
  151.     ch=getc(f);
  152.     return ch|(getc(f)<<8);
  153. }
  154.  
  155. unsigned long getdw(FILE *f) /* get long */
  156. {
  157.     unsigned short w;
  158.  
  159.     w=my_getw(f);
  160.     return ((unsigned long)my_getw(f)<<16)|(unsigned long)w;
  161. }
  162.  
  163. void my_putw(unsigned short w,FILE *f) /* write 16 bit quantity */
  164. {
  165.     putc((w&0xFF),f);
  166.     putc((w>>8),f);
  167. }
  168.  
  169. void putdw(unsigned long x,FILE *f) /* write long to file */
  170. {
  171.     fwrite(&x,4,1,f);
  172. }
  173.  
  174. void putcdw(unsigned long x,FILE *f) /* write compressed long to file */
  175. {
  176.     if(x>32767L)
  177.     {
  178.     my_putw((unsigned int)(x<<1)+1,f);
  179.     my_putw(x>>15,f);
  180.     }
  181.     else
  182.     {
  183.     my_putw(x<<1,f);
  184.     }
  185. }
  186.  
  187. void putcw(unsigned int x,FILE *f) /* write compressed word to file */
  188. {
  189.     if(x>127)
  190.     {
  191.     my_putw((x<<1)+1,f);
  192.     }
  193.     else
  194.     {
  195.     putc(x<<1,f);
  196.     }
  197. }
  198.  
  199. /* HELPDECO sometimes has to work off the help file, sometimes needs to do
  200. // the same with (decompressed) information stored in memory. MFILE and the
  201. // memory mapped file functions allow to write the same code for both, but
  202. // this approach needs some declarations first... */
  203. int MemoryPut(MFILE *f,char c) /* put char to memory mapped file */
  204. {
  205.     if(f->ptr>=f->end) return 0;
  206.     *f->ptr++=c;
  207.     return 1;
  208. }
  209.  
  210. int FilePut(MFILE *f,char c) /* put char to regular file */
  211. {
  212.     if(putc(c,f->f)==-1) return 0;
  213.     return 1;
  214. }
  215.  
  216. int MemoryGet(MFILE *f) /* get char from memory mapped file */
  217. {
  218.     if(f->ptr>=f->end) return -1;
  219.     return *(unsigned char *)f->ptr++;
  220. }
  221.  
  222. int FileGet(MFILE *f) /* get char from regular file */
  223. {
  224.     return getc(f->f);
  225. }
  226.  
  227. size_t MemoryRead(MFILE *f,void *ptr,long bytes) /* read function for memory mapped file */
  228. {
  229.     if(bytes<0||bytes>f->end-f->ptr)
  230.     {
  231.     error("read(%ld) failed",bytes);
  232.     bytes=f->end-f->ptr;
  233.     }
  234.     memcpy(ptr,f->ptr,bytes);
  235.     f->ptr+=bytes;
  236.     return bytes;
  237. }
  238.  
  239. size_t FileRead(MFILE *f,void *ptr,long bytes) /* read function for regular file */
  240. {
  241.     return my_fread(ptr,bytes,f->f);
  242. }
  243.  
  244. long MemoryTell(MFILE *f) /* tell for memory mapped file */
  245. {
  246.     return (long)f->ptr;
  247. }
  248.  
  249. long FileTell(MFILE *f) /* tell for regular file */
  250. {
  251.     return ftell(f->f);
  252. }
  253.  
  254. void MemorySeek(MFILE *f,long offset) /* seek in memory mapped file */
  255. {
  256.     f->ptr=(char *)offset;
  257. }
  258.  
  259. void FileSeek(MFILE *f,long offset) /* seek in regular file */
  260. {
  261.     fseek(f->f,offset,SEEK_SET);
  262. }
  263.  
  264. MFILE *CreateMap(char *ptr,size_t size) /* assign a memory mapped file */
  265. {
  266.     MFILE *f;
  267.  
  268.     f=my_malloc(sizeof(MFILE));
  269.     f->f=NULL;
  270.     f->ptr=ptr;
  271.     f->end=ptr+size;
  272.     f->get=MemoryGet;
  273.     f->put=MemoryPut;
  274.     f->read=MemoryRead;
  275.     f->tell=MemoryTell;
  276.     f->seek=MemorySeek;
  277.     return f;
  278. }
  279.  
  280. MFILE *CreateVirtual(FILE *f)  /* assign a real file */
  281. {
  282.     MFILE *mf;
  283.  
  284.     mf=my_malloc(sizeof(MFILE));
  285.     mf->f=f;
  286.     mf->ptr=mf->end=NULL;
  287.     mf->get=FileGet;
  288.     mf->put=FilePut;
  289.     mf->read=FileRead;
  290.     mf->tell=FileTell;
  291.     mf->seek=FileSeek;
  292.     return mf;
  293. }
  294.  
  295. void CloseMap(MFILE *f) /* close a MFILE */
  296. {
  297.     if(f) free(f);
  298. }
  299.  
  300. int GetWord(MFILE *f) /* read 16 bit value from memory mapped file or regular file */
  301. {
  302.     unsigned char b;
  303.  
  304.     b=f->get(f);
  305.     return ((unsigned short)(f->get(f))<<8)|(unsigned short)b;
  306. }
  307.  
  308. unsigned short GetCWord(MFILE *f) /* get compressed word from memory mapped file or regular file */
  309. {
  310.     unsigned char b;
  311.  
  312.     b=f->get(f);
  313.     if(b&1) return (((unsigned short)(f->get(f))<<8)|(unsigned short)b)>>1;
  314.     return ((unsigned short)b>>1);
  315. }
  316.  
  317. unsigned long GetCDWord(MFILE *f) /* get compressed long from memory mapped file or regular file */
  318. {
  319.     unsigned short w;
  320.  
  321.     w=GetWord(f);
  322.     if(w&1) return (((unsigned long)GetWord(f)<<16)|(unsigned long)w)>>1;
  323.     return ((unsigned long)w>>1);
  324. }
  325.  
  326. unsigned long GetDWord(MFILE *f) /* get long from memory mapped file or regular file */
  327. {
  328.     unsigned short w;
  329.  
  330.     w=GetWord(f);
  331.     return ((unsigned long)GetWord(f)<<16)|(unsigned long)w;
  332. }
  333.  
  334. size_t StringRead(char *ptr,size_t size,MFILE *f) /* read nul terminated string from memory mapped or regular file */
  335. {
  336.     size_t i;
  337.     int c;
  338.  
  339.     i=0;
  340.     while((c=f->get(f))>0)
  341.     {
  342.     if(i>=size-1)
  343.     {
  344.         fputs("String length exceeds decompiler limit.\n",stderr);
  345.         exit(1);
  346.     }
  347.     ptr[i++]=c;
  348.     }
  349.     ptr[i]='\0';
  350.     return i;
  351. }
  352.  
  353. long copy(FILE *f,long bytes,FILE *out)
  354. {
  355.     long length;
  356.     int size;
  357.     static char buffer[512];
  358.  
  359.     for(length=0;length<bytes;length+=size)
  360.     {
  361.     size=(int)(bytes-length>sizeof(buffer)?sizeof(buffer):bytes-length);
  362.     my_fread(buffer,size,f);
  363.     fwrite(buffer,size,1,out);
  364.     }
  365.     return length;
  366. }
  367.  
  368. long CopyBytes(MFILE *f,long bytes,FILE *out)
  369. {
  370.     long length;
  371.     int size;
  372.     static char buffer[512];
  373.  
  374.     for(length=0;length<bytes;length+=size)
  375.     {
  376.     size=(int)(bytes-length>sizeof(buffer)?sizeof(buffer):bytes-length);
  377.     f->read(f,buffer,size);
  378.     fwrite(buffer,size,1,out);
  379.     }
  380.     return length;
  381. }
  382.  
  383. signed char count; /* for run len decompression */
  384.  
  385. int DeRun(MFILE *f,char c) /* expand runlen compressed data */
  386. {
  387.     int i;
  388.  
  389.     if(count&0x7F)
  390.     {
  391.     if(count&0x80)
  392.     {
  393.         f->put(f,c);
  394.         count--;
  395.         return 1;
  396.     }
  397.     for(i=0;i<count;i++)
  398.     {
  399.         f->put(f,c);
  400.     }
  401.     count=0;
  402.     return i;
  403.     }
  404.     count=(signed char)c;
  405.     return 0;
  406. }
  407.  
  408. /* copies bytes from (memory mapped or regular file) f to (memory mapped or
  409. // regular file) fTarget, decompressed using method
  410. // 0: copy (no decompression)
  411. // 1: runlen decompression
  412. // 2: LZ77 decompression
  413. // 3: runlen and LZ77 decompression
  414. // returns number of bytes copied to fTarget. Doesn't complain if fTarget
  415. // is a memory mapped file and buffer is full, just stops writing */
  416. long decompress(int method,MFILE *f,long bytes,MFILE *fTarget)
  417. {
  418.     static unsigned char lzbuffer[0x1000];
  419.     int (*Emit)(MFILE *f,char c);
  420.     unsigned char bits,mask;
  421.     int pos,len,back;
  422.     long n;
  423.  
  424.     n=0;
  425.     if(method&1)
  426.     {
  427.     Emit=DeRun;
  428.     count=0;
  429.     }
  430.     else
  431.     {
  432.     Emit=fTarget->put;
  433.     }
  434.     if(method&2)
  435.     {
  436.     mask=0;
  437.     pos=0;
  438.     while(bytes-->0L)
  439.     {
  440.         if(!mask)
  441.         {
  442.         bits=f->get(f);
  443.         mask=1;
  444.         }
  445.         else
  446.         {
  447.         if(bits&mask)
  448.         {
  449.             if(bytes--==0) break;
  450.             back=GetWord(f);
  451.             len=((back>>12)&15)+3;
  452.             back=pos-(back&0xFFF)-1;
  453.             while(len-->0)
  454.             {
  455.             n+=Emit(fTarget,lzbuffer[pos++&0xFFF]=lzbuffer[back++&0xFFF]);
  456.             }
  457.         }
  458.         else
  459.         {
  460.             n+=Emit(fTarget,lzbuffer[pos++&0xFFF]=f->get(f));
  461.         }
  462.         mask<<=1;
  463.         }
  464.     }
  465.     }
  466.     else
  467.     {
  468.     while(bytes-->0L) n+=Emit(fTarget,f->get(f));
  469.     }
  470.     return n;
  471. }
  472.  
  473. long DecompressIntoBuffer(int method,FILE *HelpFile,long bytes,char *ptr,long size)
  474. {
  475.     MFILE *f;
  476.     MFILE *mf;
  477.  
  478.     f=CreateMap(ptr,size);
  479.     mf=CreateVirtual(HelpFile);
  480.     bytes=decompress(method,mf,bytes,f);
  481.     CloseMap(mf);
  482.     CloseMap(f);
  483.     return bytes;
  484. }
  485.  
  486. long DecompressIntoFile(int method,MFILE *f,long bytes,FILE *fTarget)
  487. {
  488.     MFILE *mf;
  489.  
  490.     mf=CreateVirtual(fTarget);
  491.     bytes=decompress(method,f,bytes,mf);
  492.     CloseMap(mf);
  493.     return bytes;
  494. }
  495.  
  496. void HexDump(FILE *f,long FileLength,long offset)
  497. {
  498.     unsigned char b[16];
  499.     long l;
  500.     int n,i;
  501.  
  502.     puts("[-Addr-] [--------------------Data---------------------] [-----Text-----]");
  503.     fseek(f,offset,SEEK_CUR);
  504.     for(l=offset;l<FileLength;l+=16)
  505.     {
  506.     printf("%08lX ",l);
  507.     n=(int)(FileLength-l>16?16:FileLength-l);
  508.     for(i=0;i<n;i++) printf("%02X ",b[i]=getc(f));
  509.     while(i++<16) printf("     ");
  510.     for(i=0;i<n;i++) putchar(isprint(b[i])?b[i]:'.');
  511.     putchar('\n');
  512.     }
  513. }
  514.  
  515. void HexDumpMemory(unsigned char *bypMem,unsigned int FileLength)
  516. {
  517.     unsigned char b[16];
  518.     unsigned int l;
  519.     int n,i;
  520.  
  521.     puts("[-Addr-] [--------------------Data---------------------] [-----Text-----]");
  522.     for(l=0;l<FileLength;l+=16)
  523.     {
  524.     printf("%08X ",l);
  525.     n=(int)(FileLength-l>16?16:FileLength-l);
  526.     for(i=0;i<n;i++) printf("%02X ",b[i]=*bypMem++);
  527.     while(i++<16) printf("     ");
  528.     for(i=0;i<n;i++) putchar(isprint(b[i])?b[i]:'.');
  529.     putchar('\n');
  530.     }
  531. }
  532.  
  533. /* write str to stdout, replacing nonprintable characters with hex codes,
  534. // returning str+len. PrintString doesn't stop at NUL characters */
  535. char *PrintString(char *str,unsigned int len)
  536. {
  537.     while(len-->0)
  538.     {
  539.     if(isprint((unsigned char)*str))
  540.     {
  541.         putchar(*str);
  542.     }
  543.     else
  544.     {
  545.         printf("(%02x)",*(unsigned char *)str);
  546.     }
  547.     str++;
  548.     }
  549.     return str;
  550. }
  551.  
  552. /* get next bit (lsb first) from 32 bit words in f, initialized if f = NULL */
  553. /* important to read longs to stop at right position */
  554. BOOL GetBit(FILE *f)
  555. {
  556.     static unsigned long mask;
  557.     static unsigned long value;
  558.  
  559.     if(f)
  560.     {
  561.     mask<<=1;
  562.     if(!mask)
  563.     {
  564.         fread(&value,4,1,f);
  565.         mask=1L;
  566.     }
  567.     }
  568.     else
  569.     {
  570.     mask=0L; /* initialize */
  571.     }
  572.     return (value&mask)!=0L;
  573. }
  574. /* output str to RTF file, escaping neccessary characters */
  575. void putrtf(FILE *rtf,char *str)
  576. {
  577.     if(rtf) while(*str)
  578.     {
  579.     if(*str=='{'||*str=='}'||*str=='\\')
  580.     {
  581.         putc('\\',rtf);
  582.         putc(*str++,rtf);
  583.     }
  584.     else if(isprint((unsigned char)*str))
  585.     {
  586.         putc(*str++,rtf);
  587.     }
  588.     else
  589.     {
  590.         fprintf(rtf,"\\'%02x",(unsigned char)*str++);
  591.     }
  592.     }
  593. }
  594.  
  595. /* scan-functions for reading compressed values from LinkData1 */
  596. short scanint(char **ptr) /* scan a compressed short */
  597. {
  598.     if(*(*ptr)&1) return (*(((unsigned short *)(*ptr))++)>>1)-0x4000;
  599.     return (*(((unsigned char *)(*ptr))++)>>1)-0x40;
  600. }
  601.  
  602. unsigned short scanword(char **ptr) /* scan a compressed unsiged short */
  603. {
  604.     if(*(*ptr)&1) return *(((unsigned short *)(*ptr))++)>>1;
  605.     return *(((unsigned char *)(*ptr))++)>>1;
  606. }
  607.  
  608. long scanlong(char **ptr)  /* scan a compressed long */
  609. {
  610.     if(*(*ptr)&1) return (*(((unsigned long *)(*ptr))++)>>1)-0x40000000L;
  611.     return (*(((unsigned short *)(*ptr))++)>>1)-0x4000;
  612. }
  613.  
  614. /* locates internal file FileName or internal directory if FileName is NULL
  615. // reads FILEHEADER and returns TRUE with current position in HelpFile set
  616. // to first byte of data of FileName or returns FALSE if not found. Stores
  617. // UsedSpace (that's the file size) in FileLength if FileLength isn't NULL */
  618. BOOL SearchFile(FILE *HelpFile,char *FileName,long *FileLength)
  619. {
  620.     HELPHEADER Header;
  621.     FILEHEADER FileHdr;
  622.     BTREEHEADER BtreeHdr;
  623.     BTREENODEHEADER CurrNode;
  624.     long offset;
  625.     char TempFile[19];
  626.     int i,n;
  627.  
  628.     fseek(HelpFile,0L,SEEK_SET);
  629.     my_fread(&Header,sizeof(Header),HelpFile);
  630.     if(Header.Magic!=0x00035F3FL) return FALSE;
  631.     fseek(HelpFile,Header.DirectoryStart,SEEK_SET);
  632.     my_fread(&FileHdr,sizeof(FileHdr),HelpFile);
  633.     if(!FileName)
  634.     {
  635.     if(FileLength) *FileLength=FileHdr.UsedSpace;
  636.     return TRUE;
  637.     }
  638.     my_fread(&BtreeHdr,sizeof(BtreeHdr),HelpFile);
  639.     offset=ftell(HelpFile);
  640.     fseek(HelpFile,offset+BtreeHdr.RootPage*(long)BtreeHdr.PageSize,SEEK_SET);
  641.     for(n=1;n<BtreeHdr.NLevels;n++)
  642.     {
  643.     my_fread(&CurrNode,sizeof(BTREEINDEXHEADER),HelpFile);
  644.     for(i=0;i<CurrNode.NEntries;i++)
  645.     {
  646.         my_gets(TempFile,sizeof(TempFile),HelpFile);
  647.         if(strcmp(FileName,TempFile)<0) break;
  648.         CurrNode.PreviousPage=my_getw(HelpFile);
  649.     }
  650.     fseek(HelpFile,offset+CurrNode.PreviousPage*(long)BtreeHdr.PageSize,SEEK_SET);
  651.     }
  652.     my_fread(&CurrNode,sizeof(CurrNode),HelpFile);
  653.     for(i=0;i<CurrNode.NEntries;i++)
  654.     {
  655.     my_gets(TempFile,sizeof(TempFile),HelpFile);
  656.     offset=getdw(HelpFile);
  657.     if(strcmp(TempFile,FileName)==0)
  658.     {
  659.         fseek(HelpFile,offset,SEEK_SET);
  660.         my_fread(&FileHdr,sizeof(FileHdr),HelpFile);
  661.         if(FileLength) *FileLength=FileHdr.UsedSpace;
  662.         return TRUE;
  663.     }
  664.     }
  665.     return FALSE;
  666. }
  667.  
  668. /* read first (and next) page from B+ tree. HelpFile must be positioned
  669. // at start of internal file prior calling GetFirstPage. It will be
  670. // positioned at first B+ tree entry after return from GetFirstPage.
  671. // Number of TotalBtreeEntries stored in TotalEntries if pointer is
  672. // not NULL, NumberOfEntries of first B+ tree page returned.
  673. // buf stores position, so GetNextPage will seek to position itself. */
  674. short GetFirstPage(FILE *HelpFile,BUFFER *buf,long *TotalEntries)
  675. {
  676.     int CurrLevel;
  677.     BTREEHEADER BTreeHdr;
  678.     BTREENODEHEADER CurrNode;
  679.  
  680.     my_fread(&BTreeHdr,sizeof(BTreeHdr),HelpFile);
  681.     if(TotalEntries) *TotalEntries=BTreeHdr.TotalBtreeEntries;
  682.     if(!BTreeHdr.TotalBtreeEntries) return 0;
  683.     buf->FirstLeaf=ftell(HelpFile);
  684.     buf->PageSize=BTreeHdr.PageSize;
  685.     fseek(HelpFile,buf->FirstLeaf+BTreeHdr.RootPage*(long)BTreeHdr.PageSize,SEEK_SET);
  686.     for(CurrLevel=1;CurrLevel<BTreeHdr.NLevels;CurrLevel++)
  687.     {
  688.     my_fread(&CurrNode,sizeof(BTREEINDEXHEADER),HelpFile);
  689.     fseek(HelpFile,buf->FirstLeaf+CurrNode.PreviousPage*(long)BTreeHdr.PageSize,SEEK_SET);
  690.     }
  691.     my_fread(&CurrNode,sizeof(CurrNode),HelpFile);
  692.     buf->NextPage=CurrNode.NextPage;
  693.     return CurrNode.NEntries;
  694. }
  695.  
  696. short GetNextPage(FILE *HelpFile,BUFFER *buf) /* walk Btree */
  697. {
  698.     BTREENODEHEADER CurrNode;
  699.  
  700.     if(buf->NextPage==-1) return 0;
  701.     fseek(HelpFile,buf->FirstLeaf+buf->NextPage*(long)buf->PageSize,SEEK_SET);
  702.     my_fread(&CurrNode,sizeof(CurrNode),HelpFile);
  703.     buf->NextPage=CurrNode.NextPage;
  704.     return CurrNode.NEntries;
  705. }
  706.  
  707. /* reads next record from |SYSTEM file, returns NULL if no more available
  708. // Use last system record as parameter SysRec (saves filehandle and pos) */
  709. SYSTEMRECORD *GetNextSystemRecord(SYSTEMRECORD *SysRec)
  710. {
  711.     if(SysRec->Remaining<4)
  712.     {
  713.     free(SysRec);
  714.     return NULL;
  715.     }
  716.     fseek(SysRec->File,SysRec->SavePos,SEEK_SET);
  717.     SysRec->RecordType=my_getw(SysRec->File);
  718.     SysRec->DataSize=my_getw(SysRec->File);
  719.     SysRec->Remaining-=4;
  720.     if(SysRec->Remaining<SysRec->DataSize)
  721.     {
  722.     free(SysRec);
  723.     return NULL;
  724.     }
  725.     SysRec=my_realloc(SysRec,sizeof(SYSTEMRECORD)+SysRec->DataSize);
  726.     my_fread(SysRec->Data,SysRec->DataSize,SysRec->File);
  727.     SysRec->Data[SysRec->DataSize]='\0';
  728.     SysRec->Remaining-=SysRec->DataSize;
  729.     SysRec->SavePos=ftell(SysRec->File);
  730.     return SysRec;
  731. }
  732.  
  733. /* reads first record from |SYSTEM file, returns NULL if none found */
  734. SYSTEMRECORD *GetFirstSystemRecord(FILE *HelpFile)
  735. {
  736.     SYSTEMHEADER SysHdr;
  737.     SYSTEMRECORD *SysRec;
  738.     long FileLength;
  739.  
  740.     if(!SearchFile(HelpFile,"|SYSTEM",&FileLength)) return NULL;
  741.     my_fread(&SysHdr,sizeof(SysHdr),HelpFile);
  742.     if(SysHdr.Major!=1||SysHdr.Minor<16) return NULL;
  743.     SysRec=my_malloc(sizeof(SYSTEMRECORD));
  744.     SysRec->File=HelpFile;
  745.     SysRec->SavePos=ftell(HelpFile);
  746.     SysRec->Remaining=FileLength-sizeof(SYSTEMHEADER);
  747.     return GetNextSystemRecord(SysRec);
  748. }
  749.  
  750. void ListFiles(FILE *HelpFile) /* display internal directory */
  751. {
  752.     BUFFER buf;
  753.     char FileName[20];
  754.     int j,i,n;
  755.  
  756.     puts("FileName          FileOffset | FileName            FileOffset");
  757.     puts("-----------------------------------+-----------------------------------");
  758.     j=0;
  759.     for(n=GetFirstPage(HelpFile,&buf,NULL);n;n=GetNextPage(HelpFile,&buf))
  760.     {
  761.     for(i=0;i<n;i++)
  762.     {
  763.         my_gets(FileName,sizeof(FileName),HelpFile);
  764.         printf("%-23s 0x%08lX",FileName,getdw(HelpFile));
  765.         if(j++&1) putchar('\n'); else printf(" | ");
  766.     }
  767.     }
  768.     if(j&1) putchar('\n');
  769. }
  770.  
  771. void ListBaggage(FILE *HelpFile,FILE *hpj,BOOL before31) /* writes out [BAGGAGE] section */
  772. {
  773.     BOOL headerwritten;
  774.     char *leader;
  775.     char FileName[20];
  776.     long FileLength;
  777.     BUFFER buf;
  778.     int i,n;
  779.     FILE *f;
  780.     long savepos;
  781.  
  782.     headerwritten=FALSE;
  783.     leader="|bm"+before31;
  784.     SearchFile(HelpFile,NULL,NULL);
  785.     for(n=GetFirstPage(HelpFile,&buf,NULL);n;n=GetNextPage(HelpFile,&buf))
  786.     {
  787.     for(i=0;i<n;i++)
  788.     {
  789.         my_gets(FileName,sizeof(FileName),HelpFile);
  790.         getdw(HelpFile);
  791.         if(FileName[0]!='|'&&memcmp(FileName,leader,strlen(leader))!=0&&!strstr(FileName,".GRP")&&!strstr(FileName,".tbl"))
  792.         {
  793.         savepos=ftell(HelpFile);
  794.         if(SearchFile(HelpFile,FileName,&FileLength))
  795.         {
  796.             if(!headerwritten)
  797.             {
  798.             fputs("[BAGGAGE]\n",hpj);
  799.             headerwritten=TRUE;
  800.             }
  801.             fprintf(hpj,"%s\n",FileName);
  802.             f=my_fopen(FileName,"wb");
  803.             if(f)
  804.             {
  805.             copy(HelpFile,FileLength,f);
  806.             my_fclose(f);
  807.             }
  808.         }
  809.         fseek(HelpFile,savepos,SEEK_SET);
  810.         }
  811.     }
  812.     }
  813.     if(headerwritten) putc('\n',hpj);
  814. }
  815.  
  816. void PrintWindow(FILE *hpj,SECWINDOW *SWin)
  817. {
  818.     if(SWin->Flags&WSYSFLAG_NAME) fprintf(hpj,"%s",SWin->Name);
  819.     putc('=',hpj);
  820.     if(SWin->Flags&WSYSFLAG_CAPTION) fprintf(hpj,"\"%s\"",SWin->Caption);
  821.     putc(',',hpj);
  822.     if(SWin->Flags&(WSYSFLAG_X|WSYSFLAG_Y|WSYSFLAG_WIDTH|WSYSFLAG_HEIGHT))
  823.     {
  824.     putc('(',hpj);
  825.     if(SWin->Flags&WSYSFLAG_X) fprintf(hpj,"%d",SWin->X);
  826.     putc(',',hpj);
  827.     if(SWin->Flags&WSYSFLAG_Y) fprintf(hpj,"%d",SWin->Y);
  828.     putc(',',hpj);
  829.     if(SWin->Flags&WSYSFLAG_WIDTH) fprintf(hpj,"%d",SWin->Width);
  830.     putc(',',hpj);
  831.     if(SWin->Flags&WSYSFLAG_HEIGHT) fprintf(hpj,"%d",SWin->Height);
  832.     putc(')',hpj);
  833.     }
  834.     putc(',',hpj);
  835.     if(SWin->Maximize) fprintf(hpj,"%u",SWin->Maximize);
  836.     putc(',',hpj);
  837.     if(SWin->Flags&WSYSFLAG_RGB) fprintf(hpj,"(%d,%d,%d)",SWin->Rgb[0],SWin->Rgb[1],SWin->Rgb[2]);
  838.     putc(',',hpj);
  839.     if(SWin->Flags&WSYSFLAG_RGBNSR) fprintf(hpj,"(%d,%d,%d)",SWin->RgbNsr[0],SWin->RgbNsr[1],SWin->RgbNsr[2]);
  840.     if(SWin->Flags&(WSYSFLAG_TOP|WSYSFLAG_AUTOSIZEHEIGHT))
  841.     {
  842.     if(SWin->Flags&WSYSFLAG_AUTOSIZEHEIGHT)
  843.     {
  844.         if(SWin->Flags&WSYSFLAG_TOP)
  845.         {
  846.         fputs(",f3",hpj);
  847.         }
  848.         else
  849.         {
  850.         fputs(",f2",hpj);
  851.         }
  852.     }
  853.     else fputs(",1",hpj);
  854.     }
  855.     putc('\n',hpj);
  856. }
  857.  
  858. void PrintMVBWindow(FILE *hpj,MVBWINDOW *SWin)
  859. {
  860.     fprintf(hpj,"%s",SWin->Name);
  861.     putc('=',hpj);
  862.     fprintf(hpj,"\"%s\"",SWin->Caption);
  863.     putc(',',hpj);
  864.     putc('(',hpj);
  865.     fprintf(hpj,"%d",SWin->X);
  866.     putc(',',hpj);
  867.     fprintf(hpj,"%d",SWin->Y);
  868.     putc(',',hpj);
  869.     fprintf(hpj,"%d",SWin->Width);
  870.     putc(',',hpj);
  871.     fprintf(hpj,"%d",SWin->Height);
  872.     putc(',',hpj);
  873.     fprintf(hpj,"%d",SWin->Maximize);
  874.     putc(')',hpj);
  875.     putc(',',hpj);
  876.     putc('(',hpj);
  877.     fprintf(hpj,"%d",0);
  878.     putc(')',hpj);
  879.     putc(',',hpj);
  880.     fprintf(hpj,"(%d,%d,%d)",SWin->TopRgb[0],SWin->TopRgb[1],SWin->TopRgb[2]);
  881.     putc(',',hpj);
  882.     fprintf(hpj,"(%d,%d,%d)",SWin->RgbNsr[0],SWin->RgbNsr[1],SWin->RgbNsr[2]);
  883.     putc(',',hpj);
  884.     fprintf(hpj,"(%d,%d,%d)",SWin->Rgb[0],SWin->Rgb[1],SWin->Rgb[2]);
  885.     putc(',',hpj);
  886.     putc('(',hpj);
  887.     fprintf(hpj,"%d",SWin->X2);
  888.     putc(',',hpj);
  889.     fprintf(hpj,"%d",SWin->Y2);
  890.     putc(',',hpj);
  891.     fprintf(hpj,"%d",SWin->Width2);
  892.     putc(',',hpj);
  893.     fprintf(hpj,"%d",SWin->Height2);
  894.     putc(',',hpj);
  895.     fprintf(hpj,"%d",0);
  896.     putc(')',hpj);
  897.     putc(',',hpj);
  898.     putc('(',hpj);
  899.     fprintf(hpj,"%d",1);
  900.     putc(',',hpj);
  901.     fprintf(hpj,"%d",SWin->X3);
  902.     putc(',',hpj);
  903.     fprintf(hpj,"%d",SWin->Y3);
  904.     putc(')',hpj);
  905.     putc(',',hpj);
  906.     putc('(',hpj);
  907.     fprintf(hpj,"%d",0);
  908.     putc(')',hpj);
  909.     putc(',',hpj);
  910.     putc('(',hpj);
  911.     fprintf(hpj,"%d",1);
  912.     putc(')',hpj);
  913.     putc('\n',hpj);
  914. }
  915.  
  916. void ToMapDump(FILE *HelpFile,long FileLength)
  917. {
  918.     long i;
  919.  
  920.     for(i=0;i*4L<FileLength;i++)
  921.     {
  922.     printf("TopicNum: %-12ld TopicOffset: 0x%08lX\n",i,getdw(HelpFile));
  923.     }
  924. }
  925.  
  926. void GroupDump(FILE *HelpFile)
  927. {
  928.     GROUPHEADER GroupHeader;
  929.     char *ptr;
  930.     unsigned long i;
  931.  
  932.     my_fread(&GroupHeader,sizeof(GroupHeader),HelpFile);
  933.     switch(GroupHeader.GroupType)
  934.     {
  935.     case 2:
  936.     ptr=my_malloc(GroupHeader.BitmapSize);
  937.     my_fread(ptr,GroupHeader.BitmapSize,HelpFile);
  938.     case 1:
  939.     for(i=GroupHeader.FirstTopic;i<=GroupHeader.LastTopic;i++)
  940.     {
  941.         if(GroupHeader.GroupType==1||ptr[i>>3]&(1<<(i&7))) printf("TopicNumber: %lu\n",i);
  942.     }
  943.     break;
  944.     default:
  945.     fprintf(stderr,"GroupHeader GroupType %ld unknown\n",GroupHeader.GroupType);
  946.     }
  947. }
  948.  
  949. void KWMapDump(FILE *HelpFile)
  950. {
  951.     unsigned short n,i;
  952.     KWMAPREC KeywordMap;
  953.  
  954.     n=my_getw(HelpFile);
  955.     for(i=0;i<n;i++)
  956.     {
  957.     my_fread(&KeywordMap,sizeof(KWMAPREC),HelpFile);
  958.     printf("Keyword: %-12ld LeafPage: %u\n",KeywordMap.FirstRec,KeywordMap.PageNum);
  959.     }
  960. }
  961.  
  962. void KWDataDump(FILE *HelpFile,long FileLength)
  963. {
  964.     long i;
  965.  
  966.     for(i=0;i<FileLength;i+=4)
  967.     {
  968.     printf("KWDataAddress: 0x%08lx TopicOffset: 0x%08lX\n",i,getdw(HelpFile));
  969.     }
  970. }
  971.  
  972. void CatalogDump(FILE *HelpFile)
  973. {
  974.     CATALOGHEADER catalog;
  975.     long n;
  976.  
  977.     my_fread(&catalog,sizeof(catalog),HelpFile);
  978.     for(n=0;n<catalog.entries;n++)
  979.     {
  980.     printf("Topic: %-12ld TopicOffset: 0x%08lx\n",n+1,getdw(HelpFile));
  981.     }
  982. }
  983.  
  984. void CTXOMAPDump(FILE *HelpFile)
  985. {
  986.     CTXOMAPREC CTXORec;
  987.     unsigned short n,i;
  988.  
  989.     n=my_getw(HelpFile);
  990.     for(i=0;i<n;i++)
  991.     {
  992.     my_fread(&CTXORec,sizeof(CTXORec),HelpFile);
  993.     printf("MapId: %-12ld TopicOffset: 0x%08lX\n",CTXORec.MapID,CTXORec.TopicOffset);
  994.     }
  995. }
  996.  
  997. void LinkDump(FILE *HelpFile)
  998. {
  999.     long data[3];
  1000.     int n,i;
  1001.  
  1002.     n=my_getw(HelpFile);
  1003.     for(i=0;i<n;i++)
  1004.     {
  1005.     my_fread(data,sizeof(data),HelpFile);
  1006.     printf("Annotation for topic 0x%08lx 0x%08lx 0x%08lx\n",data[0],data[1],data[2]);
  1007.     }
  1008. }
  1009.  
  1010. void AnnotationDump(FILE *HelpFile,long FileLength,char *name)
  1011. {
  1012.     long l;
  1013.  
  1014.     printf("Annotation %s for topic 0x%08lx:\n",name,atol(name));
  1015.     for(l=0;l<FileLength;l++) putchar(getc(HelpFile));
  1016.     putchar('\n');
  1017. }
  1018.