wine/programs/winhelp/hlpfile.c

990 lines
23 KiB
C
Raw Normal View History

Release 960506 Mon May 6 12:56:26 1996 Alexandre Julliard <julliard@lrc.epfl.ch> * [DEVELOPERS-HINTS] Added paragraph on naming conventions for Win16/Win32/Winelib. * [controls/menu.c] Create a default system menu that is the same for all windows instead of making a copy every time. * [include/wintypes.h] Added WINELIB_NAME and DECL_WINELIB_TYPE macros. Added xx16 and xx32 definitions for most types. General clean-up. * [memory/global.c] [memory/local.c] [*/*] Renamed Global and Local heap functions to xxx16. Added all xxx32 versions of the same functions. * [memory/selector.c] Mask out lower bits of selector in FreeSelector(). * [misc/lstr.c] Fixed wvsprintf(). * [windows/class.c] Changed the class structure to make Win32 support easier. * [windows/defwnd.c] Added handling of WM_INITMENUPOPUP for system menu to gray out invalid options. * [windows/winpos.c] Bug fix: the WINDOSPOS structure pointer in WM_NCCALCSIZE must be a SEGPTR. Sun May 5 03:51:26 1996 Huw D. M. Davies <h.davies1@physics.oxford.ac.uk> * [memory/local.c] Implementation of moveable and (rudimentary) support for discardable local memory, plus several bug fixes. Sat May 4 18:33:35 1996 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de> * [include/windows.h] [windows/win.c] [if1632/user.spec] FindWindowEx() implemented (someone reported it was missing for FrameMaker 4.1). * [if1632/kernel32.spec] [if1632/user32.spec] [win32/memory.c] [win32/resource.c] Misc small stubs/small functions which bring win95 binaries further down the road. (IsBadCodePtr, LocalReAlloc,GetCursorPos) Small fix in WIN32_LoadAcceleratorsA. Fri May 3 19:43:12 1996 Frans van Dorsselaer <dorssel@rulhm1.LeidenUniv.nl> * [controls/edit.c] [controls/EDIT.TODO] Changed / fixed some types and typecasts. Fixed the scrollbar reset after WM_SETHANDLE / WM_SETTEXT. Added heap initialization in WM_CREATE. Fri May 3 19:30:02 1996 Greg Kreider <kreider@natlab.research.philips.com> * [controls/combo.c] [controls/listbox.c] Pass WM_[HV]SCROLL to listbox, but not combo. Don't try to redraw non-existant scroll bars (changes dwStyle flags). Combo box gets border. Combo box includes button (otherwise button won't trigger dropdown). Proper border around RectButton. Check size consistancy of combo, listbox, and button after resizing or before painting. These routines still aren't completely correct. Localize size checks in separate routines. Listboxes are white. Thu May 2 19:21:23 1996 Albrecht Kleine <kleine@ak.sax.de> * [controls/combo.c][include/commdlg.h][include/commdlg.c] [resources/sysres_De.rc][resources/sysres_En.rc] Introduced ChooseFont dialog, but needed some patches in handling of comboboxes with edit controls. Tue Apr 30 00:33:27 1996 Ulrich Schmid <uschmid@mail.hh.provi.de> * [programs/winhelp/*] Added a help viewer and a simple `.hlp' to `.sgml' converter. Mon Apr 29 14:17:57 1996 Tristan Tarrant <tst@sthinc.demon.co.uk> * [resources/sysres_*.rc] [misc/shell.c] Modified size of "About" dialog boxes. Sat Apr 27 18:10:11 Martin von Loewis <loewis@informatik.hu-berlin.de> * [if1632/Makefile.in][loader/builtin.c] crtdll.spec, ntdll.spec, wsock32.spec: new files. * [loader/pe_image.c] Fix error message if import by ordinal failed.
1996-05-06 16:06:24 +00:00
/*
* Help Viewer
*
* Copyright 1996 Ulrich Schmid
*/
#include <stdio.h>
#include <windows.h>
#include "winhelp.h"
static void Report(LPCSTR str)
{
#if 0
fprintf(stderr, "%s\n", str);
#endif
}
#define GET_USHORT(buffer, i)\
(((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
#define GET_SHORT(buffer, i)\
(((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
#define GET_UINT(buffer, i)\
GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i+2)
static BOOL HLPFILE_DoReadHlpFile(HLPFILE*, LPCSTR);
static BOOL HLPFILE_ReadFileToBuffer(HFILE);
static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE**, BYTE**);
static VOID HLPFILE_SystemCommands(HLPFILE*);
static BOOL HLPFILE_Uncompress1_Phrases();
static BOOL HLPFILE_Uncompress1_Topic();
static BOOL HLPFILE_GetContext(HLPFILE*);
static BOOL HLPFILE_AddPage(HLPFILE*, BYTE*, BYTE*);
static BOOL HLPFILE_AddParagraph(HLPFILE*, BYTE *, BYTE*);
static UINT HLPFILE_Uncompressed2_Size(BYTE*, BYTE*);
static VOID HLPFILE_Uncompress2(BYTE**, BYTE*, BYTE*);
static HLPFILE *first_hlpfile = 0;
static HGLOBAL hFileBuffer;
static BYTE *file_buffer;
static struct
{
UINT num;
BYTE *buf;
HGLOBAL hBuffer;
} phrases;
static struct
{
BYTE **map;
BYTE *end;
UINT wMapLen;
HGLOBAL hMap;
HGLOBAL hBuffer;
} topic;
static struct
{
UINT bDebug;
UINT wFont;
UINT wIndent;
UINT wHSpace;
UINT wVSpace;
UINT wVBackSpace;
HLPFILE_LINK link;
} attributes;
/***********************************************************************
*
* HLPFILE_Contents
*/
HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath)
{
HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
if (!hlpfile) return(0);
return(hlpfile->first_page);
}
/***********************************************************************
*
* HLPFILE_PageByNumber
*/
HLPFILE_PAGE *HLPFILE_PageByNumber(LPCSTR lpszPath, UINT wNum)
{
HLPFILE_PAGE *page;
HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
if (!hlpfile) return(0);
for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
return page;
}
/***********************************************************************
*
* HLPFILE_HlpFilePageByHash
*/
HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG lHash)
{
INT i;
UINT wNum;
HLPFILE_PAGE *page;
HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
if (!hlpfile) return(0);
for (i = 0; i < hlpfile->wContextLen; i++)
if (hlpfile->Context[i].lHash == lHash) break;
if (i >= hlpfile->wContextLen)
{
HLPFILE_FreeHlpFile(hlpfile);
return(0);
}
wNum = hlpfile->Context[i].wPage;
for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
return page;
}
/***********************************************************************
*
* HLPFILE_Hash
*/
LONG HLPFILE_Hash(LPCSTR lpszContext)
{
LONG lHash = 0;
CHAR c;
while((c = *lpszContext++))
{
CHAR x = 0;
if (c >= 'A' && c <= 'Z') x = c - 'A' + 17;
if (c >= 'a' && c <= 'z') x = c - 'a' + 17;
if (c >= '1' && c <= '9') x = c - '0';
if (c == '0') x = 10;
if (c == '.') x = 12;
if (c == '_') x = 13;
if (x) lHash = lHash * 43 + x;
}
return lHash;
}
/***********************************************************************
*
* HLPFILE_ReadHlpFile
*/
HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
{
HGLOBAL hHlpFile;
HLPFILE *hlpfile;
for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
if (!lstrcmp(hlpfile->lpszPath, lpszPath))
{
hlpfile->wRefCount++;
return(hlpfile);
}
hHlpFile = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
if (!hHlpFile) return(0);
hlpfile = GlobalLock(hHlpFile);
hlpfile->hSelf = hHlpFile;
hlpfile->wRefCount = 1;
hlpfile->hTitle = 0;
hlpfile->hContext = 0;
hlpfile->wContextLen = 0;
hlpfile->first_page = 0;
hlpfile->first_macro = 0;
hlpfile->prev = 0;
hlpfile->next = first_hlpfile;
first_hlpfile = hlpfile;
if (hlpfile->next) hlpfile->next->prev = hlpfile;
hlpfile->lpszPath = GlobalLock(hHlpFile);
hlpfile->lpszPath += sizeof(HLPFILE);
lstrcpy(hlpfile->lpszPath, (SEGPTR) lpszPath);
phrases.hBuffer = topic.hBuffer = hFileBuffer = 0;
if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
{
HLPFILE_FreeHlpFile(hlpfile);
hlpfile = 0;
}
if (phrases.hBuffer) GlobalFree(phrases.hBuffer);
if (topic.hBuffer) GlobalFree(topic.hBuffer);
if (topic.hMap) GlobalFree(topic.hMap);
if (hFileBuffer) GlobalFree(hFileBuffer);
return(hlpfile);
}
/***********************************************************************
*
* HLPFILE_DoReadHlpFile
*/
static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
{
BOOL ret;
HFILE hFile;
OFSTRUCT ofs;
BYTE *buf;
hFile=OpenFile(lpszPath, &ofs, OF_READ | OF_SEARCH);
if (hFile == HFILE_ERROR) return FALSE;
ret = HLPFILE_ReadFileToBuffer(hFile);
_lclose(hFile);
if (!ret) return FALSE;
HLPFILE_SystemCommands(hlpfile);
if (!HLPFILE_Uncompress1_Phrases()) return FALSE;
if (!HLPFILE_Uncompress1_Topic()) return FALSE;
buf = topic.map[0] + 0xc;
while(buf + 0xc < topic.end)
{
BYTE *end = MIN(buf + GET_UINT(buf, 0), topic.end);
UINT next, index, offset;
switch (buf[0x14])
{
case 0x02:
if (!HLPFILE_AddPage(hlpfile, buf, end)) return(FALSE);
break;
case 0x20:
if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
break;
case 0x23:
if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
break;
default:
fprintf(stderr, "buf[0x14] = %x\n", buf[0x14]);
}
next = GET_UINT(buf, 0xc);
if (next == 0xffffffff) break;
index = next >> 14;
offset = next & 0x3fff;
if (index > topic.wMapLen) {Report("maplen"); break;}
buf = topic.map[index] + offset;
}
return(HLPFILE_GetContext(hlpfile));
}
/***********************************************************************
*
* HLPFILE_AddPage
*/
static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
{
HGLOBAL hPage;
HLPFILE_PAGE *page, **pageptr;
BYTE *title;
UINT titlesize;
for (pageptr = &hlpfile->first_page; *pageptr; pageptr = &(*pageptr)->next)
/* Nothing */;
if (buf + 0x31 > end) {Report("page1"); return(FALSE);};
title = buf + GET_UINT(buf, 0x10);
if (title > end) {Report("page2"); return(FALSE);};
titlesize = HLPFILE_Uncompressed2_Size(title, end);
hPage = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PAGE) + titlesize);
if (!hPage) return FALSE;
page = *pageptr = GlobalLock(hPage);
pageptr = &page->next;
page->hSelf = hPage;
page->file = hlpfile;
page->next = 0;
page->first_paragraph = 0;
page->lpszTitle = GlobalLock(hPage);
page->lpszTitle += sizeof(HLPFILE_PAGE);
HLPFILE_Uncompress2(&title, end, page->lpszTitle);
page->wNumber = GET_UINT(buf, 0x21);
attributes.bDebug = 0;
attributes.wFont = 0;
attributes.wVSpace = 0;
attributes.wVBackSpace = 0;
attributes.wHSpace = 0;
attributes.wIndent = 0;
attributes.link.lpszPath = 0;
return TRUE;
}
/***********************************************************************
*
* HLPFILE_AddParagraph
*/
static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
{
HGLOBAL hParagraph;
HLPFILE_PAGE *page;
HLPFILE_PARAGRAPH *paragraph, **paragraphptr;
UINT textsize;
BYTE *format, *text;
BOOL format_header = TRUE;
BOOL format_end = FALSE;
UINT mask, i;
if (!hlpfile->first_page) {Report("paragraph1"); return(FALSE);};
for (page = hlpfile->first_page; page->next; page = page->next) /* Nothing */;
for (paragraphptr = &page->first_paragraph; *paragraphptr;
paragraphptr = &(*paragraphptr)->next) /* Nothing */;
if (buf + 0x19 > end) {Report("paragraph2"); return(FALSE);};
if (buf[0x14] == 0x02) return TRUE;
text = buf + GET_UINT(buf, 0x10);
switch (buf[0x14])
{
case 0x20:
format = buf + 0x18;
while (*format) format++;
format += 4;
break;
case 0x23:
format = buf + 0x2b;
if (buf[0x17] & 1) format++;
break;
default:
Report("paragraph3");
return FALSE;
}
while (text < end)
{
if (format_header)
{
format_header = FALSE;
mask = GET_USHORT(format, 0);
mask &= 0x3ff;
format += 2;
for (i = 0; i < 10; i++, mask = mask >> 1)
{
if (mask & 1)
{
BOOL twoargs = FALSE;
CHAR prefix0 = ' ';
CHAR prefix1 = '*';
if (i == 9 && !twoargs)
{
switch (*format++)
{
default:
prefix0 = prefix1 = '?';
break;
case 0x82:
prefix0 = prefix1 = 'x';
break;
case 0x84:
prefix0 = prefix1 = 'X';
twoargs = TRUE;
}
}
if (*format & 1)
switch(*format)
{
default:
format += 2;
break;
}
else
switch(*format)
{
default:
format++;
break;
case 0x08:
format += 3;
break;
}
if (twoargs) format += (*format & 1) ? 2 : 1;
}
}
}
for (; !format_header && text < end && format < end && !*text; text++)
{
switch(*format)
{
case 0x80:
attributes.wFont = GET_USHORT(format, 1);
format += 3;
break;
case 0x81:
attributes.wVSpace++;
format += 1;
break;
case 0x82:
attributes.wVSpace += 2 - attributes.wVBackSpace;
attributes.wVBackSpace = 0;
attributes.wIndent = 0;
format += 1;
break;
case 0x83:
attributes.wIndent++;
format += 1;
break;
case 0x84:
format += 3;
break;
case 0x86:
case 0x87:
case 0x88:
format += 9;
break;
case 0x89:
attributes.wVBackSpace++;
format += 1;
break;
case 0xa9:
format += 2;
break;
case 0xe2:
case 0xe3:
attributes.link.lpszPath = hlpfile->lpszPath;
attributes.link.lHash = GET_UINT(format, 1);
attributes.link.bPopup = !(*format & 1);
format += 5;
break;
case 0xea:
attributes.link.lpszPath = format + 8;
attributes.link.lHash = GET_UINT(format, 4);
attributes.link.bPopup = !(*format & 1);
format += 3 + GET_USHORT(format, 1);
break;
case 0xff:
if (buf[0x14] != 0x23 || GET_USHORT(format, 1) == 0xffff)
{
if (format_end) Report("format_end");
format_end = TRUE;
break;
}
else
{
format_header = TRUE;
format += 10;
break;
}
default:
Report("format");
format++;
}
}
if (text > end || format > end) {Report("paragraph_end"); return(FALSE);};
if (text == end && !format_end) Report("text_end");
if (text == end) break;
textsize = HLPFILE_Uncompressed2_Size(text, end);
hParagraph = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PARAGRAPH) + textsize);
if (!hParagraph) return FALSE;
paragraph = *paragraphptr = GlobalLock(hParagraph);
paragraphptr = &paragraph->next;
paragraph->hSelf = hParagraph;
paragraph->next = 0;
paragraph->link = 0;
paragraph->lpszText = GlobalLock(hParagraph);
paragraph->lpszText += sizeof(HLPFILE_PARAGRAPH);
HLPFILE_Uncompress2(&text, end, paragraph->lpszText);
paragraph->bDebug = attributes.bDebug;
paragraph->wFont = attributes.wFont;
paragraph->wVSpace = attributes.wVSpace;
paragraph->wHSpace = attributes.wHSpace;
paragraph->wIndent = attributes.wIndent;
if (attributes.link.lpszPath)
{
LPSTR ptr;
HGLOBAL handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_LINK) +
strlen(attributes.link.lpszPath) + 1);
if (!handle) return FALSE;
paragraph->link = GlobalLock(handle);
paragraph->link->hSelf = handle;
ptr = GlobalLock(handle);
ptr += sizeof(HLPFILE_LINK);
lstrcpy(ptr, (LPSTR) attributes.link.lpszPath);
paragraph->link->lpszPath = ptr;
paragraph->link->lHash = attributes.link.lHash;
paragraph->link->bPopup = attributes.link.bPopup;
}
attributes.bDebug = 0;
attributes.wVSpace = 0;
attributes.wHSpace = 0;
attributes.link.lpszPath = 0;
}
return TRUE;
}
/***********************************************************************
*
* HLPFILE_ReadFileToBuffer
*/
static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
{
BYTE header[16], dummy[1];
UINT size;
if (_hread(hFile, header, 16) != 16) {Report("header"); return(FALSE);};
size = GET_UINT(header, 12);
hFileBuffer = GlobalAlloc(GMEM_FIXED, size + 1);
if (!hFileBuffer) return FALSE;
file_buffer = GlobalLock(hFileBuffer);
memcpy(file_buffer, header, 16);
if (_hread(hFile, file_buffer + 16, size - 16) != size - 16)
{Report("filesize1"); return(FALSE);};
if (_hread(hFile, dummy, 1) != 0) Report("filesize2");
file_buffer[size] = '0';
return TRUE;
}
/***********************************************************************
*
* 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 = root + 0x37;
while (ptr < end && ptr[0] == 0x7c)
{
BYTE *fname = ptr + 1;
ptr += strlen(ptr) + 1;
if (!lstrcmpi(fname, name))
{
*subbuf = file_buffer + GET_UINT(ptr, 0);
*subend = *subbuf + GET_UINT(*subbuf, 0);
if (file_buffer > *subbuf || *subbuf > *subend || *subend >= end)
{
Report("subfile");
return FALSE;
}
return TRUE;
}
else ptr += 4;
}
return FALSE;
}
/***********************************************************************
*
* HLPFILE_SystemCommands
*/
static VOID HLPFILE_SystemCommands(HLPFILE* hlpfile)
{
BYTE *buf, *ptr, *end;
HGLOBAL handle;
HLPFILE_MACRO *macro, **m;
LPSTR p;
hlpfile->lpszTitle = "";
if (!HLPFILE_FindSubFile("SYSTEM", &buf, &end)) return;
for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4)
{
switch (GET_USHORT(ptr, 0))
{
case 1:
if (hlpfile->hTitle) {Report("title"); break;}
hlpfile->hTitle = GlobalAlloc(GMEM_FIXED, strlen(ptr + 4) + 1);
if (!hlpfile->hTitle) return;
hlpfile->lpszTitle = GlobalLock(hlpfile->hTitle);
lstrcpy(hlpfile->lpszTitle, ptr + 4);
break;
case 2:
if (GET_USHORT(ptr, 2) != 1 || ptr[4] != 0) Report("system2");
break;
case 3:
if (GET_USHORT(ptr, 2) != 4 || GET_UINT(ptr, 4) != 0) Report("system3");
break;
case 4:
handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_MACRO) + lstrlen(ptr + 4) + 1);
if (!handle) break;
macro = GlobalLock(handle);
macro->hSelf = handle;
p = GlobalLock(handle);
p += sizeof(HLPFILE_MACRO);
lstrcpy(p, (LPSTR) ptr + 4);
macro->lpszMacro = p;
macro->next = 0;
for (m = &hlpfile->first_macro; *m; m = &(*m)->next);
*m = macro;
break;
default:
Report("system");
}
}
}
/***********************************************************************
*
* HLPFILE_Uncompressed1_Size
*/
static INT HLPFILE_Uncompressed1_Size(BYTE *ptr, BYTE *end)
{
INT i, newsize = 0;
while (ptr < end)
{
INT mask=*ptr++;
for (i = 0; i < 8 && ptr < end; i++, mask = 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_Uncompress1
*/
static BYTE *HLPFILE_Uncompress1(BYTE *ptr, BYTE *end, BYTE *newptr)
{
INT i;
while (ptr < end)
{
INT mask=*ptr++;
for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
{
if (mask & 1)
{
INT code = GET_USHORT(ptr, 0);
INT len = 3 + (code >> 12);
INT offset = code & 0xfff;
hmemcpy(newptr, newptr - offset - 1, len);
newptr += len;
ptr += 2;
}
else *newptr++ = *ptr++;
}
}
return(newptr);
}
/***********************************************************************
*
* HLPFILE_Uncompress1_Phrases
*/
static BOOL HLPFILE_Uncompress1_Phrases()
{
UINT i, num, newsize;
BYTE *buf, *end, *newbuf;
if (!HLPFILE_FindSubFile("Phrases", &buf, &end)) {Report("phrases0"); return FALSE;}
num = phrases.num = GET_USHORT(buf, 9);
if (buf + 2 * num + 0x13 >= end) {Report("uncompress1a"); return(FALSE);};
newsize = 2 * num + 2;
newsize += HLPFILE_Uncompressed1_Size(buf + 0x13 + 2 * num, end);
phrases.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
if (!phrases.hBuffer) return FALSE;
newbuf = phrases.buf = GlobalLock(phrases.hBuffer);
hmemcpy(newbuf, buf + 0x11, 2 * num + 2);
HLPFILE_Uncompress1(buf + 0x13 + 2 * num, end, newbuf + 2 * num + 2);
for (i = 0; i < num; i++)
{
INT i0 = GET_USHORT(newbuf, 2 * i);
INT i1 = GET_USHORT(newbuf, 2 * i + 2);
if (i1 < i0 || i1 > newsize) {Report("uncompress1b"); return(FALSE);};
}
return TRUE;
}
/***********************************************************************
*
* HLPFILE_Uncompress1_Topic
*/
static BOOL HLPFILE_Uncompress1_Topic()
{
BYTE *buf, *ptr, *end, *newptr;
INT i, newsize = 0;
if (!HLPFILE_FindSubFile("TOPIC", &buf, &end)) {Report("topic0"); return FALSE;}
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_Uncompressed1_Size(ptr + 0xc, MIN(end, ptr + 0x1000));
}
topic.hMap = GlobalAlloc(GMEM_FIXED, topic.wMapLen * sizeof(topic.map[0]));
topic.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
if (!topic.hMap || !topic.hBuffer) return FALSE;
topic.map = GlobalLock(topic.hMap);
newptr = GlobalLock(topic.hBuffer);
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 - 0xc;
newptr = HLPFILE_Uncompress1(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 && *ptr)
{
if (*ptr >= 0x20)
wSize++, ptr++;
else
{
BYTE *phptr, *phend;
UINT code = 0x100 * ptr[0] + ptr[1];
UINT index = (code - 0x100) / 2;
BOOL space = code & 1;
if (index < phrases.num)
{
phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
if (phend < phptr) Report("uncompress2a");
wSize += phend - phptr;
if (space) wSize++;
}
else Report("uncompress2b");
ptr += 2;
}
}
return(wSize + 1);
}
/***********************************************************************
*
* HLPFILE_Uncompress2
*/
static VOID HLPFILE_Uncompress2(BYTE **pptr, BYTE *end, BYTE *newptr)
{
BYTE *ptr = *pptr;
while (ptr < end && *ptr)
{
if (*ptr >= 0x20)
*newptr++ = *ptr++;
else
{
BYTE *phptr, *phend;
UINT code = 0x100 * ptr[0] + ptr[1];
UINT index = (code - 0x100) / 2;
BOOL space = code & 1;
phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
hmemcpy(newptr, phptr, phend - phptr);
newptr += phend - phptr;
if (space) *newptr++ = ' ';
ptr += 2;
}
}
*newptr = '\0';
*pptr = ptr;
}
/***********************************************************************
*
* HLPFILE_GetContext
*/
static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
{
UINT i, j, clen, tlen;
BYTE *cbuf, *cptr, *cend, *tbuf, *tptr, *tend;
if (!HLPFILE_FindSubFile("CONTEXT", &cbuf, &cend)) {Report("context0"); return FALSE;}
if (cbuf + 0x37 > cend) {Report("context1"); return(FALSE);};
clen = GET_UINT(cbuf, 0x2b);
if (cbuf + 0x37 + 8 * hlpfile->wContextLen > cend) {Report("context2"); return(FALSE);};
if (!HLPFILE_FindSubFile("TTLBTREE", &tbuf, &tend)) {Report("ttlb0"); return FALSE;}
if (tbuf + 0x37 > tend) {Report("ttlb1"); return(FALSE);};
tlen = GET_UINT(tbuf, 0x2b);
hlpfile->hContext = GlobalAlloc(GMEM_FIXED, clen * sizeof(HLPFILE_CONTEXT));
if (!hlpfile->hContext) return FALSE;
hlpfile->Context = GlobalLock(hlpfile->hContext);
hlpfile->wContextLen = clen;
cptr = cbuf + 0x37;
for (i = 0; i < clen; i++, cptr += 8)
{
tptr = tbuf + 0x37;
for (j = 0; j < tlen; j++, tptr += 5 + strlen(tptr + 4))
{
if (tptr + 4 >= tend) {Report("ttlb2"); return(FALSE);};
if (GET_UINT(tptr, 0) == GET_UINT(cptr, 4)) break;
}
if (j >= tlen)
{
Report("ttlb3");
j = 0;
}
hlpfile->Context[i].lHash = GET_UINT(cptr, 0);
hlpfile->Context[i].wPage = j;
}
return TRUE;
}
/***********************************************************************
*
* HLPFILE_DeleteParagraph
*/
static VOID HLPFILE_DeleteParagraph(HLPFILE_PARAGRAPH* paragraph)
{
if (!paragraph) return;
if (paragraph->link) GlobalFree(paragraph->link->hSelf);
HLPFILE_DeleteParagraph(paragraph->next);
GlobalFree(paragraph->hSelf);
}
/***********************************************************************
*
* DeletePage
*/
static VOID HLPFILE_DeletePage(HLPFILE_PAGE* page)
{
if (!page) return;
HLPFILE_DeletePage(page->next);
HLPFILE_DeleteParagraph(page->first_paragraph);
GlobalFree(page->hSelf);
}
/***********************************************************************
*
* DeleteMacro
*/
static VOID HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
{
if (!macro) return;
HLPFILE_DeleteMacro(macro->next);
GlobalFree(macro->hSelf);
}
/***********************************************************************
*
* HLPFILE_FreeHlpFile
*/
VOID HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
{
if (!hlpfile) return;
if (--hlpfile->wRefCount) return;
if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
else first_hlpfile = 0;
HLPFILE_DeletePage(hlpfile->first_page);
HLPFILE_DeleteMacro(hlpfile->first_macro);
GlobalFree(hlpfile->hContext);
GlobalFree(hlpfile->hTitle);
GlobalFree(hlpfile->hSelf);
}
/***********************************************************************
*
* FreeHlpFilePage
*/
VOID HLPFILE_FreeHlpFilePage(HLPFILE_PAGE* page)
{
if (!page) return;
HLPFILE_FreeHlpFile(page->file);
}
/* Local Variables: */
/* c-file-style: "GNU" */
/* End: */