Commit 5f6e3c88 authored by Alexandre Julliard's avatar Alexandre Julliard

Authors: Stewart Caie<kyz@uklinux.net>, Jed Wing <jedwin@ugcs.caltech.edu>, Mike…

Authors: Stewart Caie<kyz@uklinux.net>, Jed Wing <jedwin@ugcs.caltech.edu>, Mike McCormack <mike@codeweavers.com> Added an implemenation of ITSS.DLL.
parent 47c94c0e
......@@ -19955,7 +19955,7 @@ MAKE_LIB_RULES=libs/Makelib.rules
MAKE_PROG_RULES=programs/Makeprog.rules
ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/amstream/Makefile dlls/atl/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/capi2032/Makefile dlls/cards/Makefile dlls/cfgmgr32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3dim/Makefile dlls/d3drm/Makefile dlls/d3dx8/Makefile dlls/d3dxof/Makefile dlls/dbghelp/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/ddraw/tests/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnet/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/dswave/Makefile dlls/dxdiagn/Makefile dlls/dxerr8/Makefile dlls/dxerr9/Makefile dlls/dxguid/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/glut32/Makefile dlls/hhctrl.ocx/Makefile dlls/iccvid/Makefile dlls/icmp/Makefile dlls/ifsmgr.vxd/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/iphlpapi/tests/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mapi32/tests/Makefile dlls/mlang/Makefile dlls/mlang/tests/Makefile dlls/mmdevldr.vxd/Makefile dlls/monodebg.vxd/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msacm/tests/Makefile dlls/msdmo/Makefile dlls/mshtml/Makefile dlls/msi/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrt40/Makefile dlls/msvcrtd/Makefile dlls/msvcrtd/tests/Makefile dlls/msvidc32/Makefile dlls/msvideo/Makefile dlls/mswsock/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/newdev/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/ole32/tests/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/psapi/tests/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/quartz/tests/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/rsabase/Makefile dlls/rsabase/tests/Makefile dlls/secur32/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/strmiids/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/unicows/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/uuid/Makefile dlls/uxtheme/Makefile dlls/vdhcp.vxd/Makefile dlls/vdmdbg/Makefile dlls/version/Makefile dlls/version/tests/Makefile dlls/vmm.vxd/Makefile dlls/vnbt.vxd/Makefile dlls/vnetbios.vxd/Makefile dlls/vtdapi.vxd/Makefile dlls/vwin32.vxd/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/wined3d/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winejack/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile fonts/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/wine/Makefile libs/wpp/Makefile loader/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/msiexec/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/taskmgr/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winebrowser/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/amstream/Makefile dlls/atl/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/capi2032/Makefile dlls/cards/Makefile dlls/cfgmgr32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3dim/Makefile dlls/d3drm/Makefile dlls/d3dx8/Makefile dlls/d3dxof/Makefile dlls/dbghelp/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/ddraw/tests/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnet/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/dswave/Makefile dlls/dxdiagn/Makefile dlls/dxerr8/Makefile dlls/dxerr9/Makefile dlls/dxguid/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/glut32/Makefile dlls/hhctrl.ocx/Makefile dlls/iccvid/Makefile dlls/icmp/Makefile dlls/ifsmgr.vxd/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/iphlpapi/tests/Makefile dlls/itss/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mapi32/tests/Makefile dlls/mlang/Makefile dlls/mlang/tests/Makefile dlls/mmdevldr.vxd/Makefile dlls/monodebg.vxd/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msacm/tests/Makefile dlls/msdmo/Makefile dlls/mshtml/Makefile dlls/msi/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrt40/Makefile dlls/msvcrtd/Makefile dlls/msvcrtd/tests/Makefile dlls/msvidc32/Makefile dlls/msvideo/Makefile dlls/mswsock/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/newdev/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/ole32/tests/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/psapi/tests/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/quartz/tests/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/rsabase/Makefile dlls/rsabase/tests/Makefile dlls/secur32/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/strmiids/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/unicows/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/uuid/Makefile dlls/uxtheme/Makefile dlls/vdhcp.vxd/Makefile dlls/vdmdbg/Makefile dlls/version/Makefile dlls/version/tests/Makefile dlls/vmm.vxd/Makefile dlls/vnbt.vxd/Makefile dlls/vnetbios.vxd/Makefile dlls/vtdapi.vxd/Makefile dlls/vwin32.vxd/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/wined3d/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winejack/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile fonts/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/wine/Makefile libs/wpp/Makefile loader/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/msiexec/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/taskmgr/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winebrowser/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
cat >confcache <<\_ACEOF
......@@ -20555,6 +20555,7 @@ do
"dlls/imm32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/imm32/Makefile" ;;
"dlls/iphlpapi/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/iphlpapi/Makefile" ;;
"dlls/iphlpapi/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/iphlpapi/tests/Makefile" ;;
"dlls/itss/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/itss/Makefile" ;;
"dlls/kernel/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/kernel/Makefile" ;;
"dlls/kernel/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/kernel/tests/Makefile" ;;
"dlls/lzexpand/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/lzexpand/Makefile" ;;
......
......@@ -1576,6 +1576,7 @@ dlls/imagehlp/Makefile
dlls/imm32/Makefile
dlls/iphlpapi/Makefile
dlls/iphlpapi/tests/Makefile
dlls/itss/Makefile
dlls/kernel/Makefile
dlls/kernel/tests/Makefile
dlls/lzexpand/Makefile
......
......@@ -63,6 +63,7 @@ BASEDIRS = \
imagehlp \
imm32 \
iphlpapi \
itss \
kernel \
lzexpand \
mapi32 \
......@@ -287,6 +288,7 @@ SYMLINKS_SO = \
imagehlp.dll.so \
imm32.dll.so \
iphlpapi.dll.so \
itss.dll.so \
joystick.drv.so \
kernel32.dll.so \
libdxerr8.a \
......@@ -578,6 +580,9 @@ imm.dll.so : imm32.dll.so
iphlpapi.dll.so: iphlpapi/iphlpapi.dll.so
$(RM) $@ && $(LN_S) iphlpapi/iphlpapi.dll.so $@
itss.dll.so: itss/itss.dll.so
$(RM) $@ && $(LN_S) itss/itss.dll.so $@
joystick.drv.so: winmm/joystick/joystick.drv.so
$(RM) $@ && $(LN_S) winmm/joystick/joystick.drv.so $@
......@@ -1013,6 +1018,7 @@ IMPORT_LIBS = \
libimagehlp.$(IMPLIBEXT) \
libimm32.$(IMPLIBEXT) \
libiphlpapi.$(IMPLIBEXT) \
libitss.$(IMPLIBEXT) \
libkernel32.$(IMPLIBEXT) \
liblz32.$(IMPLIBEXT) \
libmapi32.$(IMPLIBEXT) \
......@@ -1348,6 +1354,11 @@ libiphlpapi.def: iphlpapi/iphlpapi.spec.def
libiphlpapi.a: iphlpapi/iphlpapi.spec.def
$(DLLTOOL) -k -l $@ -d iphlpapi/iphlpapi.spec.def
libitss.def: itss/itss.spec.def
$(RM) $@ && $(LN_S) itss/itss.spec.def $@
libitss.a: itss/itss.spec.def
$(DLLTOOL) -k -l $@ -d itss/itss.spec.def
libkernel32.def: kernel/kernel32.spec.def
$(RM) $@ && $(LN_S) kernel/kernel32.spec.def $@
libkernel32.a: kernel/kernel32.spec.def
......@@ -1759,6 +1770,7 @@ icmp/icmp.spec.def: $(WINEBUILD)
imagehlp/imagehlp.spec.def: $(WINEBUILD)
imm32/imm32.spec.def: $(WINEBUILD)
iphlpapi/iphlpapi.spec.def: $(WINEBUILD)
itss/itss.spec.def: $(WINEBUILD)
kernel/kernel32.spec.def: $(WINEBUILD)
lzexpand/lz32.spec.def: $(WINEBUILD)
mapi32/mapi32.spec.def: $(WINEBUILD)
......@@ -1891,6 +1903,7 @@ msacm/imaadp32/imaadp32.acm.so: msacm/imaadp32
imagehlp/imagehlp.dll.so: imagehlp
imm32/imm32.dll.so: imm32
iphlpapi/iphlpapi.dll.so: iphlpapi
itss/itss.dll.so: itss
winmm/joystick/joystick.drv.so: winmm/joystick
kernel/kernel32.dll.so: kernel
lzexpand/lz32.dll.so: lzexpand
......
Makefile
itss.dll.dbg.c
itss.spec.def
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = itss.dll
IMPORTS = ole32 user32 advapi32 kernel32 ntdll
EXTRALIBS = $(LIBUNICODE) -luuid
EXTRADEFS = -DCOM_NO_WINDOWS_H
C_SRCS = \
chm_lib.c \
lzx.c \
itss.c \
moniker.c \
storage.c
IDL_SRCS = \
itss.idl
@MAKE_DLL_RULES@
.SUFFIXES: .idl .h
.idl.h:
$(WIDL) $(IDLFLAGS) -b -h -H $@ $<
idl: $(IDL_SRCS:.idl=.h)
### Dependencies:
/* $Id$ */
/***************************************************************************
* chm_lib.c - CHM archive manipulation routines *
* ------------------- *
* *
* author: Jed Wing <jedwin@ugcs.caltech.edu> *
* version: 0.3 *
* notes: These routines are meant for the manipulation of microsoft *
* .chm (compiled html help) files, but may likely be used *
* for the manipulation of any ITSS archive, if ever ITSS *
* archives are used for any other purpose. *
* *
* Note also that the section names are statically handled. *
* To be entirely correct, the section names should be read *
* from the section names meta-file, and then the various *
* content sections and the "transforms" to apply to the data *
* they contain should be inferred from the section name and *
* the meta-files referenced using that name; however, all of *
* the files I've been able to get my hands on appear to have *
* only two sections: Uncompressed and MSCompressed. *
* Additionally, the ITSS.DLL file included with Windows does *
* not appear to handle any different transforms than the *
* simple LZX-transform. Furthermore, the list of transforms *
* to apply is broken, in that only half the required space *
* is allocated for the list. (It appears as though the *
* space is allocated for ASCII strings, but the strings are *
* written as unicode. As a result, only the first half of *
* the string appears.) So this is probably not too big of *
* a deal, at least until CHM v4 (MS .lit files), which also *
* incorporate encryption, of some description. *
* *
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
/***************************************************************************
* *
* Adapted for Wine by Mike McCormack *
* *
***************************************************************************/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wine/unicode.h"
#include "chm_lib.h"
#include "lzx.h"
#define CHM_ACQUIRE_LOCK(a) do { \
EnterCriticalSection(&(a)); \
} while(0)
#define CHM_RELEASE_LOCK(a) do { \
LeaveCriticalSection(&(a)); \
} while(0)
#define CHM_NULL_FD (INVALID_HANDLE_VALUE)
#define CHM_CLOSE_FILE(fd) CloseHandle((fd))
/*
* defines related to tuning
*/
#ifndef CHM_MAX_BLOCKS_CACHED
#define CHM_MAX_BLOCKS_CACHED 5
#endif
/*
* architecture specific defines
*
* Note: as soon as C99 is more widespread, the below defines should
* probably just use the C99 sized-int types.
*
* The following settings will probably work for many platforms. The sizes
* don't have to be exactly correct, but the types must accommodate at least as
* many bits as they specify.
*/
/* i386, 32-bit, Windows */
typedef BYTE UChar;
typedef SHORT Int16;
typedef USHORT UInt16;
typedef LONG Int32;
typedef DWORD UInt32;
typedef LONGLONG Int64;
typedef ULONGLONG UInt64;
/* utilities for unmarshalling data */
static int _unmarshal_char_array(unsigned char **pData,
unsigned long *pLenRemain,
char *dest,
int count)
{
if (count <= 0 || (unsigned int)count > *pLenRemain)
return 0;
memcpy(dest, (*pData), count);
*pData += count;
*pLenRemain -= count;
return 1;
}
static int _unmarshal_uchar_array(unsigned char **pData,
unsigned long *pLenRemain,
unsigned char *dest,
int count)
{
if (count <= 0 || (unsigned int)count > *pLenRemain)
return 0;
memcpy(dest, (*pData), count);
*pData += count;
*pLenRemain -= count;
return 1;
}
static int _unmarshal_int32(unsigned char **pData,
unsigned long *pLenRemain,
Int32 *dest)
{
if (4 > *pLenRemain)
return 0;
*dest = (*pData)[0] | (*pData)[1]<<8 | (*pData)[2]<<16 | (*pData)[3]<<24;
*pData += 4;
*pLenRemain -= 4;
return 1;
}
static int _unmarshal_uint32(unsigned char **pData,
unsigned long *pLenRemain,
UInt32 *dest)
{
if (4 > *pLenRemain)
return 0;
*dest = (*pData)[0] | (*pData)[1]<<8 | (*pData)[2]<<16 | (*pData)[3]<<24;
*pData += 4;
*pLenRemain -= 4;
return 1;
}
static int _unmarshal_int64(unsigned char **pData,
unsigned long *pLenRemain,
Int64 *dest)
{
Int64 temp;
int i;
if (8 > *pLenRemain)
return 0;
temp=0;
for(i=8; i>0; i--)
{
temp <<= 8;
temp |= (*pData)[i-1];
}
*dest = temp;
*pData += 8;
*pLenRemain -= 8;
return 1;
}
static int _unmarshal_uint64(unsigned char **pData,
unsigned long *pLenRemain,
UInt64 *dest)
{
UInt64 temp;
int i;
if (8 > *pLenRemain)
return 0;
temp=0;
for(i=8; i>0; i--)
{
temp <<= 8;
temp |= (*pData)[i-1];
}
*dest = temp;
*pData += 8;
*pLenRemain -= 8;
return 1;
}
static int _unmarshal_uuid(unsigned char **pData,
unsigned long *pDataLen,
unsigned char *dest)
{
return _unmarshal_uchar_array(pData, pDataLen, dest, 16);
}
/* names of sections essential to decompression */
static const WCHAR _CHMU_RESET_TABLE[] = {
':',':','D','a','t','a','S','p','a','c','e','/',
'S','t','o','r','a','g','e','/',
'M','S','C','o','m','p','r','e','s','s','e','d','/',
'T','r','a','n','s','f','o','r','m','/',
'{','7','F','C','2','8','9','4','0','-','9','D','3','1',
'-','1','1','D','0','-','9','B','2','7','-',
'0','0','A','0','C','9','1','E','9','C','7','C','}','/',
'I','n','s','t','a','n','c','e','D','a','t','a','/',
'R','e','s','e','t','T','a','b','l','e',0
};
static const WCHAR _CHMU_LZXC_CONTROLDATA[] = {
':',':','D','a','t','a','S','p','a','c','e','/',
'S','t','o','r','a','g','e','/',
'M','S','C','o','m','p','r','e','s','s','e','d','/',
'C','o','n','t','r','o','l','D','a','t','a',0
};
static const WCHAR _CHMU_CONTENT[] = {
':',':','D','a','t','a','S','p','a','c','e','/',
'S','t','o','r','a','g','e','/',
'M','S','C','o','m','p','r','e','s','s','e','d','/',
'C','o','n','t','e','n','t',0
};
static const WCHAR _CHMU_SPANINFO[] = {
':',':','D','a','t','a','S','p','a','c','e','/',
'S','t','o','r','a','g','e','/',
'M','S','C','o','m','p','r','e','s','s','e','d','/',
'S','p','a','n','I','n','f','o',
};
/*
* structures local to this module
*/
/* structure of ITSF headers */
#define _CHM_ITSF_V2_LEN (0x58)
#define _CHM_ITSF_V3_LEN (0x60)
struct chmItsfHeader
{
char signature[4]; /* 0 (ITSF) */
Int32 version; /* 4 */
Int32 header_len; /* 8 */
Int32 unknown_000c; /* c */
UInt32 last_modified; /* 10 */
UInt32 lang_id; /* 14 */
UChar dir_uuid[16]; /* 18 */
UChar stream_uuid[16]; /* 28 */
UInt64 unknown_offset; /* 38 */
UInt64 unknown_len; /* 40 */
UInt64 dir_offset; /* 48 */
UInt64 dir_len; /* 50 */
UInt64 data_offset; /* 58 (Not present before V3) */
}; /* __attribute__ ((aligned (1))); */
static int _unmarshal_itsf_header(unsigned char **pData,
unsigned long *pDataLen,
struct chmItsfHeader *dest)
{
/* we only know how to deal with the 0x58 and 0x60 byte structures */
if (*pDataLen != _CHM_ITSF_V2_LEN && *pDataLen != _CHM_ITSF_V3_LEN)
return 0;
/* unmarshal common fields */
_unmarshal_char_array(pData, pDataLen, dest->signature, 4);
_unmarshal_int32 (pData, pDataLen, &dest->version);
_unmarshal_int32 (pData, pDataLen, &dest->header_len);
_unmarshal_int32 (pData, pDataLen, &dest->unknown_000c);
_unmarshal_uint32 (pData, pDataLen, &dest->last_modified);
_unmarshal_uint32 (pData, pDataLen, &dest->lang_id);
_unmarshal_uuid (pData, pDataLen, dest->dir_uuid);
_unmarshal_uuid (pData, pDataLen, dest->stream_uuid);
_unmarshal_uint64 (pData, pDataLen, &dest->unknown_offset);
_unmarshal_uint64 (pData, pDataLen, &dest->unknown_len);
_unmarshal_uint64 (pData, pDataLen, &dest->dir_offset);
_unmarshal_uint64 (pData, pDataLen, &dest->dir_len);
/* error check the data */
/* XXX: should also check UUIDs, probably, though with a version 3 file,
* current MS tools do not seem to use them.
*/
if (memcmp(dest->signature, "ITSF", 4) != 0)
return 0;
if (dest->version == 2)
{
if (dest->header_len < _CHM_ITSF_V2_LEN)
return 0;
}
else if (dest->version == 3)
{
if (dest->header_len < _CHM_ITSF_V3_LEN)
return 0;
}
else
return 0;
/* now, if we have a V3 structure, unmarshal the rest.
* otherwise, compute it
*/
if (dest->version == 3)
{
if (*pDataLen != 0)
_unmarshal_uint64(pData, pDataLen, &dest->data_offset);
else
return 0;
}
else
dest->data_offset = dest->dir_offset + dest->dir_len;
return 1;
}
/* structure of ITSP headers */
#define _CHM_ITSP_V1_LEN (0x54)
struct chmItspHeader
{
char signature[4]; /* 0 (ITSP) */
Int32 version; /* 4 */
Int32 header_len; /* 8 */
Int32 unknown_000c; /* c */
UInt32 block_len; /* 10 */
Int32 blockidx_intvl; /* 14 */
Int32 index_depth; /* 18 */
Int32 index_root; /* 1c */
Int32 index_head; /* 20 */
Int32 unknown_0024; /* 24 */
UInt32 num_blocks; /* 28 */
Int32 unknown_002c; /* 2c */
UInt32 lang_id; /* 30 */
UChar system_uuid[16]; /* 34 */
UChar unknown_0044[16]; /* 44 */
}; /* __attribute__ ((aligned (1))); */
static int _unmarshal_itsp_header(unsigned char **pData,
unsigned long *pDataLen,
struct chmItspHeader *dest)
{
/* we only know how to deal with a 0x54 byte structures */
if (*pDataLen != _CHM_ITSP_V1_LEN)
return 0;
/* unmarshal fields */
_unmarshal_char_array(pData, pDataLen, dest->signature, 4);
_unmarshal_int32 (pData, pDataLen, &dest->version);
_unmarshal_int32 (pData, pDataLen, &dest->header_len);
_unmarshal_int32 (pData, pDataLen, &dest->unknown_000c);
_unmarshal_uint32 (pData, pDataLen, &dest->block_len);
_unmarshal_int32 (pData, pDataLen, &dest->blockidx_intvl);
_unmarshal_int32 (pData, pDataLen, &dest->index_depth);
_unmarshal_int32 (pData, pDataLen, &dest->index_root);
_unmarshal_int32 (pData, pDataLen, &dest->index_head);
_unmarshal_int32 (pData, pDataLen, &dest->unknown_0024);
_unmarshal_uint32 (pData, pDataLen, &dest->num_blocks);
_unmarshal_int32 (pData, pDataLen, &dest->unknown_002c);
_unmarshal_uint32 (pData, pDataLen, &dest->lang_id);
_unmarshal_uuid (pData, pDataLen, dest->system_uuid);
_unmarshal_uchar_array(pData, pDataLen, dest->unknown_0044, 16);
/* error check the data */
if (memcmp(dest->signature, "ITSP", 4) != 0)
return 0;
if (dest->version != 1)
return 0;
if (dest->header_len != _CHM_ITSP_V1_LEN)
return 0;
return 1;
}
/* structure of PMGL headers */
static const char _chm_pmgl_marker[4] = "PMGL";
#define _CHM_PMGL_LEN (0x14)
struct chmPmglHeader
{
char signature[4]; /* 0 (PMGL) */
UInt32 free_space; /* 4 */
UInt32 unknown_0008; /* 8 */
Int32 block_prev; /* c */
Int32 block_next; /* 10 */
}; /* __attribute__ ((aligned (1))); */
static int _unmarshal_pmgl_header(unsigned char **pData,
unsigned long *pDataLen,
struct chmPmglHeader *dest)
{
/* we only know how to deal with a 0x14 byte structures */
if (*pDataLen != _CHM_PMGL_LEN)
return 0;
/* unmarshal fields */
_unmarshal_char_array(pData, pDataLen, dest->signature, 4);
_unmarshal_uint32 (pData, pDataLen, &dest->free_space);
_unmarshal_uint32 (pData, pDataLen, &dest->unknown_0008);
_unmarshal_int32 (pData, pDataLen, &dest->block_prev);
_unmarshal_int32 (pData, pDataLen, &dest->block_next);
/* check structure */
if (memcmp(dest->signature, _chm_pmgl_marker, 4) != 0)
return 0;
return 1;
}
/* structure of PMGI headers */
static const char _chm_pmgi_marker[4] = "PMGI";
#define _CHM_PMGI_LEN (0x08)
struct chmPmgiHeader
{
char signature[4]; /* 0 (PMGI) */
UInt32 free_space; /* 4 */
}; /* __attribute__ ((aligned (1))); */
static int _unmarshal_pmgi_header(unsigned char **pData,
unsigned long *pDataLen,
struct chmPmgiHeader *dest)
{
/* we only know how to deal with a 0x8 byte structures */
if (*pDataLen != _CHM_PMGI_LEN)
return 0;
/* unmarshal fields */
_unmarshal_char_array(pData, pDataLen, dest->signature, 4);
_unmarshal_uint32 (pData, pDataLen, &dest->free_space);
/* check structure */
if (memcmp(dest->signature, _chm_pmgi_marker, 4) != 0)
return 0;
return 1;
}
/* structure of LZXC reset table */
#define _CHM_LZXC_RESETTABLE_V1_LEN (0x28)
struct chmLzxcResetTable
{
UInt32 version;
UInt32 block_count;
UInt32 unknown;
UInt32 table_offset;
UInt64 uncompressed_len;
UInt64 compressed_len;
UInt64 block_len;
}; /* __attribute__ ((aligned (1))); */
static int _unmarshal_lzxc_reset_table(unsigned char **pData,
unsigned long *pDataLen,
struct chmLzxcResetTable *dest)
{
/* we only know how to deal with a 0x28 byte structures */
if (*pDataLen != _CHM_LZXC_RESETTABLE_V1_LEN)
return 0;
/* unmarshal fields */
_unmarshal_uint32 (pData, pDataLen, &dest->version);
_unmarshal_uint32 (pData, pDataLen, &dest->block_count);
_unmarshal_uint32 (pData, pDataLen, &dest->unknown);
_unmarshal_uint32 (pData, pDataLen, &dest->table_offset);
_unmarshal_uint64 (pData, pDataLen, &dest->uncompressed_len);
_unmarshal_uint64 (pData, pDataLen, &dest->compressed_len);
_unmarshal_uint64 (pData, pDataLen, &dest->block_len);
/* check structure */
if (dest->version != 2)
return 0;
return 1;
}
/* structure of LZXC control data block */
#define _CHM_LZXC_MIN_LEN (0x18)
#define _CHM_LZXC_V2_LEN (0x1c)
struct chmLzxcControlData
{
UInt32 size; /* 0 */
char signature[4]; /* 4 (LZXC) */
UInt32 version; /* 8 */
UInt32 resetInterval; /* c */
UInt32 windowSize; /* 10 */
UInt32 windowsPerReset; /* 14 */
UInt32 unknown_18; /* 18 */
};
static int _unmarshal_lzxc_control_data(unsigned char **pData,
unsigned long *pDataLen,
struct chmLzxcControlData *dest)
{
/* we want at least 0x18 bytes */
if (*pDataLen < _CHM_LZXC_MIN_LEN)
return 0;
/* unmarshal fields */
_unmarshal_uint32 (pData, pDataLen, &dest->size);
_unmarshal_char_array(pData, pDataLen, dest->signature, 4);
_unmarshal_uint32 (pData, pDataLen, &dest->version);
_unmarshal_uint32 (pData, pDataLen, &dest->resetInterval);
_unmarshal_uint32 (pData, pDataLen, &dest->windowSize);
_unmarshal_uint32 (pData, pDataLen, &dest->windowsPerReset);
if (*pDataLen >= _CHM_LZXC_V2_LEN)
_unmarshal_uint32 (pData, pDataLen, &dest->unknown_18);
else
dest->unknown_18 = 0;
if (dest->version == 2)
{
dest->resetInterval *= 0x8000;
dest->windowSize *= 0x8000;
}
if (dest->windowSize == 0 || dest->resetInterval == 0)
return 0;
/* for now, only support resetInterval a multiple of windowSize/2 */
if (dest->windowSize == 1)
return 0;
if ((dest->resetInterval % (dest->windowSize/2)) != 0)
return 0;
/* check structure */
if (memcmp(dest->signature, "LZXC", 4) != 0)
return 0;
return 1;
}
/* the structure used for chm file handles */
struct chmFile
{
HANDLE fd;
CRITICAL_SECTION mutex;
CRITICAL_SECTION lzx_mutex;
CRITICAL_SECTION cache_mutex;
UInt64 dir_offset;
UInt64 dir_len;
UInt64 data_offset;
Int32 index_root;
Int32 index_head;
UInt32 block_len;
UInt64 span;
struct chmUnitInfo rt_unit;
struct chmUnitInfo cn_unit;
struct chmLzxcResetTable reset_table;
/* LZX control data */
int compression_enabled;
UInt32 window_size;
UInt32 reset_interval;
UInt32 reset_blkcount;
/* decompressor state */
struct LZXstate *lzx_state;
int lzx_last_block;
/* cache for decompressed blocks */
UChar **cache_blocks;
Int64 *cache_block_indices;
Int32 cache_num_blocks;
};
/*
* utility functions local to this module
*/
/* utility function to handle differences between {pread,read}(64)? */
static Int64 _chm_fetch_bytes(struct chmFile *h,
UChar *buf,
UInt64 os,
Int64 len)
{
Int64 readLen=0;
if (h->fd == CHM_NULL_FD)
return readLen;
CHM_ACQUIRE_LOCK(h->mutex);
/* NOTE: this might be better done with CreateFileMapping, et cetera... */
{
DWORD origOffsetLo=0, origOffsetHi=0;
DWORD offsetLo, offsetHi;
DWORD actualLen=0;
/* awkward Win32 Seek/Tell */
offsetLo = (unsigned long)(os & 0xffffffffL);
offsetHi = (unsigned long)((os >> 32) & 0xffffffffL);
origOffsetLo = SetFilePointer(h->fd, 0, &origOffsetHi, FILE_CURRENT);
offsetLo = SetFilePointer(h->fd, offsetLo, &offsetHi, FILE_BEGIN);
/* read the data */
if (ReadFile(h->fd,
buf,
(DWORD)len,
&actualLen,
NULL) == TRUE)
readLen = actualLen;
else
readLen = 0;
/* restore original position */
SetFilePointer(h->fd, origOffsetLo, &origOffsetHi, FILE_BEGIN);
}
CHM_RELEASE_LOCK(h->mutex);
return readLen;
}
/* open an ITS archive */
struct chmFile *chm_openW(const WCHAR *filename)
{
unsigned char sbuffer[256];
unsigned long sremain;
unsigned char *sbufpos;
struct chmFile *newHandle=NULL;
struct chmItsfHeader itsfHeader;
struct chmItspHeader itspHeader;
#if 0
struct chmUnitInfo uiSpan;
#endif
struct chmUnitInfo uiLzxc;
struct chmLzxcControlData ctlData;
/* allocate handle */
newHandle = (struct chmFile *)malloc(sizeof(struct chmFile));
newHandle->fd = CHM_NULL_FD;
newHandle->lzx_state = NULL;
newHandle->cache_blocks = NULL;
newHandle->cache_block_indices = NULL;
newHandle->cache_num_blocks = 0;
/* open file */
if ((newHandle->fd=CreateFileW(filename,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL)) == CHM_NULL_FD)
{
free(newHandle);
return NULL;
}
/* initialize mutexes, if needed */
InitializeCriticalSection(&newHandle->mutex);
InitializeCriticalSection(&newHandle->lzx_mutex);
InitializeCriticalSection(&newHandle->cache_mutex);
/* read and verify header */
sremain = _CHM_ITSF_V3_LEN;
sbufpos = sbuffer;
if (_chm_fetch_bytes(newHandle, sbuffer, (UInt64)0, sremain) != sremain ||
!_unmarshal_itsf_header(&sbufpos, &sremain, &itsfHeader))
{
chm_close(newHandle);
return NULL;
}
/* stash important values from header */
newHandle->dir_offset = itsfHeader.dir_offset;
newHandle->dir_len = itsfHeader.dir_len;
newHandle->data_offset = itsfHeader.data_offset;
/* now, read and verify the directory header chunk */
sremain = _CHM_ITSP_V1_LEN;
sbufpos = sbuffer;
if (_chm_fetch_bytes(newHandle, sbuffer,
(UInt64)itsfHeader.dir_offset, sremain) != sremain ||
!_unmarshal_itsp_header(&sbufpos, &sremain, &itspHeader))
{
chm_close(newHandle);
return NULL;
}
/* grab essential information from ITSP header */
newHandle->dir_offset += itspHeader.header_len;
newHandle->dir_len -= itspHeader.header_len;
newHandle->index_root = itspHeader.index_root;
newHandle->index_head = itspHeader.index_head;
newHandle->block_len = itspHeader.block_len;
/* if the index root is -1, this means we don't have any PMGI blocks.
* as a result, we must use the sole PMGL block as the index root
*/
if (newHandle->index_root == -1)
newHandle->index_root = newHandle->index_head;
/* By default, compression is enabled. */
newHandle->compression_enabled = 1;
/* Jed, Sun Jun 27: 'span' doesn't seem to be used anywhere?! */
#if 0
/* fetch span */
if (CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,
_CHMU_SPANINFO,
&uiSpan) ||
uiSpan.space == CHM_COMPRESSED)
{
chm_close(newHandle);
return NULL;
}
/* N.B.: we've already checked that uiSpan is in the uncompressed section,
* so this should not require attempting to decompress, which may
* rely on having a valid "span"
*/
sremain = 8;
sbufpos = sbuffer;
if (chm_retrieve_object(newHandle, &uiSpan, sbuffer,
0, sremain) != sremain ||
!_unmarshal_uint64(&sbufpos, &sremain, &newHandle->span))
{
chm_close(newHandle);
return NULL;
}
#endif
/* prefetch most commonly needed unit infos */
if (CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,
_CHMU_RESET_TABLE,
&newHandle->rt_unit) ||
newHandle->rt_unit.space == CHM_COMPRESSED ||
CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,
_CHMU_CONTENT,
&newHandle->cn_unit) ||
newHandle->cn_unit.space == CHM_COMPRESSED ||
CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,
_CHMU_LZXC_CONTROLDATA,
&uiLzxc) ||
uiLzxc.space == CHM_COMPRESSED)
{
newHandle->compression_enabled = 0;
}
/* read reset table info */
if (newHandle->compression_enabled)
{
sremain = _CHM_LZXC_RESETTABLE_V1_LEN;
sbufpos = sbuffer;
if (chm_retrieve_object(newHandle, &newHandle->rt_unit, sbuffer,
0, sremain) != sremain ||
!_unmarshal_lzxc_reset_table(&sbufpos, &sremain,
&newHandle->reset_table))
{
newHandle->compression_enabled = 0;
}
}
/* read control data */
if (newHandle->compression_enabled)
{
sremain = (unsigned long)uiLzxc.length;
sbufpos = sbuffer;
if (chm_retrieve_object(newHandle, &uiLzxc, sbuffer,
0, sremain) != sremain ||
!_unmarshal_lzxc_control_data(&sbufpos, &sremain,
&ctlData))
{
newHandle->compression_enabled = 0;
}
newHandle->window_size = ctlData.windowSize;
newHandle->reset_interval = ctlData.resetInterval;
/* Jed, Mon Jun 28: Experimentally, it appears that the reset block count */
/* must be multiplied by this formerly unknown ctrl data field in */
/* order to decompress some files. */
#if 0
newHandle->reset_blkcount = newHandle->reset_interval /
(newHandle->window_size / 2);
#else
newHandle->reset_blkcount = newHandle->reset_interval /
(newHandle->window_size / 2) *
ctlData.windowsPerReset;
#endif
}
/* initialize cache */
chm_set_param(newHandle, CHM_PARAM_MAX_BLOCKS_CACHED,
CHM_MAX_BLOCKS_CACHED);
return newHandle;
}
/* close an ITS archive */
void chm_close(struct chmFile *h)
{
if (h != NULL)
{
if (h->fd != CHM_NULL_FD)
CHM_CLOSE_FILE(h->fd);
h->fd = CHM_NULL_FD;
DeleteCriticalSection(&h->mutex);
DeleteCriticalSection(&h->lzx_mutex);
DeleteCriticalSection(&h->cache_mutex);
if (h->lzx_state)
LZXteardown(h->lzx_state);
h->lzx_state = NULL;
if (h->cache_blocks)
{
int i;
for (i=0; i<h->cache_num_blocks; i++)
{
if (h->cache_blocks[i])
free(h->cache_blocks[i]);
}
free(h->cache_blocks);
h->cache_blocks = NULL;
}
if (h->cache_block_indices)
free(h->cache_block_indices);
h->cache_block_indices = NULL;
free(h);
}
}
/*
* set a parameter on the file handle.
* valid parameter types:
* CHM_PARAM_MAX_BLOCKS_CACHED:
* how many decompressed blocks should be cached? A simple
* caching scheme is used, wherein the index of the block is
* used as a hash value, and hash collision results in the
* invalidation of the previously cached block.
*/
void chm_set_param(struct chmFile *h,
int paramType,
int paramVal)
{
switch (paramType)
{
case CHM_PARAM_MAX_BLOCKS_CACHED:
CHM_ACQUIRE_LOCK(h->cache_mutex);
if (paramVal != h->cache_num_blocks)
{
UChar **newBlocks;
UInt64 *newIndices;
int i;
/* allocate new cached blocks */
newBlocks = (UChar **)malloc(paramVal * sizeof (UChar *));
newIndices = (UInt64 *)malloc(paramVal * sizeof (UInt64));
for (i=0; i<paramVal; i++)
{
newBlocks[i] = NULL;
newIndices[i] = 0;
}
/* re-distribute old cached blocks */
if (h->cache_blocks)
{
for (i=0; i<h->cache_num_blocks; i++)
{
int newSlot = (int)(h->cache_block_indices[i] % paramVal);
if (h->cache_blocks[i])
{
/* in case of collision, destroy newcomer */
if (newBlocks[newSlot])
{
free(h->cache_blocks[i]);
h->cache_blocks[i] = NULL;
}
else
{
newBlocks[newSlot] = h->cache_blocks[i];
newIndices[newSlot] =
h->cache_block_indices[i];
}
}
}
free(h->cache_blocks);
free(h->cache_block_indices);
}
/* now, set new values */
h->cache_blocks = newBlocks;
h->cache_block_indices = newIndices;
h->cache_num_blocks = paramVal;
}
CHM_RELEASE_LOCK(h->cache_mutex);
break;
default:
break;
}
}
/*
* helper methods for chm_resolve_object
*/
/* skip a compressed dword */
static void _chm_skip_cword(UChar **pEntry)
{
while (*(*pEntry)++ >= 0x80)
;
}
/* skip the data from a PMGL entry */
static void _chm_skip_PMGL_entry_data(UChar **pEntry)
{
_chm_skip_cword(pEntry);
_chm_skip_cword(pEntry);
_chm_skip_cword(pEntry);
}
/* parse a compressed dword */
static UInt64 _chm_parse_cword(UChar **pEntry)
{
UInt64 accum = 0;
UChar temp;
while ((temp=*(*pEntry)++) >= 0x80)
{
accum <<= 7;
accum += temp & 0x7f;
}
return (accum << 7) + temp;
}
/* parse a utf-8 string into an ASCII char buffer */
static int _chm_parse_UTF8(UChar **pEntry, UInt64 count, WCHAR *path)
{
/* MJM - Modified to return real Unicode strings */
while (count != 0)
{
*path++ = (*(*pEntry)++);
--count;
}
*path = '\0';
return 1;
}
/* parse a PMGL entry into a chmUnitInfo struct; return 1 on success. */
static int _chm_parse_PMGL_entry(UChar **pEntry, struct chmUnitInfo *ui)
{
UInt64 strLen;
/* parse str len */
strLen = _chm_parse_cword(pEntry);
if (strLen > CHM_MAX_PATHLEN)
return 0;
/* parse path */
if (! _chm_parse_UTF8(pEntry, strLen, ui->path))
return 0;
/* parse info */
ui->space = (int)_chm_parse_cword(pEntry);
ui->start = _chm_parse_cword(pEntry);
ui->length = _chm_parse_cword(pEntry);
return 1;
}
/* find an exact entry in PMGL; return NULL if we fail */
static UChar *_chm_find_in_PMGL(UChar *page_buf,
UInt32 block_len,
const WCHAR *objPath)
{
/* XXX: modify this to do a binary search using the nice index structure
* that is provided for us.
*/
struct chmPmglHeader header;
UInt32 hremain;
UChar *end;
UChar *cur;
UChar *temp;
UInt64 strLen;
WCHAR buffer[CHM_MAX_PATHLEN+1];
/* figure out where to start and end */
cur = page_buf;
hremain = _CHM_PMGL_LEN;
if (! _unmarshal_pmgl_header(&cur, &hremain, &header))
return NULL;
end = page_buf + block_len - (header.free_space);
/* now, scan progressively */
while (cur < end)
{
/* grab the name */
temp = cur;
strLen = _chm_parse_cword(&cur);
if (! _chm_parse_UTF8(&cur, strLen, buffer))
return NULL;
/* check if it is the right name */
if (! strcmpiW(buffer, objPath))
return temp;
_chm_skip_PMGL_entry_data(&cur);
}
return NULL;
}
/* find which block should be searched next for the entry; -1 if no block */
static Int32 _chm_find_in_PMGI(UChar *page_buf,
UInt32 block_len,
const WCHAR *objPath)
{
/* XXX: modify this to do a binary search using the nice index structure
* that is provided for us
*/
struct chmPmgiHeader header;
UInt32 hremain;
int page=-1;
UChar *end;
UChar *cur;
UInt64 strLen;
WCHAR buffer[CHM_MAX_PATHLEN+1];
/* figure out where to start and end */
cur = page_buf;
hremain = _CHM_PMGI_LEN;
if (! _unmarshal_pmgi_header(&cur, &hremain, &header))
return -1;
end = page_buf + block_len - (header.free_space);
/* now, scan progressively */
while (cur < end)
{
/* grab the name */
strLen = _chm_parse_cword(&cur);
if (! _chm_parse_UTF8(&cur, strLen, buffer))
return -1;
/* check if it is the right name */
if (strcmpiW(buffer, objPath) > 0)
return page;
/* load next value for path */
page = (int)_chm_parse_cword(&cur);
}
return page;
}
/* resolve a particular object from the archive */
int chm_resolve_object(struct chmFile *h,
const WCHAR *objPath,
struct chmUnitInfo *ui)
{
/*
* XXX: implement caching scheme for dir pages
*/
Int32 curPage;
/* buffer to hold whatever page we're looking at */
UChar *page_buf = HeapAlloc(GetProcessHeap(), 0, h->block_len);
/* starting page */
curPage = h->index_root;
/* until we have either returned or given up */
while (curPage != -1)
{
/* try to fetch the index page */
if (_chm_fetch_bytes(h, page_buf,
(UInt64)h->dir_offset + (UInt64)curPage*h->block_len,
h->block_len) != h->block_len)
{
HeapFree(GetProcessHeap(), 0, page_buf);
return CHM_RESOLVE_FAILURE;
}
/* now, if it is a leaf node: */
if (memcmp(page_buf, _chm_pmgl_marker, 4) == 0)
{
/* scan block */
UChar *pEntry = _chm_find_in_PMGL(page_buf,
h->block_len,
objPath);
if (pEntry == NULL)
{
HeapFree(GetProcessHeap(), 0, page_buf);
return CHM_RESOLVE_FAILURE;
}
/* parse entry and return */
_chm_parse_PMGL_entry(&pEntry, ui);
HeapFree(GetProcessHeap(), 0, page_buf);
return CHM_RESOLVE_SUCCESS;
}
/* else, if it is a branch node: */
else if (memcmp(page_buf, _chm_pmgi_marker, 4) == 0)
curPage = _chm_find_in_PMGI(page_buf, h->block_len, objPath);
/* else, we are confused. give up. */
else
{
HeapFree(GetProcessHeap(), 0, page_buf);
return CHM_RESOLVE_FAILURE;
}
}
/* didn't find anything. fail. */
HeapFree(GetProcessHeap(), 0, page_buf);
return CHM_RESOLVE_FAILURE;
}
/*
* utility methods for dealing with compressed data
*/
/* get the bounds of a compressed block. return 0 on failure */
static int _chm_get_cmpblock_bounds(struct chmFile *h,
UInt64 block,
UInt64 *start,
Int64 *len)
{
UChar buffer[8], *dummy;
UInt32 remain;
/* for all but the last block, use the reset table */
if (block < h->reset_table.block_count-1)
{
/* unpack the start address */
dummy = buffer;
remain = 8;
if (_chm_fetch_bytes(h, buffer,
(UInt64)h->data_offset
+ (UInt64)h->rt_unit.start
+ (UInt64)h->reset_table.table_offset
+ (UInt64)block*8,
remain) != remain ||
!_unmarshal_uint64(&dummy, &remain, start))
return 0;
/* unpack the end address */
dummy = buffer;
remain = 8;
if (_chm_fetch_bytes(h, buffer,
(UInt64)h->data_offset
+ (UInt64)h->rt_unit.start
+ (UInt64)h->reset_table.table_offset
+ (UInt64)block*8 + 8,
remain) != remain ||
!_unmarshal_int64(&dummy, &remain, len))
return 0;
}
/* for the last block, use the span in addition to the reset table */
else
{
/* unpack the start address */
dummy = buffer;
remain = 8;
if (_chm_fetch_bytes(h, buffer,
(UInt64)h->data_offset
+ (UInt64)h->rt_unit.start
+ (UInt64)h->reset_table.table_offset
+ (UInt64)block*8,
remain) != remain ||
!_unmarshal_uint64(&dummy, &remain, start))
return 0;
*len = h->reset_table.compressed_len;
}
/* compute the length and absolute start address */
*len -= *start;
*start += h->data_offset + h->cn_unit.start;
return 1;
}
/* decompress the block. must have lzx_mutex. */
static Int64 _chm_decompress_block(struct chmFile *h,
UInt64 block,
UChar **ubuffer)
{
UChar *cbuffer = HeapAlloc( GetProcessHeap(), 0,
((unsigned int)h->reset_table.block_len + 6144));
UInt64 cmpStart; /* compressed start */
Int64 cmpLen; /* compressed len */
int indexSlot; /* cache index slot */
UChar *lbuffer; /* local buffer ptr */
UInt32 blockAlign = (UInt32)(block % h->reset_blkcount); /* reset intvl. aln. */
UInt32 i; /* local loop index */
/* let the caching system pull its weight! */
if (block - blockAlign <= h->lzx_last_block &&
block >= h->lzx_last_block)
blockAlign = (block - h->lzx_last_block);
/* check if we need previous blocks */
if (blockAlign != 0)
{
/* fetch all required previous blocks since last reset */
for (i = blockAlign; i > 0; i--)
{
UInt32 curBlockIdx = block - i;
/* check if we most recently decompressed the previous block */
if (h->lzx_last_block != curBlockIdx)
{
if ((curBlockIdx % h->reset_blkcount) == 0)
{
#ifdef CHM_DEBUG
fprintf(stderr, "***RESET (1)***\n");
#endif
LZXreset(h->lzx_state);
}
indexSlot = (int)((curBlockIdx) % h->cache_num_blocks);
h->cache_block_indices[indexSlot] = curBlockIdx;
if (! h->cache_blocks[indexSlot])
h->cache_blocks[indexSlot] = (UChar *)malloc(
(unsigned int)(h->reset_table.block_len));
lbuffer = h->cache_blocks[indexSlot];
/* decompress the previous block */
#ifdef CHM_DEBUG
fprintf(stderr, "Decompressing block #%4d (EXTRA)\n", curBlockIdx);
#endif
if (!_chm_get_cmpblock_bounds(h, curBlockIdx, &cmpStart, &cmpLen) ||
_chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen ||
LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
(int)h->reset_table.block_len) != DECR_OK)
{
#ifdef CHM_DEBUG
fprintf(stderr, " (DECOMPRESS FAILED!)\n");
#endif
HeapFree(GetProcessHeap(), 0, cbuffer);
return (Int64)0;
}
h->lzx_last_block = (int)curBlockIdx;
}
}
}
else
{
if ((block % h->reset_blkcount) == 0)
{
#ifdef CHM_DEBUG
fprintf(stderr, "***RESET (2)***\n");
#endif
LZXreset(h->lzx_state);
}
}
/* allocate slot in cache */
indexSlot = (int)(block % h->cache_num_blocks);
h->cache_block_indices[indexSlot] = block;
if (! h->cache_blocks[indexSlot])
h->cache_blocks[indexSlot] = (UChar *)malloc(
((unsigned int)h->reset_table.block_len));
lbuffer = h->cache_blocks[indexSlot];
*ubuffer = lbuffer;
/* decompress the block we actually want */
#ifdef CHM_DEBUG
fprintf(stderr, "Decompressing block #%4d (REAL )\n", block);
#endif
if (! _chm_get_cmpblock_bounds(h, block, &cmpStart, &cmpLen) ||
_chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen ||
LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
(int)h->reset_table.block_len) != DECR_OK)
{
#ifdef CHM_DEBUG
fprintf(stderr, " (DECOMPRESS FAILED!)\n");
#endif
HeapFree(GetProcessHeap(), 0, cbuffer);
return (Int64)0;
}
h->lzx_last_block = (int)block;
/* XXX: modify LZX routines to return the length of the data they
* decompressed and return that instead, for an extra sanity check.
*/
HeapFree(GetProcessHeap(), 0, cbuffer);
return h->reset_table.block_len;
}
/* grab a region from a compressed block */
static Int64 _chm_decompress_region(struct chmFile *h,
UChar *buf,
UInt64 start,
Int64 len)
{
UInt64 nBlock, nOffset;
UInt64 nLen;
UInt64 gotLen;
UChar *ubuffer;
if (len <= 0)
return (Int64)0;
/* figure out what we need to read */
nBlock = start / h->reset_table.block_len;
nOffset = start % h->reset_table.block_len;
nLen = len;
if (nLen > (h->reset_table.block_len - nOffset))
nLen = h->reset_table.block_len - nOffset;
/* if block is cached, return data from it. */
CHM_ACQUIRE_LOCK(h->lzx_mutex);
CHM_ACQUIRE_LOCK(h->cache_mutex);
if (h->cache_block_indices[nBlock % h->cache_num_blocks] == nBlock &&
h->cache_blocks[nBlock % h->cache_num_blocks] != NULL)
{
memcpy(buf,
h->cache_blocks[nBlock % h->cache_num_blocks] + nOffset,
(unsigned int)nLen);
CHM_RELEASE_LOCK(h->cache_mutex);
CHM_RELEASE_LOCK(h->lzx_mutex);
return nLen;
}
CHM_RELEASE_LOCK(h->cache_mutex);
/* data request not satisfied, so... start up the decompressor machine */
if (! h->lzx_state)
{
int window_size = ffs(h->window_size) - 1;
h->lzx_last_block = -1;
h->lzx_state = LZXinit(window_size);
}
/* decompress some data */
gotLen = _chm_decompress_block(h, nBlock, &ubuffer);
if (gotLen < nLen)
nLen = gotLen;
memcpy(buf, ubuffer+nOffset, (unsigned int)nLen);
CHM_RELEASE_LOCK(h->lzx_mutex);
return nLen;
}
/* retrieve (part of) an object */
LONGINT64 chm_retrieve_object(struct chmFile *h,
struct chmUnitInfo *ui,
unsigned char *buf,
LONGUINT64 addr,
LONGINT64 len)
{
/* must be valid file handle */
if (h == NULL)
return (Int64)0;
/* starting address must be in correct range */
if (addr < 0 || addr >= ui->length)
return (Int64)0;
/* clip length */
if (addr + len > ui->length)
len = ui->length - addr;
/* if the file is uncompressed, it's simple */
if (ui->space == CHM_UNCOMPRESSED)
{
/* read data */
return _chm_fetch_bytes(h,
buf,
(UInt64)h->data_offset + (UInt64)ui->start + (UInt64)addr,
len);
}
/* else if the file is compressed, it's a little trickier */
else /* ui->space == CHM_COMPRESSED */
{
Int64 swath=0, total=0;
/* if compression is not enabled for this file... */
if (! h->compression_enabled)
return total;
do {
/* swill another mouthful */
swath = _chm_decompress_region(h, buf, ui->start + addr, len);
/* if we didn't get any... */
if (swath == 0)
return total;
/* update stats */
total += swath;
len -= swath;
addr += swath;
buf += swath;
} while (len != 0);
return total;
}
}
/* enumerate the objects in the .chm archive */
int chm_enumerate(struct chmFile *h,
int what,
CHM_ENUMERATOR e,
void *context)
{
Int32 curPage;
/* buffer to hold whatever page we're looking at */
UChar *page_buf = HeapAlloc(GetProcessHeap(), 0, (unsigned int)h->block_len);
struct chmPmglHeader header;
UChar *end;
UChar *cur;
unsigned long lenRemain;
UInt64 ui_path_len;
/* the current ui */
struct chmUnitInfo ui;
int flag;
/* starting page */
curPage = h->index_head;
/* until we have either returned or given up */
while (curPage != -1)
{
/* try to fetch the index page */
if (_chm_fetch_bytes(h,
page_buf,
(UInt64)h->dir_offset + (UInt64)curPage*h->block_len,
h->block_len) != h->block_len)
{
HeapFree(GetProcessHeap(), 0, page_buf);
return 0;
}
/* figure out start and end for this page */
cur = page_buf;
lenRemain = _CHM_PMGL_LEN;
if (! _unmarshal_pmgl_header(&cur, &lenRemain, &header))
{
HeapFree(GetProcessHeap(), 0, page_buf);
return 0;
}
end = page_buf + h->block_len - (header.free_space);
/* loop over this page */
while (cur < end)
{
if (! _chm_parse_PMGL_entry(&cur, &ui))
{
HeapFree(GetProcessHeap(), 0, page_buf);
return 0;
}
/* get the length of the path */
ui_path_len = strlenW(ui.path)-1;
/* check for DIRS */
if (ui.path[ui_path_len] == '/' && !(what & CHM_ENUMERATE_DIRS))
continue;
/* check for FILES */
if (ui.path[ui_path_len] != '/' && !(what & CHM_ENUMERATE_FILES))
continue;
/* check for NORMAL vs. META */
if (ui.path[0] == '/')
{
/* check for NORMAL vs. SPECIAL */
if (ui.path[1] == '#' || ui.path[1] == '$')
flag = CHM_ENUMERATE_SPECIAL;
else
flag = CHM_ENUMERATE_NORMAL;
}
else
flag = CHM_ENUMERATE_META;
if (! (what & flag))
continue;
/* call the enumerator */
{
int status = (*e)(h, &ui, context);
switch (status)
{
case CHM_ENUMERATOR_FAILURE:
HeapFree(GetProcessHeap(), 0, page_buf);
return 0;
case CHM_ENUMERATOR_CONTINUE:
break;
case CHM_ENUMERATOR_SUCCESS:
HeapFree(GetProcessHeap(), 0, page_buf);
return 1;
default:
break;
}
}
}
/* advance to next page */
curPage = header.block_next;
}
HeapFree(GetProcessHeap(), 0, page_buf);
return 1;
}
int chm_enumerate_dir(struct chmFile *h,
const WCHAR *prefix,
int what,
CHM_ENUMERATOR e,
void *context)
{
/*
* XXX: do this efficiently (i.e. using the tree index)
*/
Int32 curPage;
/* buffer to hold whatever page we're looking at */
UChar *page_buf = HeapAlloc(GetProcessHeap(), 0, (unsigned int)h->block_len);
struct chmPmglHeader header;
UChar *end;
UChar *cur;
unsigned long lenRemain;
/* set to 1 once we've started */
int it_has_begun=0;
/* the current ui */
struct chmUnitInfo ui;
int flag;
UInt64 ui_path_len;
/* the length of the prefix */
WCHAR prefixRectified[CHM_MAX_PATHLEN+1];
int prefixLen;
WCHAR lastPath[CHM_MAX_PATHLEN];
int lastPathLen;
/* starting page */
curPage = h->index_head;
/* initialize pathname state */
strncpyW(prefixRectified, prefix, CHM_MAX_PATHLEN);
prefixLen = strlenW(prefixRectified);
if (prefixLen != 0)
{
if (prefixRectified[prefixLen-1] != '/')
{
prefixRectified[prefixLen] = '/';
prefixRectified[prefixLen+1] = '\0';
++prefixLen;
}
}
lastPath[0] = '\0';
lastPathLen = -1;
/* until we have either returned or given up */
while (curPage != -1)
{
/* try to fetch the index page */
if (_chm_fetch_bytes(h,
page_buf,
(UInt64)h->dir_offset + (UInt64)curPage*h->block_len,
h->block_len) != h->block_len)
{
HeapFree(GetProcessHeap(), 0, page_buf);
return 0;
}
/* figure out start and end for this page */
cur = page_buf;
lenRemain = _CHM_PMGL_LEN;
if (! _unmarshal_pmgl_header(&cur, &lenRemain, &header))
{
HeapFree(GetProcessHeap(), 0, page_buf);
return 0;
}
end = page_buf + h->block_len - (header.free_space);
/* loop over this page */
while (cur < end)
{
if (! _chm_parse_PMGL_entry(&cur, &ui))
{
HeapFree(GetProcessHeap(), 0, page_buf);
return 0;
}
/* check if we should start */
if (! it_has_begun)
{
if (ui.length == 0 && strncmpiW(ui.path, prefixRectified, prefixLen) == 0)
it_has_begun = 1;
else
continue;
if (ui.path[prefixLen] == '\0')
continue;
}
/* check if we should stop */
else
{
if (strncmpiW(ui.path, prefixRectified, prefixLen) != 0)
{
HeapFree(GetProcessHeap(), 0, page_buf);
return 1;
}
}
/* check if we should include this path */
if (lastPathLen != -1)
{
if (strncmpiW(ui.path, lastPath, lastPathLen) == 0)
continue;
}
strcpyW(lastPath, ui.path);
lastPathLen = strlenW(lastPath);
/* get the length of the path */
ui_path_len = strlenW(ui.path)-1;
/* check for DIRS */
if (ui.path[ui_path_len] == '/' && !(what & CHM_ENUMERATE_DIRS))
continue;
/* check for FILES */
if (ui.path[ui_path_len] != '/' && !(what & CHM_ENUMERATE_FILES))
continue;
/* check for NORMAL vs. META */
if (ui.path[0] == '/')
{
/* check for NORMAL vs. SPECIAL */
if (ui.path[1] == '#' || ui.path[1] == '$')
flag = CHM_ENUMERATE_SPECIAL;
else
flag = CHM_ENUMERATE_NORMAL;
}
else
flag = CHM_ENUMERATE_META;
if (! (what & flag))
continue;
/* call the enumerator */
{
int status = (*e)(h, &ui, context);
switch (status)
{
case CHM_ENUMERATOR_FAILURE:
HeapFree(GetProcessHeap(), 0, page_buf);
return 0;
case CHM_ENUMERATOR_CONTINUE:
break;
case CHM_ENUMERATOR_SUCCESS:
HeapFree(GetProcessHeap(), 0, page_buf);
return 1;
default:
break;
}
}
}
/* advance to next page */
curPage = header.block_next;
}
HeapFree(GetProcessHeap(), 0, page_buf);
return 1;
}
/* $Id$ */
/***************************************************************************
* chm_lib.h - CHM archive manipulation routines *
* ------------------- *
* *
* author: Jed Wing <jedwin@ugcs.caltech.edu> *
* version: 0.3 *
* notes: These routines are meant for the manipulation of microsoft *
* .chm (compiled html help) files, but may likely be used *
* for the manipulation of any ITSS archive, if ever ITSS *
* archives are used for any other purpose. *
* *
* Note also that the section names are statically handled. *
* To be entirely correct, the section names should be read *
* from the section names meta-file, and then the various *
* content sections and the "transforms" to apply to the data *
* they contain should be inferred from the section name and *
* the meta-files referenced using that name; however, all of *
* the files I've been able to get my hands on appear to have *
* only two sections: Uncompressed and MSCompressed. *
* Additionally, the ITSS.DLL file included with Windows does *
* not appear to handle any different transforms than the *
* simple LZX-transform. Furthermore, the list of transforms *
* to apply is broken, in that only half the required space *
* is allocated for the list. (It appears as though the *
* space is allocated for ASCII strings, but the strings are *
* written as unicode. As a result, only the first half of *
* the string appears.) So this is probably not too big of *
* a deal, at least until CHM v4 (MS .lit files), which also *
* incorporate encryption, of some description. *
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef INCLUDED_CHMLIB_H
#define INCLUDED_CHMLIB_H
typedef ULONGLONG LONGUINT64;
typedef LONGLONG LONGINT64;
/* the two available spaces in a CHM file */
/* N.B.: The format supports arbitrarily many spaces, but only */
/* two appear to be used at present. */
#define CHM_UNCOMPRESSED (0)
#define CHM_COMPRESSED (1)
/* structure representing an ITS (CHM) file stream */
struct chmFile;
/* structure representing an element from an ITS file stream */
#define CHM_MAX_PATHLEN (256)
struct chmUnitInfo
{
LONGUINT64 start;
LONGUINT64 length;
int space;
WCHAR path[CHM_MAX_PATHLEN+1];
};
struct chmFile* chm_openW(const WCHAR *filename);
/* close an ITS archive */
void chm_close(struct chmFile *h);
/* methods for ssetting tuning parameters for particular file */
#define CHM_PARAM_MAX_BLOCKS_CACHED 0
void chm_set_param(struct chmFile *h,
int paramType,
int paramVal);
/* resolve a particular object from the archive */
#define CHM_RESOLVE_SUCCESS (0)
#define CHM_RESOLVE_FAILURE (1)
int chm_resolve_object(struct chmFile *h,
const WCHAR *objPath,
struct chmUnitInfo *ui);
/* retrieve part of an object from the archive */
LONGINT64 chm_retrieve_object(struct chmFile *h,
struct chmUnitInfo *ui,
unsigned char *buf,
LONGUINT64 addr,
LONGINT64 len);
/* enumerate the objects in the .chm archive */
typedef int (*CHM_ENUMERATOR)(struct chmFile *h,
struct chmUnitInfo *ui,
void *context);
#define CHM_ENUMERATE_NORMAL (1)
#define CHM_ENUMERATE_META (2)
#define CHM_ENUMERATE_SPECIAL (4)
#define CHM_ENUMERATE_FILES (8)
#define CHM_ENUMERATE_DIRS (16)
#define CHM_ENUMERATE_ALL (31)
#define CHM_ENUMERATOR_FAILURE (0)
#define CHM_ENUMERATOR_CONTINUE (1)
#define CHM_ENUMERATOR_SUCCESS (2)
int chm_enumerate(struct chmFile *h,
int what,
CHM_ENUMERATOR e,
void *context);
int chm_enumerate_dir(struct chmFile *h,
const WCHAR *prefix,
int what,
CHM_ENUMERATOR e,
void *context);
#endif /* INCLUDED_CHMLIB_H */
/*
* ITSS Class Factory
*
* Copyright 2002 Lionel Ulmer
* Copyright 2004 Mike McCormack
*
* see http://bonedaddy.net/pabs3/hhm/#chmspec
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "ole2.h"
#include "itss.h"
#include "uuids.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(itss);
#include "initguid.h"
DEFINE_GUID(CLSID_ITStorage,0x5d02926a,0x212e,0x11d0,0x9d,0xf9,0x00,0xa0,0xc9,0x22,0xe6,0xec );
DEFINE_GUID(CLSID_ITSProtocol,0x9d148290,0xb9c8,0x11d0,0xa4,0xcc,0x00,0x00,0xf8,0x01,0x49,0xf6);
DEFINE_GUID(IID_IITStorage, 0x88cc31de, 0x27ab, 0x11d0, 0x9d, 0xf9, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xec);
static HRESULT ITSS_create(IUnknown *pUnkOuter, LPVOID *ppObj);
extern HRESULT ITS_IParseDisplayName_create(IUnknown *pUnkOuter, LPVOID *ppObj);
extern HRESULT ITSS_StgOpenStorage( const WCHAR*, IStorage*, DWORD, SNB, DWORD, IStorage** );
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
{
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInstDLL);
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
/******************************************************************************
* ITSS ClassFactory
*/
typedef struct {
IClassFactory ITF_IClassFactory;
DWORD ref;
HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
} IClassFactoryImpl;
struct object_creation_info
{
const CLSID *clsid;
LPCSTR szClassName;
HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
};
static const struct object_creation_info object_creation[] =
{
{ &CLSID_ITStorage, "ITStorage", ITSS_create },
{ &CLSID_ITSProtocol, "ITSProtocol", ITS_IParseDisplayName_create },
};
static HRESULT WINAPI
ITSSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
{
ICOM_THIS(IClassFactoryImpl,iface);
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IClassFactory))
{
IClassFactory_AddRef(iface);
*ppobj = This;
return S_OK;
}
WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
return E_NOINTERFACE;
}
static ULONG WINAPI ITSSCF_AddRef(LPCLASSFACTORY iface) {
ICOM_THIS(IClassFactoryImpl,iface);
return ++(This->ref);
}
static ULONG WINAPI ITSSCF_Release(LPCLASSFACTORY iface) {
ICOM_THIS(IClassFactoryImpl,iface);
ULONG ref = --This->ref;
if (ref == 0)
HeapFree(GetProcessHeap(), 0, This);
return ref;
}
static HRESULT WINAPI ITSSCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
REFIID riid, LPVOID *ppobj) {
ICOM_THIS(IClassFactoryImpl,iface);
HRESULT hres;
LPUNKNOWN punk;
TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
if (FAILED(hres)) {
*ppobj = NULL;
return hres;
}
hres = IUnknown_QueryInterface(punk, riid, ppobj);
if (FAILED(hres)) {
*ppobj = NULL;
return hres;
}
IUnknown_Release(punk);
return hres;
}
static HRESULT WINAPI ITSSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
ICOM_THIS(IClassFactoryImpl,iface);
FIXME("(%p)->(%d),stub!\n",This,dolock);
return S_OK;
}
static IClassFactoryVtbl ITSSCF_Vtbl =
{
ITSSCF_QueryInterface,
ITSSCF_AddRef,
ITSSCF_Release,
ITSSCF_CreateInstance,
ITSSCF_LockServer
};
HRESULT WINAPI ITSS_DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
{
int i;
IClassFactoryImpl *factory;
TRACE("%s %s %p\n",debugstr_guid(rclsid), debugstr_guid(iid), ppv);
if ( !IsEqualGUID( &IID_IClassFactory, iid )
&& ! IsEqualGUID( &IID_IUnknown, iid) )
return E_NOINTERFACE;
for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
{
if (IsEqualGUID(object_creation[i].clsid, rclsid))
break;
}
if (i == sizeof(object_creation)/sizeof(object_creation[0]))
{
FIXME("%s: no class found.\n", debugstr_guid(rclsid));
return CLASS_E_CLASSNOTAVAILABLE;
}
TRACE("Creating a class factory for %s\n",object_creation[i].szClassName);
factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
if (factory == NULL) return E_OUTOFMEMORY;
factory->ITF_IClassFactory.lpVtbl = &ITSSCF_Vtbl;
factory->ref = 1;
factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
*ppv = &(factory->ITF_IClassFactory);
TRACE("(%p) <- %p\n", ppv, &(factory->ITF_IClassFactory) );
return S_OK;
}
/*****************************************************************************/
typedef struct {
IITStorageVtbl *vtbl_IITStorage;
DWORD ref;
} ITStorageImpl;
HRESULT WINAPI ITStorageImpl_QueryInterface(
IITStorage* iface,
REFIID riid,
void** ppvObject)
{
ICOM_THIS(ITStorageImpl,iface);
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IITStorage))
{
IClassFactory_AddRef(iface);
*ppvObject = This;
return S_OK;
}
WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
return E_NOINTERFACE;
}
ULONG WINAPI ITStorageImpl_AddRef(
IITStorage* iface)
{
ICOM_THIS(ITStorageImpl,iface);
TRACE("%p\n", This);
return ++(This->ref);
}
ULONG WINAPI ITStorageImpl_Release(
IITStorage* iface)
{
ICOM_THIS(ITStorageImpl,iface);
ULONG ref = --This->ref;
if (ref == 0)
HeapFree(GetProcessHeap(), 0, This);
return ref;
}
HRESULT WINAPI ITStorageImpl_StgCreateDocfile(
IITStorage* iface,
const WCHAR* pwcsName,
DWORD grfMode,
DWORD reserved,
IStorage** ppstgOpen)
{
ICOM_THIS(ITStorageImpl,iface);
TRACE("%p %s %lu %lu %p\n", This,
debugstr_w(pwcsName), grfMode, reserved, ppstgOpen );
return ITSS_StgOpenStorage( pwcsName, NULL, grfMode,
0, reserved, ppstgOpen);
}
HRESULT WINAPI ITStorageImpl_StgCreateDocfileOnILockBytes(
IITStorage* iface,
ILockBytes* plkbyt,
DWORD grfMode,
DWORD reserved,
IStorage** ppstgOpen)
{
ICOM_THIS(ITStorageImpl,iface);
FIXME("%p\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI ITStorageImpl_StgIsStorageFile(
IITStorage* iface,
const WCHAR* pwcsName)
{
ICOM_THIS(ITStorageImpl,iface);
FIXME("%p\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI ITStorageImpl_StgIsStorageILockBytes(
IITStorage* iface,
ILockBytes* plkbyt)
{
ICOM_THIS(ITStorageImpl,iface);
FIXME("%p\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI ITStorageImpl_StgOpenStorage(
IITStorage* iface,
const WCHAR* pwcsName,
IStorage* pstgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen)
{
ICOM_THIS(ITStorageImpl,iface);
TRACE("%p %s %p %ld %p\n", This, debugstr_w( pwcsName ),
pstgPriority, grfMode, snbExclude );
return ITSS_StgOpenStorage( pwcsName, pstgPriority, grfMode,
snbExclude, reserved, ppstgOpen);
}
HRESULT WINAPI ITStorageImpl_StgOpenStorageOnILockBytes(
IITStorage* iface,
ILockBytes* plkbyt,
IStorage* pStgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen)
{
ICOM_THIS(ITStorageImpl,iface);
FIXME("%p\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI ITStorageImpl_StgSetTimes(
IITStorage* iface,
WCHAR* lpszName,
FILETIME* pctime,
FILETIME* patime,
FILETIME* pmtime)
{
ICOM_THIS(ITStorageImpl,iface);
FIXME("%p\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI ITStorageImpl_SetControlData(
IITStorage* iface,
PITS_Control_Data pControlData)
{
ICOM_THIS(ITStorageImpl,iface);
FIXME("%p\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI ITStorageImpl_DefaultControlData(
IITStorage* iface,
PITS_Control_Data* ppControlData)
{
ICOM_THIS(ITStorageImpl,iface);
FIXME("%p\n", This);
return E_NOTIMPL;
}
HRESULT WINAPI ITStorageImpl_Compact(
IITStorage* iface,
const WCHAR* pwcsName,
ECompactionLev iLev)
{
ICOM_THIS(ITStorageImpl,iface);
FIXME("%p\n", This);
return E_NOTIMPL;
}
static IITStorageVtbl ITStorageImpl_Vtbl =
{
ITStorageImpl_QueryInterface,
ITStorageImpl_AddRef,
ITStorageImpl_Release,
ITStorageImpl_StgCreateDocfile,
ITStorageImpl_StgCreateDocfileOnILockBytes,
ITStorageImpl_StgIsStorageFile,
ITStorageImpl_StgIsStorageILockBytes,
ITStorageImpl_StgOpenStorage,
ITStorageImpl_StgOpenStorageOnILockBytes,
ITStorageImpl_StgSetTimes,
ITStorageImpl_SetControlData,
ITStorageImpl_DefaultControlData,
ITStorageImpl_Compact,
};
static HRESULT ITSS_create(IUnknown *pUnkOuter, LPVOID *ppObj)
{
ITStorageImpl *its;
its = HeapAlloc( GetProcessHeap(), 0, sizeof(ITStorageImpl) );
its->vtbl_IITStorage = &ITStorageImpl_Vtbl;
its->ref = 1;
TRACE("-> %p\n", its);
*ppObj = (LPVOID) its;
return S_OK;
}
/*****************************************************************************/
HRESULT WINAPI ITSS_DllRegisterServer(void)
{
FIXME("\n");
return S_OK;
}
BOOL WINAPI ITSS_DllCanUnloadNow(void)
{
FIXME("\n");
return FALSE;
}
/*** Autogenerated by WIDL 0.1 from itss.idl - Do not edit ***/
#include <rpc.h>
#include <rpcndr.h>
#ifndef __WIDL_ITSS_H
#define __WIDL_ITSS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <oaidl.h>
typedef struct _ITS_Control_Data {
UINT cdwControlData;
UINT adwControlData[1];
} ITS_Control_Data, *PITS_Control_Data;
typedef enum ECompactionLev {
COMPACT_DATA = 0,
COMPACT_DATA_AND_PATH
} ECompactionLev;
#ifndef __IITStorage_FWD_DEFINED__
#define __IITStorage_FWD_DEFINED__
typedef struct IITStorage IITStorage;
#endif
/*****************************************************************************
* IITStorage interface
*/
#ifndef __IITStorage_INTERFACE_DEFINED__
#define __IITStorage_INTERFACE_DEFINED__
#if defined(__cplusplus) && !defined(CINTERFACE)
struct IITStorage : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE StgCreateDocfile(
const WCHAR* pwcsName,
DWORD grfMode,
DWORD reserved,
IStorage** ppstgOpen) = 0;
virtual HRESULT STDMETHODCALLTYPE StgCreateDocfileOnILockBytes(
ILockBytes* plkbyt,
DWORD grfMode,
DWORD reserved,
IStorage** ppstgOpen) = 0;
virtual HRESULT STDMETHODCALLTYPE StgIsStorageFile(
const WCHAR* pwcsName) = 0;
virtual HRESULT STDMETHODCALLTYPE StgIsStorageILockBytes(
ILockBytes* plkbyt) = 0;
virtual HRESULT STDMETHODCALLTYPE StgOpenStorage(
const WCHAR* pwcsName,
IStorage* pstgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen) = 0;
virtual HRESULT STDMETHODCALLTYPE StgOpenStorageOnILockBytes(
ILockBytes* plkbyt,
IStorage* pStgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen) = 0;
virtual HRESULT STDMETHODCALLTYPE StgSetTimes(
WCHAR* lpszName,
FILETIME* pctime,
FILETIME* patime,
FILETIME* pmtime) = 0;
virtual HRESULT STDMETHODCALLTYPE SetControlData(
PITS_Control_Data pControlData) = 0;
virtual HRESULT STDMETHODCALLTYPE DefaultControlData(
PITS_Control_Data* ppControlData) = 0;
virtual HRESULT STDMETHODCALLTYPE Compact(
const WCHAR* pwcsName,
ECompactionLev iLev) = 0;
};
#else
typedef struct IITStorageVtbl IITStorageVtbl;
struct IITStorage {
const IITStorageVtbl* lpVtbl;
};
struct IITStorageVtbl {
BEGIN_INTERFACE
/*** IUnknown methods ***/
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
IITStorage* This,
REFIID riid,
void** ppvObject);
ULONG (STDMETHODCALLTYPE *AddRef)(
IITStorage* This);
ULONG (STDMETHODCALLTYPE *Release)(
IITStorage* This);
/*** IITStorage methods ***/
HRESULT (STDMETHODCALLTYPE *StgCreateDocfile)(
IITStorage* This,
const WCHAR* pwcsName,
DWORD grfMode,
DWORD reserved,
IStorage** ppstgOpen);
HRESULT (STDMETHODCALLTYPE *StgCreateDocfileOnILockBytes)(
IITStorage* This,
ILockBytes* plkbyt,
DWORD grfMode,
DWORD reserved,
IStorage** ppstgOpen);
HRESULT (STDMETHODCALLTYPE *StgIsStorageFile)(
IITStorage* This,
const WCHAR* pwcsName);
HRESULT (STDMETHODCALLTYPE *StgIsStorageILockBytes)(
IITStorage* This,
ILockBytes* plkbyt);
HRESULT (STDMETHODCALLTYPE *StgOpenStorage)(
IITStorage* This,
const WCHAR* pwcsName,
IStorage* pstgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen);
HRESULT (STDMETHODCALLTYPE *StgOpenStorageOnILockBytes)(
IITStorage* This,
ILockBytes* plkbyt,
IStorage* pStgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen);
HRESULT (STDMETHODCALLTYPE *StgSetTimes)(
IITStorage* This,
WCHAR* lpszName,
FILETIME* pctime,
FILETIME* patime,
FILETIME* pmtime);
HRESULT (STDMETHODCALLTYPE *SetControlData)(
IITStorage* This,
PITS_Control_Data pControlData);
HRESULT (STDMETHODCALLTYPE *DefaultControlData)(
IITStorage* This,
PITS_Control_Data* ppControlData);
HRESULT (STDMETHODCALLTYPE *Compact)(
IITStorage* This,
const WCHAR* pwcsName,
ECompactionLev iLev);
END_INTERFACE
};
#ifdef COBJMACROS
/*** IUnknown methods ***/
#define IITStorage_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
#define IITStorage_AddRef(p) (p)->lpVtbl->AddRef(p)
#define IITStorage_Release(p) (p)->lpVtbl->Release(p)
/*** IITStorage methods ***/
#define IITStorage_StgCreateDocfile(p,a,b,c,d) (p)->lpVtbl->StgCreateDocfile(p,a,b,c,d)
#define IITStorage_StgCreateDocfileOnILockBytes(p,a,b,c,d) (p)->lpVtbl->StgCreateDocfileOnILockBytes(p,a,b,c,d)
#define IITStorage_StgIsStorageFile(p,a) (p)->lpVtbl->StgIsStorageFile(p,a)
#define IITStorage_StgIsStorageILockBytes(p,a) (p)->lpVtbl->StgIsStorageILockBytes(p,a)
#define IITStorage_StgOpenStorage(p,a,b,c,d,e,f) (p)->lpVtbl->StgOpenStorage(p,a,b,c,d,e,f)
#define IITStorage_StgOpenStorageOnILockBytes(p,a,b,c,d,e,f) (p)->lpVtbl->StgOpenStorageOnILockBytes(p,a,b,c,d,e,f)
#define IITStorage_StgSetTimes(p,a,b,c,d) (p)->lpVtbl->StgSetTimes(p,a,b,c,d)
#define IITStorage_SetControlData(p,a) (p)->lpVtbl->SetControlData(p,a)
#define IITStorage_DefaultControlData(p,a) (p)->lpVtbl->DefaultControlData(p,a)
#define IITStorage_Compact(p,a,b) (p)->lpVtbl->Compact(p,a,b)
#endif
#endif
#define IITStorage_METHODS \
/*** IUnknown methods ***/ \
STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; \
STDMETHOD_(ULONG,AddRef)(THIS) PURE; \
STDMETHOD_(ULONG,Release)(THIS) PURE; \
/*** IITStorage methods ***/ \
STDMETHOD_(HRESULT,StgCreateDocfile)(THIS_ const WCHAR* pwcsName, DWORD grfMode, DWORD reserved, IStorage** ppstgOpen) PURE; \
STDMETHOD_(HRESULT,StgCreateDocfileOnILockBytes)(THIS_ ILockBytes* plkbyt, DWORD grfMode, DWORD reserved, IStorage** ppstgOpen) PURE; \
STDMETHOD_(HRESULT,StgIsStorageFile)(THIS_ const WCHAR* pwcsName) PURE; \
STDMETHOD_(HRESULT,StgIsStorageILockBytes)(THIS_ ILockBytes* plkbyt) PURE; \
STDMETHOD_(HRESULT,StgOpenStorage)(THIS_ const WCHAR* pwcsName, IStorage* pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage** ppstgOpen) PURE; \
STDMETHOD_(HRESULT,StgOpenStorageOnILockBytes)(THIS_ ILockBytes* plkbyt, IStorage* pStgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage** ppstgOpen) PURE; \
STDMETHOD_(HRESULT,StgSetTimes)(THIS_ WCHAR* lpszName, FILETIME* pctime, FILETIME* patime, FILETIME* pmtime) PURE; \
STDMETHOD_(HRESULT,SetControlData)(THIS_ PITS_Control_Data pControlData) PURE; \
STDMETHOD_(HRESULT,DefaultControlData)(THIS_ PITS_Control_Data* ppControlData) PURE; \
STDMETHOD_(HRESULT,Compact)(THIS_ const WCHAR* pwcsName, ECompactionLev iLev) PURE;
HRESULT CALLBACK IITStorage_StgCreateDocfile_Proxy(
IITStorage* This,
const WCHAR* pwcsName,
DWORD grfMode,
DWORD reserved,
IStorage** ppstgOpen);
void __RPC_STUB IITStorage_StgCreateDocfile_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_StgCreateDocfileOnILockBytes_Proxy(
IITStorage* This,
ILockBytes* plkbyt,
DWORD grfMode,
DWORD reserved,
IStorage** ppstgOpen);
void __RPC_STUB IITStorage_StgCreateDocfileOnILockBytes_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_StgIsStorageFile_Proxy(
IITStorage* This,
const WCHAR* pwcsName);
void __RPC_STUB IITStorage_StgIsStorageFile_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_StgIsStorageILockBytes_Proxy(
IITStorage* This,
ILockBytes* plkbyt);
void __RPC_STUB IITStorage_StgIsStorageILockBytes_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_StgOpenStorage_Proxy(
IITStorage* This,
const WCHAR* pwcsName,
IStorage* pstgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen);
void __RPC_STUB IITStorage_StgOpenStorage_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_StgOpenStorageOnILockBytes_Proxy(
IITStorage* This,
ILockBytes* plkbyt,
IStorage* pStgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen);
void __RPC_STUB IITStorage_StgOpenStorageOnILockBytes_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_StgSetTimes_Proxy(
IITStorage* This,
WCHAR* lpszName,
FILETIME* pctime,
FILETIME* patime,
FILETIME* pmtime);
void __RPC_STUB IITStorage_StgSetTimes_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_SetControlData_Proxy(
IITStorage* This,
PITS_Control_Data pControlData);
void __RPC_STUB IITStorage_SetControlData_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_DefaultControlData_Proxy(
IITStorage* This,
PITS_Control_Data* ppControlData);
void __RPC_STUB IITStorage_DefaultControlData_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
HRESULT CALLBACK IITStorage_Compact_Proxy(
IITStorage* This,
const WCHAR* pwcsName,
ECompactionLev iLev);
void __RPC_STUB IITStorage_Compact_Stub(
struct IRpcStubBuffer* This,
struct IRpcChannelBuffer* pRpcChannelBuffer,
PRPC_MESSAGE pRpcMessage,
DWORD* pdwStubPhase);
#endif /* __IITStorage_INTERFACE_DEFINED__ */
DEFINE_GUID(CLSID_ITStorage,0x5d02926a,0x212e,0x11d0,0x9d,0xf9,0x00,0xa0,0xc9,0x22,0xe6,0xec );
DEFINE_GUID(IID_IITStorage, 0x88cc31de, 0x27ab, 0x11d0, 0x9d, 0xf9, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xec);
#ifdef __cplusplus
}
#endif
#endif /* __WIDL_ITSS_H */
/*
* Copyright (C) 2004 Mike McCormack
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import "oaidl.idl";
typedef struct _ITS_Control_Data
{
UINT cdwControlData;
UINT adwControlData[1];
} ITS_Control_Data, *PITS_Control_Data;
typedef enum ECompactionLev {
COMPACT_DATA = 0,
COMPACT_DATA_AND_PATH
} ECompactionLev;
[
object,
pointer_default(unique)
]
interface IITStorage : IUnknown
{
HRESULT StgCreateDocfile(
[in] const WCHAR * pwcsName,
[in] DWORD grfMode,
[in] DWORD reserved,
[out] IStorage ** ppstgOpen);
HRESULT StgCreateDocfileOnILockBytes(
[in] ILockBytes * plkbyt,
[in] DWORD grfMode,
[in] DWORD reserved,
[out] IStorage ** ppstgOpen);
HRESULT StgIsStorageFile(
[in] const WCHAR * pwcsName);
HRESULT StgIsStorageILockBytes(
[in] ILockBytes * plkbyt);
HRESULT StgOpenStorage(
[in] const WCHAR * pwcsName,
[in] IStorage * pstgPriority,
[in] DWORD grfMode,
[in] SNB snbExclude,
[in] DWORD reserved,
[out] IStorage ** ppstgOpen);
HRESULT StgOpenStorageOnILockBytes(
[in] ILockBytes * plkbyt,
[in] IStorage * pStgPriority,
[in] DWORD grfMode,
[in] SNB snbExclude,
[in] DWORD reserved,
[out] IStorage ** ppstgOpen);
HRESULT StgSetTimes(
[in] WCHAR const * lpszName,
[in] FILETIME const * pctime,
[in] FILETIME const * patime,
[in] FILETIME const * pmtime);
HRESULT SetControlData(
[in] PITS_Control_Data pControlData);
HRESULT DefaultControlData(
[out] PITS_Control_Data * ppControlData);
HRESULT Compact(
[in] const WCHAR * pwcsName,
[in] ECompactionLev iLev);
}
cpp_quote("DEFINE_GUID(CLSID_ITStorage,0x5d02926a,0x212e,0x11d0,0x9d,0xf9,0x00,0xa0,0xc9,0x22,0xe6,0xec );");
cpp_quote("DEFINE_GUID(IID_IITStorage, 0x88cc31de, 0x27ab, 0x11d0, 0x9d, 0xf9, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xec);");
@ stdcall -private DllCanUnloadNow() ITSS_DllCanUnloadNow
@ stdcall -private DllGetClassObject(ptr ptr ptr) ITSS_DllGetClassObject
@ stub DllInstall
@ stdcall -private DllRegisterServer() ITSS_DllRegisterServer
@ stub DllUnregisterServer
/* $Id$ */
/***************************************************************************
* lzx.c - LZX decompression routines *
* ------------------- *
* *
* maintainer: Jed Wing <jedwin@ugcs.caltech.edu> *
* source: modified lzx.c from cabextract v0.5 *
* notes: This file was taken from cabextract v0.5, which was, *
* itself, a modified version of the lzx decompression code *
* from unlzx. *
* *
* platforms: In its current incarnation, this file has been tested on *
* two different Linux platforms (one, redhat-based, with a *
* 2.1.2 glibc and gcc 2.95.x, and the other, Debian, with *
* 2.2.4 glibc and both gcc 2.95.4 and gcc 3.0.2). Both were *
* Intel x86 compatible machines. *
***************************************************************************/
/***************************************************************************
* *
* Copyright(C) Stuart Caie *
* *
* 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. *
* *
***************************************************************************/
#include "lzx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* sized types */
typedef unsigned char UBYTE; /* 8 bits exactly */
typedef unsigned short UWORD; /* 16 bits (or more) */
typedef unsigned int ULONG; /* 32 bits (or more) */
typedef signed int LONG; /* 32 bits (or more) */
/* some constants defined by the LZX specification */
#define LZX_MIN_MATCH (2)
#define LZX_MAX_MATCH (257)
#define LZX_NUM_CHARS (256)
#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */
#define LZX_BLOCKTYPE_VERBATIM (1)
#define LZX_BLOCKTYPE_ALIGNED (2)
#define LZX_BLOCKTYPE_UNCOMPRESSED (3)
#define LZX_PRETREE_NUM_ELEMENTS (20)
#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */
#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */
#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */
/* LZX huffman defines: tweak tablebits as desired */
#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
#define LZX_PRETREE_TABLEBITS (6)
#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
#define LZX_MAINTREE_TABLEBITS (12)
#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
#define LZX_LENGTH_TABLEBITS (12)
#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS)
#define LZX_ALIGNED_TABLEBITS (7)
#define LZX_LENTABLE_SAFETY (64) /* we allow length table decoding overruns */
#define LZX_DECLARE_TABLE(tbl) \
UWORD tbl##_table[(1<<LZX_##tbl##_TABLEBITS) + (LZX_##tbl##_MAXSYMBOLS<<1)];\
UBYTE tbl##_len [LZX_##tbl##_MAXSYMBOLS + LZX_LENTABLE_SAFETY]
struct LZXstate
{
UBYTE *window; /* the actual decoding window */
ULONG window_size; /* window size (32Kb through 2Mb) */
ULONG actual_size; /* window size when it was first allocated */
ULONG window_posn; /* current offset within the window */
ULONG R0, R1, R2; /* for the LRU offset system */
UWORD main_elements; /* number of main tree elements */
int header_read; /* have we started decoding at all yet? */
UWORD block_type; /* type of this block */
ULONG block_length; /* uncompressed length of this block */
ULONG block_remaining; /* uncompressed bytes still left to decode */
ULONG frames_read; /* the number of CFDATA blocks processed */
LONG intel_filesize; /* magic header value used for transform */
LONG intel_curpos; /* current offset in transform space */
int intel_started; /* have we seen any translatable data yet? */
LZX_DECLARE_TABLE(PRETREE);
LZX_DECLARE_TABLE(MAINTREE);
LZX_DECLARE_TABLE(LENGTH);
LZX_DECLARE_TABLE(ALIGNED);
};
/* LZX decruncher */
/* Microsoft's LZX document and their implementation of the
* com.ms.util.cab Java package do not concur.
*
* In the LZX document, there is a table showing the correlation between
* window size and the number of position slots. It states that the 1MB
* window = 40 slots and the 2MB window = 42 slots. In the implementation,
* 1MB = 42 slots, 2MB = 50 slots. The actual calculation is 'find the
* first slot whose position base is equal to or more than the required
* window size'. This would explain why other tables in the document refer
* to 50 slots rather than 42.
*
* The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode
* is not defined in the specification.
*
* The LZX document does not state the uncompressed block has an
* uncompressed length field. Where does this length field come from, so
* we can know how large the block is? The implementation has it as the 24
* bits following after the 3 blocktype bits, before the alignment
* padding.
*
* The LZX document states that aligned offset blocks have their aligned
* offset huffman tree AFTER the main and length trees. The implementation
* suggests that the aligned offset tree is BEFORE the main and length
* trees.
*
* The LZX document decoding algorithm states that, in an aligned offset
* block, if an extra_bits value is 1, 2 or 3, then that number of bits
* should be read and the result added to the match offset. This is
* correct for 1 and 2, but not 3, where just a huffman symbol (using the
* aligned tree) should be read.
*
* Regarding the E8 preprocessing, the LZX document states 'No translation
* may be performed on the last 6 bytes of the input block'. This is
* correct. However, the pseudocode provided checks for the *E8 leader*
* up to the last 6 bytes. If the leader appears between -10 and -7 bytes
* from the end, this would cause the next four bytes to be modified, at
* least one of which would be in the last 6 bytes, which is not allowed
* according to the spec.
*
* The specification states that the huffman trees must always contain at
* least one element. However, many CAB files contain blocks where the
* length tree is completely empty (because there are no matches), and
* this is expected to succeed.
*/
/* LZX uses what it calls 'position slots' to represent match offsets.
* What this means is that a small 'position slot' number and a small
* offset from that slot are encoded instead of one large offset for
* every match.
* - position_base is an index to the position slot bases
* - extra_bits states how many bits of offset-from-base data is needed.
*/
static const UBYTE extra_bits[51] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17
};
static const ULONG position_base[51] = {
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
1835008, 1966080, 2097152
};
struct LZXstate *LZXinit(int window)
{
struct LZXstate *pState=NULL;
ULONG wndsize = 1 << window;
int i, posn_slots;
/* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
/* if a previously allocated window is big enough, keep it */
if (window < 15 || window > 21) return NULL;
/* allocate state and associated window */
pState = (struct LZXstate *)malloc(sizeof(struct LZXstate));
if (!(pState->window = (UBYTE *)malloc(wndsize)))
{
free(pState);
return NULL;
}
pState->actual_size = wndsize;
pState->window_size = wndsize;
/* calculate required position slots */
if (window == 20) posn_slots = 42;
else if (window == 21) posn_slots = 50;
else posn_slots = window << 1;
/** alternatively **/
/* posn_slots=i=0; while (i < wndsize) i += 1 << extra_bits[posn_slots++]; */
/* initialize other state */
pState->R0 = pState->R1 = pState->R2 = 1;
pState->main_elements = LZX_NUM_CHARS + (posn_slots << 3);
pState->header_read = 0;
pState->frames_read = 0;
pState->block_remaining = 0;
pState->block_type = LZX_BLOCKTYPE_INVALID;
pState->intel_curpos = 0;
pState->intel_started = 0;
pState->window_posn = 0;
/* initialise tables to 0 (because deltas will be applied to them) */
for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) pState->MAINTREE_len[i] = 0;
for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) pState->LENGTH_len[i] = 0;
return pState;
}
void LZXteardown(struct LZXstate *pState)
{
if (pState)
{
if (pState->window)
free(pState->window);
free(pState);
}
}
int LZXreset(struct LZXstate *pState)
{
int i;
pState->R0 = pState->R1 = pState->R2 = 1;
pState->header_read = 0;
pState->frames_read = 0;
pState->block_remaining = 0;
pState->block_type = LZX_BLOCKTYPE_INVALID;
pState->intel_curpos = 0;
pState->intel_started = 0;
pState->window_posn = 0;
for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY; i++) pState->MAINTREE_len[i] = 0;
for (i = 0; i < LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY; i++) pState->LENGTH_len[i] = 0;
return DECR_OK;
}
/* Bitstream reading macros:
*
* INIT_BITSTREAM should be used first to set up the system
* READ_BITS(var,n) takes N bits from the buffer and puts them in var
*
* ENSURE_BITS(n) ensures there are at least N bits in the bit buffer
* PEEK_BITS(n) extracts (without removing) N bits from the bit buffer
* REMOVE_BITS(n) removes N bits from the bit buffer
*
* These bit access routines work by using the area beyond the MSB and the
* LSB as a free source of zeroes. This avoids having to mask any bits.
* So we have to know the bit width of the bitbuffer variable. This is
* sizeof(ULONG) * 8, also defined as ULONG_BITS
*/
/* number of bits in ULONG. Note: This must be at multiple of 16, and at
* least 32 for the bitbuffer code to work (ie, it must be able to ensure
* up to 17 bits - that's adding 16 bits when there's one bit left, or
* adding 32 bits when there are no bits left. The code should work fine
* for machines where ULONG >= 32 bits.
*/
#define ULONG_BITS (sizeof(ULONG)<<3)
#define INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0)
#define ENSURE_BITS(n) \
while (bitsleft < (n)) { \
bitbuf |= ((inpos[1]<<8)|inpos[0]) << (ULONG_BITS-16 - bitsleft); \
bitsleft += 16; inpos+=2; \
}
#define PEEK_BITS(n) (bitbuf >> (ULONG_BITS - (n)))
#define REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n)))
#define READ_BITS(v,n) do { \
ENSURE_BITS(n); \
(v) = PEEK_BITS(n); \
REMOVE_BITS(n); \
} while (0)
/* Huffman macros */
#define TABLEBITS(tbl) (LZX_##tbl##_TABLEBITS)
#define MAXSYMBOLS(tbl) (LZX_##tbl##_MAXSYMBOLS)
#define SYMTABLE(tbl) (pState->tbl##_table)
#define LENTABLE(tbl) (pState->tbl##_len)
/* BUILD_TABLE(tablename) builds a huffman lookup table from code lengths.
* In reality, it just calls make_decode_table() with the appropriate
* values - they're all fixed by some #defines anyway, so there's no point
* writing each call out in full by hand.
*/
#define BUILD_TABLE(tbl) \
if (make_decode_table( \
MAXSYMBOLS(tbl), TABLEBITS(tbl), LENTABLE(tbl), SYMTABLE(tbl) \
)) { return DECR_ILLEGALDATA; }
/* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the
* bitstream using the stated table and puts it in var.
*/
#define READ_HUFFSYM(tbl,var) do { \
ENSURE_BITS(16); \
hufftbl = SYMTABLE(tbl); \
if ((i = hufftbl[PEEK_BITS(TABLEBITS(tbl))]) >= MAXSYMBOLS(tbl)) { \
j = 1 << (ULONG_BITS - TABLEBITS(tbl)); \
do { \
j >>= 1; i <<= 1; i |= (bitbuf & j) ? 1 : 0; \
if (!j) { return DECR_ILLEGALDATA; } \
} while ((i = hufftbl[i]) >= MAXSYMBOLS(tbl)); \
} \
j = LENTABLE(tbl)[(var) = i]; \
REMOVE_BITS(j); \
} while (0)
/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
* first to last in the given table. The code lengths are stored in their
* own special LZX way.
*/
#define READ_LENGTHS(tbl,first,last) do { \
lb.bb = bitbuf; lb.bl = bitsleft; lb.ip = inpos; \
if (lzx_read_lens(pState, LENTABLE(tbl),(first),(last),&lb)) { \
return DECR_ILLEGALDATA; \
} \
bitbuf = lb.bb; bitsleft = lb.bl; inpos = lb.ip; \
} while (0)
/* make_decode_table(nsyms, nbits, length[], table[])
*
* This function was coded by David Tritscher. It builds a fast huffman
* decoding table out of just a canonical huffman code lengths table.
*
* nsyms = total number of symbols in this huffman tree.
* nbits = any symbols with a code length of nbits or less can be decoded
* in one lookup of the table.
* length = A table to get code lengths from [0 to syms-1]
* table = The table to fill up with decoded symbols and pointers.
*
* Returns 0 for OK or 1 for error
*/
static int make_decode_table(ULONG nsyms, ULONG nbits, UBYTE *length, UWORD *table) {
register UWORD sym;
register ULONG leaf;
register UBYTE bit_num = 1;
ULONG fill;
ULONG pos = 0; /* the current position in the decode table */
ULONG table_mask = 1 << nbits;
ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */
ULONG next_symbol = bit_mask; /* base of allocation for long codes */
/* fill entries for codes short enough for a direct mapping */
while (bit_num <= nbits) {
for (sym = 0; sym < nsyms; sym++) {
if (length[sym] == bit_num) {
leaf = pos;
if((pos += bit_mask) > table_mask) return 1; /* table overrun */
/* fill all possible lookups of this symbol with the symbol itself */
fill = bit_mask;
while (fill-- > 0) table[leaf++] = sym;
}
}
bit_mask >>= 1;
bit_num++;
}
/* if there are any codes longer than nbits */
if (pos != table_mask) {
/* clear the remainder of the table */
for (sym = pos; sym < table_mask; sym++) table[sym] = 0;
/* give ourselves room for codes to grow by up to 16 more bits */
pos <<= 16;
table_mask <<= 16;
bit_mask = 1 << 15;
while (bit_num <= 16) {
for (sym = 0; sym < nsyms; sym++) {
if (length[sym] == bit_num) {
leaf = pos >> 16;
for (fill = 0; fill < bit_num - nbits; fill++) {
/* if this path hasn't been taken yet, 'allocate' two entries */
if (table[leaf] == 0) {
table[(next_symbol << 1)] = 0;
table[(next_symbol << 1) + 1] = 0;
table[leaf] = next_symbol++;
}
/* follow the path and select either left or right for next bit */
leaf = table[leaf] << 1;
if ((pos >> (15-fill)) & 1) leaf++;
}
table[leaf] = sym;
if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
}
}
bit_mask >>= 1;
bit_num++;
}
}
/* full table? */
if (pos == table_mask) return 0;
/* either erroneous table, or all elements are 0 - let's find out. */
for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
return 0;
}
struct lzx_bits {
ULONG bb;
int bl;
UBYTE *ip;
};
static int lzx_read_lens(struct LZXstate *pState, UBYTE *lens, ULONG first, ULONG last, struct lzx_bits *lb) {
ULONG i,j, x,y;
int z;
register ULONG bitbuf = lb->bb;
register int bitsleft = lb->bl;
UBYTE *inpos = lb->ip;
UWORD *hufftbl;
for (x = 0; x < 20; x++) {
READ_BITS(y, 4);
LENTABLE(PRETREE)[x] = y;
}
BUILD_TABLE(PRETREE);
for (x = first; x < last; ) {
READ_HUFFSYM(PRETREE, z);
if (z == 17) {
READ_BITS(y, 4); y += 4;
while (y--) lens[x++] = 0;
}
else if (z == 18) {
READ_BITS(y, 5); y += 20;
while (y--) lens[x++] = 0;
}
else if (z == 19) {
READ_BITS(y, 1); y += 4;
READ_HUFFSYM(PRETREE, z);
z = lens[x] - z; if (z < 0) z += 17;
while (y--) lens[x++] = z;
}
else {
z = lens[x] - z; if (z < 0) z += 17;
lens[x++] = z;
}
}
lb->bb = bitbuf;
lb->bl = bitsleft;
lb->ip = inpos;
return 0;
}
int LZXdecompress(struct LZXstate *pState, unsigned char *inpos, unsigned char *outpos, int inlen, int outlen) {
UBYTE *endinp = inpos + inlen;
UBYTE *window = pState->window;
UBYTE *runsrc, *rundest;
UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */
ULONG window_posn = pState->window_posn;
ULONG window_size = pState->window_size;
ULONG R0 = pState->R0;
ULONG R1 = pState->R1;
ULONG R2 = pState->R2;
register ULONG bitbuf;
register int bitsleft;
ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */
struct lzx_bits lb; /* used in READ_LENGTHS macro */
int togo = outlen, this_run, main_element, aligned_bits;
int match_length, length_footer, extra, verbatim_bits;
int copy_length;
INIT_BITSTREAM;
/* read header if necessary */
if (!pState->header_read) {
i = j = 0;
READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); }
pState->intel_filesize = (i << 16) | j; /* or 0 if not encoded */
pState->header_read = 1;
}
/* main decoding loop */
while (togo > 0) {
/* last block finished, new block expected */
if (pState->block_remaining == 0) {
if (pState->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) {
if (pState->block_length & 1) inpos++; /* realign bitstream to word */
INIT_BITSTREAM;
}
READ_BITS(pState->block_type, 3);
READ_BITS(i, 16);
READ_BITS(j, 8);
pState->block_remaining = pState->block_length = (i << 8) | j;
switch (pState->block_type) {
case LZX_BLOCKTYPE_ALIGNED:
for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; }
BUILD_TABLE(ALIGNED);
/* rest of aligned header is same as verbatim */
case LZX_BLOCKTYPE_VERBATIM:
READ_LENGTHS(MAINTREE, 0, 256);
READ_LENGTHS(MAINTREE, 256, pState->main_elements);
BUILD_TABLE(MAINTREE);
if (LENTABLE(MAINTREE)[0xE8] != 0) pState->intel_started = 1;
READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
BUILD_TABLE(LENGTH);
break;
case LZX_BLOCKTYPE_UNCOMPRESSED:
pState->intel_started = 1; /* because we can't assume otherwise */
ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */
if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */
R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
break;
default:
return DECR_ILLEGALDATA;
}
}
/* buffer exhaustion check */
if (inpos > endinp) {
/* it's possible to have a file where the next run is less than
* 16 bits in size. In this case, the READ_HUFFSYM() macro used
* in building the tables will exhaust the buffer, so we should
* allow for this, but not allow those accidentally read bits to
* be used (so we check that there are at least 16 bits
* remaining - in this boundary case they aren't really part of
* the compressed data)
*/
if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA;
}
while ((this_run = pState->block_remaining) > 0 && togo > 0) {
if (this_run > togo) this_run = togo;
togo -= this_run;
pState->block_remaining -= this_run;
/* apply 2^x-1 mask */
window_posn &= window_size - 1;
/* runs can't straddle the window wraparound */
if ((window_posn + this_run) > window_size)
return DECR_DATAFORMAT;
switch (pState->block_type) {
case LZX_BLOCKTYPE_VERBATIM:
while (this_run > 0) {
READ_HUFFSYM(MAINTREE, main_element);
if (main_element < LZX_NUM_CHARS) {
/* literal: 0 to LZX_NUM_CHARS-1 */
window[window_posn++] = main_element;
this_run--;
}
else {
/* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
main_element -= LZX_NUM_CHARS;
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
READ_HUFFSYM(LENGTH, length_footer);
match_length += length_footer;
}
match_length += LZX_MIN_MATCH;
match_offset = main_element >> 3;
if (match_offset > 2) {
/* not repeated offset */
if (match_offset != 3) {
extra = extra_bits[match_offset];
READ_BITS(verbatim_bits, extra);
match_offset = position_base[match_offset] - 2 + verbatim_bits;
}
else {
match_offset = 1;
}
/* update repeated offset LRU queue */
R2 = R1; R1 = R0; R0 = match_offset;
}
else if (match_offset == 0) {
match_offset = R0;
}
else if (match_offset == 1) {
match_offset = R1;
R1 = R0; R0 = match_offset;
}
else /* match_offset == 2 */ {
match_offset = R2;
R2 = R0; R0 = match_offset;
}
rundest = window + window_posn;
this_run -= match_length;
/* copy any wrapped around source data */
if (window_posn >= match_offset) {
/* no wrap */
runsrc = rundest - match_offset;
} else {
runsrc = rundest + (window_size - match_offset);
copy_length = match_offset - window_posn;
if (copy_length < match_length) {
match_length -= copy_length;
window_posn += copy_length;
while (copy_length-- > 0) *rundest++ = *runsrc++;
runsrc = window;
}
}
window_posn += match_length;
/* copy match data - no worries about destination wraps */
while (match_length-- > 0) *rundest++ = *runsrc++;
}
}
break;
case LZX_BLOCKTYPE_ALIGNED:
while (this_run > 0) {
READ_HUFFSYM(MAINTREE, main_element);
if (main_element < LZX_NUM_CHARS) {
/* literal: 0 to LZX_NUM_CHARS-1 */
window[window_posn++] = main_element;
this_run--;
}
else {
/* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
main_element -= LZX_NUM_CHARS;
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
READ_HUFFSYM(LENGTH, length_footer);
match_length += length_footer;
}
match_length += LZX_MIN_MATCH;
match_offset = main_element >> 3;
if (match_offset > 2) {
/* not repeated offset */
extra = extra_bits[match_offset];
match_offset = position_base[match_offset] - 2;
if (extra > 3) {
/* verbatim and aligned bits */
extra -= 3;
READ_BITS(verbatim_bits, extra);
match_offset += (verbatim_bits << 3);
READ_HUFFSYM(ALIGNED, aligned_bits);
match_offset += aligned_bits;
}
else if (extra == 3) {
/* aligned bits only */
READ_HUFFSYM(ALIGNED, aligned_bits);
match_offset += aligned_bits;
}
else if (extra > 0) { /* extra==1, extra==2 */
/* verbatim bits only */
READ_BITS(verbatim_bits, extra);
match_offset += verbatim_bits;
}
else /* extra == 0 */ {
/* ??? */
match_offset = 1;
}
/* update repeated offset LRU queue */
R2 = R1; R1 = R0; R0 = match_offset;
}
else if (match_offset == 0) {
match_offset = R0;
}
else if (match_offset == 1) {
match_offset = R1;
R1 = R0; R0 = match_offset;
}
else /* match_offset == 2 */ {
match_offset = R2;
R2 = R0; R0 = match_offset;
}
rundest = window + window_posn;
this_run -= match_length;
/* copy any wrapped around source data */
if (window_posn >= match_offset) {
/* no wrap */
runsrc = rundest - match_offset;
} else {
runsrc = rundest + (window_size - match_offset);
copy_length = match_offset - window_posn;
if (copy_length < match_length) {
match_length -= copy_length;
window_posn += copy_length;
while (copy_length-- > 0) *rundest++ = *runsrc++;
runsrc = window;
}
}
window_posn += match_length;
/* copy match data - no worries about destination wraps */
while (match_length-- > 0) *rundest++ = *runsrc++;
}
}
break;
case LZX_BLOCKTYPE_UNCOMPRESSED:
if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA;
memcpy(window + window_posn, inpos, (size_t) this_run);
inpos += this_run; window_posn += this_run;
break;
default:
return DECR_ILLEGALDATA; /* might as well */
}
}
}
if (togo != 0) return DECR_ILLEGALDATA;
memcpy(outpos, window + ((!window_posn) ? window_size : window_posn) - outlen, (size_t) outlen);
pState->window_posn = window_posn;
pState->R0 = R0;
pState->R1 = R1;
pState->R2 = R2;
/* intel E8 decoding */
if ((pState->frames_read++ < 32768) && pState->intel_filesize != 0) {
if (outlen <= 6 || !pState->intel_started) {
pState->intel_curpos += outlen;
}
else {
UBYTE *data = outpos;
UBYTE *dataend = data + outlen - 10;
LONG curpos = pState->intel_curpos;
LONG filesize = pState->intel_filesize;
LONG abs_off, rel_off;
pState->intel_curpos = curpos + outlen;
while (data < dataend) {
if (*data++ != 0xE8) { curpos++; continue; }
abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
if ((abs_off >= -curpos) && (abs_off < filesize)) {
rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
data[0] = (UBYTE) rel_off;
data[1] = (UBYTE) (rel_off >> 8);
data[2] = (UBYTE) (rel_off >> 16);
data[3] = (UBYTE) (rel_off >> 24);
}
data += 4;
curpos += 5;
}
}
}
return DECR_OK;
}
#ifdef LZX_CHM_TESTDRIVER
int main(int c, char **v)
{
FILE *fin, *fout;
struct LZXstate state;
UBYTE ibuf[16384];
UBYTE obuf[32768];
int ilen, olen;
int status;
int i;
int count=0;
int w = atoi(v[1]);
LZXinit(&state, w);
fout = fopen(v[2], "wb");
for (i=3; i<c; i++)
{
fin = fopen(v[i], "rb");
ilen = fread(ibuf, 1, 16384, fin);
status = LZXdecompress(&state, ibuf, obuf, ilen, 32768);
switch (status)
{
case DECR_OK:
printf("ok\n");
fwrite(obuf, 1, 32768, fout);
break;
case DECR_DATAFORMAT:
printf("bad format\n");
break;
case DECR_ILLEGALDATA:
printf("illegal data\n");
break;
case DECR_NOMEMORY:
printf("no memory\n");
break;
default:
break;
}
fclose(fin);
if (++count == 2)
{
count = 0;
LZXreset(&state);
}
}
fclose(fout);
}
#endif
/* $Id$ */
/***************************************************************************
* lzx.h - LZX decompression routines *
* ------------------- *
* *
* maintainer: Jed Wing <jedwin@ugcs.caltech.edu> *
* source: modified lzx.c from cabextract v0.5 *
* notes: This file was taken from cabextract v0.5, which was, *
* itself, a modified version of the lzx decompression code *
* from unlzx. *
***************************************************************************/
/***************************************************************************
* *
* Copyright(C) Stuart Caie *
* *
* 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. *
* *
***************************************************************************/
#ifndef INCLUDED_LZX_H
#define INCLUDED_LZX_H
/* return codes */
#define DECR_OK (0)
#define DECR_DATAFORMAT (1)
#define DECR_ILLEGALDATA (2)
#define DECR_NOMEMORY (3)
/* opaque state structure */
struct LZXstate;
/* create an lzx state object */
struct LZXstate *LZXinit(int window);
/* destroy an lzx state object */
void LZXteardown(struct LZXstate *pState);
/* reset an lzx stream */
int LZXreset(struct LZXstate *pState);
/* decompress an LZX compressed block */
int LZXdecompress(struct LZXstate *pState,
unsigned char *inpos,
unsigned char *outpos,
int inlen,
int outlen);
#endif /* INCLUDED_LZX_H */
/*
* ITSS Moniker implementation
*
* Copyright 2004 Mike McCormack
*
* Implementation of the infamous mk:@MSITStore moniker
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "ole2.h"
#include "itss.h"
#include "uuids.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(itss);
/*****************************************************************************/
typedef struct {
IMonikerVtbl *vtbl_ITS_IMoniker;
DWORD ref;
LPWSTR szHtml;
WCHAR szFile[1];
} ITS_IMonikerImpl;
/*** IUnknown methods ***/
static HRESULT WINAPI ITS_IMonikerImpl_QueryInterface(
IMoniker* iface,
REFIID riid,
void** ppvObject)
{
ICOM_THIS(ITS_IMonikerImpl,iface);
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IParseDisplayName))
{
IClassFactory_AddRef(iface);
*ppvObject = This;
return S_OK;
}
WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
return E_NOINTERFACE;
}
static ULONG WINAPI ITS_IMonikerImpl_AddRef(
IMoniker* iface)
{
ICOM_THIS(ITS_IMonikerImpl,iface);
TRACE("%p\n", This);
return ++(This->ref);
}
static ULONG WINAPI ITS_IMonikerImpl_Release(
IMoniker* iface)
{
ICOM_THIS(ITS_IMonikerImpl,iface);
ULONG ref = --This->ref;
if (ref == 0)
HeapFree(GetProcessHeap(), 0, This);
return ref;
}
/*** IPersist methods ***/
static HRESULT WINAPI ITS_IMonikerImpl_GetClassID(
IMoniker* iface,
CLSID* pClassID)
{
ICOM_THIS(ITS_IMonikerImpl,iface);
TRACE("%p %p\n", This, pClassID);
memcpy( pClassID, &CLSID_ITStorage, sizeof (CLSID) );
return S_OK;
}
/*** IPersistStream methods ***/
static HRESULT WINAPI ITS_IMonikerImpl_IsDirty(
IMoniker* iface)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_Load(
IMoniker* iface,
IStream* pStm)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_Save(
IMoniker* iface,
IStream* pStm,
BOOL fClearDirty)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_GetSizeMax(
IMoniker* iface,
ULARGE_INTEGER* pcbSize)
{
FIXME("\n");
return E_NOTIMPL;
}
/*** IMoniker methods ***/
static HRESULT WINAPI ITS_IMonikerImpl_BindToObject(
IMoniker* iface,
IBindCtx* pbc,
IMoniker* pmkToLeft,
REFIID riidResult,
void** ppvResult)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_BindToStorage(
IMoniker* iface,
IBindCtx* pbc,
IMoniker* pmkToLeft,
REFIID riid,
void** ppvObj)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_Reduce(
IMoniker* iface,
IBindCtx* pbc,
DWORD dwReduceHowFar,
IMoniker** ppmkToLeft,
IMoniker** ppmkReduced)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_ComposeWith(
IMoniker* iface,
IMoniker* pmkRight,
BOOL fOnlyIfNotGeneric,
IMoniker** ppmkComposite)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_Enum(
IMoniker* iface,
BOOL fForward,
IEnumMoniker** ppenumMoniker)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_IsEqual(
IMoniker* iface,
IMoniker* pmkOtherMoniker)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_Hash(
IMoniker* iface,
DWORD* pdwHash)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_IsRunning(
IMoniker* iface,
IBindCtx* pbc,
IMoniker* pmkToLeft,
IMoniker* pmkNewlyRunning)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_GetTimeOfLastChange(
IMoniker* iface,
IBindCtx* pbc,
IMoniker* pmkToLeft,
FILETIME* pFileTime)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_Inverse(
IMoniker* iface,
IMoniker** ppmk)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_CommonPrefixWith(
IMoniker* iface,
IMoniker* pmkOther,
IMoniker** ppmkPrefix)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_RelativePathTo(
IMoniker* iface,
IMoniker* pmkOther,
IMoniker** ppmkRelPath)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_GetDisplayName(
IMoniker* iface,
IBindCtx* pbc,
IMoniker* pmkToLeft,
LPOLESTR* ppszDisplayName)
{
ICOM_THIS(ITS_IMonikerImpl,iface);
static const WCHAR szFormat[] = {
'm','s','-','i','t','s',':','%','s',':',':','%','s',0 };
DWORD len = sizeof szFormat / sizeof(WCHAR);
LPWSTR str;
TRACE("%p %p %p %p\n", iface, pbc, pmkToLeft, ppszDisplayName);
len = strlenW( This->szFile ) + strlenW( This->szHtml );
str = CoTaskMemAlloc( len*sizeof(WCHAR) );
sprintfW( str, szFormat, This->szFile, This->szHtml );
*ppszDisplayName = str;
return S_OK;
}
static HRESULT WINAPI ITS_IMonikerImpl_ParseDisplayName(
IMoniker* iface,
IBindCtx* pbc,
IMoniker* pmkToLeft,
LPOLESTR pszDisplayName,
ULONG* pchEaten,
IMoniker** ppmkOut)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITS_IMonikerImpl_IsSystemMoniker(
IMoniker* iface,
DWORD* pdwMksys)
{
FIXME("\n");
return E_NOTIMPL;
}
static IMonikerVtbl ITS_IMonikerImpl_Vtbl =
{
ITS_IMonikerImpl_QueryInterface,
ITS_IMonikerImpl_AddRef,
ITS_IMonikerImpl_Release,
ITS_IMonikerImpl_GetClassID,
ITS_IMonikerImpl_IsDirty,
ITS_IMonikerImpl_Load,
ITS_IMonikerImpl_Save,
ITS_IMonikerImpl_GetSizeMax,
ITS_IMonikerImpl_BindToObject,
ITS_IMonikerImpl_BindToStorage,
ITS_IMonikerImpl_Reduce,
ITS_IMonikerImpl_ComposeWith,
ITS_IMonikerImpl_Enum,
ITS_IMonikerImpl_IsEqual,
ITS_IMonikerImpl_Hash,
ITS_IMonikerImpl_IsRunning,
ITS_IMonikerImpl_GetTimeOfLastChange,
ITS_IMonikerImpl_Inverse,
ITS_IMonikerImpl_CommonPrefixWith,
ITS_IMonikerImpl_RelativePathTo,
ITS_IMonikerImpl_GetDisplayName,
ITS_IMonikerImpl_ParseDisplayName,
ITS_IMonikerImpl_IsSystemMoniker
};
static HRESULT ITS_IMoniker_create( IMoniker **ppObj, LPWSTR name, DWORD n )
{
ITS_IMonikerImpl *itsmon;
DWORD sz;
/* szFile[1] has space for one character already */
sz = sizeof(ITS_IMonikerImpl) + strlenW( name )*sizeof(WCHAR);
itsmon = HeapAlloc( GetProcessHeap(), 0, sz );
itsmon->vtbl_ITS_IMoniker = &ITS_IMonikerImpl_Vtbl;
itsmon->ref = 1;
strcpyW( itsmon->szFile, name );
itsmon->szHtml = &itsmon->szFile[n];
while( *itsmon->szHtml == ':' )
*itsmon->szHtml++ = 0;
TRACE("-> %p %s %s\n", itsmon,
debugstr_w(itsmon->szFile), debugstr_w(itsmon->szHtml) );
*ppObj = (IMoniker*) itsmon;
return S_OK;
}
/*****************************************************************************/
typedef struct {
IParseDisplayNameVtbl *vtbl_ITS_IParseDisplayName;
DWORD ref;
} ITS_IParseDisplayNameImpl;
static HRESULT WINAPI ITS_IParseDisplayNameImpl_QueryInterface(
IParseDisplayName* iface,
REFIID riid,
void** ppvObject)
{
ICOM_THIS(ITS_IParseDisplayNameImpl,iface);
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IParseDisplayName))
{
IClassFactory_AddRef(iface);
*ppvObject = This;
return S_OK;
}
WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
return E_NOINTERFACE;
}
static ULONG WINAPI ITS_IParseDisplayNameImpl_AddRef(
IParseDisplayName* iface)
{
ICOM_THIS(ITS_IParseDisplayNameImpl,iface);
TRACE("%p\n", This);
return ++(This->ref);
}
static ULONG WINAPI ITS_IParseDisplayNameImpl_Release(
IParseDisplayName* iface)
{
ICOM_THIS(ITS_IParseDisplayNameImpl,iface);
ULONG ref = --This->ref;
if (ref == 0)
HeapFree(GetProcessHeap(), 0, This);
return ref;
}
static HRESULT WINAPI ITS_IParseDisplayNameImpl_ParseDisplayName(
IParseDisplayName *iface,
IBindCtx * pbc,
LPOLESTR pszDisplayName,
ULONG * pchEaten,
IMoniker ** ppmkOut)
{
static const WCHAR szPrefix[] = {
'@','M','S','I','T','S','t','o','r','e',':',0 };
const DWORD prefix_len = (sizeof szPrefix/sizeof szPrefix[0])-1;
DWORD n;
ICOM_THIS(ITS_IParseDisplayNameImpl,iface);
TRACE("%p %s %p %p\n", This,
debugstr_w( pszDisplayName ), pchEaten, ppmkOut );
if( strncmpW( pszDisplayName, szPrefix, prefix_len ) )
return MK_E_SYNTAX;
/* search backwards for a double colon */
for( n = strlenW( pszDisplayName ) - 3; prefix_len <= n; n-- )
if( ( pszDisplayName[n] == ':' ) && ( pszDisplayName[n+1] == ':' ) )
break;
if( n < prefix_len )
return MK_E_SYNTAX;
if( !pszDisplayName[n+2] )
return MK_E_SYNTAX;
*pchEaten = strlenW( pszDisplayName ) - n - 3;
return ITS_IMoniker_create( ppmkOut,
&pszDisplayName[prefix_len], n-prefix_len );
}
static IParseDisplayNameVtbl ITS_IParseDisplayNameImpl_Vtbl =
{
ITS_IParseDisplayNameImpl_QueryInterface,
ITS_IParseDisplayNameImpl_AddRef,
ITS_IParseDisplayNameImpl_Release,
ITS_IParseDisplayNameImpl_ParseDisplayName
};
HRESULT ITS_IParseDisplayName_create(IUnknown *pUnkOuter, LPVOID *ppObj)
{
ITS_IParseDisplayNameImpl *its;
its = HeapAlloc( GetProcessHeap(), 0, sizeof(ITS_IParseDisplayNameImpl) );
its->vtbl_ITS_IParseDisplayName = &ITS_IParseDisplayNameImpl_Vtbl;
its->ref = 1;
TRACE("-> %p\n", its);
*ppObj = (LPVOID) its;
return S_OK;
}
/*
* ITSS Storage implementation
*
* Copyright 2004 Mike McCormack
*
* see http://bonedaddy.net/pabs3/hhm/#chmspec
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "ole2.h"
#include "uuids.h"
#include "itss.h"
#include "chm_lib.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(itss);
/************************************************************************/
typedef struct _ITSS_IStorageImpl
{
IStorageVtbl *vtbl_IStorage;
DWORD ref;
struct chmFile *chmfile;
WCHAR dir[1];
} ITSS_IStorageImpl;
struct enum_info
{
struct enum_info *next, *prev;
struct chmUnitInfo ui;
};
typedef struct _IEnumSTATSTG_Impl
{
IEnumSTATSTGVtbl *vtbl_IEnumSTATSTG;
DWORD ref;
struct enum_info *first, *last, *current;
} IEnumSTATSTG_Impl;
typedef struct _IStream_Impl
{
IStreamVtbl *vtbl_IStream;
DWORD ref;
ITSS_IStorageImpl *stg;
ULONGLONG addr;
struct chmUnitInfo ui;
} IStream_Impl;
static HRESULT ITSS_create_chm_storage(
struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen );
static IStream_Impl* ITSS_create_stream(
ITSS_IStorageImpl *stg, struct chmUnitInfo *ui );
/************************************************************************/
static HRESULT WINAPI ITSS_IEnumSTATSTG_QueryInterface(
IEnumSTATSTG* iface,
REFIID riid,
void** ppvObject)
{
ICOM_THIS(IEnumSTATSTG_Impl,iface);
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IEnumSTATSTG))
{
IEnumSTATSTG_AddRef(iface);
*ppvObject = This;
return S_OK;
}
WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
return E_NOINTERFACE;
}
static ULONG WINAPI ITSS_IEnumSTATSTG_AddRef(
IEnumSTATSTG* iface)
{
ICOM_THIS(IEnumSTATSTG_Impl,iface);
return ++(This->ref);
}
static ULONG WINAPI ITSS_IEnumSTATSTG_Release(
IEnumSTATSTG* iface)
{
ICOM_THIS(IEnumSTATSTG_Impl,iface);
ULONG ref = --This->ref;
if (ref == 0)
{
while( This->first )
{
struct enum_info *t = This->first->next;
HeapFree( GetProcessHeap(), 0, This->first );
This->first = t;
}
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
static HRESULT WINAPI ITSS_IEnumSTATSTG_Next(
IEnumSTATSTG* iface,
ULONG celt,
STATSTG* rgelt,
ULONG* pceltFetched)
{
ICOM_THIS(IEnumSTATSTG_Impl,iface);
DWORD len, n;
struct enum_info *cur;
TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched );
cur = This->current;
n = 0;
while( (n<celt) && cur)
{
WCHAR *str;
memset( rgelt, 0, sizeof *rgelt );
/* copy the name */
str = cur->ui.path;
if( *str == '/' )
str++;
len = strlenW( str ) + 1;
rgelt->pwcsName = CoTaskMemAlloc( len*sizeof(WCHAR) );
strcpyW( rgelt->pwcsName, str );
/* determine the type */
if( rgelt->pwcsName[len-2] == '/' )
{
rgelt->pwcsName[len-2] = 0;
rgelt->type = STGTY_STORAGE;
}
else
rgelt->type = STGTY_STREAM;
/* copy the size */
rgelt->cbSize.QuadPart = cur->ui.length;
/* advance to the next item if it exists */
n++;
cur = cur->next;
}
This->current = cur;
*pceltFetched = n;
if( n < celt )
return S_FALSE;
return S_OK;
}
static HRESULT WINAPI ITSS_IEnumSTATSTG_Skip(
IEnumSTATSTG* iface,
ULONG celt)
{
ICOM_THIS(IEnumSTATSTG_Impl,iface);
DWORD n;
struct enum_info *cur;
TRACE("%p %lu\n", This, celt );
cur = This->current;
n = 0;
while( (n<celt) && cur)
{
n++;
cur = cur->next;
}
This->current = cur;
if( n < celt )
return S_FALSE;
return S_OK;
}
static HRESULT WINAPI ITSS_IEnumSTATSTG_Reset(
IEnumSTATSTG* iface)
{
ICOM_THIS(IEnumSTATSTG_Impl,iface);
TRACE("%p\n", This );
This->current = This->first;
return S_OK;
}
static HRESULT WINAPI ITSS_IEnumSTATSTG_Clone(
IEnumSTATSTG* iface,
IEnumSTATSTG** ppenum)
{
FIXME("\n");
return E_NOTIMPL;
}
struct IEnumSTATSTGVtbl IEnumSTATSTG_vtbl =
{
ITSS_IEnumSTATSTG_QueryInterface,
ITSS_IEnumSTATSTG_AddRef,
ITSS_IEnumSTATSTG_Release,
ITSS_IEnumSTATSTG_Next,
ITSS_IEnumSTATSTG_Skip,
ITSS_IEnumSTATSTG_Reset,
ITSS_IEnumSTATSTG_Clone
};
static IEnumSTATSTG_Impl *ITSS_create_enum( void )
{
IEnumSTATSTG_Impl *stgenum;
stgenum = HeapAlloc( GetProcessHeap(), 0, sizeof (IEnumSTATSTG_Impl) );
stgenum->vtbl_IEnumSTATSTG = &IEnumSTATSTG_vtbl;
stgenum->ref = 1;
stgenum->first = NULL;
stgenum->last = NULL;
stgenum->current = NULL;
TRACE(" -> %p\n", stgenum );
return stgenum;
}
/************************************************************************/
HRESULT WINAPI ITSS_IStorageImpl_QueryInterface(
IStorage* iface,
REFIID riid,
void** ppvObject)
{
ICOM_THIS(ITSS_IStorageImpl,iface);
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IStorage))
{
IStorage_AddRef(iface);
*ppvObject = This;
return S_OK;
}
WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
return E_NOINTERFACE;
}
ULONG WINAPI ITSS_IStorageImpl_AddRef(
IStorage* iface)
{
ICOM_THIS(ITSS_IStorageImpl,iface);
return ++(This->ref);
}
ULONG WINAPI ITSS_IStorageImpl_Release(
IStorage* iface)
{
ICOM_THIS(ITSS_IStorageImpl,iface);
ULONG ref = --This->ref;
if (ref == 0)
{
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
HRESULT WINAPI ITSS_IStorageImpl_CreateStream(
IStorage* iface,
LPCOLESTR pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
IStream** ppstm)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_OpenStream(
IStorage* iface,
LPCOLESTR pwcsName,
void* reserved1,
DWORD grfMode,
DWORD reserved2,
IStream** ppstm)
{
ICOM_THIS(ITSS_IStorageImpl,iface);
IStream_Impl *stm;
DWORD len;
struct chmUnitInfo ui;
int r;
WCHAR *path;
TRACE("%p %s %p %lu %lu %p\n", This, debugstr_w(pwcsName),
reserved1, grfMode, reserved2, ppstm );
len = strlenW( This->dir ) + strlenW( pwcsName ) + 1;
path = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
strcpyW( path, This->dir );
strcatW( path, pwcsName );
r = chm_resolve_object(This->chmfile, path, &ui);
HeapFree( GetProcessHeap(), 0, path );
if( r != CHM_RESOLVE_SUCCESS )
return STG_E_FILENOTFOUND;
stm = ITSS_create_stream( This, &ui );
if( !stm )
return E_FAIL;
*ppstm = (IStream*) stm;
return S_OK;
}
HRESULT WINAPI ITSS_IStorageImpl_CreateStorage(
IStorage* iface,
LPCOLESTR pwcsName,
DWORD grfMode,
DWORD dwStgFmt,
DWORD reserved2,
IStorage** ppstg)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_OpenStorage(
IStorage* iface,
LPCOLESTR pwcsName,
IStorage* pstgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstg)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_CopyTo(
IStorage* iface,
DWORD ciidExclude,
const IID* rgiidExclude,
SNB snbExclude,
IStorage* pstgDest)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_MoveElementTo(
IStorage* iface,
LPCOLESTR pwcsName,
IStorage* pstgDest,
LPCOLESTR pwcsNewName,
DWORD grfFlags)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_Commit(
IStorage* iface,
DWORD grfCommitFlags)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_Revert(
IStorage* iface)
{
FIXME("\n");
return E_NOTIMPL;
}
static int ITSS_chm_enumerator(
struct chmFile *h,
struct chmUnitInfo *ui,
void *context)
{
struct enum_info *info;
IEnumSTATSTG_Impl* stgenum = context;
TRACE("adding %s to enumeration\n", debugstr_w(ui->path) );
info = HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info) );
memcpy( &info->ui, ui, sizeof info->ui );
info->next = NULL;
info->prev = stgenum->last;
if( stgenum->last )
stgenum->last->next = info;
else
stgenum->first = info;
stgenum->last = info;
return CHM_ENUMERATOR_CONTINUE;
}
HRESULT WINAPI ITSS_IStorageImpl_EnumElements(
IStorage* iface,
DWORD reserved1,
void* reserved2,
DWORD reserved3,
IEnumSTATSTG** ppenum)
{
ICOM_THIS(ITSS_IStorageImpl,iface);
IEnumSTATSTG_Impl* stgenum;
TRACE("%p %ld %p %ld %p\n", This, reserved1, reserved2, reserved3, ppenum );
stgenum = ITSS_create_enum();
if( !stgenum )
return E_FAIL;
chm_enumerate_dir(This->chmfile,
This->dir,
CHM_ENUMERATE_ALL,
ITSS_chm_enumerator,
stgenum );
stgenum->current = stgenum->first;
*ppenum = (IEnumSTATSTG*) stgenum;
return S_OK;
}
HRESULT WINAPI ITSS_IStorageImpl_DestroyElement(
IStorage* iface,
LPCOLESTR pwcsName)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_RenameElement(
IStorage* iface,
LPCOLESTR pwcsOldName,
LPCOLESTR pwcsNewName)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_SetElementTimes(
IStorage* iface,
LPCOLESTR pwcsName,
const FILETIME* pctime,
const FILETIME* patime,
const FILETIME* pmtime)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_SetClass(
IStorage* iface,
REFCLSID clsid)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_SetStateBits(
IStorage* iface,
DWORD grfStateBits,
DWORD grfMask)
{
FIXME("\n");
return E_NOTIMPL;
}
HRESULT WINAPI ITSS_IStorageImpl_Stat(
IStorage* iface,
STATSTG* pstatstg,
DWORD grfStatFlag)
{
FIXME("\n");
return E_NOTIMPL;
}
static IStorageVtbl ITSS_IStorageImpl_Vtbl =
{
ITSS_IStorageImpl_QueryInterface,
ITSS_IStorageImpl_AddRef,
ITSS_IStorageImpl_Release,
ITSS_IStorageImpl_CreateStream,
ITSS_IStorageImpl_OpenStream,
ITSS_IStorageImpl_CreateStorage,
ITSS_IStorageImpl_OpenStorage,
ITSS_IStorageImpl_CopyTo,
ITSS_IStorageImpl_MoveElementTo,
ITSS_IStorageImpl_Commit,
ITSS_IStorageImpl_Revert,
ITSS_IStorageImpl_EnumElements,
ITSS_IStorageImpl_DestroyElement,
ITSS_IStorageImpl_RenameElement,
ITSS_IStorageImpl_SetElementTimes,
ITSS_IStorageImpl_SetClass,
ITSS_IStorageImpl_SetStateBits,
ITSS_IStorageImpl_Stat,
};
static HRESULT ITSS_create_chm_storage(
struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen )
{
ITSS_IStorageImpl *stg;
DWORD len;
TRACE("%p %s\n", chmfile, debugstr_w( dir ) );
len = strlenW( dir ) + 1;
stg = HeapAlloc( GetProcessHeap(), 0,
sizeof (ITSS_IStorageImpl) + len*sizeof(WCHAR) );
stg->vtbl_IStorage = &ITSS_IStorageImpl_Vtbl;
stg->ref = 1;
stg->chmfile = chmfile;
strcpyW( stg->dir, dir );
*ppstgOpen = (IStorage*) stg;
return S_OK;
}
HRESULT ITSS_StgOpenStorage(
const WCHAR* pwcsName,
IStorage* pstgPriority,
DWORD grfMode,
SNB snbExclude,
DWORD reserved,
IStorage** ppstgOpen)
{
struct chmFile *chmfile;
static const WCHAR szRoot[] = { '/', 0 };
TRACE("%s\n", debugstr_w(pwcsName) );
chmfile = chm_openW( pwcsName );
if( !chmfile )
return E_FAIL;
return ITSS_create_chm_storage( chmfile, szRoot, ppstgOpen );
}
/************************************************************************/
static HRESULT WINAPI ITSS_IStream_QueryInterface(
IStream* iface,
REFIID riid,
void** ppvObject)
{
ICOM_THIS(IStream_Impl,iface);
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_ISequentialStream)
|| IsEqualGUID(riid, &IID_IStream))
{
IStream_AddRef(iface);
*ppvObject = This;
return S_OK;
}
WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
return E_NOINTERFACE;
}
static ULONG WINAPI ITSS_IStream_AddRef(
IStream* iface)
{
ICOM_THIS(IStream_Impl,iface);
return ++(This->ref);
}
static ULONG WINAPI ITSS_IStream_Release(
IStream* iface)
{
ICOM_THIS(IStream_Impl,iface);
ULONG ref = --This->ref;
if (ref == 0)
{
IStorage_Release( (IStorage*) This->stg );
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
static HRESULT WINAPI ITSS_IStream_Read(
IStream* iface,
void* pv,
ULONG cb,
ULONG* pcbRead)
{
ICOM_THIS(IStream_Impl,iface);
ULONG count;
TRACE("%p %p %lu %p\n", This, pv, cb, pcbRead);
count = chm_retrieve_object(This->stg->chmfile,
&This->ui, pv, This->addr, cb);
This->addr += count;
if( pcbRead )
*pcbRead = count;
return S_OK;
}
static HRESULT WINAPI ITSS_IStream_Write(
IStream* iface,
const void* pv,
ULONG cb,
ULONG* pcbWritten)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITSS_IStream_Seek(
IStream* iface,
LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER* plibNewPosition)
{
ICOM_THIS(IStream_Impl,iface);
LONGLONG newpos;
TRACE("%p %s %lu %p\n", This,
wine_dbgstr_longlong( dlibMove.QuadPart ), dwOrigin, plibNewPosition );
newpos = This->addr;
switch( dwOrigin )
{
case STREAM_SEEK_CUR:
newpos = This->addr + dlibMove.QuadPart;
break;
case STREAM_SEEK_SET:
newpos = dlibMove.QuadPart;
break;
case STREAM_SEEK_END:
newpos = This->ui.length + dlibMove.QuadPart;
break;
}
if( ( newpos < 0 ) || ( newpos > This->ui.length ) )
return STG_E_INVALIDPOINTER;
This->addr = newpos;
if( plibNewPosition )
plibNewPosition->QuadPart = This->addr;
return S_OK;
}
static HRESULT WINAPI ITSS_IStream_SetSize(
IStream* iface,
ULARGE_INTEGER libNewSize)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITSS_IStream_CopyTo(
IStream* iface,
IStream* pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER* pcbRead,
ULARGE_INTEGER* pcbWritten)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITSS_IStream_Commit(
IStream* iface,
DWORD grfCommitFlags)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITSS_IStream_Revert(
IStream* iface)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITSS_IStream_LockRegion(
IStream* iface,
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITSS_IStream_UnlockRegion(
IStream* iface,
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITSS_IStream_Stat(
IStream* iface,
STATSTG* pstatstg,
DWORD grfStatFlag)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI ITSS_IStream_Clone(
IStream* iface,
IStream** ppstm)
{
FIXME("\n");
return E_NOTIMPL;
}
struct IStreamVtbl ITSS_IStream_vtbl =
{
ITSS_IStream_QueryInterface,
ITSS_IStream_AddRef,
ITSS_IStream_Release,
ITSS_IStream_Read,
ITSS_IStream_Write,
ITSS_IStream_Seek,
ITSS_IStream_SetSize,
ITSS_IStream_CopyTo,
ITSS_IStream_Commit,
ITSS_IStream_Revert,
ITSS_IStream_LockRegion,
ITSS_IStream_UnlockRegion,
ITSS_IStream_Stat,
ITSS_IStream_Clone,
};
static IStream_Impl *ITSS_create_stream(
ITSS_IStorageImpl *stg, struct chmUnitInfo *ui )
{
IStream_Impl *stm;
stm = HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl) );
stm->vtbl_IStream = &ITSS_IStream_vtbl;
stm->ref = 1;
stm->addr = 0;
memcpy( &stm->ui, ui, sizeof stm->ui );
stm->stg = stg;
IStorage_AddRef( (IStorage*) stg );
TRACE(" -> %p\n", stm );
return stm;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment