/* * CHM Utility API * * Copyright 2005 James Hawkins * * 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 "hhctrl.h" /* Reads a string from the #STRINGS section in the CHM file */ static LPWSTR CHM_ReadString(CHMInfo *pChmInfo, DWORD dwOffset) { LARGE_INTEGER liOffset; IStorage *pStorage = pChmInfo->pStorage; IStream *pStream; DWORD cbRead; ULONG iPos; DWORD dwSize; LPSTR szString; LPWSTR stringW; const int CB_READ_BLOCK = 64; static const WCHAR stringsW[] = {'#','S','T','R','I','N','G','S',0}; dwSize = CB_READ_BLOCK; szString = hhctrl_alloc(dwSize); if (FAILED(IStorage_OpenStream(pStorage, stringsW, NULL, STGM_READ, 0, &pStream))) return NULL; liOffset.QuadPart = dwOffset; if (FAILED(IStream_Seek(pStream, liOffset, STREAM_SEEK_SET, NULL))) { IStream_Release(pStream); return NULL; } while (SUCCEEDED(IStream_Read(pStream, szString, CB_READ_BLOCK, &cbRead))) { if (!cbRead) return NULL; for (iPos = 0; iPos < cbRead; iPos++) { if (!szString[iPos]) { stringW = strdupAtoW(szString); hhctrl_free(szString); return stringW; } } dwSize *= 2; szString = hhctrl_realloc(szString, dwSize); szString += cbRead; } /* didn't find a string */ return NULL; } /* Loads the HH_WINTYPE data from the CHM file * * FIXME: There may be more than one window type in the file, so * add the ability to choose a certain window type */ BOOL CHM_LoadWinTypeFromCHM(CHMInfo *pChmInfo, HH_WINTYPEW *pHHWinType) { LARGE_INTEGER liOffset; IStorage *pStorage = pChmInfo->pStorage; IStream *pStream; HRESULT hr; DWORD cbRead; static const WCHAR windowsW[] = {'#','W','I','N','D','O','W','S',0}; hr = IStorage_OpenStream(pStorage, windowsW, NULL, STGM_READ, 0, &pStream); if (FAILED(hr)) return FALSE; /* jump past the #WINDOWS header */ liOffset.QuadPart = sizeof(DWORD) * 2; hr = IStream_Seek(pStream, liOffset, STREAM_SEEK_SET, NULL); if (FAILED(hr)) goto done; /* read the HH_WINTYPE struct data */ hr = IStream_Read(pStream, pHHWinType, sizeof(*pHHWinType), &cbRead); if (FAILED(hr)) goto done; /* convert the #STRINGS offsets to actual strings */ pHHWinType->pszType = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszType); pHHWinType->pszCaption = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszCaption); pHHWinType->pszToc = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszToc); pHHWinType->pszIndex = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszIndex); pHHWinType->pszFile = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszFile); pHHWinType->pszHome = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszHome); pHHWinType->pszJump1 = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszJump1); pHHWinType->pszJump2 = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszJump2); pHHWinType->pszUrlJump1 = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszUrlJump1); pHHWinType->pszUrlJump2 = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszUrlJump2); /* FIXME: pszCustomTabs is a list of multiple zero-terminated strings so ReadString won't * work in this case */ #if 0 pHHWinType->pszCustomTabs = CHM_ReadString(pChmInfo, (DWORD)pHHWinType->pszCustomTabs); #endif done: IStream_Release(pStream); return SUCCEEDED(hr); } /* Opens the CHM file for reading */ BOOL CHM_OpenCHM(CHMInfo *pChmInfo, LPCWSTR szFile) { pChmInfo->szFile = szFile; if (FAILED(CoCreateInstance(&CLSID_ITStorage, NULL, CLSCTX_INPROC_SERVER, &IID_IITStorage, (void **) &pChmInfo->pITStorage))) return FALSE; if (FAILED(IITStorage_StgOpenStorage(pChmInfo->pITStorage, szFile, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &pChmInfo->pStorage))) return FALSE; return TRUE; } void CHM_CloseCHM(CHMInfo *pCHMInfo) { IITStorage_Release(pCHMInfo->pITStorage); IStorage_Release(pCHMInfo->pStorage); }