Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhlpfile.c
Go to the documentation of this file.
00001 /* 00002 * Help Viewer 00003 * 00004 * Copyright 1996 Ulrich Schmid 00005 * 2002, 2008 Eric Pouech 00006 * 2007 Kirill K. Smirnov 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00021 */ 00022 00023 #include <stdarg.h> 00024 #include <stdio.h> 00025 #include <string.h> 00026 00027 #include "windef.h" 00028 #include "winbase.h" 00029 #include "wingdi.h" 00030 #include "winuser.h" 00031 #include "winhelp.h" 00032 00033 #include "wine/debug.h" 00034 00035 WINE_DEFAULT_DEBUG_CHANNEL(winhelp); 00036 00037 static inline unsigned short GET_USHORT(const BYTE* buffer, unsigned i) 00038 { 00039 return (BYTE)buffer[i] + 0x100 * (BYTE)buffer[i + 1]; 00040 } 00041 00042 static inline short GET_SHORT(const BYTE* buffer, unsigned i) 00043 { 00044 return (BYTE)buffer[i] + 0x100 * (signed char)buffer[i+1]; 00045 } 00046 00047 static inline unsigned GET_UINT(const BYTE* buffer, unsigned i) 00048 { 00049 return GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i + 2); 00050 } 00051 00052 static HLPFILE *first_hlpfile = 0; 00053 00054 00055 /************************************************************************** 00056 * HLPFILE_BPTreeSearch 00057 * 00058 * Searches for an element in B+ tree 00059 * 00060 * PARAMS 00061 * buf [I] pointer to the embedded file structured as a B+ tree 00062 * key [I] pointer to data to find 00063 * comp [I] compare function 00064 * 00065 * RETURNS 00066 * Pointer to block identified by key, or NULL if failure. 00067 * 00068 */ 00069 static void* HLPFILE_BPTreeSearch(BYTE* buf, const void* key, 00070 HLPFILE_BPTreeCompare comp) 00071 { 00072 unsigned magic; 00073 unsigned page_size; 00074 unsigned cur_page; 00075 unsigned level; 00076 BYTE *pages, *ptr, *newptr; 00077 int i, entries; 00078 int ret; 00079 00080 magic = GET_USHORT(buf, 9); 00081 if (magic != 0x293B) 00082 { 00083 WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic); 00084 return NULL; 00085 } 00086 page_size = GET_USHORT(buf, 9+4); 00087 cur_page = GET_USHORT(buf, 9+26); 00088 level = GET_USHORT(buf, 9+32); 00089 pages = buf + 9 + 38; 00090 while (--level > 0) 00091 { 00092 ptr = pages + cur_page*page_size; 00093 entries = GET_SHORT(ptr, 2); 00094 ptr += 6; 00095 for (i = 0; i < entries; i++) 00096 { 00097 if (comp(ptr, key, 0, (void **)&newptr) > 0) break; 00098 ptr = newptr; 00099 } 00100 cur_page = GET_USHORT(ptr-2, 0); 00101 } 00102 ptr = pages + cur_page*page_size; 00103 entries = GET_SHORT(ptr, 2); 00104 ptr += 8; 00105 for (i = 0; i < entries; i++) 00106 { 00107 ret = comp(ptr, key, 1, (void **)&newptr); 00108 if (ret == 0) return ptr; 00109 if (ret > 0) return NULL; 00110 ptr = newptr; 00111 } 00112 return NULL; 00113 } 00114 00115 /************************************************************************** 00116 * HLPFILE_BPTreeEnum 00117 * 00118 * Enumerates elements in B+ tree. 00119 * 00120 * PARAMS 00121 * buf [I] pointer to the embedded file structured as a B+ tree 00122 * cb [I] compare function 00123 * cookie [IO] cookie for cb function 00124 */ 00125 void HLPFILE_BPTreeEnum(BYTE* buf, HLPFILE_BPTreeCallback cb, void* cookie) 00126 { 00127 unsigned magic; 00128 unsigned page_size; 00129 unsigned cur_page; 00130 unsigned level; 00131 BYTE *pages, *ptr, *newptr; 00132 int i, entries; 00133 00134 magic = GET_USHORT(buf, 9); 00135 if (magic != 0x293B) 00136 { 00137 WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic); 00138 return; 00139 } 00140 page_size = GET_USHORT(buf, 9+4); 00141 cur_page = GET_USHORT(buf, 9+26); 00142 level = GET_USHORT(buf, 9+32); 00143 pages = buf + 9 + 38; 00144 while (--level > 0) 00145 { 00146 ptr = pages + cur_page*page_size; 00147 cur_page = GET_USHORT(ptr, 4); 00148 } 00149 while (cur_page != 0xFFFF) 00150 { 00151 ptr = pages + cur_page*page_size; 00152 entries = GET_SHORT(ptr, 2); 00153 ptr += 8; 00154 for (i = 0; i < entries; i++) 00155 { 00156 cb(ptr, (void **)&newptr, cookie); 00157 ptr = newptr; 00158 } 00159 cur_page = GET_USHORT(pages+cur_page*page_size, 6); 00160 } 00161 } 00162 00163 00164 /*********************************************************************** 00165 * 00166 * HLPFILE_UncompressedLZ77_Size 00167 */ 00168 static INT HLPFILE_UncompressedLZ77_Size(const BYTE *ptr, const BYTE *end) 00169 { 00170 int i, newsize = 0; 00171 00172 while (ptr < end) 00173 { 00174 int mask = *ptr++; 00175 for (i = 0; i < 8 && ptr < end; i++, mask >>= 1) 00176 { 00177 if (mask & 1) 00178 { 00179 int code = GET_USHORT(ptr, 0); 00180 int len = 3 + (code >> 12); 00181 newsize += len; 00182 ptr += 2; 00183 } 00184 else newsize++, ptr++; 00185 } 00186 } 00187 00188 return newsize; 00189 } 00190 00191 /*********************************************************************** 00192 * 00193 * HLPFILE_UncompressLZ77 00194 */ 00195 static BYTE *HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr) 00196 { 00197 int i; 00198 00199 while (ptr < end) 00200 { 00201 int mask = *ptr++; 00202 for (i = 0; i < 8 && ptr < end; i++, mask >>= 1) 00203 { 00204 if (mask & 1) 00205 { 00206 int code = GET_USHORT(ptr, 0); 00207 int len = 3 + (code >> 12); 00208 int offset = code & 0xfff; 00209 /* 00210 * We must copy byte-by-byte here. We cannot use memcpy nor 00211 * memmove here. Just example: 00212 * a[]={1,2,3,4,5,6,7,8,9,10} 00213 * newptr=a+2; 00214 * offset=1; 00215 * We expect: 00216 * {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 11, 12} 00217 */ 00218 for (; len>0; len--, newptr++) *newptr = *(newptr-offset-1); 00219 ptr += 2; 00220 } 00221 else *newptr++ = *ptr++; 00222 } 00223 } 00224 00225 return newptr; 00226 } 00227 00228 /*********************************************************************** 00229 * 00230 * HLPFILE_Uncompress2 00231 */ 00232 00233 static void HLPFILE_Uncompress2(HLPFILE* hlpfile, const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend) 00234 { 00235 BYTE *phptr, *phend; 00236 UINT code; 00237 UINT index; 00238 00239 while (ptr < end && newptr < newend) 00240 { 00241 if (!*ptr || *ptr >= 0x10) 00242 *newptr++ = *ptr++; 00243 else 00244 { 00245 code = 0x100 * ptr[0] + ptr[1]; 00246 index = (code - 0x100) / 2; 00247 00248 phptr = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index]; 00249 phend = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index + 1]; 00250 00251 if (newptr + (phend - phptr) > newend) 00252 { 00253 WINE_FIXME("buffer overflow %p > %p for %lu bytes\n", 00254 newptr, newend, (SIZE_T)(phend - phptr)); 00255 return; 00256 } 00257 memcpy(newptr, phptr, phend - phptr); 00258 newptr += phend - phptr; 00259 if (code & 1) *newptr++ = ' '; 00260 00261 ptr += 2; 00262 } 00263 } 00264 if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend); 00265 } 00266 00267 /****************************************************************** 00268 * HLPFILE_Uncompress3 00269 * 00270 * 00271 */ 00272 static BOOL HLPFILE_Uncompress3(HLPFILE* hlpfile, char* dst, const char* dst_end, 00273 const BYTE* src, const BYTE* src_end) 00274 { 00275 unsigned int idx, len; 00276 00277 for (; src < src_end; src++) 00278 { 00279 if ((*src & 1) == 0) 00280 { 00281 idx = *src / 2; 00282 if (idx > hlpfile->num_phrases) 00283 { 00284 WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases); 00285 len = 0; 00286 } 00287 else 00288 { 00289 len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx]; 00290 if (dst + len <= dst_end) 00291 memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len); 00292 } 00293 } 00294 else if ((*src & 0x03) == 0x01) 00295 { 00296 idx = (*src + 1) * 64; 00297 idx += *++src; 00298 if (idx > hlpfile->num_phrases) 00299 { 00300 WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases); 00301 len = 0; 00302 } 00303 else 00304 { 00305 len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx]; 00306 if (dst + len <= dst_end) 00307 memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len); 00308 } 00309 } 00310 else if ((*src & 0x07) == 0x03) 00311 { 00312 len = (*src / 8) + 1; 00313 if (dst + len <= dst_end) 00314 memcpy(dst, src + 1, len); 00315 src += len; 00316 } 00317 else 00318 { 00319 len = (*src / 16) + 1; 00320 if (dst + len <= dst_end) 00321 memset(dst, ((*src & 0x0F) == 0x07) ? ' ' : 0, len); 00322 } 00323 dst += len; 00324 } 00325 00326 if (dst > dst_end) WINE_ERR("buffer overflow (%p > %p)\n", dst, dst_end); 00327 return TRUE; 00328 } 00329 00330 /****************************************************************** 00331 * HLPFILE_UncompressRLE 00332 * 00333 * 00334 */ 00335 static void HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE* dst, unsigned dstsz) 00336 { 00337 BYTE ch; 00338 BYTE* sdst = dst + dstsz; 00339 00340 while (src < end) 00341 { 00342 ch = *src++; 00343 if (ch & 0x80) 00344 { 00345 ch &= 0x7F; 00346 if (dst + ch <= sdst) 00347 memcpy(dst, src, ch); 00348 src += ch; 00349 } 00350 else 00351 { 00352 if (dst + ch <= sdst) 00353 memset(dst, (char)*src, ch); 00354 src++; 00355 } 00356 dst += ch; 00357 } 00358 if (dst != sdst) 00359 WINE_WARN("Buffer X-flow: d(%lu) instead of d(%u)\n", 00360 (SIZE_T)(dst - (sdst - dstsz)), dstsz); 00361 } 00362 00363 00364 /****************************************************************** 00365 * HLPFILE_PageByOffset 00366 * 00367 * 00368 */ 00369 HLPFILE_PAGE *HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset, ULONG* relative) 00370 { 00371 HLPFILE_PAGE* page; 00372 HLPFILE_PAGE* found; 00373 00374 if (!hlpfile) return 0; 00375 00376 WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, offset); 00377 00378 if (offset == 0xFFFFFFFF) return NULL; 00379 page = NULL; 00380 00381 for (found = NULL, page = hlpfile->first_page; page; page = page->next) 00382 { 00383 if (page->offset <= offset && (!found || found->offset < page->offset)) 00384 { 00385 *relative = offset - page->offset; 00386 found = page; 00387 } 00388 } 00389 if (!found) 00390 WINE_ERR("Page of offset %u not found in file %s\n", 00391 offset, hlpfile->lpszPath); 00392 return found; 00393 } 00394 00395 /*********************************************************************** 00396 * 00397 * HLPFILE_Contents 00398 */ 00399 static HLPFILE_PAGE* HLPFILE_Contents(HLPFILE *hlpfile, ULONG* relative) 00400 { 00401 HLPFILE_PAGE* page = NULL; 00402 00403 if (!hlpfile) return NULL; 00404 00405 page = HLPFILE_PageByOffset(hlpfile, hlpfile->contents_start, relative); 00406 if (!page) 00407 { 00408 page = hlpfile->first_page; 00409 *relative = 0; 00410 } 00411 return page; 00412 } 00413 00414 /************************************************************************** 00415 * comp_PageByHash 00416 * 00417 * HLPFILE_BPTreeCompare function for '|CONTEXT' B+ tree file 00418 * 00419 */ 00420 static int comp_PageByHash(void *p, const void *key, 00421 int leaf, void** next) 00422 { 00423 LONG lKey = (LONG_PTR)key; 00424 LONG lTest = (INT)GET_UINT(p, 0); 00425 00426 *next = (char *)p+(leaf?8:6); 00427 WINE_TRACE("Comparing '%d' with '%d'\n", lKey, lTest); 00428 if (lTest < lKey) return -1; 00429 if (lTest > lKey) return 1; 00430 return 0; 00431 } 00432 00433 /*********************************************************************** 00434 * 00435 * HLPFILE_PageByHash 00436 */ 00437 HLPFILE_PAGE *HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash, ULONG* relative) 00438 { 00439 BYTE *ptr; 00440 00441 if (!hlpfile) return NULL; 00442 if (!lHash) return HLPFILE_Contents(hlpfile, relative); 00443 00444 WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lHash); 00445 00446 /* For win 3.0 files hash values are really page numbers */ 00447 if (hlpfile->version <= 16) 00448 { 00449 if (lHash >= hlpfile->wTOMapLen) return NULL; 00450 return HLPFILE_PageByOffset(hlpfile, hlpfile->TOMap[lHash], relative); 00451 } 00452 00453 ptr = HLPFILE_BPTreeSearch(hlpfile->Context, LongToPtr(lHash), comp_PageByHash); 00454 if (!ptr) 00455 { 00456 WINE_ERR("Page of hash %x not found in file %s\n", lHash, hlpfile->lpszPath); 00457 return NULL; 00458 } 00459 00460 return HLPFILE_PageByOffset(hlpfile, GET_UINT(ptr, 4), relative); 00461 } 00462 00463 /*********************************************************************** 00464 * 00465 * HLPFILE_PageByMap 00466 */ 00467 HLPFILE_PAGE *HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative) 00468 { 00469 unsigned int i; 00470 00471 if (!hlpfile) return 0; 00472 00473 WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lMap); 00474 00475 for (i = 0; i < hlpfile->wMapLen; i++) 00476 { 00477 if (hlpfile->Map[i].lMap == lMap) 00478 return HLPFILE_PageByOffset(hlpfile, hlpfile->Map[i].offset, relative); 00479 } 00480 00481 WINE_ERR("Page of Map %x not found in file %s\n", lMap, hlpfile->lpszPath); 00482 return NULL; 00483 } 00484 00485 /************************************************************************** 00486 * comp_FindSubFile 00487 * 00488 * HLPFILE_BPTreeCompare function for HLPFILE directory. 00489 * 00490 */ 00491 static int comp_FindSubFile(void *p, const void *key, 00492 int leaf, void** next) 00493 { 00494 *next = (char *)p+strlen(p)+(leaf?5:3); 00495 WINE_TRACE("Comparing '%s' with '%s'\n", (char *)p, (const char *)key); 00496 return strcmp(p, key); 00497 } 00498 00499 /*********************************************************************** 00500 * 00501 * HLPFILE_FindSubFile 00502 */ 00503 static BOOL HLPFILE_FindSubFile(HLPFILE* hlpfile, LPCSTR name, BYTE **subbuf, BYTE **subend) 00504 { 00505 BYTE *ptr; 00506 00507 WINE_TRACE("looking for file '%s'\n", name); 00508 ptr = HLPFILE_BPTreeSearch(hlpfile->file_buffer + GET_UINT(hlpfile->file_buffer, 4), 00509 name, comp_FindSubFile); 00510 if (!ptr) return FALSE; 00511 *subbuf = hlpfile->file_buffer + GET_UINT(ptr, strlen(name)+1); 00512 if (*subbuf >= hlpfile->file_buffer + hlpfile->file_buffer_size) 00513 { 00514 WINE_ERR("internal file %s does not fit\n", name); 00515 return FALSE; 00516 } 00517 *subend = *subbuf + GET_UINT(*subbuf, 0); 00518 if (*subend > hlpfile->file_buffer + hlpfile->file_buffer_size) 00519 { 00520 WINE_ERR("internal file %s does not fit\n", name); 00521 return FALSE; 00522 } 00523 if (GET_UINT(*subbuf, 0) < GET_UINT(*subbuf, 4) + 9) 00524 { 00525 WINE_ERR("invalid size provided for internal file %s\n", name); 00526 return FALSE; 00527 } 00528 return TRUE; 00529 } 00530 00531 /*********************************************************************** 00532 * 00533 * HLPFILE_Hash 00534 */ 00535 LONG HLPFILE_Hash(LPCSTR lpszContext) 00536 { 00537 LONG lHash = 0; 00538 CHAR c; 00539 00540 while ((c = *lpszContext++)) 00541 { 00542 CHAR x = 0; 00543 if (c >= 'A' && c <= 'Z') x = c - 'A' + 17; 00544 if (c >= 'a' && c <= 'z') x = c - 'a' + 17; 00545 if (c >= '1' && c <= '9') x = c - '0'; 00546 if (c == '0') x = 10; 00547 if (c == '.') x = 12; 00548 if (c == '_') x = 13; 00549 if (x) lHash = lHash * 43 + x; 00550 } 00551 return lHash; 00552 } 00553 00554 static LONG fetch_long(const BYTE** ptr) 00555 { 00556 LONG ret; 00557 00558 if (*(*ptr) & 1) 00559 { 00560 ret = (*(const ULONG*)(*ptr) - 0x80000000) / 2; 00561 (*ptr) += 4; 00562 } 00563 else 00564 { 00565 ret = (*(const USHORT*)(*ptr) - 0x8000) / 2; 00566 (*ptr) += 2; 00567 } 00568 00569 return ret; 00570 } 00571 00572 static ULONG fetch_ulong(const BYTE** ptr) 00573 { 00574 ULONG ret; 00575 00576 if (*(*ptr) & 1) 00577 { 00578 ret = *(const ULONG*)(*ptr) / 2; 00579 (*ptr) += 4; 00580 } 00581 else 00582 { 00583 ret = *(const USHORT*)(*ptr) / 2; 00584 (*ptr) += 2; 00585 } 00586 return ret; 00587 } 00588 00589 static short fetch_short(const BYTE** ptr) 00590 { 00591 short ret; 00592 00593 if (*(*ptr) & 1) 00594 { 00595 ret = (*(const unsigned short*)(*ptr) - 0x8000) / 2; 00596 (*ptr) += 2; 00597 } 00598 else 00599 { 00600 ret = (*(const unsigned char*)(*ptr) - 0x80) / 2; 00601 (*ptr)++; 00602 } 00603 return ret; 00604 } 00605 00606 static unsigned short fetch_ushort(const BYTE** ptr) 00607 { 00608 unsigned short ret; 00609 00610 if (*(*ptr) & 1) 00611 { 00612 ret = *(const unsigned short*)(*ptr) / 2; 00613 (*ptr) += 2; 00614 } 00615 else 00616 { 00617 ret = *(const unsigned char*)(*ptr) / 2; 00618 (*ptr)++; 00619 } 00620 return ret; 00621 } 00622 00623 /****************************************************************** 00624 * HLPFILE_DecompressGfx 00625 * 00626 * Decompress the data part of a bitmap or a metafile 00627 */ 00628 static const BYTE* HLPFILE_DecompressGfx(const BYTE* src, unsigned csz, unsigned sz, BYTE packing, 00629 BYTE** alloc) 00630 { 00631 const BYTE* dst; 00632 BYTE* tmp; 00633 unsigned sz77; 00634 00635 WINE_TRACE("Unpacking (%d) from %u bytes to %u bytes\n", packing, csz, sz); 00636 00637 switch (packing) 00638 { 00639 case 0: /* uncompressed */ 00640 if (sz != csz) 00641 WINE_WARN("Bogus gfx sizes (uncompressed): %u / %u\n", sz, csz); 00642 dst = src; 00643 *alloc = NULL; 00644 break; 00645 case 1: /* RunLen */ 00646 dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz); 00647 if (!dst) return NULL; 00648 HLPFILE_UncompressRLE(src, src + csz, *alloc, sz); 00649 break; 00650 case 2: /* LZ77 */ 00651 sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz); 00652 dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz77); 00653 if (!dst) return NULL; 00654 HLPFILE_UncompressLZ77(src, src + csz, *alloc); 00655 if (sz77 != sz) 00656 WINE_WARN("Bogus gfx sizes (LZ77): %u / %u\n", sz77, sz); 00657 break; 00658 case 3: /* LZ77 then RLE */ 00659 sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz); 00660 tmp = HeapAlloc(GetProcessHeap(), 0, sz77); 00661 if (!tmp) return FALSE; 00662 HLPFILE_UncompressLZ77(src, src + csz, tmp); 00663 dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz); 00664 if (!dst) 00665 { 00666 HeapFree(GetProcessHeap(), 0, tmp); 00667 return FALSE; 00668 } 00669 HLPFILE_UncompressRLE(tmp, tmp + sz77, *alloc, sz); 00670 HeapFree(GetProcessHeap(), 0, tmp); 00671 break; 00672 default: 00673 WINE_FIXME("Unsupported packing %u\n", packing); 00674 return NULL; 00675 } 00676 return dst; 00677 } 00678 00679 static BOOL HLPFILE_RtfAddRawString(struct RtfData* rd, const char* str, size_t sz) 00680 { 00681 if (rd->ptr + sz >= rd->data + rd->allocated) 00682 { 00683 char* new = HeapReAlloc(GetProcessHeap(), 0, rd->data, rd->allocated *= 2); 00684 if (!new) return FALSE; 00685 rd->ptr = new + (rd->ptr - rd->data); 00686 rd->data = new; 00687 } 00688 memcpy(rd->ptr, str, sz); 00689 rd->ptr += sz; 00690 00691 return TRUE; 00692 } 00693 00694 static BOOL HLPFILE_RtfAddControl(struct RtfData* rd, const char* str) 00695 { 00696 if (*str == '\\' || *str == '{') rd->in_text = FALSE; 00697 else if (*str == '}') rd->in_text = TRUE; 00698 return HLPFILE_RtfAddRawString(rd, str, strlen(str)); 00699 } 00700 00701 static BOOL HLPFILE_RtfAddText(struct RtfData* rd, const char* str) 00702 { 00703 const char* p; 00704 const char* last; 00705 const char* replace; 00706 unsigned rlen; 00707 00708 if (!rd->in_text) 00709 { 00710 if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE; 00711 rd->in_text = TRUE; 00712 } 00713 for (last = p = str; *p; p++) 00714 { 00715 if (*p < 0) /* escape non ASCII chars */ 00716 { 00717 static char xx[8]; 00718 rlen = sprintf(xx, "\\'%x", *(const BYTE*)p); 00719 replace = xx; 00720 } 00721 else switch (*p) 00722 { 00723 case '{': rlen = 2; replace = "\\{"; break; 00724 case '}': rlen = 2; replace = "\\}"; break; 00725 case '\\': rlen = 2; replace = "\\\\"; break; 00726 default: continue; 00727 } 00728 if ((p != last && !HLPFILE_RtfAddRawString(rd, last, p - last)) || 00729 !HLPFILE_RtfAddRawString(rd, replace, rlen)) return FALSE; 00730 last = p + 1; 00731 } 00732 return HLPFILE_RtfAddRawString(rd, last, p - last); 00733 } 00734 00735 /****************************************************************** 00736 * RtfAddHexBytes 00737 * 00738 */ 00739 static BOOL HLPFILE_RtfAddHexBytes(struct RtfData* rd, const void* _ptr, unsigned sz) 00740 { 00741 char tmp[512]; 00742 unsigned i, step; 00743 const BYTE* ptr = _ptr; 00744 static const char* _2hex = "0123456789abcdef"; 00745 00746 if (!rd->in_text) 00747 { 00748 if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE; 00749 rd->in_text = TRUE; 00750 } 00751 for (; sz; sz -= step) 00752 { 00753 step = min(256, sz); 00754 for (i = 0; i < step; i++) 00755 { 00756 tmp[2 * i + 0] = _2hex[*ptr >> 4]; 00757 tmp[2 * i + 1] = _2hex[*ptr++ & 0xF]; 00758 } 00759 if (!HLPFILE_RtfAddRawString(rd, tmp, 2 * step)) return FALSE; 00760 } 00761 return TRUE; 00762 } 00763 00764 static HLPFILE_LINK* HLPFILE_AllocLink(struct RtfData* rd, int cookie, 00765 const char* str, unsigned len, LONG hash, 00766 unsigned clrChange, unsigned bHotSpot, unsigned wnd); 00767 00768 /****************************************************************** 00769 * HLPFILE_AddHotSpotLinks 00770 * 00771 */ 00772 static void HLPFILE_AddHotSpotLinks(struct RtfData* rd, HLPFILE* file, 00773 const BYTE* start, ULONG hs_size, ULONG hs_offset) 00774 { 00775 unsigned i, hs_num; 00776 ULONG hs_macro; 00777 const char* str; 00778 00779 if (hs_size == 0 || hs_offset == 0) return; 00780 00781 start += hs_offset; 00782 /* always 1 ?? */ 00783 hs_num = GET_USHORT(start, 1); 00784 hs_macro = GET_UINT(start, 3); 00785 00786 str = (const char*)start + 7 + 15 * hs_num + hs_macro; 00787 /* FIXME: should use hs_size to prevent out of bounds reads */ 00788 for (i = 0; i < hs_num; i++) 00789 { 00790 HLPFILE_HOTSPOTLINK* hslink; 00791 00792 WINE_TRACE("%02x-%02x%02x {%s,%s}\n", 00793 start[7 + 15 * i + 0], start[7 + 15 * i + 1], start[7 + 15 * i + 2], 00794 str, str + strlen(str) + 1); 00795 /* str points to two null terminated strings: 00796 * hotspot name, then link name 00797 */ 00798 str += strlen(str) + 1; /* skip hotspot name */ 00799 00800 hslink = NULL; 00801 switch (start[7 + 15 * i + 0]) 00802 /* The next two chars always look like 0x04 0x00 ??? 00803 * What are they for ? 00804 */ 00805 { 00806 case 0xC8: 00807 hslink = (HLPFILE_HOTSPOTLINK*) 00808 HLPFILE_AllocLink(rd, hlp_link_macro, str, -1, 0, 0, 1, -1); 00809 break; 00810 00811 case 0xE6: 00812 case 0xE7: 00813 hslink = (HLPFILE_HOTSPOTLINK*) 00814 HLPFILE_AllocLink(rd, (start[7 + 15 * i + 0] & 1) ? hlp_link_link : hlp_link_popup, 00815 file->lpszPath, -1, HLPFILE_Hash(str), 00816 0, 1, -1); 00817 break; 00818 00819 case 0xEE: 00820 case 0xEF: 00821 { 00822 const char* win = strchr(str, '>'); 00823 int wnd = -1; 00824 char* tgt = NULL; 00825 00826 if (win) 00827 { 00828 for (wnd = file->numWindows - 1; wnd >= 0; wnd--) 00829 { 00830 if (!strcmp(win + 1, file->windows[wnd].name)) break; 00831 } 00832 if (wnd == -1) 00833 WINE_WARN("Couldn't find window info for %s\n", win); 00834 if ((tgt = HeapAlloc(GetProcessHeap(), 0, win - str + 1))) 00835 { 00836 memcpy(tgt, str, win - str); 00837 tgt[win - str] = '\0'; 00838 } 00839 } 00840 hslink = (HLPFILE_HOTSPOTLINK*) 00841 HLPFILE_AllocLink(rd, (start[7 + 15 * i + 0] & 1) ? hlp_link_link : hlp_link_popup, 00842 file->lpszPath, -1, HLPFILE_Hash(tgt ? tgt : str), 0, 1, wnd); 00843 HeapFree(GetProcessHeap(), 0, tgt); 00844 break; 00845 } 00846 default: 00847 WINE_FIXME("unknown hotsport target 0x%x\n", start[7 + 15 * i + 0]); 00848 } 00849 if (hslink) 00850 { 00851 hslink->x = GET_USHORT(start, 7 + 15 * i + 3); 00852 hslink->y = GET_USHORT(start, 7 + 15 * i + 5); 00853 hslink->width = GET_USHORT(start, 7 + 15 * i + 7); 00854 hslink->height = GET_USHORT(start, 7 + 15 * i + 9); 00855 /* target = GET_UINT(start, 7 + 15 * i + 11); */ 00856 } 00857 str += strlen(str) + 1; 00858 } 00859 } 00860 00861 /****************************************************************** 00862 * HLPFILE_RtfAddTransparentBitmap 00863 * 00864 * We'll transform a transparent bitmap into an metafile that 00865 * we then transform into RTF 00866 */ 00867 static BOOL HLPFILE_RtfAddTransparentBitmap(struct RtfData* rd, const BITMAPINFO* bi, 00868 const void* pict, unsigned nc) 00869 { 00870 HDC hdc, hdcMask, hdcMem, hdcEMF; 00871 HBITMAP hbm, hbmMask, hbmOldMask, hbmOldMem; 00872 HENHMETAFILE hEMF; 00873 BOOL ret = FALSE; 00874 void* data; 00875 UINT sz; 00876 00877 hbm = CreateDIBitmap(hdc = GetDC(0), &bi->bmiHeader, 00878 CBM_INIT, pict, bi, DIB_RGB_COLORS); 00879 00880 hdcMem = CreateCompatibleDC(hdc); 00881 hbmOldMem = SelectObject(hdcMem, hbm); 00882 00883 /* create the mask bitmap from the main bitmap */ 00884 hdcMask = CreateCompatibleDC(hdc); 00885 hbmMask = CreateBitmap(bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, 1, 1, NULL); 00886 hbmOldMask = SelectObject(hdcMask, hbmMask); 00887 SetBkColor(hdcMem, 00888 RGB(bi->bmiColors[nc - 1].rgbRed, 00889 bi->bmiColors[nc - 1].rgbGreen, 00890 bi->bmiColors[nc - 1].rgbBlue)); 00891 BitBlt(hdcMask, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCCOPY); 00892 00893 /* sets to RGB(0,0,0) the transparent bits in main bitmap */ 00894 SetBkColor(hdcMem, RGB(0,0,0)); 00895 SetTextColor(hdcMem, RGB(255,255,255)); 00896 BitBlt(hdcMem, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMask, 0, 0, SRCAND); 00897 00898 SelectObject(hdcMask, hbmOldMask); 00899 DeleteDC(hdcMask); 00900 00901 SelectObject(hdcMem, hbmOldMem); 00902 DeleteDC(hdcMem); 00903 00904 /* we create the bitmap on the fly */ 00905 hdcEMF = CreateEnhMetaFile(NULL, NULL, NULL, NULL); 00906 hdcMem = CreateCompatibleDC(hdcEMF); 00907 00908 /* sets to RGB(0,0,0) the transparent bits in final bitmap */ 00909 hbmOldMem = SelectObject(hdcMem, hbmMask); 00910 SetBkColor(hdcEMF, RGB(255, 255, 255)); 00911 SetTextColor(hdcEMF, RGB(0, 0, 0)); 00912 BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCAND); 00913 00914 /* and copy the remaining bits of main bitmap */ 00915 SelectObject(hdcMem, hbm); 00916 BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCPAINT); 00917 SelectObject(hdcMem, hbmOldMem); 00918 DeleteDC(hdcMem); 00919 00920 /* do the cleanup */ 00921 ReleaseDC(0, hdc); 00922 DeleteObject(hbmMask); 00923 DeleteObject(hbm); 00924 00925 hEMF = CloseEnhMetaFile(hdcEMF); 00926 00927 /* generate rtf stream */ 00928 sz = GetEnhMetaFileBits(hEMF, 0, NULL); 00929 if (sz && (data = HeapAlloc(GetProcessHeap(), 0, sz))) 00930 { 00931 if (sz == GetEnhMetaFileBits(hEMF, sz, data)) 00932 { 00933 ret = HLPFILE_RtfAddControl(rd, "{\\pict\\emfblip") && 00934 HLPFILE_RtfAddHexBytes(rd, data, sz) && 00935 HLPFILE_RtfAddControl(rd, "}"); 00936 } 00937 HeapFree(GetProcessHeap(), 0, data); 00938 } 00939 DeleteEnhMetaFile(hEMF); 00940 00941 return ret; 00942 } 00943 00944 /****************************************************************** 00945 * HLPFILE_RtfAddBitmap 00946 * 00947 */ 00948 static BOOL HLPFILE_RtfAddBitmap(struct RtfData* rd, HLPFILE* file, const BYTE* beg, BYTE type, BYTE pack) 00949 { 00950 const BYTE* ptr; 00951 const BYTE* pict_beg; 00952 BYTE* alloc = NULL; 00953 BITMAPINFO* bi; 00954 ULONG off, csz; 00955 unsigned nc = 0; 00956 BOOL clrImportant = FALSE; 00957 BOOL ret = FALSE; 00958 char tmp[256]; 00959 unsigned hs_size, hs_offset; 00960 00961 bi = HeapAlloc(GetProcessHeap(), 0, sizeof(*bi)); 00962 if (!bi) return FALSE; 00963 00964 ptr = beg + 2; /* for type and pack */ 00965 00966 bi->bmiHeader.biSize = sizeof(bi->bmiHeader); 00967 bi->bmiHeader.biXPelsPerMeter = fetch_ulong(&ptr); 00968 bi->bmiHeader.biYPelsPerMeter = fetch_ulong(&ptr); 00969 bi->bmiHeader.biPlanes = fetch_ushort(&ptr); 00970 bi->bmiHeader.biBitCount = fetch_ushort(&ptr); 00971 bi->bmiHeader.biWidth = fetch_ulong(&ptr); 00972 bi->bmiHeader.biHeight = fetch_ulong(&ptr); 00973 bi->bmiHeader.biClrUsed = fetch_ulong(&ptr); 00974 clrImportant = fetch_ulong(&ptr); 00975 bi->bmiHeader.biClrImportant = (clrImportant > 1) ? clrImportant : 0; 00976 bi->bmiHeader.biCompression = BI_RGB; 00977 if (bi->bmiHeader.biBitCount > 32) WINE_FIXME("Unknown bit count %u\n", bi->bmiHeader.biBitCount); 00978 if (bi->bmiHeader.biPlanes != 1) WINE_FIXME("Unsupported planes %u\n", bi->bmiHeader.biPlanes); 00979 bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8) * bi->bmiHeader.biHeight; 00980 WINE_TRACE("planes=%d bc=%d size=(%d,%d)\n", 00981 bi->bmiHeader.biPlanes, bi->bmiHeader.biBitCount, 00982 bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); 00983 00984 csz = fetch_ulong(&ptr); 00985 hs_size = fetch_ulong(&ptr); 00986 00987 off = GET_UINT(ptr, 0); ptr += 4; 00988 hs_offset = GET_UINT(ptr, 0); ptr += 4; 00989 HLPFILE_AddHotSpotLinks(rd, file, beg, hs_size, hs_offset); 00990 00991 /* now read palette info */ 00992 if (type == 0x06) 00993 { 00994 unsigned i; 00995 00996 nc = bi->bmiHeader.biClrUsed; 00997 /* not quite right, especially for bitfields type of compression */ 00998 if (!nc && bi->bmiHeader.biBitCount <= 8) 00999 nc = 1 << bi->bmiHeader.biBitCount; 01000 01001 bi = HeapReAlloc(GetProcessHeap(), 0, bi, sizeof(*bi) + nc * sizeof(RGBQUAD)); 01002 if (!bi) return FALSE; 01003 for (i = 0; i < nc; i++) 01004 { 01005 bi->bmiColors[i].rgbBlue = ptr[0]; 01006 bi->bmiColors[i].rgbGreen = ptr[1]; 01007 bi->bmiColors[i].rgbRed = ptr[2]; 01008 bi->bmiColors[i].rgbReserved = 0; 01009 ptr += 4; 01010 } 01011 } 01012 pict_beg = HLPFILE_DecompressGfx(beg + off, csz, bi->bmiHeader.biSizeImage, pack, &alloc); 01013 01014 if (clrImportant == 1 && nc > 0) 01015 { 01016 ret = HLPFILE_RtfAddTransparentBitmap(rd, bi, pict_beg, nc); 01017 goto done; 01018 } 01019 if (!HLPFILE_RtfAddControl(rd, "{\\pict")) goto done; 01020 if (type == 0x06) 01021 { 01022 sprintf(tmp, "\\dibitmap0\\picw%d\\pich%d", 01023 bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); 01024 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01025 if (!HLPFILE_RtfAddHexBytes(rd, bi, sizeof(*bi) + nc * sizeof(RGBQUAD))) goto done; 01026 } 01027 else 01028 { 01029 sprintf(tmp, "\\wbitmap0\\wbmbitspixel%d\\wbmplanes%d\\picw%d\\pich%d", 01030 bi->bmiHeader.biBitCount, bi->bmiHeader.biPlanes, 01031 bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); 01032 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01033 } 01034 if (!HLPFILE_RtfAddHexBytes(rd, pict_beg, bi->bmiHeader.biSizeImage)) goto done; 01035 if (!HLPFILE_RtfAddControl(rd, "}")) goto done; 01036 01037 ret = TRUE; 01038 done: 01039 HeapFree(GetProcessHeap(), 0, bi); 01040 HeapFree(GetProcessHeap(), 0, alloc); 01041 01042 return ret; 01043 } 01044 01045 /****************************************************************** 01046 * HLPFILE_RtfAddMetaFile 01047 * 01048 */ 01049 static BOOL HLPFILE_RtfAddMetaFile(struct RtfData* rd, HLPFILE* file, const BYTE* beg, BYTE pack) 01050 { 01051 ULONG size, csize, off, hs_offset, hs_size; 01052 const BYTE* ptr; 01053 const BYTE* bits; 01054 BYTE* alloc = NULL; 01055 char tmp[256]; 01056 unsigned mm; 01057 BOOL ret; 01058 01059 WINE_TRACE("Loading metafile\n"); 01060 01061 ptr = beg + 2; /* for type and pack */ 01062 01063 mm = fetch_ushort(&ptr); /* mapping mode */ 01064 sprintf(tmp, "{\\pict\\wmetafile%d\\picw%d\\pich%d", 01065 mm, GET_USHORT(ptr, 0), GET_USHORT(ptr, 2)); 01066 if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; 01067 ptr += 4; 01068 01069 size = fetch_ulong(&ptr); /* decompressed size */ 01070 csize = fetch_ulong(&ptr); /* compressed size */ 01071 hs_size = fetch_ulong(&ptr); /* hotspot size */ 01072 off = GET_UINT(ptr, 0); 01073 hs_offset = GET_UINT(ptr, 4); 01074 ptr += 8; 01075 01076 HLPFILE_AddHotSpotLinks(rd, file, beg, hs_size, hs_offset); 01077 01078 WINE_TRACE("sz=%u csz=%u offs=%u/%u,%u/%u\n", 01079 size, csize, off, (ULONG)(ptr - beg), hs_size, hs_offset); 01080 01081 bits = HLPFILE_DecompressGfx(beg + off, csize, size, pack, &alloc); 01082 if (!bits) return FALSE; 01083 01084 ret = HLPFILE_RtfAddHexBytes(rd, bits, size) && 01085 HLPFILE_RtfAddControl(rd, "}"); 01086 01087 HeapFree(GetProcessHeap(), 0, alloc); 01088 01089 return ret; 01090 } 01091 01092 /****************************************************************** 01093 * HLPFILE_RtfAddGfxByAddr 01094 * 01095 */ 01096 static BOOL HLPFILE_RtfAddGfxByAddr(struct RtfData* rd, HLPFILE *hlpfile, 01097 const BYTE* ref, ULONG size) 01098 { 01099 unsigned i, numpict; 01100 01101 numpict = GET_USHORT(ref, 2); 01102 WINE_TRACE("Got picture magic=%04x #=%d\n", GET_USHORT(ref, 0), numpict); 01103 01104 for (i = 0; i < numpict; i++) 01105 { 01106 const BYTE* beg; 01107 const BYTE* ptr; 01108 BYTE type, pack; 01109 01110 WINE_TRACE("Offset[%d] = %x\n", i, GET_UINT(ref, (1 + i) * 4)); 01111 beg = ptr = ref + GET_UINT(ref, (1 + i) * 4); 01112 01113 type = *ptr++; 01114 pack = *ptr++; 01115 01116 switch (type) 01117 { 01118 case 5: /* device dependent bmp */ 01119 case 6: /* device independent bmp */ 01120 HLPFILE_RtfAddBitmap(rd, hlpfile, beg, type, pack); 01121 break; 01122 case 8: 01123 HLPFILE_RtfAddMetaFile(rd, hlpfile, beg, pack); 01124 break; 01125 default: WINE_FIXME("Unknown type %u\n", type); return FALSE; 01126 } 01127 01128 /* FIXME: hotspots */ 01129 01130 /* FIXME: implement support for multiple picture format */ 01131 if (numpict != 1) WINE_FIXME("Supporting only one bitmap format per logical bitmap (for now). Using first format\n"); 01132 break; 01133 } 01134 return TRUE; 01135 } 01136 01137 /****************************************************************** 01138 * HLPFILE_RtfAddGfxByIndex 01139 * 01140 * 01141 */ 01142 static BOOL HLPFILE_RtfAddGfxByIndex(struct RtfData* rd, HLPFILE *hlpfile, 01143 unsigned index) 01144 { 01145 char tmp[16]; 01146 BYTE *ref, *end; 01147 01148 WINE_TRACE("Loading picture #%d\n", index); 01149 01150 sprintf(tmp, "|bm%u", index); 01151 01152 if (!HLPFILE_FindSubFile(hlpfile, tmp, &ref, &end)) {WINE_WARN("no sub file\n"); return FALSE;} 01153 01154 ref += 9; 01155 return HLPFILE_RtfAddGfxByAddr(rd, hlpfile, ref, end - ref); 01156 } 01157 01158 /****************************************************************** 01159 * HLPFILE_AllocLink 01160 * 01161 * 01162 */ 01163 static HLPFILE_LINK* HLPFILE_AllocLink(struct RtfData* rd, int cookie, 01164 const char* str, unsigned len, LONG hash, 01165 unsigned clrChange, unsigned bHotSpot, unsigned wnd) 01166 { 01167 HLPFILE_LINK* link; 01168 char* link_str; 01169 unsigned asz = bHotSpot ? sizeof(HLPFILE_HOTSPOTLINK) : sizeof(HLPFILE_LINK); 01170 01171 /* FIXME: should build a string table for the attributes.link.lpszPath 01172 * they are reallocated for each link 01173 */ 01174 if (len == -1) len = strlen(str); 01175 link = HeapAlloc(GetProcessHeap(), 0, asz + len + 1); 01176 if (!link) return NULL; 01177 01178 link->cookie = cookie; 01179 link->string = link_str = (char*)link + asz; 01180 memcpy(link_str, str, len); 01181 link_str[len] = '\0'; 01182 link->hash = hash; 01183 link->bClrChange = clrChange ? 1 : 0; 01184 link->bHotSpot = bHotSpot; 01185 link->window = wnd; 01186 link->next = rd->first_link; 01187 rd->first_link = link; 01188 link->cpMin = rd->char_pos; 01189 rd->force_color = clrChange; 01190 if (rd->current_link) WINE_FIXME("Pending link\n"); 01191 if (bHotSpot) 01192 link->cpMax = rd->char_pos; 01193 else 01194 rd->current_link = link; 01195 01196 WINE_TRACE("Link[%d] to %s@%08x:%d\n", 01197 link->cookie, link->string, link->hash, link->window); 01198 return link; 01199 } 01200 01201 static unsigned HLPFILE_HalfPointsToTwips(unsigned pts) 01202 { 01203 static unsigned logPxY; 01204 if (!logPxY) 01205 { 01206 HDC hdc = GetDC(NULL); 01207 logPxY = GetDeviceCaps(hdc, LOGPIXELSY); 01208 ReleaseDC(NULL, hdc); 01209 } 01210 return MulDiv(pts, 72 * 10, logPxY); 01211 } 01212 01213 /*********************************************************************** 01214 * 01215 * HLPFILE_BrowseParagraph 01216 */ 01217 static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, 01218 BYTE *buf, BYTE* end, unsigned* parlen) 01219 { 01220 UINT textsize; 01221 const BYTE *format, *format_end; 01222 char *text, *text_base, *text_end; 01223 LONG size, blocksize, datalen; 01224 unsigned short bits; 01225 unsigned nc, ncol = 1; 01226 short table_width; 01227 BOOL in_table = FALSE; 01228 char tmp[256]; 01229 BOOL ret = FALSE; 01230 01231 if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;}; 01232 01233 *parlen = 0; 01234 blocksize = GET_UINT(buf, 0); 01235 size = GET_UINT(buf, 0x4); 01236 datalen = GET_UINT(buf, 0x10); 01237 text = text_base = HeapAlloc(GetProcessHeap(), 0, size); 01238 if (!text) return FALSE; 01239 if (size > blocksize - datalen) 01240 { 01241 /* need to decompress */ 01242 if (page->file->hasPhrases) 01243 HLPFILE_Uncompress2(page->file, buf + datalen, end, (BYTE*)text, (BYTE*)text + size); 01244 else if (page->file->hasPhrases40) 01245 HLPFILE_Uncompress3(page->file, text, text + size, buf + datalen, end); 01246 else 01247 { 01248 WINE_FIXME("Text size is too long, splitting\n"); 01249 size = blocksize - datalen; 01250 memcpy(text, buf + datalen, size); 01251 } 01252 } 01253 else 01254 memcpy(text, buf + datalen, size); 01255 01256 text_end = text + size; 01257 01258 format = buf + 0x15; 01259 format_end = buf + GET_UINT(buf, 0x10); 01260 01261 if (buf[0x14] == 0x20 || buf[0x14] == 0x23) 01262 { 01263 fetch_long(&format); 01264 *parlen = fetch_ushort(&format); 01265 } 01266 01267 if (buf[0x14] == 0x23) 01268 { 01269 char type; 01270 01271 in_table = TRUE; 01272 ncol = *format++; 01273 01274 if (!HLPFILE_RtfAddControl(rd, "\\trowd")) goto done; 01275 type = *format++; 01276 if (type == 0 || type == 2) 01277 { 01278 table_width = GET_SHORT(format, 0); 01279 format += 2; 01280 } 01281 else 01282 table_width = 32767; 01283 WINE_TRACE("New table: cols=%d type=%x width=%d\n", 01284 ncol, type, table_width); 01285 if (ncol > 1) 01286 { 01287 int pos; 01288 sprintf(tmp, "\\trgaph%d\\trleft%d", 01289 HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 6), table_width, 32767)), 01290 HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0), table_width, 32767))); 01291 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01292 pos = HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 6) / 2, table_width, 32767)); 01293 for (nc = 0; nc < ncol; nc++) 01294 { 01295 WINE_TRACE("column(%d/%d) gap=%d width=%d\n", 01296 nc, ncol, GET_SHORT(format, nc*4), 01297 GET_SHORT(format, nc*4+2)); 01298 pos += GET_SHORT(format, nc * 4) + GET_SHORT(format, nc * 4 + 2); 01299 sprintf(tmp, "\\cellx%d", 01300 HLPFILE_HalfPointsToTwips(MulDiv(pos, table_width, 32767))); 01301 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01302 } 01303 } 01304 else 01305 { 01306 WINE_TRACE("column(0/%d) gap=%d width=%d\n", 01307 ncol, GET_SHORT(format, 0), GET_SHORT(format, 2)); 01308 sprintf(tmp, "\\trleft%d\\cellx%d ", 01309 HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0), table_width, 32767)), 01310 HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0) + GET_SHORT(format, 2), 01311 table_width, 32767))); 01312 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01313 } 01314 format += ncol * 4; 01315 } 01316 01317 for (nc = 0; nc < ncol; ) 01318 { 01319 WINE_TRACE("looking for format at offset %lu in column %d\n", (SIZE_T)(format - (buf + 0x15)), nc); 01320 if (!HLPFILE_RtfAddControl(rd, "\\pard")) goto done; 01321 if (in_table) 01322 { 01323 nc = GET_SHORT(format, 0); 01324 if (nc == -1) break; 01325 format += 5; 01326 if (!HLPFILE_RtfAddControl(rd, "\\intbl")) goto done; 01327 } 01328 else nc++; 01329 if (buf[0x14] == 0x01) 01330 format += 6; 01331 else 01332 format += 4; 01333 bits = GET_USHORT(format, 0); format += 2; 01334 if (bits & 0x0001) fetch_long(&format); 01335 if (bits & 0x0002) 01336 { 01337 sprintf(tmp, "\\sb%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); 01338 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01339 } 01340 if (bits & 0x0004) 01341 { 01342 sprintf(tmp, "\\sa%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); 01343 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01344 } 01345 if (bits & 0x0008) 01346 { 01347 sprintf(tmp, "\\sl%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); 01348 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01349 } 01350 if (bits & 0x0010) 01351 { 01352 sprintf(tmp, "\\li%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); 01353 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01354 } 01355 if (bits & 0x0020) 01356 { 01357 sprintf(tmp, "\\ri%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); 01358 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01359 } 01360 if (bits & 0x0040) 01361 { 01362 sprintf(tmp, "\\fi%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); 01363 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01364 } 01365 if (bits & 0x0100) 01366 { 01367 BYTE brdr = *format++; 01368 short w; 01369 01370 if (brdr & 0x01 && !HLPFILE_RtfAddControl(rd, "\\box")) goto done; 01371 if (brdr & 0x02 && !HLPFILE_RtfAddControl(rd, "\\brdrt")) goto done; 01372 if (brdr & 0x04 && !HLPFILE_RtfAddControl(rd, "\\brdrl")) goto done; 01373 if (brdr & 0x08 && !HLPFILE_RtfAddControl(rd, "\\brdrb")) goto done; 01374 if (brdr & 0x10 && !HLPFILE_RtfAddControl(rd, "\\brdrr")) goto done; 01375 if (brdr & 0x20 && !HLPFILE_RtfAddControl(rd, "\\brdrth")) goto done; 01376 if (!(brdr & 0x20) && !HLPFILE_RtfAddControl(rd, "\\brdrs")) goto done; 01377 if (brdr & 0x40 && !HLPFILE_RtfAddControl(rd, "\\brdrdb")) goto done; 01378 /* 0x80: unknown */ 01379 01380 w = GET_SHORT(format, 0); format += 2; 01381 if (w) 01382 { 01383 sprintf(tmp, "\\brdrw%d", HLPFILE_HalfPointsToTwips(w)); 01384 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01385 } 01386 } 01387 if (bits & 0x0200) 01388 { 01389 int i, ntab = fetch_short(&format); 01390 unsigned tab, ts; 01391 const char* kind; 01392 01393 for (i = 0; i < ntab; i++) 01394 { 01395 tab = fetch_ushort(&format); 01396 ts = (tab & 0x4000) ? fetch_ushort(&format) : 0 /* left */; 01397 switch (ts) 01398 { 01399 default: WINE_FIXME("Unknown tab style %x\n", ts); 01400 /* fall through */ 01401 case 0: kind = ""; break; 01402 case 1: kind = "\\tqr"; break; 01403 case 2: kind = "\\tqc"; break; 01404 } 01405 /* FIXME: do kind */ 01406 sprintf(tmp, "%s\\tx%d", 01407 kind, HLPFILE_HalfPointsToTwips(tab & 0x3FFF)); 01408 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01409 } 01410 } 01411 switch (bits & 0xc00) 01412 { 01413 default: WINE_FIXME("Unsupported alignment 0xC00\n"); break; 01414 case 0: if (!HLPFILE_RtfAddControl(rd, "\\ql")) goto done; break; 01415 case 0x400: if (!HLPFILE_RtfAddControl(rd, "\\qr")) goto done; break; 01416 case 0x800: if (!HLPFILE_RtfAddControl(rd, "\\qc")) goto done; break; 01417 } 01418 01419 /* 0x1000 doesn't need space */ 01420 if ((bits & 0x1000) && !HLPFILE_RtfAddControl(rd, "\\keep")) goto done; 01421 if ((bits & 0xE080) != 0) 01422 WINE_FIXME("Unsupported bits %04x, potential trouble ahead\n", bits); 01423 01424 while (text < text_end && format < format_end) 01425 { 01426 WINE_TRACE("Got text: %s (%p/%p - %p/%p)\n", wine_dbgstr_a(text), text, text_end, format, format_end); 01427 textsize = strlen(text); 01428 if (textsize) 01429 { 01430 if (rd->force_color) 01431 { 01432 if ((rd->current_link->cookie == hlp_link_popup) ? 01433 !HLPFILE_RtfAddControl(rd, "{\\uld\\cf1") : 01434 !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1")) goto done; 01435 } 01436 if (!HLPFILE_RtfAddText(rd, text)) goto done; 01437 if (rd->force_color && !HLPFILE_RtfAddControl(rd, "}")) goto done; 01438 rd->char_pos += textsize; 01439 } 01440 /* else: null text, keep on storing attributes */ 01441 text += textsize + 1; 01442 01443 if (*format == 0xff) 01444 { 01445 format++; 01446 break; 01447 } 01448 01449 WINE_TRACE("format=%02x\n", *format); 01450 switch (*format) 01451 { 01452 case 0x20: 01453 WINE_FIXME("NIY20\n"); 01454 format += 5; 01455 break; 01456 01457 case 0x21: 01458 WINE_FIXME("NIY21\n"); 01459 format += 3; 01460 break; 01461 01462 case 0x80: 01463 { 01464 unsigned font = GET_USHORT(format, 1); 01465 unsigned fs; 01466 01467 WINE_TRACE("Changing font to %d\n", font); 01468 format += 3; 01469 /* Font size in hlpfile is given in the same units as 01470 rtf control word \fs uses (half-points). */ 01471 switch (rd->font_scale) 01472 { 01473 case 0: fs = page->file->fonts[font].LogFont.lfHeight - 4; break; 01474 default: 01475 case 1: fs = page->file->fonts[font].LogFont.lfHeight; break; 01476 case 2: fs = page->file->fonts[font].LogFont.lfHeight + 4; break; 01477 } 01478 /* FIXME: missing at least colors, also bold attribute looses information */ 01479 01480 sprintf(tmp, "\\f%d\\cf%d\\fs%d%s%s%s%s", 01481 font, font + 2, fs, 01482 page->file->fonts[font].LogFont.lfWeight > 400 ? "\\b" : "\\b0", 01483 page->file->fonts[font].LogFont.lfItalic ? "\\i" : "\\i0", 01484 page->file->fonts[font].LogFont.lfUnderline ? "\\ul" : "\\ul0", 01485 page->file->fonts[font].LogFont.lfStrikeOut ? "\\strike" : "\\strike0"); 01486 if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; 01487 } 01488 break; 01489 01490 case 0x81: 01491 if (!HLPFILE_RtfAddControl(rd, "\\line")) goto done; 01492 format += 1; 01493 rd->char_pos++; 01494 break; 01495 01496 case 0x82: 01497 if (in_table) 01498 { 01499 if (format[1] != 0xFF) 01500 { 01501 if (!HLPFILE_RtfAddControl(rd, "\\par\\intbl")) goto done; 01502 } 01503 else 01504 { 01505 if (!HLPFILE_RtfAddControl(rd, "\\cell\\pard\\intbl")) goto done; 01506 } 01507 } 01508 else if (!HLPFILE_RtfAddControl(rd, "\\par")) goto done; 01509 format += 1; 01510 rd->char_pos++; 01511 break; 01512 01513 case 0x83: 01514 if (!HLPFILE_RtfAddControl(rd, "\\tab")) goto done; 01515 format += 1; 01516 rd->char_pos++; 01517 break; 01518 01519 #if 0 01520 case 0x84: 01521 format += 3; 01522 break; 01523 #endif 01524 01525 case 0x86: 01526 case 0x87: 01527 case 0x88: 01528 { 01529 BYTE type = format[1]; 01530 LONG size; 01531 01532 /* FIXME: we don't use 'BYTE pos = (*format - 0x86);' for the image position */ 01533 format += 2; 01534 size = fetch_long(&format); 01535 01536 switch (type) 01537 { 01538 case 0x22: 01539 fetch_ushort(&format); /* hot spot */ 01540 /* fall thru */ 01541 case 0x03: 01542 switch (GET_SHORT(format, 0)) 01543 { 01544 case 0: 01545 HLPFILE_RtfAddGfxByIndex(rd, page->file, GET_SHORT(format, 2)); 01546 rd->char_pos++; 01547 break; 01548 case 1: 01549 WINE_FIXME("does it work ??? %x<%u>#%u\n", 01550 GET_SHORT(format, 0), 01551 size, GET_SHORT(format, 2)); 01552 HLPFILE_RtfAddGfxByAddr(rd, page->file, format + 2, size - 4); 01553 rd->char_pos++; 01554 break; 01555 default: 01556 WINE_FIXME("??? %u\n", GET_SHORT(format, 0)); 01557 break; 01558 } 01559 break; 01560 case 0x05: 01561 WINE_FIXME("Got an embedded element %s\n", format + 6); 01562 break; 01563 default: 01564 WINE_FIXME("Got a type %d picture\n", type); 01565 break; 01566 } 01567 format += size; 01568 } 01569 break; 01570 01571 case 0x89: 01572 format += 1; 01573 if (!rd->current_link) 01574 WINE_FIXME("No existing link\n"); 01575 rd->current_link->cpMax = rd->char_pos; 01576 rd->current_link = NULL; 01577 rd->force_color = FALSE; 01578 break; 01579 01580 case 0x8B: 01581 if (!HLPFILE_RtfAddControl(rd, "\\~")) goto done; 01582 format += 1; 01583 rd->char_pos++; 01584 break; 01585 01586 case 0x8C: 01587 if (!HLPFILE_RtfAddControl(rd, "\\_")) goto done; 01588 /* FIXME: it could be that hypen is also in input stream !! */ 01589 format += 1; 01590 rd->char_pos++; 01591 break; 01592 01593 #if 0 01594 case 0xA9: 01595 format += 2; 01596 break; 01597 #endif 01598 01599 case 0xC8: 01600 case 0xCC: 01601 WINE_TRACE("macro => %s\n", format + 3); 01602 HLPFILE_AllocLink(rd, hlp_link_macro, (const char*)format + 3, 01603 GET_USHORT(format, 1), 0, !(*format & 4), 0, -1); 01604 format += 3 + GET_USHORT(format, 1); 01605 break; 01606 01607 case 0xE0: 01608 case 0xE1: 01609 WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1)); 01610 HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, 01611 page->file->lpszPath, -1, GET_UINT(format, 1), 1, 0, -1); 01612 01613 01614 format += 5; 01615 break; 01616 01617 case 0xE2: 01618 case 0xE3: 01619 case 0xE6: 01620 case 0xE7: 01621 HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, 01622 page->file->lpszPath, -1, GET_UINT(format, 1), 01623 !(*format & 4), 0, -1); 01624 format += 5; 01625 break; 01626 01627 case 0xEA: 01628 case 0xEB: 01629 case 0xEE: 01630 case 0xEF: 01631 { 01632 const char* ptr = (const char*) format + 8; 01633 BYTE type = format[3]; 01634 int wnd = -1; 01635 01636 switch (type) 01637 { 01638 case 1: 01639 wnd = *ptr; 01640 /* fall through */ 01641 case 0: 01642 ptr = page->file->lpszPath; 01643 break; 01644 case 6: 01645 for (wnd = page->file->numWindows - 1; wnd >= 0; wnd--) 01646 { 01647 if (!strcmp(ptr, page->file->windows[wnd].name)) break; 01648 } 01649 if (wnd == -1) 01650 WINE_WARN("Couldn't find window info for %s\n", ptr); 01651 ptr += strlen(ptr) + 1; 01652 /* fall through */ 01653 case 4: 01654 break; 01655 default: 01656 WINE_WARN("Unknown link type %d\n", type); 01657 break; 01658 } 01659 HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, 01660 ptr, -1, GET_UINT(format, 4), !(*format & 4), 0, wnd); 01661 } 01662 format += 3 + GET_USHORT(format, 1); 01663 break; 01664 01665 default: 01666 WINE_WARN("format %02x\n", *format); 01667 format++; 01668 } 01669 } 01670 } 01671 if (in_table) 01672 { 01673 if (!HLPFILE_RtfAddControl(rd, "\\row\\par\\pard\\plain")) goto done; 01674 rd->char_pos += 2; 01675 } 01676 ret = TRUE; 01677 done: 01678 01679 HeapFree(GetProcessHeap(), 0, text_base); 01680 return ret; 01681 } 01682 01683 /****************************************************************** 01684 * HLPFILE_BrowsePage 01685 * 01686 */ 01687 BOOL HLPFILE_BrowsePage(HLPFILE_PAGE* page, struct RtfData* rd, 01688 unsigned font_scale, unsigned relative) 01689 { 01690 HLPFILE *hlpfile = page->file; 01691 BYTE *buf, *end; 01692 DWORD ref = page->reference; 01693 unsigned index, old_index = -1, offset, count = 0, offs = 0; 01694 unsigned cpg, parlen; 01695 char tmp[1024]; 01696 const char* ck = NULL; 01697 01698 rd->in_text = TRUE; 01699 rd->data = rd->ptr = HeapAlloc(GetProcessHeap(), 0, rd->allocated = 32768); 01700 rd->char_pos = 0; 01701 rd->first_link = rd->current_link = NULL; 01702 rd->force_color = FALSE; 01703 rd->font_scale = font_scale; 01704 rd->relative = relative; 01705 rd->char_pos_rel = 0; 01706 01707 switch (hlpfile->charset) 01708 { 01709 case DEFAULT_CHARSET: 01710 case ANSI_CHARSET: cpg = 1252; break; 01711 case SHIFTJIS_CHARSET: cpg = 932; break; 01712 case HANGEUL_CHARSET: cpg = 949; break; 01713 case GB2312_CHARSET: cpg = 936; break; 01714 case CHINESEBIG5_CHARSET: cpg = 950; break; 01715 case GREEK_CHARSET: cpg = 1253; break; 01716 case TURKISH_CHARSET: cpg = 1254; break; 01717 case HEBREW_CHARSET: cpg = 1255; break; 01718 case ARABIC_CHARSET: cpg = 1256; break; 01719 case BALTIC_CHARSET: cpg = 1257; break; 01720 case VIETNAMESE_CHARSET: cpg = 1258; break; 01721 case RUSSIAN_CHARSET: cpg = 1251; break; 01722 case EE_CHARSET: cpg = 1250; break; 01723 case THAI_CHARSET: cpg = 874; break; 01724 case JOHAB_CHARSET: cpg = 1361; break; 01725 case MAC_CHARSET: ck = "mac"; break; 01726 default: 01727 WINE_FIXME("Unsupported charset %u\n", hlpfile->charset); 01728 cpg = 1252; 01729 } 01730 if (ck) 01731 { 01732 sprintf(tmp, "{\\rtf1\\%s\\deff0", ck); 01733 if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; 01734 } 01735 else 01736 { 01737 sprintf(tmp, "{\\rtf1\\ansi\\ansicpg%d\\deff0", cpg); 01738 if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; 01739 } 01740 01741 /* generate font table */ 01742 if (!HLPFILE_RtfAddControl(rd, "{\\fonttbl")) return FALSE; 01743 for (index = 0; index < hlpfile->numFonts; index++) 01744 { 01745 const char* family; 01746 switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0) 01747 { 01748 case FF_MODERN: family = "modern"; break; 01749 case FF_ROMAN: family = "roman"; break; 01750 case FF_SWISS: family = "swiss"; break; 01751 case FF_SCRIPT: family = "script"; break; 01752 case FF_DECORATIVE: family = "decor"; break; 01753 default: family = "nil"; break; 01754 } 01755 sprintf(tmp, "{\\f%d\\f%s\\fprq%d\\fcharset%d %s;}", 01756 index, family, 01757 hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0x0F, 01758 hlpfile->fonts[index].LogFont.lfCharSet, 01759 hlpfile->fonts[index].LogFont.lfFaceName); 01760 if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; 01761 } 01762 if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE; 01763 /* generate color table */ 01764 if (!HLPFILE_RtfAddControl(rd, "{\\colortbl ;\\red0\\green128\\blue0;")) return FALSE; 01765 for (index = 0; index < hlpfile->numFonts; index++) 01766 { 01767 sprintf(tmp, "\\red%d\\green%d\\blue%d;", 01768 GetRValue(hlpfile->fonts[index].color), 01769 GetGValue(hlpfile->fonts[index].color), 01770 GetBValue(hlpfile->fonts[index].color)); 01771 if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; 01772 } 01773 if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE; 01774 01775 do 01776 { 01777 if (hlpfile->version <= 16) 01778 { 01779 index = (ref - 0x0C) / hlpfile->dsize; 01780 offset = (ref - 0x0C) % hlpfile->dsize; 01781 } 01782 else 01783 { 01784 index = (ref - 0x0C) >> 14; 01785 offset = (ref - 0x0C) & 0x3FFF; 01786 } 01787 01788 if (hlpfile->version <= 16 && index != old_index && old_index != -1) 01789 { 01790 /* we jumped to the next block, adjust pointers */ 01791 ref -= 12; 01792 offset -= 12; 01793 } 01794 01795 if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;} 01796 buf = hlpfile->topic_map[index] + offset; 01797 if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;} 01798 end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end); 01799 if (index != old_index) {offs = 0; old_index = index;} 01800 01801 switch (buf[0x14]) 01802 { 01803 case 0x02: 01804 if (count++) goto done; 01805 break; 01806 case 0x01: 01807 case 0x20: 01808 case 0x23: 01809 if (!HLPFILE_BrowseParagraph(page, rd, buf, end, &parlen)) return FALSE; 01810 if (relative > index * 0x8000 + offs) 01811 rd->char_pos_rel = rd->char_pos; 01812 offs += parlen; 01813 break; 01814 default: 01815 WINE_ERR("buf[0x14] = %x\n", buf[0x14]); 01816 } 01817 if (hlpfile->version <= 16) 01818 { 01819 ref += GET_UINT(buf, 0xc); 01820 if (GET_UINT(buf, 0xc) == 0) 01821 break; 01822 } 01823 else 01824 ref = GET_UINT(buf, 0xc); 01825 } while (ref != 0xffffffff); 01826 done: 01827 page->first_link = rd->first_link; 01828 return HLPFILE_RtfAddControl(rd, "}"); 01829 } 01830 01831 /****************************************************************** 01832 * HLPFILE_ReadFont 01833 * 01834 * 01835 */ 01836 static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile) 01837 { 01838 BYTE *ref, *end; 01839 unsigned i, len, idx; 01840 unsigned face_num, dscr_num, face_offset, dscr_offset; 01841 BYTE flag, family; 01842 01843 if (!HLPFILE_FindSubFile(hlpfile, "|FONT", &ref, &end)) 01844 { 01845 WINE_WARN("no subfile FONT\n"); 01846 hlpfile->numFonts = 0; 01847 hlpfile->fonts = NULL; 01848 return FALSE; 01849 } 01850 01851 ref += 9; 01852 01853 face_num = GET_USHORT(ref, 0); 01854 dscr_num = GET_USHORT(ref, 2); 01855 face_offset = GET_USHORT(ref, 4); 01856 dscr_offset = GET_USHORT(ref, 6); 01857 01858 WINE_TRACE("Got NumFacenames=%u@%u NumDesc=%u@%u\n", 01859 face_num, face_offset, dscr_num, dscr_offset); 01860 01861 hlpfile->numFonts = dscr_num; 01862 hlpfile->fonts = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_FONT) * dscr_num); 01863 01864 len = (dscr_offset - face_offset) / face_num; 01865 /* EPP for (i = face_offset; i < dscr_offset; i += len) */ 01866 /* EPP WINE_FIXME("[%d]: %*s\n", i / len, len, ref + i); */ 01867 for (i = 0; i < dscr_num; i++) 01868 { 01869 flag = ref[dscr_offset + i * 11 + 0]; 01870 family = ref[dscr_offset + i * 11 + 2]; 01871 01872 hlpfile->fonts[i].LogFont.lfHeight = ref[dscr_offset + i * 11 + 1]; 01873 hlpfile->fonts[i].LogFont.lfWidth = 0; 01874 hlpfile->fonts[i].LogFont.lfEscapement = 0; 01875 hlpfile->fonts[i].LogFont.lfOrientation = 0; 01876 hlpfile->fonts[i].LogFont.lfWeight = (flag & 1) ? 700 : 400; 01877 hlpfile->fonts[i].LogFont.lfItalic = (flag & 2) ? TRUE : FALSE; 01878 hlpfile->fonts[i].LogFont.lfUnderline = (flag & 4) ? TRUE : FALSE; 01879 hlpfile->fonts[i].LogFont.lfStrikeOut = (flag & 8) ? TRUE : FALSE; 01880 hlpfile->fonts[i].LogFont.lfCharSet = hlpfile->charset; 01881 hlpfile->fonts[i].LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS; 01882 hlpfile->fonts[i].LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; 01883 hlpfile->fonts[i].LogFont.lfQuality = DEFAULT_QUALITY; 01884 hlpfile->fonts[i].LogFont.lfPitchAndFamily = DEFAULT_PITCH; 01885 01886 switch (family) 01887 { 01888 case 0x01: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_MODERN; break; 01889 case 0x02: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_ROMAN; break; 01890 case 0x03: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SWISS; break; 01891 case 0x04: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SCRIPT; break; 01892 case 0x05: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_DECORATIVE; break; 01893 default: WINE_FIXME("Unknown family %u\n", family); 01894 } 01895 idx = GET_USHORT(ref, dscr_offset + i * 11 + 3); 01896 01897 if (idx < face_num) 01898 { 01899 memcpy(hlpfile->fonts[i].LogFont.lfFaceName, ref + face_offset + idx * len, min(len, LF_FACESIZE - 1)); 01900 hlpfile->fonts[i].LogFont.lfFaceName[min(len, LF_FACESIZE - 1)] = '\0'; 01901 } 01902 else 01903 { 01904 WINE_FIXME("Too high face ref (%u/%u)\n", idx, face_num); 01905 strcpy(hlpfile->fonts[i].LogFont.lfFaceName, "Helv"); 01906 } 01907 hlpfile->fonts[i].hFont = 0; 01908 hlpfile->fonts[i].color = RGB(ref[dscr_offset + i * 11 + 5], 01909 ref[dscr_offset + i * 11 + 6], 01910 ref[dscr_offset + i * 11 + 7]); 01911 #define X(b,s) ((flag & (1 << b)) ? "-"s: "") 01912 WINE_TRACE("Font[%d]: flags=%02x%s%s%s%s%s%s pSize=%u family=%u face=%s[%u] color=%08x\n", 01913 i, flag, 01914 X(0, "bold"), 01915 X(1, "italic"), 01916 X(2, "underline"), 01917 X(3, "strikeOut"), 01918 X(4, "dblUnderline"), 01919 X(5, "smallCaps"), 01920 ref[dscr_offset + i * 11 + 1], 01921 family, 01922 hlpfile->fonts[i].LogFont.lfFaceName, idx, 01923 GET_UINT(ref, dscr_offset + i * 11 + 5) & 0x00FFFFFF); 01924 } 01925 return TRUE; 01926 } 01927 01928 /*********************************************************************** 01929 * 01930 * HLPFILE_ReadFileToBuffer 01931 */ 01932 static BOOL HLPFILE_ReadFileToBuffer(HLPFILE* hlpfile, HFILE hFile) 01933 { 01934 BYTE header[16], dummy[1]; 01935 01936 if (_hread(hFile, header, 16) != 16) {WINE_WARN("header\n"); return FALSE;}; 01937 01938 /* sanity checks */ 01939 if (GET_UINT(header, 0) != 0x00035F3F) 01940 {WINE_WARN("wrong header\n"); return FALSE;}; 01941 01942 hlpfile->file_buffer_size = GET_UINT(header, 12); 01943 hlpfile->file_buffer = HeapAlloc(GetProcessHeap(), 0, hlpfile->file_buffer_size + 1); 01944 if (!hlpfile->file_buffer) return FALSE; 01945 01946 memcpy(hlpfile->file_buffer, header, 16); 01947 if (_hread(hFile, hlpfile->file_buffer + 16, hlpfile->file_buffer_size - 16) !=hlpfile->file_buffer_size - 16) 01948 {WINE_WARN("filesize1\n"); return FALSE;}; 01949 01950 if (_hread(hFile, dummy, 1) != 0) WINE_WARN("filesize2\n"); 01951 01952 hlpfile->file_buffer[hlpfile->file_buffer_size] = '\0'; /* FIXME: was '0', sounds backwards to me */ 01953 01954 return TRUE; 01955 } 01956 01957 /*********************************************************************** 01958 * 01959 * HLPFILE_SystemCommands 01960 */ 01961 static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile) 01962 { 01963 BYTE *buf, *ptr, *end; 01964 HLPFILE_MACRO *macro, **m; 01965 LPSTR p; 01966 unsigned short magic, minor, major, flags; 01967 01968 hlpfile->lpszTitle = NULL; 01969 01970 if (!HLPFILE_FindSubFile(hlpfile, "|SYSTEM", &buf, &end)) return FALSE; 01971 01972 magic = GET_USHORT(buf + 9, 0); 01973 minor = GET_USHORT(buf + 9, 2); 01974 major = GET_USHORT(buf + 9, 4); 01975 /* gen date on 4 bytes */ 01976 flags = GET_USHORT(buf + 9, 10); 01977 WINE_TRACE("Got system header: magic=%04x version=%d.%d flags=%04x\n", 01978 magic, major, minor, flags); 01979 if (magic != 0x036C || major != 1) 01980 {WINE_WARN("Wrong system header\n"); return FALSE;} 01981 if (minor <= 16) 01982 { 01983 hlpfile->tbsize = 0x800; 01984 hlpfile->compressed = 0; 01985 } 01986 else if (flags == 0) 01987 { 01988 hlpfile->tbsize = 0x1000; 01989 hlpfile->compressed = 0; 01990 } 01991 else if (flags == 4) 01992 { 01993 hlpfile->tbsize = 0x1000; 01994 hlpfile->compressed = 1; 01995 } 01996 else 01997 { 01998 hlpfile->tbsize = 0x800; 01999 hlpfile->compressed = 1; 02000 } 02001 02002 if (hlpfile->compressed) 02003 hlpfile->dsize = 0x4000; 02004 else 02005 hlpfile->dsize = hlpfile->tbsize - 0x0C; 02006 02007 hlpfile->version = minor; 02008 hlpfile->flags = flags; 02009 hlpfile->charset = DEFAULT_CHARSET; 02010 02011 if (hlpfile->version <= 16) 02012 { 02013 char *str = (char*)buf + 0x15; 02014 02015 hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); 02016 if (!hlpfile->lpszTitle) return FALSE; 02017 lstrcpy(hlpfile->lpszTitle, str); 02018 WINE_TRACE("Title: %s\n", hlpfile->lpszTitle); 02019 /* Nothing more to parse */ 02020 return TRUE; 02021 } 02022 for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4) 02023 { 02024 char *str = (char*) ptr + 4; 02025 switch (GET_USHORT(ptr, 0)) 02026 { 02027 case 1: 02028 if (hlpfile->lpszTitle) {WINE_WARN("title\n"); break;} 02029 hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); 02030 if (!hlpfile->lpszTitle) return FALSE; 02031 lstrcpy(hlpfile->lpszTitle, str); 02032 WINE_TRACE("Title: %s\n", hlpfile->lpszTitle); 02033 break; 02034 02035 case 2: 02036 if (hlpfile->lpszCopyright) {WINE_WARN("copyright\n"); break;} 02037 hlpfile->lpszCopyright = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); 02038 if (!hlpfile->lpszCopyright) return FALSE; 02039 lstrcpy(hlpfile->lpszCopyright, str); 02040 WINE_TRACE("Copyright: %s\n", hlpfile->lpszCopyright); 02041 break; 02042 02043 case 3: 02044 if (GET_USHORT(ptr, 2) != 4) {WINE_WARN("system3\n");break;} 02045 hlpfile->contents_start = GET_UINT(ptr, 4); 02046 WINE_TRACE("Setting contents start at %08lx\n", hlpfile->contents_start); 02047 break; 02048 02049 case 4: 02050 macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + lstrlen(str) + 1); 02051 if (!macro) break; 02052 p = (char*)macro + sizeof(HLPFILE_MACRO); 02053 lstrcpy(p, str); 02054 macro->lpszMacro = p; 02055 macro->next = 0; 02056 for (m = &hlpfile->first_macro; *m; m = &(*m)->next); 02057 *m = macro; 02058 break; 02059 02060 case 5: 02061 if (GET_USHORT(ptr, 4 + 4) != 1) 02062 WINE_FIXME("More than one icon, picking up first\n"); 02063 /* 0x16 is sizeof(CURSORICONDIR), see user32/user_private.h */ 02064 hlpfile->hIcon = CreateIconFromResourceEx(ptr + 4 + 0x16, 02065 GET_USHORT(ptr, 2) - 0x16, TRUE, 02066 0x30000, 0, 0, 0); 02067 break; 02068 02069 case 6: 02070 if (GET_USHORT(ptr, 2) != 90) {WINE_WARN("system6\n");break;} 02071 02072 if (hlpfile->windows) 02073 hlpfile->windows = HeapReAlloc(GetProcessHeap(), 0, hlpfile->windows, 02074 sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows); 02075 else 02076 hlpfile->windows = HeapAlloc(GetProcessHeap(), 0, 02077 sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows); 02078 02079 if (hlpfile->windows) 02080 { 02081 unsigned flags = GET_USHORT(ptr, 4); 02082 HLPFILE_WINDOWINFO* wi = &hlpfile->windows[hlpfile->numWindows - 1]; 02083 02084 if (flags & 0x0001) strcpy(wi->type, &str[2]); 02085 else wi->type[0] = '\0'; 02086 if (flags & 0x0002) strcpy(wi->name, &str[12]); 02087 else wi->name[0] = '\0'; 02088 if (flags & 0x0004) strcpy(wi->caption, &str[21]); 02089 else lstrcpynA(wi->caption, hlpfile->lpszTitle, sizeof(wi->caption)); 02090 wi->origin.x = (flags & 0x0008) ? GET_USHORT(ptr, 76) : CW_USEDEFAULT; 02091 wi->origin.y = (flags & 0x0010) ? GET_USHORT(ptr, 78) : CW_USEDEFAULT; 02092 wi->size.cx = (flags & 0x0020) ? GET_USHORT(ptr, 80) : CW_USEDEFAULT; 02093 wi->size.cy = (flags & 0x0040) ? GET_USHORT(ptr, 82) : CW_USEDEFAULT; 02094 wi->style = (flags & 0x0080) ? GET_USHORT(ptr, 84) : SW_SHOW; 02095 wi->win_style = WS_OVERLAPPEDWINDOW; 02096 wi->sr_color = (flags & 0x0100) ? GET_UINT(ptr, 86) : 0xFFFFFF; 02097 wi->nsr_color = (flags & 0x0200) ? GET_UINT(ptr, 90) : 0xFFFFFF; 02098 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", 02099 flags & 0x0001 ? 'T' : 't', 02100 flags & 0x0002 ? 'N' : 'n', 02101 flags & 0x0004 ? 'C' : 'c', 02102 flags & 0x0008 ? 'X' : 'x', 02103 flags & 0x0010 ? 'Y' : 'y', 02104 flags & 0x0020 ? 'W' : 'w', 02105 flags & 0x0040 ? 'H' : 'h', 02106 flags & 0x0080 ? 'S' : 's', 02107 wi->type, wi->name, wi->caption, wi->origin.x, wi->origin.y, 02108 wi->size.cx, wi->size.cy); 02109 } 02110 break; 02111 case 8: 02112 WINE_WARN("Citation: '%s'\n", ptr + 4); 02113 break; 02114 case 11: 02115 hlpfile->charset = ptr[4]; 02116 WINE_TRACE("Charset: %d\n", hlpfile->charset); 02117 break; 02118 default: 02119 WINE_WARN("Unsupported SystemRecord[%d]\n", GET_USHORT(ptr, 0)); 02120 } 02121 } 02122 if (!hlpfile->lpszTitle) 02123 hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1); 02124 return TRUE; 02125 } 02126 02127 /*********************************************************************** 02128 * 02129 * HLPFILE_GetContext 02130 */ 02131 static BOOL HLPFILE_GetContext(HLPFILE *hlpfile) 02132 { 02133 BYTE *cbuf, *cend; 02134 unsigned clen; 02135 02136 if (!HLPFILE_FindSubFile(hlpfile, "|CONTEXT", &cbuf, &cend)) 02137 {WINE_WARN("context0\n"); return FALSE;} 02138 02139 clen = cend - cbuf; 02140 hlpfile->Context = HeapAlloc(GetProcessHeap(), 0, clen); 02141 if (!hlpfile->Context) return FALSE; 02142 memcpy(hlpfile->Context, cbuf, clen); 02143 02144 return TRUE; 02145 } 02146 02147 /*********************************************************************** 02148 * 02149 * HLPFILE_GetKeywords 02150 */ 02151 static BOOL HLPFILE_GetKeywords(HLPFILE *hlpfile) 02152 { 02153 BYTE *cbuf, *cend; 02154 unsigned clen; 02155 02156 if (!HLPFILE_FindSubFile(hlpfile, "|KWBTREE", &cbuf, &cend)) return FALSE; 02157 clen = cend - cbuf; 02158 hlpfile->kwbtree = HeapAlloc(GetProcessHeap(), 0, clen); 02159 if (!hlpfile->kwbtree) return FALSE; 02160 memcpy(hlpfile->kwbtree, cbuf, clen); 02161 02162 if (!HLPFILE_FindSubFile(hlpfile, "|KWDATA", &cbuf, &cend)) 02163 { 02164 WINE_ERR("corrupted help file: kwbtree present but kwdata absent\n"); 02165 HeapFree(GetProcessHeap(), 0, hlpfile->kwbtree); 02166 return FALSE; 02167 } 02168 clen = cend - cbuf; 02169 hlpfile->kwdata = HeapAlloc(GetProcessHeap(), 0, clen); 02170 if (!hlpfile->kwdata) 02171 { 02172 HeapFree(GetProcessHeap(), 0, hlpfile->kwdata); 02173 return FALSE; 02174 } 02175 memcpy(hlpfile->kwdata, cbuf, clen); 02176 02177 return TRUE; 02178 } 02179 02180 /*********************************************************************** 02181 * 02182 * HLPFILE_GetMap 02183 */ 02184 static BOOL HLPFILE_GetMap(HLPFILE *hlpfile) 02185 { 02186 BYTE *cbuf, *cend; 02187 unsigned entries, i; 02188 02189 if (!HLPFILE_FindSubFile(hlpfile, "|CTXOMAP", &cbuf, &cend)) 02190 {WINE_WARN("no map section\n"); return FALSE;} 02191 02192 entries = GET_USHORT(cbuf, 9); 02193 hlpfile->Map = HeapAlloc(GetProcessHeap(), 0, entries * sizeof(HLPFILE_MAP)); 02194 if (!hlpfile->Map) return FALSE; 02195 hlpfile->wMapLen = entries; 02196 for (i = 0; i < entries; i++) 02197 { 02198 hlpfile->Map[i].lMap = GET_UINT(cbuf+11,i*8); 02199 hlpfile->Map[i].offset = GET_UINT(cbuf+11,i*8+4); 02200 } 02201 return TRUE; 02202 } 02203 02204 /*********************************************************************** 02205 * 02206 * HLPFILE_GetTOMap 02207 */ 02208 static BOOL HLPFILE_GetTOMap(HLPFILE *hlpfile) 02209 { 02210 BYTE *cbuf, *cend; 02211 unsigned clen; 02212 02213 if (!HLPFILE_FindSubFile(hlpfile, "|TOMAP", &cbuf, &cend)) 02214 {WINE_WARN("no tomap section\n"); return FALSE;} 02215 02216 clen = cend - cbuf - 9; 02217 hlpfile->TOMap = HeapAlloc(GetProcessHeap(), 0, clen); 02218 if (!hlpfile->TOMap) return FALSE; 02219 memcpy(hlpfile->TOMap, cbuf+9, clen); 02220 hlpfile->wTOMapLen = clen/4; 02221 return TRUE; 02222 } 02223 02224 /*********************************************************************** 02225 * 02226 * DeleteMacro 02227 */ 02228 static void HLPFILE_DeleteMacro(HLPFILE_MACRO* macro) 02229 { 02230 HLPFILE_MACRO* next; 02231 02232 while (macro) 02233 { 02234 next = macro->next; 02235 HeapFree(GetProcessHeap(), 0, macro); 02236 macro = next; 02237 } 02238 } 02239 02240 /*********************************************************************** 02241 * 02242 * DeletePage 02243 */ 02244 static void HLPFILE_DeletePage(HLPFILE_PAGE* page) 02245 { 02246 HLPFILE_PAGE* next; 02247 02248 while (page) 02249 { 02250 next = page->next; 02251 HLPFILE_DeleteMacro(page->first_macro); 02252 HeapFree(GetProcessHeap(), 0, page); 02253 page = next; 02254 } 02255 } 02256 02257 /*********************************************************************** 02258 * 02259 * HLPFILE_FreeHlpFile 02260 */ 02261 void HLPFILE_FreeHlpFile(HLPFILE* hlpfile) 02262 { 02263 unsigned i; 02264 02265 if (!hlpfile || --hlpfile->wRefCount > 0) return; 02266 02267 if (hlpfile->next) hlpfile->next->prev = hlpfile->prev; 02268 if (hlpfile->prev) hlpfile->prev->next = hlpfile->next; 02269 else first_hlpfile = hlpfile->next; 02270 02271 if (hlpfile->numFonts) 02272 { 02273 for (i = 0; i < hlpfile->numFonts; i++) 02274 { 02275 DeleteObject(hlpfile->fonts[i].hFont); 02276 } 02277 HeapFree(GetProcessHeap(), 0, hlpfile->fonts); 02278 } 02279 02280 if (hlpfile->numBmps) 02281 { 02282 for (i = 0; i < hlpfile->numBmps; i++) 02283 { 02284 DeleteObject(hlpfile->bmps[i]); 02285 } 02286 HeapFree(GetProcessHeap(), 0, hlpfile->bmps); 02287 } 02288 02289 HLPFILE_DeletePage(hlpfile->first_page); 02290 HLPFILE_DeleteMacro(hlpfile->first_macro); 02291 02292 DestroyIcon(hlpfile->hIcon); 02293 if (hlpfile->numWindows) HeapFree(GetProcessHeap(), 0, hlpfile->windows); 02294 HeapFree(GetProcessHeap(), 0, hlpfile->Context); 02295 HeapFree(GetProcessHeap(), 0, hlpfile->Map); 02296 HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle); 02297 HeapFree(GetProcessHeap(), 0, hlpfile->lpszCopyright); 02298 HeapFree(GetProcessHeap(), 0, hlpfile->file_buffer); 02299 HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); 02300 HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); 02301 HeapFree(GetProcessHeap(), 0, hlpfile->topic_map); 02302 HeapFree(GetProcessHeap(), 0, hlpfile->help_on_file); 02303 HeapFree(GetProcessHeap(), 0, hlpfile); 02304 } 02305 02306 /*********************************************************************** 02307 * 02308 * HLPFILE_UncompressLZ77_Phrases 02309 */ 02310 static BOOL HLPFILE_UncompressLZ77_Phrases(HLPFILE* hlpfile) 02311 { 02312 UINT i, num, dec_size, head_size; 02313 BYTE *buf, *end; 02314 02315 if (!HLPFILE_FindSubFile(hlpfile, "|Phrases", &buf, &end)) return FALSE; 02316 02317 if (hlpfile->version <= 16) 02318 head_size = 13; 02319 else 02320 head_size = 17; 02321 02322 num = hlpfile->num_phrases = GET_USHORT(buf, 9); 02323 if (buf + 2 * num + 0x13 >= end) {WINE_WARN("1a\n"); return FALSE;}; 02324 02325 if (hlpfile->version <= 16) 02326 dec_size = end - buf - 15 - 2 * num; 02327 else 02328 dec_size = HLPFILE_UncompressedLZ77_Size(buf + 0x13 + 2 * num, end); 02329 02330 hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1)); 02331 hlpfile->phrases_buffer = HeapAlloc(GetProcessHeap(), 0, dec_size); 02332 if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer) 02333 { 02334 HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); 02335 HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); 02336 return FALSE; 02337 } 02338 02339 for (i = 0; i <= num; i++) 02340 hlpfile->phrases_offsets[i] = GET_USHORT(buf, head_size + 2 * i) - 2 * num - 2; 02341 02342 if (hlpfile->version <= 16) 02343 memcpy(hlpfile->phrases_buffer, buf + 15 + 2*num, dec_size); 02344 else 02345 HLPFILE_UncompressLZ77(buf + 0x13 + 2 * num, end, (BYTE*)hlpfile->phrases_buffer); 02346 02347 hlpfile->hasPhrases = TRUE; 02348 return TRUE; 02349 } 02350 02351 /*********************************************************************** 02352 * 02353 * HLPFILE_Uncompress_Phrases40 02354 */ 02355 static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE* hlpfile) 02356 { 02357 UINT num; 02358 INT dec_size, cpr_size; 02359 BYTE *buf_idx, *end_idx; 02360 BYTE *buf_phs, *end_phs; 02361 LONG* ptr, mask = 0; 02362 unsigned int i; 02363 unsigned short bc, n; 02364 02365 if (!HLPFILE_FindSubFile(hlpfile, "|PhrIndex", &buf_idx, &end_idx) || 02366 !HLPFILE_FindSubFile(hlpfile, "|PhrImage", &buf_phs, &end_phs)) return FALSE; 02367 02368 ptr = (LONG*)(buf_idx + 9 + 28); 02369 bc = GET_USHORT(buf_idx, 9 + 24) & 0x0F; 02370 num = hlpfile->num_phrases = GET_USHORT(buf_idx, 9 + 4); 02371 02372 WINE_TRACE("Index: Magic=%08x #entries=%u CpsdSize=%u PhrImgSize=%u\n" 02373 "\tPhrImgCprsdSize=%u 0=%u bc=%x ukn=%x\n", 02374 GET_UINT(buf_idx, 9 + 0), 02375 GET_UINT(buf_idx, 9 + 4), 02376 GET_UINT(buf_idx, 9 + 8), 02377 GET_UINT(buf_idx, 9 + 12), 02378 GET_UINT(buf_idx, 9 + 16), 02379 GET_UINT(buf_idx, 9 + 20), 02380 GET_USHORT(buf_idx, 9 + 24), 02381 GET_USHORT(buf_idx, 9 + 26)); 02382 02383 dec_size = GET_UINT(buf_idx, 9 + 12); 02384 cpr_size = GET_UINT(buf_idx, 9 + 16); 02385 02386 if (dec_size != cpr_size && 02387 dec_size != HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)) 02388 { 02389 WINE_WARN("size mismatch %u %u\n", 02390 dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)); 02391 dec_size = max(dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)); 02392 } 02393 02394 hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1)); 02395 hlpfile->phrases_buffer = HeapAlloc(GetProcessHeap(), 0, dec_size); 02396 if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer) 02397 { 02398 HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); 02399 HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); 02400 return FALSE; 02401 } 02402 02403 #define getbit() (ptr += (mask < 0), mask = mask*2 + (mask<=0), (*ptr & mask) != 0) 02404 02405 hlpfile->phrases_offsets[0] = 0; 02406 for (i = 0; i < num; i++) 02407 { 02408 for (n = 1; getbit(); n += 1 << bc); 02409 if (getbit()) n++; 02410 if (bc > 1 && getbit()) n += 2; 02411 if (bc > 2 && getbit()) n += 4; 02412 if (bc > 3 && getbit()) n += 8; 02413 if (bc > 4 && getbit()) n += 16; 02414 hlpfile->phrases_offsets[i + 1] = hlpfile->phrases_offsets[i] + n; 02415 } 02416 #undef getbit 02417 02418 if (dec_size == cpr_size) 02419 memcpy(hlpfile->phrases_buffer, buf_phs + 9, dec_size); 02420 else 02421 HLPFILE_UncompressLZ77(buf_phs + 9, end_phs, (BYTE*)hlpfile->phrases_buffer); 02422 02423 hlpfile->hasPhrases40 = TRUE; 02424 return TRUE; 02425 } 02426 02427 /*********************************************************************** 02428 * 02429 * HLPFILE_Uncompress_Topic 02430 */ 02431 static BOOL HLPFILE_Uncompress_Topic(HLPFILE* hlpfile) 02432 { 02433 BYTE *buf, *ptr, *end, *newptr; 02434 unsigned int i, newsize = 0; 02435 unsigned int topic_size; 02436 02437 if (!HLPFILE_FindSubFile(hlpfile, "|TOPIC", &buf, &end)) 02438 {WINE_WARN("topic0\n"); return FALSE;} 02439 02440 buf += 9; /* Skip file header */ 02441 topic_size = end - buf; 02442 if (hlpfile->compressed) 02443 { 02444 hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1; 02445 02446 for (i = 0; i < hlpfile->topic_maplen; i++) 02447 { 02448 ptr = buf + i * hlpfile->tbsize; 02449 02450 /* I don't know why, it's necessary for printman.hlp */ 02451 if (ptr + 0x44 > end) ptr = end - 0x44; 02452 02453 newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + hlpfile->tbsize)); 02454 } 02455 02456 hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0, 02457 hlpfile->topic_maplen * sizeof(hlpfile->topic_map[0]) + newsize); 02458 if (!hlpfile->topic_map) return FALSE; 02459 newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen); 02460 hlpfile->topic_end = newptr + newsize; 02461 02462 for (i = 0; i < hlpfile->topic_maplen; i++) 02463 { 02464 ptr = buf + i * hlpfile->tbsize; 02465 if (ptr + 0x44 > end) ptr = end - 0x44; 02466 02467 hlpfile->topic_map[i] = newptr; 02468 newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + hlpfile->tbsize), newptr); 02469 } 02470 } 02471 else 02472 { 02473 /* basically, we need to copy the TopicBlockSize byte pages 02474 * (removing the first 0x0C) in one single area in memory 02475 */ 02476 hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1; 02477 hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0, 02478 hlpfile->topic_maplen * (sizeof(hlpfile->topic_map[0]) + hlpfile->dsize)); 02479 if (!hlpfile->topic_map) return FALSE; 02480 newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen); 02481 hlpfile->topic_end = newptr + topic_size; 02482 02483 for (i = 0; i < hlpfile->topic_maplen; i++) 02484 { 02485 hlpfile->topic_map[i] = newptr + i * hlpfile->dsize; 02486 memcpy(hlpfile->topic_map[i], buf + i * hlpfile->tbsize + 0x0C, hlpfile->dsize); 02487 } 02488 } 02489 return TRUE; 02490 } 02491 02492 /*********************************************************************** 02493 * 02494 * HLPFILE_AddPage 02495 */ 02496 static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned ref, unsigned offset) 02497 { 02498 HLPFILE_PAGE* page; 02499 const BYTE* title; 02500 UINT titlesize, blocksize, datalen; 02501 char* ptr; 02502 HLPFILE_MACRO*macro; 02503 02504 blocksize = GET_UINT(buf, 0); 02505 datalen = GET_UINT(buf, 0x10); 02506 title = buf + datalen; 02507 if (title > end) {WINE_WARN("page2\n"); return FALSE;}; 02508 02509 titlesize = GET_UINT(buf, 4); 02510 page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize + 1); 02511 if (!page) return FALSE; 02512 page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE); 02513 02514 if (titlesize > blocksize - datalen) 02515 { 02516 /* need to decompress */ 02517 if (hlpfile->hasPhrases) 02518 HLPFILE_Uncompress2(hlpfile, title, end, (BYTE*)page->lpszTitle, (BYTE*)page->lpszTitle + titlesize); 02519 else if (hlpfile->hasPhrases40) 02520 HLPFILE_Uncompress3(hlpfile, page->lpszTitle, page->lpszTitle + titlesize, title, end); 02521 else 02522 { 02523 WINE_FIXME("Text size is too long, splitting\n"); 02524 titlesize = blocksize - datalen; 02525 memcpy(page->lpszTitle, title, titlesize); 02526 } 02527 } 02528 else 02529 memcpy(page->lpszTitle, title, titlesize); 02530 02531 page->lpszTitle[titlesize] = '\0'; 02532 02533 if (hlpfile->first_page) 02534 { 02535 hlpfile->last_page->next = page; 02536 page->prev = hlpfile->last_page; 02537 hlpfile->last_page = page; 02538 } 02539 else 02540 { 02541 hlpfile->first_page = page; 02542 hlpfile->last_page = page; 02543 page->prev = NULL; 02544 } 02545 02546 page->file = hlpfile; 02547 page->next = NULL; 02548 page->first_macro = NULL; 02549 page->first_link = NULL; 02550 page->wNumber = GET_UINT(buf, 0x21); 02551 page->offset = offset; 02552 page->reference = ref; 02553 02554 page->browse_bwd = GET_UINT(buf, 0x19); 02555 page->browse_fwd = GET_UINT(buf, 0x1D); 02556 02557 if (hlpfile->version <= 16) 02558 { 02559 if (page->browse_bwd == 0xFFFF || page->browse_bwd == 0xFFFFFFFF) 02560 page->browse_bwd = 0xFFFFFFFF; 02561 else 02562 page->browse_bwd = hlpfile->TOMap[page->browse_bwd]; 02563 02564 if (page->browse_fwd == 0xFFFF || page->browse_fwd == 0xFFFFFFFF) 02565 page->browse_fwd = 0xFFFFFFFF; 02566 else 02567 page->browse_fwd = hlpfile->TOMap[page->browse_fwd]; 02568 } 02569 02570 WINE_TRACE("Added page[%d]: title='%s' %08x << %08x >> %08x\n", 02571 page->wNumber, page->lpszTitle, 02572 page->browse_bwd, page->offset, page->browse_fwd); 02573 02574 /* now load macros */ 02575 ptr = page->lpszTitle + strlen(page->lpszTitle) + 1; 02576 while (ptr < page->lpszTitle + titlesize) 02577 { 02578 unsigned len = strlen(ptr); 02579 char* macro_str; 02580 02581 WINE_TRACE("macro: %s\n", ptr); 02582 macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + len + 1); 02583 macro->lpszMacro = macro_str = (char*)(macro + 1); 02584 memcpy(macro_str, ptr, len + 1); 02585 /* FIXME: shall we really link macro in reverse order ?? 02586 * may produce strange results when played at page opening 02587 */ 02588 macro->next = page->first_macro; 02589 page->first_macro = macro; 02590 ptr += len + 1; 02591 } 02592 02593 return TRUE; 02594 } 02595 02596 /*********************************************************************** 02597 * 02598 * HLPFILE_SkipParagraph 02599 */ 02600 static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned* len) 02601 { 02602 const BYTE *tmp; 02603 02604 if (!hlpfile->first_page) {WINE_WARN("no page\n"); return FALSE;}; 02605 if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;}; 02606 02607 tmp = buf + 0x15; 02608 if (buf[0x14] == 0x20 || buf[0x14] == 0x23) 02609 { 02610 fetch_long(&tmp); 02611 *len = fetch_ushort(&tmp); 02612 } 02613 else *len = end-buf-15; 02614 02615 return TRUE; 02616 } 02617 02618 /*********************************************************************** 02619 * 02620 * HLPFILE_DoReadHlpFile 02621 */ 02622 static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath) 02623 { 02624 BOOL ret; 02625 HFILE hFile; 02626 OFSTRUCT ofs; 02627 BYTE* buf; 02628 DWORD ref = 0x0C; 02629 unsigned index, old_index, offset, len, offs, topicoffset; 02630 02631 hFile = OpenFile(lpszPath, &ofs, OF_READ); 02632 if (hFile == HFILE_ERROR) return FALSE; 02633 02634 ret = HLPFILE_ReadFileToBuffer(hlpfile, hFile); 02635 _lclose(hFile); 02636 if (!ret) return FALSE; 02637 02638 if (!HLPFILE_SystemCommands(hlpfile)) return FALSE; 02639 02640 if (hlpfile->version <= 16 && !HLPFILE_GetTOMap(hlpfile)) return FALSE; 02641 02642 /* load phrases support */ 02643 if (!HLPFILE_UncompressLZ77_Phrases(hlpfile)) 02644 HLPFILE_Uncompress_Phrases40(hlpfile); 02645 02646 if (!HLPFILE_Uncompress_Topic(hlpfile)) return FALSE; 02647 if (!HLPFILE_ReadFont(hlpfile)) return FALSE; 02648 02649 buf = hlpfile->topic_map[0]; 02650 old_index = -1; 02651 offs = 0; 02652 do 02653 { 02654 BYTE* end; 02655 02656 if (hlpfile->version <= 16) 02657 { 02658 index = (ref - 0x0C) / hlpfile->dsize; 02659 offset = (ref - 0x0C) % hlpfile->dsize; 02660 } 02661 else 02662 { 02663 index = (ref - 0x0C) >> 14; 02664 offset = (ref - 0x0C) & 0x3FFF; 02665 } 02666 02667 if (hlpfile->version <= 16 && index != old_index && old_index != -1) 02668 { 02669 /* we jumped to the next block, adjust pointers */ 02670 ref -= 12; 02671 offset -= 12; 02672 } 02673 02674 WINE_TRACE("ref=%08x => [%u/%u]\n", ref, index, offset); 02675 02676 if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;} 02677 buf = hlpfile->topic_map[index] + offset; 02678 if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;} 02679 end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end); 02680 if (index != old_index) {offs = 0; old_index = index;} 02681 02682 switch (buf[0x14]) 02683 { 02684 case 0x02: 02685 if (hlpfile->version <= 16) 02686 topicoffset = ref + index * 12; 02687 else 02688 topicoffset = index * 0x8000 + offs; 02689 if (!HLPFILE_AddPage(hlpfile, buf, end, ref, topicoffset)) return FALSE; 02690 break; 02691 02692 case 0x01: 02693 case 0x20: 02694 case 0x23: 02695 if (!HLPFILE_SkipParagraph(hlpfile, buf, end, &len)) return FALSE; 02696 offs += len; 02697 break; 02698 02699 default: 02700 WINE_ERR("buf[0x14] = %x\n", buf[0x14]); 02701 } 02702 02703 if (hlpfile->version <= 16) 02704 { 02705 ref += GET_UINT(buf, 0xc); 02706 if (GET_UINT(buf, 0xc) == 0) 02707 break; 02708 } 02709 else 02710 ref = GET_UINT(buf, 0xc); 02711 } while (ref != 0xffffffff); 02712 02713 HLPFILE_GetKeywords(hlpfile); 02714 HLPFILE_GetMap(hlpfile); 02715 if (hlpfile->version <= 16) return TRUE; 02716 return HLPFILE_GetContext(hlpfile); 02717 } 02718 02719 /*********************************************************************** 02720 * 02721 * HLPFILE_ReadHlpFile 02722 */ 02723 HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath) 02724 { 02725 HLPFILE* hlpfile; 02726 02727 for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next) 02728 { 02729 if (!strcmp(lpszPath, hlpfile->lpszPath)) 02730 { 02731 hlpfile->wRefCount++; 02732 return hlpfile; 02733 } 02734 } 02735 02736 hlpfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 02737 sizeof(HLPFILE) + lstrlen(lpszPath) + 1); 02738 if (!hlpfile) return 0; 02739 02740 hlpfile->lpszPath = (char*)hlpfile + sizeof(HLPFILE); 02741 hlpfile->contents_start = 0xFFFFFFFF; 02742 hlpfile->next = first_hlpfile; 02743 hlpfile->wRefCount = 1; 02744 02745 strcpy(hlpfile->lpszPath, lpszPath); 02746 02747 first_hlpfile = hlpfile; 02748 if (hlpfile->next) hlpfile->next->prev = hlpfile; 02749 02750 if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath)) 02751 { 02752 HLPFILE_FreeHlpFile(hlpfile); 02753 hlpfile = 0; 02754 } 02755 02756 return hlpfile; 02757 } Generated on Fri May 25 2012 04:15:54 for ReactOS by
1.7.6.1
|