home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / os2 / i2htm091.arj / I2HTM091.ZIP / source / inf2html.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-11-11  |  65.2 KB  |  1,782 lines

  1. /*
  2.  * inf2html.c:
  3.  *      converts a compiled .INF or .HLP file into HTML code.
  4.  *      Takes the file to be converted as command-line input.
  5.  *
  6.  *      Credits:
  7.  *      --  Most of the information for creating this stems
  8.  *          from the article in EDM/2 vol. 3 no. 8 about INF internals.
  9.  *          Big thanks go out to Peter Childs for this.
  10.  *          His work in turn is based on that of others. See inf03.txt
  11.  *          for details.
  12.  *      --  The bitmap decompression code at the bottom was
  13.  *          written by Peter Fitzsimmons, who kindly sent me
  14.  *          his code (pfitz@ican.net).
  15.  *
  16.  *      Copyright (C) 1997-98 Ulrich Möller.
  17.  *      This file is part of the INF2HTML package.
  18.  *      INF2HTML is free software; you can redistribute it and/or modify
  19.  *      it under the terms of the GNU General Public License as published
  20.  *      by the Free Software Foundation, in version 2 as it comes in the
  21.  *      "COPYING" file of INF2HTML distribution.
  22.  *      This program is distributed in the hope that it will be useful,
  23.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  24.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25.  *      GNU General Public License for more details.
  26.  */
  27.  
  28. #define INCL_DOS
  29. #define INCL_DOSERRORS
  30. #include <os2.h>
  31.  
  32. #include <pmbitmap.h>
  33.  
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38. #include <io.h>
  39. #include <fcntl.h>
  40. #include <sys\stat.h>
  41. #include <setjmp.h>         // needed for exception handlers
  42. #include <assert.h>         // needed for exception handlers
  43.  
  44. #include "inf.h"
  45. #include "inf2html.h"
  46.  
  47. #include "ansi.h"
  48.  
  49. // #define DEBUG_SPACING
  50.  
  51. /********************************************************************
  52.  *                                                                  *
  53.  *  prototypes                                                      *
  54.  *                                                                  *
  55.  *******************************************************************/
  56.  
  57. PTOCENTRY DecodeTocHeader(ULONG ulTocEntry,
  58.                           PTOCENTRYINFO ptei);
  59. VOID TranslateArticle(FILE *file,
  60.                       PTOCENTRY pteThis,
  61.                       PTOCENTRYINFO ptei);
  62. VOID TranslateSlot(FILE *file,
  63.                    PTOCENTRYINFO ptei,
  64.                    PFORMAT pFormat);
  65. BOOL DecodeINFBitmap(PSZ pszBmpFile, ULONG ulBitmapOfs,
  66.             PULONG pulWidth, PULONG pulHeight);
  67. BOOL WriteBitmapFile(int hBitmapFile,
  68.                 PINFBITMAPHEADER pbmh,
  69.                 PBYTE pbRGBTable,
  70.                 PBYTE pbBits);
  71. BOOL LZWDecompressBlock(PBYTE *ppbInput,
  72.                     FILE *fOutput,
  73.                     unsigned int number_bytes,
  74.                     unsigned long *pBytesOut,
  75.                     unsigned *pLastCode);
  76.  
  77.  
  78. CHAR        szCurrentDir[CCHMAXPATH];
  79. ULONG       cbCurrentDir = sizeof(szCurrentDir);
  80.  
  81. /********************************************************************
  82.  *                                                                  *
  83.  *  globals                                                         *
  84.  *                                                                  *
  85.  *******************************************************************/
  86.  
  87. // command line arguments
  88. CHAR        szInfFile[CCHMAXPATH] = "",
  89.             szOutputDir[CCHMAXPATH] = "",
  90.             szInfFilestem[CCHMAXPATH] = "";
  91. BOOL        optCreateFrames = FALSE,
  92.             optRewriteTitle = FALSE,
  93.             optDecodeBitmaps = FALSE,
  94.             optExcplitAutoLinks = FALSE;
  95. ULONG       ulVerboseMode = 0,
  96.             ulNavigationMode = 0,
  97.             ulMaxCharsPerLine = 70;
  98.  
  99. // file content
  100. PBYTE       pbContent = NULL;
  101.  
  102. // INF header @ offset 0
  103. PINFHEADER  pInfHeader = NULL;
  104.  
  105. // dictionary: array of CHAR pointers
  106. PSZ         apszDictionary[65536] = {0};
  107.  
  108. // slots: array of SLOT pointers
  109. PSLOT       aPSlots[65536];
  110.  
  111. // table of contents (TOC): array of TOCENTRY pointers
  112. PTOCENTRY   aPTocEntries[65535];
  113.  
  114. // bitmap count
  115. ULONG       ulBitmapCount = 0;
  116.  
  117. /********************************************************************
  118.  *                                                                  *
  119.  *  cmdline interface                                               *
  120.  *                                                                  *
  121.  *******************************************************************/
  122.  
  123. /*
  124.  * Exit:
  125.  *
  126.  */
  127.  
  128. VOID Exit(ULONG ulExit)
  129. {
  130.     DosSetCurrentDir(szCurrentDir);
  131.     DosExit(EXIT_PROCESS, ulExit);
  132. }
  133.  
  134. /*
  135.  * PrintHeader:
  136.  *
  137.  */
  138.  
  139. VOID PrintHeader(VOID)
  140. {
  141.     printf("\ninf2html V" VERSION_NUMBER " - (W)(C) 1998 Ulrich Möller");
  142.     printf("\n  This program comes with ABSOLUTELY NO WARRANTY. This is free software, ");
  143.     printf("\n  and you are welcome to redistribute it under the conditions of the GNU ");
  144.     printf("\n  General Public Licence, version 2, as specified in the 'COPYING' file of ");
  145.     printf("\n  this distribution.\n");
  146. }
  147.  
  148. /*
  149.  * Explain:
  150.  *
  151.  */
  152.  
  153. VOID Explain(VOID)
  154. {
  155.     PrintHeader();
  156.     printf("Command line usage:");
  157.     printf("\n    inf2html [-w<num>] [-vVaFTnNb] <input> [<outdir>]");
  158.     printf("\nwith:");
  159.     printf("\n    <input>     being either an INF or a HLP file");
  160.     printf("\n    <outdir>    directory for the output files; default is to create a new\n");
  161.     printf("                subdirectory from the filestem of <input>\n");
  162.     printf("General options:\n");
  163.     printf("    -v          verbose mode, list all files\n");
  164.     printf("    -V          very verbose mode, lotsa output\n");
  165.     printf("HTML output options:\n");
  166.     printf("    -w<num>     maximum no. of characters per HTML line (def: 70)\n");
  167.     printf("    -F          create frames version (index.html)\n");
  168.     printf("    -T          rewrite panel title on every page (header 1)\n");
  169.     printf("    -n          create next/back links on every page\n");
  170.     printf("    -N          dito, but include titles\n");
  171.     printf("    -b          attempt to decode bitmaps (might crash)\n");
  172.     printf("    -a          write out auto-links with target title\n");
  173.     Exit(1);
  174. }
  175.  
  176. /*
  177.  * CheckForError:
  178.  *      asserts successful completion of Dos* functions.
  179.  *      Usage: CheckForError(Dos*(), "description");
  180.  *      If the Dos* function returns an error, "description"
  181.  *      is printed with the error code.
  182.  */
  183.  
  184. VOID CheckForError(APIRET arc, PSZ pszAction)
  185. {
  186.     if (arc != NO_ERROR)
  187.     {
  188.         PSZ pszError = NULL;
  189.  
  190.         switch (arc) {
  191.             case 110: pszError = "Open failed"; break;
  192.             default: pszError = "unknown";
  193.         }
  194.  
  195.         PrintHeader();
  196.         printf("\nError %s: %s. Terminating.\n", pszAction, pszError);
  197.  
  198.         Exit(1);
  199.     }
  200. }
  201.  
  202. /*
  203.  * strrpl:
  204.  *      replace oldStr with newStr in str.
  205.  *
  206.  *      str should have enough allocated space for the replacement, no check
  207.  *      is made for this. str and OldStr/NewStr should not overlap.
  208.  *      The empty string ("") is found at the beginning of every string.
  209.  *
  210.  *      Returns: pointer to first location behind where NewStr was inserted
  211.  *      or NULL if OldStr was not found.
  212.  *      This is useful for multiple replacements also.
  213.  *      (be careful not to replace the empty string this way !)
  214.  *
  215.  *      Author:     Gilles Kohl
  216.  *      Started:    09.06.1992   12:16:47
  217.  *      Modified:   09.06.1992   12:41:41
  218.  *      Subject:    Replace one string by another in a given buffer.
  219.  *                  This code is public domain. Use freely.
  220.  */
  221.  
  222. PBYTE strrpl(PBYTE str, PBYTE oldStr, PBYTE newStr)
  223. {
  224.       int OldLen, NewLen;
  225.       char *p, *q;
  226.  
  227.       if (NULL == (p = strstr(str, oldStr)))
  228.             return p;
  229.       OldLen = strlen(oldStr);
  230.       NewLen = strlen(newStr);
  231.       memmove(q = p+NewLen, p+OldLen, strlen(p+OldLen)+1);
  232.       memcpy(p, newStr, NewLen);
  233.       return (q);
  234. }
  235.  
  236. /*
  237.  * DumpBytes:
  238.  *
  239.  */
  240.  
  241. VOID DumpBytes(PSZ pszBuf, PBYTE pb, ULONG ulCount)
  242. {
  243.     PBYTE pb2 = pb;
  244.     PSZ pszBuf2 = pszBuf;
  245.     ULONG ul;
  246.     for (ul = 0; ul < ulCount; ul++, pb2++)
  247.         pszBuf2 += sprintf(pszBuf2, "%02lX ", *pb2);
  248. }
  249.  
  250. /*
  251.  * DecodeWindowBytes:
  252.  *
  253.  */
  254.  
  255. BOOL DecodeWindowBytes(PSZ pszBuf, PBYTE pb, ULONG ulCount, PSZ pszDebug)
  256. {
  257.     BOOL         fAutoLink = FALSE,
  258.                  fSplit = FALSE,
  259.                  fViewport = FALSE,
  260.                  fDependent = FALSE,
  261.                  fTargetGroup = FALSE,
  262.                  fTargetPos = FALSE,
  263.                  fTargetSize = FALSE;
  264.     USHORT       usTargetGroup;
  265.     ULONG        ulGroup = 2,
  266.                  ulSize = 0;
  267.  
  268.     if (ulCount)
  269.     {
  270.         strcpy(pszDebug, "<!-- extra bytes: ");
  271.         DumpBytes(pszDebug+strlen(pszDebug),
  272.                 pb,
  273.                 ulCount);
  274.         strcat(pszDebug, "-->");
  275.  
  276.         // first extra byte
  277.         if ((*(pb) & 0x40))
  278.             fAutoLink = TRUE;
  279.         if ((*(pb) & 0x80))
  280.             fSplit = TRUE;
  281.         if ((*(pb) & 0x04))
  282.             fViewport = TRUE;
  283.         if ((*(pb) & 0x01))
  284.         {
  285.             fTargetPos = TRUE;
  286.             ulGroup += 5;
  287.         }
  288.         if ((*(pb) & 0x02))
  289.         {
  290.             fTargetSize = TRUE;
  291.             ulSize = ulGroup;
  292.             ulGroup += 5;
  293.         }
  294.         // second extra byte
  295.         if ((*(pb+1) & 0x02))
  296.             fDependent = TRUE;
  297.         if ((*(pb+1) & 0x04))
  298.         {
  299.             fTargetGroup = TRUE;
  300.             // if so, target group follows
  301.             // in the next 2 bytes
  302.             usTargetGroup =
  303.                 *(PUSHORT)(pb+ulGroup);
  304.         }
  305.     }
  306.  
  307.     if (fAutoLink)
  308.         strcat(pszBuf, " AUTO");
  309.     if (fSplit)
  310.         strcat(pszBuf, " SPLIT");
  311.     if (fViewport)
  312.         strcat(pszBuf, " VIEWPORT");
  313.     if (fDependent)
  314.         strcat(pszBuf, " DEPENDENT");
  315.  
  316.     if (fTargetPos)
  317.     {
  318.         if (*(pb+2) & 0x40)
  319.         {
  320.             // dynamic x-positioning
  321.             if (*(pb+3) & 0x01)
  322.                 strcat(pszBuf, " XPOS=LEFT");
  323.             if (*(pb+3) & 0x02)
  324.                 strcat(pszBuf, " XPOS=RIGHT");
  325.             if (*(pb+3) & 0x10)
  326.                 strcat(pszBuf, " XPOS=CENTER");
  327.         }
  328.         else if (*(pb+2) & 0x10)
  329.         {
  330.             // relative (percentage) x-positioning
  331.             sprintf(pszBuf+strlen(pszBuf), " XPOS=%d",
  332.                 *(PUSHORT)&(*(pb+3)));
  333.             strcat(pszBuf, "%");
  334.         }
  335.  
  336.         if (*(pb+2) & 0x04)
  337.         {
  338.             // dynamic y-positioning
  339.             if (*(pb+5) & 0x08)
  340.                 strcat(pszBuf, " YPOS=BOTTOM");
  341.             if (*(pb+5) & 0x04)
  342.                 strcat(pszBuf, " YPOS=TOP");
  343.             if (*(pb+5) & 0x10)
  344.                 strcat(pszBuf, " YPOS=CENTER");
  345.         }
  346.         else if (*(pb+2) & 0x01)
  347.         {
  348.             // relative (percentage) x-positioning
  349.             sprintf(pszBuf+strlen(pszBuf), " YPOS=%d",
  350.                 *(PUSHORT)&(*(pb+5)));
  351.             strcat(pszBuf, "%");
  352.         }
  353.     }
  354.  
  355.     if (fTargetSize)
  356.     {
  357.         if (*(pb+ulSize) & 0x40)
  358.         {
  359.             // dynamic x-positioning
  360.             if (*(pb+ulSize+1) & 0x01)
  361.                 strcat(pszBuf, " WIDTH=LEFT");
  362.             if (*(pb+ulSize+1) & 0x02)
  363.                 strcat(pszBuf, " WIDTH=RIGHT");
  364.             if (*(pb+ulSize+1) & 0x10)
  365.                 strcat(pszBuf, " WIDTH=CENTER");
  366.         }
  367.         else if (*(pb+ulSize) & 0x10)
  368.         {
  369.             // relative (percentage) x-positioning
  370.             sprintf(pszBuf+strlen(pszBuf), " WIDTH=%d",
  371.                 *(PUSHORT)&(*(pb+ulSize+1)));
  372.             strcat(pszBuf, "%");
  373.         }
  374.  
  375.         if (*(pb+ulSize) & 0x04)
  376.         {
  377.             // dynamic y-positioning
  378.             if (*(pb+ulSize+3) & 0x08)
  379.                 strcat(pszBuf, " HEIGHT=BOTTOM");
  380.             if (*(pb+ulSize+3) & 0x04)
  381.                 strcat(pszBuf, " HEIGHT=TOP");
  382.             if (*(pb+ulSize+3) & 0x10)
  383.                 strcat(pszBuf, " HEIGHT=CENTER");
  384.         }
  385.         else if (*(pb+ulSize) & 0x01)
  386.         {
  387.             // relative (percentage) x-positioning
  388.             sprintf(pszBuf+strlen(pszBuf), " HEIGHT=%d",
  389.                 *(PUSHORT)&(*(pb+ulSize+3)));
  390.             strcat(pszBuf, "%");
  391.         }
  392.     }
  393.  
  394.     if (fTargetGroup)
  395.         sprintf(pszBuf+strlen(pszBuf), " GROUP=%d",
  396.             usTargetGroup);
  397.     return (fAutoLink);
  398. }
  399.  
  400. /*
  401.  * main:
  402.  *      parses cmdline options and then sets up
  403.  *      a lot of data structures from the read-in
  404.  *      inf file; finally, it goes thru the table
  405.  *      of contents (TOC) to produce HTML output
  406.  *      files by calling subroutines
  407.  */
  408.  
  409. int main(int argc, char *argv[])
  410. {
  411.     HFILE       hfInf;
  412.     APIRET      arc;
  413.     ULONG       ulAction = 0,
  414.                 ulBytesRead = 0;
  415.     FILESTATUS3 fs3;
  416.  
  417.     PBYTE       pbTemp;
  418.     PULONG      pulTemp;
  419.  
  420.     ULONG       ul, ulTocEntry;
  421.  
  422.     CHAR        szMainIndexFile[CCHMAXPATH];
  423.     FILE        *MainIndexFile;
  424.     BYTE        bLastNestingLevel = 0;
  425.  
  426.     // parse cmdline parameters
  427.  
  428.     if (argc < 2) {
  429.         // we need at least one input file
  430.         Explain();
  431.     } else {
  432.         // parse arguments
  433.         SHORT i = 0;
  434.         while (i++ < argc-1) {
  435.             if (argv[i][0] == '-') {
  436.                 SHORT i2;
  437.                 for (i2 = 1; i2 < strlen(argv[i]); i2++) {
  438.                     switch (argv[i][i2]) {
  439.                         case 'v':
  440.                             ulVerboseMode = 1;
  441.                         break;
  442.  
  443.                         case 'V':
  444.                             ulVerboseMode = 2;
  445.                         break;
  446.  
  447.                         case 'F':
  448.                             optCreateFrames = TRUE;
  449.                         break;
  450.  
  451.                         case 'T':
  452.                             optRewriteTitle = TRUE;
  453.                         break;
  454.  
  455.                         case 'n':
  456.                             ulNavigationMode = 1;
  457.                         break;
  458.  
  459.                         case 'N':
  460.                             ulNavigationMode = 2;
  461.                         break;
  462.  
  463.                         case 'b':
  464.                             optDecodeBitmaps = TRUE;
  465.                         break;
  466.  
  467.                         case 'a':
  468.                             optExcplitAutoLinks = TRUE;
  469.                         break;
  470.  
  471.                         case 'w': {
  472.                             if (sscanf(&(argv[i][i2+1]), "%d", &ulMaxCharsPerLine) == 0)
  473.                                 Explain();
  474.                             printf("%d", ulMaxCharsPerLine);
  475.                             // skip rest of this arg
  476.                             i2 = strlen(argv[i]);
  477.                         break; }
  478.  
  479.                         default:  // unknown parameter
  480.                             Explain();
  481.                         break;
  482.                     }
  483.                 }
  484.             }
  485.             else {
  486.                 // no option ("-"): seems to be file
  487.                 if (szInfFile[0] == 0)
  488.                     // first no-option argument: must be input file
  489.                     strcpy(szInfFile, argv[i]);
  490.                 else
  491.                     // second no-option argument: must be ouput dir
  492.                     strcpy(szOutputDir, argv[i]);
  493.             }
  494.         }
  495.     }
  496.  
  497.     // OK, continue
  498.  
  499.     // open INF/HLP file
  500.     CheckForError(DosOpen(szInfFile, &hfInf, &ulAction,
  501.                             0, 0,    // write flags
  502.                             OPEN_ACTION_FAIL_IF_NEW
  503.                                 | OPEN_ACTION_OPEN_IF_EXISTS,
  504.                             OPEN_FLAGS_NOINHERIT
  505.                                 | OPEN_SHARE_DENYWRITE
  506.                                 | OPEN_ACCESS_READONLY,
  507.                             NULL), // EAs for writing
  508.                     "opening input file");
  509.  
  510.     // open successful: read complete file into buffer
  511.     CheckForError(DosQueryFileInfo(hfInf, FIL_STANDARD, &fs3, sizeof(fs3)),
  512.                     "querying file size");
  513.     pbContent = malloc(fs3.cbFile);
  514.     printf("Reading contents of \"%s\" (%d bytes)...\n", szInfFile, fs3.cbFile);
  515.     CheckForError(DosRead(hfInf, pbContent, fs3.cbFile, &ulBytesRead),
  516.                     "reading contents");
  517.     // close input file
  518.     CheckForError(DosClose(hfInf), "closing file");
  519.  
  520.     // INF header is at beginning
  521.     pInfHeader = (PINFHEADER)pbContent;
  522.  
  523.     if (pInfHeader->usMagicID != 0x5348) {
  524.         // no INF/HLP file: stop
  525.         PrintHeader();
  526.         printf("Error: \"%s\" is not an INF or HLP file.\n", szInfFile);
  527.         Exit(1);
  528.     }
  529.  
  530.     if (ulVerboseMode == 2) {
  531.         printf("Header information:\n");
  532.         printf("  Title: \"%s\"\n", pInfHeader->szTitle);
  533.         printf("  %s style\n", (pInfHeader->bFlags & 1) ? "INF" : "HLP");
  534.         printf("  No. of TOC entries:   %5d\n", pInfHeader->usNToc);
  535.         printf("  No. of res panels:    %5d\n", pInfHeader->usNRes);
  536.         printf("  No. of named panels:  %5d\n", pInfHeader->usNName);
  537.         printf("  No. of index entries: %5d\n", pInfHeader->usNIndex);
  538.         printf("  No. of slots:         %5d\n", pInfHeader->usNSlots);
  539.         printf("  No. of dict entries:  %5d\n", pInfHeader->usNDict);
  540.         printf("  Dict offset:          %5d\n", pInfHeader->ulDictStart);
  541.     }
  542.  
  543.     // find master dictionary:
  544.     pbTemp = (PBYTE)(pbContent + (pInfHeader->ulDictStart));
  545.     memset(&apszDictionary, sizeof(apszDictionary), 0);
  546.  
  547.     // set up an array of PSZs to the dictionary entries
  548.     // to speed up processing; otherwise we couldn't use
  549.     // the str* C library functions, because the dictionary
  550.     // doesn't use zero-terminated strings (duh)
  551.     if (ulVerboseMode == 2)
  552.         printf("Getting dictionary entries... \n");
  553.     for (ul = 0; ul < pInfHeader->usNDict; ul++)
  554.     {
  555.         BYTE bSizeThis = *pbTemp;
  556.         PSZ  pszThis = malloc(bSizeThis+50);
  557.  
  558.         memcpy(pszThis, pbTemp+1, bSizeThis-1);
  559.         pszThis[bSizeThis-1] = 0;
  560.         apszDictionary[ul] = pszThis;
  561.  
  562.         if (ulVerboseMode == 2)
  563.             if (((ul % 50) == 0) || (ul == pInfHeader->usNDict - 1)) {
  564.                 printf("  Item %5d out of %5d\n", ul+1, pInfHeader->usNDict);
  565.                 ANSI_up(1);
  566.             }
  567.  
  568.         pbTemp += bSizeThis;
  569.     }
  570.  
  571.     // translate special characters
  572.     if (ulVerboseMode == 2)
  573.         printf("\nTranslating special characters... \n");
  574.     for (ul = 0; ul < pInfHeader->usNDict; ul++)
  575.     {
  576.         strrpl(apszDictionary[ul], "&", "&");
  577.         strrpl(apszDictionary[ul], "<", "<");
  578.         strrpl(apszDictionary[ul], ">", ">");
  579.         strrpl(apszDictionary[ul], "ä", "ä");
  580.         strrpl(apszDictionary[ul], "ö", "ö");
  581.         strrpl(apszDictionary[ul], "ü", "ü");
  582.         strrpl(apszDictionary[ul], "ß", "ß");
  583.         strrpl(apszDictionary[ul], "Ä", "Ä");
  584.         strrpl(apszDictionary[ul], "Ö", "Ö");
  585.         strrpl(apszDictionary[ul], "Ü", "Ü");
  586.     }
  587.  
  588.     // find slots table
  589.     if (ulVerboseMode == 2)
  590.         printf("Getting slots... \n");
  591.     pulTemp = (PULONG)(pbContent + (pInfHeader->ulSlotsStart));
  592.     memset(&aPSlots, sizeof(aPSlots), 0);
  593.  
  594.     // set up an array of PSLOTs pointing to the slots in the file
  595.     for (ul = 0; ul < pInfHeader->usNSlots; ul++)
  596.     {
  597.         aPSlots[ul] = (PSLOT)(pbContent + (*pulTemp));
  598.  
  599.         if (ulVerboseMode == 2)
  600.             if (((ul % 50) == 0) || (ul == pInfHeader->usNSlots - 1)) {
  601.                 printf("  Slot %5d out of %5d\n", ul+1, pInfHeader->usNSlots);
  602.                 ANSI_up(1);
  603.             }
  604.         pulTemp++;
  605.     }
  606.  
  607.     // get table of contents (TOC)
  608.     if (ulVerboseMode == 2)
  609.         printf("\nGetting table of contents... \n");
  610.     pulTemp = (PULONG)(pbContent + (pInfHeader->ulTocStart));
  611.     memset(&aPTocEntries, sizeof(aPTocEntries), 0);
  612.  
  613.     // set up an array of PTOCENTRYs
  614.     for (ul = 0; ul < pInfHeader->usNToc; ul++)
  615.     {
  616.         aPTocEntries[ul] = (PTOCENTRY)(pbContent + (*pulTemp));
  617.  
  618.         if (ulVerboseMode == 2)
  619.             if (((ul % 50) == 0) || (ul == pInfHeader->usNToc - 1)) {
  620.                 printf("  TOC entry %5d out of %5d\n", ul+1, pInfHeader->usNToc);
  621.                 ANSI_up(1);
  622.             }
  623.             pulTemp++;
  624.     }
  625.     if (ulVerboseMode == 2)
  626.         printf("\n");
  627.  
  628.     // prepare output: create directory, if neccessary
  629.     _splitpath(szInfFile, NULL, NULL, szInfFilestem, NULL);
  630.     if (szOutputDir[0] == 0)
  631.         strcpy(szOutputDir, szInfFilestem);
  632.     printf("Output goes to dir \"%s\"\n", szOutputDir);
  633.     DosCreateDir(szOutputDir, NULL);
  634.     DosQueryCurrentDir(0, szCurrentDir, &cbCurrentDir);
  635.     CheckForError(DosSetCurrentDir(szOutputDir), "creating target directory");
  636.  
  637.     if (ulVerboseMode > 0)
  638.         printf("Creating HTML files... \n");
  639.     // create main index file; we'll keep this open while processing
  640.     // and add a new link to every HTML file we've created
  641.     sprintf(szMainIndexFile, "%s.html", szInfFilestem);
  642.     MainIndexFile = fopen(szMainIndexFile, "w");
  643.     fprintf(MainIndexFile, "<HTML>\n<HEAD>\n");
  644.     fprintf(MainIndexFile, "<TITLE>%s</TITLE>\n", pInfHeader->szTitle);
  645.     fprintf(MainIndexFile, "</HEAD>\n<BODY>\n");
  646.  
  647.     // *** translate
  648.  
  649.     // now go thru all the TOC entries and produce HTML files
  650.     for (ulTocEntry = 0; ulTocEntry < pInfHeader->usNToc; ulTocEntry++)
  651.     {
  652.         TOCENTRYINFO tei;
  653.         PTOCENTRY pteThis;
  654.         FILE    *file;
  655.         ULONG   ul1, ul2;
  656.         CHAR    szHTMLFile[CCHMAXPATH],
  657.                 szTemp[400],
  658.                 szDebug[400];
  659.  
  660.         if (ulVerboseMode == 2)
  661.             printf("Decoding TOC entry...\n");
  662.  
  663.         // have the current TOC entry decoded; this will
  664.         // fill the TOCENTRYINFO structure above and also
  665.         // return a PTOCENTRY for the current entry (ulTocEntry)
  666.         pteThis = DecodeTocHeader(ulTocEntry, &tei);
  667.  
  668.         // open HTML output file
  669.         sprintf(szHTMLFile, "%s.html", tei.szHTMLFilestem);
  670.         file = fopen(szHTMLFile, "w");
  671.  
  672.         if (ulVerboseMode == 2) {
  673.             printf("    Title: \"%s\"\n", tei.szTocTitle);
  674.             printf("    TOC level: %d, slots: %d\n",
  675.                         tei.bNestingLevel,
  676.                         pteThis->bNTocSlots);
  677.             printf("    Flags: ");
  678.             if (tei.fHidden)
  679.                 printf("hidden ");
  680.             if (tei.fHasChildren)
  681.                 printf("hasChildren ");
  682.             if (tei.fExtended)
  683.                 printf("extended");
  684.             printf("\n");
  685.         }
  686.  
  687.         if (ulVerboseMode > 0) {
  688.             printf("    %d/%d: Writing \"%s.html\"... ",
  689.                     ulTocEntry+1, pInfHeader->usNToc,
  690.                     tei.szHTMLFilestem);
  691.             ANSI_savecurs();
  692.         } else {
  693.             printf("Writing file %3d out of %3d (%3d%%)...\n",
  694.                     ulTocEntry+1, pInfHeader->usNToc,
  695.                     ((ulTocEntry+1)*100) / pInfHeader->usNToc);
  696.             ANSI_up(1);
  697.         }
  698.  
  699.         // store reference in main index file
  700.         while (bLastNestingLevel < tei.bNestingLevel) {
  701.             fprintf(MainIndexFile, "<UL>");
  702.             bLastNestingLevel ++;
  703.         }
  704.         while (bLastNestingLevel > tei.bNestingLevel) {
  705.             fprintf(MainIndexFile, "</UL>");
  706.             bLastNestingLevel--;
  707.         }
  708.         if (!tei.fHidden)
  709.             fprintf(MainIndexFile, "<LI><A HREF=\"%s.html\"%s>%s</A>\n",
  710.                     tei.szHTMLFilestem,
  711.                     (optCreateFrames) ? " TARGET=\"main\"" : "",
  712.                     tei.szTocTitle);
  713.  
  714.         // write HTML header for new file
  715.         szTemp[0] = 0;
  716.         if (tei.fExtended)
  717.             DecodeWindowBytes(szTemp,
  718.                               tei.pbExtraBytes,
  719.                               tei.bBytes2Skip,
  720.                               szDebug);
  721.         if (tei.fHidden)
  722.             strcat(szTemp, "HIDDEN");
  723.  
  724.         fprintf(file, "<HTML%s>\n<HEAD>\n", szTemp);
  725.         if (tei.fExtended)
  726.             fprintf(file, szDebug);
  727.         /* if (tei.fExtended) {
  728.             CHAR szTemp2[400];
  729.             sprintf(szTemp2, "<!-- bExt1: 0x%lX, bExt2: 0x%lX, skipped bytes: %d\n",
  730.                           tei.bExt1, tei.bExt2, tei.bBytes2Skip);
  731.             DumpBytes(szTemp2+strlen(szTemp2), tei.pbExtraBytes, tei.bBytes2Skip);
  732.             strcat(szTemp2, "-->\n");
  733.             fprintf(file, szTemp2);
  734.         } */
  735.         fprintf(file, "<TITLE>%s</TITLE>\n", tei.szTocTitle);
  736.         fprintf(file, "</HEAD>\n<BODY>\n");
  737.         if (optRewriteTitle)
  738.             fprintf(file, "<H1>%s</H1>", tei.szTocTitle);
  739.  
  740.         TranslateArticle(file, pteThis, &tei);
  741.  
  742.         // add navigation links for next/back, if desired
  743.         if (ulNavigationMode > 0) {
  744.             TOCENTRYINFO tei2;
  745.             fprintf(file, "\n\n<P><HR>\n");
  746.             if (ulTocEntry > 0) {
  747.                 DecodeTocHeader(ulTocEntry-1, &tei2);
  748.                 fprintf(file, "\n<A HREF=\"%s.html\">[%s%s]</A> ",
  749.                         tei2.szHTMLFilestem,
  750.                         (ulNavigationMode == 2) ? "Back: " : "Back",
  751.                         (ulNavigationMode == 2) ? tei2.szTocTitle : "");
  752.             }
  753.             if (ulNavigationMode == 2)
  754.                 fprintf(file, "<BR>");
  755.             if (ulTocEntry < pInfHeader->usNToc-1) {
  756.                 DecodeTocHeader(ulTocEntry+1, &tei2);
  757.                 fprintf(file, "\n<A HREF=\"%s.html\">[%s%s]</A> ",
  758.                         tei2.szHTMLFilestem,
  759.                         (ulNavigationMode == 2) ? "Next: " : "Next",
  760.                         (ulNavigationMode == 2) ? tei2.szTocTitle : "");
  761.             }
  762.         }
  763.  
  764.         // close HTML output file
  765.         fprintf(file, "\n</BODY>\n</HTML>\n");
  766.         fclose(file);
  767.     }
  768.     // done with all files:
  769.  
  770.     // close main index file
  771.     if (ulVerboseMode > 0)
  772.         printf("Writing main index \"%s\"... \n", szMainIndexFile);
  773.     fprintf(MainIndexFile, "\n</BODY>\n</HTML>\n");
  774.     fclose(MainIndexFile);
  775.  
  776.     // create "index.html" if frame mode
  777.     if (optCreateFrames) {
  778.         TOCENTRYINFO tei;
  779.         if (ulVerboseMode > 0)
  780.             printf("Writing frameset file \"index.html\" ... \n");
  781.         DecodeTocHeader(0, &tei);
  782.         MainIndexFile = fopen("index.html", "w");
  783.         fprintf(MainIndexFile, "<HTML>\n<HEAD>\n");
  784.         fprintf(MainIndexFile, "<TITLE>%s</TITLE>\n", pInfHeader->szTitle);
  785.         fprintf(MainIndexFile, "</HEAD>");
  786.         fprintf(MainIndexFile, "\n<FRAMESET cols=\"30%%, *\">");
  787.         fprintf(MainIndexFile, "\n<FRAME NAME=\"navigate\" SRC=\"%s\">", szMainIndexFile);
  788.         fprintf(MainIndexFile, "\n<FRAME NAME=\"main\" SRC=\"%s.html\">",
  789.                         tei.szHTMLFilestem);
  790.         fprintf(MainIndexFile, "\n</FRAMESET>");
  791.         fprintf(MainIndexFile, "\n<BODY>\n");
  792.         fprintf(MainIndexFile, "\n</BODY>\n</HTML>\n");
  793.         fclose(MainIndexFile);
  794.     }
  795.  
  796.     printf("\nDone!\n");
  797.  
  798.     Exit(0);
  799.     return (0); // keep compiler happy
  800. }
  801.  
  802. /********************************************************************
  803.  *                                                                  *
  804.  *  INF-to-HTML logic                                               *
  805.  *                                                                  *
  806.  *******************************************************************/
  807.  
  808. /*
  809.  * Output:
  810.  *      writes HTML output, monitoring the line
  811.  *      length
  812.  */
  813.  
  814. VOID Output(FILE *file, PSZ pszOutput, PFORMAT pFormat)
  815. {
  816.     fwrite(pszOutput, 1, strlen(pszOutput), file);
  817.     if (pFormat)
  818.         pFormat->ulCurX += strlen(pszOutput);
  819. }
  820.  
  821. /*
  822.  * DecodeTocHeader:
  823.  *      this takes an index in to the table of contents (TOC)
  824.  *      in the INF file and returns the corresponding TOCENTRY
  825.  *      pointer. Since that structure is somewhat obscure
  826.  *      with variable length struct entries, this is translated
  827.  *      into a fixed TOCENTRYINFO structure.
  828.  */
  829.  
  830. PTOCENTRY DecodeTocHeader(ULONG ulTocEntry,     // in: TOC index
  831.                           PTOCENTRYINFO ptei)   // out: TOC entry info
  832. {
  833.     CHAR        szTemp[CCHMAXPATH];
  834.     ULONG   ul1, ul2;
  835.     CHAR    *pachTitle;
  836.  
  837.     PTOCENTRY   pteThis = aPTocEntries[ulTocEntry];
  838.     PBYTE   pb = ((PBYTE)(pteThis) + sizeof(TOCENTRY));
  839.  
  840.     // now translate the TOCENTRY into TOCENTRYINFO
  841.     ptei->bNestingLevel = (pteThis->bFlags & 0x0F);
  842.     ptei->fExtended    = ((pteThis->bFlags & 0x20) != 0),
  843.     ptei->fHidden      = ((pteThis->bFlags & 0x40) != 0),
  844.     ptei->fHasChildren = ((pteThis->bFlags & 0x80) != 0),
  845.     ptei->fXPosSet = FALSE,
  846.     ptei->fYPosSet = FALSE;
  847.     ptei->bNTocSlots = pteThis->bNTocSlots;
  848.  
  849.     // "extended" flag on: extra bytes follow (see inf.h)
  850.     if (ptei->fExtended) {
  851.         ULONG ul3 = 0;
  852.         ptei->bBytes2Skip = 2; // always skip at least the first two bytes
  853.         ptei->pbExtraBytes = pb;
  854.         ptei->bExt1 = *(PBYTE)(pb);
  855.         ptei->bExt2 = *(PBYTE)(pb + 1);
  856.         if (ptei->bExt1 & 0x8)
  857.             ptei->bBytes2Skip += 2;
  858.         if (ptei->bExt1 & 0x1) {
  859.             ptei->fXPosSet = TRUE;
  860.             ptei->bBytes2Skip += 5;
  861.         }
  862.         if (ptei->bExt1 & 0x2) {
  863.             ptei->fYPosSet = TRUE;
  864.             ptei->bBytes2Skip += 5;
  865.         }
  866.         if (ptei->bExt2 & 0x4)
  867.             ptei->bBytes2Skip += 2;
  868.  
  869.         if (ulVerboseMode == 2) {
  870.             printf("  Skipping %d bytes: ", ptei->bBytes2Skip);
  871.             for (ul3 = 0; ul3 < ptei->bBytes2Skip; ul3++)
  872.                 printf("%lX ", *(PBYTE)(pb+ul3));
  873.             printf("\n");
  874.         }
  875.  
  876.         // skip
  877.         pb += ptei->bBytes2Skip;
  878.     }
  879.  
  880.     // next byte is PUSHORT to slots
  881.     ptei->pusSlotList = (PUSHORT)(pb);
  882.  
  883.     // copy TOC entry title
  884.     pachTitle = (CHAR*)(pb + (sizeof(USHORT) * ptei->bNTocSlots) );
  885.     ul1 = 0;
  886.     while (pachTitle < (PBYTE)(pteThis)
  887.                         + (pteThis->bLen))
  888.     {
  889.         ptei->szTocTitle[ul1] = *pachTitle;
  890.         ul1++;
  891.         pachTitle++;
  892.     }
  893.     ptei->szTocTitle[ul1] = 0;
  894.  
  895.     // compose HTML output filename:
  896.     ul1 = 0;
  897.     ul2 = 0;
  898.     while ((ptei->szTocTitle[ul2]) && (ul1 < 20))
  899.     {
  900.         // skip characters which we don't want in filename
  901.         if (    (!strchr(".<>?*|+ = -:;, /[]()\\\"\' ", ptei->szTocTitle[ul2]))
  902.              && (ptei->szTocTitle[ul2] > (CHAR)32)
  903.            )
  904.         {
  905.             szTemp[ul1] = ptei->szTocTitle[ul2];
  906.             ul1++;
  907.         }
  908.         ul2++;
  909.     }
  910.     szTemp[ul1] = 0;
  911.     // format is: <TOC entry index>_L<level>_<title>
  912.     // "H" is added to the level if the entry is hidden.
  913.     // Note that ".html" is not added here, because the
  914.     // filestem is needed for bitmap files also.
  915.     sprintf(ptei->szHTMLFilestem, "%03d_L%d%s_%s",
  916.             ulTocEntry,
  917.             ptei->bNestingLevel,
  918.             (ptei->fHidden) ? "H" : "",
  919.             szTemp);
  920.  
  921.     return (pteThis);
  922. }
  923.  
  924. /*
  925.  * TranslateArticle:
  926.  *
  927.  */
  928.  
  929. VOID TranslateArticle(FILE *file,          // output file (from fopen)
  930.                       PTOCENTRY pteThis,
  931.                       PTOCENTRYINFO ptei)     // info structure maintained by main()
  932. {
  933.     USHORT  usSlot;
  934.     FORMAT  Format = {0};
  935.     CHAR    szTemp[100];
  936.     // reset format info structure (we need to maintain
  937.     // formatting info across several slots)
  938.     memset(&Format, sizeof(Format), 0);
  939.     Format.fSpace = TRUE;
  940.  
  941.     for (usSlot = 0; usSlot < pteThis->bNTocSlots; usSlot++)
  942.     {
  943.         if (ulVerboseMode > 0) {
  944.             ANSI_restcurs();
  945.             printf("%3d%%", (usSlot *100 / (pteThis->bNTocSlots+1)));
  946.             fflush(stdout);
  947.         }
  948.  
  949.         sprintf(szTemp, "<!-- entering slot %d -->", *(ptei->pusSlotList));
  950.         Output(file, szTemp, &Format);
  951.  
  952.         // decode!! this will write HTML code
  953.         TranslateSlot(file, ptei, &Format);
  954.  
  955.         // next slot
  956.         ptei->pusSlotList++;
  957.     }
  958.  
  959.     if (ulVerboseMode > 0) {
  960.         ANSI_restcurs();
  961.         printf("100\n");
  962.     }
  963. }
  964.  
  965. /*
  966.  * TranslateSlot:
  967.  *      goes through the contents of one slot and
  968.  *      puts out HTML text into "file", using the
  969.  *      local and global dictionaries and all that.
  970.  *      Each article is composed of at least one
  971.  *      slot; is has several slots if the localdict
  972.  *      contains more than 250 different words.
  973.  */
  974.  
  975. VOID TranslateSlot(FILE *file,          // output file (from fopen)
  976.                    PTOCENTRYINFO ptei,  // info structure from DecodeTocHeader
  977.                    PFORMAT pFormat)     // formatting info; since formatting flags
  978.                            // need to be maintained across slots, if one panel has
  979.                            // several slots, we need a permanent structure
  980. {
  981.     // get current slot number (updated by main())
  982.     USHORT usSlot = *(ptei->pusSlotList);
  983.  
  984.     if (usSlot < pInfHeader->usNSlots)
  985.     {
  986.  
  987.         // get pointer to slot structure in INF file data
  988.         PSLOT       pSlotThis = aPSlots[usSlot];
  989.         ULONG       ulCode;
  990.  
  991.         // get pointer to slot's local dictionary
  992.         PLOCALDICT  pLocalDict = (PLOCALDICT)(pbContent + (pSlotThis->ulLocalDictStart));
  993.  
  994.         // now go through the encoded data of this slot byte by byte
  995.         for (ulCode = 0 ; ulCode < pSlotThis->usNText; ulCode++ )
  996.  
  997.             switch(pSlotThis->abText[ulCode])
  998.             {
  999.                 // check for special codes:
  1000.  
  1001.                 // end of paragraph, sets space to TRUE
  1002.                 case 0xfa:
  1003.                     if (!pFormat->fJustHadBullet)
  1004.                         if (pFormat->ulLeftMargin < pFormat->ulLastLeftMargin)
  1005.                         {
  1006.                             Output(file, "\n</UL>", pFormat);
  1007.                             pFormat->fJustHadBullet = FALSE;
  1008.                             pFormat->ulLastLeftMargin = pFormat->ulLeftMargin;
  1009.                             break;
  1010.                         }
  1011.  
  1012.                     if (!pFormat->fMonoSpace)
  1013.                         fprintf(file, "\n<P>\n");
  1014.                     else
  1015.                         fprintf(file, "\n");
  1016.                     pFormat->ulCurX = 0;
  1017.                     pFormat->fSpace = TRUE;
  1018.                     pFormat->fJustHadLinebreak = TRUE;
  1019.                     pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1020.                     break;
  1021.  
  1022.                 // line break, set space to TRUE if not monospaced example
  1023.                 case 0xfd:
  1024.                     if (!pFormat->fJustHadBullet)
  1025.                         if (pFormat->ulLeftMargin < pFormat->ulLastLeftMargin)
  1026.                         {
  1027.                             fprintf(file, "\n</UL>");
  1028.                             pFormat->ulCurX = 5;
  1029.                             pFormat->fJustHadBullet = FALSE;
  1030.                             pFormat->ulLastLeftMargin = pFormat->ulLeftMargin;
  1031.                             pFormat->fSuppressNextBR = TRUE;
  1032.                             pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1033.                             break;
  1034.                         }
  1035.  
  1036.                     if (!pFormat->fSuppressNextBR)
  1037.                     {
  1038.                         if (!(pFormat->fMonoSpace)) {
  1039.                             fprintf(file, "\n<BR>\n");
  1040.                             pFormat->fSpace = TRUE;
  1041.                             pFormat->fJustHadLinebreak = TRUE;
  1042.                         } else
  1043.                             fprintf(file, "\n");
  1044.                         pFormat->ulCurX = 0;
  1045.                         pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1046.                     } else
  1047.                         pFormat->fSuppressNextBR = FALSE;
  1048.                 break;
  1049.  
  1050.                 // [unknown]
  1051.                 case 0xfb:
  1052.                     Output(file, "<!--0xfb-->", pFormat);
  1053.                     break;
  1054.  
  1055.                 // spacing = !spacing
  1056.                 case 0xfc:
  1057.                     pFormat->fSpace = !(pFormat->fSpace);
  1058.                     #ifdef DEBUG_SPACING
  1059.                         fprintf(file, "<!--spacing %d-->", pFormat->fSpace);
  1060.                     #endif
  1061.                     break;
  1062.  
  1063.                 // space
  1064.                 case 0xfe:
  1065.                     // if the line is long enough, put out linebreak
  1066.                     if (pFormat->ulCurX > ulMaxCharsPerLine) {
  1067.                         fprintf(file, "\n");
  1068.                         pFormat->ulCurX = 0;
  1069.                         pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1070.                     } else {
  1071.                         // else normal space
  1072.                         fprintf(file, " ");
  1073.                         pFormat->ulCurX++;
  1074.                     }
  1075.                 break;
  1076.  
  1077.                 // escape code
  1078.                 case 0xff: {
  1079.                     BYTE bEscLen  = pSlotThis->abText[ulCode+1];
  1080.                     BYTE bEscCode = pSlotThis->abText[ulCode+2];
  1081.  
  1082.                     switch (bEscCode)
  1083.                     {
  1084.                         // formatting flags:
  1085.                         case 0x04: {
  1086.                             BYTE bFormat = pSlotThis->abText[ulCode+3];
  1087.                             switch (bFormat) {
  1088.                                 case 1: // italics
  1089.                                     Output(file, "<I>", pFormat);
  1090.                                     pFormat->fItalics = TRUE;
  1091.                                     break;
  1092.                                 case 2: // bold
  1093.                                     Output(file, "<B>", pFormat);
  1094.                                     pFormat->fBold = TRUE;
  1095.                                     break;
  1096.                                 case 3: // bold italics
  1097.                                     Output(file, "<B><I>", pFormat);
  1098.                                     pFormat->fBold = TRUE;
  1099.                                     pFormat->fItalics = TRUE;
  1100.                                     break;
  1101.                                 case 5: // underlined
  1102.                                     Output(file, "<U>", pFormat);
  1103.                                     pFormat->fUnderlined = TRUE;
  1104.                                     break;
  1105.                                 case 6: // italics underlined
  1106.                                     Output(file, "<U><I>", pFormat);
  1107.                                     pFormat->fUnderlined = TRUE;
  1108.                                     pFormat->fItalics = TRUE;
  1109.                                     break;
  1110.                                 case 7: // bold underlined
  1111.                                     Output(file, "<B><U>", pFormat);
  1112.                                     pFormat->fBold = TRUE;
  1113.                                     pFormat->fUnderlined = TRUE;
  1114.                                     break;
  1115.                                 case 0: // reset (plain text)
  1116.                                     if (pFormat->fBold)
  1117.                                         Output(file, "</B>", pFormat);
  1118.                                     if (pFormat->fItalics)
  1119.                                         Output(file, "</I>", pFormat);
  1120.                                     if (pFormat->fUnderlined)
  1121.                                         Output(file, "</U>", pFormat);
  1122.                                     pFormat->fBold = FALSE;
  1123.                                     pFormat->fItalics = FALSE;
  1124.                                     pFormat->fUnderlined = FALSE;
  1125.                                 break;
  1126.                             }
  1127.                         break; }
  1128.  
  1129.                         // begin link
  1130.                         case 0x05:  // "real" link
  1131.                         case 0x07:  // footnote
  1132.                         {
  1133.                             // the next two bytes are are a USHORT index into
  1134.                             // the TOC array
  1135.                             PUSHORT pusTarget = (PUSHORT)&(pSlotThis->abText[ulCode+3]);
  1136.                             TOCENTRYINFO teiTarget;
  1137.                             CHAR         szTemp[400] = "",
  1138.                                          szDebug[400] = "";
  1139.                             ULONG        ul;
  1140.                             BOOL         fAutoLink = FALSE;
  1141.  
  1142.                             // set up HTML filename to link to
  1143.                             DecodeTocHeader(*pusTarget, &teiTarget);
  1144.  
  1145.                             strcpy(szTemp, "<A");
  1146.                             if (bEscLen >= 5)
  1147.                                 fAutoLink = DecodeWindowBytes(szTemp+strlen(szTemp),
  1148.                                         &(pSlotThis->abText[ulCode+5]),
  1149.                                         bEscLen-4,
  1150.                                         szDebug);
  1151.  
  1152.                             sprintf(szTemp+strlen(szTemp), " HREF=\"%s.html\">",
  1153.                                     teiTarget.szHTMLFilestem);
  1154.                             if (fAutoLink) {
  1155.                                 if (optExcplitAutoLinks) {
  1156.                                     strcat(szTemp, "[Autolink] ");
  1157.                                     strcat(szTemp, teiTarget.szTocTitle);
  1158.                                 }
  1159.                                 strcat(szTemp, "</A><P>");
  1160.                             }
  1161.  
  1162.                             if (pFormat->fOutputSpaceBeforeNextWord) {
  1163.                                 Output(file, " ", pFormat);
  1164.                                 pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1165.                             }
  1166.                             Output(file, szTemp, pFormat);
  1167.                             Output(file, szDebug, pFormat);
  1168.                         break; }
  1169.  
  1170.                         // end link:
  1171.                         case 0x08: {
  1172.                             Output(file, "</A>", pFormat);
  1173.                         break; }
  1174.  
  1175.                         // left margin:
  1176.                         case 0x2:
  1177.                         case 0x11:
  1178.                         case 0x12: {
  1179.                             CHAR szTemp[100];
  1180.                             ULONG ulNewLeftMargin = pSlotThis->abText[ulCode+3];
  1181.                             sprintf(szTemp, "<!-- lm: 0x%lX %d -->",
  1182.                                     bEscCode, ulNewLeftMargin);
  1183.                             Output(file, szTemp, pFormat);
  1184.                             pFormat->ulLeftMargin = ulNewLeftMargin;
  1185.                             pFormat->fJustHadLeftMargin = TRUE;
  1186.                             if (!pFormat->fJustHadBullet)
  1187.                                 if (ulNewLeftMargin > pFormat->ulLastLeftMargin)
  1188.                                 {
  1189.                                     Output(file, "\n<UL>", pFormat);
  1190.                                     pFormat->fJustHadBullet = FALSE;
  1191.                                     pFormat->ulLastLeftMargin = ulNewLeftMargin;
  1192.                                 }
  1193.                         break; }
  1194.  
  1195.                         // begin monospace:
  1196.                         case 0x0B:
  1197.                             if (bEscLen == 0x02) {
  1198.                                 pFormat->fMonoSpace = TRUE;  // begin monospaced example!
  1199.                                 pFormat->fSpace = FALSE;
  1200.                                 fprintf(file, "\n<PRE>");
  1201.                                 pFormat->ulCurX = 5;
  1202.                                 pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1203.                             }
  1204.                         break;
  1205.  
  1206.                         // end monospace
  1207.                         case 0x0C:
  1208.                             if (bEscLen == 0x02) {
  1209.                                 pFormat->fMonoSpace = FALSE;  // end monospaced example!
  1210.                                 pFormat->fSpace = TRUE;
  1211.                                 fprintf(file, "</PRE>\n");
  1212.                                 pFormat->ulCurX = 0;
  1213.                                 pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1214.                             }
  1215.                         break;
  1216.  
  1217.                         // bitmap
  1218.                         case 0x0E: {
  1219.                             CHAR szBmpFile[CCHMAXPATH],
  1220.                                  szTemp[400];
  1221.                             BYTE bBitmapFlags = pSlotThis->abText[ulCode+3];
  1222.                             ULONG ulBitmapOfs = *(PULONG)&(pSlotThis->abText[ulCode+4]);
  1223.                             ULONG ulWidth, ulHeight;
  1224.  
  1225.                             sprintf(szBmpFile, "%s_%d.bmp",
  1226.                                     ptei->szHTMLFilestem,
  1227.                                     ulBitmapCount);
  1228.  
  1229.                             if (!DecodeINFBitmap(szBmpFile, ulBitmapOfs,
  1230.                                         &ulWidth, &ulHeight))
  1231.                                 Output(file, "<!-- Unable to decode bitmap format -->",
  1232.                                         pFormat);
  1233.  
  1234.                             sprintf(szTemp, "<IMG SRC=\"%s_%d.gif\" WIDTH=%d HEIGHT=%d",
  1235.                                     ptei->szHTMLFilestem,
  1236.                                     ulBitmapCount,
  1237.                                     ulWidth, ulHeight);
  1238.                             /* if (bBitmapFlags & 0x01)
  1239.                                 strcat(szTemp, " ALIGN=left"); */
  1240.                                         // left not needed
  1241.                             if (bBitmapFlags & 0x02)
  1242.                                 strcat(szTemp, " ALIGN=right");
  1243.                             if (bBitmapFlags & 0x04)
  1244.                                 strcat(szTemp, " ALIGN=center");
  1245.                             strcat(szTemp, ">");
  1246.                             /* if (bBitmapFlags & 0x08 ) printf ("Fit ");
  1247.                                 strcat(szTemp, "left");
  1248.                             if (bBitmapFlags & 0x10 ) printf ("Runin ");  // 00010000
  1249.                                 strcat(szTemp, "left");   */
  1250.                             Output(file, szTemp, pFormat);
  1251.                             ulBitmapCount++;
  1252.                         break; }
  1253.  
  1254.                         // link to external file
  1255.                         case 0x1D: {
  1256.                             CHAR szTemp[400];
  1257.                             PUSHORT pusTarget = (PUSHORT)&(pSlotThis->abText[ulCode+3]);
  1258.                             int i;
  1259.                             /* sprintf(szTemp, "<!-- external link: ");
  1260.                             strcat(szTemp, pbContent+
  1261.                                            pInfHeader->ulExtStart
  1262.                                            + (*pusTarget));
  1263.                                            // );
  1264.                             strcat(szTemp, " -->");
  1265.                             Output(file, szTemp, pFormat); */
  1266.                             strcpy(szTemp, "<A><!-- external link: ");
  1267.                             DumpBytes(szTemp+strlen(szTemp),
  1268.                                 &(pSlotThis->abText[ulCode+2]),
  1269.                                 bEscLen);
  1270.                             strcat(szTemp, "-->");
  1271.                             Output(file, szTemp, pFormat);
  1272.                             /* for (i = 0; i < 4096; i+=128)
  1273.                             {
  1274.                                 fprintf(file, "%04lX: ", i);
  1275.                                 fwrite(pbContent+
  1276.                                        pInfHeader->ulExtStart
  1277.                                        // + (*pusTarget)
  1278.                                        + i,
  1279.                                        1, 128, file);
  1280.                                 fprintf(file, "\n");
  1281.                             } */
  1282.                         break; }
  1283.  
  1284.                         default: {
  1285.                             /*  */
  1286.                         }
  1287.  
  1288.                     } // end switch (bEscCode)
  1289.  
  1290.                     ulCode = ulCode + bEscLen; // skip the esccode!
  1291.                 break; }
  1292.  
  1293.                 // other code: should be offset into dictionaries
  1294.                 default: {
  1295.                     BYTE  bLocalDictOfs = pSlotThis->abText[ulCode];
  1296.                     USHORT usGlobalDictOfs = pLocalDict->usEntries[bLocalDictOfs];
  1297.  
  1298.                     if (    (pFormat->fJustHadLinebreak)
  1299.                          && (pFormat->fJustHadLeftMargin)
  1300.                          && (!pFormat->fMonoSpace)
  1301.                        )
  1302.                     {
  1303.                         // graphics character? seems to be list bullet
  1304.                         if (    (strlen(apszDictionary[usGlobalDictOfs]) == 1)
  1305.                              && ( (isalpha(*apszDictionary[usGlobalDictOfs]) == 0) )
  1306.                            )
  1307.                         {
  1308.                             pFormat->fJustHadBullet = TRUE;
  1309.                             Output(file, "<LI>", pFormat);
  1310.                             break; // don't print explicit bullet
  1311.                             /* if (pFormat->ulLastLeftMargin == pFormat->ulLeftMargin)
  1312.                                 Output(file, "<LI>", pFormat);
  1313.                             else if (pFormat->ulLastLeftMargin > pFormat->ulLeftMargin) {
  1314.                                 Output(file, "</UL><LI>", pFormat);
  1315.                                 pFormat->ulLastLeftMargin = pFormat->ulLeftMargin;
  1316.                             } else if (pFormat->ulLastLeftMargin < pFormat->ulLeftMargin) {
  1317.                                 Output(file, "<UL><LI>", pFormat);
  1318.                                 pFormat->ulLastLeftMargin = pFormat->ulLeftMargin;
  1319.                             }
  1320.                             break; */
  1321.                         }
  1322.                         /* else
  1323.                             if (pFormat->ulLastLeftMargin > pFormat->ulLeftMargin)
  1324.                             {
  1325.                                 CHAR szTemp[100];
  1326.                                 sprintf(szTemp, "</UL><!-- lm now: %d -->",
  1327.                                         pFormat->ulLeftMargin);
  1328.                                 Output(file, szTemp, pFormat);
  1329.                                 pFormat->ulLastLeftMargin = pFormat->ulLeftMargin;
  1330.                             }  */
  1331.                     }
  1332.  
  1333.                     // otherwise: print word from global dictionary
  1334.                     if (pFormat->fOutputSpaceBeforeNextWord) {
  1335.                         Output(file, " ", pFormat);
  1336.                         pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1337.                     }
  1338.                     Output(file, apszDictionary[usGlobalDictOfs], pFormat);
  1339.  
  1340.                     // increase X count for line breaks in HTML source
  1341.                     // pFormat->ulCurX += strlen(apszDictionary[usGlobalDictOfs]);
  1342.                     pFormat->fJustHadLeftMargin = FALSE;
  1343.                     pFormat->fJustHadLinebreak = FALSE;
  1344.                     pFormat->fJustHadBullet = FALSE;
  1345.  
  1346.                     if (pFormat->fSpace) {
  1347.                         pFormat->fOutputSpaceBeforeNextWord = TRUE;
  1348.                         // Output(file, " ", pFormat);
  1349.                         // pFormat->ulCurX++;
  1350.  
  1351.                         if (!pFormat->fMonoSpace)
  1352.                             // line long enough?
  1353.                             if (pFormat->ulCurX > ulMaxCharsPerLine) {
  1354.                                 // insert line break in HTML source
  1355.                                 fprintf(file, "\n");
  1356.                                 pFormat->ulCurX = 0;
  1357.                                 pFormat->fOutputSpaceBeforeNextWord = FALSE;
  1358.                             }
  1359.                     }
  1360.                     break;
  1361.                 }
  1362.             }
  1363.     } else {
  1364.         // shouldn't happen
  1365.         Output(file, "<!-- Error: invalid slot number found -->", pFormat);
  1366.         if (ulVerboseMode > 0)
  1367.             printf("\nError: Invalid slot number %d\n", usSlot);
  1368.     }
  1369. }
  1370.  
  1371. /********************************************************************
  1372.  *                                                                  *
  1373.  *  bitmap handling                                                 *
  1374.  *                                                                  *
  1375.  *******************************************************************/
  1376.  
  1377. /*
  1378.  * DecodeINFBitmap:
  1379.  *      this is called by TranslateSlot above ifottom is used.
  1380.  */
  1381.  
  1382. #define BFT_bMAP           0x4d62   /* 'bM' */
  1383.  
  1384. BOOL DecodeINFBitmap(PSZ pszBmpFile,        // in: bmp filename to create
  1385.                      ULONG ulBitmapOfs,     // in: bmp data offset in file
  1386.                      PULONG pulWidth,       // out: bitmap dimensions
  1387.                      PULONG pulHeight)
  1388. {
  1389.     BOOL brc = FALSE;
  1390.  
  1391.     // get start of this bitmap in file
  1392.     PBYTE pBitmapStart = pbContent + (pInfHeader->ulImgStart) + ulBitmapOfs;
  1393.     PINFBITMAPHEADER pbmh = (PINFBITMAPHEADER)pBitmapStart;
  1394.  
  1395.     *pulWidth = pbmh->cx;
  1396.     *pulHeight = pbmh->cy;
  1397.  
  1398.     pbmh->offBits = 14 + pbmh->cbFix;
  1399.     if (pbmh->cBitCount < 24)
  1400.         pbmh->offBits += ( 3 * (1 << (pbmh->cBitCount)) );
  1401.  
  1402.     if (ulVerboseMode > 0) {
  1403.         printf("\nWriting bitmap: %s", pszBmpFile);
  1404.         fflush(stdout);
  1405.     }
  1406.  
  1407.     if (optDecodeBitmaps)
  1408.         if (    (*(PCHAR)pBitmapStart == 'b')
  1409.              // && (*(PCHAR)pBitmapStart+1 == 'M')
  1410.            )
  1411.         {
  1412.             FILE *fBitmap = fopen(pszBmpFile, "wb");
  1413.             SHORT sRgbTableSize,
  1414.                   sScanLineSize;
  1415.             if (fBitmap)
  1416.             {
  1417.                 unsigned int last_out_code;
  1418.                 ULONG   ulTotalBytesToOutput,
  1419.                         ulBytesRead, ulTotal;
  1420.                 ULONG bytes_output;
  1421.                 PBMPDATAHEADER pHeader;
  1422.                 PBMPDATABLOCK pBlock;
  1423.                 PBYTE pbCurrent = (PBYTE)pbmh;
  1424.                 PBYTE pRGBData;
  1425.                 ULONG   ulBlockCount = 0;
  1426.  
  1427.                 BITMAPFILEHEADER bmfh;
  1428.  
  1429.                 if (ulVerboseMode >=2 )
  1430.                     printf("\n  Bitmap header:\n    usType    = %x (%c%c)\n",
  1431.                         pbmh->usType,
  1432.                         LOBYTE(pbmh->usType), HIBYTE(pbmh->usType)  );
  1433.                 if(pbmh->usType != BFT_BMAP && pbmh->usType != BFT_bMAP)
  1434.                     return FALSE;
  1435.                 if (ulVerboseMode >=2 ) {
  1436.                     printf("    cbSize    = %d\n", pbmh->cbSize   );
  1437.                     printf("    xHotspot  = %d\n", pbmh->xHotspot );
  1438.                     printf("    yHotspot  = %d\n", pbmh->yHotspot );
  1439.                     printf("    offBits   = %d\n", pbmh->offBits  );
  1440.                     printf("    bmp.cbFix       = %d\n", pbmh->cbFix      );
  1441.                     printf("    bmp.cx          = %d\n", pbmh->cx         );
  1442.                     printf("    bmp.cy          = %d\n", pbmh->cy         );
  1443.                     printf("    bmp.cPlanes     = %d\n", pbmh->cPlanes    );
  1444.                     printf("    bmp.cBitCount   = %d\n", pbmh->cBitCount  );
  1445.                 }
  1446.  
  1447.                 if (pbmh->cBitCount < 9)
  1448.                 {
  1449.                     sRgbTableSize = (1 << pbmh->cPlanes * pbmh->cBitCount)
  1450.                                             * sizeof(RGB);
  1451.                     if(sRgbTableSize > 0x10000)
  1452.                         return (FALSE);
  1453.                 }
  1454.                 else
  1455.                     sRgbTableSize = 0;
  1456.  
  1457.                 bmfh.usType = BFT_BMAP;
  1458.                 sScanLineSize = ((pbmh->cBitCount * pbmh->cx + 31) / 32)
  1459.                                 * 4 * pbmh->cPlanes;
  1460.                 bmfh.cbSize = sizeof(BITMAPFILEHEADER);
  1461.                 bmfh.xHotspot = 0;
  1462.                 bmfh.yHotspot = 0;
  1463.                 bmfh.offBits = sizeof(BITMAPFILEHEADER) + sRgbTableSize;
  1464.  
  1465.                 bmfh.bmp.cbFix = pbmh->cbFix;
  1466.                 bmfh.bmp.cx = pbmh->cx;
  1467.                 bmfh.bmp.cy = pbmh->cy;
  1468.                 bmfh.bmp.cPlanes = pbmh->cPlanes;
  1469.                 bmfh.bmp.cBitCount = pbmh->cBitCount;
  1470.  
  1471.                 if (ulVerboseMode >=2 ) {
  1472.                     printf("  Calculating:\n    sRgbTableSize = %d\n", sRgbTableSize);
  1473.                     printf("    sScanLineSize = %d\n", sScanLineSize);
  1474.                     printf("    new offBits   = %d\n", pbmh->offBits);
  1475.                 }
  1476.  
  1477.                 fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, fBitmap);
  1478.  
  1479.                 // go to RGB data
  1480.                 pbCurrent = ((PBYTE)pbmh) + sizeof(BITMAPFILEHEADER);
  1481.  
  1482.                 if (sRgbTableSize)
  1483.                 {
  1484.                     pRGBData = pbCurrent;
  1485.                     fwrite(pRGBData, 1, sRgbTableSize, fBitmap);
  1486.                     pbCurrent += sRgbTableSize;
  1487.                 }
  1488.  
  1489.                 ulTotalBytesToOutput = sScanLineSize * pbmh->cy;
  1490.                 if (ulVerboseMode >=2 )
  1491.                     printf("    ulTotalBytesToOutput = %ld\n", ulTotalBytesToOutput);
  1492.  
  1493.                 pHeader = (PBMPDATAHEADER)pbCurrent;
  1494.  
  1495.                 pbCurrent += sizeof(BMPDATAHEADER);
  1496.                 if (ulVerboseMode >=2 ) {
  1497.                     printf("    Length of data = %d\n", pHeader->ulTotalSize);
  1498.                     printf("    Uncompressed data block size  = %d\n", pHeader->usUncompPerBlock);
  1499.                 }
  1500.  
  1501.                 ulBytesRead = sizeof(pHeader->usUncompPerBlock);  // 2
  1502.  
  1503.                 ulTotal = 0L;
  1504.                 while (ulBytesRead < pHeader->ulTotalSize) {
  1505.                     PBYTE pbInput;
  1506.                     pBlock = (PBMPDATABLOCK)pbCurrent;
  1507.                     ulBlockCount++;
  1508.  
  1509.                     if (ulVerboseMode >=2 )
  1510.                         printf("    Block %d: size %d, compression type %d\n",
  1511.                                 ulBlockCount,
  1512.                                 pBlock->usCompressedSize, pBlock->ucCompressionType);
  1513.  
  1514.                     bytes_output = 0;
  1515.                     pbInput = &(pBlock->Data);
  1516.                     if (!LZWDecompressBlock(&pbInput,
  1517.                                 fBitmap,
  1518.                                 (pBlock->usCompressedSize)-1,
  1519.                                 &bytes_output,
  1520.                                 &last_out_code))
  1521.                     {
  1522.                         printf("\nError: LZWDecompression failed -\n");
  1523.                     }
  1524.  
  1525.                     if (ulVerboseMode >=2 )
  1526.                         printf("    bytes_output = %d\n", bytes_output);
  1527.  
  1528.                     if (ferror(fBitmap))
  1529.                     {
  1530.                         fclose(fBitmap);
  1531.                         printf("\nError writing bitmap file %s (disk full?)\n",
  1532.                                 pszBmpFile);
  1533.                         Exit(1);
  1534.                     }
  1535.                     ulBytesRead += sizeof(BMPDATABLOCK) + pBlock->usCompressedSize-1;
  1536.                     ulTotal += bytes_output;
  1537.                     if (ulVerboseMode >=2 ) {
  1538.                         printf("    Bytes written from this block: %ld\n", bytes_output);
  1539.                         printf("    Total so far =  %ld (of %ld)\n",
  1540.                                         ulTotal, ulTotalBytesToOutput);
  1541.                         printf("    Bytes read so far =  %ld (of %ld)\n",
  1542.                                 ulBytesRead, pHeader->ulTotalSize);
  1543.                     }
  1544.  
  1545.                     if (    (bytes_output < pHeader->usUncompPerBlock)
  1546.                          && (ulTotal < ulTotalBytesToOutput)
  1547.                        )
  1548.                     {
  1549.                         unsigned i, cb;
  1550.                         cb = pHeader->usUncompPerBlock - bytes_output;
  1551.                         cb = min(cb, ulTotalBytesToOutput - ulTotal);
  1552.                         if (ulVerboseMode >=2 )
  1553.                             printf("    Catch up %d bytes\n",  cb);
  1554.                         ulTotal += cb;
  1555.                         for(i=0; i<cb; i++)
  1556.                             putc(last_out_code, fBitmap);
  1557.                     }
  1558.                     //flushall();
  1559.  
  1560.                     pbCurrent += ((pBlock->usCompressedSize) + 2);
  1561.                 }
  1562.                 fclose(fBitmap);
  1563.                 *pulWidth = pbmh->cx;
  1564.                 *pulHeight = pbmh->cy;
  1565.             } else {
  1566.                 printf("    Error!");
  1567.                 return (FALSE);
  1568.             }
  1569.         }
  1570.  
  1571.     return (brc);
  1572. }
  1573.  
  1574. /********************************************************************
  1575.  *                                                                  *
  1576.  *  LZW decompression                                               *
  1577.  *                                                                  *
  1578.  *******************************************************************/
  1579.  
  1580. /*
  1581.  *  This is based on code (W) by Peter Fitzsimmons, pfitz@ican.net.
  1582.  *  His liner notes in the original:
  1583.  *      has its roots in a June 1990
  1584.  *      DDJ article "LZW REVISITED", by Shawn M. Regan
  1585.  *      --=>revision history<=--
  1586.  *      1 lzw.c 21-Aug-96,2:24:36,`PLF' ;
  1587.  *      2 lzw.c 24-Aug-96,2:27:24,`PLF' wip
  1588.  *
  1589.  *  The code has been modified to take the input not from an
  1590.  *  open file, but from any memory region. For this, a double
  1591.  *  pointer is used, which must be passed to LZWDecompressBlock.
  1592.  *  I've also added a few comments for clarity.
  1593.  *
  1594.  */
  1595.  
  1596. /* -- Stuff for LZW decompression -- */
  1597. #define INIT_BITS 9
  1598. #define MAX_BITS 12     /*PLF Tue  95-10-03 02:16:56*/
  1599. #define HASHING_SHIFT MAX_BITS - 8
  1600.  
  1601. #if MAX_BITS == 15
  1602. #define TABLE_SIZE 36768
  1603. #elif MAX_BITS == 14
  1604. #define TABLE_SIZE 18041
  1605. #elif MAX_BITS == 13
  1606. #define TABLE_SIZE 9029
  1607. #else
  1608. #define TABLE_SIZE 5021
  1609. #endif
  1610.  
  1611. #define CLEAR_TABLE 256
  1612. #define TERMINATOR  257
  1613. #define FIRST_CODE  258
  1614. #define CHECK_TIME  100
  1615.  
  1616. #define MAXVAL(n) (( 1 << (n)) -1)
  1617.  
  1618. char *decode_string(unsigned char *buffer, unsigned int code);
  1619. unsigned input_code(PBYTE *ppbInput, unsigned bytes_to_read);
  1620.  
  1621. static unsigned int *prefix_code;
  1622. static unsigned char *append_character;
  1623. static unsigned char decode_stack[4000];
  1624. static int num_bits;
  1625. static int max_code;
  1626.  
  1627. unsigned int last_out_code = 0; /*PLF Tue  96-04-16 02:22:33*/
  1628.  
  1629. ULONG ulBytesRead = 0;
  1630.  
  1631. /*
  1632.  * decode_string:
  1633.  *
  1634.  */
  1635.  
  1636. char *decode_string(unsigned char *buffer, unsigned int code)
  1637. {
  1638.     int i = 0;
  1639.  
  1640.     while (code > 255) {
  1641.         *buffer++ = append_character[code];
  1642.         code = prefix_code[code];
  1643.         if (i++ >= 4000) {
  1644.             printf("Error during LZW code expansion.\n");
  1645.             Exit(1);
  1646.         }
  1647.     }
  1648.     *buffer = code;
  1649.     return (buffer);
  1650. }
  1651.  
  1652. /*
  1653.  * input_code:
  1654.  *      this function reads in bytes from the input
  1655.  *      stream.
  1656.  */
  1657.  
  1658. unsigned input_code(PBYTE *ppbInput, unsigned bytes_to_read)
  1659. {
  1660.     unsigned int return_value;
  1661.     static unsigned long bytes_out = 0;
  1662.     static int input_bit_count = 0;
  1663.     static unsigned long input_bit_buffer = 0L;
  1664.  
  1665.     while (input_bit_count <= 24) {
  1666.         if (bytes_out <= bytes_to_read) {
  1667.             input_bit_buffer |= (unsigned long)(**ppbInput) << (24 - input_bit_count);
  1668.             (*ppbInput)++;
  1669.             ulBytesRead++;
  1670.         } else
  1671.             input_bit_buffer |= (unsigned long) 0x00 << (24 - input_bit_count);
  1672.         bytes_out++;
  1673.         input_bit_count += 8;
  1674.     }
  1675.     return_value = input_bit_buffer >> (32 - num_bits);
  1676.     input_bit_buffer <<= num_bits;
  1677.     input_bit_count -= num_bits;
  1678.     if (bytes_out > bytes_to_read) {    /* flush static vars and quit */
  1679.         bytes_out = 0;
  1680.         input_bit_count = 0;
  1681.         input_bit_buffer = 0L;
  1682.         return (TERMINATOR);
  1683.     }
  1684.     else
  1685.         return (return_value);
  1686. }
  1687.  
  1688. /*
  1689.  * LZWDecompressBlock:
  1690.  *      this takes one of the INF bitmap blocks
  1691.  *      and decompresses it using LZW algorithms.
  1692.  *      The output is written to the fOutput file,
  1693.  *      to which a standard PM BITMAPFILEHEADER and
  1694.  *      the RGB table should already have been written
  1695.  *      to.
  1696.  */
  1697.  
  1698. BOOL LZWDecompressBlock(PBYTE *ppbInput,        // in: compressed data
  1699.                     FILE *fOutput,              // out: uncompressed data
  1700.                     unsigned int number_bytes,  // in: bytes to decompress
  1701.                     unsigned long *pBytesOut,
  1702.                     unsigned *pLastCode)
  1703. {
  1704.     unsigned int next_code = FIRST_CODE;
  1705.     unsigned int new_code;
  1706.     unsigned int old_code;
  1707.     int character, /*counter = 0,*/ clear_flag = 1;
  1708.     unsigned char *string;
  1709.  
  1710.     num_bits = INIT_BITS;
  1711.     max_code = MAXVAL(num_bits);
  1712.  
  1713.     ulBytesRead = number_bytes;
  1714.  
  1715.     /* -- allocate memory to buffers -- */
  1716.     prefix_code = malloc(TABLE_SIZE * sizeof(unsigned int));
  1717.     append_character = malloc(TABLE_SIZE * sizeof(unsigned char));
  1718.  
  1719.     if (ulVerboseMode >=2 )
  1720.         printf("      LZW - Expanding\n");
  1721.  
  1722.     while ((new_code = input_code(ppbInput, number_bytes)) != TERMINATOR) {
  1723.         if (clear_flag) {
  1724.             clear_flag = 0;
  1725.             old_code = new_code;
  1726.             character = old_code;
  1727.             if (EOF == putc(old_code, fOutput) )
  1728.               break;
  1729.             // **ppbOutput = old_code;
  1730.             // (*ppbOutput)++;
  1731.             /* if (ulBytesRead > number_bytes)
  1732.                 break; */
  1733.             *pLastCode = old_code;
  1734.             (*pBytesOut)++;
  1735.             continue;
  1736.         }
  1737.         if (new_code == CLEAR_TABLE) {
  1738.             clear_flag = 1;
  1739.             num_bits = INIT_BITS;
  1740.             next_code = FIRST_CODE;
  1741.             max_code = MAXVAL(num_bits);
  1742.             continue;
  1743.         }
  1744.  
  1745.         if (new_code >= next_code) {
  1746.             *decode_stack = character;
  1747.             string = decode_string(decode_stack + 1, old_code);
  1748.         }
  1749.         else
  1750.             string = decode_string(decode_stack, new_code);
  1751.  
  1752.         character = *string;
  1753.         while (string >= decode_stack) {
  1754.             *pLastCode = *string;
  1755.             if(EOF==putc(*string--, fOutput))
  1756.                break;
  1757.             /* if (ulBytesRead > number_bytes)
  1758.                 break; */
  1759.             // **ppbOutput = *string;
  1760.             // (*ppbOutput)++;
  1761.             // string--;
  1762.  
  1763.             (*pBytesOut)++;
  1764.         }
  1765.  
  1766.         if (next_code <= max_code) {
  1767.             prefix_code[next_code] = old_code;
  1768.             append_character[next_code++] = character;
  1769.             if (next_code == max_code && num_bits < MAX_BITS) {
  1770.                 //printf("(Increase bit-size to %d)", num_bits + 1);
  1771.                 max_code = MAXVAL(++num_bits);
  1772.             }
  1773.         }
  1774.         old_code = new_code;
  1775.     }
  1776.     free(prefix_code);
  1777.     free(append_character);
  1778.     return (TRUE);
  1779. }
  1780.  
  1781.  
  1782.