Release 960717
[wine/multimedia.git] / programs / winhelp / hlpfile.c
blob2a6c36a58b7b115dee9e94ae92473470cbd5b85c
1 /*
2 * Help Viewer
4 * Copyright 1996 Ulrich Schmid
5 */
7 #include <stdio.h>
8 #include <windows.h>
9 #include "winhelp.h"
11 static void Report(LPCSTR str)
13 #if 0
14 fprintf(stderr, "%s\n", str);
15 #endif
18 #define GET_USHORT(buffer, i)\
19 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
20 #define GET_SHORT(buffer, i)\
21 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
22 #define GET_UINT(buffer, i)\
23 GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i+2)
25 static BOOL HLPFILE_DoReadHlpFile(HLPFILE*, LPCSTR);
26 static BOOL HLPFILE_ReadFileToBuffer(HFILE);
27 static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE**, BYTE**);
28 static VOID HLPFILE_SystemCommands(HLPFILE*);
29 static BOOL HLPFILE_Uncompress1_Phrases();
30 static BOOL HLPFILE_Uncompress1_Topic();
31 static BOOL HLPFILE_GetContext(HLPFILE*);
32 static BOOL HLPFILE_AddPage(HLPFILE*, BYTE*, BYTE*);
33 static BOOL HLPFILE_AddParagraph(HLPFILE*, BYTE *, BYTE*);
34 static UINT HLPFILE_Uncompressed2_Size(BYTE*, BYTE*);
35 static VOID HLPFILE_Uncompress2(BYTE**, BYTE*, BYTE*);
37 static HLPFILE *first_hlpfile = 0;
38 static HGLOBAL hFileBuffer;
39 static BYTE *file_buffer;
41 static struct
43 UINT num;
44 BYTE *buf;
45 HGLOBAL hBuffer;
46 } phrases;
48 static struct
50 BYTE **map;
51 BYTE *end;
52 UINT wMapLen;
53 HGLOBAL hMap;
54 HGLOBAL hBuffer;
55 } topic;
57 static struct
59 UINT bDebug;
60 UINT wFont;
61 UINT wIndent;
62 UINT wHSpace;
63 UINT wVSpace;
64 UINT wVBackSpace;
65 HLPFILE_LINK link;
66 } attributes;
68 /***********************************************************************
70 * HLPFILE_Contents
73 HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath)
75 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
77 if (!hlpfile) return(0);
79 return(hlpfile->first_page);
82 /***********************************************************************
84 * HLPFILE_PageByNumber
87 HLPFILE_PAGE *HLPFILE_PageByNumber(LPCSTR lpszPath, UINT wNum)
89 HLPFILE_PAGE *page;
90 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
92 if (!hlpfile) return(0);
94 for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
96 return page;
99 /***********************************************************************
101 * HLPFILE_HlpFilePageByHash
104 HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG lHash)
106 INT i;
107 UINT wNum;
108 HLPFILE_PAGE *page;
109 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
111 if (!hlpfile) return(0);
113 for (i = 0; i < hlpfile->wContextLen; i++)
114 if (hlpfile->Context[i].lHash == lHash) break;
116 if (i >= hlpfile->wContextLen)
118 HLPFILE_FreeHlpFile(hlpfile);
119 return(0);
122 wNum = hlpfile->Context[i].wPage;
123 for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
125 return page;
128 /***********************************************************************
130 * HLPFILE_Hash
133 LONG HLPFILE_Hash(LPCSTR lpszContext)
135 LONG lHash = 0;
136 CHAR c;
137 while((c = *lpszContext++))
139 CHAR x = 0;
140 if (c >= 'A' && c <= 'Z') x = c - 'A' + 17;
141 if (c >= 'a' && c <= 'z') x = c - 'a' + 17;
142 if (c >= '1' && c <= '9') x = c - '0';
143 if (c == '0') x = 10;
144 if (c == '.') x = 12;
145 if (c == '_') x = 13;
146 if (x) lHash = lHash * 43 + x;
148 return lHash;
151 /***********************************************************************
153 * HLPFILE_ReadHlpFile
156 HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
158 HGLOBAL hHlpFile;
159 HLPFILE *hlpfile;
161 for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
162 if (!lstrcmp(hlpfile->lpszPath, lpszPath))
164 hlpfile->wRefCount++;
165 return(hlpfile);
168 hHlpFile = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
169 if (!hHlpFile) return(0);
171 hlpfile = GlobalLock(hHlpFile);
172 hlpfile->hSelf = hHlpFile;
173 hlpfile->wRefCount = 1;
174 hlpfile->hTitle = 0;
175 hlpfile->hContext = 0;
176 hlpfile->wContextLen = 0;
177 hlpfile->first_page = 0;
178 hlpfile->first_macro = 0;
179 hlpfile->prev = 0;
180 hlpfile->next = first_hlpfile;
181 first_hlpfile = hlpfile;
182 if (hlpfile->next) hlpfile->next->prev = hlpfile;
184 hlpfile->lpszPath = GlobalLock(hHlpFile);
185 hlpfile->lpszPath += sizeof(HLPFILE);
186 strcpy(hlpfile->lpszPath, lpszPath);
188 phrases.hBuffer = topic.hBuffer = hFileBuffer = 0;
190 if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
192 HLPFILE_FreeHlpFile(hlpfile);
193 hlpfile = 0;
196 if (phrases.hBuffer) GlobalFree(phrases.hBuffer);
197 if (topic.hBuffer) GlobalFree(topic.hBuffer);
198 if (topic.hMap) GlobalFree(topic.hMap);
199 if (hFileBuffer) GlobalFree(hFileBuffer);
201 return(hlpfile);
204 /***********************************************************************
206 * HLPFILE_DoReadHlpFile
209 static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
211 BOOL ret;
212 HFILE hFile;
213 OFSTRUCT ofs;
214 BYTE *buf;
216 hFile=OpenFile(lpszPath, &ofs, OF_READ | OF_SEARCH);
217 if (hFile == HFILE_ERROR) return FALSE;
219 ret = HLPFILE_ReadFileToBuffer(hFile);
220 _lclose(hFile);
221 if (!ret) return FALSE;
223 HLPFILE_SystemCommands(hlpfile);
224 if (!HLPFILE_Uncompress1_Phrases()) return FALSE;
225 if (!HLPFILE_Uncompress1_Topic()) return FALSE;
227 buf = topic.map[0] + 0xc;
228 while(buf + 0xc < topic.end)
230 BYTE *end = MIN(buf + GET_UINT(buf, 0), topic.end);
231 UINT next, index, offset;
233 switch (buf[0x14])
235 case 0x02:
236 if (!HLPFILE_AddPage(hlpfile, buf, end)) return(FALSE);
237 break;
239 case 0x20:
240 if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
241 break;
243 case 0x23:
244 if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
245 break;
247 default:
248 fprintf(stderr, "buf[0x14] = %x\n", buf[0x14]);
251 next = GET_UINT(buf, 0xc);
252 if (next == 0xffffffff) break;
254 index = next >> 14;
255 offset = next & 0x3fff;
256 if (index > topic.wMapLen) {Report("maplen"); break;}
257 buf = topic.map[index] + offset;
260 return(HLPFILE_GetContext(hlpfile));
263 /***********************************************************************
265 * HLPFILE_AddPage
268 static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
270 HGLOBAL hPage;
271 HLPFILE_PAGE *page, **pageptr;
272 BYTE *title;
273 UINT titlesize;
275 for (pageptr = &hlpfile->first_page; *pageptr; pageptr = &(*pageptr)->next)
276 /* Nothing */;
278 if (buf + 0x31 > end) {Report("page1"); return(FALSE);};
279 title = buf + GET_UINT(buf, 0x10);
280 if (title > end) {Report("page2"); return(FALSE);};
282 titlesize = HLPFILE_Uncompressed2_Size(title, end);
283 hPage = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PAGE) + titlesize);
284 if (!hPage) return FALSE;
285 page = *pageptr = GlobalLock(hPage);
286 pageptr = &page->next;
287 page->hSelf = hPage;
288 page->file = hlpfile;
289 page->next = 0;
290 page->first_paragraph = 0;
292 page->lpszTitle = GlobalLock(hPage);
293 page->lpszTitle += sizeof(HLPFILE_PAGE);
294 HLPFILE_Uncompress2(&title, end, page->lpszTitle);
296 page->wNumber = GET_UINT(buf, 0x21);
298 attributes.bDebug = 0;
299 attributes.wFont = 0;
300 attributes.wVSpace = 0;
301 attributes.wVBackSpace = 0;
302 attributes.wHSpace = 0;
303 attributes.wIndent = 0;
304 attributes.link.lpszPath = 0;
306 return TRUE;
309 /***********************************************************************
311 * HLPFILE_AddParagraph
314 static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
316 HGLOBAL hParagraph;
317 HLPFILE_PAGE *page;
318 HLPFILE_PARAGRAPH *paragraph, **paragraphptr;
319 UINT textsize;
320 BYTE *format, *text;
321 BOOL format_header = TRUE;
322 BOOL format_end = FALSE;
323 UINT mask, i;
325 if (!hlpfile->first_page) {Report("paragraph1"); return(FALSE);};
327 for (page = hlpfile->first_page; page->next; page = page->next) /* Nothing */;
328 for (paragraphptr = &page->first_paragraph; *paragraphptr;
329 paragraphptr = &(*paragraphptr)->next) /* Nothing */;
331 if (buf + 0x19 > end) {Report("paragraph2"); return(FALSE);};
333 if (buf[0x14] == 0x02) return TRUE;
335 text = buf + GET_UINT(buf, 0x10);
337 switch (buf[0x14])
339 case 0x20:
340 format = buf + 0x18;
341 while (*format) format++;
342 format += 4;
343 break;
345 case 0x23:
346 format = buf + 0x2b;
347 if (buf[0x17] & 1) format++;
348 break;
350 default:
351 Report("paragraph3");
352 return FALSE;
355 while (text < end)
357 if (format_header)
359 format_header = FALSE;
361 mask = GET_USHORT(format, 0);
362 mask &= 0x3ff;
363 format += 2;
365 for (i = 0; i < 10; i++, mask = mask >> 1)
367 if (mask & 1)
369 BOOL twoargs = FALSE;
370 CHAR prefix0 = ' ';
371 CHAR prefix1 = '*';
373 if (i == 9 && !twoargs)
375 switch (*format++)
377 default:
378 prefix0 = prefix1 = '?';
379 break;
381 case 0x82:
382 prefix0 = prefix1 = 'x';
383 break;
385 case 0x84:
386 prefix0 = prefix1 = 'X';
387 twoargs = TRUE;
391 if (*format & 1)
392 switch(*format)
394 default:
395 format += 2;
396 break;
398 else
399 switch(*format)
402 default:
403 format++;
404 break;
406 case 0x08:
407 format += 3;
408 break;
411 if (twoargs) format += (*format & 1) ? 2 : 1;
416 for (; !format_header && text < end && format < end && !*text; text++)
418 switch(*format)
420 case 0x80:
421 attributes.wFont = GET_USHORT(format, 1);
422 format += 3;
423 break;
425 case 0x81:
426 attributes.wVSpace++;
427 format += 1;
428 break;
430 case 0x82:
431 attributes.wVSpace += 2 - attributes.wVBackSpace;
432 attributes.wVBackSpace = 0;
433 attributes.wIndent = 0;
434 format += 1;
435 break;
437 case 0x83:
438 attributes.wIndent++;
439 format += 1;
440 break;
442 case 0x84:
443 format += 3;
444 break;
446 case 0x86:
447 case 0x87:
448 case 0x88:
449 format += 9;
450 break;
452 case 0x89:
453 attributes.wVBackSpace++;
454 format += 1;
455 break;
457 case 0xa9:
458 format += 2;
459 break;
461 case 0xe2:
462 case 0xe3:
463 attributes.link.lpszPath = hlpfile->lpszPath;
464 attributes.link.lHash = GET_UINT(format, 1);
465 attributes.link.bPopup = !(*format & 1);
466 format += 5;
467 break;
469 case 0xea:
470 attributes.link.lpszPath = format + 8;
471 attributes.link.lHash = GET_UINT(format, 4);
472 attributes.link.bPopup = !(*format & 1);
473 format += 3 + GET_USHORT(format, 1);
474 break;
476 case 0xff:
477 if (buf[0x14] != 0x23 || GET_USHORT(format, 1) == 0xffff)
479 if (format_end) Report("format_end");
480 format_end = TRUE;
481 break;
483 else
485 format_header = TRUE;
486 format += 10;
487 break;
490 default:
491 Report("format");
492 format++;
496 if (text > end || format > end) {Report("paragraph_end"); return(FALSE);};
497 if (text == end && !format_end) Report("text_end");
499 if (text == end) break;
501 textsize = HLPFILE_Uncompressed2_Size(text, end);
502 hParagraph = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PARAGRAPH) + textsize);
503 if (!hParagraph) return FALSE;
504 paragraph = *paragraphptr = GlobalLock(hParagraph);
505 paragraphptr = &paragraph->next;
506 paragraph->hSelf = hParagraph;
507 paragraph->next = 0;
508 paragraph->link = 0;
510 paragraph->lpszText = GlobalLock(hParagraph);
511 paragraph->lpszText += sizeof(HLPFILE_PARAGRAPH);
512 HLPFILE_Uncompress2(&text, end, paragraph->lpszText);
514 paragraph->bDebug = attributes.bDebug;
515 paragraph->wFont = attributes.wFont;
516 paragraph->wVSpace = attributes.wVSpace;
517 paragraph->wHSpace = attributes.wHSpace;
518 paragraph->wIndent = attributes.wIndent;
519 if (attributes.link.lpszPath)
521 LPSTR ptr;
522 HGLOBAL handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_LINK) +
523 strlen(attributes.link.lpszPath) + 1);
524 if (!handle) return FALSE;
525 paragraph->link = GlobalLock(handle);
526 paragraph->link->hSelf = handle;
528 ptr = GlobalLock(handle);
529 ptr += sizeof(HLPFILE_LINK);
530 lstrcpy(ptr, (LPSTR) attributes.link.lpszPath);
532 paragraph->link->lpszPath = ptr;
533 paragraph->link->lHash = attributes.link.lHash;
534 paragraph->link->bPopup = attributes.link.bPopup;
537 attributes.bDebug = 0;
538 attributes.wVSpace = 0;
539 attributes.wHSpace = 0;
540 attributes.link.lpszPath = 0;
543 return TRUE;
546 /***********************************************************************
548 * HLPFILE_ReadFileToBuffer
551 static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
553 BYTE header[16], dummy[1];
554 UINT size;
556 if (_hread(hFile, header, 16) != 16) {Report("header"); return(FALSE);};
558 size = GET_UINT(header, 12);
559 hFileBuffer = GlobalAlloc(GMEM_FIXED, size + 1);
560 if (!hFileBuffer) return FALSE;
561 file_buffer = GlobalLock(hFileBuffer);
563 memcpy(file_buffer, header, 16);
564 if (_hread(hFile, file_buffer + 16, size - 16) != size - 16)
565 {Report("filesize1"); return(FALSE);};
567 if (_hread(hFile, dummy, 1) != 0) Report("filesize2");
569 file_buffer[size] = '0';
571 return TRUE;
574 /***********************************************************************
576 * HLPFILE_FindSubFile
579 static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE **subbuf, BYTE **subend)
581 BYTE *root = file_buffer + GET_UINT(file_buffer, 4);
582 BYTE *end = file_buffer + GET_UINT(file_buffer, 12);
583 BYTE *ptr = root + 0x37;
585 while (ptr < end && ptr[0] == 0x7c)
587 BYTE *fname = ptr + 1;
588 ptr += strlen(ptr) + 1;
589 if (!lstrcmpi(fname, name))
591 *subbuf = file_buffer + GET_UINT(ptr, 0);
592 *subend = *subbuf + GET_UINT(*subbuf, 0);
593 if (file_buffer > *subbuf || *subbuf > *subend || *subend >= end)
595 Report("subfile");
596 return FALSE;
598 return TRUE;
600 else ptr += 4;
602 return FALSE;
605 /***********************************************************************
607 * HLPFILE_SystemCommands
609 static VOID HLPFILE_SystemCommands(HLPFILE* hlpfile)
611 BYTE *buf, *ptr, *end;
612 HGLOBAL handle;
613 HLPFILE_MACRO *macro, **m;
614 LPSTR p;
616 hlpfile->lpszTitle = "";
618 if (!HLPFILE_FindSubFile("SYSTEM", &buf, &end)) return;
620 for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4)
622 switch (GET_USHORT(ptr, 0))
624 case 1:
625 if (hlpfile->hTitle) {Report("title"); break;}
626 hlpfile->hTitle = GlobalAlloc(GMEM_FIXED, strlen(ptr + 4) + 1);
627 if (!hlpfile->hTitle) return;
628 hlpfile->lpszTitle = GlobalLock(hlpfile->hTitle);
629 lstrcpy(hlpfile->lpszTitle, ptr + 4);
630 break;
632 case 2:
633 if (GET_USHORT(ptr, 2) != 1 || ptr[4] != 0) Report("system2");
634 break;
636 case 3:
637 if (GET_USHORT(ptr, 2) != 4 || GET_UINT(ptr, 4) != 0) Report("system3");
638 break;
640 case 4:
641 handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_MACRO) + lstrlen(ptr + 4) + 1);
642 if (!handle) break;
643 macro = GlobalLock(handle);
644 macro->hSelf = handle;
645 p = GlobalLock(handle);
646 p += sizeof(HLPFILE_MACRO);
647 lstrcpy(p, (LPSTR) ptr + 4);
648 macro->lpszMacro = p;
649 macro->next = 0;
650 for (m = &hlpfile->first_macro; *m; m = &(*m)->next);
651 *m = macro;
652 break;
654 default:
655 Report("system");
660 /***********************************************************************
662 * HLPFILE_Uncompressed1_Size
665 static INT HLPFILE_Uncompressed1_Size(BYTE *ptr, BYTE *end)
667 INT i, newsize = 0;
669 while (ptr < end)
671 INT mask=*ptr++;
672 for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
674 if (mask & 1)
676 INT code = GET_USHORT(ptr, 0);
677 INT len = 3 + (code >> 12);
678 newsize += len;
679 ptr += 2;
681 else newsize++, ptr++;
685 return(newsize);
688 /***********************************************************************
690 * HLPFILE_Uncompress1
693 static BYTE *HLPFILE_Uncompress1(BYTE *ptr, BYTE *end, BYTE *newptr)
695 INT i;
697 while (ptr < end)
699 INT mask=*ptr++;
700 for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
702 if (mask & 1)
704 INT code = GET_USHORT(ptr, 0);
705 INT len = 3 + (code >> 12);
706 INT offset = code & 0xfff;
707 hmemcpy(newptr, newptr - offset - 1, len);
708 newptr += len;
709 ptr += 2;
711 else *newptr++ = *ptr++;
715 return(newptr);
718 /***********************************************************************
720 * HLPFILE_Uncompress1_Phrases
723 static BOOL HLPFILE_Uncompress1_Phrases()
725 UINT i, num, newsize;
726 BYTE *buf, *end, *newbuf;
728 if (!HLPFILE_FindSubFile("Phrases", &buf, &end)) {Report("phrases0"); return FALSE;}
730 num = phrases.num = GET_USHORT(buf, 9);
731 if (buf + 2 * num + 0x13 >= end) {Report("uncompress1a"); return(FALSE);};
733 newsize = 2 * num + 2;
734 newsize += HLPFILE_Uncompressed1_Size(buf + 0x13 + 2 * num, end);
735 phrases.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
736 if (!phrases.hBuffer) return FALSE;
737 newbuf = phrases.buf = GlobalLock(phrases.hBuffer);
739 hmemcpy(newbuf, buf + 0x11, 2 * num + 2);
740 HLPFILE_Uncompress1(buf + 0x13 + 2 * num, end, newbuf + 2 * num + 2);
742 for (i = 0; i < num; i++)
744 INT i0 = GET_USHORT(newbuf, 2 * i);
745 INT i1 = GET_USHORT(newbuf, 2 * i + 2);
746 if (i1 < i0 || i1 > newsize) {Report("uncompress1b"); return(FALSE);};
748 return TRUE;
751 /***********************************************************************
753 * HLPFILE_Uncompress1_Topic
756 static BOOL HLPFILE_Uncompress1_Topic()
758 BYTE *buf, *ptr, *end, *newptr;
759 INT i, newsize = 0;
761 if (!HLPFILE_FindSubFile("TOPIC", &buf, &end)) {Report("topic0"); return FALSE;}
763 buf += 9;
764 topic.wMapLen = (end - buf - 1) / 0x1000 + 1;
766 for (i = 0; i < topic.wMapLen; i++)
768 ptr = buf + i * 0x1000;
770 /* I don't know why, it's necessary for printman.hlp */
771 if (ptr + 0x44 > end) ptr = end - 0x44;
773 newsize += HLPFILE_Uncompressed1_Size(ptr + 0xc, MIN(end, ptr + 0x1000));
776 topic.hMap = GlobalAlloc(GMEM_FIXED, topic.wMapLen * sizeof(topic.map[0]));
777 topic.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
778 if (!topic.hMap || !topic.hBuffer) return FALSE;
779 topic.map = GlobalLock(topic.hMap);
780 newptr = GlobalLock(topic.hBuffer);
781 topic.end = newptr + newsize;
783 for (i = 0; i < topic.wMapLen; i++)
785 ptr = buf + i * 0x1000;
786 if (ptr + 0x44 > end) ptr = end - 0x44;
788 topic.map[i] = newptr - 0xc;
789 newptr = HLPFILE_Uncompress1(ptr + 0xc, MIN(end, ptr + 0x1000), newptr);
792 return TRUE;
795 /***********************************************************************
797 * HLPFILE_Uncompressed2_Size
800 static UINT HLPFILE_Uncompressed2_Size(BYTE *ptr, BYTE *end)
802 UINT wSize = 0;
804 while (ptr < end && *ptr)
806 if (*ptr >= 0x20)
807 wSize++, ptr++;
808 else
810 BYTE *phptr, *phend;
811 UINT code = 0x100 * ptr[0] + ptr[1];
812 UINT index = (code - 0x100) / 2;
813 BOOL space = code & 1;
815 if (index < phrases.num)
817 phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
818 phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
820 if (phend < phptr) Report("uncompress2a");
822 wSize += phend - phptr;
823 if (space) wSize++;
825 else Report("uncompress2b");
827 ptr += 2;
831 return(wSize + 1);
834 /***********************************************************************
836 * HLPFILE_Uncompress2
839 static VOID HLPFILE_Uncompress2(BYTE **pptr, BYTE *end, BYTE *newptr)
841 BYTE *ptr = *pptr;
843 while (ptr < end && *ptr)
845 if (*ptr >= 0x20)
846 *newptr++ = *ptr++;
847 else
849 BYTE *phptr, *phend;
850 UINT code = 0x100 * ptr[0] + ptr[1];
851 UINT index = (code - 0x100) / 2;
852 BOOL space = code & 1;
854 phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
855 phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
857 hmemcpy(newptr, phptr, phend - phptr);
858 newptr += phend - phptr;
859 if (space) *newptr++ = ' ';
861 ptr += 2;
864 *newptr = '\0';
865 *pptr = ptr;
868 /***********************************************************************
870 * HLPFILE_GetContext
873 static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
875 UINT i, j, clen, tlen;
876 BYTE *cbuf, *cptr, *cend, *tbuf, *tptr, *tend;
878 if (!HLPFILE_FindSubFile("CONTEXT", &cbuf, &cend)) {Report("context0"); return FALSE;}
879 if (cbuf + 0x37 > cend) {Report("context1"); return(FALSE);};
880 clen = GET_UINT(cbuf, 0x2b);
881 if (cbuf + 0x37 + 8 * hlpfile->wContextLen > cend) {Report("context2"); return(FALSE);};
883 if (!HLPFILE_FindSubFile("TTLBTREE", &tbuf, &tend)) {Report("ttlb0"); return FALSE;}
884 if (tbuf + 0x37 > tend) {Report("ttlb1"); return(FALSE);};
885 tlen = GET_UINT(tbuf, 0x2b);
887 hlpfile->hContext = GlobalAlloc(GMEM_FIXED, clen * sizeof(HLPFILE_CONTEXT));
888 if (!hlpfile->hContext) return FALSE;
889 hlpfile->Context = GlobalLock(hlpfile->hContext);
890 hlpfile->wContextLen = clen;
892 cptr = cbuf + 0x37;
893 for (i = 0; i < clen; i++, cptr += 8)
895 tptr = tbuf + 0x37;
896 for (j = 0; j < tlen; j++, tptr += 5 + strlen(tptr + 4))
898 if (tptr + 4 >= tend) {Report("ttlb2"); return(FALSE);};
899 if (GET_UINT(tptr, 0) == GET_UINT(cptr, 4)) break;
901 if (j >= tlen)
903 Report("ttlb3");
904 j = 0;
906 hlpfile->Context[i].lHash = GET_UINT(cptr, 0);
907 hlpfile->Context[i].wPage = j;
910 return TRUE;
913 /***********************************************************************
915 * HLPFILE_DeleteParagraph
918 static VOID HLPFILE_DeleteParagraph(HLPFILE_PARAGRAPH* paragraph)
920 if (!paragraph) return;
922 if (paragraph->link) GlobalFree(paragraph->link->hSelf);
924 HLPFILE_DeleteParagraph(paragraph->next);
925 GlobalFree(paragraph->hSelf);
928 /***********************************************************************
930 * DeletePage
933 static VOID HLPFILE_DeletePage(HLPFILE_PAGE* page)
935 if (!page) return;
937 HLPFILE_DeletePage(page->next);
938 HLPFILE_DeleteParagraph(page->first_paragraph);
939 GlobalFree(page->hSelf);
942 /***********************************************************************
944 * DeleteMacro
947 static VOID HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
949 if (!macro) return;
951 HLPFILE_DeleteMacro(macro->next);
952 GlobalFree(macro->hSelf);
955 /***********************************************************************
957 * HLPFILE_FreeHlpFile
960 VOID HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
962 if (!hlpfile) return;
963 if (--hlpfile->wRefCount) return;
965 if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
966 if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
967 else first_hlpfile = 0;
969 HLPFILE_DeletePage(hlpfile->first_page);
970 HLPFILE_DeleteMacro(hlpfile->first_macro);
971 if (hlpfile->hContext) GlobalFree(hlpfile->hContext);
972 if (hlpfile->hTitle) GlobalFree(hlpfile->hTitle);
973 GlobalFree(hlpfile->hSelf);
976 /***********************************************************************
978 * FreeHlpFilePage
981 VOID HLPFILE_FreeHlpFilePage(HLPFILE_PAGE* page)
983 if (!page) return;
984 HLPFILE_FreeHlpFile(page->file);
987 /* Local Variables: */
988 /* c-file-style: "GNU" */
989 /* End: */