[1/2] winhlp32: Reorder some functions to avoid forward declarations in hlpfile.c.

Francois Gouget fgouget at free.fr
Thu Jan 8 07:17:00 CST 2009


---
 programs/winhlp32/hlpfile.c | 1456 +++++++++++++++++++++----------------------
 1 files changed, 719 insertions(+), 737 deletions(-)

diff --git a/programs/winhlp32/hlpfile.c b/programs/winhlp32/hlpfile.c
index 99043ac..913cdab 100644
--- a/programs/winhlp32/hlpfile.c
+++ b/programs/winhlp32/hlpfile.c
@@ -51,25 +51,315 @@ static inline unsigned GET_UINT(const BYTE* buffer, unsigned i)
 
 static HLPFILE *first_hlpfile = 0;
 
-static BOOL  HLPFILE_DoReadHlpFile(HLPFILE*, LPCSTR);
-static BOOL  HLPFILE_ReadFileToBuffer(HLPFILE*, HFILE);
-static BOOL  HLPFILE_FindSubFile(HLPFILE*, LPCSTR, BYTE**, BYTE**);
-static BOOL  HLPFILE_SystemCommands(HLPFILE*);
-static INT   HLPFILE_UncompressedLZ77_Size(const BYTE *ptr, const BYTE *end);
-static BYTE* HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr);
-static BOOL  HLPFILE_UncompressLZ77_Phrases(HLPFILE*);
-static BOOL  HLPFILE_Uncompress_Phrases40(HLPFILE*);
-static BOOL  HLPFILE_Uncompress_Topic(HLPFILE*);
-static BOOL  HLPFILE_GetContext(HLPFILE*);
-static BOOL  HLPFILE_GetKeywords(HLPFILE*);
-static BOOL  HLPFILE_GetMap(HLPFILE*);
-static BOOL  HLPFILE_GetTOMap(HLPFILE*);
-static BOOL  HLPFILE_AddPage(HLPFILE*, const BYTE*, const BYTE*, unsigned, unsigned);
-static BOOL  HLPFILE_SkipParagraph(HLPFILE*, const BYTE*, const BYTE*, unsigned*);
-static void  HLPFILE_Uncompress2(HLPFILE*, const BYTE*, const BYTE*, BYTE*, const BYTE*);
-static BOOL  HLPFILE_Uncompress3(HLPFILE*, char*, const char*, const BYTE*, const BYTE*);
-static void  HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE* dst, unsigned dstsz);
-static BOOL  HLPFILE_ReadFont(HLPFILE* hlpfile);
+
+/**************************************************************************
+ * HLPFILE_BPTreeSearch
+ *
+ * Searches for an element in B+ tree
+ *
+ * PARAMS
+ *     buf        [I] pointer to the embedded file structured as a B+ tree
+ *     key        [I] pointer to data to find
+ *     comp       [I] compare function
+ *
+ * RETURNS
+ *     Pointer to block identified by key, or NULL if failure.
+ *
+ */
+void* HLPFILE_BPTreeSearch(BYTE* buf, const void* key,
+                           HLPFILE_BPTreeCompare comp)
+{
+    unsigned magic;
+    unsigned page_size;
+    unsigned cur_page;
+    unsigned level;
+    BYTE *pages, *ptr, *newptr;
+    int i, entries;
+    int ret;
+
+    magic = GET_USHORT(buf, 9);
+    if (magic != 0x293B)
+    {
+        WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic);
+        return NULL;
+    }
+    page_size = GET_USHORT(buf, 9+4);
+    cur_page  = GET_USHORT(buf, 9+26);
+    level     = GET_USHORT(buf, 9+32);
+    pages     = buf + 9 + 38;
+    while (--level > 0)
+    {
+        ptr = pages + cur_page*page_size;
+        entries = GET_SHORT(ptr, 2);
+        ptr += 6;
+        for (i = 0; i < entries; i++)
+        {
+            if (comp(ptr, key, 0, (void **)&newptr) > 0) break;
+            ptr = newptr;
+        }
+        cur_page = GET_USHORT(ptr-2, 0);
+    }
+    ptr = pages + cur_page*page_size;
+    entries = GET_SHORT(ptr, 2);
+    ptr += 8;
+    for (i = 0; i < entries; i++)
+    {
+        ret = comp(ptr, key, 1, (void **)&newptr);
+        if (ret == 0) return ptr;
+        if (ret > 0) return NULL;
+        ptr = newptr;
+    }
+    return NULL;
+}
+
+/**************************************************************************
+ * HLPFILE_BPTreeEnum
+ *
+ * Enumerates elements in B+ tree.
+ *
+ * PARAMS
+ *     buf        [I]  pointer to the embedded file structured as a B+ tree
+ *     cb         [I]  compare function
+ *     cookie     [IO] cookie for cb function
+ */
+void HLPFILE_BPTreeEnum(BYTE* buf, HLPFILE_BPTreeCallback cb, void* cookie)
+{
+    unsigned magic;
+    unsigned page_size;
+    unsigned cur_page;
+    unsigned level;
+    BYTE *pages, *ptr, *newptr;
+    int i, entries;
+
+    magic = GET_USHORT(buf, 9);
+    if (magic != 0x293B)
+    {
+        WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic);
+        return;
+    }
+    page_size = GET_USHORT(buf, 9+4);
+    cur_page  = GET_USHORT(buf, 9+26);
+    level     = GET_USHORT(buf, 9+32);
+    pages     = buf + 9 + 38;
+    while (--level > 0)
+    {
+        ptr = pages + cur_page*page_size;
+        cur_page = GET_USHORT(ptr, 4);
+    }
+    while (cur_page != 0xFFFF)
+    {
+        ptr = pages + cur_page*page_size;
+        entries = GET_SHORT(ptr, 2);
+        ptr += 8;
+        for (i = 0; i < entries; i++)
+        {
+            cb(ptr, (void **)&newptr, cookie);
+            ptr = newptr;
+        }
+        cur_page = GET_USHORT(pages+cur_page*page_size, 6);
+    }
+}
+
+
+/***********************************************************************
+ *
+ *           HLPFILE_UncompressedLZ77_Size
+ */
+static INT HLPFILE_UncompressedLZ77_Size(const BYTE *ptr, const BYTE *end)
+{
+    int  i, newsize = 0;
+
+    while (ptr < end)
+    {
+        int mask = *ptr++;
+        for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)
+	{
+            if (mask & 1)
+	    {
+                int code = GET_USHORT(ptr, 0);
+                int len  = 3 + (code >> 12);
+                newsize += len;
+                ptr     += 2;
+	    }
+            else newsize++, ptr++;
+	}
+    }
+
+    return newsize;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_UncompressLZ77
+ */
+static BYTE *HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr)
+{
+    int i;
+
+    while (ptr < end)
+    {
+        int mask = *ptr++;
+        for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)
+	{
+            if (mask & 1)
+	    {
+                int code   = GET_USHORT(ptr, 0);
+                int len    = 3 + (code >> 12);
+                int offset = code & 0xfff;
+                /*
+                 * We must copy byte-by-byte here. We cannot use memcpy nor
+                 * memmove here. Just example:
+                 * a[]={1,2,3,4,5,6,7,8,9,10}
+                 * newptr=a+2;
+                 * offset=1;
+                 * We expect:
+                 * {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 11, 12}
+                 */
+                for (; len>0; len--, newptr++) *newptr = *(newptr-offset-1);
+                ptr    += 2;
+	    }
+            else *newptr++ = *ptr++;
+	}
+    }
+
+    return newptr;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_Uncompress2
+ */
+
+static void HLPFILE_Uncompress2(HLPFILE* hlpfile, const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend)
+{
+    BYTE *phptr, *phend;
+    UINT code;
+    UINT index;
+
+    while (ptr < end && newptr < newend)
+    {
+        if (!*ptr || *ptr >= 0x10)
+            *newptr++ = *ptr++;
+        else
+	{
+            code  = 0x100 * ptr[0] + ptr[1];
+            index = (code - 0x100) / 2;
+
+            phptr = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index];
+            phend = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index + 1];
+
+            if (newptr + (phend - phptr) > newend)
+            {
+                WINE_FIXME("buffer overflow %p > %p for %lu bytes\n",
+                           newptr, newend, (SIZE_T)(phend - phptr));
+                return;
+            }
+            memcpy(newptr, phptr, phend - phptr);
+            newptr += phend - phptr;
+            if (code & 1) *newptr++ = ' ';
+
+            ptr += 2;
+	}
+    }
+    if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend);
+}
+
+/******************************************************************
+ *		HLPFILE_Uncompress3
+ *
+ *
+ */
+static BOOL HLPFILE_Uncompress3(HLPFILE* hlpfile, char* dst, const char* dst_end,
+                                const BYTE* src, const BYTE* src_end)
+{
+    unsigned int idx, len;
+
+    for (; src < src_end; src++)
+    {
+        if ((*src & 1) == 0)
+        {
+            idx = *src / 2;
+            if (idx > hlpfile->num_phrases)
+            {
+                WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases);
+                len = 0;
+            }
+            else 
+            {
+                len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx];
+                if (dst + len <= dst_end)
+                    memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len);
+            }
+        }
+        else if ((*src & 0x03) == 0x01)
+        {
+            idx = (*src + 1) * 64;
+            idx += *++src;
+            if (idx > hlpfile->num_phrases)
+            {
+                WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases);
+                len = 0;
+            }
+            else
+            {
+                len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx];
+                if (dst + len <= dst_end)
+                    memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len);
+            }
+        }
+        else if ((*src & 0x07) == 0x03)
+        {
+            len = (*src / 8) + 1;
+            if (dst + len <= dst_end)
+                memcpy(dst, src + 1, len);
+            src += len;
+        }
+        else
+        {
+            len = (*src / 16) + 1;
+            if (dst + len <= dst_end)
+                memset(dst, ((*src & 0x0F) == 0x07) ? ' ' : 0, len);
+        }
+        dst += len;
+    }
+
+    if (dst > dst_end) WINE_ERR("buffer overflow (%p > %p)\n", dst, dst_end);
+    return TRUE;
+}
+
+/******************************************************************
+ *		HLPFILE_UncompressRLE
+ *
+ *
+ */
+static void HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE* dst, unsigned dstsz)
+{
+    BYTE        ch;
+    BYTE*       sdst = dst + dstsz;
+
+    while (src < end)
+    {
+        ch = *src++;
+        if (ch & 0x80)
+        {
+            ch &= 0x7F;
+            if (dst + ch <= sdst)
+                memcpy(dst, src, ch);
+            src += ch;
+        }
+        else
+        {
+            if (dst + ch <= sdst)
+                memset(dst, (char)*src, ch);
+            src++;
+        }
+        dst += ch;
+    }
+    if (dst != sdst)
+        WINE_WARN("Buffer X-flow: d(%lu) instead of d(%u)\n",
+                  (SIZE_T)(dst - (sdst - dstsz)), dstsz);
+}
+
 
 /******************************************************************
  *		HLPFILE_PageByOffset
@@ -102,6 +392,25 @@ HLPFILE_PAGE *HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset, ULONG* relativ
     return found;
 }
 
+/***********************************************************************
+ *
+ *           HLPFILE_Contents
+ */
+HLPFILE_PAGE* HLPFILE_Contents(HLPFILE *hlpfile, ULONG* relative)
+{
+    HLPFILE_PAGE*       page = NULL;
+
+    if (!hlpfile) return NULL;
+
+    page = HLPFILE_PageByOffset(hlpfile, hlpfile->contents_start, relative);
+    if (!page)
+    {
+        page = hlpfile->first_page;
+        *relative = 0;
+    }
+    return page;
+}
+
 /**************************************************************************
  * comp_PageByHash
  *
@@ -173,23 +482,50 @@ HLPFILE_PAGE *HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative)
     return NULL;
 }
 
-/***********************************************************************
+/**************************************************************************
+ * comp_FindSubFile
+ *
+ * HLPFILE_BPTreeCompare function for HLPFILE directory.
  *
- *           HLPFILE_Contents
  */
-HLPFILE_PAGE* HLPFILE_Contents(HLPFILE *hlpfile, ULONG* relative)
+static int comp_FindSubFile(void *p, const void *key,
+                            int leaf, void** next)
 {
-    HLPFILE_PAGE*       page = NULL;
+    *next = (char *)p+strlen(p)+(leaf?5:3);
+    WINE_TRACE("Comparing '%s' with '%s'\n", (char *)p, (char *)key);
+    return strcmp(p, key);
+}
 
-    if (!hlpfile) return NULL;
+/***********************************************************************
+ *
+ *           HLPFILE_FindSubFile
+ */
+static BOOL HLPFILE_FindSubFile(HLPFILE* hlpfile, LPCSTR name, BYTE **subbuf, BYTE **subend)
+{
+    BYTE *ptr;
 
-    page = HLPFILE_PageByOffset(hlpfile, hlpfile->contents_start, relative);
-    if (!page)
+    WINE_TRACE("looking for file '%s'\n", name);
+    ptr = HLPFILE_BPTreeSearch(hlpfile->file_buffer + GET_UINT(hlpfile->file_buffer, 4),
+                               name, comp_FindSubFile);
+    if (!ptr) return FALSE;
+    *subbuf = hlpfile->file_buffer + GET_UINT(ptr, strlen(name)+1);
+    if (*subbuf >= hlpfile->file_buffer + hlpfile->file_buffer_size)
     {
-        page = hlpfile->first_page;
-        *relative = 0;
+        WINE_ERR("internal file %s does not fit\n", name);
+        return FALSE;
     }
-    return page;
+    *subend = *subbuf + GET_UINT(*subbuf, 0);
+    if (*subend > hlpfile->file_buffer + hlpfile->file_buffer_size)
+    {
+        WINE_ERR("internal file %s does not fit\n", name);
+        return FALSE;
+    }
+    if (GET_UINT(*subbuf, 0) < GET_UINT(*subbuf, 4) + 9)
+    {
+        WINE_ERR("invalid size provided for internal file %s\n", name);
+        return FALSE;
+    }
+    return TRUE;
 }
 
 /***********************************************************************
@@ -215,251 +551,6 @@ LONG HLPFILE_Hash(LPCSTR lpszContext)
     return lHash;
 }
 
-/***********************************************************************
- *
- *           HLPFILE_ReadHlpFile
- */
-HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
-{
-    HLPFILE*      hlpfile;
-
-    for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
-    {
-        if (!strcmp(lpszPath, hlpfile->lpszPath))
-        {
-            hlpfile->wRefCount++;
-            return hlpfile;
-        }
-    }
-
-    hlpfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-                        sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
-    if (!hlpfile) return 0;
-
-    hlpfile->lpszPath           = (char*)hlpfile + sizeof(HLPFILE);
-    hlpfile->contents_start     = 0xFFFFFFFF;
-    hlpfile->next               = first_hlpfile;
-    hlpfile->wRefCount          = 1;
-
-    strcpy(hlpfile->lpszPath, lpszPath);
-
-    first_hlpfile = hlpfile;
-    if (hlpfile->next) hlpfile->next->prev = hlpfile;
-
-    if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
-    {
-        HLPFILE_FreeHlpFile(hlpfile);
-        hlpfile = 0;
-    }
-
-    return hlpfile;
-}
-
-/***********************************************************************
- *
- *           HLPFILE_DoReadHlpFile
- */
-static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
-{
-    BOOL        ret;
-    HFILE       hFile;
-    OFSTRUCT    ofs;
-    BYTE*       buf;
-    DWORD       ref = 0x0C;
-    unsigned    index, old_index, offset, len, offs, topicoffset;
-
-    hFile = OpenFile(lpszPath, &ofs, OF_READ);
-    if (hFile == HFILE_ERROR) return FALSE;
-
-    ret = HLPFILE_ReadFileToBuffer(hlpfile, hFile);
-    _lclose(hFile);
-    if (!ret) return FALSE;
-
-    if (!HLPFILE_SystemCommands(hlpfile)) return FALSE;
-
-    if (hlpfile->version <= 16 && !HLPFILE_GetTOMap(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 = hlpfile->topic_map[0];
-    old_index = -1;
-    offs = 0;
-    do
-    {
-        BYTE*   end;
-
-        if (hlpfile->version <= 16)
-        {
-            index  = (ref - 0x0C) / hlpfile->dsize;
-            offset = (ref - 0x0C) % hlpfile->dsize;
-        }
-        else
-        {
-            index  = (ref - 0x0C) >> 14;
-            offset = (ref - 0x0C) & 0x3FFF;
-        }
-
-        if (hlpfile->version <= 16 && index != old_index && old_index != -1)
-        {
-            /* we jumped to the next block, adjust pointers */
-            ref -= 12;
-            offset -= 12;
-        }
-
-        WINE_TRACE("ref=%08x => [%u/%u]\n", ref, index, offset);
-
-        if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;}
-        buf = hlpfile->topic_map[index] + offset;
-        if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;}
-        end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end);
-        if (index != old_index) {offs = 0; old_index = index;}
-
-        switch (buf[0x14])
-	{
-	case 0x02:
-            if (hlpfile->version <= 16)
-                topicoffset = ref + index * 12;
-            else
-                topicoffset = index * 0x8000 + offs;
-            if (!HLPFILE_AddPage(hlpfile, buf, end, ref, topicoffset)) return FALSE;
-            break;
-
-	case 0x01:
-	case 0x20:
-	case 0x23:
-            if (!HLPFILE_SkipParagraph(hlpfile, buf, end, &len)) return FALSE;
-            offs += len;
-            break;
-
-	default:
-            WINE_ERR("buf[0x14] = %x\n", buf[0x14]);
-	}
-
-        if (hlpfile->version <= 16)
-        {
-            ref += GET_UINT(buf, 0xc);
-            if (GET_UINT(buf, 0xc) == 0)
-                break;
-        }
-        else
-            ref = GET_UINT(buf, 0xc);
-    } while (ref != 0xffffffff);
-
-    HLPFILE_GetKeywords(hlpfile);
-    HLPFILE_GetMap(hlpfile);
-    if (hlpfile->version <= 16) return TRUE;
-    return HLPFILE_GetContext(hlpfile);
-}
-
-/***********************************************************************
- *
- *           HLPFILE_AddPage
- */
-static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned ref, unsigned offset)
-{
-    HLPFILE_PAGE* page;
-    const BYTE*   title;
-    UINT          titlesize, blocksize, datalen;
-    char*         ptr;
-    HLPFILE_MACRO*macro;
-
-    blocksize = GET_UINT(buf, 0);
-    datalen = GET_UINT(buf, 0x10);
-    title = buf + datalen;
-    if (title > end) {WINE_WARN("page2\n"); return FALSE;};
-
-    titlesize = GET_UINT(buf, 4);
-    page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize + 1);
-    if (!page) return FALSE;
-    page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
-
-    if (titlesize > blocksize - datalen)
-    {
-        /* need to decompress */
-        if (hlpfile->hasPhrases)
-            HLPFILE_Uncompress2(hlpfile, title, end, (BYTE*)page->lpszTitle, (BYTE*)page->lpszTitle + titlesize);
-        else if (hlpfile->hasPhrases40)
-            HLPFILE_Uncompress3(hlpfile, page->lpszTitle, page->lpszTitle + titlesize, title, end);
-        else
-        {
-            WINE_FIXME("Text size is too long, splitting\n");
-            titlesize = blocksize - datalen;
-            memcpy(page->lpszTitle, title, titlesize);
-        }
-    }
-    else
-        memcpy(page->lpszTitle, title, titlesize);
-
-    page->lpszTitle[titlesize] = '\0';
-
-    if (hlpfile->first_page)
-    {
-        hlpfile->last_page->next = page;
-        page->prev = hlpfile->last_page;
-        hlpfile->last_page = page;
-    }
-    else
-    {
-        hlpfile->first_page = page;
-        hlpfile->last_page = page;
-        page->prev = NULL;
-    }
-
-    page->file            = hlpfile;
-    page->next            = NULL;
-    page->first_macro     = NULL;
-    page->first_link      = NULL;
-    page->wNumber         = GET_UINT(buf, 0x21);
-    page->offset          = offset;
-    page->reference       = ref;
-
-    page->browse_bwd = GET_UINT(buf, 0x19);
-    page->browse_fwd = GET_UINT(buf, 0x1D);
-
-    if (hlpfile->version <= 16)
-    {
-        if (page->browse_bwd == 0xFFFF || page->browse_bwd == 0xFFFFFFFF)
-            page->browse_bwd = 0xFFFFFFFF;
-        else
-            page->browse_bwd = hlpfile->TOMap[page->browse_bwd];
-
-        if (page->browse_fwd == 0xFFFF || page->browse_fwd == 0xFFFFFFFF)
-            page->browse_fwd = 0xFFFFFFFF;
-        else
-            page->browse_fwd = hlpfile->TOMap[page->browse_fwd];
-    }
-
-    WINE_TRACE("Added page[%d]: title='%s' %08x << %08x >> %08x\n",
-               page->wNumber, page->lpszTitle, 
-               page->browse_bwd, page->offset, page->browse_fwd);
-
-    /* now load macros */
-    ptr = page->lpszTitle + strlen(page->lpszTitle) + 1;
-    while (ptr < page->lpszTitle + titlesize)
-    {
-        unsigned len = strlen(ptr);
-        char*    macro_str;
-
-        WINE_TRACE("macro: %s\n", ptr);
-        macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + len + 1);
-        macro->lpszMacro = macro_str = (char*)(macro + 1);
-        memcpy(macro_str, ptr, len + 1);
-        /* FIXME: shall we really link macro in reverse order ??
-         * may produce strange results when played at page opening
-         */
-        macro->next = page->first_macro;
-        page->first_macro = macro;
-        ptr += len + 1;
-    }
-
-    return TRUE;
-}
-
 static long fetch_long(const BYTE** ptr)
 {
     long        ret;
@@ -529,28 +620,6 @@ static unsigned short fetch_ushort(const BYTE** ptr)
     return ret;
 }
 
-/***********************************************************************
- *
- *           HLPFILE_SkipParagraph
- */
-static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned* len)
-{
-    const BYTE  *tmp;
-
-    if (!hlpfile->first_page) {WINE_WARN("no page\n"); return FALSE;};
-    if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};
-
-    tmp = buf + 0x15;
-    if (buf[0x14] == 0x20 || buf[0x14] == 0x23)
-    {
-        fetch_long(&tmp);
-        *len = fetch_ushort(&tmp);
-    }
-    else *len = end-buf-15;
-
-    return TRUE;
-}
-
 /******************************************************************
  *		HLPFILE_DecompressGfx
  *
@@ -1791,52 +1860,6 @@ static BOOL HLPFILE_ReadFileToBuffer(HLPFILE* hlpfile, HFILE hFile)
     return TRUE;
 }
 
-/**************************************************************************
- * comp_FindSubFile
- *
- * HLPFILE_BPTreeCompare function for HLPFILE directory.
- *
- */
-static int comp_FindSubFile(void *p, const void *key,
-                            int leaf, void** next)
-{
-    *next = (char *)p+strlen(p)+(leaf?5:3);
-    WINE_TRACE("Comparing '%s' with '%s'\n", (char *)p, (char *)key);
-    return strcmp(p, key);
-}
-
-/***********************************************************************
- *
- *           HLPFILE_FindSubFile
- */
-static BOOL HLPFILE_FindSubFile(HLPFILE* hlpfile, LPCSTR name, BYTE **subbuf, BYTE **subend)
-{
-    BYTE *ptr;
-
-    WINE_TRACE("looking for file '%s'\n", name);
-    ptr = HLPFILE_BPTreeSearch(hlpfile->file_buffer + GET_UINT(hlpfile->file_buffer, 4),
-                               name, comp_FindSubFile);
-    if (!ptr) return FALSE;
-    *subbuf = hlpfile->file_buffer + GET_UINT(ptr, strlen(name)+1);
-    if (*subbuf >= hlpfile->file_buffer + hlpfile->file_buffer_size)
-    {
-        WINE_ERR("internal file %s does not fit\n", name);
-        return FALSE;
-    }
-    *subend = *subbuf + GET_UINT(*subbuf, 0);
-    if (*subend > hlpfile->file_buffer + hlpfile->file_buffer_size)
-    {
-        WINE_ERR("internal file %s does not fit\n", name);
-        return FALSE;
-    }
-    if (GET_UINT(*subbuf, 0) < GET_UINT(*subbuf, 4) + 9)
-    {
-        WINE_ERR("invalid size provided for internal file %s\n", name);
-        return FALSE;
-    }
-    return TRUE;
-}
-
 /***********************************************************************
  *
  *           HLPFILE_SystemCommands
@@ -2009,66 +2032,181 @@ static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile)
 
 /***********************************************************************
  *
- *           HLPFILE_UncompressedLZ77_Size
+ *           HLPFILE_GetContext
  */
-static INT HLPFILE_UncompressedLZ77_Size(const BYTE *ptr, const BYTE *end)
+static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
 {
-    int  i, newsize = 0;
+    BYTE                *cbuf, *cend;
+    unsigned            clen;
 
-    while (ptr < end)
+    if (!HLPFILE_FindSubFile(hlpfile, "|CONTEXT",  &cbuf, &cend))
+    {WINE_WARN("context0\n"); return FALSE;}
+
+    clen = cend - cbuf;
+    hlpfile->Context = HeapAlloc(GetProcessHeap(), 0, clen);
+    if (!hlpfile->Context) return FALSE;
+    memcpy(hlpfile->Context, cbuf, clen);
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_GetKeywords
+ */
+static BOOL HLPFILE_GetKeywords(HLPFILE *hlpfile)
+{
+    BYTE                *cbuf, *cend;
+    unsigned            clen;
+
+    if (!HLPFILE_FindSubFile(hlpfile, "|KWBTREE", &cbuf, &cend)) return FALSE;
+    clen = cend - cbuf;
+    hlpfile->kwbtree = HeapAlloc(GetProcessHeap(), 0, clen);
+    if (!hlpfile->kwbtree) return FALSE;
+    memcpy(hlpfile->kwbtree, cbuf, clen);
+
+    if (!HLPFILE_FindSubFile(hlpfile, "|KWDATA", &cbuf, &cend))
     {
-        int mask = *ptr++;
-        for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)
-	{
-            if (mask & 1)
-	    {
-                int code = GET_USHORT(ptr, 0);
-                int len  = 3 + (code >> 12);
-                newsize += len;
-                ptr     += 2;
-	    }
-            else newsize++, ptr++;
-	}
+        WINE_ERR("corrupted help file: kwbtree present but kwdata absent\n");
+        HeapFree(GetProcessHeap(), 0, hlpfile->kwbtree);
+        return FALSE;
     }
+    clen = cend - cbuf;
+    hlpfile->kwdata = HeapAlloc(GetProcessHeap(), 0, clen);
+    if (!hlpfile->kwdata)
+    {
+        HeapFree(GetProcessHeap(), 0, hlpfile->kwdata);
+        return FALSE;
+    }
+    memcpy(hlpfile->kwdata, cbuf, clen);
 
-    return newsize;
+    return TRUE;
 }
 
 /***********************************************************************
  *
- *           HLPFILE_UncompressLZ77
+ *           HLPFILE_GetMap
  */
-static BYTE *HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr)
+static BOOL HLPFILE_GetMap(HLPFILE *hlpfile)
 {
-    int i;
+    BYTE                *cbuf, *cend;
+    unsigned            entries, i;
 
-    while (ptr < end)
+    if (!HLPFILE_FindSubFile(hlpfile, "|CTXOMAP",  &cbuf, &cend))
+    {WINE_WARN("no map section\n"); return FALSE;}
+
+    entries = GET_USHORT(cbuf, 9);
+    hlpfile->Map = HeapAlloc(GetProcessHeap(), 0, entries * sizeof(HLPFILE_MAP));
+    if (!hlpfile->Map) return FALSE;
+    hlpfile->wMapLen = entries;
+    for (i = 0; i < entries; i++)
     {
-        int mask = *ptr++;
-        for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)
-	{
-            if (mask & 1)
-	    {
-                int code   = GET_USHORT(ptr, 0);
-                int len    = 3 + (code >> 12);
-                int offset = code & 0xfff;
-                /*
-                 * We must copy byte-by-byte here. We cannot use memcpy nor
-                 * memmove here. Just example:
-                 * a[]={1,2,3,4,5,6,7,8,9,10}
-                 * newptr=a+2;
-                 * offset=1;
-                 * We expect:
-                 * {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 11, 12}
-                 */
-                for (; len>0; len--, newptr++) *newptr = *(newptr-offset-1);
-                ptr    += 2;
-	    }
-            else *newptr++ = *ptr++;
-	}
+        hlpfile->Map[i].lMap = GET_UINT(cbuf+11,i*8);
+        hlpfile->Map[i].offset = GET_UINT(cbuf+11,i*8+4);
     }
+    return TRUE;
+}
 
-    return newptr;
+/***********************************************************************
+ *
+ *           HLPFILE_GetTOMap
+ */
+static BOOL HLPFILE_GetTOMap(HLPFILE *hlpfile)
+{
+    BYTE                *cbuf, *cend;
+    unsigned            clen;
+
+    if (!HLPFILE_FindSubFile(hlpfile, "|TOMAP",  &cbuf, &cend))
+    {WINE_WARN("no tomap section\n"); return FALSE;}
+
+    clen = cend - cbuf - 9;
+    hlpfile->TOMap = HeapAlloc(GetProcessHeap(), 0, clen);
+    if (!hlpfile->TOMap) return FALSE;
+    memcpy(hlpfile->TOMap, cbuf+9, clen);
+    hlpfile->wTOMapLen = clen/4;
+    return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           DeleteMacro
+ */
+static void HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
+{
+    HLPFILE_MACRO*      next;
+
+    while (macro)
+    {
+        next = macro->next;
+        HeapFree(GetProcessHeap(), 0, macro);
+        macro = next;
+    }
+}
+
+/***********************************************************************
+ *
+ *           DeletePage
+ */
+static void HLPFILE_DeletePage(HLPFILE_PAGE* page)
+{
+    HLPFILE_PAGE* next;
+
+    while (page)
+    {
+        next = page->next;
+        HLPFILE_DeleteMacro(page->first_macro);
+        HeapFree(GetProcessHeap(), 0, page);
+        page = next;
+    }
+}
+
+/***********************************************************************
+ *
+ *           HLPFILE_FreeHlpFile
+ */
+void HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
+{
+    unsigned i;
+
+    if (!hlpfile || --hlpfile->wRefCount > 0) return;
+
+    if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
+    if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
+    else first_hlpfile = hlpfile->next;
+
+    if (hlpfile->numFonts)
+    {
+        for (i = 0; i < hlpfile->numFonts; i++)
+        {
+            DeleteObject(hlpfile->fonts[i].hFont);
+        }
+        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);
+
+    DestroyIcon(hlpfile->hIcon);
+    if (hlpfile->numWindows)    HeapFree(GetProcessHeap(), 0, hlpfile->windows);
+    HeapFree(GetProcessHeap(), 0, hlpfile->Context);
+    HeapFree(GetProcessHeap(), 0, hlpfile->Map);
+    HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle);
+    HeapFree(GetProcessHeap(), 0, hlpfile->lpszCopyright);
+    HeapFree(GetProcessHeap(), 0, hlpfile->file_buffer);
+    HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets);
+    HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer);
+    HeapFree(GetProcessHeap(), 0, hlpfile->topic_map);
+    HeapFree(GetProcessHeap(), 0, hlpfile->help_on_file);
+    HeapFree(GetProcessHeap(), 0, hlpfile);
 }
 
 /***********************************************************************
@@ -2259,423 +2397,267 @@ static BOOL HLPFILE_Uncompress_Topic(HLPFILE* hlpfile)
 
 /***********************************************************************
  *
- *           HLPFILE_Uncompress2
- */
-
-static void HLPFILE_Uncompress2(HLPFILE* hlpfile, const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend)
-{
-    BYTE *phptr, *phend;
-    UINT code;
-    UINT index;
-
-    while (ptr < end && newptr < newend)
-    {
-        if (!*ptr || *ptr >= 0x10)
-            *newptr++ = *ptr++;
-        else
-	{
-            code  = 0x100 * ptr[0] + ptr[1];
-            index = (code - 0x100) / 2;
-
-            phptr = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index];
-            phend = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index + 1];
-
-            if (newptr + (phend - phptr) > newend)
-            {
-                WINE_FIXME("buffer overflow %p > %p for %lu bytes\n",
-                           newptr, newend, (SIZE_T)(phend - phptr));
-                return;
-            }
-            memcpy(newptr, phptr, phend - phptr);
-            newptr += phend - phptr;
-            if (code & 1) *newptr++ = ' ';
-
-            ptr += 2;
-	}
-    }
-    if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend);
-}
-
-/******************************************************************
- *		HLPFILE_Uncompress3
- *
- *
+ *           HLPFILE_AddPage
  */
-static BOOL HLPFILE_Uncompress3(HLPFILE* hlpfile, char* dst, const char* dst_end,
-                                const BYTE* src, const BYTE* src_end)
+static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned ref, unsigned offset)
 {
-    unsigned int idx, len;
-
-    for (; src < src_end; src++)
-    {
-        if ((*src & 1) == 0)
-        {
-            idx = *src / 2;
-            if (idx > hlpfile->num_phrases)
-            {
-                WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases);
-                len = 0;
-            }
-            else 
-            {
-                len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx];
-                if (dst + len <= dst_end)
-                    memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len);
-            }
-        }
-        else if ((*src & 0x03) == 0x01)
-        {
-            idx = (*src + 1) * 64;
-            idx += *++src;
-            if (idx > hlpfile->num_phrases)
-            {
-                WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases);
-                len = 0;
-            }
-            else
-            {
-                len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx];
-                if (dst + len <= dst_end)
-                    memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len);
-            }
-        }
-        else if ((*src & 0x07) == 0x03)
-        {
-            len = (*src / 8) + 1;
-            if (dst + len <= dst_end)
-                memcpy(dst, src + 1, len);
-            src += len;
-        }
-        else
-        {
-            len = (*src / 16) + 1;
-            if (dst + len <= dst_end)
-                memset(dst, ((*src & 0x0F) == 0x07) ? ' ' : 0, len);
-        }
-        dst += len;
-    }
+    HLPFILE_PAGE* page;
+    const BYTE*   title;
+    UINT          titlesize, blocksize, datalen;
+    char*         ptr;
+    HLPFILE_MACRO*macro;
 
-    if (dst > dst_end) WINE_ERR("buffer overflow (%p > %p)\n", dst, dst_end);
-    return TRUE;
-}
+    blocksize = GET_UINT(buf, 0);
+    datalen = GET_UINT(buf, 0x10);
+    title = buf + datalen;
+    if (title > end) {WINE_WARN("page2\n"); return FALSE;};
 
-/******************************************************************
- *		HLPFILE_UncompressRLE
- *
- *
- */
-static void HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE* dst, unsigned dstsz)
-{
-    BYTE        ch;
-    BYTE*       sdst = dst + dstsz;
+    titlesize = GET_UINT(buf, 4);
+    page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize + 1);
+    if (!page) return FALSE;
+    page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
 
-    while (src < end)
+    if (titlesize > blocksize - datalen)
     {
-        ch = *src++;
-        if (ch & 0x80)
-        {
-            ch &= 0x7F;
-            if (dst + ch <= sdst)
-                memcpy(dst, src, ch);
-            src += ch;
-        }
+        /* need to decompress */
+        if (hlpfile->hasPhrases)
+            HLPFILE_Uncompress2(hlpfile, title, end, (BYTE*)page->lpszTitle, (BYTE*)page->lpszTitle + titlesize);
+        else if (hlpfile->hasPhrases40)
+            HLPFILE_Uncompress3(hlpfile, page->lpszTitle, page->lpszTitle + titlesize, title, end);
         else
         {
-            if (dst + ch <= sdst)
-                memset(dst, (char)*src, ch);
-            src++;
+            WINE_FIXME("Text size is too long, splitting\n");
+            titlesize = blocksize - datalen;
+            memcpy(page->lpszTitle, title, titlesize);
         }
-        dst += ch;
     }
-    if (dst != sdst)
-        WINE_WARN("Buffer X-flow: d(%lu) instead of d(%u)\n",
-                  (SIZE_T)(dst - (sdst - dstsz)), dstsz);
-}
+    else
+        memcpy(page->lpszTitle, title, titlesize);
 
-/**************************************************************************
- * HLPFILE_BPTreeSearch
- *
- * Searches for an element in B+ tree
- *
- * PARAMS
- *     buf        [I] pointer to the embedded file structured as a B+ tree
- *     key        [I] pointer to data to find
- *     comp       [I] compare function
- *
- * RETURNS
- *     Pointer to block identified by key, or NULL if failure.
- *
- */
-void* HLPFILE_BPTreeSearch(BYTE* buf, const void* key,
-                           HLPFILE_BPTreeCompare comp)
-{
-    unsigned magic;
-    unsigned page_size;
-    unsigned cur_page;
-    unsigned level;
-    BYTE *pages, *ptr, *newptr;
-    int i, entries;
-    int ret;
+    page->lpszTitle[titlesize] = '\0';
 
-    magic = GET_USHORT(buf, 9);
-    if (magic != 0x293B)
-    {
-        WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic);
-        return NULL;
-    }
-    page_size = GET_USHORT(buf, 9+4);
-    cur_page  = GET_USHORT(buf, 9+26);
-    level     = GET_USHORT(buf, 9+32);
-    pages     = buf + 9 + 38;
-    while (--level > 0)
+    if (hlpfile->first_page)
     {
-        ptr = pages + cur_page*page_size;
-        entries = GET_SHORT(ptr, 2);
-        ptr += 6;
-        for (i = 0; i < entries; i++)
-        {
-            if (comp(ptr, key, 0, (void **)&newptr) > 0) break;
-            ptr = newptr;
-        }
-        cur_page = GET_USHORT(ptr-2, 0);
+        hlpfile->last_page->next = page;
+        page->prev = hlpfile->last_page;
+        hlpfile->last_page = page;
     }
-    ptr = pages + cur_page*page_size;
-    entries = GET_SHORT(ptr, 2);
-    ptr += 8;
-    for (i = 0; i < entries; i++)
+    else
     {
-        ret = comp(ptr, key, 1, (void **)&newptr);
-        if (ret == 0) return ptr;
-        if (ret > 0) return NULL;
-        ptr = newptr;
+        hlpfile->first_page = page;
+        hlpfile->last_page = page;
+        page->prev = NULL;
     }
-    return NULL;
-}
 
-/**************************************************************************
- * HLPFILE_BPTreeEnum
- *
- * Enumerates elements in B+ tree.
- *
- * PARAMS
- *     buf        [I]  pointer to the embedded file structured as a B+ tree
- *     cb         [I]  compare function
- *     cookie     [IO] cookie for cb function
- */
-void HLPFILE_BPTreeEnum(BYTE* buf, HLPFILE_BPTreeCallback cb, void* cookie)
-{
-    unsigned magic;
-    unsigned page_size;
-    unsigned cur_page;
-    unsigned level;
-    BYTE *pages, *ptr, *newptr;
-    int i, entries;
+    page->file            = hlpfile;
+    page->next            = NULL;
+    page->first_macro     = NULL;
+    page->first_link      = NULL;
+    page->wNumber         = GET_UINT(buf, 0x21);
+    page->offset          = offset;
+    page->reference       = ref;
 
-    magic = GET_USHORT(buf, 9);
-    if (magic != 0x293B)
-    {
-        WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic);
-        return;
-    }
-    page_size = GET_USHORT(buf, 9+4);
-    cur_page  = GET_USHORT(buf, 9+26);
-    level     = GET_USHORT(buf, 9+32);
-    pages     = buf + 9 + 38;
-    while (--level > 0)
-    {
-        ptr = pages + cur_page*page_size;
-        cur_page = GET_USHORT(ptr, 4);
-    }
-    while (cur_page != 0xFFFF)
+    page->browse_bwd = GET_UINT(buf, 0x19);
+    page->browse_fwd = GET_UINT(buf, 0x1D);
+
+    if (hlpfile->version <= 16)
     {
-        ptr = pages + cur_page*page_size;
-        entries = GET_SHORT(ptr, 2);
-        ptr += 8;
-        for (i = 0; i < entries; i++)
-        {
-            cb(ptr, (void **)&newptr, cookie);
-            ptr = newptr;
-        }
-        cur_page = GET_USHORT(pages+cur_page*page_size, 6);
-    }
-}
+        if (page->browse_bwd == 0xFFFF || page->browse_bwd == 0xFFFFFFFF)
+            page->browse_bwd = 0xFFFFFFFF;
+        else
+            page->browse_bwd = hlpfile->TOMap[page->browse_bwd];
 
+        if (page->browse_fwd == 0xFFFF || page->browse_fwd == 0xFFFFFFFF)
+            page->browse_fwd = 0xFFFFFFFF;
+        else
+            page->browse_fwd = hlpfile->TOMap[page->browse_fwd];
+    }
 
-/***********************************************************************
- *
- *           HLPFILE_GetContext
- */
-static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
-{
-    BYTE                *cbuf, *cend;
-    unsigned            clen;
+    WINE_TRACE("Added page[%d]: title='%s' %08x << %08x >> %08x\n",
+               page->wNumber, page->lpszTitle, 
+               page->browse_bwd, page->offset, page->browse_fwd);
 
-    if (!HLPFILE_FindSubFile(hlpfile, "|CONTEXT",  &cbuf, &cend))
-    {WINE_WARN("context0\n"); return FALSE;}
+    /* now load macros */
+    ptr = page->lpszTitle + strlen(page->lpszTitle) + 1;
+    while (ptr < page->lpszTitle + titlesize)
+    {
+        unsigned len = strlen(ptr);
+        char*    macro_str;
 
-    clen = cend - cbuf;
-    hlpfile->Context = HeapAlloc(GetProcessHeap(), 0, clen);
-    if (!hlpfile->Context) return FALSE;
-    memcpy(hlpfile->Context, cbuf, clen);
+        WINE_TRACE("macro: %s\n", ptr);
+        macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + len + 1);
+        macro->lpszMacro = macro_str = (char*)(macro + 1);
+        memcpy(macro_str, ptr, len + 1);
+        /* FIXME: shall we really link macro in reverse order ??
+         * may produce strange results when played at page opening
+         */
+        macro->next = page->first_macro;
+        page->first_macro = macro;
+        ptr += len + 1;
+    }
 
     return TRUE;
 }
 
 /***********************************************************************
  *
- *           HLPFILE_GetKeywords
+ *           HLPFILE_SkipParagraph
  */
-static BOOL HLPFILE_GetKeywords(HLPFILE *hlpfile)
+static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned* len)
 {
-    BYTE                *cbuf, *cend;
-    unsigned            clen;
+    const BYTE  *tmp;
 
-    if (!HLPFILE_FindSubFile(hlpfile, "|KWBTREE", &cbuf, &cend)) return FALSE;
-    clen = cend - cbuf;
-    hlpfile->kwbtree = HeapAlloc(GetProcessHeap(), 0, clen);
-    if (!hlpfile->kwbtree) return FALSE;
-    memcpy(hlpfile->kwbtree, cbuf, clen);
+    if (!hlpfile->first_page) {WINE_WARN("no page\n"); return FALSE;};
+    if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};
 
-    if (!HLPFILE_FindSubFile(hlpfile, "|KWDATA", &cbuf, &cend))
-    {
-        WINE_ERR("corrupted help file: kwbtree present but kwdata absent\n");
-        HeapFree(GetProcessHeap(), 0, hlpfile->kwbtree);
-        return FALSE;
-    }
-    clen = cend - cbuf;
-    hlpfile->kwdata = HeapAlloc(GetProcessHeap(), 0, clen);
-    if (!hlpfile->kwdata)
+    tmp = buf + 0x15;
+    if (buf[0x14] == 0x20 || buf[0x14] == 0x23)
     {
-        HeapFree(GetProcessHeap(), 0, hlpfile->kwdata);
-        return FALSE;
+        fetch_long(&tmp);
+        *len = fetch_ushort(&tmp);
     }
-    memcpy(hlpfile->kwdata, cbuf, clen);
+    else *len = end-buf-15;
 
     return TRUE;
 }
 
 /***********************************************************************
  *
- *           HLPFILE_GetMap
+ *           HLPFILE_DoReadHlpFile
  */
-static BOOL HLPFILE_GetMap(HLPFILE *hlpfile)
+static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
 {
-    BYTE                *cbuf, *cend;
-    unsigned            entries, i;
+    BOOL        ret;
+    HFILE       hFile;
+    OFSTRUCT    ofs;
+    BYTE*       buf;
+    DWORD       ref = 0x0C;
+    unsigned    index, old_index, offset, len, offs, topicoffset;
 
-    if (!HLPFILE_FindSubFile(hlpfile, "|CTXOMAP",  &cbuf, &cend))
-    {WINE_WARN("no map section\n"); return FALSE;}
+    hFile = OpenFile(lpszPath, &ofs, OF_READ);
+    if (hFile == HFILE_ERROR) return FALSE;
 
-    entries = GET_USHORT(cbuf, 9);
-    hlpfile->Map = HeapAlloc(GetProcessHeap(), 0, entries * sizeof(HLPFILE_MAP));
-    if (!hlpfile->Map) return FALSE;
-    hlpfile->wMapLen = entries;
-    for (i = 0; i < entries; i++)
-    {
-        hlpfile->Map[i].lMap = GET_UINT(cbuf+11,i*8);
-        hlpfile->Map[i].offset = GET_UINT(cbuf+11,i*8+4);
-    }
-    return TRUE;
-}
+    ret = HLPFILE_ReadFileToBuffer(hlpfile, hFile);
+    _lclose(hFile);
+    if (!ret) return FALSE;
 
-/***********************************************************************
- *
- *           HLPFILE_GetTOMap
- */
-static BOOL HLPFILE_GetTOMap(HLPFILE *hlpfile)
-{
-    BYTE                *cbuf, *cend;
-    unsigned            clen;
+    if (!HLPFILE_SystemCommands(hlpfile)) return FALSE;
 
-    if (!HLPFILE_FindSubFile(hlpfile, "|TOMAP",  &cbuf, &cend))
-    {WINE_WARN("no tomap section\n"); return FALSE;}
+    if (hlpfile->version <= 16 && !HLPFILE_GetTOMap(hlpfile)) return FALSE;
 
-    clen = cend - cbuf - 9;
-    hlpfile->TOMap = HeapAlloc(GetProcessHeap(), 0, clen);
-    if (!hlpfile->TOMap) return FALSE;
-    memcpy(hlpfile->TOMap, cbuf+9, clen);
-    hlpfile->wTOMapLen = clen/4;
-    return TRUE;
-}
+    /* load phrases support */
+    if (!HLPFILE_UncompressLZ77_Phrases(hlpfile))
+        HLPFILE_Uncompress_Phrases40(hlpfile);
 
-/***********************************************************************
- *
- *           DeleteMacro
- */
-static void HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
-{
-    HLPFILE_MACRO*      next;
+    if (!HLPFILE_Uncompress_Topic(hlpfile)) return FALSE;
+    if (!HLPFILE_ReadFont(hlpfile)) return FALSE;
 
-    while (macro)
+    buf = hlpfile->topic_map[0];
+    old_index = -1;
+    offs = 0;
+    do
     {
-        next = macro->next;
-        HeapFree(GetProcessHeap(), 0, macro);
-        macro = next;
-    }
-}
+        BYTE*   end;
 
-/***********************************************************************
- *
- *           DeletePage
- */
-static void HLPFILE_DeletePage(HLPFILE_PAGE* page)
-{
-    HLPFILE_PAGE* next;
+        if (hlpfile->version <= 16)
+        {
+            index  = (ref - 0x0C) / hlpfile->dsize;
+            offset = (ref - 0x0C) % hlpfile->dsize;
+        }
+        else
+        {
+            index  = (ref - 0x0C) >> 14;
+            offset = (ref - 0x0C) & 0x3FFF;
+        }
 
-    while (page)
-    {
-        next = page->next;
-        HLPFILE_DeleteMacro(page->first_macro);
-        HeapFree(GetProcessHeap(), 0, page);
-        page = next;
-    }
+        if (hlpfile->version <= 16 && index != old_index && old_index != -1)
+        {
+            /* we jumped to the next block, adjust pointers */
+            ref -= 12;
+            offset -= 12;
+        }
+
+        WINE_TRACE("ref=%08x => [%u/%u]\n", ref, index, offset);
+
+        if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;}
+        buf = hlpfile->topic_map[index] + offset;
+        if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;}
+        end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end);
+        if (index != old_index) {offs = 0; old_index = index;}
+
+        switch (buf[0x14])
+	{
+	case 0x02:
+            if (hlpfile->version <= 16)
+                topicoffset = ref + index * 12;
+            else
+                topicoffset = index * 0x8000 + offs;
+            if (!HLPFILE_AddPage(hlpfile, buf, end, ref, topicoffset)) return FALSE;
+            break;
+
+	case 0x01:
+	case 0x20:
+	case 0x23:
+            if (!HLPFILE_SkipParagraph(hlpfile, buf, end, &len)) return FALSE;
+            offs += len;
+            break;
+
+	default:
+            WINE_ERR("buf[0x14] = %x\n", buf[0x14]);
+	}
+
+        if (hlpfile->version <= 16)
+        {
+            ref += GET_UINT(buf, 0xc);
+            if (GET_UINT(buf, 0xc) == 0)
+                break;
+        }
+        else
+            ref = GET_UINT(buf, 0xc);
+    } while (ref != 0xffffffff);
+
+    HLPFILE_GetKeywords(hlpfile);
+    HLPFILE_GetMap(hlpfile);
+    if (hlpfile->version <= 16) return TRUE;
+    return HLPFILE_GetContext(hlpfile);
 }
 
 /***********************************************************************
  *
- *           HLPFILE_FreeHlpFile
+ *           HLPFILE_ReadHlpFile
  */
-void HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
+HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
 {
-    unsigned i;
-
-    if (!hlpfile || --hlpfile->wRefCount > 0) return;
-
-    if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
-    if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
-    else first_hlpfile = hlpfile->next;
+    HLPFILE*      hlpfile;
 
-    if (hlpfile->numFonts)
+    for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
     {
-        for (i = 0; i < hlpfile->numFonts; i++)
+        if (!strcmp(lpszPath, hlpfile->lpszPath))
         {
-            DeleteObject(hlpfile->fonts[i].hFont);
+            hlpfile->wRefCount++;
+            return hlpfile;
         }
-        HeapFree(GetProcessHeap(), 0, hlpfile->fonts);
     }
 
-    if (hlpfile->numBmps)
+    hlpfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                        sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
+    if (!hlpfile) return 0;
+
+    hlpfile->lpszPath           = (char*)hlpfile + sizeof(HLPFILE);
+    hlpfile->contents_start     = 0xFFFFFFFF;
+    hlpfile->next               = first_hlpfile;
+    hlpfile->wRefCount          = 1;
+
+    strcpy(hlpfile->lpszPath, lpszPath);
+
+    first_hlpfile = hlpfile;
+    if (hlpfile->next) hlpfile->next->prev = hlpfile;
+
+    if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
     {
-        for (i = 0; i < hlpfile->numBmps; i++)
-        {
-            DeleteObject(hlpfile->bmps[i]);
-        }
-        HeapFree(GetProcessHeap(), 0, hlpfile->bmps);
+        HLPFILE_FreeHlpFile(hlpfile);
+        hlpfile = 0;
     }
 
-    HLPFILE_DeletePage(hlpfile->first_page);
-    HLPFILE_DeleteMacro(hlpfile->first_macro);
-
-    DestroyIcon(hlpfile->hIcon);
-    if (hlpfile->numWindows)    HeapFree(GetProcessHeap(), 0, hlpfile->windows);
-    HeapFree(GetProcessHeap(), 0, hlpfile->Context);
-    HeapFree(GetProcessHeap(), 0, hlpfile->Map);
-    HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle);
-    HeapFree(GetProcessHeap(), 0, hlpfile->lpszCopyright);
-    HeapFree(GetProcessHeap(), 0, hlpfile->file_buffer);
-    HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets);
-    HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer);
-    HeapFree(GetProcessHeap(), 0, hlpfile->topic_map);
-    HeapFree(GetProcessHeap(), 0, hlpfile->help_on_file);
-    HeapFree(GetProcessHeap(), 0, hlpfile);
+    return hlpfile;
 }
-- 
1.5.6.5




More information about the wine-patches mailing list