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

This commit is contained in:
Kirill K. Smirnov 2007-12-01 19:01:47 +03:00 committed by Alexandre Julliard
parent f4023569b3
commit 2c52f8883d
1 changed files with 37 additions and 59 deletions

View File

@ -51,6 +51,7 @@ static inline unsigned GET_UINT(const BYTE* buffer, unsigned i)
static HLPFILE *first_hlpfile = 0; static HLPFILE *first_hlpfile = 0;
static BYTE *file_buffer; static BYTE *file_buffer;
static UINT file_buffer_size;
static struct static struct
{ {
@ -1328,7 +1329,6 @@ static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile)
static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile) static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
{ {
BYTE header[16], dummy[1]; BYTE header[16], dummy[1];
UINT size;
if (_hread(hFile, header, 16) != 16) {WINE_WARN("header\n"); return FALSE;}; 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) if (GET_UINT(header, 0) != 0x00035F3F)
{WINE_WARN("wrong header\n"); return FALSE;}; {WINE_WARN("wrong header\n"); return FALSE;};
size = GET_UINT(header, 12); file_buffer_size = GET_UINT(header, 12);
file_buffer = HeapAlloc(GetProcessHeap(), 0, size + 1); file_buffer = HeapAlloc(GetProcessHeap(), 0, file_buffer_size + 1);
if (!file_buffer) return FALSE; if (!file_buffer) return FALSE;
memcpy(file_buffer, header, 16); 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;}; {WINE_WARN("filesize1\n"); return FALSE;};
if (_hread(hFile, dummy, 1) != 0) WINE_WARN("filesize2\n"); 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; 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 * HLPFILE_FindSubFile
*/ */
static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE **subbuf, BYTE **subend) 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 *ptr;
BYTE *bth;
unsigned pgsize; WINE_TRACE("looking for file '%s'\n", name);
unsigned pglast; ptr = HLPFILE_BPTreeSearch(file_buffer + GET_UINT(file_buffer, 4),
unsigned nentries; name, comp_FindSubFile);
unsigned i, n; if (!ptr) return FALSE;
*subbuf = file_buffer + GET_UINT(ptr, strlen(name)+1);
bth = root + 9; if (*subbuf >= file_buffer + file_buffer_size)
/* 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++)
{ {
nentries = GET_USHORT(ptr, 2); WINE_ERR("internal file %s does not fit\n", name);
pglast = GET_USHORT(ptr, 4); return FALSE;
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;
} }
*subend = *subbuf + GET_UINT(*subbuf, 0);
nentries = GET_USHORT(ptr, 2); if (*subend > file_buffer + file_buffer_size)
ptr += 8;
for (i = 0; i < nentries; i++)
{ {
char* fname = (char*)ptr; WINE_ERR("internal file %s does not fit\n", name);
ptr += strlen(fname) + 1; return FALSE;
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;
} }
if (GET_UINT(*subbuf, 0) < GET_UINT(*subbuf, 4) + 9)
return FALSE; {
WINE_ERR("invalid size provided for internal file %s\n", name);
return FALSE;
}
return TRUE;
} }
/*********************************************************************** /***********************************************************************