winhelp

Eric Pouech eric.pouech at wanadoo.fr
Tue Nov 12 14:26:06 CST 2002


this patch fixes several bugs (and crashes) while loading .hlp files in
our own winhelp
it should now become way more stable (but there's still quite a few bugs
around :-(
A+
-------------- next part --------------
Name:          wh_reader
ChangeLog:
fixed several bugs in:
	- page/paragraph reading for >= Win95 help files without compression
	- bitmap & metafile loading
	- btree reading
now caching bitmap loading for better performance
several internal code cleanups
License:       X11
GenDate:       2002/11/12 20:13:55 UTC
ModifiedFiles: programs/winhelp/hlpfile.c programs/winhelp/hlpfile.h programs/winhelp/winhelp.c programs/winhelp/winhelp.h
AddedFiles:    
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/programs/winhelp/hlpfile.c,v
retrieving revision 1.12
diff -u -u -r1.12 hlpfile.c
--- programs/winhelp/hlpfile.c	11 Nov 2002 19:52:07 -0000	1.12
+++ programs/winhelp/hlpfile.c	12 Nov 2002 20:06:53 -0000
@@ -23,6 +23,7 @@
 #include <string.h>
 #include "winbase.h"
 #include "wingdi.h"
+#include "winuser.h"
 #include "winhelp.h"
 
 #include "wine/debug.h"
@@ -74,12 +75,11 @@
 static BYTE* HLPFILE_UncompressLZ77(BYTE *ptr, BYTE *end, BYTE *newptr);
 static BOOL  HLPFILE_UncompressLZ77_Phrases(HLPFILE*);
 static BOOL  HLPFILE_Uncompress_Phrases40(HLPFILE*);
-static BOOL  HLPFILE_UncompressLZ77_Topic(HLPFILE*);
+static BOOL  HLPFILE_Uncompress_Topic(HLPFILE*);
 static BOOL  HLPFILE_GetContext(HLPFILE*);
 static BOOL  HLPFILE_AddPage(HLPFILE*, BYTE*, BYTE*, unsigned);
 static BOOL  HLPFILE_AddParagraph(HLPFILE*, BYTE *, BYTE*, unsigned*);
-static UINT  HLPFILE_Uncompressed2_Size(BYTE*, BYTE*);
-static void  HLPFILE_Uncompress2(BYTE**, BYTE*, BYTE*);
+static void  HLPFILE_Uncompress2(const BYTE*, const BYTE*, BYTE*, const BYTE*);
 static BOOL  HLPFILE_Uncompress3(char*, const char*, const BYTE*, const BYTE*);
 static void  HLPFILE_UncompressRLE(const BYTE* src, unsigned sz, BYTE** dst);
 static BOOL  HLPFILE_ReadFont(HLPFILE* hlpfile);
@@ -88,13 +88,17 @@
  *
  *           HLPFILE_Contents
  */
-HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath)
+HLPFILE_PAGE *HLPFILE_Contents(HLPFILE *hlpfile)
 {
-    HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
-
     if (!hlpfile) return 0;
-
+#if 1
     return hlpfile->first_page;
+#else
+    if (hlpfile->contents_start) 
+        return HLPFILE_PageByHash(hlpfile, hlpfile->contents_start);
+    else
+        return hlpfile->first_page;
+#endif
 }
 
 /***********************************************************************
@@ -119,14 +123,13 @@
  *
  *           HLPFILE_HlpFilePageByHash
  */
-HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG lHash)
+HLPFILE_PAGE *HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash)
 {
     HLPFILE_PAGE*       page;
     HLPFILE_PAGE*       found;
-    HLPFILE*            hlpfile = HLPFILE_ReadHlpFile(lpszPath);
     int                 i;
 
-    WINE_TRACE("path<%s>[%lx]\n", lpszPath, lHash);
+    WINE_TRACE("path<%s>[%lx]\n", hlpfile->lpszPath, lHash);
 
     if (!hlpfile) return 0;
 
@@ -156,10 +159,10 @@
         if (found) return found;
 
         WINE_ERR("Page of offset %lu not found in file %s\n",
-                  hlpfile->Context[i].offset, lpszPath);
+                  hlpfile->Context[i].offset, hlpfile->lpszPath);
         return NULL;
     }
-    WINE_ERR("Page of hash %lx not found in file %s\n", lHash, lpszPath);
+    WINE_ERR("Page of hash %lx not found in file %s\n", lHash, hlpfile->lpszPath);
     return NULL;
 }
 
@@ -206,18 +209,23 @@
     hlpfile = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
     if (!hlpfile) return 0;
 
-    hlpfile->wRefCount   = 1;
-    hlpfile->Context     = NULL;
-    hlpfile->wContextLen = 0;
-    hlpfile->first_page  = NULL;
-    hlpfile->first_macro = NULL;
-    hlpfile->prev        = NULL;
-    hlpfile->next        = first_hlpfile;
-    hlpfile->lpszPath    = (char*)hlpfile + sizeof(HLPFILE);
-    hlpfile->lpszTitle   = NULL;
+    hlpfile->lpszPath           = (char*)hlpfile + sizeof(HLPFILE);
+    hlpfile->lpszTitle          = NULL;
+    hlpfile->lpszCopyright      = NULL;
+    hlpfile->first_page         = NULL;
+    hlpfile->first_macro        = NULL;
+    hlpfile->wContextLen        = 0;
+    hlpfile->Context            = NULL;
+    hlpfile->contents_start     = 0;
+    hlpfile->prev               = NULL;
+    hlpfile->next               = first_hlpfile;
+    hlpfile->wRefCount          = 1;
+
+    hlpfile->numBmps            = 0;
+    hlpfile->bmps               = NULL;
 
-    hlpfile->numFonts    = 0;
-    hlpfile->fonts       = NULL;
+    hlpfile->numFonts           = 0;
+    hlpfile->fonts              = NULL;
 
     strcpy(hlpfile->lpszPath, lpszPath);
 
@@ -265,10 +273,12 @@
     if (!ret) return FALSE;
 
     if (!HLPFILE_SystemCommands(hlpfile)) return FALSE;
-    if (!HLPFILE_UncompressLZ77_Phrases(hlpfile) &&
-        !HLPFILE_Uncompress_Phrases40(hlpfile))
-        return FALSE;
-    if (!HLPFILE_UncompressLZ77_Topic(hlpfile)) return FALSE;
+
+    /* load phrases support */
+    if (!HLPFILE_UncompressLZ77_Phrases(hlpfile))
+        HLPFILE_Uncompress_Phrases40(hlpfile);
+
+    if (!HLPFILE_Uncompress_Topic(hlpfile)) return FALSE;
     if (!HLPFILE_ReadFont(hlpfile)) return FALSE;
 
     buf = topic.map[0];
@@ -330,36 +340,30 @@
     title = buf + GET_UINT(buf, 0x10);
     if (title > end) {WINE_WARN("page2\n"); return FALSE;};
 
-    if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10))
+    titlesize = GET_UINT(buf, 4) + 1;
+    page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize);
+    if (!page) return FALSE;
+    page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
+
+    if (hlpfile->hasPhrases)
+    {
+        HLPFILE_Uncompress2(title, end, page->lpszTitle, page->lpszTitle + titlesize - 1);
+    }
+    else
     {
-        if (hlpfile->hasPhrases)
+        if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10))
         {
-            titlesize = HLPFILE_Uncompressed2_Size(title, end);
-            page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize);
-            if (!page) return FALSE;
-
-            page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
-            HLPFILE_Uncompress2(&title, end, page->lpszTitle);
+            /* need to decompress */
+            HLPFILE_Uncompress3(page->lpszTitle, page->lpszTitle + titlesize - 1, 
+                                title, end);
         }
         else
         {
-            titlesize = GET_UINT(buf, 4) + 1;
-            page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize);
-            if (!page) return FALSE;
-            page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
-
-            HLPFILE_Uncompress3(page->lpszTitle, page->lpszTitle + titlesize, title, end);
+            memcpy(page->lpszTitle, title, titlesize - 1);
         }
     }
-    else
-    {
-        titlesize = GET_UINT(buf, 0x4);
-        page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize);
-        if (!page) return FALSE;
 
-        page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
-        memcpy(page->lpszTitle, title, titlesize);
-    }
+    page->lpszTitle[titlesize - 1] = 0;
 
     if (hlpfile->first_page)
     {
@@ -469,6 +473,8 @@
     unsigned    i, numpict;
 
     numpict = *(unsigned short*)(ref + 2);
+    WINE_TRACE("Got picture magic=%04x #=%d\n", 
+               *(unsigned short*)ref, numpict);
 
     for (i = 0; i < numpict; i++)
     {
@@ -477,12 +483,20 @@
         BYTE                    type, pack;
         BITMAPINFO*             bi;
         unsigned long           off, sz;
-        unsigned                shift;
 
-        ptr = beg = ref + *((unsigned long*)ref + 1 + i);
+        WINE_TRACE("Offset[%d] = %lx\n", i, ((unsigned long*)ref)[1 + i]);
+        ptr = beg = ref + ((unsigned long*)ref)[1 + i];
 
         type = *ptr++;
         pack = *ptr++;
+        
+        switch (type)
+        {
+        case 5: /* device dependent bmp */ break;
+        case 6: /* device independent bmp */ break;
+        case 8: WINE_FIXME("Unsupported metafile\n"); return FALSE;
+        default: WINE_FIXME("Unknown type %u\n", type); return FALSE;
+        }
 
         bi = HeapAlloc(GetProcessHeap(), 0, sizeof(*bi));
         if (!bi) return FALSE;
@@ -499,8 +513,7 @@
         bi->bmiHeader.biCompression   = BI_RGB;
         if (bi->bmiHeader.biBitCount > 32) WINE_FIXME("Unknown bit count %u\n", bi->bmiHeader.biBitCount);
         if (bi->bmiHeader.biPlanes != 1) WINE_FIXME("Unsupported planes %u\n", bi->bmiHeader.biPlanes);
-        shift = 32 / bi->bmiHeader.biBitCount;
-        bi->bmiHeader.biSizeImage = ((bi->bmiHeader.biWidth + shift - 1) / shift) * 4 * bi->bmiHeader.biHeight;
+        bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8) * bi->bmiHeader.biHeight;
 
         sz = fetch_ulong(&ptr);
         fetch_ulong(&ptr); /* hotspot size */
@@ -548,7 +561,7 @@
                 if (!pict_beg) return FALSE;
                 HLPFILE_UncompressRLE(beg + off, sz, &dst);
                 if (dst - pict_beg != bi->bmiHeader.biSizeImage)
-                    WINE_FIXME("buffer XXX-flow\n");
+                    WINE_FIXME("buffer XXX-flow (%u/%lu)\n", dst - pict_beg, bi->bmiHeader.biSizeImage);
             }
             break;
         case 2: /* LZ77 */
@@ -616,15 +629,36 @@
 {
     char        tmp[16];
     BYTE        *ref, *end;
-
+    BOOL        ret;
     WINE_TRACE("Loading picture #%d\n", index);
+
+    if (index < hlpfile->numBmps && hlpfile->bmps[index] != NULL)
+    {
+        attributes.hBitmap = hlpfile->bmps[index];
+        attributes.bmpPos  = pos;
+        return TRUE;
+    }
+
     sprintf(tmp, "|bm%u", index);
 
     if (!HLPFILE_FindSubFile(tmp, &ref, &end)) {WINE_WARN("no sub file\n"); return FALSE;}
 
     ref += 9;
 
-    return HLPFILE_LoadPictureByAddr(hlpfile, ref, end - ref, pos);
+    ret = HLPFILE_LoadPictureByAddr(hlpfile, ref, end - ref, pos);
+
+    /* cache bitmap */
+    if (ret)
+    {
+        if (index >= hlpfile->numBmps)
+        {
+            hlpfile->numBmps = index + 1;
+            hlpfile->bmps = HeapReAlloc(GetProcessHeap(), 0, hlpfile->bmps, 
+                                        hlpfile->numBmps * sizeof(hlpfile->bmps[0]));
+        }
+        hlpfile->bmps[index] = attributes.hBitmap;
+    }
+    return ret;
 }
 
 /***********************************************************************
@@ -650,33 +684,24 @@
     if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};
 
     size = GET_UINT(buf, 0x4);
-
-    if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10))
+    text = HeapAlloc(GetProcessHeap(), 0, size);
+    if (!text) return FALSE;
+    if (hlpfile->hasPhrases)
+    {
+        HLPFILE_Uncompress2(buf + GET_UINT(buf, 0x10), end, text, text + size);
+    }
+    else
     {
-        if (hlpfile->hasPhrases)
+        if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10))
         {
-            BYTE* lptr = buf + GET_UINT(buf, 0x10);
-            unsigned size2;
-
-            size2 = HLPFILE_Uncompressed2_Size(lptr, end);
-            if (size2 != size + 1)
-                WINE_FIXME("Mismatch in sizes: decomp2=%u header=%lu\n", size2, size);
-            text = HeapAlloc(GetProcessHeap(), 0, size + 1);
-            if (!text) return FALSE;
-            HLPFILE_Uncompress2(&lptr, end, text);
+            /* block is compressed */
+            HLPFILE_Uncompress3(text, text + size, buf + GET_UINT(buf, 0x10), end);
         }
         else
         {
-            /* block is compressed */
-            text = HeapAlloc(GetProcessHeap(), 0, size);
-            if (!text) return FALSE;
-            HLPFILE_Uncompress3(text, text + size, buf + GET_UINT(buf, 0x10), end);
+            text = buf + GET_UINT(buf, 0x10);
         }
     }
-    else
-    {
-        text = buf + GET_UINT(buf, 0x10);
-    }
     text_end = text + size;
 
     format = buf + 0x15;
@@ -684,6 +709,7 @@
 
     fetch_long(&format);
     *len = fetch_ushort(&format);
+
     if (buf[0x14] == 0x23)
     {
         char    type;
@@ -723,6 +749,9 @@
                 if (ts & 0x4000) fetch_ushort(&format);
             }
         }
+        /* 0x0400, 0x0800 and 0x1000 don't need space */
+        if ((bits & 0xE080) != 0) 
+            WINE_FIXME("Unsupported bits %04x, potential trouble ahead\n", bits);
 
         while (text < text_end && format < format_end)
         {
@@ -772,7 +801,7 @@
                     paragraph->link->lHash      = attributes.link.lHash;
                     paragraph->link->bClrChange = attributes.link.bClrChange;
 
-                    WINE_TRACE("Link[%d] to %s/%08lx\n",
+                    WINE_TRACE("Link[%d] to %s@%08lx\n",
                                paragraph->link->cookie, paragraph->link->lpszString, paragraph->link->lHash);
                 }
 #if 0
@@ -800,12 +829,12 @@
             switch (*format)
             {
             case 0x20:
-                WINE_FIXME("NIY\n");
+                WINE_FIXME("NIY20\n");
                 format += 5;
                 break;
 
             case 0x21:
-                WINE_FIXME("NIY\n");
+                WINE_FIXME("NIY21\n");
                 format += 3;
                 break;
 
@@ -848,21 +877,28 @@
 
                     format += 2;
                     size = fetch_long(&format);
+
                     switch (type)
                     {
                     case 0x22:
                         fetch_ushort(&format); /* hot spot */
                         /* fall thru */
                     case 0x03:
-                        if (*(short*)format == 0)
-                            HLPFILE_LoadPictureByIndex(hlpfile,
-                                                       *(short*)(format + 2),
-                                                       pos);
-                        else
+                        switch (*(short*)format)
                         {
-                            WINE_FIXME("does it work ???\n");
+                        case 0:
+                            HLPFILE_LoadPictureByIndex(hlpfile,
+                                                       *(short*)(format + 2), pos);
+                            break;
+                        case 1:
+                            WINE_FIXME("does it work ??? %x<%lu>#%u\n", 
+                                       *(short*)format, size, *(short*)(format+2));
                             HLPFILE_LoadPictureByAddr(hlpfile, format + 2,
                                                       size - 4, pos);
+                            break;
+                        default:
+                            WINE_FIXME("??? %u\n", *(short*)format);
+                            break;
                         }
                         break;
                     case 0x05:
@@ -1052,16 +1088,6 @@
                    hlpfile->fonts[i].LogFont.lfFaceName, idx,
                    *(unsigned long*)(ref + dscr_offset + i * 11 + 5) & 0x00FFFFFF);
     }
-/*
----				      only if FacenamesOffset >= 12
-unsigned short NumStyles	      number of style descriptors
-unsigned short StyleOffset	      start of array of style descriptors
-				      relative to &NumFacenames
----				      only if FacenamesOffset >= 16
-unsigned short NumCharMapTables       number of character mapping tables
-unsigned short CharMapTableOffset     start of array of character mapping
-table names relative to &NumFacenames
-*/
     return TRUE;
 }
 
@@ -1187,6 +1213,7 @@
     if (magic != 0x036C || major != 1)
     {WINE_WARN("Wrong system header\n"); return FALSE;}
     if (minor <= 16) {WINE_WARN("too old file format (NIY)\n"); return FALSE;}
+    if (flags & 8) {WINE_WARN("Unsupported yet page size\n"); return FALSE;}
 
     hlpfile->version = minor;
     hlpfile->flags = flags;
@@ -1204,12 +1231,17 @@
             break;
 
 	case 2:
-            if (GET_USHORT(ptr, 2) != 1 || ptr[4] != 0) WINE_WARN("system2\n");
+            if (hlpfile->lpszCopyright) {WINE_WARN("copyright\n"); break;}
+            hlpfile->lpszCopyright = HeapAlloc(GetProcessHeap(), 0, strlen(ptr + 4) + 1);
+            if (!hlpfile->lpszCopyright) return FALSE;
+            lstrcpy(hlpfile->lpszCopyright, ptr + 4);
+            WINE_TRACE("Copyright: %s\n", hlpfile->lpszCopyright);
             break;
 
 	case 3:
-            if (GET_USHORT(ptr, 2) != 4 || GET_UINT(ptr, 4) != 0)
-                WINE_WARN("system3\n");
+            if (GET_USHORT(ptr, 2) != 4) {WINE_WARN("system3\n");break;}
+            hlpfile->contents_start = GET_UINT(ptr, 4);
+            WINE_TRACE("Setting contents start at %08lx\n", hlpfile->contents_start);
             break;
 
 	case 4:
@@ -1223,8 +1255,15 @@
             *m = macro;
             break;
 
+        case 6:
+            if (GET_USHORT(ptr, 2) != 90) {WINE_WARN("system6\n");break;}
+            WINE_FIXME("System-Window: flags=%4x type=%s name=%s caption=%s (%d,%d)x(%d,%d)\n",
+                       GET_USHORT(ptr, 4), ptr + 6, ptr + 16, ptr + 25, 
+                       GET_SHORT(ptr, 76), GET_USHORT(ptr, 78),
+                       GET_SHORT(ptr, 80), GET_USHORT(ptr, 82));
+            break;
 	default:
-            WINE_WARN("Unsupport SystemRecord[%d]\n", GET_USHORT(ptr, 0));
+            WINE_WARN("Unsupported SystemRecord[%d]\n", GET_USHORT(ptr, 0));
 	}
     }
     return TRUE;
@@ -1387,9 +1426,9 @@
 
 /***********************************************************************
  *
- *           HLPFILE_UncompressLZ77_Topic
+ *           HLPFILE_Uncompress_Topic
  */
-static BOOL HLPFILE_UncompressLZ77_Topic(HLPFILE* hlpfile)
+static BOOL HLPFILE_Uncompress_Topic(HLPFILE* hlpfile)
 {
     BYTE *buf, *ptr, *end, *newptr;
     int  i, newsize = 0;
@@ -1397,98 +1436,95 @@
     if (!HLPFILE_FindSubFile("|TOPIC", &buf, &end))
     {WINE_WARN("topic0\n"); return FALSE;}
 
-    if (!(hlpfile->flags & 4)) WINE_FIXME("Unsupported format\n");
-
-    buf += 9;
-    topic.wMapLen = (end - buf - 1) / 0x1000 + 1;
-
-    for (i = 0; i < topic.wMapLen; i++)
+    switch (hlpfile->flags & (8|4))
     {
-        ptr = buf + i * 0x1000;
-
-        /* I don't know why, it's necessary for printman.hlp */
-        if (ptr + 0x44 > end) ptr = end - 0x44;
-
-        newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + 0x1000));
-    }
+    case 8:
+        WINE_FIXME("Unsupported format\n");
+        return FALSE;
+    case 4:
+        buf += 9;
+        topic.wMapLen = (end - buf - 1) / 0x1000 + 1;
+        
+        for (i = 0; i < topic.wMapLen; i++)
+        {
+            ptr = buf + i * 0x1000;
+            
+            /* I don't know why, it's necessary for printman.hlp */
+            if (ptr + 0x44 > end) ptr = end - 0x44;
+
+            newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + 0x1000));
+        }
+        
+        topic.map = HeapAlloc(GetProcessHeap(), 0,
+                              topic.wMapLen * sizeof(topic.map[0]) + newsize);
+        if (!topic.map) return FALSE;
+        newptr = (char*)(topic.map + topic.wMapLen);
+        topic.end = newptr + newsize;
 
-    topic.map = HeapAlloc(GetProcessHeap(), 0,
-                          topic.wMapLen * sizeof(topic.map[0]) + newsize);
-    if (!topic.map) return FALSE;
-    newptr = (char*)topic.map + topic.wMapLen * sizeof(topic.map[0]);
-    topic.end = newptr + newsize;
+        for (i = 0; i < topic.wMapLen; i++)
+        {
+            ptr = buf + i * 0x1000;
+            if (ptr + 0x44 > end) ptr = end - 0x44;
 
-    for (i = 0; i < topic.wMapLen; i++)
-    {
-        ptr = buf + i * 0x1000;
-        if (ptr + 0x44 > end) ptr = end - 0x44;
+            topic.map[i] = newptr;
+            newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + 0x1000), newptr);
+        }
+        break;
+    case 0:
+        /* basically, we need to copy the 0x1000 byte pages (removing the first 0x0C) in
+         * one single are in memory
+         */
+#define DST_LEN (0x1000 - 0x0C)
+        buf += 9;
+        newsize = end - buf;
+        /* number of destination pages */
+        topic.wMapLen = (newsize - 1) / DST_LEN + 1;
+        topic.map = HeapAlloc(GetProcessHeap(), 0,
+                              topic.wMapLen * (sizeof(topic.map[0]) + DST_LEN));
+        if (!topic.map) return FALSE;
+        newptr = (char*)(topic.map + topic.wMapLen);
+        topic.end = newptr + newsize;
 
-        topic.map[i] = newptr;
-        newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + 0x1000), newptr);
+        for (i = 0; i < topic.wMapLen; i++)
+        {
+            topic.map[i] = newptr + i * DST_LEN;
+            memcpy(topic.map[i], buf + i * 0x1000 + 0x0C, DST_LEN);
+        }
+#undef DST_LEN
+        break;
     }
-
     return TRUE;
 }
 
 /***********************************************************************
  *
- *           HLPFILE_Uncompressed2_Size
- */
-static UINT HLPFILE_Uncompressed2_Size(BYTE *ptr, BYTE *end)
-{
-    UINT wSize = 0;
-
-    while (ptr < end)
-    {
-        if (!*ptr || *ptr >= 0x10)
-            wSize++, ptr++;
-        else
-	{
-            BYTE *phptr, *phend;
-            UINT code  = 0x100 * ptr[0] + ptr[1];
-            UINT index = (code - 0x100) / 2;
-
-            if (index < phrases.num)
-	    {
-                phptr = phrases.buffer + phrases.offsets[index];
-                phend = phrases.buffer + phrases.offsets[index + 1];
-
-                if (phend < phptr) WINE_WARN("uncompress2a\n");
-
-                wSize += phend - phptr;
-                if (code & 1) wSize++;
-	    }
-            else WINE_WARN("uncompress2b %d|%d\n", index, phrases.num);
-
-            ptr += 2;
-	}
-    }
-
-    return wSize + 1;
-}
-
-/***********************************************************************
- *
  *           HLPFILE_Uncompress2
  */
 
-static void HLPFILE_Uncompress2(BYTE **pptr, BYTE *end, BYTE *newptr)
+static void HLPFILE_Uncompress2(const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend)
 {
-    BYTE *ptr = *pptr;
+    BYTE *phptr, *phend;
+    UINT code;
+    UINT index;
 
-    while (ptr < end)
+    while (ptr < end && newptr < newend)
     {
         if (!*ptr || *ptr >= 0x10)
             *newptr++ = *ptr++;
         else
 	{
-            BYTE *phptr, *phend;
-            UINT code  = 0x100 * ptr[0] + ptr[1];
-            UINT index = (code - 0x100) / 2;
+            code  = 0x100 * ptr[0] + ptr[1];
+            index = (code - 0x100) / 2;
 
             phptr = phrases.buffer + phrases.offsets[index];
             phend = phrases.buffer + phrases.offsets[index + 1];
 
+            if (newptr + (phend - phptr) > newend)
+            {
+                WINE_FIXME("buffer overflow %p > %p for %d bytes\n", 
+                           newptr, newend, phend - phptr);
+                return;
+            }
             memcpy(newptr, phptr, phend - phptr);
             newptr += phend - phptr;
             if (code & 1) *newptr++ = ' ';
@@ -1496,8 +1532,7 @@
             ptr += 2;
 	}
     }
-    *newptr = '\0';
-    *pptr = ptr;
+    if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend);
 }
 
 /******************************************************************
@@ -1515,16 +1550,31 @@
         if ((*src & 1) == 0)
         {
             idx = *src / 2;
-            if (idx > phrases.num) WINE_ERR("index in phrases\n");
-            len = phrases.offsets[idx + 1] - phrases.offsets[idx];
-            memcpy(dst, &phrases.buffer[phrases.offsets[idx]], len);
+            if (idx > phrases.num) 
+            {
+                WINE_ERR("index in phrases %d/%d\n", idx, phrases.num);
+                len = 0;
+            }
+            else 
+            {
+                len = phrases.offsets[idx + 1] - phrases.offsets[idx];
+                memcpy(dst, &phrases.buffer[phrases.offsets[idx]], len);
+            }
         }
         else if ((*src & 0x03) == 0x01)
         {
-            idx = (*src + 1) * 64 + *++src;
-            if (idx > phrases.num) WINE_ERR("index in phrases\n");
-            len = phrases.offsets[idx + 1] - phrases.offsets[idx];
-            memcpy(dst, &phrases.buffer[phrases.offsets[idx]], len);
+            idx = (*src + 1) * 64;
+            idx += *++src;
+            if (idx > phrases.num) 
+            {
+                WINE_ERR("index in phrases %d/%d\n", idx, phrases.num);
+                len = 0;
+            }
+            else
+            {
+                len = phrases.offsets[idx + 1] - phrases.offsets[idx];
+                memcpy(dst, &phrases.buffer[phrases.offsets[idx]], len);
+            }
         }
         else if ((*src & 0x07) == 0x03)
         {
@@ -1586,7 +1636,7 @@
     num    = GET_UINT(buf, 9 + 34);
     psize  = GET_USHORT(buf, 9 + 4);
     nlvl   = GET_USHORT(buf, 9 + 32);
-    pnext  = GET_USHORT(buf, 26);
+    pnext  = GET_USHORT(buf, 9 + 26);
 
     WINE_TRACE("BTree: #entries=%u pagSize=%u #levels=%u #pages=%u root=%u struct%16s\n",
                num, psize, nlvl, GET_USHORT(buf, 9 + 30), pnext, buf + 9 + 6);
@@ -1597,7 +1647,7 @@
         ptr = (buf + 9 + 38) + pnext * psize;
         WINE_TRACE("BTree: (index[%u]) unused=%u #entries=%u <%u\n",
                    pnext, GET_USHORT(ptr, 0), GET_USHORT(ptr, 2), GET_USHORT(ptr, 4));
-        pnext = GET_USHORT(ptr, 6);
+        pnext = GET_USHORT(ptr, 4);
     }
     while (pnext != 0xFFFF)
     {
@@ -1711,6 +1761,8 @@
  */
 void HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
 {
+    unsigned i;
+
     if (!hlpfile || --hlpfile->wRefCount > 0) return;
 
     if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
@@ -1719,7 +1771,6 @@
 
     if (hlpfile->numFonts)
     {
-        unsigned i;
         for (i = 0; i < hlpfile->numFonts; i++)
         {
             DeleteObject(hlpfile->fonts[i].hFont);
@@ -1727,11 +1778,21 @@
         HeapFree(GetProcessHeap(), 0, hlpfile->fonts);
     }
 
+    if (hlpfile->numBmps)
+    {
+        for (i = 0; i < hlpfile->numBmps; i++)
+        {
+            DeleteObject(hlpfile->bmps[i]);
+        }
+        HeapFree(GetProcessHeap(), 0, hlpfile->bmps);
+    }
+
     HLPFILE_DeletePage(hlpfile->first_page);
     HLPFILE_DeleteMacro(hlpfile->first_macro);
 
     if (hlpfile->Context)       HeapFree(GetProcessHeap(), 0, hlpfile->Context);
     if (hlpfile->lpszTitle)     HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle);
+    if (hlpfile->lpszCopyright) HeapFree(GetProcessHeap(), 0, hlpfile->lpszCopyright);
     HeapFree(GetProcessHeap(), 0, hlpfile);
 }
 
Index: programs/winhelp/hlpfile.h
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/programs/winhelp/hlpfile.h,v
retrieving revision 1.4
diff -u -u -r1.4 hlpfile.h
--- programs/winhelp/hlpfile.h	21 Oct 2002 18:20:05 -0000	1.4
+++ programs/winhelp/hlpfile.h	11 Nov 2002 19:01:04 -0000
@@ -92,10 +92,13 @@
 {
     LPSTR                       lpszPath;
     LPSTR                       lpszTitle;
+    LPSTR                       lpszCopyright;
     HLPFILE_PAGE*               first_page;
     HLPFILE_MACRO*              first_macro;
     unsigned                    wContextLen;
     HLPFILE_CONTEXT*            Context;
+    unsigned long               contents_start;
+
     struct tagHlpFileFile*      prev;
     struct tagHlpFileFile*      next;
 
@@ -105,13 +108,16 @@
     unsigned short              flags;
     unsigned                    hasPhrases; /* Phrases or PhrIndex/PhrImage */
 
+    unsigned                    numBmps;
+    HBITMAP*                    bmps;
+
     unsigned                    numFonts;
     HLPFILE_FONT*               fonts;
 } HLPFILE;
 
 HLPFILE      *HLPFILE_ReadHlpFile(LPCSTR lpszPath);
-HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath);
-HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG wNum);
+HLPFILE_PAGE *HLPFILE_Contents(HLPFILE* hlpfile);
+HLPFILE_PAGE *HLPFILE_PageByHash(HLPFILE* hlpfile, LONG wNum);
 LONG          HLPFILE_Hash(LPCSTR lpszContext);
 VOID          HLPFILE_FreeHlpFilePage(HLPFILE_PAGE*);
 VOID          HLPFILE_FreeHlpFile(HLPFILE*);
Index: programs/winhelp/winhelp.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/programs/winhelp/winhelp.c,v
retrieving revision 1.18
diff -u -u -r1.18 winhelp.c
--- programs/winhelp/winhelp.c	11 Nov 2002 22:20:47 -0000	1.18
+++ programs/winhelp/winhelp.c	11 Nov 2002 22:26:54 -0000
@@ -24,9 +24,10 @@
 #include <string.h>
 #include "winbase.h"
 #include "wingdi.h"
-#include "windowsx.h"
+#include "winuser.h"
 #include "winhelp.h"
 #include "winhelp_res.h"
+#include "shellapi.h"
 
 #include "wine/debug.h"
 
@@ -372,15 +375,17 @@
 BOOL WINHELP_CreateHelpWindowByHash(LPCSTR lpszFile, LONG lHash, LPCSTR lpszWindow,
                                     BOOL bPopup, HWND hParentWnd, LPPOINT mouse, INT nCmdShow)
 {
-    HLPFILE_PAGE*       page;
+    HLPFILE_PAGE*       page = NULL;
 
     /* Read help file */
     if (lpszFile[0])
     {
-        page = lHash ? HLPFILE_PageByHash(lpszFile, lHash) : HLPFILE_Contents(lpszFile);
+        HLPFILE*        hlpfile;
+
+        hlpfile = HLPFILE_ReadHlpFile(lpszFile);
 
         /* Add Suffix `.hlp' */
-        if (!page && lstrcmpi(lpszFile + strlen(lpszFile) - 4, ".hlp"))
+        if (!hlpfile && lstrcmpi(lpszFile + strlen(lpszFile) - 4, ".hlp") != 0)
 	{
             CHAR      szFile_hlp[MAX_PATHNAME_LEN];
 
@@ -388,13 +393,16 @@
             szFile_hlp[sizeof(szFile_hlp) - 5] = '\0';
             lstrcat(szFile_hlp, ".hlp");
 
-            page = lHash ? HLPFILE_PageByHash(szFile_hlp, lHash) : HLPFILE_Contents(szFile_hlp);
-            if (!page)
-	    {
-                WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile, STID_WHERROR, MB_OK);
-                if (Globals.win_list) return FALSE;
-	    }
+            hlpfile = HLPFILE_ReadHlpFile(szFile_hlp);
 	}
+        if (!hlpfile)
+        {
+            WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile, STID_WHERROR, MB_OK);
+            if (Globals.win_list) return FALSE;
+        }
+        else 
+            page = lHash ? HLPFILE_PageByHash(hlpfile, lHash) : 
+                HLPFILE_Contents(hlpfile);
     }
     else page = NULL;
     return WINHELP_CreateHelpWindowByPage(page, lpszWindow, bPopup, hParentWnd, mouse, nCmdShow);


More information about the wine-patches mailing list