Kirill K. Smirnov : winhelp: Rewrite internal files lookup using B+ tree search. Add some sanity checks .

Alexandre Julliard julliard at winehq.org
Mon Dec 3 09:17:59 CST 2007


Module: wine
Branch: master
Commit: 2c52f8883ddc3ef1d8973b272dbdb6596dd5bc45
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=2c52f8883ddc3ef1d8973b272dbdb6596dd5bc45

Author: Kirill K. Smirnov <lich at math.spbu.ru>
Date:   Sat Dec  1 19:01:47 2007 +0300

winhelp: Rewrite internal files lookup using B+ tree search. Add some sanity checks.

---

 programs/winhelp/hlpfile.c |   96 +++++++++++++++++---------------------------
 1 files changed, 37 insertions(+), 59 deletions(-)

diff --git a/programs/winhelp/hlpfile.c b/programs/winhelp/hlpfile.c
index 27d5555..54ea5bd 100644
--- a/programs/winhelp/hlpfile.c
+++ b/programs/winhelp/hlpfile.c
@@ -51,6 +51,7 @@ static inline unsigned GET_UINT(const BYTE* buffer, unsigned i)
 
 static HLPFILE *first_hlpfile = 0;
 static BYTE    *file_buffer;
+static UINT     file_buffer_size;
 
 static struct
 {
@@ -1328,7 +1329,6 @@ static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile)
 static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
 {
     BYTE  header[16], dummy[1];
-    UINT  size;
 
     if (_hread(hFile, header, 16) != 16) {WINE_WARN("header\n"); return FALSE;};
 
@@ -1336,87 +1336,65 @@ static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
     if (GET_UINT(header, 0) != 0x00035F3F)
     {WINE_WARN("wrong header\n"); return FALSE;};
 
-    size = GET_UINT(header, 12);
-    file_buffer = HeapAlloc(GetProcessHeap(), 0, size + 1);
+    file_buffer_size = GET_UINT(header, 12);
+    file_buffer = HeapAlloc(GetProcessHeap(), 0, file_buffer_size + 1);
     if (!file_buffer) return FALSE;
 
     memcpy(file_buffer, header, 16);
-    if (_hread(hFile, file_buffer + 16, size - 16) != size - 16)
+    if (_hread(hFile, file_buffer + 16, file_buffer_size - 16) != file_buffer_size - 16)
     {WINE_WARN("filesize1\n"); return FALSE;};
 
     if (_hread(hFile, dummy, 1) != 0) WINE_WARN("filesize2\n");
 
-    file_buffer[size] = '\0'; /* FIXME: was '0', sounds ackward to me */
+    file_buffer[file_buffer_size] = '\0'; /* FIXME: was '0', sounds ackward to me */
 
     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(LPCSTR name, BYTE **subbuf, BYTE **subend)
 {
-    BYTE *root = file_buffer + GET_UINT(file_buffer,  4);
-    BYTE *end  = file_buffer + GET_UINT(file_buffer, 12);
     BYTE *ptr;
-    BYTE *bth;
-
-    unsigned    pgsize;
-    unsigned    pglast;
-    unsigned    nentries;
-    unsigned    i, n;
 
-    bth = root + 9;
-
-    /* FIXME: this should be using the EnumBTree functions from this file */
-    pgsize = GET_USHORT(bth, 4);
-    WINE_TRACE("%s => pgsize=%u #pg=%u rootpg=%u #lvl=%u\n", 
-               name, pgsize, GET_USHORT(bth, 30), GET_USHORT(bth, 26), GET_USHORT(bth, 32));
-
-    ptr = bth + 38 + GET_USHORT(bth, 26) * pgsize;
-
-    for (n = 1; n < GET_USHORT(bth, 32); n++)
+    WINE_TRACE("looking for file '%s'\n", name);
+    ptr = HLPFILE_BPTreeSearch(file_buffer + GET_UINT(file_buffer, 4),
+                               name, comp_FindSubFile);
+    if (!ptr) return FALSE;
+    *subbuf = file_buffer + GET_UINT(ptr, strlen(name)+1);
+    if (*subbuf >= file_buffer + file_buffer_size)
     {
-        nentries = GET_USHORT(ptr, 2);
-        pglast = GET_USHORT(ptr, 4);
-        WINE_TRACE("[%u]: #entries=%u next=%u\n", n, nentries, pglast);
-
-        ptr += 6;
-        for (i = 0; i < nentries; i++)
-        {
-            char *str = (char*) ptr;
-            WINE_TRACE("<= %s\n", str);
-            if (strcmp(name, str) < 0) break;
-            ptr += strlen(str) + 1;
-            pglast = GET_USHORT(ptr, 0);
-            ptr += 2;
-        }
-        ptr = bth + 38 + pglast * pgsize;
+        WINE_ERR("internal file %s does not fit\n", name);
+        return FALSE;
     }
-
-    nentries = GET_USHORT(ptr, 2);
-    ptr += 8;
-    for (i = 0; i < nentries; i++)
+    *subend = *subbuf + GET_UINT(*subbuf, 0);
+    if (*subend > file_buffer + file_buffer_size)
     {
-        char*   fname = (char*)ptr;
-        ptr += strlen(fname) + 1;
-        WINE_TRACE("\\- %s\n", fname);
-        if (strcmp(fname, name) == 0)
-        {
-            *subbuf = file_buffer + GET_UINT(ptr, 0);
-            *subend = *subbuf + GET_UINT(*subbuf, 0);
-            if (file_buffer > *subbuf || *subbuf > *subend || *subend > end)
-	    {
-                WINE_WARN("size mismatch\n");
-                return FALSE;
-	    }
-            return TRUE;
-        }
-        ptr += 4;
+        WINE_ERR("internal file %s does not fit\n", name);
+        return FALSE;
     }
-
-    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;
 }
 
 /***********************************************************************




More information about the wine-cvs mailing list