hlpfile.c
来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 2,066 行 · 第 1/5 页
C
2,066 行
/* * Help Viewer * * Copyright 1996 Ulrich Schmid * 2002 Eric Pouech * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */#include <stdarg.h>#include <stdio.h>#include <string.h>#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "winhelp.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(winhelp);static inline unsigned short GET_USHORT(const BYTE* buffer, unsigned i){ return (BYTE)buffer[i] + 0x100 * (BYTE)buffer[i + 1];}static inline short GET_SHORT(const BYTE* buffer, unsigned i){ return (BYTE)buffer[i] + 0x100 * (signed char)buffer[i+1];}static inline unsigned GET_UINT(const BYTE* buffer, unsigned i){ return GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i + 2);}static HLPFILE *first_hlpfile = 0;static BYTE *file_buffer;static struct{ UINT num; unsigned* offsets; char* buffer;} phrases;static struct{ BYTE** map; BYTE* end; UINT wMapLen;} topic;static struct{ UINT wFont; UINT wIndent; UINT wHSpace; UINT wVSpace; HLPFILE_LINK* link;} attributes;static BOOL HLPFILE_DoReadHlpFile(HLPFILE*, LPCSTR);static BOOL HLPFILE_ReadFileToBuffer(HFILE);static BOOL HLPFILE_FindSubFile(LPCSTR name, BYTE**, BYTE**);static BOOL HLPFILE_SystemCommands(HLPFILE*);static INT HLPFILE_UncompressedLZ77_Size(BYTE *ptr, BYTE *end);static BYTE* HLPFILE_UncompressLZ77(BYTE *ptr, BYTE *end, BYTE *newptr);static BOOL HLPFILE_UncompressLZ77_Phrases(HLPFILE*);static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE*);static BOOL HLPFILE_Uncompress_Topic(HLPFILE*);static BOOL HLPFILE_GetContext(HLPFILE*);static BOOL HLPFILE_GetMap(HLPFILE*);static BOOL HLPFILE_AddPage(HLPFILE*, BYTE*, BYTE*, unsigned);static BOOL HLPFILE_AddParagraph(HLPFILE*, BYTE *, BYTE*, unsigned*);static void HLPFILE_Uncompress2(const BYTE*, const BYTE*, BYTE*, const BYTE*);static BOOL HLPFILE_Uncompress3(char*, const char*, const BYTE*, const BYTE*);static void HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE** dst, unsigned dstsz);static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile);#if 0/*********************************************************************** * * HLPFILE_PageByNumber */static HLPFILE_PAGE *HLPFILE_PageByNumber(LPCSTR lpszPath, UINT wNum){ HLPFILE_PAGE *page; HLPFILE *hlpfile = HLPFILE_ReadHlpFile(lpszPath); if (!hlpfile) return 0; WINE_TRACE("[%s/%u]\n", lpszPath, wNum); for (page = hlpfile->first_page; page && wNum; page = page->next) wNum--; /* HLPFILE_FreeHlpFile(lpszPath); */ return page;}#endif/* FIXME: * this finds the page containing the offset. The offset can either * refer to the top of the page (offset == page->offset), or * to some paragraph inside the page... * As of today, we only return the page... we should also return * a paragraph, and then, while opening a new page, compute the * y-offset of the paragraph to be shown and scroll the window * accordinly *//****************************************************************** * HLPFILE_PageByOffset * * */HLPFILE_PAGE *HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset){ HLPFILE_PAGE* page; HLPFILE_PAGE* found; if (!hlpfile) return 0; WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, offset); if (offset == 0xFFFFFFFF) return NULL; page = NULL; for (found = NULL, page = hlpfile->first_page; page; page = page->next) { if (page->offset <= offset && (!found || found->offset < page->offset)) found = page; } if (!found) WINE_ERR("Page of offset %u not found in file %s\n", offset, hlpfile->lpszPath); return found;}/*********************************************************************** * * HLPFILE_HlpFilePageByHash */HLPFILE_PAGE *HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash){ int i; if (!hlpfile) return 0; WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lHash); for (i = 0; i < hlpfile->wContextLen; i++) { if (hlpfile->Context[i].lHash == lHash) return HLPFILE_PageByOffset(hlpfile, hlpfile->Context[i].offset); } WINE_ERR("Page of hash %x not found in file %s\n", lHash, hlpfile->lpszPath); return NULL;}/*********************************************************************** * * HLPFILE_PageByMap */HLPFILE_PAGE *HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap){ int i; if (!hlpfile) return 0; WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lMap); for (i = 0; i < hlpfile->wMapLen; i++) { if (hlpfile->Map[i].lMap == lMap) return HLPFILE_PageByOffset(hlpfile, hlpfile->Map[i].offset); } WINE_ERR("Page of Map %x not found in file %s\n", lMap, hlpfile->lpszPath); return NULL;}/*********************************************************************** * * HLPFILE_Contents */HLPFILE_PAGE* HLPFILE_Contents(HLPFILE *hlpfile){ HLPFILE_PAGE* page = NULL; if (!hlpfile) return NULL; page = HLPFILE_PageByOffset(hlpfile, hlpfile->contents_start); if (!page) page = hlpfile->first_page; return page;}/*********************************************************************** * * HLPFILE_Hash */LONG HLPFILE_Hash(LPCSTR lpszContext){ LONG lHash = 0; CHAR c; while ((c = *lpszContext++)) { CHAR x = 0; if (c >= 'A' && c <= 'Z') x = c - 'A' + 17; if (c >= 'a' && c <= 'z') x = c - 'a' + 17; if (c >= '1' && c <= '9') x = c - '0'; if (c == '0') x = 10; if (c == '.') x = 12; if (c == '_') x = 13; if (x) lHash = lHash * 43 + x; } return lHash;}/*********************************************************************** * * HLPFILE_ReadHlpFile */HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath){ HLPFILE* hlpfile; for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next) { if (!strcmp(lpszPath, hlpfile->lpszPath)) { hlpfile->wRefCount++; return hlpfile; } } hlpfile = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE) + lstrlen(lpszPath) + 1); if (!hlpfile) return 0; hlpfile->lpszPath = (char*)hlpfile + sizeof(HLPFILE); hlpfile->lpszTitle = NULL; hlpfile->lpszCopyright = NULL; hlpfile->first_page = NULL; hlpfile->first_macro = NULL; hlpfile->wContextLen = 0; hlpfile->Context = NULL; hlpfile->wMapLen = 0; hlpfile->Map = NULL; hlpfile->contents_start = 0xFFFFFFFF; hlpfile->prev = NULL; hlpfile->next = first_hlpfile; hlpfile->wRefCount = 1; hlpfile->numBmps = 0; hlpfile->bmps = NULL; hlpfile->numFonts = 0; hlpfile->fonts = NULL; hlpfile->numWindows = 0; hlpfile->windows = NULL; strcpy(hlpfile->lpszPath, lpszPath); first_hlpfile = hlpfile; if (hlpfile->next) hlpfile->next->prev = hlpfile; phrases.offsets = NULL; phrases.buffer = NULL; topic.map = NULL; topic.end = NULL; file_buffer = NULL; if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath)) { HLPFILE_FreeHlpFile(hlpfile); hlpfile = 0; } HeapFree(GetProcessHeap(), 0, phrases.offsets); HeapFree(GetProcessHeap(), 0, phrases.buffer); HeapFree(GetProcessHeap(), 0, topic.map); HeapFree(GetProcessHeap(), 0, file_buffer); return hlpfile;}/*********************************************************************** * * HLPFILE_DoReadHlpFile */static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath){ BOOL ret; HFILE hFile; OFSTRUCT ofs; BYTE* buf; DWORD ref = 0x0C; unsigned index, old_index, offset, len, offs; hFile = OpenFile(lpszPath, &ofs, OF_READ); if (hFile == HFILE_ERROR) return FALSE; ret = HLPFILE_ReadFileToBuffer(hFile); _lclose(hFile); if (!ret) return FALSE; if (!HLPFILE_SystemCommands(hlpfile)) return FALSE; /* load phrases support */ if (!HLPFILE_UncompressLZ77_Phrases(hlpfile)) HLPFILE_Uncompress_Phrases40(hlpfile); if (!HLPFILE_Uncompress_Topic(hlpfile)) return FALSE; if (!HLPFILE_ReadFont(hlpfile)) return FALSE; buf = topic.map[0]; old_index = -1; offs = 0; do { BYTE* end; /* FIXME this depends on the blocksize, can be 2k in some cases */ index = (ref - 0x0C) >> 14; offset = (ref - 0x0C) & 0x3fff; WINE_TRACE("ref=%08x => [%u/%u]\n", ref, index, offset); if (index >= topic.wMapLen) {WINE_WARN("maplen\n"); break;} buf = topic.map[index] + offset; if (buf + 0x15 >= topic.end) {WINE_WARN("extra\n"); break;} end = min(buf + GET_UINT(buf, 0), topic.end); if (index != old_index) {offs = 0; old_index = index;} switch (buf[0x14]) { case 0x02: if (!HLPFILE_AddPage(hlpfile, buf, end, index * 0x8000L + offs)) return FALSE; break; case 0x20: if (!HLPFILE_AddParagraph(hlpfile, buf, end, &len)) return FALSE; offs += len; break; case 0x23: if (!HLPFILE_AddParagraph(hlpfile, buf, end, &len)) return FALSE; offs += len; break; default: WINE_ERR("buf[0x14] = %x\n", buf[0x14]); } ref = GET_UINT(buf, 0xc); } while (ref != 0xffffffff); HLPFILE_GetMap(hlpfile); return HLPFILE_GetContext(hlpfile);}/*********************************************************************** * * HLPFILE_AddPage */static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigned offset){ HLPFILE_PAGE* page; BYTE* title; UINT titlesize; char* ptr; HLPFILE_MACRO*macro; if (buf + 0x31 > end) {WINE_WARN("page1\n"); return FALSE;}; title = buf + GET_UINT(buf, 0x10); if (title > end) {WINE_WARN("page2\n"); return FALSE;}; titlesize = GET_UINT(buf, 4); page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize + 1); if (!page) return FALSE; page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE); if (hlpfile->hasPhrases) { HLPFILE_Uncompress2(title, end, (BYTE*)page->lpszTitle, (BYTE*)page->lpszTitle + titlesize); } else { if (GET_UINT(buf, 0x4) > GET_UINT(buf, 0) - GET_UINT(buf, 0x10)) { /* need to decompress */ HLPFILE_Uncompress3(page->lpszTitle, page->lpszTitle + titlesize, title, end); } else { memcpy(page->lpszTitle, title, titlesize);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?