blob: a52afacaad1d24206bbc34eb4d936012609538a0 [file] [log] [blame]
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00001/*
2 * Help Viewer
3 *
4 * Copyright 1996 Ulrich Schmid
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard1285c2f1996-05-06 16:06:24 +000019 */
20
21#include <stdio.h>
Niels Kristian Bech Jensen52be93c2000-03-19 21:49:49 +000022#include <string.h>
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000023#include "windows.h"
Niels Kristian Bech Jensen52be93c2000-03-19 21:49:49 +000024#include "windowsx.h"
Alexandre Julliard1285c2f1996-05-06 16:06:24 +000025#include "winhelp.h"
26
27static void Report(LPCSTR str)
28{
29#if 0
30 fprintf(stderr, "%s\n", str);
31#endif
32}
33
34#define GET_USHORT(buffer, i)\
35(((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
36#define GET_SHORT(buffer, i)\
37(((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
38#define GET_UINT(buffer, i)\
39GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i+2)
40
41static BOOL HLPFILE_DoReadHlpFile(HLPFILE*, LPCSTR);
42static BOOL HLPFILE_ReadFileToBuffer(HFILE);
43static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE**, BYTE**);
44static VOID HLPFILE_SystemCommands(HLPFILE*);
45static BOOL HLPFILE_Uncompress1_Phrases();
46static BOOL HLPFILE_Uncompress1_Topic();
47static BOOL HLPFILE_GetContext(HLPFILE*);
48static BOOL HLPFILE_AddPage(HLPFILE*, BYTE*, BYTE*);
49static BOOL HLPFILE_AddParagraph(HLPFILE*, BYTE *, BYTE*);
50static UINT HLPFILE_Uncompressed2_Size(BYTE*, BYTE*);
51static VOID HLPFILE_Uncompress2(BYTE**, BYTE*, BYTE*);
52
53static HLPFILE *first_hlpfile = 0;
54static HGLOBAL hFileBuffer;
55static BYTE *file_buffer;
56
57static struct
58{
59 UINT num;
60 BYTE *buf;
61 HGLOBAL hBuffer;
62} phrases;
63
64static struct
65{
66 BYTE **map;
67 BYTE *end;
68 UINT wMapLen;
69 HGLOBAL hMap;
70 HGLOBAL hBuffer;
71} topic;
72
73static struct
74{
75 UINT bDebug;
76 UINT wFont;
77 UINT wIndent;
78 UINT wHSpace;
79 UINT wVSpace;
80 UINT wVBackSpace;
81 HLPFILE_LINK link;
82} attributes;
83
84/***********************************************************************
85 *
86 * HLPFILE_Contents
87 */
88
89HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath)
90{
91 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
92
93 if (!hlpfile) return(0);
94
95 return(hlpfile->first_page);
96}
97
98/***********************************************************************
99 *
100 * HLPFILE_PageByNumber
101 */
102
103HLPFILE_PAGE *HLPFILE_PageByNumber(LPCSTR lpszPath, UINT wNum)
104{
105 HLPFILE_PAGE *page;
106 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
107
108 if (!hlpfile) return(0);
109
110 for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
111
112 return page;
113}
114
115/***********************************************************************
116 *
117 * HLPFILE_HlpFilePageByHash
118 */
119
120HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG lHash)
121{
122 INT i;
123 UINT wNum;
124 HLPFILE_PAGE *page;
125 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
126
127 if (!hlpfile) return(0);
128
129 for (i = 0; i < hlpfile->wContextLen; i++)
130 if (hlpfile->Context[i].lHash == lHash) break;
131
132 if (i >= hlpfile->wContextLen)
133 {
134 HLPFILE_FreeHlpFile(hlpfile);
135 return(0);
136 }
137
138 wNum = hlpfile->Context[i].wPage;
139 for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
140
141 return page;
142}
143
144/***********************************************************************
145 *
146 * HLPFILE_Hash
147 */
148
149LONG HLPFILE_Hash(LPCSTR lpszContext)
150{
151 LONG lHash = 0;
152 CHAR c;
153 while((c = *lpszContext++))
154 {
155 CHAR x = 0;
156 if (c >= 'A' && c <= 'Z') x = c - 'A' + 17;
157 if (c >= 'a' && c <= 'z') x = c - 'a' + 17;
158 if (c >= '1' && c <= '9') x = c - '0';
159 if (c == '0') x = 10;
160 if (c == '.') x = 12;
161 if (c == '_') x = 13;
162 if (x) lHash = lHash * 43 + x;
163 }
164 return lHash;
165}
166
167/***********************************************************************
168 *
169 * HLPFILE_ReadHlpFile
170 */
171
172HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
173{
174 HGLOBAL hHlpFile;
175 HLPFILE *hlpfile;
176
177 for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
178 if (!lstrcmp(hlpfile->lpszPath, lpszPath))
179 {
180 hlpfile->wRefCount++;
181 return(hlpfile);
182 }
183
184 hHlpFile = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
185 if (!hHlpFile) return(0);
186
187 hlpfile = GlobalLock(hHlpFile);
188 hlpfile->hSelf = hHlpFile;
189 hlpfile->wRefCount = 1;
190 hlpfile->hTitle = 0;
191 hlpfile->hContext = 0;
192 hlpfile->wContextLen = 0;
193 hlpfile->first_page = 0;
194 hlpfile->first_macro = 0;
195 hlpfile->prev = 0;
196 hlpfile->next = first_hlpfile;
197 first_hlpfile = hlpfile;
198 if (hlpfile->next) hlpfile->next->prev = hlpfile;
199
200 hlpfile->lpszPath = GlobalLock(hHlpFile);
201 hlpfile->lpszPath += sizeof(HLPFILE);
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000202 strcpy(hlpfile->lpszPath, lpszPath);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000203
204 phrases.hBuffer = topic.hBuffer = hFileBuffer = 0;
205
206 if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
207 {
208 HLPFILE_FreeHlpFile(hlpfile);
209 hlpfile = 0;
210 }
211
212 if (phrases.hBuffer) GlobalFree(phrases.hBuffer);
213 if (topic.hBuffer) GlobalFree(topic.hBuffer);
214 if (topic.hMap) GlobalFree(topic.hMap);
215 if (hFileBuffer) GlobalFree(hFileBuffer);
216
217 return(hlpfile);
218}
219
220/***********************************************************************
221 *
222 * HLPFILE_DoReadHlpFile
223 */
224
225static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
226{
227 BOOL ret;
228 HFILE hFile;
229 OFSTRUCT ofs;
230 BYTE *buf;
231
232 hFile=OpenFile(lpszPath, &ofs, OF_READ | OF_SEARCH);
233 if (hFile == HFILE_ERROR) return FALSE;
234
235 ret = HLPFILE_ReadFileToBuffer(hFile);
236 _lclose(hFile);
237 if (!ret) return FALSE;
238
239 HLPFILE_SystemCommands(hlpfile);
240 if (!HLPFILE_Uncompress1_Phrases()) return FALSE;
241 if (!HLPFILE_Uncompress1_Topic()) return FALSE;
242
243 buf = topic.map[0] + 0xc;
244 while(buf + 0xc < topic.end)
245 {
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000246 BYTE *end = min(buf + GET_UINT(buf, 0), topic.end);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000247 UINT next, index, offset;
248
249 switch (buf[0x14])
250 {
251 case 0x02:
252 if (!HLPFILE_AddPage(hlpfile, buf, end)) return(FALSE);
253 break;
254
255 case 0x20:
256 if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
257 break;
258
259 case 0x23:
260 if (!HLPFILE_AddParagraph(hlpfile, buf, end)) return(FALSE);
261 break;
262
263 default:
264 fprintf(stderr, "buf[0x14] = %x\n", buf[0x14]);
265 }
266
267 next = GET_UINT(buf, 0xc);
268 if (next == 0xffffffff) break;
269
270 index = next >> 14;
271 offset = next & 0x3fff;
272 if (index > topic.wMapLen) {Report("maplen"); break;}
273 buf = topic.map[index] + offset;
274 }
275
276 return(HLPFILE_GetContext(hlpfile));
277}
278
279/***********************************************************************
280 *
281 * HLPFILE_AddPage
282 */
283
284static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
285{
286 HGLOBAL hPage;
287 HLPFILE_PAGE *page, **pageptr;
288 BYTE *title;
289 UINT titlesize;
290
291 for (pageptr = &hlpfile->first_page; *pageptr; pageptr = &(*pageptr)->next)
292 /* Nothing */;
293
294 if (buf + 0x31 > end) {Report("page1"); return(FALSE);};
295 title = buf + GET_UINT(buf, 0x10);
296 if (title > end) {Report("page2"); return(FALSE);};
297
298 titlesize = HLPFILE_Uncompressed2_Size(title, end);
299 hPage = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PAGE) + titlesize);
300 if (!hPage) return FALSE;
301 page = *pageptr = GlobalLock(hPage);
302 pageptr = &page->next;
303 page->hSelf = hPage;
304 page->file = hlpfile;
305 page->next = 0;
306 page->first_paragraph = 0;
307
308 page->lpszTitle = GlobalLock(hPage);
309 page->lpszTitle += sizeof(HLPFILE_PAGE);
310 HLPFILE_Uncompress2(&title, end, page->lpszTitle);
311
312 page->wNumber = GET_UINT(buf, 0x21);
313
314 attributes.bDebug = 0;
315 attributes.wFont = 0;
316 attributes.wVSpace = 0;
317 attributes.wVBackSpace = 0;
318 attributes.wHSpace = 0;
319 attributes.wIndent = 0;
320 attributes.link.lpszPath = 0;
321
322 return TRUE;
323}
324
325/***********************************************************************
326 *
327 * HLPFILE_AddParagraph
328 */
329
330static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end)
331{
332 HGLOBAL hParagraph;
333 HLPFILE_PAGE *page;
334 HLPFILE_PARAGRAPH *paragraph, **paragraphptr;
335 UINT textsize;
336 BYTE *format, *text;
337 BOOL format_header = TRUE;
338 BOOL format_end = FALSE;
339 UINT mask, i;
340
341 if (!hlpfile->first_page) {Report("paragraph1"); return(FALSE);};
342
343 for (page = hlpfile->first_page; page->next; page = page->next) /* Nothing */;
344 for (paragraphptr = &page->first_paragraph; *paragraphptr;
345 paragraphptr = &(*paragraphptr)->next) /* Nothing */;
346
347 if (buf + 0x19 > end) {Report("paragraph2"); return(FALSE);};
348
349 if (buf[0x14] == 0x02) return TRUE;
350
351 text = buf + GET_UINT(buf, 0x10);
352
353 switch (buf[0x14])
354 {
355 case 0x20:
356 format = buf + 0x18;
357 while (*format) format++;
358 format += 4;
359 break;
360
361 case 0x23:
362 format = buf + 0x2b;
363 if (buf[0x17] & 1) format++;
364 break;
365
366 default:
367 Report("paragraph3");
368 return FALSE;
369 }
370
371 while (text < end)
372 {
373 if (format_header)
374 {
375 format_header = FALSE;
376
377 mask = GET_USHORT(format, 0);
378 mask &= 0x3ff;
379 format += 2;
380
381 for (i = 0; i < 10; i++, mask = mask >> 1)
382 {
383 if (mask & 1)
384 {
385 BOOL twoargs = FALSE;
386 CHAR prefix0 = ' ';
387 CHAR prefix1 = '*';
388
389 if (i == 9 && !twoargs)
390 {
391 switch (*format++)
392 {
393 default:
394 prefix0 = prefix1 = '?';
395 break;
396
397 case 0x82:
398 prefix0 = prefix1 = 'x';
399 break;
400
401 case 0x84:
402 prefix0 = prefix1 = 'X';
403 twoargs = TRUE;
404 }
405 }
406
407 if (*format & 1)
408 switch(*format)
409 {
410 default:
411 format += 2;
412 break;
413 }
414 else
415 switch(*format)
416 {
417
418 default:
419 format++;
420 break;
421
422 case 0x08:
423 format += 3;
424 break;
425 }
426
427 if (twoargs) format += (*format & 1) ? 2 : 1;
428 }
429 }
430 }
431
432 for (; !format_header && text < end && format < end && !*text; text++)
433 {
434 switch(*format)
435 {
436 case 0x80:
437 attributes.wFont = GET_USHORT(format, 1);
438 format += 3;
439 break;
440
441 case 0x81:
442 attributes.wVSpace++;
443 format += 1;
444 break;
445
446 case 0x82:
447 attributes.wVSpace += 2 - attributes.wVBackSpace;
448 attributes.wVBackSpace = 0;
449 attributes.wIndent = 0;
450 format += 1;
451 break;
452
453 case 0x83:
454 attributes.wIndent++;
455 format += 1;
456 break;
457
458 case 0x84:
459 format += 3;
460 break;
461
462 case 0x86:
463 case 0x87:
464 case 0x88:
465 format += 9;
466 break;
467
468 case 0x89:
469 attributes.wVBackSpace++;
470 format += 1;
471 break;
472
473 case 0xa9:
474 format += 2;
475 break;
476
477 case 0xe2:
478 case 0xe3:
479 attributes.link.lpszPath = hlpfile->lpszPath;
480 attributes.link.lHash = GET_UINT(format, 1);
481 attributes.link.bPopup = !(*format & 1);
482 format += 5;
483 break;
484
485 case 0xea:
486 attributes.link.lpszPath = format + 8;
487 attributes.link.lHash = GET_UINT(format, 4);
488 attributes.link.bPopup = !(*format & 1);
489 format += 3 + GET_USHORT(format, 1);
490 break;
491
492 case 0xff:
493 if (buf[0x14] != 0x23 || GET_USHORT(format, 1) == 0xffff)
494 {
495 if (format_end) Report("format_end");
496 format_end = TRUE;
497 break;
498 }
499 else
500 {
501 format_header = TRUE;
502 format += 10;
503 break;
504 }
505
506 default:
507 Report("format");
508 format++;
509 }
510 }
511
512 if (text > end || format > end) {Report("paragraph_end"); return(FALSE);};
513 if (text == end && !format_end) Report("text_end");
514
515 if (text == end) break;
516
517 textsize = HLPFILE_Uncompressed2_Size(text, end);
518 hParagraph = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_PARAGRAPH) + textsize);
519 if (!hParagraph) return FALSE;
520 paragraph = *paragraphptr = GlobalLock(hParagraph);
521 paragraphptr = &paragraph->next;
522 paragraph->hSelf = hParagraph;
523 paragraph->next = 0;
524 paragraph->link = 0;
525
526 paragraph->lpszText = GlobalLock(hParagraph);
527 paragraph->lpszText += sizeof(HLPFILE_PARAGRAPH);
528 HLPFILE_Uncompress2(&text, end, paragraph->lpszText);
529
530 paragraph->bDebug = attributes.bDebug;
531 paragraph->wFont = attributes.wFont;
532 paragraph->wVSpace = attributes.wVSpace;
533 paragraph->wHSpace = attributes.wHSpace;
534 paragraph->wIndent = attributes.wIndent;
535 if (attributes.link.lpszPath)
536 {
537 LPSTR ptr;
538 HGLOBAL handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_LINK) +
539 strlen(attributes.link.lpszPath) + 1);
540 if (!handle) return FALSE;
541 paragraph->link = GlobalLock(handle);
542 paragraph->link->hSelf = handle;
543
544 ptr = GlobalLock(handle);
545 ptr += sizeof(HLPFILE_LINK);
546 lstrcpy(ptr, (LPSTR) attributes.link.lpszPath);
547
548 paragraph->link->lpszPath = ptr;
549 paragraph->link->lHash = attributes.link.lHash;
550 paragraph->link->bPopup = attributes.link.bPopup;
551 }
552
553 attributes.bDebug = 0;
554 attributes.wVSpace = 0;
555 attributes.wHSpace = 0;
556 attributes.link.lpszPath = 0;
557 }
558
559 return TRUE;
560}
561
562/***********************************************************************
563 *
564 * HLPFILE_ReadFileToBuffer
565 */
566
567static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
568{
569 BYTE header[16], dummy[1];
570 UINT size;
571
572 if (_hread(hFile, header, 16) != 16) {Report("header"); return(FALSE);};
573
574 size = GET_UINT(header, 12);
575 hFileBuffer = GlobalAlloc(GMEM_FIXED, size + 1);
576 if (!hFileBuffer) return FALSE;
577 file_buffer = GlobalLock(hFileBuffer);
578
579 memcpy(file_buffer, header, 16);
580 if (_hread(hFile, file_buffer + 16, size - 16) != size - 16)
581 {Report("filesize1"); return(FALSE);};
582
583 if (_hread(hFile, dummy, 1) != 0) Report("filesize2");
584
585 file_buffer[size] = '0';
586
587 return TRUE;
588}
589
590/***********************************************************************
591 *
592 * HLPFILE_FindSubFile
593 */
594
595static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE **subbuf, BYTE **subend)
596{
597 BYTE *root = file_buffer + GET_UINT(file_buffer, 4);
598 BYTE *end = file_buffer + GET_UINT(file_buffer, 12);
599 BYTE *ptr = root + 0x37;
600
601 while (ptr < end && ptr[0] == 0x7c)
602 {
603 BYTE *fname = ptr + 1;
604 ptr += strlen(ptr) + 1;
605 if (!lstrcmpi(fname, name))
606 {
607 *subbuf = file_buffer + GET_UINT(ptr, 0);
608 *subend = *subbuf + GET_UINT(*subbuf, 0);
609 if (file_buffer > *subbuf || *subbuf > *subend || *subend >= end)
610 {
611 Report("subfile");
612 return FALSE;
613 }
614 return TRUE;
615 }
616 else ptr += 4;
617 }
618 return FALSE;
619}
620
621/***********************************************************************
622 *
623 * HLPFILE_SystemCommands
624 */
625static VOID HLPFILE_SystemCommands(HLPFILE* hlpfile)
626{
627 BYTE *buf, *ptr, *end;
628 HGLOBAL handle;
629 HLPFILE_MACRO *macro, **m;
630 LPSTR p;
631
632 hlpfile->lpszTitle = "";
633
634 if (!HLPFILE_FindSubFile("SYSTEM", &buf, &end)) return;
635
636 for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4)
637 {
638 switch (GET_USHORT(ptr, 0))
639 {
640 case 1:
641 if (hlpfile->hTitle) {Report("title"); break;}
642 hlpfile->hTitle = GlobalAlloc(GMEM_FIXED, strlen(ptr + 4) + 1);
643 if (!hlpfile->hTitle) return;
644 hlpfile->lpszTitle = GlobalLock(hlpfile->hTitle);
645 lstrcpy(hlpfile->lpszTitle, ptr + 4);
646 break;
647
648 case 2:
649 if (GET_USHORT(ptr, 2) != 1 || ptr[4] != 0) Report("system2");
650 break;
651
652 case 3:
653 if (GET_USHORT(ptr, 2) != 4 || GET_UINT(ptr, 4) != 0) Report("system3");
654 break;
655
656 case 4:
657 handle = GlobalAlloc(GMEM_FIXED, sizeof(HLPFILE_MACRO) + lstrlen(ptr + 4) + 1);
658 if (!handle) break;
659 macro = GlobalLock(handle);
660 macro->hSelf = handle;
661 p = GlobalLock(handle);
662 p += sizeof(HLPFILE_MACRO);
663 lstrcpy(p, (LPSTR) ptr + 4);
664 macro->lpszMacro = p;
665 macro->next = 0;
Alexandre Julliard566a52a2001-03-05 19:34:17 +0000666 m = &hlpfile->first_macro;
667 while (*m) m = &(*m)->next;
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000668 *m = macro;
669 break;
670
671 default:
672 Report("system");
673 }
674 }
675}
676
677/***********************************************************************
678 *
679 * HLPFILE_Uncompressed1_Size
680 */
681
682static INT HLPFILE_Uncompressed1_Size(BYTE *ptr, BYTE *end)
683{
684 INT i, newsize = 0;
685
686 while (ptr < end)
687 {
688 INT mask=*ptr++;
689 for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
690 {
691 if (mask & 1)
692 {
693 INT code = GET_USHORT(ptr, 0);
694 INT len = 3 + (code >> 12);
695 newsize += len;
696 ptr += 2;
697 }
698 else newsize++, ptr++;
699 }
700 }
701
702 return(newsize);
703}
704
705/***********************************************************************
706 *
707 * HLPFILE_Uncompress1
708 */
709
710static BYTE *HLPFILE_Uncompress1(BYTE *ptr, BYTE *end, BYTE *newptr)
711{
712 INT i;
713
714 while (ptr < end)
715 {
716 INT mask=*ptr++;
717 for (i = 0; i < 8 && ptr < end; i++, mask = mask >> 1)
718 {
719 if (mask & 1)
720 {
721 INT code = GET_USHORT(ptr, 0);
722 INT len = 3 + (code >> 12);
723 INT offset = code & 0xfff;
Rein Klazes9cc9d592000-06-20 20:34:11 +0000724 memcpy(newptr, newptr - offset - 1, len);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000725 newptr += len;
726 ptr += 2;
727 }
728 else *newptr++ = *ptr++;
729 }
730 }
731
732 return(newptr);
733}
734
735/***********************************************************************
736 *
737 * HLPFILE_Uncompress1_Phrases
738 */
739
740static BOOL HLPFILE_Uncompress1_Phrases()
741{
742 UINT i, num, newsize;
743 BYTE *buf, *end, *newbuf;
744
745 if (!HLPFILE_FindSubFile("Phrases", &buf, &end)) {Report("phrases0"); return FALSE;}
746
747 num = phrases.num = GET_USHORT(buf, 9);
748 if (buf + 2 * num + 0x13 >= end) {Report("uncompress1a"); return(FALSE);};
749
750 newsize = 2 * num + 2;
751 newsize += HLPFILE_Uncompressed1_Size(buf + 0x13 + 2 * num, end);
752 phrases.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
753 if (!phrases.hBuffer) return FALSE;
754 newbuf = phrases.buf = GlobalLock(phrases.hBuffer);
755
Rein Klazes9cc9d592000-06-20 20:34:11 +0000756 memcpy(newbuf, buf + 0x11, 2 * num + 2);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000757 HLPFILE_Uncompress1(buf + 0x13 + 2 * num, end, newbuf + 2 * num + 2);
758
759 for (i = 0; i < num; i++)
760 {
761 INT i0 = GET_USHORT(newbuf, 2 * i);
762 INT i1 = GET_USHORT(newbuf, 2 * i + 2);
763 if (i1 < i0 || i1 > newsize) {Report("uncompress1b"); return(FALSE);};
764 }
765 return TRUE;
766}
767
768/***********************************************************************
769 *
770 * HLPFILE_Uncompress1_Topic
771 */
772
773static BOOL HLPFILE_Uncompress1_Topic()
774{
775 BYTE *buf, *ptr, *end, *newptr;
776 INT i, newsize = 0;
777
778 if (!HLPFILE_FindSubFile("TOPIC", &buf, &end)) {Report("topic0"); return FALSE;}
779
780 buf += 9;
781 topic.wMapLen = (end - buf - 1) / 0x1000 + 1;
782
783 for (i = 0; i < topic.wMapLen; i++)
784 {
785 ptr = buf + i * 0x1000;
786
787 /* I don't know why, it's necessary for printman.hlp */
788 if (ptr + 0x44 > end) ptr = end - 0x44;
789
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000790 newsize += HLPFILE_Uncompressed1_Size(ptr + 0xc, min(end, ptr + 0x1000));
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000791 }
792
793 topic.hMap = GlobalAlloc(GMEM_FIXED, topic.wMapLen * sizeof(topic.map[0]));
794 topic.hBuffer = GlobalAlloc(GMEM_FIXED, newsize);
795 if (!topic.hMap || !topic.hBuffer) return FALSE;
796 topic.map = GlobalLock(topic.hMap);
797 newptr = GlobalLock(topic.hBuffer);
798 topic.end = newptr + newsize;
799
800 for (i = 0; i < topic.wMapLen; i++)
801 {
802 ptr = buf + i * 0x1000;
803 if (ptr + 0x44 > end) ptr = end - 0x44;
804
805 topic.map[i] = newptr - 0xc;
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000806 newptr = HLPFILE_Uncompress1(ptr + 0xc, min(end, ptr + 0x1000), newptr);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000807 }
808
809 return TRUE;
810}
811
812/***********************************************************************
813 *
814 * HLPFILE_Uncompressed2_Size
815 */
816
817static UINT HLPFILE_Uncompressed2_Size(BYTE *ptr, BYTE *end)
818{
819 UINT wSize = 0;
820
821 while (ptr < end && *ptr)
822 {
823 if (*ptr >= 0x20)
824 wSize++, ptr++;
825 else
826 {
827 BYTE *phptr, *phend;
828 UINT code = 0x100 * ptr[0] + ptr[1];
829 UINT index = (code - 0x100) / 2;
830 BOOL space = code & 1;
831
832 if (index < phrases.num)
833 {
834 phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
835 phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
836
837 if (phend < phptr) Report("uncompress2a");
838
839 wSize += phend - phptr;
840 if (space) wSize++;
841 }
842 else Report("uncompress2b");
843
844 ptr += 2;
845 }
846 }
847
848 return(wSize + 1);
849}
850
851/***********************************************************************
852 *
853 * HLPFILE_Uncompress2
854 */
855
856static VOID HLPFILE_Uncompress2(BYTE **pptr, BYTE *end, BYTE *newptr)
857{
858 BYTE *ptr = *pptr;
859
860 while (ptr < end && *ptr)
861 {
862 if (*ptr >= 0x20)
863 *newptr++ = *ptr++;
864 else
865 {
866 BYTE *phptr, *phend;
867 UINT code = 0x100 * ptr[0] + ptr[1];
868 UINT index = (code - 0x100) / 2;
869 BOOL space = code & 1;
870
871 phptr = phrases.buf + GET_USHORT(phrases.buf, 2 * index);
872 phend = phrases.buf + GET_USHORT(phrases.buf, 2 * index + 2);
873
Rein Klazes9cc9d592000-06-20 20:34:11 +0000874 memcpy(newptr, phptr, phend - phptr);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000875 newptr += phend - phptr;
876 if (space) *newptr++ = ' ';
877
878 ptr += 2;
879 }
880 }
881 *newptr = '\0';
882 *pptr = ptr;
883}
884
885/***********************************************************************
886 *
887 * HLPFILE_GetContext
888 */
889
890static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
891{
892 UINT i, j, clen, tlen;
893 BYTE *cbuf, *cptr, *cend, *tbuf, *tptr, *tend;
894
895 if (!HLPFILE_FindSubFile("CONTEXT", &cbuf, &cend)) {Report("context0"); return FALSE;}
896 if (cbuf + 0x37 > cend) {Report("context1"); return(FALSE);};
897 clen = GET_UINT(cbuf, 0x2b);
898 if (cbuf + 0x37 + 8 * hlpfile->wContextLen > cend) {Report("context2"); return(FALSE);};
899
900 if (!HLPFILE_FindSubFile("TTLBTREE", &tbuf, &tend)) {Report("ttlb0"); return FALSE;}
901 if (tbuf + 0x37 > tend) {Report("ttlb1"); return(FALSE);};
902 tlen = GET_UINT(tbuf, 0x2b);
903
904 hlpfile->hContext = GlobalAlloc(GMEM_FIXED, clen * sizeof(HLPFILE_CONTEXT));
905 if (!hlpfile->hContext) return FALSE;
906 hlpfile->Context = GlobalLock(hlpfile->hContext);
907 hlpfile->wContextLen = clen;
908
909 cptr = cbuf + 0x37;
910 for (i = 0; i < clen; i++, cptr += 8)
911 {
912 tptr = tbuf + 0x37;
913 for (j = 0; j < tlen; j++, tptr += 5 + strlen(tptr + 4))
914 {
915 if (tptr + 4 >= tend) {Report("ttlb2"); return(FALSE);};
916 if (GET_UINT(tptr, 0) == GET_UINT(cptr, 4)) break;
917 }
918 if (j >= tlen)
919 {
920 Report("ttlb3");
921 j = 0;
922 }
923 hlpfile->Context[i].lHash = GET_UINT(cptr, 0);
924 hlpfile->Context[i].wPage = j;
925 }
926
927 return TRUE;
928}
929
930/***********************************************************************
931 *
932 * HLPFILE_DeleteParagraph
933 */
934
935static VOID HLPFILE_DeleteParagraph(HLPFILE_PARAGRAPH* paragraph)
936{
937 if (!paragraph) return;
938
939 if (paragraph->link) GlobalFree(paragraph->link->hSelf);
940
941 HLPFILE_DeleteParagraph(paragraph->next);
942 GlobalFree(paragraph->hSelf);
943}
944
945/***********************************************************************
946 *
947 * DeletePage
948 */
949
950static VOID HLPFILE_DeletePage(HLPFILE_PAGE* page)
951{
952 if (!page) return;
953
954 HLPFILE_DeletePage(page->next);
955 HLPFILE_DeleteParagraph(page->first_paragraph);
956 GlobalFree(page->hSelf);
957}
958
959/***********************************************************************
960 *
961 * DeleteMacro
962 */
963
964static VOID HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
965{
966 if (!macro) return;
967
968 HLPFILE_DeleteMacro(macro->next);
969 GlobalFree(macro->hSelf);
970}
971
972/***********************************************************************
973 *
974 * HLPFILE_FreeHlpFile
975 */
976
977VOID HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
978{
979 if (!hlpfile) return;
980 if (--hlpfile->wRefCount) return;
981
982 if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
983 if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
984 else first_hlpfile = 0;
985
986 HLPFILE_DeletePage(hlpfile->first_page);
987 HLPFILE_DeleteMacro(hlpfile->first_macro);
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000988 if (hlpfile->hContext) GlobalFree(hlpfile->hContext);
989 if (hlpfile->hTitle) GlobalFree(hlpfile->hTitle);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000990 GlobalFree(hlpfile->hSelf);
991}
992
993/***********************************************************************
994 *
995 * FreeHlpFilePage
996 */
997
998VOID HLPFILE_FreeHlpFilePage(HLPFILE_PAGE* page)
999{
1000 if (!page) return;
1001 HLPFILE_FreeHlpFile(page->file);
1002}
1003
1004/* Local Variables: */
1005/* c-file-style: "GNU" */
1006/* End: */