Sweden-Number/programs/winhelp/hlpfile.c

1007 lines
24 KiB
C

/*
* Help Viewer
*
* Copyright 1996 Ulrich Schmid
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <string.h>
#include "windows.h"
#include "windowsx.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);
strcpy(hlpfile->lpszPath, 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;
m = &hlpfile->first_macro;
while (*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;
memcpy(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);
memcpy(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);
memcpy(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);
if (hlpfile->hContext) GlobalFree(hlpfile->hContext);
if (hlpfile->hTitle) 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: */