4 * Copyright 1996 Ulrich Schmid
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(winhelp);
32 #define GET_USHORT(buffer, i)\
33 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
34 #define GET_SHORT(buffer, i)\
35 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
36 #define GET_UINT(buffer, i)\
37 GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i+2)
39 static HLPFILE *first_hlpfile = 0;
40 static BYTE *file_buffer;
69 static BOOL HLPFILE_DoReadHlpFile(HLPFILE*, LPCSTR);
70 static BOOL HLPFILE_ReadFileToBuffer(HFILE);
71 static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE**, BYTE**);
72 static BOOL HLPFILE_SystemCommands(HLPFILE*);
73 static INT HLPFILE_UncompressedLZ77_Size(BYTE *ptr, BYTE *end);
74 static BYTE* HLPFILE_UncompressLZ77(BYTE *ptr, BYTE *end, BYTE *newptr);
75 static BOOL HLPFILE_UncompressLZ77_Phrases(HLPFILE*);
76 static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE*);
77 static BOOL HLPFILE_UncompressLZ77_Topic(HLPFILE*);
78 static BOOL HLPFILE_GetContext(HLPFILE*);
79 static BOOL HLPFILE_AddPage(HLPFILE*, BYTE*, BYTE*, unsigned);
80 static BOOL HLPFILE_AddParagraph(HLPFILE*, BYTE *, BYTE*, unsigned*);
81 static UINT HLPFILE_Uncompressed2_Size(BYTE*, BYTE*);
82 static void HLPFILE_Uncompress2(BYTE**, BYTE*, BYTE*);
83 static BOOL HLPFILE_Uncompress3(char*, const char*, const BYTE*, const BYTE*);
84 static void HLPFILE_UncompressRLE(const BYTE* src, unsigned sz, BYTE** dst);
85 static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile);
87 /***********************************************************************
91 HLPFILE_PAGE *HLPFILE_Contents(LPCSTR lpszPath)
93 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
95 if (!hlpfile) return 0;
97 return hlpfile->first_page;
100 /***********************************************************************
102 * HLPFILE_PageByNumber
104 HLPFILE_PAGE *HLPFILE_PageByNumber(LPCSTR lpszPath, UINT wNum)
107 HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath);
109 if (!hlpfile) return 0;
111 WINE_TRACE("[%s/%u]\n", lpszPath, wNum);
113 for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--;
118 /***********************************************************************
120 * HLPFILE_HlpFilePageByHash
122 HLPFILE_PAGE *HLPFILE_PageByHash(LPCSTR lpszPath, LONG lHash)
126 HLPFILE* hlpfile = HLPFILE_ReadHlpFile(lpszPath);
129 WINE_TRACE("path<%s>[%lx]\n", lpszPath, lHash);
131 if (!hlpfile) return 0;
134 for (i = 0; i < hlpfile->wContextLen; i++)
136 if (hlpfile->Context[i].lHash != lHash) continue;
139 * this finds the page containing the offset. The offset can either
140 * refer to the top of the page (offset == page->offset), or
141 * to some paragraph inside the page...
142 * As of today, we only return the page... we should also return
143 * a paragraph, and then, while opening a new page, compute the
144 * y-offset of the paragraph to be shown and scroll the window
148 for (page = hlpfile->first_page; page; page = page->next)
150 if (page->offset <= hlpfile->Context[i].offset)
152 if (!found || found->offset < page->offset)
156 if (found) return found;
158 WINE_ERR("Page of offset %lu not found in file %s\n",
159 hlpfile->Context[i].offset, lpszPath);
162 WINE_ERR("Page of hash %lx not found in file %s\n", lHash, lpszPath);
166 /***********************************************************************
170 LONG HLPFILE_Hash(LPCSTR lpszContext)
175 while ((c = *lpszContext++))
178 if (c >= 'A' && c <= 'Z') x = c - 'A' + 17;
179 if (c >= 'a' && c <= 'z') x = c - 'a' + 17;
180 if (c >= '1' && c <= '9') x = c - '0';
181 if (c == '0') x = 10;
182 if (c == '.') x = 12;
183 if (c == '_') x = 13;
184 if (x) lHash = lHash * 43 + x;
189 /***********************************************************************
191 * HLPFILE_ReadHlpFile
193 HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)
197 for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
199 if (!lstrcmp(hlpfile->lpszPath, lpszPath))
201 hlpfile->wRefCount++;
206 hlpfile = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE) + lstrlen(lpszPath) + 1);
207 if (!hlpfile) return 0;
209 hlpfile->wRefCount = 1;
210 hlpfile->Context = NULL;
211 hlpfile->wContextLen = 0;
212 hlpfile->first_page = NULL;
213 hlpfile->first_macro = NULL;
214 hlpfile->prev = NULL;
215 hlpfile->next = first_hlpfile;
216 hlpfile->lpszPath = (char*)hlpfile + sizeof(HLPFILE);
217 hlpfile->lpszTitle = NULL;
219 hlpfile->numFonts = 0;
220 hlpfile->fonts = NULL;
222 strcpy(hlpfile->lpszPath, lpszPath);
224 first_hlpfile = hlpfile;
225 if (hlpfile->next) hlpfile->next->prev = hlpfile;
227 phrases.offsets = NULL;
228 phrases.buffer = NULL;
233 if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
235 HLPFILE_FreeHlpFile(hlpfile);
239 if (phrases.offsets) HeapFree(GetProcessHeap(), 0, phrases.offsets);
240 if (phrases.buffer) HeapFree(GetProcessHeap(), 0, phrases.buffer);
241 if (topic.map) HeapFree(GetProcessHeap(), 0, topic.map);
242 if (file_buffer) HeapFree(GetProcessHeap(), 0, file_buffer);
247 /***********************************************************************
249 * HLPFILE_DoReadHlpFile
251 static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
258 unsigned index, old_index, offset, len, offs;
260 hFile = OpenFile(lpszPath, &ofs, OF_READ | OF_SEARCH);
261 if (hFile == HFILE_ERROR) return FALSE;
263 ret = HLPFILE_ReadFileToBuffer(hFile);
265 if (!ret) return FALSE;
267 if (!HLPFILE_SystemCommands(hlpfile)) return FALSE;
268 if (!HLPFILE_UncompressLZ77_Phrases(hlpfile) &&
269 !HLPFILE_Uncompress_Phrases40(hlpfile))
271 if (!HLPFILE_UncompressLZ77_Topic(hlpfile)) return FALSE;
272 if (!HLPFILE_ReadFont(hlpfile)) return FALSE;
281 /* FIXME this depends on the blocksize, can be 2k in some cases */
282 index = (ref - 0x0C) >> 14;
283 offset = (ref - 0x0C) & 0x3fff;
285 WINE_TRACE("ref=%08lx => [%u/%u]\n", ref, index, offset);
287 if (index >= topic.wMapLen) {WINE_WARN("maplen\n"); break;}
288 buf = topic.map[index] + offset;
289 if (buf + 0x15 >= topic.end) {WINE_WARN("extra\n"); break;}
290 end = min(buf + GET_UINT(buf, 0), topic.end);
291 if (index != old_index) {offs = 0; old_index = index;}
296 if (!HLPFILE_AddPage(hlpfile, buf, end, index * 0x8000L + offs)) return FALSE;
300 if (!HLPFILE_AddParagraph(hlpfile, buf, end, &len)) return FALSE;
305 if (!HLPFILE_AddParagraph(hlpfile, buf, end, &len)) return FALSE;
310 WINE_ERR("buf[0x14] = %x\n", buf[0x14]);
313 ref = GET_UINT(buf, 0xc);
314 } while (ref != 0xffffffff);
316 return HLPFILE_GetContext(hlpfile);
319 /***********************************************************************
323 static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigned offset)
329 if (buf + 0x31 > end) {WINE_WARN("page1\n"); return FALSE;};
330 title = buf + GET_UINT(buf, 0x10);
331 if (title > end) {WINE_WARN("page2\n"); return FALSE;};
333 if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10))
335 if (hlpfile->hasPhrases)
337 titlesize = HLPFILE_Uncompressed2_Size(title, end);
338 page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize);
339 if (!page) return FALSE;
341 page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
342 HLPFILE_Uncompress2(&title, end, page->lpszTitle);
346 titlesize = GET_UINT(buf, 4) + 1;
347 page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize);
348 if (!page) return FALSE;
349 page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
351 HLPFILE_Uncompress3(page->lpszTitle, page->lpszTitle + titlesize, title, end);
356 titlesize = GET_UINT(buf, 0x4);
357 page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize);
358 if (!page) return FALSE;
360 page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
361 memcpy(page->lpszTitle, title, titlesize);
364 if (hlpfile->first_page)
368 for (p = hlpfile->first_page; p->next; p = p->next);
374 hlpfile->first_page = page;
378 page->file = hlpfile;
380 page->first_paragraph = NULL;
381 page->wNumber = GET_UINT(buf, 0x21);
382 page->offset = offset;
384 WINE_TRACE("Added page[%d]: title='%s' offset=%08x\n",
385 page->wNumber, page->lpszTitle, page->offset);
387 memset(&attributes, 0, sizeof(attributes));
392 static long fetch_long(BYTE** ptr)
398 ret = (*(unsigned long*)(*ptr) - 0x80000000L) / 2;
403 ret = (*(unsigned short*)(*ptr) - 0x8000) / 2;
410 static unsigned long fetch_ulong(BYTE** ptr)
416 ret = *(unsigned long*)(*ptr) / 2;
421 ret = *(unsigned short*)(*ptr) / 2;
427 static short fetch_short(BYTE** ptr)
433 ret = (*(unsigned short*)(*ptr) - 0x8000) / 2;
438 ret = (*(unsigned char*)(*ptr) - 0x80) / 2;
444 static unsigned short fetch_ushort(BYTE** ptr)
450 ret = *(unsigned short*)(*ptr) / 2;
455 ret = *(unsigned char*)(*ptr) / 2;
461 /******************************************************************
462 * HLPFILE_LoadPictureByAddr
466 static BOOL HLPFILE_LoadPictureByAddr(HLPFILE *hlpfile, char* ref,
467 unsigned long size, unsigned pos)
471 numpict = *(unsigned short*)(ref + 2);
473 for (i = 0; i < numpict; i++)
479 unsigned long off, sz;
482 ptr = beg = ref + *((unsigned long*)ref + 1 + i);
487 bi = HeapAlloc(GetProcessHeap(), 0, sizeof(*bi));
488 if (!bi) return FALSE;
490 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
491 bi->bmiHeader.biXPelsPerMeter = fetch_ulong(&ptr);
492 bi->bmiHeader.biYPelsPerMeter = fetch_ulong(&ptr);
493 bi->bmiHeader.biPlanes = fetch_ushort(&ptr);
494 bi->bmiHeader.biBitCount = fetch_ushort(&ptr);
495 bi->bmiHeader.biWidth = fetch_ulong(&ptr);
496 bi->bmiHeader.biHeight = fetch_ulong(&ptr);
497 bi->bmiHeader.biClrUsed = fetch_ulong(&ptr);
498 bi->bmiHeader.biClrImportant = fetch_ulong(&ptr);
499 bi->bmiHeader.biCompression = BI_RGB;
500 if (bi->bmiHeader.biBitCount > 32) WINE_FIXME("Unknown bit count %u\n", bi->bmiHeader.biBitCount);
501 if (bi->bmiHeader.biPlanes != 1) WINE_FIXME("Unsupported planes %u\n", bi->bmiHeader.biPlanes);
502 shift = 32 / bi->bmiHeader.biBitCount;
503 bi->bmiHeader.biSizeImage = ((bi->bmiHeader.biWidth + shift - 1) / shift) * 4 * bi->bmiHeader.biHeight;
505 sz = fetch_ulong(&ptr);
506 fetch_ulong(&ptr); /* hotspot size */
508 off = *(unsigned long*)ptr; ptr += 4;
509 /* *(unsigned long*)ptr; hotspot offset */ ptr += 4;
511 /* now read palette info */
514 unsigned nc = bi->bmiHeader.biClrUsed;
517 /* not quite right, especially for bitfields type of compression */
518 if (!nc && bi->bmiHeader.biBitCount <= 8)
519 nc = 1 << bi->bmiHeader.biBitCount;
521 bi = HeapReAlloc(GetProcessHeap(), 0, bi, sizeof(*bi) + nc * sizeof(RGBQUAD));
522 if (!bi) return FALSE;
523 for (i = 0; i < nc; i++)
525 bi->bmiColors[i].rgbBlue = ptr[0];
526 bi->bmiColors[i].rgbGreen = ptr[1];
527 bi->bmiColors[i].rgbRed = ptr[2];
528 bi->bmiColors[i].rgbReserved = 0;
535 case 0: /* uncompressed */
536 pict_beg = beg + off;
537 if (sz != bi->bmiHeader.biSizeImage)
538 WINE_WARN("Bogus image sizes: %lu / %lu [sz=(%lu,%lu) bc=%u pl=%u]\n",
539 sz, bi->bmiHeader.biSizeImage,
540 bi->bmiHeader.biWidth, bi->bmiHeader.biHeight,
541 bi->bmiHeader.biBitCount, bi->bmiHeader.biPlanes);
547 dst = pict_beg = HeapAlloc(GetProcessHeap(), 0, bi->bmiHeader.biSizeImage);
548 if (!pict_beg) return FALSE;
549 HLPFILE_UncompressRLE(beg + off, sz, &dst);
550 if (dst - pict_beg != bi->bmiHeader.biSizeImage)
551 WINE_FIXME("buffer XXX-flow\n");
557 esz = HLPFILE_UncompressedLZ77_Size(beg + off, beg + off + sz);
558 pict_beg = HeapAlloc(GetProcessHeap(), 0, esz);
559 if (!pict_beg) return FALSE;
560 HLPFILE_UncompressLZ77(beg + off, beg + off + sz, pict_beg);
561 if (esz != bi->bmiHeader.biSizeImage)
562 WINE_WARN("Bogus image sizes: %lu / %lu [sz=(%lu,%lu) bc=%u pl=%u]\n",
563 esz, bi->bmiHeader.biSizeImage,
564 bi->bmiHeader.biWidth, bi->bmiHeader.biHeight,
565 bi->bmiHeader.biBitCount, bi->bmiHeader.biPlanes);
568 case 3: /* LZ77 then RLE */
574 sz77 = HLPFILE_UncompressedLZ77_Size(beg + off, beg + off + sz);
575 tmp = HeapAlloc(GetProcessHeap(), 0, bi->bmiHeader.biSizeImage);
576 if (!tmp) return FALSE;
577 HLPFILE_UncompressLZ77(beg + off, beg + off + sz, tmp);
578 pict_beg = dst = HeapAlloc(GetProcessHeap(), 0, bi->bmiHeader.biSizeImage);
579 if (!pict_beg) return FALSE;
580 HLPFILE_UncompressRLE(tmp, sz77, &dst);
581 if (dst - pict_beg != bi->bmiHeader.biSizeImage)
582 WINE_WARN("Bogus image sizes: %u / %lu [sz=(%lu,%lu) bc=%u pl=%u]\n",
583 dst - pict_beg, bi->bmiHeader.biSizeImage,
584 bi->bmiHeader.biWidth, bi->bmiHeader.biHeight,
585 bi->bmiHeader.biBitCount, bi->bmiHeader.biPlanes);
586 HeapFree(GetProcessHeap(), 0, tmp);
590 WINE_FIXME("Unsupported packing %u\n", pack);
594 attributes.hBitmap = CreateDIBitmap(GetDC(0), &bi->bmiHeader, CBM_INIT,
595 pict_beg, bi, DIB_RGB_COLORS);
596 if (!attributes.hBitmap)
597 WINE_ERR("Couldn't create bitmap\n");
598 attributes.bmpPos = pos;
600 HeapFree(GetProcessHeap(), 0, bi);
601 if (pict_beg != beg + off) HeapFree(GetProcessHeap(), 0, pict_beg);
603 /* FIXME: implement support for multiple picture format */
604 if (numpict != 1) WINE_FIXME("Supporting only one bitmap format per logical bitmap (for now). Using first format\n");
610 /******************************************************************
611 * HLPFILE_LoadPictureByIndex
615 static BOOL HLPFILE_LoadPictureByIndex(HLPFILE *hlpfile, unsigned index, unsigned pos)
620 WINE_TRACE("Loading picture #%d\n", index);
621 sprintf(tmp, "|bm%u", index);
623 if (!HLPFILE_FindSubFile(tmp, &ref, &end)) {WINE_WARN("no sub file\n"); return FALSE;}
627 return HLPFILE_LoadPictureByAddr(hlpfile, ref, end - ref, pos);
630 /***********************************************************************
632 * HLPFILE_AddParagraph
634 static BOOL HLPFILE_AddParagraph(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigned* len)
637 HLPFILE_PARAGRAPH *paragraph, **paragraphptr;
639 BYTE *format, *format_end, *text, *text_end;
642 unsigned nc, ncol = 1;
644 if (!hlpfile->first_page) {WINE_WARN("no page\n"); return FALSE;};
646 for (page = hlpfile->first_page; page->next; page = page->next) /* Nothing */;
647 for (paragraphptr = &page->first_paragraph; *paragraphptr;
648 paragraphptr = &(*paragraphptr)->next) /* Nothing */;
650 if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};
652 size = GET_UINT(buf, 0x4);
654 if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10))
656 if (hlpfile->hasPhrases)
658 BYTE* lptr = buf + GET_UINT(buf, 0x10);
661 size2 = HLPFILE_Uncompressed2_Size(lptr, end);
662 if (size2 != size + 1)
663 WINE_FIXME("Mismatch in sizes: decomp2=%u header=%lu\n", size2, size);
664 text = HeapAlloc(GetProcessHeap(), 0, size + 1);
665 if (!text) return FALSE;
666 HLPFILE_Uncompress2(&lptr, end, text);
670 /* block is compressed */
671 text = HeapAlloc(GetProcessHeap(), 0, size);
672 if (!text) return FALSE;
673 HLPFILE_Uncompress3(text, text + size, buf + GET_UINT(buf, 0x10), end);
678 text = buf + GET_UINT(buf, 0x10);
680 text_end = text + size;
683 format_end = buf + GET_UINT(buf, 0x10);
686 *len = fetch_ushort(&format);
687 if (buf[0x14] == 0x23)
693 WINE_TRACE("#cols %u\n", ncol);
695 if (type == 0 || type == 2)
700 for (nc = 0; nc < ncol; nc++)
702 WINE_TRACE("looking for format at offset %u for column %d\n", format - (buf + 0x15), nc);
703 if (buf[0x14] == 0x23)
706 bits = *(unsigned short*)format; format += 2;
707 if (bits & 0x0001) fetch_long(&format);
708 if (bits & 0x0002) fetch_short(&format);
709 if (bits & 0x0004) fetch_short(&format);
710 if (bits & 0x0008) fetch_short(&format);
711 if (bits & 0x0010) fetch_short(&format);
712 if (bits & 0x0020) fetch_short(&format);
713 if (bits & 0x0040) fetch_short(&format);
714 if (bits & 0x0100) format += 3;
717 int ntab = fetch_short(&format);
722 ts = fetch_ushort(&format);
723 if (ts & 0x4000) fetch_ushort(&format);
727 while (text < text_end && format < format_end)
729 WINE_TRACE("Got text: '%s' (%p/%p - %p/%p)\n", text, text, text_end, format, format_end);
730 textsize = strlen(text) + 1;
731 if (textsize > 1 || attributes.hBitmap)
733 paragraph = HeapAlloc(GetProcessHeap(), 0,
734 sizeof(HLPFILE_PARAGRAPH) + textsize);
735 if (!paragraph) return FALSE;
736 *paragraphptr = paragraph;
737 paragraphptr = ¶graph->next;
739 paragraph->next = NULL;
740 paragraph->link = NULL;
742 if (attributes.hBitmap)
744 paragraph->cookie = para_image;
745 paragraph->u.image.hBitmap = attributes.hBitmap;
746 paragraph->u.image.pos = attributes.bmpPos;
747 if (attributes.wVSpace) paragraph->u.image.pos |= 0x8000;
751 paragraph->cookie = (attributes.bDebug) ? para_debug_text : para_normal_text;
752 paragraph->u.text.wFont = attributes.wFont;
753 paragraph->u.text.wVSpace = attributes.wVSpace;
754 paragraph->u.text.wHSpace = attributes.wHSpace;
755 paragraph->u.text.wIndent = attributes.wIndent;
756 paragraph->u.text.lpszText = (char*)paragraph + sizeof(HLPFILE_PARAGRAPH);
757 strcpy(paragraph->u.text.lpszText, text);
760 if (attributes.link.lpszString)
762 /* FIXME: should build a string table for the attributes.link.lpszPath
763 * they are reallocated for each link
765 paragraph->link = HeapAlloc(GetProcessHeap(), 0,
766 sizeof(HLPFILE_LINK) + strlen(attributes.link.lpszString) + 1);
767 if (!paragraph->link) return FALSE;
769 paragraph->link->cookie = attributes.link.cookie;
770 paragraph->link->lpszString = (char*)paragraph->link + sizeof(HLPFILE_LINK);
771 strcpy((char*)paragraph->link->lpszString, attributes.link.lpszString);
772 paragraph->link->lHash = attributes.link.lHash;
773 paragraph->link->bClrChange = attributes.link.bClrChange;
775 WINE_TRACE("Link[%d] to %s/%08lx\n",
776 paragraph->link->cookie, paragraph->link->lpszString, paragraph->link->lHash);
779 memset(&attributes, 0, sizeof(attributes));
781 attributes.hBitmap = 0;
782 attributes.link.lpszString = NULL;
783 attributes.link.bClrChange = FALSE;
784 attributes.link.lHash = 0;
785 attributes.wVSpace = 0;
786 attributes.wHSpace = 0;
787 attributes.wIndent = 0;
790 /* else: null text, keep on storing attributes */
799 WINE_TRACE("format=%02x\n", *format);
813 attributes.wFont = GET_USHORT(format, 1);
814 WINE_TRACE("Changing font to %d\n", attributes.wFont);
819 attributes.wVSpace++;
824 attributes.wVSpace += 2 - attributes.wVBackSpace;
825 attributes.wVBackSpace = 0;
826 attributes.wIndent = 0;
831 attributes.wIndent++;
845 BYTE pos = (*format - 0x86);
846 BYTE type = format[1];
850 size = fetch_long(&format);
854 fetch_ushort(&format); /* hot spot */
857 if (*(short*)format == 0)
858 HLPFILE_LoadPictureByIndex(hlpfile,
859 *(short*)(format + 2),
863 WINE_FIXME("does it work ???\n");
864 HLPFILE_LoadPictureByAddr(hlpfile, format + 2,
869 WINE_FIXME("Got an embedded element %s\n", format + 6);
872 WINE_FIXME("Got a type %d picture\n", type);
880 attributes.wVBackSpace++;
886 WINE_FIXME("NIY non-break space/hyphen\n");
898 WINE_TRACE("macro => %s\n", format + 3);
899 attributes.link.bClrChange = !(*format & 4);
900 attributes.link.cookie = hlp_link_macro;
901 attributes.link.lpszString = format + 3;
902 format += 3 + GET_USHORT(format, 1);
907 WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1));
913 attributes.link.bClrChange = TRUE;
917 attributes.link.cookie = (*format & 1) ? hlp_link_link : hlp_link_popup;
918 attributes.link.lpszString = hlpfile->lpszPath;
919 attributes.link.lHash = GET_UINT(format, 1);
928 char* ptr = format + 8;
929 BYTE type = format[3];
931 attributes.link.cookie = hlp_link_link;
932 attributes.link.lHash = GET_UINT(format, 4);
933 attributes.link.bClrChange = !(*format & 1);
936 {WINE_FIXME("Unsupported wnd number %d for link\n", *ptr); ptr++;}
937 if (type == 4 || type == 6)
939 attributes.link.lpszString = ptr;
940 ptr += strlen(ptr) + 1;
943 attributes.link.lpszString = hlpfile->lpszPath;
945 WINE_FIXME("Unsupported wnd name '%s' for link\n", ptr);
947 format += 3 + GET_USHORT(format, 1);
951 WINE_WARN("format %02x\n", *format);
956 if (text_end != buf + GET_UINT(buf, 0x10) + size)
957 HeapFree(GetProcessHeap(), 0, text_end - size);
961 /******************************************************************
966 static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile)
969 unsigned i, len, idx;
970 unsigned face_num, dscr_num, face_offset, dscr_offset;
973 if (!HLPFILE_FindSubFile("|FONT", &ref, &end))
975 WINE_WARN("no subfile FONT\n");
976 hlpfile->numFonts = 0;
977 hlpfile->fonts = NULL;
983 face_num = GET_USHORT(ref, 0);
984 dscr_num = GET_USHORT(ref, 2);
985 face_offset = GET_USHORT(ref, 4);
986 dscr_offset = GET_USHORT(ref, 6);
988 WINE_TRACE("Got NumFacenames=%u@%u NumDesc=%u@%u\n",
989 face_num, face_offset, dscr_num, dscr_offset);
991 hlpfile->numFonts = dscr_num;
992 hlpfile->fonts = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_FONT) * dscr_num);
994 len = (dscr_offset - face_offset) / face_num;
995 /* EPP for (i = face_offset; i < dscr_offset; i += len) */
996 /* EPP WINE_FIXME("[%d]: %*s\n", i / len, len, ref + i); */
997 for (i = 0; i < dscr_num; i++)
999 flag = ref[dscr_offset + i * 11 + 0];
1000 family = ref[dscr_offset + i * 11 + 2];
1002 hlpfile->fonts[i].LogFont.lfHeight = -ref[dscr_offset + i * 11 + 1] / 2;
1003 hlpfile->fonts[i].LogFont.lfWidth = 0;
1004 hlpfile->fonts[i].LogFont.lfEscapement = 0;
1005 hlpfile->fonts[i].LogFont.lfOrientation = 0;
1006 hlpfile->fonts[i].LogFont.lfWeight = (flag & 1) ? 700 : 400;
1007 hlpfile->fonts[i].LogFont.lfItalic = (flag & 2) ? TRUE : FALSE;
1008 hlpfile->fonts[i].LogFont.lfUnderline = (flag & 4) ? TRUE : FALSE;
1009 hlpfile->fonts[i].LogFont.lfStrikeOut = (flag & 8) ? TRUE : FALSE;
1010 hlpfile->fonts[i].LogFont.lfCharSet = ANSI_CHARSET;
1011 hlpfile->fonts[i].LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
1012 hlpfile->fonts[i].LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1013 hlpfile->fonts[i].LogFont.lfQuality = DEFAULT_QUALITY;
1014 hlpfile->fonts[i].LogFont.lfPitchAndFamily = DEFAULT_PITCH;
1018 case 0x01: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_MODERN; break;
1019 case 0x02: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_ROMAN; break;
1020 case 0x03: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SWISS; break;
1021 case 0x04: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SCRIPT; break;
1022 case 0x05: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_DECORATIVE; break;
1023 default: WINE_FIXME("Unknown family %u\n", family);
1025 idx = *(unsigned short*)(ref + dscr_offset + i * 11 + 3);
1029 strncpy(hlpfile->fonts[i].LogFont.lfFaceName, ref + face_offset + idx * len, min(len, LF_FACESIZE - 1));
1030 hlpfile->fonts[i].LogFont.lfFaceName[min(len, LF_FACESIZE - 1) + 1] = '\0';
1034 WINE_FIXME("Too high face ref (%u/%u)\n", idx, face_num);
1035 strcpy(hlpfile->fonts[i].LogFont.lfFaceName, "Helv");
1037 hlpfile->fonts[i].hFont = (HANDLE)0;
1038 hlpfile->fonts[i].color = RGB(ref[dscr_offset + i * 11 + 5],
1039 ref[dscr_offset + i * 11 + 6],
1040 ref[dscr_offset + i * 11 + 7]);
1041 #define X(b,s) ((flag & (1 << b)) ? "-"s: "")
1042 WINE_TRACE("Font[%d]: flags=%02x%s%s%s%s%s%s pSize=%u family=%u face=%s[%u] color=%08lx\n",
1048 X(4, "dblUnderline"),
1050 ref[dscr_offset + i * 11 + 1],
1052 hlpfile->fonts[i].LogFont.lfFaceName, idx,
1053 *(unsigned long*)(ref + dscr_offset + i * 11 + 5) & 0x00FFFFFF);
1056 --- only if FacenamesOffset >= 12
1057 unsigned short NumStyles number of style descriptors
1058 unsigned short StyleOffset start of array of style descriptors
1059 relative to &NumFacenames
1060 --- only if FacenamesOffset >= 16
1061 unsigned short NumCharMapTables number of character mapping tables
1062 unsigned short CharMapTableOffset start of array of character mapping
1063 table names relative to &NumFacenames
1068 /***********************************************************************
1070 * HLPFILE_ReadFileToBuffer
1072 static BOOL HLPFILE_ReadFileToBuffer(HFILE hFile)
1074 BYTE header[16], dummy[1];
1077 if (_hread(hFile, header, 16) != 16) {WINE_WARN("header\n"); return FALSE;};
1080 if (GET_UINT(header, 0) != 0x00035F3F)
1081 {WINE_WARN("wrong header\n"); return FALSE;};
1083 size = GET_UINT(header, 12);
1084 file_buffer = HeapAlloc(GetProcessHeap(), 0, size + 1);
1085 if (!file_buffer) return FALSE;
1087 memcpy(file_buffer, header, 16);
1088 if (_hread(hFile, file_buffer + 16, size - 16) != size - 16)
1089 {WINE_WARN("filesize1\n"); return FALSE;};
1091 if (_hread(hFile, dummy, 1) != 0) WINE_WARN("filesize2\n");
1093 file_buffer[size] = '\0'; /* FIXME: was '0', sounds ackward to me */
1098 /***********************************************************************
1100 * HLPFILE_FindSubFile
1102 static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE **subbuf, BYTE **subend)
1104 BYTE *root = file_buffer + GET_UINT(file_buffer, 4);
1105 BYTE *end = file_buffer + GET_UINT(file_buffer, 12);
1116 /* FIXME: this should be using the EnumBTree functions from this file */
1117 pgsize = GET_USHORT(bth, 4);
1118 WINE_TRACE("%s => pgsize=%u #pg=%u rootpg=%u #lvl=%u\n",
1119 name, pgsize, GET_USHORT(bth, 30), GET_USHORT(bth, 26), GET_USHORT(bth, 32));
1121 ptr = bth + 38 + GET_USHORT(bth, 26) * pgsize;
1123 for (n = 1; n < GET_USHORT(bth, 32); n++)
1125 nentries = GET_USHORT(ptr, 2);
1126 pglast = GET_USHORT(ptr, 4);
1127 WINE_TRACE("[%u]: #entries=%u next=%u\n", n, nentries, pglast);
1130 for (i = 0; i < nentries; i++)
1132 WINE_TRACE("<= %s\n", ptr);
1133 if (strcmp(name, ptr) < 0) break;
1134 ptr += strlen(ptr) + 1;
1135 pglast = GET_USHORT(ptr, 0);
1138 ptr = bth + 38 + pglast * pgsize;
1141 nentries = GET_USHORT(ptr, 2);
1143 for (i = 0; i < nentries; i++)
1146 ptr += strlen(fname) + 1;
1147 WINE_TRACE("\\- %s\n", fname);
1148 if (strcmp(fname, name) == 0)
1150 *subbuf = file_buffer + GET_UINT(ptr, 0);
1151 *subend = *subbuf + GET_UINT(*subbuf, 0);
1152 if (file_buffer > *subbuf || *subbuf > *subend || *subend > end)
1154 WINE_WARN("size mismatch\n");
1165 /***********************************************************************
1167 * HLPFILE_SystemCommands
1169 static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile)
1171 BYTE *buf, *ptr, *end;
1172 HLPFILE_MACRO *macro, **m;
1174 unsigned short magic, minor, major, flags;
1176 hlpfile->lpszTitle = NULL;
1178 if (!HLPFILE_FindSubFile("|SYSTEM", &buf, &end)) return FALSE;
1180 magic = GET_USHORT(buf + 9, 0);
1181 minor = GET_USHORT(buf + 9, 2);
1182 major = GET_USHORT(buf + 9, 4);
1183 /* gen date on 4 bytes */
1184 flags = GET_USHORT(buf + 9, 10);
1185 WINE_TRACE("Got system header: magic=%04x version=%d.%d flags=%04x\n",
1186 magic, major, minor, flags);
1187 if (magic != 0x036C || major != 1)
1188 {WINE_WARN("Wrong system header\n"); return FALSE;}
1189 if (minor <= 16) {WINE_WARN("too old file format (NIY)\n"); return FALSE;}
1191 hlpfile->version = minor;
1192 hlpfile->flags = flags;
1194 for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4)
1196 switch (GET_USHORT(ptr, 0))
1199 if (hlpfile->lpszTitle) {WINE_WARN("title\n"); break;}
1200 hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(ptr + 4) + 1);
1201 if (!hlpfile->lpszTitle) return FALSE;
1202 lstrcpy(hlpfile->lpszTitle, ptr + 4);
1203 WINE_TRACE("Title: %s\n", hlpfile->lpszTitle);
1207 if (GET_USHORT(ptr, 2) != 1 || ptr[4] != 0) WINE_WARN("system2\n");
1211 if (GET_USHORT(ptr, 2) != 4 || GET_UINT(ptr, 4) != 0)
1212 WINE_WARN("system3\n");
1216 macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + lstrlen(ptr + 4) + 1);
1218 p = (char*)macro + sizeof(HLPFILE_MACRO);
1219 lstrcpy(p, (LPSTR)ptr + 4);
1220 macro->lpszMacro = p;
1222 for (m = &hlpfile->first_macro; *m; m = &(*m)->next);
1227 WINE_WARN("Unsupport SystemRecord[%d]\n", GET_USHORT(ptr, 0));
1233 /***********************************************************************
1235 * HLPFILE_UncompressedLZ77_Size
1237 static INT HLPFILE_UncompressedLZ77_Size(BYTE *ptr, BYTE *end)
1244 for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)
1248 int code = GET_USHORT(ptr, 0);
1249 int len = 3 + (code >> 12);
1253 else newsize++, ptr++;
1260 /***********************************************************************
1262 * HLPFILE_UncompressLZ77
1264 static BYTE *HLPFILE_UncompressLZ77(BYTE *ptr, BYTE *end, BYTE *newptr)
1271 for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)
1275 int code = GET_USHORT(ptr, 0);
1276 int len = 3 + (code >> 12);
1277 int offset = code & 0xfff;
1278 memcpy(newptr, newptr - offset - 1, len);
1282 else *newptr++ = *ptr++;
1289 /***********************************************************************
1291 * HLPFILE_UncompressLZ77_Phrases
1293 static BOOL HLPFILE_UncompressLZ77_Phrases(HLPFILE* hlpfile)
1295 UINT i, num, dec_size;
1298 if (!HLPFILE_FindSubFile("|Phrases", &buf, &end)) return FALSE;
1300 num = phrases.num = GET_USHORT(buf, 9);
1301 if (buf + 2 * num + 0x13 >= end) {WINE_WARN("1a\n"); return FALSE;};
1303 dec_size = HLPFILE_UncompressedLZ77_Size(buf + 0x13 + 2 * num, end);
1305 phrases.offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1));
1306 phrases.buffer = HeapAlloc(GetProcessHeap(), 0, dec_size);
1307 if (!phrases.offsets || !phrases.buffer) return FALSE;
1309 for (i = 0; i <= num; i++)
1310 phrases.offsets[i] = GET_USHORT(buf, 0x11 + 2 * i) - 2 * num - 2;
1312 HLPFILE_UncompressLZ77(buf + 0x13 + 2 * num, end, phrases.buffer);
1314 hlpfile->hasPhrases = TRUE;
1318 /***********************************************************************
1320 * HLPFILE_Uncompress_Phrases40
1322 static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE* hlpfile)
1325 BYTE *buf_idx, *end_idx;
1326 BYTE *buf_phs, *end_phs;
1328 long* ptr, mask = 0;
1331 if (!HLPFILE_FindSubFile("|PhrIndex", &buf_idx, &end_idx) ||
1332 !HLPFILE_FindSubFile("|PhrImage", &buf_phs, &end_phs)) return FALSE;
1334 ptr = (long*)(buf_idx + 9 + 28);
1335 bc = GET_USHORT(buf_idx, 9 + 24) & 0x0F;
1336 num = phrases.num = GET_USHORT(buf_idx, 9 + 4);
1338 WINE_TRACE("Index: Magic=%08x #entries=%u CpsdSize=%u PhrImgSize=%u\n"
1339 "\tPhrImgCprsdSize=%u 0=%u bc=%x ukn=%x\n",
1340 GET_UINT(buf_idx, 9 + 0),
1341 GET_UINT(buf_idx, 9 + 4),
1342 GET_UINT(buf_idx, 9 + 8),
1343 GET_UINT(buf_idx, 9 + 12),
1344 GET_UINT(buf_idx, 9 + 16),
1345 GET_UINT(buf_idx, 9 + 20),
1346 GET_USHORT(buf_idx, 9 + 24),
1347 GET_USHORT(buf_idx, 9 + 26));
1349 dec_size = GET_UINT(buf_idx, 9 + 12);
1350 if (dec_size != HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs))
1352 WINE_WARN("size mismatch %u %u\n",
1353 dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs, end_phs));
1354 dec_size = max(dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs, end_phs));
1357 phrases.offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1));
1358 phrases.buffer = HeapAlloc(GetProcessHeap(), 0, dec_size);
1359 if (!phrases.offsets || !phrases.buffer) return FALSE;
1361 #define getbit() (ptr += (mask < 0), mask = mask*2 + (mask<=0), (*ptr & mask) != 0)
1363 phrases.offsets[0] = 0;
1364 for (i = 0; i < num; i++)
1366 for (n = 1; getbit(); n += 1 << bc);
1368 if (bc > 1 && getbit()) n += 2;
1369 if (bc > 2 && getbit()) n += 4;
1370 if (bc > 3 && getbit()) n += 8;
1371 if (bc > 4 && getbit()) n += 16;
1372 phrases.offsets[i + 1] = phrases.offsets[i] + n;
1376 HLPFILE_UncompressLZ77(buf_phs + 9, end_phs, phrases.buffer);
1378 hlpfile->hasPhrases = FALSE;
1382 /***********************************************************************
1384 * HLPFILE_UncompressLZ77_Topic
1386 static BOOL HLPFILE_UncompressLZ77_Topic(HLPFILE* hlpfile)
1388 BYTE *buf, *ptr, *end, *newptr;
1391 if (!HLPFILE_FindSubFile("|TOPIC", &buf, &end))
1392 {WINE_WARN("topic0\n"); return FALSE;}
1394 if (!(hlpfile->flags & 4)) WINE_FIXME("Unsupported format\n");
1397 topic.wMapLen = (end - buf - 1) / 0x1000 + 1;
1399 for (i = 0; i < topic.wMapLen; i++)
1401 ptr = buf + i * 0x1000;
1403 /* I don't know why, it's necessary for printman.hlp */
1404 if (ptr + 0x44 > end) ptr = end - 0x44;
1406 newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + 0x1000));
1409 topic.map = HeapAlloc(GetProcessHeap(), 0,
1410 topic.wMapLen * sizeof(topic.map[0]) + newsize);
1411 if (!topic.map) return FALSE;
1412 newptr = (char*)topic.map + topic.wMapLen * sizeof(topic.map[0]);
1413 topic.end = newptr + newsize;
1415 for (i = 0; i < topic.wMapLen; i++)
1417 ptr = buf + i * 0x1000;
1418 if (ptr + 0x44 > end) ptr = end - 0x44;
1420 topic.map[i] = newptr;
1421 newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + 0x1000), newptr);
1427 /***********************************************************************
1429 * HLPFILE_Uncompressed2_Size
1431 static UINT HLPFILE_Uncompressed2_Size(BYTE *ptr, BYTE *end)
1437 if (!*ptr || *ptr >= 0x10)
1441 BYTE *phptr, *phend;
1442 UINT code = 0x100 * ptr[0] + ptr[1];
1443 UINT index = (code - 0x100) / 2;
1445 if (index < phrases.num)
1447 phptr = phrases.buffer + phrases.offsets[index];
1448 phend = phrases.buffer + phrases.offsets[index + 1];
1450 if (phend < phptr) WINE_WARN("uncompress2a\n");
1452 wSize += phend - phptr;
1453 if (code & 1) wSize++;
1455 else WINE_WARN("uncompress2b %d|%d\n", index, phrases.num);
1464 /***********************************************************************
1466 * HLPFILE_Uncompress2
1469 static void HLPFILE_Uncompress2(BYTE **pptr, BYTE *end, BYTE *newptr)
1475 if (!*ptr || *ptr >= 0x10)
1479 BYTE *phptr, *phend;
1480 UINT code = 0x100 * ptr[0] + ptr[1];
1481 UINT index = (code - 0x100) / 2;
1483 phptr = phrases.buffer + phrases.offsets[index];
1484 phend = phrases.buffer + phrases.offsets[index + 1];
1486 memcpy(newptr, phptr, phend - phptr);
1487 newptr += phend - phptr;
1488 if (code & 1) *newptr++ = ' ';
1497 /******************************************************************
1498 * HLPFILE_Uncompress3
1502 static BOOL HLPFILE_Uncompress3(char* dst, const char* dst_end,
1503 const BYTE* src, const BYTE* src_end)
1507 for (; src < src_end; src++)
1509 if ((*src & 1) == 0)
1512 if (idx > phrases.num) WINE_ERR("index in phrases\n");
1513 len = phrases.offsets[idx + 1] - phrases.offsets[idx];
1514 memcpy(dst, &phrases.buffer[phrases.offsets[idx]], len);
1516 else if ((*src & 0x03) == 0x01)
1518 idx = (*src + 1) * 64 + *++src;
1519 if (idx > phrases.num) WINE_ERR("index in phrases\n");
1520 len = phrases.offsets[idx + 1] - phrases.offsets[idx];
1521 memcpy(dst, &phrases.buffer[phrases.offsets[idx]], len);
1523 else if ((*src & 0x07) == 0x03)
1525 len = (*src / 8) + 1;
1526 memcpy(dst, src + 1, len);
1531 len = (*src / 16) + 1;
1532 memset(dst, ((*src & 0x0F) == 0x07) ? ' ' : 0, len);
1537 if (dst > dst_end) WINE_ERR("buffer overflow (%p > %p)\n", dst, dst_end);
1541 /******************************************************************
1542 * HLPFILE_UncompressRLE
1546 static void HLPFILE_UncompressRLE(const BYTE* src, unsigned sz, BYTE** dst)
1551 for (i = 0; i < sz; i++)
1557 memcpy(*dst, src + i + 1, ch);
1562 memset(*dst, (char)src[i + 1], ch);
1569 /******************************************************************
1570 * HLPFILE_EnumBTreeLeaves
1574 static void HLPFILE_EnumBTreeLeaves(const BYTE* buf, const BYTE* end, unsigned (*fn)(const BYTE*, void*), void* user)
1576 unsigned psize, pnext;
1580 num = GET_UINT(buf, 9 + 34);
1581 psize = GET_USHORT(buf, 9 + 4);
1582 nlvl = GET_USHORT(buf, 9 + 32);
1583 pnext = GET_USHORT(buf, 26);
1585 WINE_TRACE("BTree: #entries=%u pagSize=%u #levels=%u #pages=%u root=%u struct%16s\n",
1586 num, psize, nlvl, GET_USHORT(buf, 9 + 30), pnext, buf + 9 + 6);
1591 ptr = (buf + 9 + 38) + pnext * psize;
1592 WINE_TRACE("BTree: (index[%u]) unused=%u #entries=%u <%u\n",
1593 pnext, GET_USHORT(ptr, 0), GET_USHORT(ptr, 2), GET_USHORT(ptr, 4));
1594 pnext = GET_USHORT(ptr, 6);
1596 while (pnext != 0xFFFF)
1598 const BYTE* node_page;
1599 unsigned short limit;
1601 node_page = ptr = (buf + 9 + 38) + pnext * psize;
1602 limit = GET_USHORT(ptr, 2);
1603 WINE_TRACE("BTree: (leaf [%u]) unused=%u #entries=%u <%u >%u\n",
1604 pnext, GET_USHORT(ptr, 0), limit, GET_USHORT(ptr, 4), GET_USHORT(ptr, 6));
1607 ptr += (fn)(ptr, user);
1608 pnext = GET_USHORT(node_page, 6);
1617 static unsigned myfn(const BYTE* ptr, void* user)
1619 struct myfncb* m = user;
1621 m->hlpfile->Context[m->i].lHash = GET_UINT(ptr, 0);
1622 m->hlpfile->Context[m->i].offset = GET_UINT(ptr, 4);
1627 /***********************************************************************
1629 * HLPFILE_GetContext
1631 static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
1637 if (!HLPFILE_FindSubFile("|CONTEXT", &cbuf, &cend)) {WINE_WARN("context0\n"); return FALSE;}
1639 clen = GET_UINT(cbuf, 0x2b);
1640 hlpfile->Context = HeapAlloc(GetProcessHeap(), 0, clen * sizeof(HLPFILE_CONTEXT));
1641 if (!hlpfile->Context) return FALSE;
1642 hlpfile->wContextLen = clen;
1644 m.hlpfile = hlpfile;
1646 HLPFILE_EnumBTreeLeaves(cbuf, cend, myfn, &m);
1651 /***********************************************************************
1653 * HLPFILE_DeleteParagraph
1655 static void HLPFILE_DeleteParagraph(HLPFILE_PARAGRAPH* paragraph)
1657 HLPFILE_PARAGRAPH* next;
1661 next = paragraph->next;
1662 if (paragraph->link) HeapFree(GetProcessHeap(), 0, paragraph->link);
1664 HeapFree(GetProcessHeap(), 0, paragraph);
1669 /***********************************************************************
1673 static void HLPFILE_DeletePage(HLPFILE_PAGE* page)
1680 HLPFILE_DeleteParagraph(page->first_paragraph);
1681 HeapFree(GetProcessHeap(), 0, page);
1686 /***********************************************************************
1690 static void HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)
1692 HLPFILE_MACRO* next;
1697 HeapFree(GetProcessHeap(), 0, macro);
1702 /***********************************************************************
1704 * HLPFILE_FreeHlpFile
1706 void HLPFILE_FreeHlpFile(HLPFILE* hlpfile)
1708 if (!hlpfile || --hlpfile->wRefCount > 0) return;
1710 if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
1711 if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
1712 else first_hlpfile = hlpfile->next;
1714 if (hlpfile->numFonts)
1717 for (i = 0; i < hlpfile->numFonts; i++)
1719 DeleteObject(hlpfile->fonts[i].hFont);
1721 HeapFree(GetProcessHeap(), 0, hlpfile->fonts);
1724 HLPFILE_DeletePage(hlpfile->first_page);
1725 HLPFILE_DeleteMacro(hlpfile->first_macro);
1727 if (hlpfile->Context) HeapFree(GetProcessHeap(), 0, hlpfile->Context);
1728 if (hlpfile->lpszTitle) HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle);
1729 HeapFree(GetProcessHeap(), 0, hlpfile);
1732 /***********************************************************************
1736 void HLPFILE_FreeHlpFilePage(HLPFILE_PAGE* page)
1739 HLPFILE_FreeHlpFile(page->file);