Fixed warning.
[wine.git] / programs / winhelp / hlpfile.c
blobe15c0ae3bc17238a482f5b4c414e0dab9b7c3054
1 /*
2 * Help Viewer
4 * Copyright 1996 Ulrich Schmid
5 */
7 #include <stdio.h>
8 #include <string.h>
9 #include "windows.h"
10 #include "windowsx.h"
11 #include "winhelp.h"
13 static void Report(LPCSTR str)
15 #if 0
16 fprintf(stderr, "%s\n", str);
17 #endif
20 #define GET_USHORT(buffer, i)\
21 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
22 #define GET_SHORT(buffer, i)\
23 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
24 #define GET_UINT(buffer, i)\
25 GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i+2)
27 static BOOL HLPFILE_DoReadHlpFile(HLPFILE*, LPCSTR);
28 static BOOL HLPFILE_ReadFileToBuffer(HFILE);
29 static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE**, BYTE**);
30 static VOID HLPFILE_SystemCommands(HLPFILE*);
31 static BOOL HLPFILE_Uncompress1_Phrases();
32 static BOOL HLPFILE_Uncompress1_Topic();
33 static BOOL HLPFILE_GetContext(HLPFILE*);
34 static BOOL HLPFILE_AddPage(HLPFILE*, BYTE*, BYTE*);
35 static BOOL HLPFILE_AddParagraph(HLPFILE*, BYTE *, BYTE*);
36 static UINT HLPFILE_Uncompressed2_Size(BYTE*, BYTE*);
37 static VOID HLPFILE_Uncompress2(BYTE**, BYTE*, BYTE*);
39 static HLPFILE *first_hlpfile = 0;
40 static HGLOBAL hFileBuffer;
41 static BYTE *file_buffer;
43 static struct
45 UINT num;
46 BYTE *buf;
47 HGLOBAL hBuffer;
48 } phrases;
50 static struct
52 BYTE **map;
53 BYTE *end;
54 UINT wMapLen;
55 HGLOBAL hMap;
56 HGLOBAL hBuffer;
57 } topic;
59 static struct
61 UINT bDebug;
62 UINT wFont;
63 UINT wIndent;
64 UINT wHSpace;
65 UINT wVSpace;
66 UINT wVBackSpace;
67 HLPFILE_LINK link;
68 } attributes;
70 /***********************************************************************
72 * HLPFILE_Contents
75 HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath)
77 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
79 if (!hlpfile) return(0);
81 return(hlpfile->first_page);
84 /***********************************************************************
86 * HLPFILE_PageByNumber
89 HLPFILE_PAGE *HLPFILE_PageByNumber(LPCSTR lpszPath, UINT wNum)
91 HLPFILE_PAGE *page;
92 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
94 if (!hlpfile) return(0);
96 for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
98 return page;
101 /***********************************************************************
103 * HLPFILE_HlpFilePageByHash
106 HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG lHash)
108 INT i;
109 UINT wNum;
110 HLPFILE_PAGE *page;
111 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
113 if (!hlpfile) return(0);
115 for (i = 0; i < hlpfile->wContextLen; i++)
116 if (hlpfile->Context[i].lHash == lHash) break;
118 if (i >= hlpfile->wContextLen)
120 HLPFILE_FreeHlpFile(hlpfile);
121 return(0);
124 wNum = hlpfile->Context[i].wPage;
125 for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
127 return page;
130 /***********************************************************************
132 * HLPFILE_Hash
135 LONG HLPFILE_Hash(LPCSTR lpszContext)
137 LONG lHash = 0;
138 CHAR c;
139 while((c = *lpszContext++))
141 CHAR x = 0;
142 if (c >= 'A' && c <= 'Z') x = c - 'A' + 17;
143 if (c >= 'a' && c <= 'z') x = c - 'a' + 17;
144 if (c >= '1' && c <= '9') x = c - '0';
145 if (c == '0') x = 10;
146 if (c == '.') x = 12;
147 if (c == '_') x = 13;
148 if (x) lHash = lHash * 43 + x;
150 return lHash;
153 /***********************************************************************
155 * HLPFILE_ReadHlpFile
158 HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
160 HGLOBAL hHlpFile;
161 HLPFILE *hlpfile;
163 for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
164 if (!lstrcmp(hlpfile->lpszPath, lpszPath))
166 hlpfile->wRefCount++;
167 return(hlpfile);
170 hHlpFile = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
171 if (!hHlpFile) return(0);
173 hlpfile = GlobalLock(hHlpFile);
174 hlpfile->hSelf = hHlpFile;
175 hlpfile->wRefCount = 1;
176 hlpfile->hTitle = 0;
177 hlpfile->hContext = 0;
178 hlpfile->wContextLen = 0;
179 hlpfile->first_page = 0;
180 hlpfile->first_macro = 0;
181 hlpfile->prev = 0;
182 hlpfile->next = first_hlpfile;
183 first_hlpfile = hlpfile;
184 if (hlpfile->next) hlpfile->next->prev = hlpfile;
186 hlpfile->lpszPath = GlobalLock(hHlpFile);
187 hlpfile->lpszPath += sizeof(HLPFILE);
188 strcpy(hlpfile->lpszPath, lpszPath);
190 phrases.hBuffer = topic.hBuffer = hFileBuffer = 0;
192 if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
194 HLPFILE_FreeHlpFile(hlpfile);
195 hlpfile = 0;
198 if (phrases.hBuffer) GlobalFree(phrases.hBuffer);
199 if (topic.hBuffer) GlobalFree(topic.hBuffer);
200 if (topic.hMap) GlobalFree(topic.hMap);
201 if (hFileBuffer) GlobalFree(hFileBuffer);
203 return(hlpfile);
206 /***********************************************************************
208 * HLPFILE_DoReadHlpFile
211 static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
213 BOOL ret;
214 HFILE hFile;
215 OFSTRUCT ofs;
216 BYTE *buf;
218 hFile=OpenFile(lpszPath, &ofs, OF_READ | OF_SEARCH);
219 if (hFile == HFILE_ERROR) return FALSE;
221 ret = HLPFILE_ReadFileToBuffer(hFile);
222 _lclose(hFile);
223 if (!ret) return FALSE;
225 HLPFILE_SystemCommands(hlpfile);
226 if (!HLPFILE_Uncompress1_Phrases()) return FALSE;
227 if (!HLPFILE_Uncompress1_Topic()) return FALSE;
229 buf = topic.map[0] + 0xc;
230 while(buf + 0xc < topic.end)
232 BYTE *end = min(buf + GET_UINT(buf, 0), topic.end);
233 UINT next, index, offset;
235 switch (buf[0x14])
237 case 0x02:
238 if (!HLPFILE_AddPage(hlpfile, buf, end)) return(FALSE);
239 break;
241 case 0x20:
242 if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
243 break;
245 case 0x23:
246 if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
247 break;
249 default:
250 fprintf(stderr, "buf[0x14] = %x\n", buf[0x14]);
253 next = GET_UINT(buf, 0xc);
254 if (next == 0xffffffff) break;
256 index = next >> 14;
257 offset = next & 0x3fff;
258 if (index > topic.wMapLen) {Report("maplen"); break;}
259 buf = topic.map[index] + offset;
262 return(HLPFILE_GetContext(hlpfile));
265 /***********************************************************************
267 * HLPFILE_AddPage
270 static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
272 HGLOBAL hPage;
273 HLPFILE_PAGE *page, **pageptr;
274 BYTE *title;
275 UINT titlesize;
277 for (pageptr = &hlpfile->first_page; *pageptr; pageptr = &(*pageptr)->next)
278 /* Nothing */;
280 if (buf + 0x31 > end) {Report("page1"); return(FALSE);};
281 title = buf + GET_UINT(buf, 0x10);
282 if (title > end) {Report("page2"); return(FALSE);};
284 titlesize = HLPFILE_Uncompressed2_Size(title, end);
285 hPage = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PAGE) + titlesize);
286 if (!hPage) return FALSE;
287 page = *pageptr = GlobalLock(hPage);
288 pageptr = &page->next;
289 page->hSelf = hPage;
290 page->file = hlpfile;
291 page->next = 0;
292 page->first_paragraph = 0;
294 page->lpszTitle = GlobalLock(hPage);
295 page->lpszTitle += sizeof(HLPFILE_PAGE);
296 HLPFILE_Uncompress2(&title, end, page->lpszTitle);
298 page->wNumber = GET_UINT(buf, 0x21);
300 attributes.bDebug = 0;
301 attributes.wFont = 0;
302 attributes.wVSpace = 0;
303 attributes.wVBackSpace = 0;
304 attributes.wHSpace = 0;
305 attributes.wIndent = 0;
306 attributes.link.lpszPath = 0;
308 return TRUE;
311 /***********************************************************************
313 * HLPFILE_AddParagraph
316 static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
318 HGLOBAL hParagraph;
319 HLPFILE_PAGE *page;
320 HLPFILE_PARAGRAPH *paragraph, **paragraphptr;
321 UINT textsize;
322 BYTE *format, *text;
323 BOOL format_header = TRUE;
324 BOOL format_end = FALSE;
325 UINT mask, i;
327 if (!hlpfile->first_page) {Report("paragraph1"); return(FALSE);};
329 for (page = hlpfile->first_page; page->next; page = page->next) /* Nothing */;
330 for (paragraphptr = &page->first_paragraph; *paragraphptr;
331 paragraphptr = &(*paragraphptr)->next) /* Nothing */;
333 if (buf + 0x19 > end) {Report("paragraph2"); return(FALSE);};
335 if (buf[0x14] == 0x02) return TRUE;
337 text = buf + GET_UINT(buf, 0x10);
339 switch (buf[0x14])
341 case 0x20:
342 format = buf + 0x18;
343 while (*format) format++;
344 format += 4;
345 break;
347 case 0x23:
348 format = buf + 0x2b;
349 if (buf[0x17] & 1) format++;
350 break;
352 default:
353 Report("paragraph3");
354 return FALSE;
357 while (text < end)
359 if (format_header)
361 format_header = FALSE;
363 mask = GET_USHORT(format, 0);
364 mask &= 0x3ff;
365 format += 2;
367 for (i = 0; i < 10; i++, mask = mask >> 1)
369 if (mask & 1)
371 BOOL twoargs = FALSE;
372 CHAR prefix0 = ' ';
373 CHAR prefix1 = '*';
375 if (i == 9 && !twoargs)
377 switch (*format++)
379 default:
380 prefix0 = prefix1 = '?';
381 break;
383 case 0x82:
384 prefix0 = prefix1 = 'x';
385 break;
387 case 0x84:
388 prefix0 = prefix1 = 'X';
389 twoargs = TRUE;
393 if (*format & 1)
394 switch(*format)
396 default:
397 format += 2;
398 break;
400 else
401 switch(*format)
404 default:
405 format++;
406 break;
408 case 0x08:
409 format += 3;
410 break;
413 if (twoargs) format += (*format & 1) ? 2 : 1;
418 for (; !format_header && text < end && format < end && !*text; text++)
420 switch(*format)
422 case 0x80:
423 attributes.wFont = GET_USHORT(format, 1);
424 format += 3;
425 break;
427 case 0x81:
428 attributes.wVSpace++;
429 format += 1;
430 break;
432 case 0x82:
433 attributes.wVSpace += 2 - attributes.wVBackSpace;
434 attributes.wVBackSpace = 0;
435 attributes.wIndent = 0;
436 format += 1;
437 break;
439 case 0x83:
440 attributes.wIndent++;
441 format += 1;
442 break;
444 case 0x84:
445 format += 3;
446 break;
448 case 0x86:
449 case 0x87:
450 case 0x88:
451 format += 9;
452 break;
454 case 0x89:
455 attributes.wVBackSpace++;
456 format += 1;
457 break;
459 case 0xa9:
460 format += 2;
461 break;
463 case 0xe2:
464 case 0xe3:
465 attributes.link.lpszPath = hlpfile->lpszPath;
466 attributes.link.lHash = GET_UINT(format, 1);
467 attributes.link.bPopup = !(*format & 1);
468 format += 5;
469 break;
471 case 0xea:
472 attributes.link.lpszPath = format + 8;
473 attributes.link.lHash = GET_UINT(format, 4);
474 attributes.link.bPopup = !(*format & 1);
475 format += 3 + GET_USHORT(format, 1);
476 break;
478 case 0xff:
479 if (buf[0x14] != 0x23 || GET_USHORT(format, 1) == 0xffff)
481 if (format_end) Report("format_end");
482 format_end = TRUE;
483 break;
485 else
487 format_header = TRUE;
488 format += 10;
489 break;
492 default:
493 Report("format");
494 format++;
498 if (text > end || format > end) {Report("paragraph_end"); return(FALSE);};
499 if (text == end && !format_end) Report("text_end");
501 if (text == end) break;
503 textsize = HLPFILE_Uncompressed2_Size(text, end);
504 hParagraph = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PARAGRAPH) + textsize);
505 if (!hParagraph) return FALSE;
506 paragraph = *paragraphptr = GlobalLock(hParagraph);
507 paragraphptr = &paragraph->next;
508 paragraph->hSelf = hParagraph;
509 paragraph->next = 0;
510 paragraph->link = 0;
512 paragraph->lpszText = GlobalLock(hParagraph);
513 paragraph->lpszText += sizeof(HLPFILE_PARAGRAPH);
514 HLPFILE_Uncompress2(&text, end, paragraph->lpszText);
516 paragraph->bDebug = attributes.bDebug;
517 paragraph->wFont = attributes.wFont;
518 paragraph->wVSpace = attributes.wVSpace;
519 paragraph->wHSpace = attributes.wHSpace;
520 paragraph->wIndent = attributes.wIndent;
521 if (attributes.link.lpszPath)
523 LPSTR ptr;
524 HGLOBAL handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_LINK) +
525 strlen(attributes.link.lpszPath) + 1);
526 if (!handle) return FALSE;
527 paragraph->link = GlobalLock(handle);
528 paragraph->link->hSelf = handle;
530 ptr = GlobalLock(handle);
531 ptr += sizeof(HLPFILE_LINK);
532 lstrcpy(ptr, (LPSTR) attributes.link.lpszPath);
534 paragraph->link->lpszPath = ptr;
535 paragraph->link->lHash = attributes.link.lHash;
536 paragraph->link->bPopup = attributes.link.bPopup;
539 attributes.bDebug = 0;
540 attributes.wVSpace = 0;
541 attributes.wHSpace = 0;
542 attributes.link.lpszPath = 0;
545 return TRUE;
548 /***********************************************************************
550 * HLPFILE_ReadFileToBuffer
553 static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
555 BYTE header[16], dummy[1];
556 UINT size;
558 if (_hread(hFile, header, 16) != 16) {Report("header"); return(FALSE);};
560 size = GET_UINT(header, 12);
561 hFileBuffer = GlobalAlloc(GMEM_FIXED, size + 1);
562 if (!hFileBuffer) return FALSE;
563 file_buffer = GlobalLock(hFileBuffer);
565 memcpy(file_buffer, header, 16);
566 if (_hread(hFile, file_buffer + 16, size - 16) != size - 16)
567 {Report("filesize1"); return(FALSE);};
569 if (_hread(hFile, dummy, 1) != 0) Report("filesize2");
571 file_buffer[size] = '0';
573 return TRUE;
576 /***********************************************************************
578 * HLPFILE_FindSubFile
581 static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE **subbuf, BYTE **subend)
583 BYTE *root = file_buffer + GET_UINT(file_buffer, 4);
584 BYTE *end = file_buffer + GET_UINT(file_buffer, 12);
585 BYTE *ptr = root + 0x37;
587 while (ptr < end && ptr[0] == 0x7c)
589 BYTE *fname = ptr + 1;
590 ptr += strlen(ptr) + 1;
591 if (!lstrcmpi(fname, name))
593 *subbuf = file_buffer + GET_UINT(ptr, 0);
594 *subend = *subbuf + GET_UINT(*subbuf, 0);
595 if (file_buffer > *subbuf || *subbuf > *subend || *subend >= end)
597 Report("subfile");
598 return FALSE;
600 return TRUE;
602 else ptr += 4;
604 return FALSE;
607 /***********************************************************************
609 * HLPFILE_SystemCommands
611 static VOID HLPFILE_SystemCommands(HLPFILE* hlpfile)
613 BYTE *buf, *ptr, *end;
614 HGLOBAL handle;
615 HLPFILE_MACRO *macro, **m;
616 LPSTR p;
618 hlpfile->lpszTitle = "";
620 if (!HLPFILE_FindSubFile("SYSTEM", &buf, &end)) return;
622 for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4)
624 switch (GET_USHORT(ptr, 0))
626 case 1:
627 if (hlpfile->hTitle) {Report("title"); break;}
628 hlpfile->hTitle = GlobalAlloc(GMEM_FIXED, strlen(ptr + 4) + 1);
629 if (!hlpfile->hTitle) return;
630 hlpfile->lpszTitle = GlobalLock(hlpfile->hTitle);
631 lstrcpy(hlpfile->lpszTitle, ptr + 4);
632 break;
634 case 2:
635 if (GET_USHORT(ptr, 2) != 1 || ptr[4] != 0) Report("system2");
636 break;
638 case 3:
639 if (GET_USHORT(ptr, 2) != 4 || GET_UINT(ptr, 4) != 0) Report("system3");
640 break;
642 case 4:
643 handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_MACRO) + lstrlen(ptr + 4) + 1);
644 if (!handle) break;
645 macro = GlobalLock(handle);
646 macro->hSelf = handle;
647 p = GlobalLock(handle);
648 p += sizeof(HLPFILE_MACRO);
649 lstrcpy(p, (LPSTR) ptr + 4);
650 macro->lpszMacro = p;
651 macro->next = 0;
652 for (m = &hlpfile->first_macro; *m; m = &(*m)->next);
653 *m = macro;
654 break;
656 default:
657 Report("system");
662 /***********************************************************************
664 * HLPFILE_Uncompressed1_Size
667 static INT HLPFILE_Uncompressed1_Size(BYTE *ptr, BYTE *end)
669 INT i, newsize = 0;
671 while (ptr < end)
673 INT mask=*ptr++;
674 for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
676 if (mask & 1)
678 INT code = GET_USHORT(ptr, 0);
679 INT len = 3 + (code >> 12);
680 newsize += len;
681 ptr += 2;
683 else newsize++, ptr++;
687 return(newsize);
690 /***********************************************************************
692 * HLPFILE_Uncompress1
695 static BYTE *HLPFILE_Uncompress1(BYTE *ptr, BYTE *end, BYTE *newptr)
697 INT i;
699 while (ptr < end)
701 INT mask=*ptr++;
702 for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
704 if (mask & 1)
706 INT code = GET_USHORT(ptr, 0);
707 INT len = 3 + (code >> 12);
708 INT offset = code & 0xfff;
709 hmemcpy16(newptr, newptr - offset - 1, len);
710 newptr += len;
711 ptr += 2;
713 else *newptr++ = *ptr++;
717 return(newptr);
720 /***********************************************************************
722 * HLPFILE_Uncompress1_Phrases
725 static BOOL HLPFILE_Uncompress1_Phrases()
727 UINT i, num, newsize;
728 BYTE *buf, *end, *newbuf;
730 if (!HLPFILE_FindSubFile("Phrases", &buf, &end)) {Report("phrases0"); return FALSE;}
732 num = phrases.num = GET_USHORT(buf, 9);
733 if (buf + 2 * num + 0x13 >= end) {Report("uncompress1a"); return(FALSE);};
735 newsize = 2 * num + 2;
736 newsize += HLPFILE_Uncompressed1_Size(buf + 0x13 + 2 * num, end);
737 phrases.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
738 if (!phrases.hBuffer) return FALSE;
739 newbuf = phrases.buf = GlobalLock(phrases.hBuffer);
741 hmemcpy16(newbuf, buf + 0x11, 2 * num + 2);
742 HLPFILE_Uncompress1(buf + 0x13 + 2 * num, end, newbuf + 2 * num + 2);
744 for (i = 0; i < num; i++)
746 INT i0 = GET_USHORT(newbuf, 2 * i);
747 INT i1 = GET_USHORT(newbuf, 2 * i + 2);
748 if (i1 < i0 || i1 > newsize) {Report("uncompress1b"); return(FALSE);};
750 return TRUE;
753 /***********************************************************************
755 * HLPFILE_Uncompress1_Topic
758 static BOOL HLPFILE_Uncompress1_Topic()
760 BYTE *buf, *ptr, *end, *newptr;
761 INT i, newsize = 0;
763 if (!HLPFILE_FindSubFile("TOPIC", &buf, &end)) {Report("topic0"); return FALSE;}
765 buf += 9;
766 topic.wMapLen = (end - buf - 1) / 0x1000 + 1;
768 for (i = 0; i < topic.wMapLen; i++)
770 ptr = buf + i * 0x1000;
772 /* I don't know why, it's necessary for printman.hlp */
773 if (ptr + 0x44 > end) ptr = end - 0x44;
775 newsize += HLPFILE_Uncompressed1_Size(ptr + 0xc, min(end, ptr + 0x1000));
778 topic.hMap = GlobalAlloc(GMEM_FIXED, topic.wMapLen * sizeof(topic.map[0]));
779 topic.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
780 if (!topic.hMap || !topic.hBuffer) return FALSE;
781 topic.map = GlobalLock(topic.hMap);
782 newptr = GlobalLock(topic.hBuffer);
783 topic.end = newptr + newsize;
785 for (i = 0; i < topic.wMapLen; i++)
787 ptr = buf + i * 0x1000;
788 if (ptr + 0x44 > end) ptr = end - 0x44;
790 topic.map[i] = newptr - 0xc;
791 newptr = HLPFILE_Uncompress1(ptr + 0xc, min(end, ptr + 0x1000), newptr);
794 return TRUE;
797 /***********************************************************************
799 * HLPFILE_Uncompressed2_Size
802 static UINT HLPFILE_Uncompressed2_Size(BYTE *ptr, BYTE *end)
804 UINT wSize = 0;
806 while (ptr < end && *ptr)
808 if (*ptr >= 0x20)
809 wSize++, ptr++;
810 else
812 BYTE *phptr, *phend;
813 UINT code = 0x100 * ptr[0] + ptr[1];
814 UINT index = (code - 0x100) / 2;
815 BOOL space = code & 1;
817 if (index < phrases.num)
819 phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
820 phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
822 if (phend < phptr) Report("uncompress2a");
824 wSize += phend - phptr;
825 if (space) wSize++;
827 else Report("uncompress2b");
829 ptr += 2;
833 return(wSize + 1);
836 /***********************************************************************
838 * HLPFILE_Uncompress2
841 static VOID HLPFILE_Uncompress2(BYTE **pptr, BYTE *end, BYTE *newptr)
843 BYTE *ptr = *pptr;
845 while (ptr < end && *ptr)
847 if (*ptr >= 0x20)
848 *newptr++ = *ptr++;
849 else
851 BYTE *phptr, *phend;
852 UINT code = 0x100 * ptr[0] + ptr[1];
853 UINT index = (code - 0x100) / 2;
854 BOOL space = code & 1;
856 phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
857 phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
859 hmemcpy16(newptr, phptr, phend - phptr);
860 newptr += phend - phptr;
861 if (space) *newptr++ = ' ';
863 ptr += 2;
866 *newptr = '\0';
867 *pptr = ptr;
870 /***********************************************************************
872 * HLPFILE_GetContext
875 static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
877 UINT i, j, clen, tlen;
878 BYTE *cbuf, *cptr, *cend, *tbuf, *tptr, *tend;
880 if (!HLPFILE_FindSubFile("CONTEXT", &cbuf, &cend)) {Report("context0"); return FALSE;}
881 if (cbuf + 0x37 > cend) {Report("context1"); return(FALSE);};
882 clen = GET_UINT(cbuf, 0x2b);
883 if (cbuf + 0x37 + 8 * hlpfile->wContextLen > cend) {Report("context2"); return(FALSE);};
885 if (!HLPFILE_FindSubFile("TTLBTREE", &tbuf, &tend)) {Report("ttlb0"); return FALSE;}
886 if (tbuf + 0x37 > tend) {Report("ttlb1"); return(FALSE);};
887 tlen = GET_UINT(tbuf, 0x2b);
889 hlpfile->hContext = GlobalAlloc(GMEM_FIXED, clen * sizeof(HLPFILE_CONTEXT));
890 if (!hlpfile->hContext) return FALSE;
891 hlpfile->Context = GlobalLock(hlpfile->hContext);
892 hlpfile->wContextLen = clen;
894 cptr = cbuf + 0x37;
895 for (i = 0; i < clen; i++, cptr += 8)
897 tptr = tbuf + 0x37;
898 for (j = 0; j < tlen; j++, tptr += 5 + strlen(tptr + 4))
900 if (tptr + 4 >= tend) {Report("ttlb2"); return(FALSE);};
901 if (GET_UINT(tptr, 0) == GET_UINT(cptr, 4)) break;
903 if (j >= tlen)
905 Report("ttlb3");
906 j = 0;
908 hlpfile->Context[i].lHash = GET_UINT(cptr, 0);
909 hlpfile->Context[i].wPage = j;
912 return TRUE;
915 /***********************************************************************
917 * HLPFILE_DeleteParagraph
920 static VOID HLPFILE_DeleteParagraph(HLPFILE_PARAGRAPH* paragraph)
922 if (!paragraph) return;
924 if (paragraph->link) GlobalFree(paragraph->link->hSelf);
926 HLPFILE_DeleteParagraph(paragraph->next);
927 GlobalFree(paragraph->hSelf);
930 /***********************************************************************
932 * DeletePage
935 static VOID HLPFILE_DeletePage(HLPFILE_PAGE* page)
937 if (!page) return;
939 HLPFILE_DeletePage(page->next);
940 HLPFILE_DeleteParagraph(page->first_paragraph);
941 GlobalFree(page->hSelf);
944 /***********************************************************************
946 * DeleteMacro
949 static VOID HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
951 if (!macro) return;
953 HLPFILE_DeleteMacro(macro->next);
954 GlobalFree(macro->hSelf);
957 /***********************************************************************
959 * HLPFILE_FreeHlpFile
962 VOID HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
964 if (!hlpfile) return;
965 if (--hlpfile->wRefCount) return;
967 if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
968 if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
969 else first_hlpfile = 0;
971 HLPFILE_DeletePage(hlpfile->first_page);
972 HLPFILE_DeleteMacro(hlpfile->first_macro);
973 if (hlpfile->hContext) GlobalFree(hlpfile->hContext);
974 if (hlpfile->hTitle) GlobalFree(hlpfile->hTitle);
975 GlobalFree(hlpfile->hSelf);
978 /***********************************************************************
980 * FreeHlpFilePage
983 VOID HLPFILE_FreeHlpFilePage(HLPFILE_PAGE* page)
985 if (!page) return;
986 HLPFILE_FreeHlpFile(page->file);
989 /* Local Variables: */
990 /* c-file-style: "GNU" */
991 /* End: */