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.
This commit is contained in:
Eric Pouech 2002-11-13 04:09:34 +00:00 committed by Alexandre Julliard
parent b61fd42e4d
commit 6637654b53
3 changed files with 272 additions and 199 deletions

View file

@ -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 INT HLPFILE_UncompressedLZ77_Size(BYTE *ptr, BYTE *end);
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 @@ static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile);
*
* 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_PAGE *HLPFILE_PageByNumber(LPCSTR lpszPath, UINT wNum)
*
* 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 @@ HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG lHash)
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 *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
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->numFonts = 0;
hlpfile->fonts = NULL;
hlpfile->numBmps = 0;
hlpfile->bmps = NULL;
hlpfile->numFonts = 0;
hlpfile->fonts = NULL;
strcpy(hlpfile->lpszPath, lpszPath);
@ -265,10 +273,12 @@ static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
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,37 +340,31 @@ static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigned off
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)
{
if (hlpfile->hasPhrases)
{
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);
}
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);
}
HLPFILE_Uncompress2(title, end, page->lpszTitle, page->lpszTitle + 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);
if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10))
{
/* need to decompress */
HLPFILE_Uncompress3(page->lpszTitle, page->lpszTitle + titlesize - 1,
title, end);
}
else
{
memcpy(page->lpszTitle, title, titlesize - 1);
}
}
page->lpszTitle[titlesize - 1] = 0;
if (hlpfile->first_page)
{
HLPFILE_PAGE *p;
@ -469,6 +473,8 @@ static BOOL HLPFILE_LoadPictureByAddr(HLPFILE *hlpfile, char* ref,
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 @@ static BOOL HLPFILE_LoadPictureByAddr(HLPFILE *hlpfile, char* ref,
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 @@ static BOOL HLPFILE_LoadPictureByAddr(HLPFILE *hlpfile, char* ref,
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 @@ static BOOL HLPFILE_LoadPictureByAddr(HLPFILE *hlpfile, char* ref,
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 @@ static BOOL HLPFILE_LoadPictureByIndex(HLPFILE *hlpfile, unsigned index, uns
{
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,32 +684,23 @@ static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigne
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)
{
if (hlpfile->hasPhrases)
{
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);
}
else
{
/* block is compressed */
text = HeapAlloc(GetProcessHeap(), 0, size);
if (!text) return FALSE;
HLPFILE_Uncompress3(text, text + size, buf + GET_UINT(buf, 0x10), end);
}
HLPFILE_Uncompress2(buf + GET_UINT(buf, 0x10), end, text, text + size);
}
else
{
text = buf + GET_UINT(buf, 0x10);
if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10))
{
/* block is compressed */
HLPFILE_Uncompress3(text, text + size, buf + GET_UINT(buf, 0x10), end);
}
else
{
text = buf + GET_UINT(buf, 0x10);
}
}
text_end = text + size;
@ -684,6 +709,7 @@ static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigne
fetch_long(&format);
*len = fetch_ushort(&format);
if (buf[0x14] == 0x23)
{
char type;
@ -723,6 +749,9 @@ static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigne
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 @@ static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigne
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 @@ static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigne
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 @@ static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigne
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 @@ static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile)
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 @@ static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile)
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 @@ static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile)
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 @@ static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile)
*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 @@ static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE* hlpfile)
/***********************************************************************
*
* 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 @@ static BOOL HLPFILE_UncompressLZ77_Topic(HLPFILE* hlpfile)
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;
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;
/* 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;
newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + 0x1000));
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;
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;
}
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;
topic.map[i] = newptr;
newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + 0x1000), newptr);
}
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 @@ static void HLPFILE_Uncompress2(BYTE **pptr, BYTE *end, BYTE *newptr)
ptr += 2;
}
}
*newptr = '\0';
*pptr = ptr;
if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend);
}
/******************************************************************
@ -1515,16 +1550,31 @@ static BOOL HLPFILE_Uncompress3(char* dst, const char* dst_end,
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 @@ static void HLPFILE_EnumBTreeLeaves(const BYTE* buf, const BYTE* end, unsigned (
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 @@ static void HLPFILE_EnumBTreeLeaves(const BYTE* buf, const BYTE* end, unsigned (
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 @@ static void HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
*/
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 @@ void HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
if (hlpfile->numFonts)
{
unsigned i;
for (i = 0; i < hlpfile->numFonts; i++)
{
DeleteObject(hlpfile->fonts[i].hFont);
@ -1727,11 +1778,21 @@ void HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
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);
}

View file

@ -92,10 +92,13 @@ typedef struct tagHlpFileFile
{
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 @@ typedef struct tagHlpFileFile
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*);

View file

@ -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 +373,17 @@ BOOL WINHELP_CreateHelpWindowByPage(HLPFILE_PAGE* page, LPCSTR lpszWindow,
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 +391,16 @@ BOOL WINHELP_CreateHelpWindowByHash(LPCSTR lpszFile, LONG lHash, LPCSTR lpszWind
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);