4 * Copyright 2005 James Hawkins
5 * Copyright 2007 Jacek Caban
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
29 #define BLOCK_SIZE (1 << BLOCK_BITS)
30 #define BLOCK_MASK (BLOCK_SIZE-1)
32 /* Reads a string from the #STRINGS section in the CHM file */
33 static LPCSTR GetChmString(CHMInfo *chm, DWORD offset)
35 if(!chm->strings_stream)
38 if(chm->strings_size <= (offset >> BLOCK_BITS)) {
40 chm->strings = hhctrl_realloc_zero(chm->strings,
41 chm->strings_size = ((offset >> BLOCK_BITS)+1)*sizeof(char*));
43 chm->strings = hhctrl_alloc_zero(
44 chm->strings_size = ((offset >> BLOCK_BITS)+1)*sizeof(char*));
48 if(!chm->strings[offset >> BLOCK_BITS]) {
53 pos.QuadPart = offset & ~BLOCK_MASK;
54 hres = IStream_Seek(chm->strings_stream, pos, STREAM_SEEK_SET, NULL);
56 WARN("Seek failed: %08x\n", hres);
60 chm->strings[offset >> BLOCK_BITS] = hhctrl_alloc(BLOCK_SIZE);
62 hres = IStream_Read(chm->strings_stream, chm->strings[offset >> BLOCK_BITS],
65 WARN("Read failed: %08x\n", hres);
66 hhctrl_free(chm->strings[offset >> BLOCK_BITS]);
67 chm->strings[offset >> BLOCK_BITS] = NULL;
72 return chm->strings[offset >> BLOCK_BITS] + (offset & BLOCK_MASK);
75 /* Loads the HH_WINTYPE data from the CHM file
77 * FIXME: There may be more than one window type in the file, so
78 * add the ability to choose a certain window type
80 BOOL CHM_LoadWinTypeFromCHM(CHMInfo *pChmInfo, HH_WINTYPEW *pHHWinType)
82 LARGE_INTEGER liOffset;
83 IStorage *pStorage = pChmInfo->pStorage;
88 static const WCHAR windowsW[] = {'#','W','I','N','D','O','W','S',0};
90 hr = IStorage_OpenStream(pStorage, windowsW, NULL, STGM_READ, 0, &pStream);
94 /* jump past the #WINDOWS header */
95 liOffset.QuadPart = sizeof(DWORD) * 2;
97 hr = IStream_Seek(pStream, liOffset, STREAM_SEEK_SET, NULL);
98 if (FAILED(hr)) goto done;
100 /* read the HH_WINTYPE struct data */
101 hr = IStream_Read(pStream, pHHWinType, sizeof(*pHHWinType), &cbRead);
102 if (FAILED(hr)) goto done;
104 /* convert the #STRINGS offsets to actual strings */
105 pHHWinType->pszType = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszType));
106 pHHWinType->pszCaption = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszCaption));
107 pHHWinType->pszToc = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszToc));
108 pHHWinType->pszIndex = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszIndex));
109 pHHWinType->pszFile = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszFile));
110 pHHWinType->pszHome = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszHome));
111 pHHWinType->pszJump1 = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszJump1));
112 pHHWinType->pszJump2 = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszJump2));
113 pHHWinType->pszUrlJump1 = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszUrlJump1));
114 pHHWinType->pszUrlJump2 = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszUrlJump2));
116 /* FIXME: pszCustomTabs is a list of multiple zero-terminated strings so ReadString won't
120 pHHWinType->pszCustomTabs = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszCustomTabs);
124 IStream_Release(pStream);
126 return SUCCEEDED(hr);
129 /* Opens the CHM file for reading */
130 CHMInfo *OpenCHM(LPCWSTR szFile)
134 static const WCHAR wszSTRINGS[] = {'#','S','T','R','I','N','G','S',0};
136 CHMInfo *ret = hhctrl_alloc_zero(sizeof(CHMInfo));
138 ret->szFile = szFile;
140 hres = CoCreateInstance(&CLSID_ITStorage, NULL, CLSCTX_INPROC_SERVER,
141 &IID_IITStorage, (void **) &ret->pITStorage) ;
143 WARN("Could not create ITStorage: %08x\n", hres);
144 return CloseCHM(ret);
147 hres = IITStorage_StgOpenStorage(ret->pITStorage, szFile, NULL,
148 STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &ret->pStorage);
150 WARN("Could not open storage: %08x\n", hres);
151 return CloseCHM(ret);
154 hres = IStorage_OpenStream(ret->pStorage, wszSTRINGS, NULL, STGM_READ, 0,
155 &ret->strings_stream);
157 WARN("Could not open #STRINGS stream: %08x\n", hres);
158 return CloseCHM(ret);
164 CHMInfo *CloseCHM(CHMInfo *chm)
167 IITStorage_Release(chm->pITStorage);
170 IStorage_Release(chm->pStorage);
172 if(chm->strings_stream)
173 IStream_Release(chm->strings_stream);
175 if(chm->strings_size) {
178 for(i=0; i<chm->strings_size; i++)
179 hhctrl_free(chm->strings[i]);
182 hhctrl_free(chm->strings);