ReactOS  0.4.12-dev-14-gd0c8636
hlpfile.c
Go to the documentation of this file.
1 /*
2  * Help Viewer
3  *
4  * Copyright 1996 Ulrich Schmid
5  * 2002, 2008 Eric Pouech
6  * 2007 Kirill K. Smirnov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winhelp.h"
32 
33 #include "wine/debug.h"
34 
36 
37 static inline unsigned short GET_USHORT(const BYTE* buffer, unsigned i)
38 {
39  return (BYTE)buffer[i] + 0x100 * (BYTE)buffer[i + 1];
40 }
41 
42 static inline short GET_SHORT(const BYTE* buffer, unsigned i)
43 {
44  return (BYTE)buffer[i] + 0x100 * (signed char)buffer[i+1];
45 }
46 
47 static inline unsigned GET_UINT(const BYTE* buffer, unsigned i)
48 {
49  return GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i + 2);
50 }
51 
52 static HLPFILE *first_hlpfile = 0;
53 
54 
55 /**************************************************************************
56  * HLPFILE_BPTreeSearch
57  *
58  * Searches for an element in B+ tree
59  *
60  * PARAMS
61  * buf [I] pointer to the embedded file structured as a B+ tree
62  * key [I] pointer to data to find
63  * comp [I] compare function
64  *
65  * RETURNS
66  * Pointer to block identified by key, or NULL if failure.
67  *
68  */
69 static void* HLPFILE_BPTreeSearch(BYTE* buf, const void* key,
71 {
72  unsigned magic;
73  unsigned page_size;
74  unsigned cur_page;
75  unsigned level;
76  BYTE *pages, *ptr, *newptr;
77  int i, entries;
78  int ret;
79 
80  magic = GET_USHORT(buf, 9);
81  if (magic != 0x293B)
82  {
83  WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic);
84  return NULL;
85  }
86  page_size = GET_USHORT(buf, 9+4);
87  cur_page = GET_USHORT(buf, 9+26);
88  level = GET_USHORT(buf, 9+32);
89  pages = buf + 9 + 38;
90  while (--level > 0)
91  {
92  ptr = pages + cur_page*page_size;
93  entries = GET_SHORT(ptr, 2);
94  ptr += 6;
95  for (i = 0; i < entries; i++)
96  {
97  if (comp(ptr, key, 0, (void **)&newptr) > 0) break;
98  ptr = newptr;
99  }
100  cur_page = GET_USHORT(ptr-2, 0);
101  }
102  ptr = pages + cur_page*page_size;
103  entries = GET_SHORT(ptr, 2);
104  ptr += 8;
105  for (i = 0; i < entries; i++)
106  {
107  ret = comp(ptr, key, 1, (void **)&newptr);
108  if (ret == 0) return ptr;
109  if (ret > 0) return NULL;
110  ptr = newptr;
111  }
112  return NULL;
113 }
114 
115 /**************************************************************************
116  * HLPFILE_BPTreeEnum
117  *
118  * Enumerates elements in B+ tree.
119  *
120  * PARAMS
121  * buf [I] pointer to the embedded file structured as a B+ tree
122  * cb [I] compare function
123  * cookie [IO] cookie for cb function
124  */
126 {
127  unsigned magic;
128  unsigned page_size;
129  unsigned cur_page;
130  unsigned level;
131  BYTE *pages, *ptr, *newptr;
132  int i, entries;
133 
134  magic = GET_USHORT(buf, 9);
135  if (magic != 0x293B)
136  {
137  WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic);
138  return;
139  }
140  page_size = GET_USHORT(buf, 9+4);
141  cur_page = GET_USHORT(buf, 9+26);
142  level = GET_USHORT(buf, 9+32);
143  pages = buf + 9 + 38;
144  while (--level > 0)
145  {
146  ptr = pages + cur_page*page_size;
147  cur_page = GET_USHORT(ptr, 4);
148  }
149  while (cur_page != 0xFFFF)
150  {
151  ptr = pages + cur_page*page_size;
152  entries = GET_SHORT(ptr, 2);
153  ptr += 8;
154  for (i = 0; i < entries; i++)
155  {
156  cb(ptr, (void **)&newptr, cookie);
157  ptr = newptr;
158  }
159  cur_page = GET_USHORT(pages+cur_page*page_size, 6);
160  }
161 }
162 
163 
164 /***********************************************************************
165  *
166  * HLPFILE_UncompressedLZ77_Size
167  */
169 {
170  int i, newsize = 0;
171 
172  while (ptr < end)
173  {
174  int mask = *ptr++;
175  for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)
176  {
177  if (mask & 1)
178  {
179  int code = GET_USHORT(ptr, 0);
180  int len = 3 + (code >> 12);
181  newsize += len;
182  ptr += 2;
183  }
184  else newsize++, ptr++;
185  }
186  }
187 
188  return newsize;
189 }
190 
191 /***********************************************************************
192  *
193  * HLPFILE_UncompressLZ77
194  */
195 static BYTE *HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr)
196 {
197  int i;
198 
199  while (ptr < end)
200  {
201  int mask = *ptr++;
202  for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)
203  {
204  if (mask & 1)
205  {
206  int code = GET_USHORT(ptr, 0);
207  int len = 3 + (code >> 12);
208  int offset = code & 0xfff;
209  /*
210  * We must copy byte-by-byte here. We cannot use memcpy nor
211  * memmove here. Just example:
212  * a[]={1,2,3,4,5,6,7,8,9,10}
213  * newptr=a+2;
214  * offset=1;
215  * We expect:
216  * {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 11, 12}
217  */
218  for (; len>0; len--, newptr++) *newptr = *(newptr-offset-1);
219  ptr += 2;
220  }
221  else *newptr++ = *ptr++;
222  }
223  }
224 
225  return newptr;
226 }
227 
228 /***********************************************************************
229  *
230  * HLPFILE_Uncompress2
231  */
232 
233 static void HLPFILE_Uncompress2(HLPFILE* hlpfile, const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend)
234 {
235  BYTE *phptr, *phend;
236  UINT code;
237  UINT index;
238 
239  while (ptr < end && newptr < newend)
240  {
241  if (!*ptr || *ptr >= 0x10)
242  *newptr++ = *ptr++;
243  else
244  {
245  code = 0x100 * ptr[0] + ptr[1];
246  index = (code - 0x100) / 2;
247 
248  phptr = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index];
249  phend = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index + 1];
250 
251  if (newptr + (phend - phptr) > newend)
252  {
253  WINE_FIXME("buffer overflow %p > %p for %lu bytes\n",
254  newptr, newend, (SIZE_T)(phend - phptr));
255  return;
256  }
257  memcpy(newptr, phptr, phend - phptr);
258  newptr += phend - phptr;
259  if (code & 1) *newptr++ = ' ';
260 
261  ptr += 2;
262  }
263  }
264  if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend);
265 }
266 
267 /******************************************************************
268  * HLPFILE_Uncompress3
269  *
270  *
271  */
272 static BOOL HLPFILE_Uncompress3(HLPFILE* hlpfile, char* dst, const char* dst_end,
273  const BYTE* src, const BYTE* src_end)
274 {
275  unsigned int idx, len;
276 
277  for (; src < src_end; src++)
278  {
279  if ((*src & 1) == 0)
280  {
281  idx = *src / 2;
282  if (idx > hlpfile->num_phrases)
283  {
284  WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases);
285  len = 0;
286  }
287  else
288  {
289  len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx];
290  if (dst + len <= dst_end)
291  memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len);
292  }
293  }
294  else if ((*src & 0x03) == 0x01)
295  {
296  idx = (*src + 1) * 64;
297  idx += *++src;
298  if (idx > hlpfile->num_phrases)
299  {
300  WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases);
301  len = 0;
302  }
303  else
304  {
305  len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx];
306  if (dst + len <= dst_end)
307  memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len);
308  }
309  }
310  else if ((*src & 0x07) == 0x03)
311  {
312  len = (*src / 8) + 1;
313  if (dst + len <= dst_end)
314  memcpy(dst, src + 1, len);
315  src += len;
316  }
317  else
318  {
319  len = (*src / 16) + 1;
320  if (dst + len <= dst_end)
321  memset(dst, ((*src & 0x0F) == 0x07) ? ' ' : 0, len);
322  }
323  dst += len;
324  }
325 
326  if (dst > dst_end) WINE_ERR("buffer overflow (%p > %p)\n", dst, dst_end);
327  return TRUE;
328 }
329 
330 /******************************************************************
331  * HLPFILE_UncompressRLE
332  *
333  *
334  */
335 static void HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE* dst, unsigned dstsz)
336 {
337  BYTE ch;
338  BYTE* sdst = dst + dstsz;
339 
340  while (src < end)
341  {
342  ch = *src++;
343  if (ch & 0x80)
344  {
345  ch &= 0x7F;
346  if (dst + ch <= sdst)
347  memcpy(dst, src, ch);
348  src += ch;
349  }
350  else
351  {
352  if (dst + ch <= sdst)
353  memset(dst, (char)*src, ch);
354  src++;
355  }
356  dst += ch;
357  }
358  if (dst != sdst)
359  WINE_WARN("Buffer X-flow: d(%lu) instead of d(%u)\n",
360  (SIZE_T)(dst - (sdst - dstsz)), dstsz);
361 }
362 
363 
364 /******************************************************************
365  * HLPFILE_PageByOffset
366  *
367  *
368  */
370 {
372  HLPFILE_PAGE* found;
373 
374  if (!hlpfile) return 0;
375 
376  WINE_TRACE("<%s>[%x]\n", debugstr_a(hlpfile->lpszPath), offset);
377 
378  if (offset == 0xFFFFFFFF) return NULL;
379  page = NULL;
380 
381  for (found = NULL, page = hlpfile->first_page; page; page = page->next)
382  {
383  if (page->offset <= offset && (!found || found->offset < page->offset))
384  {
385  *relative = offset - page->offset;
386  found = page;
387  }
388  }
389  if (!found)
390  WINE_ERR("Page of offset %u not found in file %s\n",
391  offset, debugstr_a(hlpfile->lpszPath));
392  return found;
393 }
394 
395 /***********************************************************************
396  *
397  * HLPFILE_Contents
398  */
399 static HLPFILE_PAGE* HLPFILE_Contents(HLPFILE *hlpfile, ULONG* relative)
400 {
402 
403  if (!hlpfile) return NULL;
404 
405  page = HLPFILE_PageByOffset(hlpfile, hlpfile->contents_start, relative);
406  if (!page)
407  {
408  page = hlpfile->first_page;
409  *relative = 0;
410  }
411  return page;
412 }
413 
414 /**************************************************************************
415  * comp_PageByHash
416  *
417  * HLPFILE_BPTreeCompare function for '|CONTEXT' B+ tree file
418  *
419  */
420 static int comp_PageByHash(void *p, const void *key,
421  int leaf, void** next)
422 {
423  LONG lKey = (LONG_PTR)key;
424  LONG lTest = (INT)GET_UINT(p, 0);
425 
426  *next = (char *)p+(leaf?8:6);
427  WINE_TRACE("Comparing '%d' with '%d'\n", lKey, lTest);
428  if (lTest < lKey) return -1;
429  if (lTest > lKey) return 1;
430  return 0;
431 }
432 
433 /***********************************************************************
434  *
435  * HLPFILE_PageByHash
436  */
437 HLPFILE_PAGE *HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash, ULONG* relative)
438 {
439  BYTE *ptr;
440 
441  if (!hlpfile) return NULL;
442  if (!lHash) return HLPFILE_Contents(hlpfile, relative);
443 
444  WINE_TRACE("<%s>[%x]\n", debugstr_a(hlpfile->lpszPath), lHash);
445 
446  /* For win 3.0 files hash values are really page numbers */
447  if (hlpfile->version <= 16)
448  {
449  if (lHash >= hlpfile->wTOMapLen) return NULL;
450  return HLPFILE_PageByOffset(hlpfile, hlpfile->TOMap[lHash], relative);
451  }
452 
453  ptr = HLPFILE_BPTreeSearch(hlpfile->Context, LongToPtr(lHash), comp_PageByHash);
454  if (!ptr)
455  {
456  WINE_ERR("Page of hash %x not found in file %s\n", lHash, debugstr_a(hlpfile->lpszPath));
457  return NULL;
458  }
459 
460  return HLPFILE_PageByOffset(hlpfile, GET_UINT(ptr, 4), relative);
461 }
462 
463 /***********************************************************************
464  *
465  * HLPFILE_PageByMap
466  */
467 HLPFILE_PAGE *HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative)
468 {
469  unsigned int i;
470 
471  if (!hlpfile) return 0;
472 
473  WINE_TRACE("<%s>[%x]\n", debugstr_a(hlpfile->lpszPath), lMap);
474 
475  for (i = 0; i < hlpfile->wMapLen; i++)
476  {
477  if (hlpfile->Map[i].lMap == lMap)
478  return HLPFILE_PageByOffset(hlpfile, hlpfile->Map[i].offset, relative);
479  }
480 
481  WINE_ERR("Page of Map %x not found in file %s\n", lMap, debugstr_a(hlpfile->lpszPath));
482  return NULL;
483 }
484 
485 /**************************************************************************
486  * comp_FindSubFile
487  *
488  * HLPFILE_BPTreeCompare function for HLPFILE directory.
489  *
490  */
491 static int comp_FindSubFile(void *p, const void *key,
492  int leaf, void** next)
493 {
494  *next = (char *)p+strlen(p)+(leaf?5:3);
495  WINE_TRACE("Comparing %s with %s\n", debugstr_a((char *)p), debugstr_a((const char *)key));
496  return strcmp(p, key);
497 }
498 
499 /***********************************************************************
500  *
501  * HLPFILE_FindSubFile
502  */
503 static BOOL HLPFILE_FindSubFile(HLPFILE* hlpfile, LPCSTR name, BYTE **subbuf, BYTE **subend)
504 {
505  BYTE *ptr;
506 
507  WINE_TRACE("looking for file %s\n", debugstr_a(name));
508  ptr = HLPFILE_BPTreeSearch(hlpfile->file_buffer + GET_UINT(hlpfile->file_buffer, 4),
509  name, comp_FindSubFile);
510  if (!ptr)
511  { /* Subfiles with bitmap images are usually prefixed with '|', but sometimes not.
512  Unfortunately, there is no consensus among different pieces of unofficial
513  documentation. So remove leading '|' and try again. */
514  CHAR c = *name++;
515  if (c == '|')
516  {
517  WINE_TRACE("not found. try %s\n", debugstr_a(name));
518  ptr = HLPFILE_BPTreeSearch(hlpfile->file_buffer + GET_UINT(hlpfile->file_buffer, 4),
519  name, comp_FindSubFile);
520  }
521  }
522  if (!ptr) return FALSE;
523  *subbuf = hlpfile->file_buffer + GET_UINT(ptr, strlen(name)+1);
524  if (*subbuf >= hlpfile->file_buffer + hlpfile->file_buffer_size)
525  {
526  WINE_ERR("internal file %s does not fit\n", debugstr_a(name));
527  return FALSE;
528  }
529  *subend = *subbuf + GET_UINT(*subbuf, 0);
530  if (*subend > hlpfile->file_buffer + hlpfile->file_buffer_size)
531  {
532  WINE_ERR("internal file %s does not fit\n", debugstr_a(name));
533  return FALSE;
534  }
535  if (GET_UINT(*subbuf, 0) < GET_UINT(*subbuf, 4) + 9)
536  {
537  WINE_ERR("invalid size provided for internal file %s\n", debugstr_a(name));
538  return FALSE;
539  }
540  return TRUE;
541 }
542 
543 /***********************************************************************
544  *
545  * HLPFILE_Hash
546  */
548 {
549  LONG lHash = 0;
550  CHAR c;
551 
552  while ((c = *lpszContext++))
553  {
554  CHAR x = 0;
555  if (c >= 'A' && c <= 'Z') x = c - 'A' + 17;
556  if (c >= 'a' && c <= 'z') x = c - 'a' + 17;
557  if (c >= '1' && c <= '9') x = c - '0';
558  if (c == '0') x = 10;
559  if (c == '.') x = 12;
560  if (c == '_') x = 13;
561  if (x) lHash = lHash * 43 + x;
562  }
563  return lHash;
564 }
565 
566 static LONG fetch_long(const BYTE** ptr)
567 {
568  LONG ret;
569 
570  if (*(*ptr) & 1)
571  {
572  ret = (*(const ULONG*)(*ptr) - 0x80000000) / 2;
573  (*ptr) += 4;
574  }
575  else
576  {
577  ret = (*(const USHORT*)(*ptr) - 0x8000) / 2;
578  (*ptr) += 2;
579  }
580 
581  return ret;
582 }
583 
584 static ULONG fetch_ulong(const BYTE** ptr)
585 {
586  ULONG ret;
587 
588  if (*(*ptr) & 1)
589  {
590  ret = *(const ULONG*)(*ptr) / 2;
591  (*ptr) += 4;
592  }
593  else
594  {
595  ret = *(const USHORT*)(*ptr) / 2;
596  (*ptr) += 2;
597  }
598  return ret;
599 }
600 
601 static short fetch_short(const BYTE** ptr)
602 {
603  short ret;
604 
605  if (*(*ptr) & 1)
606  {
607  ret = (*(const unsigned short*)(*ptr) - 0x8000) / 2;
608  (*ptr) += 2;
609  }
610  else
611  {
612  ret = (*(const unsigned char*)(*ptr) - 0x80) / 2;
613  (*ptr)++;
614  }
615  return ret;
616 }
617 
618 static unsigned short fetch_ushort(const BYTE** ptr)
619 {
620  unsigned short ret;
621 
622  if (*(*ptr) & 1)
623  {
624  ret = *(const unsigned short*)(*ptr) / 2;
625  (*ptr) += 2;
626  }
627  else
628  {
629  ret = *(const unsigned char*)(*ptr) / 2;
630  (*ptr)++;
631  }
632  return ret;
633 }
634 
635 /******************************************************************
636  * HLPFILE_DecompressGfx
637  *
638  * Decompress the data part of a bitmap or a metafile
639  */
640 static const BYTE* HLPFILE_DecompressGfx(const BYTE* src, unsigned csz, unsigned sz, BYTE packing,
641  BYTE** alloc)
642 {
643  const BYTE* dst;
644  BYTE* tmp;
645  unsigned sz77;
646 
647  WINE_TRACE("Unpacking (%d) from %u bytes to %u bytes\n", packing, csz, sz);
648 
649  switch (packing)
650  {
651  case 0: /* uncompressed */
652  if (sz != csz)
653  WINE_WARN("Bogus gfx sizes (uncompressed): %u / %u\n", sz, csz);
654  dst = src;
655  *alloc = NULL;
656  break;
657  case 1: /* RunLen */
658  dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz);
659  if (!dst) return NULL;
660  HLPFILE_UncompressRLE(src, src + csz, *alloc, sz);
661  break;
662  case 2: /* LZ77 */
663  sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz);
664  dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz77);
665  if (!dst) return NULL;
666  HLPFILE_UncompressLZ77(src, src + csz, *alloc);
667  if (sz77 != sz)
668  WINE_WARN("Bogus gfx sizes (LZ77): %u / %u\n", sz77, sz);
669  break;
670  case 3: /* LZ77 then RLE */
671  sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz);
672  tmp = HeapAlloc(GetProcessHeap(), 0, sz77);
673  if (!tmp) return FALSE;
674  HLPFILE_UncompressLZ77(src, src + csz, tmp);
675  dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz);
676  if (!dst)
677  {
678  HeapFree(GetProcessHeap(), 0, tmp);
679  return FALSE;
680  }
681  HLPFILE_UncompressRLE(tmp, tmp + sz77, *alloc, sz);
682  HeapFree(GetProcessHeap(), 0, tmp);
683  break;
684  default:
685  WINE_FIXME("Unsupported packing %u\n", packing);
686  return NULL;
687  }
688  return dst;
689 }
690 
691 static BOOL HLPFILE_RtfAddRawString(struct RtfData* rd, const char* str, size_t sz)
692 {
693  if (rd->ptr + sz >= rd->data + rd->allocated)
694  {
695  char* new = HeapReAlloc(GetProcessHeap(), 0, rd->data, rd->allocated *= 2);
696  if (!new) return FALSE;
697  rd->ptr = new + (rd->ptr - rd->data);
698  rd->data = new;
699  }
700  memcpy(rd->ptr, str, sz);
701  rd->ptr += sz;
702 
703  return TRUE;
704 }
705 
706 static BOOL HLPFILE_RtfAddControl(struct RtfData* rd, const char* str)
707 {
708  WINE_TRACE("%s\n", debugstr_a(str));
709  if (*str == '\\' || *str == '{') rd->in_text = FALSE;
710  else if (*str == '}') rd->in_text = TRUE;
711  return HLPFILE_RtfAddRawString(rd, str, strlen(str));
712 }
713 
714 static BOOL HLPFILE_RtfAddText(struct RtfData* rd, const char* str)
715 {
716  const char* p;
717  const char* last;
718  const char* replace;
719  unsigned rlen;
720 
721  if (!rd->in_text)
722  {
723  if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE;
724  rd->in_text = TRUE;
725  }
726  for (last = p = str; *p; p++)
727  {
728  if (*p & 0x80) /* escape non-ASCII chars */
729  {
730  static char xx[8];
731  rlen = sprintf(xx, "\\'%x", *(const BYTE*)p);
732  replace = xx;
733  }
734  else switch (*p)
735  {
736  case '{': rlen = 2; replace = "\\{"; break;
737  case '}': rlen = 2; replace = "\\}"; break;
738  case '\\': rlen = 2; replace = "\\\\"; break;
739  default: continue;
740  }
741  if ((p != last && !HLPFILE_RtfAddRawString(rd, last, p - last)) ||
742  !HLPFILE_RtfAddRawString(rd, replace, rlen)) return FALSE;
743  last = p + 1;
744  }
745  return HLPFILE_RtfAddRawString(rd, last, p - last);
746 }
747 
748 /******************************************************************
749  * RtfAddHexBytes
750  *
751  */
752 static BOOL HLPFILE_RtfAddHexBytes(struct RtfData* rd, const void* _ptr, unsigned sz)
753 {
754  char tmp[512];
755  unsigned i, step;
756  const BYTE* ptr = _ptr;
757  static const char* _2hex = "0123456789abcdef";
758 
759  if (!rd->in_text)
760  {
761  if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE;
762  rd->in_text = TRUE;
763  }
764  for (; sz; sz -= step)
765  {
766  step = min(256, sz);
767  for (i = 0; i < step; i++)
768  {
769  tmp[2 * i + 0] = _2hex[*ptr >> 4];
770  tmp[2 * i + 1] = _2hex[*ptr++ & 0xF];
771  }
772  if (!HLPFILE_RtfAddRawString(rd, tmp, 2 * step)) return FALSE;
773  }
774  return TRUE;
775 }
776 
777 static HLPFILE_LINK* HLPFILE_AllocLink(struct RtfData* rd, int cookie,
778  const char* str, unsigned len, LONG hash,
779  BOOL clrChange, BOOL bHotSpot, unsigned wnd);
780 
781 /******************************************************************
782  * HLPFILE_AddHotSpotLinks
783  *
784  */
785 static void HLPFILE_AddHotSpotLinks(struct RtfData* rd, HLPFILE* file,
786  const BYTE* start, ULONG hs_size, ULONG hs_offset)
787 {
788  unsigned i, hs_num;
789  ULONG hs_macro;
790  const char* str;
791 
792  if (hs_size == 0 || hs_offset == 0) return;
793 
794  start += hs_offset;
795  /* always 1 ?? */
796  hs_num = GET_USHORT(start, 1);
797  hs_macro = GET_UINT(start, 3);
798 
799  str = (const char*)start + 7 + 15 * hs_num + hs_macro;
800  /* FIXME: should use hs_size to prevent out of bounds reads */
801  for (i = 0; i < hs_num; i++)
802  {
803  HLPFILE_HOTSPOTLINK* hslink;
804 
805  WINE_TRACE("%02x-%02x%02x {%s,%s}\n",
806  start[7 + 15 * i + 0], start[7 + 15 * i + 1], start[7 + 15 * i + 2],
807  debugstr_a(str), debugstr_a(str + strlen(str) + 1));
808  /* str points to two null terminated strings:
809  * hotspot name, then link name
810  */
811  str += strlen(str) + 1; /* skip hotspot name */
812 
813  hslink = NULL;
814  switch (start[7 + 15 * i + 0])
815  /* The next two chars always look like 0x04 0x00 ???
816  * What are they for ?
817  */
818  {
819  case 0xC8:
820  hslink = (HLPFILE_HOTSPOTLINK*)
821  HLPFILE_AllocLink(rd, hlp_link_macro, str, -1, 0, FALSE, TRUE, -1);
822  break;
823 
824  case 0xE6:
825  case 0xE7:
826  hslink = (HLPFILE_HOTSPOTLINK*)
827  HLPFILE_AllocLink(rd, (start[7 + 15 * i + 0] & 1) ? hlp_link_link : hlp_link_popup,
828  file->lpszPath, -1, HLPFILE_Hash(str),
829  FALSE, TRUE, -1);
830  break;
831 
832  case 0xEE:
833  case 0xEF:
834  {
835  const char* win = strchr(str, '>');
836  int wnd = -1;
837  char* tgt = NULL;
838 
839  if (win)
840  {
841  for (wnd = file->numWindows - 1; wnd >= 0; wnd--)
842  {
843  if (!strcmp(win + 1, file->windows[wnd].name)) break;
844  }
845  if (wnd == -1)
846  WINE_WARN("Couldn't find window info for %s\n", debugstr_a(win));
847  if ((tgt = HeapAlloc(GetProcessHeap(), 0, win - str + 1)))
848  {
849  memcpy(tgt, str, win - str);
850  tgt[win - str] = '\0';
851  }
852  }
853  hslink = (HLPFILE_HOTSPOTLINK*)
854  HLPFILE_AllocLink(rd, (start[7 + 15 * i + 0] & 1) ? hlp_link_link : hlp_link_popup,
855  file->lpszPath, -1, HLPFILE_Hash(tgt ? tgt : str), FALSE, TRUE, wnd);
856  HeapFree(GetProcessHeap(), 0, tgt);
857  break;
858  }
859  default:
860  WINE_FIXME("unknown hotsport target 0x%x\n", start[7 + 15 * i + 0]);
861  }
862  if (hslink)
863  {
864  hslink->x = GET_USHORT(start, 7 + 15 * i + 3);
865  hslink->y = GET_USHORT(start, 7 + 15 * i + 5);
866  hslink->width = GET_USHORT(start, 7 + 15 * i + 7);
867  hslink->height = GET_USHORT(start, 7 + 15 * i + 9);
868  /* target = GET_UINT(start, 7 + 15 * i + 11); */
869  }
870  str += strlen(str) + 1;
871  }
872 }
873 
874 /******************************************************************
875  * HLPFILE_RtfAddTransparentBitmap
876  *
877  * We'll transform a transparent bitmap into an metafile that
878  * we then transform into RTF
879  */
881  const void* pict, unsigned nc)
882 {
883  HDC hdc, hdcMask, hdcMem, hdcEMF;
884  HBITMAP hbm, hbmMask, hbmOldMask, hbmOldMem;
885  HENHMETAFILE hEMF;
886  BOOL ret = FALSE;
887  void* data;
888  UINT sz;
889 
890  hbm = CreateDIBitmap(hdc = GetDC(0), &bi->bmiHeader,
891  CBM_INIT, pict, bi, DIB_RGB_COLORS);
892 
893  hdcMem = CreateCompatibleDC(hdc);
894  hbmOldMem = SelectObject(hdcMem, hbm);
895 
896  /* create the mask bitmap from the main bitmap */
897  hdcMask = CreateCompatibleDC(hdc);
898  hbmMask = CreateBitmap(bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, 1, 1, NULL);
899  hbmOldMask = SelectObject(hdcMask, hbmMask);
900  SetBkColor(hdcMem,
901  RGB(bi->bmiColors[nc - 1].rgbRed,
902  bi->bmiColors[nc - 1].rgbGreen,
903  bi->bmiColors[nc - 1].rgbBlue));
904  BitBlt(hdcMask, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCCOPY);
905 
906  /* sets to RGB(0,0,0) the transparent bits in main bitmap */
907  SetBkColor(hdcMem, RGB(0,0,0));
908  SetTextColor(hdcMem, RGB(255,255,255));
909  BitBlt(hdcMem, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMask, 0, 0, SRCAND);
910 
911  SelectObject(hdcMask, hbmOldMask);
912  DeleteDC(hdcMask);
913 
914  SelectObject(hdcMem, hbmOldMem);
915  DeleteDC(hdcMem);
916 
917  /* we create the bitmap on the fly */
918  hdcEMF = CreateEnhMetaFileW(NULL, NULL, NULL, NULL);
919  hdcMem = CreateCompatibleDC(hdcEMF);
920 
921  /* sets to RGB(0,0,0) the transparent bits in final bitmap */
922  hbmOldMem = SelectObject(hdcMem, hbmMask);
923  SetBkColor(hdcEMF, RGB(255, 255, 255));
924  SetTextColor(hdcEMF, RGB(0, 0, 0));
925  BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCAND);
926 
927  /* and copy the remaining bits of main bitmap */
928  SelectObject(hdcMem, hbm);
929  BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCPAINT);
930  SelectObject(hdcMem, hbmOldMem);
931  DeleteDC(hdcMem);
932 
933  /* do the cleanup */
934  ReleaseDC(0, hdc);
935  DeleteObject(hbmMask);
936  DeleteObject(hbm);
937 
938  hEMF = CloseEnhMetaFile(hdcEMF);
939 
940  /* generate rtf stream */
941  sz = GetEnhMetaFileBits(hEMF, 0, NULL);
942  if (sz && (data = HeapAlloc(GetProcessHeap(), 0, sz)))
943  {
944  if (sz == GetEnhMetaFileBits(hEMF, sz, data))
945  {
946  ret = HLPFILE_RtfAddControl(rd, "{\\pict\\emfblip") &&
947  HLPFILE_RtfAddHexBytes(rd, data, sz) &&
948  HLPFILE_RtfAddControl(rd, "}");
949  }
950  HeapFree(GetProcessHeap(), 0, data);
951  }
952  DeleteEnhMetaFile(hEMF);
953 
954  return ret;
955 }
956 
957 /******************************************************************
958  * HLPFILE_RtfAddBitmap
959  *
960  */
961 static BOOL HLPFILE_RtfAddBitmap(struct RtfData* rd, HLPFILE* file, const BYTE* beg, BYTE type, BYTE pack)
962 {
963  const BYTE* ptr;
964  const BYTE* pict_beg;
965  BYTE* alloc = NULL;
966  BITMAPINFO* bi;
967  ULONG off, csz;
968  unsigned nc = 0;
969  BOOL clrImportant = FALSE;
970  BOOL ret = FALSE;
971  char tmp[256];
972  unsigned hs_size, hs_offset;
973 
974  bi = HeapAlloc(GetProcessHeap(), 0, sizeof(*bi));
975  if (!bi) return FALSE;
976 
977  ptr = beg + 2; /* for type and pack */
978 
979  bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
982  bi->bmiHeader.biPlanes = fetch_ushort(&ptr);
983  bi->bmiHeader.biBitCount = fetch_ushort(&ptr);
984  bi->bmiHeader.biWidth = fetch_ulong(&ptr);
985  bi->bmiHeader.biHeight = fetch_ulong(&ptr);
986  bi->bmiHeader.biClrUsed = fetch_ulong(&ptr);
987  clrImportant = fetch_ulong(&ptr);
988  bi->bmiHeader.biClrImportant = (clrImportant > 1) ? clrImportant : 0;
990  if (bi->bmiHeader.biBitCount > 32) WINE_FIXME("Unknown bit count %u\n", bi->bmiHeader.biBitCount);
991  if (bi->bmiHeader.biPlanes != 1) WINE_FIXME("Unsupported planes %u\n", bi->bmiHeader.biPlanes);
992  bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8) * bi->bmiHeader.biHeight;
993  WINE_TRACE("planes=%d bc=%d size=(%d,%d)\n",
996 
997  csz = fetch_ulong(&ptr);
998  hs_size = fetch_ulong(&ptr);
999 
1000  off = GET_UINT(ptr, 0); ptr += 4;
1001  hs_offset = GET_UINT(ptr, 0); ptr += 4;
1002  HLPFILE_AddHotSpotLinks(rd, file, beg, hs_size, hs_offset);
1003 
1004  /* now read palette info */
1005  if (type == 0x06)
1006  {
1007  unsigned i;
1008 
1009  nc = bi->bmiHeader.biClrUsed;
1010  /* not quite right, especially for bitfields type of compression */
1011  if (!nc && bi->bmiHeader.biBitCount <= 8)
1012  nc = 1 << bi->bmiHeader.biBitCount;
1013 
1014  bi = HeapReAlloc(GetProcessHeap(), 0, bi, sizeof(*bi) + nc * sizeof(RGBQUAD));
1015  if (!bi) return FALSE;
1016  for (i = 0; i < nc; i++)
1017  {
1018  bi->bmiColors[i].rgbBlue = ptr[0];
1019  bi->bmiColors[i].rgbGreen = ptr[1];
1020  bi->bmiColors[i].rgbRed = ptr[2];
1021  bi->bmiColors[i].rgbReserved = 0;
1022  ptr += 4;
1023  }
1024  }
1025  pict_beg = HLPFILE_DecompressGfx(beg + off, csz, bi->bmiHeader.biSizeImage, pack, &alloc);
1026 
1027  if (clrImportant == 1 && nc > 0)
1028  {
1029  ret = HLPFILE_RtfAddTransparentBitmap(rd, bi, pict_beg, nc);
1030  goto done;
1031  }
1032  if (!HLPFILE_RtfAddControl(rd, "{\\pict")) goto done;
1033  if (type == 0x06)
1034  {
1035  sprintf(tmp, "\\dibitmap0\\picw%d\\pich%d",
1036  bi->bmiHeader.biWidth, bi->bmiHeader.biHeight);
1037  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1038  if (!HLPFILE_RtfAddHexBytes(rd, bi, sizeof(*bi) + nc * sizeof(RGBQUAD))) goto done;
1039  }
1040  else
1041  {
1042  sprintf(tmp, "\\wbitmap0\\wbmbitspixel%d\\wbmplanes%d\\picw%d\\pich%d",
1044  bi->bmiHeader.biWidth, bi->bmiHeader.biHeight);
1045  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1046  }
1047  if (!HLPFILE_RtfAddHexBytes(rd, pict_beg, bi->bmiHeader.biSizeImage)) goto done;
1048  if (!HLPFILE_RtfAddControl(rd, "}")) goto done;
1049 
1050  ret = TRUE;
1051 done:
1052  HeapFree(GetProcessHeap(), 0, bi);
1053  HeapFree(GetProcessHeap(), 0, alloc);
1054 
1055  return ret;
1056 }
1057 
1058 /******************************************************************
1059  * HLPFILE_RtfAddMetaFile
1060  *
1061  */
1062 static BOOL HLPFILE_RtfAddMetaFile(struct RtfData* rd, HLPFILE* file, const BYTE* beg, BYTE pack)
1063 {
1064  ULONG size, csize, off, hs_offset, hs_size;
1065  const BYTE* ptr;
1066  const BYTE* bits;
1067  BYTE* alloc = NULL;
1068  char tmp[256];
1069  unsigned mm;
1070  BOOL ret;
1071 
1072  WINE_TRACE("Loading metafile\n");
1073 
1074  ptr = beg + 2; /* for type and pack */
1075 
1076  mm = fetch_ushort(&ptr); /* mapping mode */
1077  sprintf(tmp, "{\\pict\\wmetafile%u\\picw%u\\pich%u",
1078  mm, GET_USHORT(ptr, 0), GET_USHORT(ptr, 2));
1079  if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;
1080  ptr += 4;
1081 
1082  size = fetch_ulong(&ptr); /* decompressed size */
1083  csize = fetch_ulong(&ptr); /* compressed size */
1084  hs_size = fetch_ulong(&ptr); /* hotspot size */
1085  off = GET_UINT(ptr, 0);
1086  hs_offset = GET_UINT(ptr, 4);
1087  ptr += 8;
1088 
1089  HLPFILE_AddHotSpotLinks(rd, file, beg, hs_size, hs_offset);
1090 
1091  WINE_TRACE("sz=%u csz=%u offs=%u/%u,%u/%u\n",
1092  size, csize, off, (ULONG)(ptr - beg), hs_size, hs_offset);
1093 
1094  bits = HLPFILE_DecompressGfx(beg + off, csize, size, pack, &alloc);
1095  if (!bits) return FALSE;
1096 
1097  ret = HLPFILE_RtfAddHexBytes(rd, bits, size) &&
1098  HLPFILE_RtfAddControl(rd, "}");
1099 
1100  HeapFree(GetProcessHeap(), 0, alloc);
1101 
1102  return ret;
1103 }
1104 
1105 /******************************************************************
1106  * HLPFILE_RtfAddGfxByAddr
1107  *
1108  */
1109 static BOOL HLPFILE_RtfAddGfxByAddr(struct RtfData* rd, HLPFILE *hlpfile,
1110  const BYTE* ref, ULONG size)
1111 {
1112  unsigned i, numpict;
1113 
1114  numpict = GET_USHORT(ref, 2);
1115  WINE_TRACE("Got picture magic=%04x #=%d\n", GET_USHORT(ref, 0), numpict);
1116 
1117  for (i = 0; i < numpict; i++)
1118  {
1119  const BYTE* beg;
1120  const BYTE* ptr;
1121  BYTE type, pack;
1122 
1123  WINE_TRACE("Offset[%d] = %x\n", i, GET_UINT(ref, (1 + i) * 4));
1124  beg = ptr = ref + GET_UINT(ref, (1 + i) * 4);
1125 
1126  type = *ptr++;
1127  pack = *ptr++;
1128 
1129  switch (type)
1130  {
1131  case 5: /* device dependent bmp */
1132  case 6: /* device independent bmp */
1133  HLPFILE_RtfAddBitmap(rd, hlpfile, beg, type, pack);
1134  break;
1135  case 8:
1136  HLPFILE_RtfAddMetaFile(rd, hlpfile, beg, pack);
1137  break;
1138  default: WINE_FIXME("Unknown type %u\n", type); return FALSE;
1139  }
1140 
1141  /* FIXME: hotspots */
1142 
1143  /* FIXME: implement support for multiple picture format */
1144  if (numpict != 1) WINE_FIXME("Supporting only one bitmap format per logical bitmap (for now). Using first format\n");
1145  break;
1146  }
1147  return TRUE;
1148 }
1149 
1150 /******************************************************************
1151  * HLPFILE_RtfAddGfxByIndex
1152  *
1153  *
1154  */
1155 static BOOL HLPFILE_RtfAddGfxByIndex(struct RtfData* rd, HLPFILE *hlpfile,
1156  unsigned index)
1157 {
1158  char tmp[16];
1159  BYTE *ref, *end;
1160 
1161  WINE_TRACE("Loading picture #%d\n", index);
1162 
1163  sprintf(tmp, "|bm%u", index);
1164 
1165  if (!HLPFILE_FindSubFile(hlpfile, tmp, &ref, &end)) {WINE_WARN("no sub file\n"); return FALSE;}
1166 
1167  ref += 9;
1168  return HLPFILE_RtfAddGfxByAddr(rd, hlpfile, ref, end - ref);
1169 }
1170 
1171 /******************************************************************
1172  * HLPFILE_AllocLink
1173  *
1174  *
1175  */
1176 static HLPFILE_LINK* HLPFILE_AllocLink(struct RtfData* rd, int cookie,
1177  const char* str, unsigned len, LONG hash,
1178  BOOL clrChange, BOOL bHotSpot, unsigned wnd)
1179 {
1180  HLPFILE_LINK* link;
1181  char* link_str;
1182  unsigned asz = bHotSpot ? sizeof(HLPFILE_HOTSPOTLINK) : sizeof(HLPFILE_LINK);
1183 
1184  /* FIXME: should build a string table for the attributes.link.lpszPath
1185  * they are reallocated for each link
1186  */
1187  if (len == -1) len = strlen(str);
1188  link = HeapAlloc(GetProcessHeap(), 0, asz + len + 1);
1189  if (!link) return NULL;
1190 
1191  link->cookie = cookie;
1192  link->string = link_str = (char*)link + asz;
1193  memcpy(link_str, str, len);
1194  link_str[len] = '\0';
1195  link->hash = hash;
1196  link->bClrChange = clrChange;
1197  link->bHotSpot = bHotSpot;
1198  link->window = wnd;
1199  link->next = rd->first_link;
1200  rd->first_link = link;
1201  link->cpMin = rd->char_pos;
1202  rd->force_color = clrChange;
1203  if (rd->current_link) WINE_FIXME("Pending link\n");
1204  if (bHotSpot)
1205  link->cpMax = rd->char_pos;
1206  else
1207  rd->current_link = link;
1208 
1209  WINE_TRACE("Link[%d] to %s@%08x:%d\n",
1210  link->cookie, debugstr_a(link->string), link->hash, link->window);
1211  return link;
1212 }
1213 
1214 static unsigned HLPFILE_HalfPointsScale(HLPFILE_PAGE* page, unsigned pts)
1215 {
1216  return pts * page->file->scale - page->file->rounderr;
1217 }
1218 
1219 /***********************************************************************
1220  *
1221  * HLPFILE_BrowseParagraph
1222  */
1224  BYTE *buf, BYTE* end, unsigned* parlen)
1225 {
1226  UINT textsize;
1227  const BYTE *format, *format_end;
1228  char *text, *text_base, *text_end;
1229  LONG size, blocksize, datalen;
1230  unsigned short bits;
1231  unsigned ncol = 1;
1232  short nc, lastcol, table_width;
1233  char tmp[256];
1234  BOOL ret = FALSE;
1235 
1236  if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};
1237 
1238  *parlen = 0;
1239  blocksize = GET_UINT(buf, 0);
1240  size = GET_UINT(buf, 0x4);
1241  datalen = GET_UINT(buf, 0x10);
1242  text = text_base = HeapAlloc(GetProcessHeap(), 0, size);
1243  if (!text) return FALSE;
1244  if (size > blocksize - datalen)
1245  {
1246  /* need to decompress */
1247  if (page->file->hasPhrases)
1248  HLPFILE_Uncompress2(page->file, buf + datalen, end, (BYTE*)text, (BYTE*)text + size);
1249  else if (page->file->hasPhrases40)
1250  HLPFILE_Uncompress3(page->file, text, text + size, buf + datalen, end);
1251  else
1252  {
1253  WINE_FIXME("Text size is too long, splitting\n");
1254  size = blocksize - datalen;
1255  memcpy(text, buf + datalen, size);
1256  }
1257  }
1258  else
1259  memcpy(text, buf + datalen, size);
1260 
1261  text_end = text + size;
1262 
1263  format = buf + 0x15;
1264  format_end = buf + GET_UINT(buf, 0x10);
1265 
1266  WINE_TRACE("Record type (buf[0x14]) = 0x%x\n", buf[0x14]);
1267 
1268  if (buf[0x14] == HLP_DISPLAY || buf[0x14] == HLP_TABLE)
1269  {
1270  fetch_long(&format);
1271  *parlen = fetch_ushort(&format);
1272  }
1273 
1274  if (buf[0x14] == HLP_TABLE)
1275  {
1276  unsigned char type;
1277 
1278  ncol = *format++;
1279 
1280  if (!HLPFILE_RtfAddControl(rd, "\\trowd")) goto done;
1281  type = *format++;
1282  if (type == 0 || type == 2)
1283  {
1284  table_width = GET_SHORT(format, 0);
1285  format += 2;
1286  if (!HLPFILE_RtfAddControl(rd, "\\trqc")) goto done;
1287  }
1288  else
1289  table_width = 32767;
1290  WINE_TRACE("New table: cols=%d type=%x width=%d\n",
1291  ncol, type, table_width);
1292  if (ncol > 1)
1293  {
1294  int pos;
1295  sprintf(tmp, "\\trgaph%d\\trleft%d",
1296  MulDiv(HLPFILE_HalfPointsScale(page, GET_SHORT(format, 6)), table_width, 32767),
1297  MulDiv(HLPFILE_HalfPointsScale(page, GET_SHORT(format, 2) - GET_SHORT(format, 6)), table_width, 32767) - 1);
1298  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1299  pos = GET_SHORT(format, 6) / 2;
1300  for (nc = 0; nc < ncol; nc++)
1301  {
1302  WINE_TRACE("column(%d/%d) gap=%d width=%d\n",
1303  nc, ncol, GET_SHORT(format, nc*4),
1304  GET_SHORT(format, nc*4+2));
1305  pos += GET_SHORT(format, nc * 4) + GET_SHORT(format, nc * 4 + 2);
1306  sprintf(tmp, "\\cellx%d",
1307  MulDiv(HLPFILE_HalfPointsScale(page, pos), table_width, 32767));
1308  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1309  }
1310  }
1311  else
1312  {
1313  WINE_TRACE("column(0/%d) gap=%d width=%d\n",
1314  ncol, GET_SHORT(format, 0), GET_SHORT(format, 2));
1315  sprintf(tmp, "\\trleft%d\\cellx%d ",
1316  MulDiv(HLPFILE_HalfPointsScale(page, GET_SHORT(format, 2)), table_width, 32767) - 1,
1317  MulDiv(HLPFILE_HalfPointsScale(page, GET_SHORT(format, 0)), table_width, 32767));
1318  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1319  }
1320  format += ncol * 4;
1321  }
1322 
1323  lastcol = -1;
1324  for (nc = 0; nc < ncol; )
1325  {
1326  WINE_TRACE("looking for format at offset %lu in column %d\n", (SIZE_T)(format - (buf + 0x15)), nc);
1327  if (!HLPFILE_RtfAddControl(rd, "\\pard")) goto done;
1328  if (buf[0x14] == HLP_TABLE)
1329  {
1330  nc = lastcol = GET_SHORT(format, 0);
1331  if (nc == -1) /* last column */
1332  {
1333  if (!HLPFILE_RtfAddControl(rd, "\\row")) goto done;
1334  rd->char_pos += 2;
1335  break;
1336  }
1337  format += 5;
1338  if (!HLPFILE_RtfAddControl(rd, "\\intbl")) goto done;
1339  }
1340  else nc++;
1341  if (buf[0x14] == HLP_DISPLAY30)
1342  format += 6;
1343  else
1344  format += 4;
1345  bits = GET_USHORT(format, 0); format += 2;
1346  if (bits & 0x0001) fetch_long(&format);
1347  if (bits & 0x0002)
1348  {
1349  sprintf(tmp, "\\sb%d", HLPFILE_HalfPointsScale(page, fetch_short(&format)));
1350  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1351  }
1352  if (bits & 0x0004)
1353  {
1354  sprintf(tmp, "\\sa%d", HLPFILE_HalfPointsScale(page, fetch_short(&format)));
1355  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1356  }
1357  if (bits & 0x0008)
1358  {
1359  sprintf(tmp, "\\sl%d", HLPFILE_HalfPointsScale(page, fetch_short(&format)));
1360  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1361  }
1362  if (bits & 0x0010)
1363  {
1364  sprintf(tmp, "\\li%d", HLPFILE_HalfPointsScale(page, fetch_short(&format)));
1365  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1366  }
1367  if (bits & 0x0020)
1368  {
1369  sprintf(tmp, "\\ri%d", HLPFILE_HalfPointsScale(page, fetch_short(&format)));
1370  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1371  }
1372  if (bits & 0x0040)
1373  {
1374  sprintf(tmp, "\\fi%d", HLPFILE_HalfPointsScale(page, fetch_short(&format)));
1375  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1376  }
1377  if (bits & 0x0100)
1378  {
1379  BYTE brdr = *format++;
1380  short w;
1381 
1382  if ((brdr & 0x01) && !HLPFILE_RtfAddControl(rd, "\\box")) goto done;
1383  if ((brdr & 0x02) && !HLPFILE_RtfAddControl(rd, "\\brdrt")) goto done;
1384  if ((brdr & 0x04) && !HLPFILE_RtfAddControl(rd, "\\brdrl")) goto done;
1385  if ((brdr & 0x08) && !HLPFILE_RtfAddControl(rd, "\\brdrb")) goto done;
1386  if ((brdr & 0x10) && !HLPFILE_RtfAddControl(rd, "\\brdrr")) goto done;
1387  if ((brdr & 0x20) && !HLPFILE_RtfAddControl(rd, "\\brdrth")) goto done;
1388  if (!(brdr & 0x20) && !HLPFILE_RtfAddControl(rd, "\\brdrs")) goto done;
1389  if ((brdr & 0x40) && !HLPFILE_RtfAddControl(rd, "\\brdrdb")) goto done;
1390  /* 0x80: unknown */
1391 
1392  w = GET_SHORT(format, 0); format += 2;
1393  if (w)
1394  {
1395  sprintf(tmp, "\\brdrw%d", HLPFILE_HalfPointsScale(page, w));
1396  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1397  }
1398  }
1399  if (bits & 0x0200)
1400  {
1401  int i, ntab = fetch_short(&format);
1402  unsigned tab, ts;
1403  const char* kind;
1404 
1405  for (i = 0; i < ntab; i++)
1406  {
1407  tab = fetch_ushort(&format);
1408  ts = (tab & 0x4000) ? fetch_ushort(&format) : 0 /* left */;
1409  switch (ts)
1410  {
1411  default: WINE_FIXME("Unknown tab style %x\n", ts);
1412  /* fall through */
1413  case 0: kind = ""; break;
1414  case 1: kind = "\\tqr"; break;
1415  case 2: kind = "\\tqc"; break;
1416  }
1417  /* FIXME: do kind */
1418  sprintf(tmp, "%s\\tx%d",
1419  kind, HLPFILE_HalfPointsScale(page, tab & 0x3FFF));
1420  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1421  }
1422  }
1423  switch (bits & 0xc00)
1424  {
1425  default: WINE_FIXME("Unsupported alignment 0xC00\n"); break;
1426  case 0: if (!HLPFILE_RtfAddControl(rd, "\\ql")) goto done; break;
1427  case 0x400: if (!HLPFILE_RtfAddControl(rd, "\\qr")) goto done; break;
1428  case 0x800: if (!HLPFILE_RtfAddControl(rd, "\\qc")) goto done; break;
1429  }
1430 
1431  /* 0x1000 doesn't need space */
1432  if ((bits & 0x1000) && !HLPFILE_RtfAddControl(rd, "\\keep")) goto done;
1433  if ((bits & 0xE080) != 0)
1434  WINE_FIXME("Unsupported bits %04x, potential trouble ahead\n", bits);
1435 
1436  while (text < text_end && format < format_end)
1437  {
1438  WINE_TRACE("Got text: %s (%p/%p - %p/%p)\n", debugstr_a(text), text, text_end, format, format_end);
1439  textsize = strlen(text);
1440  if (textsize)
1441  {
1442  if (rd->force_color)
1443  {
1444  if ((rd->current_link->cookie == hlp_link_popup) ?
1445  !HLPFILE_RtfAddControl(rd, "{\\uld\\cf1") :
1446  !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1")) goto done;
1447  }
1448  if (!HLPFILE_RtfAddText(rd, text)) goto done;
1449  if (rd->force_color && !HLPFILE_RtfAddControl(rd, "}")) goto done;
1450  rd->char_pos += textsize;
1451  }
1452  /* else: null text, keep on storing attributes */
1453  text += textsize + 1;
1454 
1455  WINE_TRACE("format=0x%02x\n", *format);
1456  if (*format == 0xff)
1457  {
1458  format++;
1459  break;
1460  }
1461 
1462  switch (*format)
1463  {
1464  case 0x20:
1465  WINE_FIXME("NIY20\n");
1466  format += 5;
1467  break;
1468 
1469  case 0x21:
1470  WINE_FIXME("NIY21\n");
1471  format += 3;
1472  break;
1473 
1474  case 0x80:
1475  {
1476  unsigned font = GET_USHORT(format, 1);
1477  unsigned fs;
1478 
1479  WINE_TRACE("Changing font to %d\n", font);
1480  format += 3;
1481  /* Font size in hlpfile is given in the same units as
1482  rtf control word \fs uses (half-points). */
1483  switch (rd->font_scale)
1484  {
1485  case 0: fs = page->file->fonts[font].LogFont.lfHeight - 4; break;
1486  default:
1487  case 1: fs = page->file->fonts[font].LogFont.lfHeight; break;
1488  case 2: fs = page->file->fonts[font].LogFont.lfHeight + 4; break;
1489  }
1490  /* FIXME: colors are missing, at a minimum; also, the bold attribute loses information */
1491 
1492  sprintf(tmp, "\\f%u\\cf%u\\fs%u%s%s%s%s",
1493  font, font + 2, fs,
1494  page->file->fonts[font].LogFont.lfWeight > 400 ? "\\b" : "\\b0",
1495  page->file->fonts[font].LogFont.lfItalic ? "\\i" : "\\i0",
1496  page->file->fonts[font].LogFont.lfUnderline ? "\\ul" : "\\ul0",
1497  page->file->fonts[font].LogFont.lfStrikeOut ? "\\strike" : "\\strike0");
1498  if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;
1499  }
1500  break;
1501 
1502  case 0x81:
1503  if (!HLPFILE_RtfAddControl(rd, "\\line")) goto done;
1504  format += 1;
1505  rd->char_pos++;
1506  break;
1507 
1508  case 0x82:
1509  if (buf[0x14] == HLP_TABLE)
1510  {
1511  if (format[1] != 0xFF)
1512  {
1513  if (!HLPFILE_RtfAddControl(rd, "\\par\\intbl")) goto done;
1514  }
1515  else if (GET_SHORT(format, 2) == -1)
1516  {
1517  if (!HLPFILE_RtfAddControl(rd, "\\cell\\intbl\\row")) goto done;
1518  rd->char_pos += 2;
1519  }
1520  else if (GET_SHORT(format, 2) == lastcol)
1521  {
1522  if (!HLPFILE_RtfAddControl(rd, "\\par\\pard")) goto done;
1523  }
1524  else
1525  {
1526  if (!HLPFILE_RtfAddControl(rd, "\\cell\\pard")) goto done;
1527  }
1528  }
1529  else if (!HLPFILE_RtfAddControl(rd, "\\par")) goto done;
1530  format += 1;
1531  rd->char_pos++;
1532  break;
1533 
1534  case 0x83:
1535  if (!HLPFILE_RtfAddControl(rd, "\\tab")) goto done;
1536  format += 1;
1537  rd->char_pos++;
1538  break;
1539 
1540 #if 0
1541  case 0x84:
1542  format += 3;
1543  break;
1544 #endif
1545 
1546  case 0x86:
1547  case 0x87:
1548  case 0x88:
1549  {
1550  BYTE type = format[1];
1551 
1552  /* FIXME: we don't use 'BYTE pos = (*format - 0x86);' for the image position */
1553  format += 2;
1554  size = fetch_long(&format);
1555 
1556  switch (type)
1557  {
1558  case 0x22:
1559  fetch_ushort(&format); /* hot spot */
1560  /* fall through */
1561  case 0x03:
1562  switch (GET_SHORT(format, 0))
1563  {
1564  case 0:
1565  HLPFILE_RtfAddGfxByIndex(rd, page->file, GET_SHORT(format, 2));
1566  rd->char_pos++;
1567  break;
1568  case 1:
1569  WINE_FIXME("does it work ??? %x<%u>#%u\n",
1570  GET_SHORT(format, 0),
1571  size, GET_SHORT(format, 2));
1572  HLPFILE_RtfAddGfxByAddr(rd, page->file, format + 2, size - 4);
1573  rd->char_pos++;
1574  break;
1575  default:
1576  WINE_FIXME("??? %u\n", GET_SHORT(format, 0));
1577  break;
1578  }
1579  break;
1580  case 0x05:
1581  WINE_FIXME("Got an embedded element %s\n", debugstr_a((char *)format + 6));
1582  break;
1583  default:
1584  WINE_FIXME("Got a type %d picture\n", type);
1585  break;
1586  }
1587  format += size;
1588  }
1589  break;
1590 
1591  case 0x89:
1592  format += 1;
1593  if (!rd->current_link)
1594  WINE_FIXME("No existing link\n");
1595  rd->current_link->cpMax = rd->char_pos;
1596  rd->current_link = NULL;
1597  rd->force_color = FALSE;
1598  break;
1599 
1600  case 0x8B:
1601  if (!HLPFILE_RtfAddControl(rd, "\\~")) goto done;
1602  format += 1;
1603  rd->char_pos++;
1604  break;
1605 
1606  case 0x8C:
1607  if (!HLPFILE_RtfAddControl(rd, "\\_")) goto done;
1608  /* FIXME: it could be that hyphen is also in input stream !! */
1609  format += 1;
1610  rd->char_pos++;
1611  break;
1612 
1613 #if 0
1614  case 0xA9:
1615  format += 2;
1616  break;
1617 #endif
1618 
1619  case 0xC8:
1620  case 0xCC:
1621  WINE_TRACE("macro => %s\n", debugstr_a((char *)format + 3));
1622  HLPFILE_AllocLink(rd, hlp_link_macro, (const char*)format + 3,
1623  GET_USHORT(format, 1), 0, !(*format & 4), FALSE, -1);
1624  format += 3 + GET_USHORT(format, 1);
1625  break;
1626 
1627  case 0xE0:
1628  case 0xE1:
1629  WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1));
1630  HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,
1631  page->file->lpszPath, -1, GET_UINT(format, 1), TRUE, FALSE, -1);
1632 
1633 
1634  format += 5;
1635  break;
1636 
1637  case 0xE2:
1638  case 0xE3:
1639  case 0xE6:
1640  case 0xE7:
1641  WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1));
1642  HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,
1643  page->file->lpszPath, -1, GET_UINT(format, 1),
1644  !(*format & 4), FALSE, -1);
1645  format += 5;
1646  break;
1647 
1648  case 0xEA:
1649  case 0xEB:
1650  case 0xEE:
1651  case 0xEF:
1652  {
1653  const char* ptr = (const char*) format + 8;
1654  BYTE type = format[3];
1655  int wnd = -1;
1656 
1657  switch (type)
1658  {
1659  case 1:
1660  wnd = *ptr;
1661  /* fall through */
1662  case 0:
1663  ptr = page->file->lpszPath;
1664  break;
1665  case 6:
1666  for (wnd = page->file->numWindows - 1; wnd >= 0; wnd--)
1667  {
1668  if (!strcmp(ptr, page->file->windows[wnd].name)) break;
1669  }
1670  if (wnd == -1)
1671  WINE_WARN("Couldn't find window info for %s\n", debugstr_a(ptr));
1672  ptr += strlen(ptr) + 1;
1673  /* fall through */
1674  case 4:
1675  break;
1676  default:
1677  WINE_WARN("Unknown link type %d\n", type);
1678  break;
1679  }
1680  HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,
1681  ptr, -1, GET_UINT(format, 4), !(*format & 4), FALSE, wnd);
1682  }
1683  format += 3 + GET_USHORT(format, 1);
1684  break;
1685 
1686  default:
1687  WINE_WARN("format %02x\n", *format);
1688  format++;
1689  }
1690  }
1691  }
1692  ret = TRUE;
1693 done:
1694 
1695  HeapFree(GetProcessHeap(), 0, text_base);
1696  return ret;
1697 }
1698 
1699 /******************************************************************
1700  * HLPFILE_BrowsePage
1701  *
1702  */
1704  unsigned font_scale, unsigned relative)
1705 {
1706  HLPFILE *hlpfile = page->file;
1707  BYTE *buf, *end;
1708  DWORD ref = page->reference;
1709  unsigned index, old_index = -1, offset, count = 0, offs = 0;
1710  unsigned cpg, parlen;
1711  char tmp[1024];
1712  const char* ck = NULL;
1713 
1714  rd->in_text = TRUE;
1715  rd->data = rd->ptr = HeapAlloc(GetProcessHeap(), 0, rd->allocated = 32768);
1716  rd->char_pos = 0;
1717  rd->first_link = rd->current_link = NULL;
1718  rd->force_color = FALSE;
1719  rd->font_scale = font_scale;
1720  rd->relative = relative;
1721  rd->char_pos_rel = 0;
1722 
1723  switch (hlpfile->charset)
1724  {
1725  case DEFAULT_CHARSET:
1726  case ANSI_CHARSET: cpg = 1252; break;
1727  case SHIFTJIS_CHARSET: cpg = 932; break;
1728  case HANGEUL_CHARSET: cpg = 949; break;
1729  case GB2312_CHARSET: cpg = 936; break;
1730  case CHINESEBIG5_CHARSET: cpg = 950; break;
1731  case GREEK_CHARSET: cpg = 1253; break;
1732  case TURKISH_CHARSET: cpg = 1254; break;
1733  case HEBREW_CHARSET: cpg = 1255; break;
1734  case ARABIC_CHARSET: cpg = 1256; break;
1735  case BALTIC_CHARSET: cpg = 1257; break;
1736  case VIETNAMESE_CHARSET: cpg = 1258; break;
1737  case RUSSIAN_CHARSET: cpg = 1251; break;
1738  case EE_CHARSET: cpg = 1250; break;
1739  case THAI_CHARSET: cpg = 874; break;
1740  case JOHAB_CHARSET: cpg = 1361; break;
1741  case MAC_CHARSET: ck = "mac"; break;
1742  default:
1743  WINE_FIXME("Unsupported charset %u\n", hlpfile->charset);
1744  cpg = 1252;
1745  }
1746  if (ck)
1747  {
1748  sprintf(tmp, "{\\rtf1\\%s\\deff0", ck);
1749  if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;
1750  }
1751  else
1752  {
1753  sprintf(tmp, "{\\rtf1\\ansi\\ansicpg%d\\deff0", cpg);
1754  if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;
1755  }
1756 
1757  /* generate font table */
1758  if (!HLPFILE_RtfAddControl(rd, "{\\fonttbl")) return FALSE;
1759  for (index = 0; index < hlpfile->numFonts; index++)
1760  {
1761  const char* family;
1762  switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0)
1763  {
1764  case FF_MODERN: family = "modern"; break;
1765  case FF_ROMAN: family = "roman"; break;
1766  case FF_SWISS: family = "swiss"; break;
1767  case FF_SCRIPT: family = "script"; break;
1768  case FF_DECORATIVE: family = "decor"; break;
1769  default: family = "nil"; break;
1770  }
1771  sprintf(tmp, "{\\f%d\\f%s\\fprq%d\\fcharset%d %s;}",
1772  index, family,
1773  hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0x0F,
1774  hlpfile->fonts[index].LogFont.lfCharSet,
1775  hlpfile->fonts[index].LogFont.lfFaceName);
1776  if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;
1777  }
1778  if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE;
1779  /* generate color table */
1780  if (!HLPFILE_RtfAddControl(rd, "{\\colortbl ;\\red0\\green128\\blue0;")) return FALSE;
1781  for (index = 0; index < hlpfile->numFonts; index++)
1782  {
1783  sprintf(tmp, "\\red%d\\green%d\\blue%d;",
1784  GetRValue(hlpfile->fonts[index].color),
1785  GetGValue(hlpfile->fonts[index].color),
1786  GetBValue(hlpfile->fonts[index].color));
1787  if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;
1788  }
1789  if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE;
1790 
1791  do
1792  {
1793  if (hlpfile->version <= 16)
1794  {
1795  index = (ref - 0x0C) / hlpfile->dsize;
1796  offset = (ref - 0x0C) % hlpfile->dsize;
1797  }
1798  else
1799  {
1800  index = (ref - 0x0C) >> 14;
1801  offset = (ref - 0x0C) & 0x3FFF;
1802  }
1803 
1804  if (hlpfile->version <= 16 && index != old_index && old_index != -1)
1805  {
1806  /* we jumped to the next block, adjust pointers */
1807  ref -= 12;
1808  offset -= 12;
1809  }
1810 
1811  if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;}
1812  buf = hlpfile->topic_map[index] + offset;
1813  if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;}
1814  end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end);
1815  if (index != old_index) {offs = 0; old_index = index;}
1816 
1817  switch (buf[0x14])
1818  {
1819  case HLP_TOPICHDR:
1820  if (count++) goto done;
1821  break;
1822  case HLP_DISPLAY30:
1823  case HLP_DISPLAY:
1824  case HLP_TABLE:
1825  if (!HLPFILE_BrowseParagraph(page, rd, buf, end, &parlen)) return FALSE;
1826  if (relative > index * 0x8000 + offs)
1827  rd->char_pos_rel = rd->char_pos;
1828  offs += parlen;
1829  break;
1830  default:
1831  WINE_ERR("buf[0x14] = %x\n", buf[0x14]);
1832  }
1833  if (hlpfile->version <= 16)
1834  {
1835  ref += GET_UINT(buf, 0xc);
1836  if (GET_UINT(buf, 0xc) == 0)
1837  break;
1838  }
1839  else
1840  ref = GET_UINT(buf, 0xc);
1841  } while (ref != 0xffffffff);
1842 done:
1843  page->first_link = rd->first_link;
1844  return HLPFILE_RtfAddControl(rd, "}");
1845 }
1846 
1847 /******************************************************************
1848  * HLPFILE_ReadFont
1849  *
1850  *
1851  */
1853 {
1854  BYTE *ref, *end;
1855  unsigned i, len, idx;
1856  unsigned face_num, dscr_num, face_offset, dscr_offset;
1857  BYTE flag, family;
1858 
1859  if (!HLPFILE_FindSubFile(hlpfile, "|FONT", &ref, &end))
1860  {
1861  WINE_WARN("no subfile FONT\n");
1862  hlpfile->numFonts = 0;
1863  hlpfile->fonts = NULL;
1864  return FALSE;
1865  }
1866 
1867  ref += 9;
1868 
1869  face_num = GET_USHORT(ref, 0);
1870  dscr_num = GET_USHORT(ref, 2);
1871  face_offset = GET_USHORT(ref, 4);
1872  dscr_offset = GET_USHORT(ref, 6);
1873 
1874  WINE_TRACE("Got NumFacenames=%u@%u NumDesc=%u@%u\n",
1875  face_num, face_offset, dscr_num, dscr_offset);
1876 
1877  hlpfile->numFonts = dscr_num;
1878  hlpfile->fonts = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_FONT) * dscr_num);
1879 
1880  len = (dscr_offset - face_offset) / face_num;
1881 
1882  /* mvb font */
1883  if (face_offset >= 16)
1884  {
1885  hlpfile->scale = 1;
1886  hlpfile->rounderr = 0;
1887  WINE_FIXME("mvb font: not implemented\n");
1888  return FALSE;
1889  }
1890  /* new font */
1891  if (face_offset >= 12)
1892  {
1893  hlpfile->scale = 1;
1894  hlpfile->rounderr = 0;
1895  WINE_FIXME("new font: not implemented\n");
1896  return FALSE;
1897  }
1898  /* old font */
1899  hlpfile->scale = 10;
1900  hlpfile->rounderr = 5;
1901 /* EPP for (i = face_offset; i < dscr_offset; i += len) */
1902 /* EPP WINE_FIXME("[%d]: %*s\n", i / len, len, ref + i); */
1903  for (i = 0; i < dscr_num; i++)
1904  {
1905  flag = ref[dscr_offset + i * 11 + 0];
1906  family = ref[dscr_offset + i * 11 + 2];
1907 
1908  hlpfile->fonts[i].LogFont.lfHeight = ref[dscr_offset + i * 11 + 1];
1909  hlpfile->fonts[i].LogFont.lfWidth = 0;
1910  hlpfile->fonts[i].LogFont.lfEscapement = 0;
1911  hlpfile->fonts[i].LogFont.lfOrientation = 0;
1912  hlpfile->fonts[i].LogFont.lfWeight = (flag & 1) ? 700 : 400;
1913  hlpfile->fonts[i].LogFont.lfItalic = (flag & 2) != 0;
1914  hlpfile->fonts[i].LogFont.lfUnderline = (flag & 4) != 0;
1915  hlpfile->fonts[i].LogFont.lfStrikeOut = (flag & 8) != 0;
1916  hlpfile->fonts[i].LogFont.lfCharSet = hlpfile->charset;
1919  hlpfile->fonts[i].LogFont.lfQuality = DEFAULT_QUALITY;
1921 
1922  switch (family)
1923  {
1924  case 0x01: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_MODERN; break;
1925  case 0x02: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_ROMAN; break;
1926  case 0x03: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SWISS; break;
1927  case 0x04: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SCRIPT; break;
1928  case 0x05: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_DECORATIVE; break;
1929  default: WINE_FIXME("Unknown family %u\n", family);
1930  }
1931  idx = GET_USHORT(ref, dscr_offset + i * 11 + 3);
1932 
1933  if (idx < face_num)
1934  {
1935  memcpy(hlpfile->fonts[i].LogFont.lfFaceName, ref + face_offset + idx * len, min(len, LF_FACESIZE - 1));
1936  hlpfile->fonts[i].LogFont.lfFaceName[min(len, LF_FACESIZE - 1)] = '\0';
1937  }
1938  else
1939  {
1940  WINE_FIXME("Too high face ref (%u/%u)\n", idx, face_num);
1941  strcpy(hlpfile->fonts[i].LogFont.lfFaceName, "Helv");
1942  }
1943  hlpfile->fonts[i].hFont = 0;
1944  hlpfile->fonts[i].color = RGB(ref[dscr_offset + i * 11 + 5],
1945  ref[dscr_offset + i * 11 + 6],
1946  ref[dscr_offset + i * 11 + 7]);
1947 #define X(b,s) ((flag & (1 << b)) ? "-"s: "")
1948  WINE_TRACE("Font[%d]: flags=%02x%s%s%s%s%s%s pSize=%u family=%u face=%s[%u] color=%08x\n",
1949  i, flag,
1950  X(0, "bold"),
1951  X(1, "italic"),
1952  X(2, "underline"),
1953  X(3, "strikeOut"),
1954  X(4, "dblUnderline"),
1955  X(5, "smallCaps"),
1956  ref[dscr_offset + i * 11 + 1],
1957  family,
1958  debugstr_a(hlpfile->fonts[i].LogFont.lfFaceName), idx,
1959  GET_UINT(ref, dscr_offset + i * 11 + 5) & 0x00FFFFFF);
1960  }
1961  return TRUE;
1962 }
1963 
1964 /***********************************************************************
1965  *
1966  * HLPFILE_ReadFileToBuffer
1967  */
1969 {
1970  BYTE header[16], dummy[1];
1971 
1972  if (_hread(hFile, header, 16) != 16) {WINE_WARN("header\n"); return FALSE;};
1973 
1974  /* sanity checks */
1975  if (GET_UINT(header, 0) != 0x00035F3F)
1976  {WINE_WARN("wrong header\n"); return FALSE;};
1977 
1978  hlpfile->file_buffer_size = GET_UINT(header, 12);
1979  hlpfile->file_buffer = HeapAlloc(GetProcessHeap(), 0, hlpfile->file_buffer_size + 1);
1980  if (!hlpfile->file_buffer) return FALSE;
1981 
1982  memcpy(hlpfile->file_buffer, header, 16);
1983  if (_hread(hFile, hlpfile->file_buffer + 16, hlpfile->file_buffer_size - 16) !=hlpfile->file_buffer_size - 16)
1984  {WINE_WARN("filesize1\n"); return FALSE;};
1985 
1986  if (_hread(hFile, dummy, 1) != 0) WINE_WARN("filesize2\n");
1987 
1988  hlpfile->file_buffer[hlpfile->file_buffer_size] = '\0'; /* FIXME: was '0', sounds backwards to me */
1989 
1990  return TRUE;
1991 }
1992 
1993 /***********************************************************************
1994  *
1995  * HLPFILE_SystemCommands
1996  */
1998 {
1999  BYTE *buf, *ptr, *end;
2000  HLPFILE_MACRO *macro, **m;
2001  LPSTR p;
2002  unsigned short magic, minor, major, flags;
2003 
2004  hlpfile->lpszTitle = NULL;
2005 
2006  if (!HLPFILE_FindSubFile(hlpfile, "|SYSTEM", &buf, &end)) return FALSE;
2007 
2008  magic = GET_USHORT(buf + 9, 0);
2009  minor = GET_USHORT(buf + 9, 2);
2010  major = GET_USHORT(buf + 9, 4);
2011  /* gen date on 4 bytes */
2012  flags = GET_USHORT(buf + 9, 10);
2013  WINE_TRACE("Got system header: magic=%04x version=%d.%d flags=%04x\n",
2014  magic, major, minor, flags);
2015  if (magic != 0x036C || major != 1)
2016  {WINE_WARN("Wrong system header\n"); return FALSE;}
2017  if (minor <= 16)
2018  {
2019  hlpfile->tbsize = 0x800;
2020  hlpfile->compressed = FALSE;
2021  }
2022  else if (flags == 0)
2023  {
2024  hlpfile->tbsize = 0x1000;
2025  hlpfile->compressed = FALSE;
2026  }
2027  else if (flags == 4)
2028  {
2029  hlpfile->tbsize = 0x1000;
2030  hlpfile->compressed = TRUE;
2031  }
2032  else
2033  {
2034  hlpfile->tbsize = 0x800;
2035  hlpfile->compressed = TRUE;
2036  }
2037 
2038  if (hlpfile->compressed)
2039  hlpfile->dsize = 0x4000;
2040  else
2041  hlpfile->dsize = hlpfile->tbsize - 0x0C;
2042 
2043  hlpfile->version = minor;
2044  hlpfile->flags = flags;
2045  hlpfile->charset = DEFAULT_CHARSET;
2046 
2047  if (hlpfile->version <= 16)
2048  {
2049  char *str = (char*)buf + 0x15;
2050 
2051  hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1);
2052  if (!hlpfile->lpszTitle) return FALSE;
2053  strcpy(hlpfile->lpszTitle, str);
2054  WINE_TRACE("Title: %s\n", debugstr_a(hlpfile->lpszTitle));
2055  /* Nothing more to parse */
2056  return TRUE;
2057  }
2058  for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4)
2059  {
2060  char *str = (char*) ptr + 4;
2061  switch (GET_USHORT(ptr, 0))
2062  {
2063  case 1:
2064  if (hlpfile->lpszTitle) {WINE_WARN("title\n"); break;}
2065  hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1);
2066  if (!hlpfile->lpszTitle) return FALSE;
2067  strcpy(hlpfile->lpszTitle, str);
2068  WINE_TRACE("Title: %s\n", debugstr_a(hlpfile->lpszTitle));
2069  break;
2070 
2071  case 2:
2072  if (hlpfile->lpszCopyright) {WINE_WARN("copyright\n"); break;}
2073  hlpfile->lpszCopyright = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1);
2074  if (!hlpfile->lpszCopyright) return FALSE;
2075  strcpy(hlpfile->lpszCopyright, str);
2076  WINE_TRACE("Copyright: %s\n", debugstr_a(hlpfile->lpszCopyright));
2077  break;
2078 
2079  case 3:
2080  if (GET_USHORT(ptr, 2) != 4) {WINE_WARN("system3\n");break;}
2081  hlpfile->contents_start = GET_UINT(ptr, 4);
2082  WINE_TRACE("Setting contents start at %08lx\n", hlpfile->contents_start);
2083  break;
2084 
2085  case 4:
2086  macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + strlen(str) + 1);
2087  if (!macro) break;
2088  p = (char*)macro + sizeof(HLPFILE_MACRO);
2089  strcpy(p, str);
2090  macro->lpszMacro = p;
2091  macro->next = 0;
2092  for (m = &hlpfile->first_macro; *m; m = &(*m)->next);
2093  *m = macro;
2094  break;
2095 
2096  case 5:
2097  if (GET_USHORT(ptr, 4 + 4) != 1)
2098  WINE_FIXME("More than one icon, picking up first\n");
2099  /* 0x16 is sizeof(CURSORICONDIR), see user32/user_private.h */
2100  hlpfile->hIcon = CreateIconFromResourceEx(ptr + 4 + 0x16,
2101  GET_USHORT(ptr, 2) - 0x16, TRUE,
2102  0x30000, 0, 0, 0);
2103  break;
2104 
2105  case 6:
2106  if (GET_USHORT(ptr, 2) != 90) {WINE_WARN("system6\n");break;}
2107 
2108  if (hlpfile->windows)
2109  hlpfile->windows = HeapReAlloc(GetProcessHeap(), 0, hlpfile->windows,
2110  sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows);
2111  else
2112  hlpfile->windows = HeapAlloc(GetProcessHeap(), 0,
2113  sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows);
2114 
2115  if (hlpfile->windows)
2116  {
2117  HLPFILE_WINDOWINFO* wi = &hlpfile->windows[hlpfile->numWindows - 1];
2118 
2119  flags = GET_USHORT(ptr, 4);
2120  if (flags & 0x0001) strcpy(wi->type, &str[2]);
2121  else wi->type[0] = '\0';
2122  if (flags & 0x0002) strcpy(wi->name, &str[12]);
2123  else wi->name[0] = '\0';
2124  if (flags & 0x0004) strcpy(wi->caption, &str[21]);
2125  else lstrcpynA(wi->caption, hlpfile->lpszTitle, sizeof(wi->caption));
2126  wi->origin.x = (flags & 0x0008) ? GET_USHORT(ptr, 76) : CW_USEDEFAULT;
2127  wi->origin.y = (flags & 0x0010) ? GET_USHORT(ptr, 78) : CW_USEDEFAULT;
2128  wi->size.cx = (flags & 0x0020) ? GET_USHORT(ptr, 80) : CW_USEDEFAULT;
2129  wi->size.cy = (flags & 0x0040) ? GET_USHORT(ptr, 82) : CW_USEDEFAULT;
2130  wi->style = (flags & 0x0080) ? GET_USHORT(ptr, 84) : SW_SHOW;
2132  wi->sr_color = (flags & 0x0100) ? GET_UINT(ptr, 86) : 0xFFFFFF;
2133  wi->nsr_color = (flags & 0x0200) ? GET_UINT(ptr, 90) : 0xFFFFFF;
2134  WINE_TRACE("System-Window: flags=%c%c%c%c%c%c%c%c type=%s name=%s caption=%s (%d,%d)x(%d,%d)\n",
2135  flags & 0x0001 ? 'T' : 't',
2136  flags & 0x0002 ? 'N' : 'n',
2137  flags & 0x0004 ? 'C' : 'c',
2138  flags & 0x0008 ? 'X' : 'x',
2139  flags & 0x0010 ? 'Y' : 'y',
2140  flags & 0x0020 ? 'W' : 'w',
2141  flags & 0x0040 ? 'H' : 'h',
2142  flags & 0x0080 ? 'S' : 's',
2143  debugstr_a(wi->type), debugstr_a(wi->name), debugstr_a(wi->caption), wi->origin.x, wi->origin.y,
2144  wi->size.cx, wi->size.cy);
2145  }
2146  break;
2147  case 8:
2148  WINE_WARN("Citation: %s\n", debugstr_a((char *)ptr + 4));
2149  break;
2150  case 11:
2151  hlpfile->charset = ptr[4];
2152  WINE_TRACE("Charset: %d\n", hlpfile->charset);
2153  break;
2154  default:
2155  WINE_WARN("Unsupported SystemRecord[%d]\n", GET_USHORT(ptr, 0));
2156  }
2157  }
2158  if (!hlpfile->lpszTitle)
2160  return TRUE;
2161 }
2162 
2163 /***********************************************************************
2164  *
2165  * HLPFILE_GetContext
2166  */
2168 {
2169  BYTE *cbuf, *cend;
2170  unsigned clen;
2171 
2172  if (!HLPFILE_FindSubFile(hlpfile, "|CONTEXT", &cbuf, &cend))
2173  {WINE_WARN("context0\n"); return FALSE;}
2174 
2175  clen = cend - cbuf;
2176  hlpfile->Context = HeapAlloc(GetProcessHeap(), 0, clen);
2177  if (!hlpfile->Context) return FALSE;
2178  memcpy(hlpfile->Context, cbuf, clen);
2179 
2180  return TRUE;
2181 }
2182 
2183 /***********************************************************************
2184  *
2185  * HLPFILE_GetKeywords
2186  */
2188 {
2189  BYTE *cbuf, *cend;
2190  unsigned clen;
2191 
2192  if (!HLPFILE_FindSubFile(hlpfile, "|KWBTREE", &cbuf, &cend)) return FALSE;
2193  clen = cend - cbuf;
2194  hlpfile->kwbtree = HeapAlloc(GetProcessHeap(), 0, clen);
2195  if (!hlpfile->kwbtree) return FALSE;
2196  memcpy(hlpfile->kwbtree, cbuf, clen);
2197 
2198  if (!HLPFILE_FindSubFile(hlpfile, "|KWDATA", &cbuf, &cend))
2199  {
2200  WINE_ERR("corrupted help file: kwbtree present but kwdata absent\n");
2201  HeapFree(GetProcessHeap(), 0, hlpfile->kwbtree);
2202  return FALSE;
2203  }
2204  clen = cend - cbuf;
2205  hlpfile->kwdata = HeapAlloc(GetProcessHeap(), 0, clen);
2206  if (!hlpfile->kwdata)
2207  {
2208  HeapFree(GetProcessHeap(), 0, hlpfile->kwdata);
2209  return FALSE;
2210  }
2211  memcpy(hlpfile->kwdata, cbuf, clen);
2212 
2213  return TRUE;
2214 }
2215 
2216 /***********************************************************************
2217  *
2218  * HLPFILE_GetMap
2219  */
2220 static BOOL HLPFILE_GetMap(HLPFILE *hlpfile)
2221 {
2222  BYTE *cbuf, *cend;
2223  unsigned entries, i;
2224 
2225  if (!HLPFILE_FindSubFile(hlpfile, "|CTXOMAP", &cbuf, &cend))
2226  {WINE_WARN("no map section\n"); return FALSE;}
2227 
2228  entries = GET_USHORT(cbuf, 9);
2229  hlpfile->Map = HeapAlloc(GetProcessHeap(), 0, entries * sizeof(HLPFILE_MAP));
2230  if (!hlpfile->Map) return FALSE;
2231  hlpfile->wMapLen = entries;
2232  for (i = 0; i < entries; i++)
2233  {
2234  hlpfile->Map[i].lMap = GET_UINT(cbuf+11,i*8);
2235  hlpfile->Map[i].offset = GET_UINT(cbuf+11,i*8+4);
2236  }
2237  return TRUE;
2238 }
2239 
2240 /***********************************************************************
2241  *
2242  * HLPFILE_GetTOMap
2243  */
2245 {
2246  BYTE *cbuf, *cend;
2247  unsigned clen;
2248 
2249  if (!HLPFILE_FindSubFile(hlpfile, "|TOMAP", &cbuf, &cend))
2250  {WINE_WARN("no tomap section\n"); return FALSE;}
2251 
2252  clen = cend - cbuf - 9;
2253  hlpfile->TOMap = HeapAlloc(GetProcessHeap(), 0, clen);
2254  if (!hlpfile->TOMap) return FALSE;
2255  memcpy(hlpfile->TOMap, cbuf+9, clen);
2256  hlpfile->wTOMapLen = clen/4;
2257  return TRUE;
2258 }
2259 
2260 /***********************************************************************
2261  *
2262  * DeleteMacro
2263  */
2265 {
2267 
2268  while (macro)
2269  {
2270  next = macro->next;
2271  HeapFree(GetProcessHeap(), 0, macro);
2272  macro = next;
2273  }
2274 }
2275 
2276 /***********************************************************************
2277  *
2278  * DeletePage
2279  */
2281 {
2282  HLPFILE_PAGE* next;
2283 
2284  while (page)
2285  {
2286  next = page->next;
2288  HeapFree(GetProcessHeap(), 0, page);
2289  page = next;
2290  }
2291 }
2292 
2293 /***********************************************************************
2294  *
2295  * HLPFILE_FreeHlpFile
2296  */
2298 {
2299  unsigned i;
2300 
2301  if (!hlpfile || --hlpfile->wRefCount > 0) return;
2302 
2303  if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;
2304  if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;
2305  else first_hlpfile = hlpfile->next;
2306 
2307  if (hlpfile->numFonts)
2308  {
2309  for (i = 0; i < hlpfile->numFonts; i++)
2310  {
2311  DeleteObject(hlpfile->fonts[i].hFont);
2312  }
2313  HeapFree(GetProcessHeap(), 0, hlpfile->fonts);
2314  }
2315 
2316  if (hlpfile->numBmps)
2317  {
2318  for (i = 0; i < hlpfile->numBmps; i++)
2319  {
2320  DeleteObject(hlpfile->bmps[i]);
2321  }
2322  HeapFree(GetProcessHeap(), 0, hlpfile->bmps);
2323  }
2324 
2325  HLPFILE_DeletePage(hlpfile->first_page);
2326  HLPFILE_DeleteMacro(hlpfile->first_macro);
2327 
2328  DestroyIcon(hlpfile->hIcon);
2329  if (hlpfile->numWindows) HeapFree(GetProcessHeap(), 0, hlpfile->windows);
2330  HeapFree(GetProcessHeap(), 0, hlpfile->Context);
2331  HeapFree(GetProcessHeap(), 0, hlpfile->Map);
2332  HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle);
2333  HeapFree(GetProcessHeap(), 0, hlpfile->lpszCopyright);
2334  HeapFree(GetProcessHeap(), 0, hlpfile->file_buffer);
2335  HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets);
2336  HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer);
2337  HeapFree(GetProcessHeap(), 0, hlpfile->topic_map);
2338  HeapFree(GetProcessHeap(), 0, hlpfile->help_on_file);
2339  HeapFree(GetProcessHeap(), 0, hlpfile);
2340 }
2341 
2342 /***********************************************************************
2343  *
2344  * HLPFILE_UncompressLZ77_Phrases
2345  */
2347 {
2348  UINT i, num, dec_size, head_size;
2349  BYTE *buf, *end;
2350 
2351  if (!HLPFILE_FindSubFile(hlpfile, "|Phrases", &buf, &end)) return FALSE;
2352 
2353  if (hlpfile->version <= 16)
2354  head_size = 13;
2355  else
2356  head_size = 17;
2357 
2358  num = hlpfile->num_phrases = GET_USHORT(buf, 9);
2359  if (buf + 2 * num + 0x13 >= end) {WINE_WARN("1a\n"); return FALSE;};
2360 
2361  if (hlpfile->version <= 16)
2362  dec_size = end - buf - 15 - 2 * num;
2363  else
2364  dec_size = HLPFILE_UncompressedLZ77_Size(buf + 0x13 + 2 * num, end);
2365 
2366  hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1));
2367  hlpfile->phrases_buffer = HeapAlloc(GetProcessHeap(), 0, dec_size);
2368  if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer)
2369  {
2370  HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets);
2371  HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer);
2372  return FALSE;
2373  }
2374 
2375  for (i = 0; i <= num; i++)
2376  hlpfile->phrases_offsets[i] = GET_USHORT(buf, head_size + 2 * i) - 2 * num - 2;
2377 
2378  if (hlpfile->version <= 16)
2379  memcpy(hlpfile->phrases_buffer, buf + 15 + 2*num, dec_size);
2380  else
2381  HLPFILE_UncompressLZ77(buf + 0x13 + 2 * num, end, (BYTE*)hlpfile->phrases_buffer);
2382 
2383  hlpfile->hasPhrases = TRUE;
2384  return TRUE;
2385 }
2386 
2387 /***********************************************************************
2388  *
2389  * HLPFILE_Uncompress_Phrases40
2390  */
2392 {
2393  UINT num;
2394  INT dec_size, cpr_size;
2395  BYTE *buf_idx, *end_idx;
2396  BYTE *buf_phs, *end_phs;
2397  ULONG* ptr, mask = 0;
2398  unsigned int i;
2399  unsigned short bc, n;
2400 
2401  if (!HLPFILE_FindSubFile(hlpfile, "|PhrIndex", &buf_idx, &end_idx) ||
2402  !HLPFILE_FindSubFile(hlpfile, "|PhrImage", &buf_phs, &end_phs)) return FALSE;
2403 
2404  ptr = (ULONG*)(buf_idx + 9 + 28);
2405  bc = GET_USHORT(buf_idx, 9 + 24) & 0x0F;
2406  num = hlpfile->num_phrases = GET_USHORT(buf_idx, 9 + 4);
2407 
2408  WINE_TRACE("Index: Magic=%08x #entries=%u CpsdSize=%u PhrImgSize=%u\n"
2409  "\tPhrImgCprsdSize=%u 0=%u bc=%x ukn=%x\n",
2410  GET_UINT(buf_idx, 9 + 0),
2411  GET_UINT(buf_idx, 9 + 4),
2412  GET_UINT(buf_idx, 9 + 8),
2413  GET_UINT(buf_idx, 9 + 12),
2414  GET_UINT(buf_idx, 9 + 16),
2415  GET_UINT(buf_idx, 9 + 20),
2416  GET_USHORT(buf_idx, 9 + 24),
2417  GET_USHORT(buf_idx, 9 + 26));
2418 
2419  dec_size = GET_UINT(buf_idx, 9 + 12);
2420  cpr_size = GET_UINT(buf_idx, 9 + 16);
2421 
2422  if (dec_size != cpr_size &&
2423  dec_size != HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs))
2424  {
2425  WINE_WARN("size mismatch %u %u\n",
2426  dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs));
2427  dec_size = max(dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs));
2428  }
2429 
2430  hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1));
2431  hlpfile->phrases_buffer = HeapAlloc(GetProcessHeap(), 0, dec_size);
2432  if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer)
2433  {
2434  HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets);
2435  HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer);
2436  return FALSE;
2437  }
2438 
2439 #define getbit() ((mask <<= 1) ? (*ptr & mask) != 0: (*++ptr & (mask=1)) != 0)
2440 
2441  hlpfile->phrases_offsets[0] = 0;
2442  ptr--; /* as we'll first increment ptr because mask is 0 on first getbit() call */
2443  for (i = 0; i < num; i++)
2444  {
2445  for (n = 1; getbit(); n += 1 << bc);
2446  if (getbit()) n++;
2447  if (bc > 1 && getbit()) n += 2;
2448  if (bc > 2 && getbit()) n += 4;
2449  if (bc > 3 && getbit()) n += 8;
2450  if (bc > 4 && getbit()) n += 16;
2451  hlpfile->phrases_offsets[i + 1] = hlpfile->phrases_offsets[i] + n;
2452  }
2453 #undef getbit
2454 
2455  if (dec_size == cpr_size)
2456  memcpy(hlpfile->phrases_buffer, buf_phs + 9, dec_size);
2457  else
2458  HLPFILE_UncompressLZ77(buf_phs + 9, end_phs, (BYTE*)hlpfile->phrases_buffer);
2459 
2460  hlpfile->hasPhrases40 = TRUE;
2461  return TRUE;
2462 }
2463 
2464 /***********************************************************************
2465  *
2466  * HLPFILE_Uncompress_Topic
2467  */
2469 {
2470  BYTE *buf, *ptr, *end, *newptr;
2471  unsigned int i, newsize = 0;
2472  unsigned int topic_size;
2473 
2474  if (!HLPFILE_FindSubFile(hlpfile, "|TOPIC", &buf, &end))
2475  {WINE_WARN("topic0\n"); return FALSE;}
2476 
2477  buf += 9; /* Skip file header */
2478  topic_size = end - buf;
2479  if (hlpfile->compressed)
2480  {
2481  hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1;
2482 
2483  for (i = 0; i < hlpfile->topic_maplen; i++)
2484  {
2485  ptr = buf + i * hlpfile->tbsize;
2486 
2487  /* I don't know why, it's necessary for printman.hlp */
2488  if (ptr + 0x44 > end) ptr = end - 0x44;
2489 
2490  newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + hlpfile->tbsize));
2491  }
2492 
2493  hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0,
2494  hlpfile->topic_maplen * sizeof(hlpfile->topic_map[0]) + newsize);
2495  if (!hlpfile->topic_map) return FALSE;
2496  newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen);
2497  hlpfile->topic_end = newptr + newsize;
2498 
2499  for (i = 0; i < hlpfile->topic_maplen; i++)
2500  {
2501  ptr = buf + i * hlpfile->tbsize;
2502  if (ptr + 0x44 > end) ptr = end - 0x44;
2503 
2504  hlpfile->topic_map[i] = newptr;
2505  newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + hlpfile->tbsize), newptr);
2506  }
2507  }
2508  else
2509  {
2510  /* basically, we need to copy the TopicBlockSize byte pages
2511  * (removing the first 0x0C) in one single area in memory
2512  */
2513  hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1;
2514  hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0,
2515  hlpfile->topic_maplen * (sizeof(hlpfile->topic_map[0]) + hlpfile->dsize));
2516  if (!hlpfile->topic_map) return FALSE;
2517  newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen);
2518  hlpfile->topic_end = newptr + topic_size;
2519 
2520  for (i = 0; i < hlpfile->topic_maplen; i++)
2521  {
2522  hlpfile->topic_map[i] = newptr + i * hlpfile->dsize;
2523  memcpy(hlpfile->topic_map[i], buf + i * hlpfile->tbsize + 0x0C, hlpfile->dsize);
2524  }
2525  }
2526  return TRUE;
2527 }
2528 
2529 /***********************************************************************
2530  *
2531  * HLPFILE_AddPage
2532  */
2533 static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned ref, unsigned offset)
2534 {
2535  HLPFILE_PAGE* page;
2536  const BYTE* title;
2537  UINT titlesize, blocksize, datalen;
2538  char* ptr;
2539  HLPFILE_MACRO*macro;
2540 
2541  blocksize = GET_UINT(buf, 0);
2542  datalen = GET_UINT(buf, 0x10);
2543  title = buf + datalen;
2544  if (title > end) {WINE_WARN("page2\n"); return FALSE;};
2545 
2546  titlesize = GET_UINT(buf, 4);
2547  page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize + 1);
2548  if (!page) return FALSE;
2549  page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);
2550 
2551  if (titlesize > blocksize - datalen)
2552  {
2553  /* need to decompress */
2554  if (hlpfile->hasPhrases)
2555  HLPFILE_Uncompress2(hlpfile, title, end, (BYTE*)page->lpszTitle, (BYTE*)page->lpszTitle + titlesize);
2556  else if (hlpfile->hasPhrases40)
2557  HLPFILE_Uncompress3(hlpfile, page->lpszTitle, page->lpszTitle + titlesize, title, end);
2558  else
2559  {
2560  WINE_FIXME("Text size is too long, splitting\n");
2561  titlesize = blocksize - datalen;
2562  memcpy(page->lpszTitle, title, titlesize);
2563  }
2564  }
2565  else
2566  memcpy(page->lpszTitle, title, titlesize);
2567 
2568  page->lpszTitle[titlesize] = '\0';
2569 
2570  if (hlpfile->first_page)
2571  {
2572  hlpfile->last_page->next = page;
2573  page->prev = hlpfile->last_page;
2574  hlpfile->last_page = page;
2575  }
2576  else
2577  {
2578  hlpfile->first_page = page;
2579  hlpfile->last_page = page;
2580  page->prev = NULL;
2581  }
2582 
2583  page->file = hlpfile;
2584  page->next = NULL;
2585  page->first_macro = NULL;
2586  page->first_link = NULL;
2587  page->wNumber = GET_UINT(buf, 0x21);
2588  page->offset = offset;
2589  page->reference = ref;
2590 
2591  page->browse_bwd = GET_UINT(buf, 0x19);
2592  page->browse_fwd = GET_UINT(buf, 0x1D);
2593 
2594  if (hlpfile->version <= 16)
2595  {
2596  if (page->browse_bwd == 0xFFFF || page->browse_bwd == 0xFFFFFFFF)
2597  page->browse_bwd = 0xFFFFFFFF;
2598  else
2599  page->browse_bwd = hlpfile->TOMap[page->browse_bwd];
2600 
2601  if (page->browse_fwd == 0xFFFF || page->browse_fwd == 0xFFFFFFFF)
2602  page->browse_fwd = 0xFFFFFFFF;
2603  else
2604  page->browse_fwd = hlpfile->TOMap[page->browse_fwd];
2605  }
2606 
2607  WINE_TRACE("Added page[%d]: title=%s %08x << %08x >> %08x\n",
2608  page->wNumber, debugstr_a(page->lpszTitle),
2609  page->browse_bwd, page->offset, page->browse_fwd);
2610 
2611  /* now load macros */
2612  ptr = page->lpszTitle + strlen(page->lpszTitle) + 1;
2613  while (ptr < page->lpszTitle + titlesize)
2614  {
2615  unsigned len = strlen(ptr);
2616  char* macro_str;
2617 
2618  WINE_TRACE("macro: %s\n", debugstr_a(ptr));
2619  macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + len + 1);
2620  macro->lpszMacro = macro_str = (char*)(macro + 1);
2621  memcpy(macro_str, ptr, len + 1);
2622  /* FIXME: shall we really link macro in reverse order ??
2623  * may produce strange results when played at page opening
2624  */
2625  macro->next = page->first_macro;
2626  page->first_macro = macro;
2627  ptr += len + 1;
2628  }
2629 
2630  return TRUE;
2631 }
2632 
2633 /***********************************************************************
2634  *
2635  * HLPFILE_SkipParagraph
2636  */
2637 static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned* len)
2638 {
2639  const BYTE *tmp;
2640 
2641  if (!hlpfile->first_page) {WINE_WARN("no page\n"); return FALSE;};
2642  if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};
2643 
2644  tmp = buf + 0x15;
2645  if (buf[0x14] == HLP_DISPLAY || buf[0x14] == HLP_TABLE)
2646  {
2647  fetch_long(&tmp);
2648  *len = fetch_ushort(&tmp);
2649  }
2650  else *len = end-buf-15;
2651 
2652  return TRUE;
2653 }
2654 
2655 /***********************************************************************
2656  *
2657  * HLPFILE_DoReadHlpFile
2658  */
2659 static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
2660 {
2661  BOOL ret;
2662  HFILE hFile;
2663  OFSTRUCT ofs;
2664  BYTE* buf;
2665  DWORD ref = 0x0C;
2666  unsigned index, old_index, offset, len, offs, topicoffset;
2667 
2668  hFile = OpenFile(lpszPath, &ofs, OF_READ);
2669  if (hFile == HFILE_ERROR) return FALSE;
2670 
2671  ret = HLPFILE_ReadFileToBuffer(hlpfile, hFile);
2672  _lclose(hFile);
2673  if (!ret) return FALSE;
2674 
2675  if (!HLPFILE_SystemCommands(hlpfile)) return FALSE;
2676 
2677  if (hlpfile->version <= 16 && !HLPFILE_GetTOMap(hlpfile)) return FALSE;
2678 
2679  /* load phrases support */
2680  if (!HLPFILE_UncompressLZ77_Phrases(hlpfile))
2682 
2683  if (!HLPFILE_Uncompress_Topic(hlpfile)) return FALSE;
2684  if (!HLPFILE_ReadFont(hlpfile)) return FALSE;
2685 
2686  old_index = -1;
2687  offs = 0;
2688  do
2689  {
2690  BYTE* end;
2691 
2692  if (hlpfile->version <= 16)
2693  {
2694  index = (ref - 0x0C) / hlpfile->dsize;
2695  offset = (ref - 0x0C) % hlpfile->dsize;
2696  }
2697  else
2698  {
2699  index = (ref - 0x0C) >> 14;
2700  offset = (ref - 0x0C) & 0x3FFF;
2701  }
2702 
2703  if (hlpfile->version <= 16 && index != old_index && old_index != -1)
2704  {
2705  /* we jumped to the next block, adjust pointers */
2706  ref -= 12;
2707  offset -= 12;
2708  }
2709 
2710  WINE_TRACE("ref=%08x => [%u/%u]\n", ref, index, offset);
2711 
2712  if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;}
2713  buf = hlpfile->topic_map[index] + offset;
2714  if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;}
2715  end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end);
2716  if (index != old_index) {offs = 0; old_index = index;}
2717 
2718  switch (buf[0x14])
2719  {
2720  case HLP_TOPICHDR: /* Topic Header */
2721  if (hlpfile->version <= 16)
2722  topicoffset = ref + index * 12;
2723  else
2724  topicoffset = index * 0x8000 + offs;
2725  if (!HLPFILE_AddPage(hlpfile, buf, end, ref, topicoffset)) return FALSE;
2726  break;
2727 
2728  case HLP_DISPLAY30:
2729  case HLP_DISPLAY:
2730  case HLP_TABLE:
2731  if (!HLPFILE_SkipParagraph(hlpfile, buf, end, &len)) return FALSE;
2732  offs += len;
2733  break;
2734 
2735  default:
2736  WINE_ERR("buf[0x14] = %x\n", buf[0x14]);
2737  }
2738 
2739  if (hlpfile->version <= 16)
2740  {
2741  ref += GET_UINT(buf, 0xc);
2742  if (GET_UINT(buf, 0xc) == 0)
2743  break;
2744  }
2745  else
2746  ref = GET_UINT(buf, 0xc);
2747  } while (ref != 0xffffffff);
2748 
2749  HLPFILE_GetKeywords(hlpfile);
2750  HLPFILE_GetMap(hlpfile);
2751  if (hlpfile->version <= 16) return TRUE;
2752  return HLPFILE_GetContext(hlpfile);
2753 }
2754 
2755 /***********************************************************************
2756  *
2757  * HLPFILE_ReadHlpFile
2758  */
2760 {
2761  HLPFILE* hlpfile;
2762 
2763  for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)
2764  {
2765  if (!strcmp(lpszPath, hlpfile->lpszPath))
2766  {
2767  hlpfile->wRefCount++;
2768  return hlpfile;
2769  }
2770  }
2771 
2773  sizeof(HLPFILE) + strlen(lpszPath) + 1);
2774  if (!hlpfile) return 0;
2775 
2776  hlpfile->lpszPath = (char*)hlpfile + sizeof(HLPFILE);
2777  hlpfile->contents_start = 0xFFFFFFFF;
2778  hlpfile->next = first_hlpfile;
2779  hlpfile->wRefCount = 1;
2780 
2781  strcpy(hlpfile->lpszPath, lpszPath);
2782 
2783  first_hlpfile = hlpfile;
2784  if (hlpfile->next) hlpfile->next->prev = hlpfile;
2785 
2786  if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))
2787  {
2788  HLPFILE_FreeHlpFile(hlpfile);
2789  hlpfile = 0;
2790  }
2791 
2792  return hlpfile;
2793 }
static BOOL HLPFILE_RtfAddGfxByIndex(struct RtfData *rd, HLPFILE *hlpfile, unsigned index)
Definition: hlpfile.c:1155
#define SRCPAINT
Definition: wingdi.h:332
unsigned short version
Definition: hlpfile.h:124
BYTE lfItalic
Definition: dimm.idl:47
int rd
Definition: scanf.h:134
LOGFONTA LogFont
Definition: hlpfile.h:95
#define HDC
Definition: msvc.h:22
COLORREF color
Definition: hlpfile.h:97
GLint level
Definition: gl.h:1546
HLPFILE_PAGE * last_page
Definition: hlpfile.h:108
BYTE * file_buffer
Definition: hlpfile.h:102
#define LONG_PTR
Definition: treelist.c:79
LPCSTR lpszMacro
Definition: hlpfile.h:64
#define max(a, b)
Definition: svc.c:63
#define EE_CHARSET
Definition: wingdi.h:396
#define TRUE
Definition: types.h:120
#define LongToPtr(l)
Definition: basetsd.h:91
#define LF_FACESIZE
Definition: dimm.idl:39
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
#define MAC_CHARSET
Definition: wingdi.h:401
void(* HLPFILE_BPTreeCallback)(void *p, void **next, void *cookie)
Definition: hlpfile.h:179
unsigned long offset
Definition: hlpfile.h:90
#define HBITMAP
Definition: msvc.h:28
#define OF_READ
Definition: winbase.h:116
BITMAPINFOHEADER bmiHeader
Definition: wingdi.h:1453
long y
Definition: polytest.cpp:48
#define DEFAULT_QUALITY
Definition: wingdi.h:434
#define HLP_DISPLAY30
Definition: hlpfile.h:208
HLPFILE_LINK * first_link
Definition: hlpfile.h:198
DWORD biClrImportant
Definition: amvideo.idl:40
static BYTE * HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr)
Definition: hlpfile.c:195
long x
Definition: polytest.cpp:48
LPBATCH_CONTEXT bc
Definition: batch.c:66
HDC WINAPI GetDC(_In_opt_ HWND)
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
Definition: mk_font.cpp:20
BOOL WINAPI DestroyIcon(_In_ HICON)
Definition: cursoricon.c:2022
POINT last
Definition: font.c:46
struct tagHlpFileFile * file
Definition: hlpfile.h:84
static void HLPFILE_UncompressRLE(const BYTE *src, const BYTE *end, BYTE *dst, unsigned dstsz)
Definition: hlpfile.c:335
LONG biXPelsPerMeter
Definition: amvideo.idl:37
const WCHAR * text
Definition: package.c:1827
static BOOL HLPFILE_ReadFileToBuffer(HLPFILE *hlpfile, HFILE hFile)
Definition: hlpfile.c:1968
BYTE lfStrikeOut
Definition: dimm.idl:49
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define FF_DECORATIVE
Definition: wingdi.h:445
long dst_end
Definition: timezone.c:17
char CHAR
Definition: xmlstorage.h:175
void HLPFILE_FreeHlpFile(HLPFILE *hlpfile)
Definition: hlpfile.c:2297
unsigned short tbsize
Definition: hlpfile.h:127
UINT topic_maplen
Definition: hlpfile.h:138
static BOOL HLPFILE_UncompressLZ77_Phrases(HLPFILE *hlpfile)
Definition: hlpfile.c:2346
GLintptr offset
Definition: glext.h:5920
BYTE lfUnderline
Definition: dimm.idl:48
#define GetRValue(rgb)
Definition: wingdi.h:2912
static BOOL HLPFILE_RtfAddText(struct RtfData *rd, const char *str)
Definition: hlpfile.c:714
#define CHINESEBIG5_CHARSET
Definition: wingdi.h:388
static void * HLPFILE_BPTreeSearch(BYTE *buf, const void *key, HLPFILE_BPTreeCompare comp)
Definition: hlpfile.c:69
unsigned font_scale
Definition: hlpfile.h:197
static INT HLPFILE_UncompressedLZ77_Size(const BYTE *ptr, const BYTE *end)
Definition: hlpfile.c:168
static BOOL HLPFILE_RtfAddTransparentBitmap(struct RtfData *rd, const BITMAPINFO *bi, const void *pict, unsigned nc)
Definition: hlpfile.c:880
char caption[51]
Definition: hlpfile.h:31
u32_t magic(void)
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1497
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define WINE_TRACE
Definition: debug.h:358
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
GLuint buffer
Definition: glext.h:5915
long WINAPI _hread(HFILE hFile, LPVOID lpBuffer, long lBytes)
Definition: lfile.c:20
static BOOL HLPFILE_Uncompress3(HLPFILE *hlpfile, char *dst, const char *dst_end, const BYTE *src, const BYTE *src_end)
Definition: hlpfile.c:272
BYTE lfCharSet
Definition: dimm.idl:50
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
static ULONG fetch_ulong(const BYTE **ptr)
Definition: hlpfile.c:584
GLuint GLuint end
Definition: gl.h:1545
char * phrases_buffer
Definition: hlpfile.h:134
HDC WINAPI CreateEnhMetaFileW(_In_opt_ HDC, _In_opt_ LPCWSTR, _In_opt_ LPCRECT, _In_opt_ LPCWSTR)
static BOOL HLPFILE_GetMap(HLPFILE *hlpfile)
Definition: hlpfile.c:2220
HBITMAP * bmps
Definition: hlpfile.h:141
unsigned short charset
Definition: hlpfile.h:126
int const JOCTET unsigned int datalen
Definition: jpeglib.h:1027
char * LPSTR
Definition: xmlstorage.h:182
#define DEFAULT_CHARSET
Definition: wingdi.h:382
unsigned allocated
Definition: hlpfile.h:194
LONG biYPelsPerMeter
Definition: amvideo.idl:38
LONG lMap
Definition: hlpfile.h:89
static VOID NTAPI BitBlt(IN ULONG Left, IN ULONG Top, IN ULONG Width, IN ULONG Height, IN PUCHAR Buffer, IN ULONG BitsPerPixel, IN ULONG Delta)
Definition: vga.c:416
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * bits
Definition: glext.h:10929
int32_t INT
Definition: typedefs.h:56
Definition: send.c:47
int WINAPI _lclose(HFILE hFile)
Definition: lfile.c:138
UCHAR rgbBlue
Definition: inbv.c:118
static BOOL HLPFILE_RtfAddHexBytes(struct RtfData *rd, const void *_ptr, unsigned sz)
Definition: hlpfile.c:752
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
BYTE lfOutPrecision
Definition: dimm.idl:51
unsigned numWindows
Definition: hlpfile.h:146
HLPFILE_LINK * first_link
Definition: hlpfile.h:73
UCHAR rgbGreen
Definition: inbv.c:119
BOOL in_text
Definition: hlpfile.h:191
HLPFILE_MACRO * first_macro
Definition: hlpfile.h:71
#define CBM_INIT
Definition: wingdi.h:363
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:975
#define sprintf(buf, format,...)
Definition: sprintf.c:55
#define GetGValue(rgb)
Definition: wingdi.h:2913
UCHAR rgbRed
Definition: inbv.c:120
GLuint n
Definition: s_context.h:57
GLuint const GLubyte GLvoid * src
Definition: s_context.h:57
UINT WINAPI GetEnhMetaFileBits(_In_ HENHMETAFILE hEMF, _In_ UINT nSize, _Out_writes_bytes_opt_(nSize) LPBYTE lpData)
GLenum GLclampf GLint i
Definition: glfuncs.h:14
unsigned long contents_start
Definition: hlpfile.h:117
static short GET_SHORT(const BYTE *buffer, unsigned i)
Definition: hlpfile.c:42
GLenum GLint GLuint mask
Definition: glext.h:6028
unsigned relative
Definition: hlpfile.h:201
#define HFILE_ERROR
Definition: winbase.h:111
LPSTR help_on_file
Definition: hlpfile.h:153
HLPFILE_LINK * current_link
Definition: hlpfile.h:199
int hash
Definition: main.c:58
static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE *hlpfile)
Definition: hlpfile.c:2391
HLPFILE_PAGE * HLPFILE_PageByOffset(HLPFILE *hlpfile, LONG offset, ULONG *relative)
Definition: hlpfile.c:369
long LONG
Definition: pedump.c:60
HLPFILE * HLPFILE_ReadHlpFile(LPCSTR lpszPath)
Definition: hlpfile.c:2759
LONG lfHeight
Definition: dimm.idl:42
struct tagHlpFileMacro * next
Definition: hlpfile.h:65
HLPFILE_PAGE * first_page
Definition: hlpfile.h:107
static BOOL HLPFILE_RtfAddControl(struct RtfData *rd, const char *str)
Definition: hlpfile.c:706
GLenum GLint ref
Definition: glext.h:6028
#define CLIP_DEFAULT_PRECIS
Definition: wingdi.h:424
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
unsigned numBmps
Definition: hlpfile.h:140
DWORD biCompression
Definition: amvideo.idl:35
static PVOID ptr
Definition: dispmode.c:27
WINE_DEFAULT_DEBUG_CHANNEL(winhelp)
#define INT(a)
Definition: assyntax.h:463
DWORD browse_fwd
Definition: hlpfile.h:82
BOOL hasPhrases40
Definition: hlpfile.h:131
LPSTR lpszPath
Definition: hlpfile.h:104
unsigned int idx
Definition: utils.c:41
#define CW_USEDEFAULT
Definition: winuser.h:225
static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)
Definition: hlpfile.c:2659
static BOOL HLPFILE_RtfAddBitmap(struct RtfData *rd, HLPFILE *file, const BYTE *beg, BYTE type, BYTE pack)
Definition: hlpfile.c:961
BYTE ** topic_map
Definition: hlpfile.h:136
HDC hdc
Definition: msvc.h:53
const WCHAR * str
static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE *page, struct RtfData *rd, BYTE *buf, BYTE *end, unsigned *parlen)
Definition: hlpfile.c:1223
#define WINE_ERR
Definition: debug.h:375
static const char * ts(int t)
LONG lfWeight
Definition: dimm.idl:46
struct tagHlpFileHotSpotLink HLPFILE_HOTSPOTLINK
smooth NULL
Definition: ftsmooth.c:416
unsigned char
Definition: typeof.h:27
LONG cx
Definition: windef.h:324
static BOOL HLPFILE_RtfAddGfxByAddr(struct RtfData *rd, HLPFILE *hlpfile, const BYTE *ref, ULONG size)
Definition: hlpfile.c:1109
HLPFILE_PAGE * HLPFILE_PageByMap(HLPFILE *hlpfile, LONG lMap, ULONG *relative)
Definition: hlpfile.c:467
Definition: module.h:566
#define TURKISH_CHARSET
Definition: wingdi.h:390
GLuint index
Definition: glext.h:6031
BYTE lfPitchAndFamily
Definition: dimm.idl:54
BOOL WINAPI DeleteEnhMetaFile(_In_opt_ HENHMETAFILE)
const char * LPCSTR
Definition: xmlstorage.h:183
#define SW_SHOW
Definition: winuser.h:769
BYTE * topic_end
Definition: hlpfile.h:137
static BOOL HLPFILE_RtfAddMetaFile(struct RtfData *rd, HLPFILE *file, const BYTE *beg, BYTE pack)
Definition: hlpfile.c:1062
static BOOL HLPFILE_FindSubFile(HLPFILE *hlpfile, LPCSTR name, BYTE **subbuf, BYTE **subend)
Definition: hlpfile.c:503
HLPFILE_MACRO * first_macro
Definition: hlpfile.h:109
char name[9]
Definition: hlpfile.h:30
INT replace(TCHAR source[MAX_PATH], TCHAR dest[MAX_PATH], DWORD dwFlags, BOOL *doMore)
Definition: replace.c:47
HFILE WINAPI OpenFile(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle)
Definition: create.c:368
static unsigned GET_UINT(const BYTE *buffer, unsigned i)
Definition: hlpfile.c:47
unsigned * phrases_offsets
Definition: hlpfile.h:133
unsigned * TOMap
Definition: hlpfile.h:116
void HLPFILE_BPTreeEnum(BYTE *buf, HLPFILE_BPTreeCallback cb, void *cookie)
Definition: hlpfile.c:125
unsigned int BOOL
Definition: ntddk_ex.h:94
GLsizeiptr size
Definition: glext.h:5919
GLenum GLclampf GLint GLenum GLuint GLenum GLenum GLsizei GLenum const GLvoid GLfloat GLfloat GLfloat GLfloat GLclampd GLint GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean GLboolean GLboolean GLboolean GLint GLenum GLsizei const GLvoid GLenum GLint GLenum GLint GLint GLsizei GLint GLenum GLint GLint GLint GLint GLsizei GLenum GLsizei const GLuint GLboolean flag
Definition: glfuncs.h:72
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define DEFAULT_PITCH
Definition: wingdi.h:441
COLORREF sr_color
Definition: hlpfile.h:36
COLORREF nsr_color
Definition: hlpfile.h:37
RGBQUAD bmiColors[1]
Definition: wingdi.h:1454
static void HLPFILE_AddHotSpotLinks(struct RtfData *rd, HLPFILE *file, const BYTE *start, ULONG hs_size, ULONG hs_offset)
Definition: hlpfile.c:785
#define debugstr_a
Definition: kernel32.h:31
#define THAI_CHARSET
Definition: wingdi.h:395
unsigned offset
Definition: hlpfile.h:76
static void HLPFILE_DeletePage(HLPFILE_PAGE *page)
Definition: hlpfile.c:2280
#define RGB(r, g, b)
Definition: wingdi.h:2917
const GLubyte * c
Definition: glext.h:8905
#define SHIFTJIS_CHARSET
Definition: wingdi.h:384
unsigned int UINT
Definition: ndis.h:50
LPSTR lpszCopyright
Definition: hlpfile.h:106
LPSTR lpszTitle
Definition: hlpfile.h:105
#define OUT_DEFAULT_PRECIS
Definition: wingdi.h:413
int xx
Definition: npserver.c:29
#define for
Definition: utility.h:88
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned char_pos
Definition: hlpfile.h:195
GLuint GLuint num
Definition: glext.h:9618
HICON WINAPI CreateIconFromResourceEx(_In_reads_bytes_(dwResSize) PBYTE presbits, _In_ DWORD dwResSize, _In_ BOOL fIcon, _In_ DWORD dwVer, _In_ int cxDesired, _In_ int cyDesired, _In_ UINT Flags)
DWORD biSizeImage
Definition: amvideo.idl:36
LONG lfWidth
Definition: dimm.idl:43
BYTE * kwdata
Definition: hlpfile.h:112
HLPFILE_MAP * Map
Definition: hlpfile.h:114
static DWORD cb
Definition: integrity.c:41
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
HENHMETAFILE WINAPI CloseEnhMetaFile(_In_ HDC hdc)
BOOL HLPFILE_BrowsePage(HLPFILE_PAGE *page, struct RtfData *rd, unsigned font_scale, unsigned relative)
Definition: hlpfile.c:1703
static int comp_FindSubFile(void *p, const void *key, int leaf, void **next)
Definition: hlpfile.c:491
#define RUSSIAN_CHARSET
Definition: wingdi.h:394
BOOL compressed
Definition: hlpfile.h:129
GLbitfield flags
Definition: glext.h:7161
LONG lfOrientation
Definition: dimm.idl:45
struct tagHlpFilePage * prev
Definition: hlpfile.h:79
HBITMAP WINAPI CreateDIBitmap(_In_ HDC hdc, _In_opt_ const BITMAPINFOHEADER *pbmih, _In_ DWORD fdwInit, _In_opt_ const VOID *pvInit, _In_opt_ const BITMAPINFO *pbmi, _In_ UINT uUsage)
unsigned numFonts
Definition: hlpfile.h:143
static LONG fetch_long(const BYTE **ptr)
Definition: hlpfile.c:566
static BOOL HLPFILE_Uncompress_Topic(HLPFILE *hlpfile)
Definition: hlpfile.c:2468
struct tagHlpFileFile * prev
Definition: hlpfile.h:119
int ret
LPSTR lpszTitle
Definition: hlpfile.h:70
#define index(s, c)
Definition: various.h:29
BOOL hasPhrases
Definition: hlpfile.h:130
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
#define GB2312_CHARSET
Definition: wingdi.h:387
#define FF_ROMAN
Definition: wingdi.h:448
static unsigned short GET_USHORT(const BYTE *buffer, unsigned i)
Definition: hlpfile.c:37
HLPFILE_WINDOWINFO * windows
Definition: hlpfile.h:147
_In_ HANDLE hFile
Definition: mswsock.h:90
int code
Definition: i386-dis.c:3591
static const BYTE * HLPFILE_DecompressGfx(const BYTE *src, unsigned csz, unsigned sz, BYTE packing, BYTE **alloc)
Definition: hlpfile.c:640
static void HLPFILE_DeleteMacro(HLPFILE_MACRO *macro)
Definition: hlpfile.c:2264
DWORD browse_bwd
Definition: hlpfile.h:81
HICON hIcon
Definition: hlpfile.h:148
unsigned char BYTE
Definition: ntddk_ex.h:96
BYTE lfQuality
Definition: dimm.idl:53
static BOOL HLPFILE_SystemCommands(HLPFILE *hlpfile)
Definition: hlpfile.c:1997
HFONT hFont
Definition: hlpfile.h:96
COLORREF WINAPI SetTextColor(_In_ HDC, _In_ COLORREF)
Definition: text.c:784
ULONG_PTR SIZE_T
Definition: typedefs.h:78
static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned *len)
Definition: hlpfile.c:2637
#define FF_SWISS
Definition: wingdi.h:450
static unsigned __int64 next
Definition: rand_nt.c:6
static real win[4][36]
BOOL WINAPI DeleteDC(_In_ HDC)
unsigned short USHORT
Definition: pedump.c:61
INT x
Definition: msvc.h:62
static BOOL HLPFILE_GetTOMap(HLPFILE *hlpfile)
Definition: hlpfile.c:2244
#define fs
Definition: i386-dis.c:435
#define VIETNAMESE_CHARSET
Definition: wingdi.h:400
GLuint start
Definition: gl.h:1545
unsigned char dummy
Definition: maze.c:118
BYTE lfClipPrecision
Definition: dimm.idl:52
#define HEBREW_CHARSET
Definition: wingdi.h:391
#define major(rdev)
Definition: propsheet.cpp:818
_In_ HBITMAP hbm
Definition: ntgdi.h:2776
#define HeapReAlloc
Definition: compat.h:393
static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned ref, unsigned offset)
Definition: hlpfile.c:2533
static void HLPFILE_Uncompress2(HLPFILE *hlpfile, const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend)
Definition: hlpfile.c:233
unsigned wMapLen
Definition: hlpfile.h:113
#define HLP_DISPLAY
Definition: hlpfile.h:210
unsigned wRefCount
Definition: hlpfile.h:122
#define WINE_WARN
Definition: debug.h:364
#define FF_MODERN
Definition: wingdi.h:447
#define min(a, b)
Definition: monoChain.cc:55
#define alloc
Definition: rosglue.h:13
#define SRCAND
Definition: wingdi.h:328
unsigned short flags
Definition: hlpfile.h:125
static BOOL HLPFILE_GetKeywords(HLPFILE *hlpfile)
Definition: hlpfile.c:2187
BOOL force_color
Definition: hlpfile.h:200
#define HLP_TABLE
Definition: hlpfile.h:211
GLuint const GLubyte GLvoid const GLvoid * dst
Definition: s_context.h:57
static BOOL HLPFILE_RtfAddRawString(struct RtfData *rd, const char *str, size_t sz)
Definition: hlpfile.c:691
#define lstrcpynA
Definition: compat.h:408
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
LONG HLPFILE_Hash(LPCSTR lpszContext)
Definition: hlpfile.c:547
static short fetch_short(const BYTE **ptr)
Definition: hlpfile.c:601
BYTE * Context
Definition: hlpfile.h:110
#define FF_SCRIPT
Definition: wingdi.h:449
static HLPFILE * first_hlpfile
Definition: hlpfile.c:52
#define ARABIC_CHARSET
Definition: wingdi.h:392
char * strchr(const char *String, int ch)
Definition: utclib.c:501
BYTE * kwbtree
Definition: hlpfile.h:111
char * ptr
Definition: hlpfile.h:193
DWORD reference
Definition: hlpfile.h:77
#define getbit()
unsigned wTOMapLen
Definition: hlpfile.h:115
Definition: name.c:36
CONST GLfloat m[16]
Definition: m_xform.h:144
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
unsigned char_pos_rel
Definition: hlpfile.h:202
#define WS_OVERLAPPEDWINDOW
Definition: pedump.c:637
#define c
Definition: ke_i.h:80
unsigned int ULONG
Definition: retypes.h:1
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
CHAR lfFaceName[LF_FACESIZE]
Definition: dimm.idl:55
#define minor(rdev)
Definition: propsheet.cpp:819
#define HANGEUL_CHARSET
Definition: wingdi.h:385
HLPFILE_PAGE * HLPFILE_PageByHash(HLPFILE *hlpfile, LONG lHash, ULONG *relative)
Definition: hlpfile.c:437
#define GetBValue(rgb)
Definition: wingdi.h:2914
#define HLP_TOPICHDR
Definition: hlpfile.h:209
int(* HLPFILE_BPTreeCompare)(void *p, const void *key, int leaf, void **next)
Definition: hlpfile.h:168
static HLPFILE_PAGE * HLPFILE_Contents(HLPFILE *hlpfile, ULONG *relative)
Definition: hlpfile.c:399
const WCHAR * link
Definition: db.cpp:926
UCHAR rgbReserved
Definition: inbv.c:121
unsigned short dsize
Definition: hlpfile.h:128
static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)
Definition: hlpfile.c:2167
#define ANSI_CHARSET
Definition: wingdi.h:381
GLfloat GLfloat p
Definition: glext.h:8902
#define JOHAB_CHARSET
Definition: wingdi.h:399
unsigned wNumber
Definition: hlpfile.h:75
#define DIB_RGB_COLORS
Definition: wingdi.h:365
#define BALTIC_CHARSET
Definition: wingdi.h:393
struct tagHlpFilePage * next
Definition: hlpfile.h:78
#define GREEK_CHARSET
Definition: wingdi.h:389
HLPFILE_FONT * fonts
Definition: hlpfile.h:144
Definition: _hash_fun.h:40
static unsigned short fetch_ushort(const BYTE **ptr)
Definition: hlpfile.c:618
#define memset(x, y, z)
Definition: compat.h:39
int HFILE
Definition: windef.h:288
LONG cy
Definition: windef.h:325
#define BI_RGB
Definition: precomp.h:35
static char title[]
Definition: ps.c:92
UINT num_phrases
Definition: hlpfile.h:132
#define HeapFree(x, y, z)
Definition: compat.h:394
UINT file_buffer_size
Definition: hlpfile.h:103
static unsigned HLPFILE_HalfPointsScale(HLPFILE_PAGE *page, unsigned pts)
Definition: hlpfile.c:1214
#define MulDiv(x, y, z)
Definition: gdifloat.h:86
#define SRCCOPY
Definition: wingdi.h:331
struct CFHEADER header
Definition: fdi.c:109
HDC hdcMem
Definition: welcome.c:104
char * data
Definition: hlpfile.h:192
#define X(b, s)
LONG lfEscapement
Definition: dimm.idl:44
static HLPFILE_LINK * HLPFILE_AllocLink(struct RtfData *rd, int cookie, const char *str, unsigned len, LONG hash, BOOL clrChange, BOOL bHotSpot, unsigned wnd)
Definition: hlpfile.c:1176
static int comp_PageByHash(void *p, const void *key, int leaf, void **next)
Definition: hlpfile.c:420
char type[10]
Definition: hlpfile.h:29
Definition: path.c:42
struct tagHlpFileFile * next
Definition: hlpfile.h:120
static BOOL HLPFILE_ReadFont(HLPFILE *hlpfile)
Definition: hlpfile.c:1852
HBITMAP WINAPI CreateBitmap(_In_ INT cx, _In_ INT cy, _In_ UINT cPlanes, _In_ UINT cBitsPerPel, _In_opt_ const VOID *pvBits)
off
Definition: i386-dis.c:3909
Definition: fci.c:126
#define WINE_FIXME
Definition: debug.h:370