Windows2000/private/shell/shlwapi/rcstream.cpp
2020-09-30 17:12:32 +02:00

513 lines
14 KiB
C++

#include "priv.h"
#include <shlwapi.h>
#include "w95wraps.h"
//RC Stream Type
#define RCST_RAW 0
#define RCST_COMPRESSED 1
class CRCStream : public IStream
{
public:
CRCStream(LPCWSTR pcszFileName, int iResID, HRESULT* phres = NULL);
~CRCStream();
public:
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid,void **pv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// ISequentialStream methods (copied from sdk\inc\objidl.h and edited)
STDMETHODIMP Read(void* pv, ULONG cb, ULONG* pcbRead);
STDMETHODIMP Write(const void* pv, ULONG cb, ULONG* pcbWritten) { return E_NOTIMPL; }
// IStream methods (copied from sdk\inc\objidl.h and edited)
STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
ULARGE_INTEGER* plibNewPosition) { return E_NOTIMPL; }
STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize) { return E_NOTIMPL; }
STDMETHODIMP CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead,
ULARGE_INTEGER* pcbWritten) { return E_NOTIMPL; }
STDMETHODIMP Commit(DWORD grfCommitFlags) { return E_NOTIMPL; }
STDMETHODIMP Revert(void) { return E_NOTIMPL; }
STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
DWORD dwLockType) { return E_NOTIMPL; }
STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
DWORD dwLockType) { return E_NOTIMPL; }
STDMETHODIMP Stat(STATSTG* pstatstg, DWORD grfStatFlag) { return E_NOTIMPL; }
STDMETHODIMP Clone(IStream** ppstm) { return E_NOTIMPL; }
private:
STDMETHODIMP CRCStream::Read_RCST_COMPRESSED(void* pv, ULONG cb, ULONG* pcbRead);
STDMETHODIMP CRCStream::Read_RCST_RAW(void* pv, ULONG cb, ULONG* pcbRead);
private:
LONG _cRef;
HINSTANCE _hinstModule;
PBYTE _pbData;
ULONG _cbData;
WORD _wType;
PBYTE _pbPos;
// RCST_COMPRESSED
// UnCompressed data to this point
ULONG _cbUnComp;
// Total data to UnCompress
ULONG _cbTotalUnComp;
BYTE _cbRemain;
};
CRCStream::CRCStream(LPCWSTR pcszFileName, int iResID, HRESULT* phres) : _cRef(1)
{
ASSERT(pcszFileName && *pcszFileName);
HRESULT hres = E_FAIL;
HINSTANCE _hinstModule = LoadLibraryW(pcszFileName);
if (_hinstModule)
{
HRSRC hRsrc = FindResource(_hinstModule, MAKEINTRESOURCE(iResID), RT_RCDATA);
if (hRsrc)
{
HGLOBAL hLoadedRes = LoadResource(_hinstModule, hRsrc);
if (hLoadedRes)
{
_pbData = (PBYTE)LockResource(hLoadedRes);
hres = (_pbData?S_OK:E_OUTOFMEMORY);
int cbResData = SizeofResource(_hinstModule, hRsrc);
// Extract type
WORD* pwType = (WORD*)_pbData;
_wType = *pwType;
_pbData = (PBYTE)(pwType + 1);
switch(_wType)
{
case RCST_RAW:
{
// The first DWORD is the actual size of the blob we've put in the resource
// this needs to be done because RCDATA takes only WORDs and we may need to
// put an odd number of bytes in RCDATA
ASSERT(sizeof(ULONG) == sizeof(DWORD));
DWORD* pdwBuf = (DWORD*)_pbData;
_cbData = *pdwBuf;
_pbData = (PBYTE)(pdwBuf + 1);
_pbPos = _pbData;
break;
}
case RCST_COMPRESSED:
{
ASSERT(sizeof(ULONG) == sizeof(DWORD));
DWORD* pdwBuf = (DWORD*)_pbData;
_cbTotalUnComp = *pdwBuf;
++pdwBuf;
// Get compress file size
_cbData = *pdwBuf;
_pbData = (PBYTE)(pdwBuf + 1);
_pbPos = _pbData;
break;
}
default:
{
hres = E_FAIL;
break;
}
}
}
else
hres = E_OUTOFMEMORY;
}
else
hres = E_INVALIDARG;
}
else
hres = E_INVALIDARG;
if (phres)
*phres = hres;
}
CRCStream::~CRCStream()
{
}
STDMETHODIMP CRCStream::QueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
QITABENT(CRCStream, IStream),
{ 0 },
};
return QISearch(this, (LPCQITAB)qit, riid, ppvObj);
}
STDMETHODIMP_(ULONG) CRCStream::AddRef()
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CRCStream::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
STDMETHODIMP CRCStream::Read(void* pv, ULONG cb, ULONG* pcbRead)
{
ASSERT(pv);
HRESULT hres = E_FAIL;
switch(_wType)
{
case RCST_RAW:
{
hres = Read_RCST_RAW(pv, cb, pcbRead);
break;
}
case RCST_COMPRESSED:
{
hres = Read_RCST_COMPRESSED(pv, cb, pcbRead);
break;
}
default:
{
break;
}
}
return hres;
}
STDMETHODIMP CRCStream::Read_RCST_COMPRESSED(void* pv, ULONG cb, ULONG* pcbRead)
{
HRESULT hres = E_FAIL;
ULONG cbCopy = 0;
if (pv)
{
if (cb > 0)
{
// Is the requested nb of bytes completely fitting in buffer from
// actual position?
if (cb <= (_cbTotalUnComp - _cbUnComp))
{
// Yes
cbCopy = cb;
}
else
{
// No, is there at least one byte to copy?
if (_cbUnComp < _cbTotalUnComp)
{
// Yes
cbCopy = _cbTotalUnComp - _cbUnComp;
}
else
{
// No
ASSERT(_cbUnComp == _cbTotalUnComp);
cbCopy = 0;
}
}
// Is there anything to copy?
if (cbCopy > 0)
{
ULONG cbTmpCopy = cbCopy;
PBYTE pbOut = (PBYTE)pv;
// Yes, copy it and move the position pointer, if appropriate
while (cbTmpCopy)
{
// Do we have a repeated byte?
if (0 != *_pbPos)
{
// Yes, expand it
// e.g.: 0x05, 0x98
// 0x05 : 5 repeated bytes
// 0x98 : the byte that needs to be repeated
PBYTE pbTmpPos = _pbPos;
// Is section already partially expanded?
if (!_cbRemain)
{
// Total number of repeated bytes
_cbRemain = *_pbPos;
}
BYTE cbExpand = 0;
// Is the remaining bytes to expand less than/equal to the
// requested bytes?
if (_cbRemain <= cbTmpCopy)
{
// Yes copy all the repeated bytes
cbExpand = _cbRemain;
cbTmpCopy -= cbExpand;
_cbRemain = 0;
// Next time, go to the next repeated/non-repeated section
_pbPos += 2;
}
else
{
// No, there will be some remaining
// We know cbTmpCopy <= 255, so OK to cast
cbExpand = (BYTE)cbTmpCopy;
cbTmpCopy = 0;
_cbRemain -= cbExpand;
}
// Do the copy
while (cbExpand)
{
*pbOut = *(pbTmpPos + 1);
++pbOut;
--cbExpand;
}
}
else
{
// No, copy the non-repeated bytes as is
// e.g.: 0x00, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05
// 0x00 : non-repeat bytes flag
// 0x05 : there will 5 non repeated bytes
// ... : the non-repeated bytes that need to be copied as is
PBYTE pbTmpPos = _pbPos + 2;
// Is section already partially expanded?
if (!_cbRemain)
{
// No
// Total number of repeated bytes
_cbRemain = *(_pbPos + 1);
}
else
pbTmpPos += *(_pbPos + 1) - _cbRemain ;
BYTE cbExpand = 0;
// Is the remaining bytes to expand less than/equal to the
// requested bytes?
if (_cbRemain <= cbTmpCopy)
{
// Yes copy all the repeated bytes
cbExpand = _cbRemain;
cbTmpCopy -= cbExpand;
_cbRemain = 0;
// Next time, go to the next repeated/non-repeated section
_pbPos += 1 + 1 + (*(_pbPos + 1));
}
else
{
// No, there will be some remaining
// We know cbTmpCopy <= 255, so OK to cast
cbExpand = (BYTE)cbTmpCopy;
cbTmpCopy = 0;
_cbRemain -= cbExpand;
}
// Do the copy
memcpy(pbOut, pbTmpPos, cbExpand);
pbOut += cbExpand;
}
}
}
hres = S_OK;
_cbUnComp += cbCopy;
}
else
{
if (cb == 0)
hres = S_OK;
else
hres = S_FALSE;
}
}
else
hres = STG_E_INVALIDPOINTER;
if (pcbRead)
*pcbRead = cbCopy;
return hres;
}
STDMETHODIMP CRCStream::Read_RCST_RAW(void* pv, ULONG cb, ULONG* pcbRead)
{
HRESULT hres = E_FAIL;
ULONG cbCopy = 0;
if (pv)
{
if (cb > 0)
{
// Is the requested nb of bytes completely fitting in buffer from
// actual position?
if ((_pbPos + cb) <= (_pbData + _cbData))
{
// Yes
cbCopy = cb;
}
else
{
// No, is there at least one byte to copy?
if (_pbPos < (_pbData + _cbData))
{
// Yes
cbCopy = (ULONG)((_pbData + _cbData) - _pbPos);
}
else
{
// No
ASSERT(_pbPos == (_pbData + _cbData));
cbCopy = 0;
}
}
// Is there anything to copy?
if (cbCopy > 0)
{
// Yes, copy it and move the position pointer
memcpy(pv, _pbPos, cbCopy);
_pbPos += cbCopy;
}
hres = S_OK;
}
else
{
if (cb == 0)
hres = S_OK;
else
hres = S_FALSE;
}
}
else
hres = STG_E_INVALIDPOINTER;
if (pcbRead)
*pcbRead = cbCopy;
return hres;
}
STDAPI SHOpenStreamOnRCFromRegValueW(HKEY hkey, LPCWSTR pszSubKey, LPCWSTR pszValue,
IStream** pStream)
{
ASSERT(pStream);
HRESULT hres = E_FAIL;
*pStream = NULL;
HKEY hOpenedKey = NULL;
if (ERROR_SUCCESS == RegOpenKeyExW(hkey, pszSubKey, 0, KEY_QUERY_VALUE, &hOpenedKey))
{
// +20 for the comma and the resource id
WCHAR szModule[MAX_PATH + 20];
WCHAR* pszExpanded = szModule;
DWORD dwModule = ARRAYSIZE(szModule);
DWORD dwType = 0;
LONG lRes = RegQueryValueExW(hOpenedKey, pszValue, NULL, &dwType, (LPBYTE)szModule, &dwModule);
if (ERROR_SUCCESS == lRes)
{
WCHAR szExpanded[MAX_PATH + 20];
// Do we need to expand Env variable?
if (REG_EXPAND_SZ == dwType)
{
// Yes
SHExpandEnvironmentStringsW(szModule, szExpanded, ARRAYSIZE(szExpanded));
pszExpanded = szExpanded;
}
// pszExpanded should now contain something like: TEXT("C:\\WINNT\\SYSTEM32\\shell32.dll,1234")
if (dwRes && pszExpanded && *pszExpanded)
{
int iResID = PathParseIconLocationW(pszExpanded);
// Create the object
*pStream = new CRCStream(pszExpanded, iResID, &hres);
}
}
RegCloseKey(hOpenedKey);
}
return hres;
}
STDAPI SHOpenStreamOnRCFromRegValueA(HKEY hkey, LPCSTR pszSubKey, LPCSTR pszValue,
IStream** pStream)
{
ASSERT(pStream);
*pStream = NULL;
HRESULT hres = E_INVALIDARG;
if (pszSubKey)
{
WCHAR wszSubKey[MAX_PATH];
WCHAR wszValue[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, pszSubKey, -1, wszSubKey, SIZECHARS(wszSubKey));
pszSubKey = (LPCSTR)wszSubKey;
if (pszValue)
{
MultiByteToWideChar(CP_ACP, 0, pszValue, -1, wszValue, SIZECHARS(wszValue));
pszValue = (LPCSTR)wszValue;
}
SHOpenStreamOnRCFromRegValueW(hkey, (LPCWSTR)pszSubKey, (LPCWSTR)pszValue, pStream);
}
return hres;
}