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 static BOOL
ReadChmSystem(CHMInfo
*chm
)
78 DWORD ver
=0xdeadbeef, read
, buf_size
;
87 static const WCHAR wszSYSTEM
[] = {'#','S','Y','S','T','E','M',0};
89 hres
= IStorage_OpenStream(chm
->pStorage
, wszSYSTEM
, NULL
, STGM_READ
, 0, &stream
);
91 WARN("Could not open #SYSTEM stream: %08x\n", hres
);
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
);
102 hres
= IStream_Read(stream
, &entry
, sizeof(entry
), &read
);
106 if(entry
.len
> buf_size
)
107 buf
= hhctrl_realloc(buf
, buf_size
=entry
.len
);
109 hres
= IStream_Read(stream
, buf
, entry
.len
, &read
);
115 TRACE("Default topic is %s\n", debugstr_an(buf
, entry
.len
));
118 TRACE("Title is %s\n", debugstr_an(buf
, entry
.len
));
121 TRACE("Default window is %s\n", debugstr_an(buf
, entry
.len
));
124 TRACE("Compiled file is %s\n", debugstr_an(buf
, entry
.len
));
127 TRACE("Version is %s\n", debugstr_an(buf
, entry
.len
));
130 TRACE("Time is %08x\n", *(DWORD
*)buf
);
133 TRACE("Number of info types: %d\n", *(DWORD
*)buf
);
136 TRACE("Check sum: %x\n", *(DWORD
*)buf
);
139 TRACE("unhandled code %x, size %x\n", entry
.code
, entry
.len
);
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
;
162 static const WCHAR windowsW
[] = {'#','W','I','N','D','O','W','S',0};
164 hr
= IStorage_OpenStream(pStorage
, windowsW
, NULL
, STGM_READ
, 0, &pStream
);
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
194 pHHWinType
->pszCustomTabs
= CHM_ReadString(pChmInfo
, (DWORD
)pHHWinType
->pszCustomTabs
);
198 IStream_Release(pStream
);
200 return SUCCEEDED(hr
);
203 /* Opens the CHM file for reading */
204 CHMInfo
*OpenCHM(LPCWSTR szFile
)
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
) ;
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
);
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
);
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
);
243 CHMInfo
*CloseCHM(CHMInfo
*chm
)
246 IITStorage_Release(chm
->pITStorage
);
249 IStorage_Release(chm
->pStorage
);
251 if(chm
->strings_stream
)
252 IStream_Release(chm
->strings_stream
);
254 if(chm
->strings_size
) {
257 for(i
=0; i
<chm
->strings_size
; i
++)
258 hhctrl_free(chm
->strings
[i
]);
261 hhctrl_free(chm
->strings
);