ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

chm.c
Go to the documentation of this file.
00001 /*
00002  * CHM Utility API
00003  *
00004  * Copyright 2005 James Hawkins
00005  * Copyright 2007 Jacek Caban
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include "hhctrl.h"
00023 
00024 #include "winreg.h"
00025 #include "shlwapi.h"
00026 #include "wine/debug.h"
00027 
00028 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
00029 
00030 #define BLOCK_BITS 12
00031 #define BLOCK_SIZE (1 << BLOCK_BITS)
00032 #define BLOCK_MASK (BLOCK_SIZE-1)
00033 
00034 /* Reads a string from the #STRINGS section in the CHM file */
00035 static LPCSTR GetChmString(CHMInfo *chm, DWORD offset)
00036 {
00037     LPCSTR str;
00038 
00039     if(!chm->strings_stream)
00040         return NULL;
00041 
00042     if(chm->strings_size <= (offset >> BLOCK_BITS)) {
00043         chm->strings_size = (offset >> BLOCK_BITS)+1;
00044         if(chm->strings)
00045             chm->strings = heap_realloc_zero(chm->strings,
00046                     chm->strings_size*sizeof(char*));
00047         else
00048             chm->strings = heap_alloc_zero(
00049                     chm->strings_size*sizeof(char*));
00050 
00051     }
00052 
00053     if(!chm->strings[offset >> BLOCK_BITS]) {
00054         LARGE_INTEGER pos;
00055         DWORD read;
00056         HRESULT hres;
00057 
00058         pos.QuadPart = offset & ~BLOCK_MASK;
00059         hres = IStream_Seek(chm->strings_stream, pos, STREAM_SEEK_SET, NULL);
00060         if(FAILED(hres)) {
00061             WARN("Seek failed: %08x\n", hres);
00062             return NULL;
00063         }
00064 
00065         chm->strings[offset >> BLOCK_BITS] = heap_alloc(BLOCK_SIZE);
00066 
00067         hres = IStream_Read(chm->strings_stream, chm->strings[offset >> BLOCK_BITS],
00068                             BLOCK_SIZE, &read);
00069         if(FAILED(hres)) {
00070             WARN("Read failed: %08x\n", hres);
00071             heap_free(chm->strings[offset >> BLOCK_BITS]);
00072             chm->strings[offset >> BLOCK_BITS] = NULL;
00073             return NULL;
00074         }
00075     }
00076 
00077     str = chm->strings[offset >> BLOCK_BITS] + (offset & BLOCK_MASK);
00078     TRACE("offset %#x => %s\n", offset, debugstr_a(str));
00079     return str;
00080 }
00081 
00082 static BOOL ReadChmSystem(CHMInfo *chm)
00083 {
00084     IStream *stream;
00085     DWORD ver=0xdeadbeef, read, buf_size;
00086     char *buf;
00087     HRESULT hres;
00088 
00089     struct {
00090         WORD code;
00091         WORD len;
00092     } entry;
00093 
00094     static const WCHAR wszSYSTEM[] = {'#','S','Y','S','T','E','M',0};
00095 
00096     hres = IStorage_OpenStream(chm->pStorage, wszSYSTEM, NULL, STGM_READ, 0, &stream);
00097     if(FAILED(hres)) {
00098         WARN("Could not open #SYSTEM stream: %08x\n", hres);
00099         return FALSE;
00100     }
00101 
00102     IStream_Read(stream, &ver, sizeof(ver), &read);
00103     TRACE("version is %x\n", ver);
00104 
00105     buf = heap_alloc(8*sizeof(DWORD));
00106     buf_size = 8*sizeof(DWORD);
00107 
00108     while(1) {
00109         hres = IStream_Read(stream, &entry, sizeof(entry), &read);
00110         if(hres != S_OK)
00111             break;
00112 
00113         if(entry.len > buf_size)
00114             buf = heap_realloc(buf, buf_size=entry.len);
00115 
00116         hres = IStream_Read(stream, buf, entry.len, &read);
00117         if(hres != S_OK)
00118             break;
00119 
00120         switch(entry.code) {
00121         case 0x0:
00122             TRACE("TOC is %s\n", debugstr_an(buf, entry.len));
00123             heap_free(chm->defToc);
00124             chm->defToc = strdupnAtoW(buf, entry.len);
00125             break;
00126         case 0x2:
00127             TRACE("Default topic is %s\n", debugstr_an(buf, entry.len));
00128             heap_free(chm->defTopic);
00129             chm->defTopic = strdupnAtoW(buf, entry.len);
00130             break;
00131         case 0x3:
00132             TRACE("Title is %s\n", debugstr_an(buf, entry.len));
00133             heap_free(chm->defTitle);
00134             chm->defTitle = strdupnAtoW(buf, entry.len);
00135             break;
00136         case 0x5:
00137             TRACE("Default window is %s\n", debugstr_an(buf, entry.len));
00138             break;
00139         case 0x6:
00140             TRACE("Compiled file is %s\n", debugstr_an(buf, entry.len));
00141             break;
00142         case 0x9:
00143             TRACE("Version is %s\n", debugstr_an(buf, entry.len));
00144             break;
00145         case 0xa:
00146             TRACE("Time is %08x\n", *(DWORD*)buf);
00147             break;
00148         case 0xc:
00149             TRACE("Number of info types: %d\n", *(DWORD*)buf);
00150             break;
00151         case 0xf:
00152             TRACE("Check sum: %x\n", *(DWORD*)buf);
00153             break;
00154         default:
00155             TRACE("unhandled code %x, size %x\n", entry.code, entry.len);
00156         }
00157     }
00158 
00159     heap_free(buf);
00160     IStream_Release(stream);
00161 
00162     return SUCCEEDED(hres);
00163 }
00164 
00165 LPWSTR FindContextAlias(CHMInfo *chm, DWORD index)
00166 {
00167     IStream *ivb_stream;
00168     DWORD size, read, i;
00169     DWORD *buf;
00170     LPCSTR ret = NULL;
00171     HRESULT hres;
00172 
00173     static const WCHAR wszIVB[] = {'#','I','V','B',0};
00174 
00175     hres = IStorage_OpenStream(chm->pStorage, wszIVB, NULL, STGM_READ, 0, &ivb_stream);
00176     if(FAILED(hres)) {
00177         WARN("Could not open #IVB stream: %08x\n", hres);
00178         return NULL;
00179     }
00180 
00181     hres = IStream_Read(ivb_stream, &size, sizeof(size), &read);
00182     if(FAILED(hres)) {
00183         WARN("Read failed: %08x\n", hres);
00184         IStream_Release(ivb_stream);
00185         return NULL;
00186     }
00187 
00188     buf = heap_alloc(size);
00189     hres = IStream_Read(ivb_stream, buf, size, &read);
00190     IStream_Release(ivb_stream);
00191     if(FAILED(hres)) {
00192         WARN("Read failed: %08x\n", hres);
00193         heap_free(buf);
00194         return NULL;
00195     }
00196 
00197     size /= 2*sizeof(DWORD);
00198 
00199     for(i=0; i<size; i++) {
00200         if(buf[2*i] == index) {
00201             ret = GetChmString(chm, buf[2*i+1]);
00202             break;
00203         }
00204     }
00205 
00206     heap_free(buf);
00207 
00208     TRACE("returning %s\n", debugstr_a(ret));
00209     return strdupAtoW(ret);
00210 }
00211 
00212 /* Loads the HH_WINTYPE data from the CHM file
00213  *
00214  * FIXME: There may be more than one window type in the file, so
00215  *        add the ability to choose a certain window type
00216  */
00217 BOOL LoadWinTypeFromCHM(HHInfo *info)
00218 {
00219     LARGE_INTEGER liOffset;
00220     IStorage *pStorage = info->pCHMInfo->pStorage;
00221     IStream *pStream;
00222     HRESULT hr;
00223     DWORD cbRead;
00224 
00225     static const WCHAR windowsW[] = {'#','W','I','N','D','O','W','S',0};
00226 
00227     hr = IStorage_OpenStream(pStorage, windowsW, NULL, STGM_READ, 0, &pStream);
00228     if (FAILED(hr))
00229     {
00230         /* no defined window types so use (hopefully) sane defaults */
00231         static const WCHAR defaultwinW[] = {'d','e','f','a','u','l','t','w','i','n','\0'};
00232         static const WCHAR null[] = {0};
00233         memset((void*)&(info->WinType), 0, sizeof(info->WinType));
00234         info->WinType.cbStruct=sizeof(info->WinType);
00235         info->WinType.fUniCodeStrings=TRUE;
00236         info->WinType.pszType=strdupW(defaultwinW);
00237         info->WinType.pszToc = strdupW(info->pCHMInfo->defToc ? info->pCHMInfo->defToc : null);
00238         info->WinType.pszIndex = strdupW(null);
00239         info->WinType.fsValidMembers=0;
00240         info->WinType.fsWinProperties=HHWIN_PROP_TRI_PANE;
00241         info->WinType.pszCaption=strdupW(info->pCHMInfo->defTitle ? info->pCHMInfo->defTitle : null);
00242         info->WinType.dwStyles=WS_POPUP;
00243         info->WinType.dwExStyles=0;
00244         info->WinType.nShowState=SW_SHOW;
00245         info->WinType.pszFile=strdupW(info->pCHMInfo->defTopic ? info->pCHMInfo->defTopic : null);
00246         info->WinType.curNavType=HHWIN_NAVTYPE_TOC;
00247         return TRUE;
00248     }
00249 
00250     /* jump past the #WINDOWS header */
00251     liOffset.QuadPart = sizeof(DWORD) * 2;
00252 
00253     hr = IStream_Seek(pStream, liOffset, STREAM_SEEK_SET, NULL);
00254     if (FAILED(hr)) goto done;
00255 
00256     /* read the HH_WINTYPE struct data */
00257     hr = IStream_Read(pStream, &info->WinType, sizeof(info->WinType), &cbRead);
00258     if (FAILED(hr)) goto done;
00259 
00260     /* convert the #STRINGS offsets to actual strings */
00261     info->WinType.pszType     = info->pszType     = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszType));
00262     info->WinType.pszCaption  = info->pszCaption  = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszCaption));
00263     info->WinType.pszToc      = info->pszToc      = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszToc));
00264     info->WinType.pszIndex    = info->pszIndex    = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszIndex));
00265     info->WinType.pszFile     = info->pszFile     = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszFile));
00266     info->WinType.pszHome     = info->pszHome     = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszHome));
00267     info->WinType.pszJump1    = info->pszJump1    = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszJump1));
00268     info->WinType.pszJump2    = info->pszJump2    = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszJump2));
00269     info->WinType.pszUrlJump1 = info->pszUrlJump1 = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszUrlJump1));
00270     info->WinType.pszUrlJump2 = info->pszUrlJump2 = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszUrlJump2));
00271 
00272     /* FIXME: pszCustomTabs is a list of multiple zero-terminated strings so ReadString won't
00273      * work in this case
00274      */
00275 #if 0
00276     info->WinType.pszCustomTabs = info->pszCustomTabs = CHM_ReadString(pChmInfo, (DWORD_PTR)info->WinType.pszCustomTabs);
00277 #endif
00278 
00279 done:
00280     IStream_Release(pStream);
00281 
00282     return SUCCEEDED(hr);
00283 }
00284 
00285 static LPCWSTR skip_schema(LPCWSTR url)
00286 {
00287     static const WCHAR its_schema[] = {'i','t','s',':'};
00288     static const WCHAR msits_schema[] = {'m','s','-','i','t','s',':'};
00289     static const WCHAR mk_schema[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':'};
00290 
00291     if(!strncmpiW(its_schema, url, sizeof(its_schema)/sizeof(WCHAR)))
00292         return url+sizeof(its_schema)/sizeof(WCHAR);
00293     if(!strncmpiW(msits_schema, url, sizeof(msits_schema)/sizeof(WCHAR)))
00294         return url+sizeof(msits_schema)/sizeof(WCHAR);
00295     if(!strncmpiW(mk_schema, url, sizeof(mk_schema)/sizeof(WCHAR)))
00296         return url+sizeof(mk_schema)/sizeof(WCHAR);
00297 
00298     return url;
00299 }
00300 
00301 void SetChmPath(ChmPath *file, LPCWSTR base_file, LPCWSTR path)
00302 {
00303     LPCWSTR ptr;
00304     static const WCHAR separatorW[] = {':',':',0};
00305 
00306     path = skip_schema(path);
00307 
00308     ptr = strstrW(path, separatorW);
00309     if(ptr) {
00310         WCHAR chm_file[MAX_PATH];
00311         WCHAR rel_path[MAX_PATH];
00312         WCHAR base_path[MAX_PATH];
00313         LPWSTR p;
00314 
00315         strcpyW(base_path, base_file);
00316         p = strrchrW(base_path, '\\');
00317         if(p)
00318             *p = 0;
00319 
00320         memcpy(rel_path, path, (ptr-path)*sizeof(WCHAR));
00321         rel_path[ptr-path] = 0;
00322 
00323         PathCombineW(chm_file, base_path, rel_path);
00324 
00325         file->chm_file = strdupW(chm_file);
00326         ptr += 2;
00327     }else {
00328         file->chm_file = strdupW(base_file);
00329         ptr = path;
00330     }
00331 
00332     file->chm_index = strdupW(ptr);
00333 
00334     TRACE("ChmFile = {%s %s}\n", debugstr_w(file->chm_file), debugstr_w(file->chm_index));
00335 }
00336 
00337 IStream *GetChmStream(CHMInfo *info, LPCWSTR parent_chm, ChmPath *chm_file)
00338 {
00339     IStorage *storage;
00340     IStream *stream = NULL;
00341     HRESULT hres;
00342 
00343     TRACE("%s (%s :: %s)\n", debugstr_w(parent_chm), debugstr_w(chm_file->chm_file),
00344           debugstr_w(chm_file->chm_index));
00345 
00346     if(parent_chm || chm_file->chm_file) {
00347         hres = IITStorage_StgOpenStorage(info->pITStorage,
00348                 chm_file->chm_file ? chm_file->chm_file : parent_chm, NULL,
00349                 STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &storage);
00350         if(FAILED(hres)) {
00351             WARN("Could not open storage: %08x\n", hres);
00352             return NULL;
00353         }
00354     }else {
00355         storage = info->pStorage;
00356         IStorage_AddRef(info->pStorage);
00357     }
00358 
00359     hres = IStorage_OpenStream(storage, chm_file->chm_index, NULL, STGM_READ, 0, &stream);
00360     IStorage_Release(storage);
00361     if(FAILED(hres))
00362         WARN("Could not open stream: %08x\n", hres);
00363 
00364     return stream;
00365 }
00366 
00367 /* Opens the CHM file for reading */
00368 CHMInfo *OpenCHM(LPCWSTR szFile)
00369 {
00370     HRESULT hres;
00371     CHMInfo *ret;
00372 
00373     static const WCHAR wszSTRINGS[] = {'#','S','T','R','I','N','G','S',0};
00374 
00375     if (!(ret = heap_alloc_zero(sizeof(CHMInfo))))
00376         return NULL;
00377 
00378     if (!(ret->szFile = strdupW(szFile))) {
00379         heap_free(ret);
00380         return NULL;
00381     }
00382 
00383     hres = CoCreateInstance(&CLSID_ITStorage, NULL, CLSCTX_INPROC_SERVER,
00384             &IID_IITStorage, (void **) &ret->pITStorage) ;
00385     if(FAILED(hres)) {
00386         WARN("Could not create ITStorage: %08x\n", hres);
00387         return CloseCHM(ret);
00388     }
00389 
00390     hres = IITStorage_StgOpenStorage(ret->pITStorage, szFile, NULL,
00391             STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &ret->pStorage);
00392     if(FAILED(hres)) {
00393         WARN("Could not open storage: %08x\n", hres);
00394         return CloseCHM(ret);
00395     }
00396     hres = IStorage_OpenStream(ret->pStorage, wszSTRINGS, NULL, STGM_READ, 0,
00397             &ret->strings_stream);
00398     if(FAILED(hres)) {
00399         WARN("Could not open #STRINGS stream: %08x\n", hres);
00400         /* It's not critical, so we pass */
00401     }
00402 
00403     if(!ReadChmSystem(ret)) {
00404         WARN("Could not read #SYSTEM\n");
00405         return CloseCHM(ret);
00406     }
00407 
00408     return ret;
00409 }
00410 
00411 CHMInfo *CloseCHM(CHMInfo *chm)
00412 {
00413     if(chm->pITStorage)
00414         IITStorage_Release(chm->pITStorage);
00415 
00416     if(chm->pStorage)
00417         IStorage_Release(chm->pStorage);
00418 
00419     if(chm->strings_stream)
00420         IStream_Release(chm->strings_stream);
00421 
00422     if(chm->strings_size) {
00423         DWORD i;
00424 
00425         for(i=0; i<chm->strings_size; i++)
00426             heap_free(chm->strings[i]);
00427     }
00428 
00429     heap_free(chm->strings);
00430     heap_free(chm->defTitle);
00431     heap_free(chm->defTopic);
00432     heap_free(chm->defToc);
00433     heap_free(chm->szFile);
00434     heap_free(chm);
00435 
00436     return NULL;
00437 }

Generated on Sat May 26 2012 04:22:22 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.