hhctrl.ocx: Move more code from doWinMain.
[wine/multimedia.git] / dlls / hhctrl.ocx / chm.c
blob8e9fcf8ae9f16274fcca6218bc39094198d765ba
1 /*
2 * CHM Utility API
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
22 #include "hhctrl.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
28 #define BLOCK_BITS 12
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)
36 return NULL;
38 if(chm->strings_size <= (offset >> BLOCK_BITS)) {
39 if(chm->strings)
40 chm->strings = hhctrl_realloc_zero(chm->strings,
41 chm->strings_size = ((offset >> BLOCK_BITS)+1)*sizeof(char*));
42 else
43 chm->strings = hhctrl_alloc_zero(
44 chm->strings_size = ((offset >> BLOCK_BITS)+1)*sizeof(char*));
48 if(!chm->strings[offset >> BLOCK_BITS]) {
49 LARGE_INTEGER pos;
50 DWORD read;
51 HRESULT hres;
53 pos.QuadPart = offset & ~BLOCK_MASK;
54 hres = IStream_Seek(chm->strings_stream, pos, STREAM_SEEK_SET, NULL);
55 if(FAILED(hres)) {
56 WARN("Seek failed: %08x\n", hres);
57 return NULL;
60 chm->strings[offset >> BLOCK_BITS] = hhctrl_alloc(BLOCK_SIZE);
62 hres = IStream_Read(chm->strings_stream, chm->strings[offset >> BLOCK_BITS],
63 BLOCK_SIZE, &read);
64 if(FAILED(hres)) {
65 WARN("Read failed: %08x\n", hres);
66 hhctrl_free(chm->strings[offset >> BLOCK_BITS]);
67 chm->strings[offset >> BLOCK_BITS] = NULL;
68 return NULL;
72 return chm->strings[offset >> BLOCK_BITS] + (offset & BLOCK_MASK);
75 static BOOL ReadChmSystem(CHMInfo *chm)
77 IStream *stream;
78 DWORD ver=0xdeadbeef, read, buf_size;
79 char *buf;
80 HRESULT hres;
82 struct {
83 WORD code;
84 WORD len;
85 } entry;
87 static const WCHAR wszSYSTEM[] = {'#','S','Y','S','T','E','M',0};
89 hres = IStorage_OpenStream(chm->pStorage, wszSYSTEM, NULL, STGM_READ, 0, &stream);
90 if(FAILED(hres)) {
91 WARN("Could not open #SYSTEM stream: %08x\n", hres);
92 return FALSE;
95 IStream_Read(stream, &ver, sizeof(ver), &read);
96 TRACE("version is %x\n", ver);
98 buf = hhctrl_alloc(8*sizeof(DWORD));
99 buf_size = 8*sizeof(DWORD);
101 while(1) {
102 hres = IStream_Read(stream, &entry, sizeof(entry), &read);
103 if(hres != S_OK)
104 break;
106 if(entry.len > buf_size)
107 buf = hhctrl_realloc(buf, buf_size=entry.len);
109 hres = IStream_Read(stream, buf, entry.len, &read);
110 if(hres != S_OK)
111 break;
113 switch(entry.code) {
114 case 0x2:
115 TRACE("Default topic is %s\n", debugstr_an(buf, entry.len));
116 break;
117 case 0x3:
118 TRACE("Title is %s\n", debugstr_an(buf, entry.len));
119 break;
120 case 0x5:
121 TRACE("Default window is %s\n", debugstr_an(buf, entry.len));
122 break;
123 case 0x6:
124 TRACE("Compiled file is %s\n", debugstr_an(buf, entry.len));
125 break;
126 case 0x9:
127 TRACE("Version is %s\n", debugstr_an(buf, entry.len));
128 break;
129 case 0xa:
130 TRACE("Time is %08x\n", *(DWORD*)buf);
131 break;
132 case 0xc:
133 TRACE("Number of info types: %d\n", *(DWORD*)buf);
134 break;
135 case 0xf:
136 TRACE("Check sum: %x\n", *(DWORD*)buf);
137 break;
138 default:
139 TRACE("unhandled code %x, size %x\n", entry.code, entry.len);
143 hhctrl_free(buf);
144 IStream_Release(stream);
146 return SUCCEEDED(hres);
149 /* Loads the HH_WINTYPE data from the CHM file
151 * FIXME: There may be more than one window type in the file, so
152 * add the ability to choose a certain window type
154 BOOL LoadWinTypeFromCHM(CHMInfo *pChmInfo, HH_WINTYPEW *pHHWinType)
156 LARGE_INTEGER liOffset;
157 IStorage *pStorage = pChmInfo->pStorage;
158 IStream *pStream;
159 HRESULT hr;
160 DWORD cbRead;
162 static const WCHAR windowsW[] = {'#','W','I','N','D','O','W','S',0};
164 hr = IStorage_OpenStream(pStorage, windowsW, NULL, STGM_READ, 0, &pStream);
165 if (FAILED(hr))
166 return FALSE;
168 /* jump past the #WINDOWS header */
169 liOffset.QuadPart = sizeof(DWORD) * 2;
171 hr = IStream_Seek(pStream, liOffset, STREAM_SEEK_SET, NULL);
172 if (FAILED(hr)) goto done;
174 /* read the HH_WINTYPE struct data */
175 hr = IStream_Read(pStream, pHHWinType, sizeof(*pHHWinType), &cbRead);
176 if (FAILED(hr)) goto done;
178 /* convert the #STRINGS offsets to actual strings */
179 pHHWinType->pszType = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszType));
180 pHHWinType->pszCaption = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszCaption));
181 pHHWinType->pszToc = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszToc));
182 pHHWinType->pszIndex = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszIndex));
183 pHHWinType->pszFile = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszFile));
184 pHHWinType->pszHome = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszHome));
185 pHHWinType->pszJump1 = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszJump1));
186 pHHWinType->pszJump2 = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszJump2));
187 pHHWinType->pszUrlJump1 = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszUrlJump1));
188 pHHWinType->pszUrlJump2 = strdupAtoW(GetChmString(pChmInfo, (DWORD)pHHWinType->pszUrlJump2));
190 /* FIXME: pszCustomTabs is a list of multiple zero-terminated strings so ReadString won't
191 * work in this case
193 #if 0
194 pHHWinType->pszCustomTabs = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszCustomTabs);
195 #endif
197 done:
198 IStream_Release(pStream);
200 return SUCCEEDED(hr);
203 /* Opens the CHM file for reading */
204 CHMInfo *OpenCHM(LPCWSTR szFile)
206 HRESULT hres;
208 static const WCHAR wszSTRINGS[] = {'#','S','T','R','I','N','G','S',0};
210 CHMInfo *ret = hhctrl_alloc_zero(sizeof(CHMInfo));
212 ret->szFile = strdupW(szFile);
214 hres = CoCreateInstance(&CLSID_ITStorage, NULL, CLSCTX_INPROC_SERVER,
215 &IID_IITStorage, (void **) &ret->pITStorage) ;
216 if(FAILED(hres)) {
217 WARN("Could not create ITStorage: %08x\n", hres);
218 return CloseCHM(ret);
221 hres = IITStorage_StgOpenStorage(ret->pITStorage, szFile, NULL,
222 STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &ret->pStorage);
223 if(FAILED(hres)) {
224 WARN("Could not open storage: %08x\n", hres);
225 return CloseCHM(ret);
228 hres = IStorage_OpenStream(ret->pStorage, wszSTRINGS, NULL, STGM_READ, 0,
229 &ret->strings_stream);
230 if(FAILED(hres)) {
231 WARN("Could not open #STRINGS stream: %08x\n", hres);
232 return CloseCHM(ret);
235 if(!ReadChmSystem(ret)) {
236 WARN("Could not read #SYSTEM\n");
237 return CloseCHM(ret);
240 return ret;
243 CHMInfo *CloseCHM(CHMInfo *chm)
245 if(chm->pITStorage)
246 IITStorage_Release(chm->pITStorage);
248 if(chm->pStorage)
249 IStorage_Release(chm->pStorage);
251 if(chm->strings_stream)
252 IStream_Release(chm->strings_stream);
254 if(chm->strings_size) {
255 int i;
257 for(i=0; i<chm->strings_size; i++)
258 hhctrl_free(chm->strings[i]);
261 hhctrl_free(chm->strings);
262 hhctrl_free(chm);
264 return NULL;