windows-nt/Source/XPSP1/NT/enduser/stuff/hhctrl/fsclient.cpp
2020-09-26 16:20:57 +08:00

307 lines
7.6 KiB
C++

// Copyright 1997 Microsoft Corporation. All Rights Reserved.
#include "header.h"
#include "fsclient.h"
#include "sitemap.h"
static const UINT CSTREAM_BUF_SIZE = (4 * 1024);
CFSClient::CFSClient()
{
ClearMemory(this, sizeof(CFSClient));
}
CFSClient::CFSClient(CFileSystem* pFS, PCSTR pszSubFile)
{
ClearMemory(this, sizeof(CFSClient));
m_pFS = pFS;
m_fNoDeleteFS = TRUE;
OpenStream(pszSubFile);
}
CFSClient::~CFSClient()
{
if (m_pSubFS)
delete m_pSubFS;
if (m_pFS && !m_fNoDeleteFS)
delete m_pFS;
if (m_pbuf)
lcFree(m_pbuf);
}
BOOL CFSClient::Initialize(PCSTR pszCompiledFile)
{
CStr cszCompiledFile;
PCSTR pszFilePortion = GetCompiledName(pszCompiledFile, &cszCompiledFile);
ASSERT(cszCompiledFile.IsNonEmpty());
ASSERT(!m_pFS);
m_pFS = new CFileSystem;
if (! SUCCEEDED(m_pFS->Init()) )
return FALSE;
if ( !SUCCEEDED(m_pFS->Open((PSTR)cszCompiledFile)) )
{
delete m_pFS;
m_pFS = NULL;
return FALSE;
}
if (pszFilePortion)
return SUCCEEDED(OpenStream(pszFilePortion));
return TRUE;
}
HRESULT CFSClient::OpenStream(PCSTR pszFile, DWORD dwAccess)
{
HRESULT hr;
ASSERT(m_pFS);
if (! m_pFS )
return E_FAIL;
m_pSubFS = new CSubFileSystem(m_pFS);
PSTR pszFileCopy = _strdup(pszFile);
ReplaceEscapes(pszFile, pszFileCopy, ESCAPE_URL);
if (! SUCCEEDED(hr = m_pSubFS->OpenSub(pszFileCopy, dwAccess)) )
{
delete m_pSubFS;
m_pSubFS = NULL;
}
free(pszFileCopy);
return hr;
}
void CFSClient::WriteStorageContents(PCSTR pszRootFolder, OLECHAR* wszFSName)
{
IStorage* pStorage;
HRESULT hr;
BOOL fDoRelease = FALSE;
if (! m_pFS )
return;
if (wszFSName != NULL)
{
IStorage* pStorage2 = m_pFS->GetITStorageDocObj();
HRESULT hr = pStorage2->OpenStorage(wszFSName, NULL, STGM_READ, NULL, 0, &pStorage);
if (!SUCCEEDED(hr))
{
DEBUG_ReportOleError(hr);
return;
}
fDoRelease = TRUE;
}
else
pStorage = m_pFS->GetITStorageDocObj();
IEnumSTATSTG* pEnum;
hr = pStorage->EnumElements(0, NULL, 0, &pEnum);
if (!SUCCEEDED(hr)) {
DEBUG_ReportOleError(hr);
return;
}
STATSTG Stat;
if (GetFileAttributes(pszRootFolder) == HFILE_ERROR) {
// Only ask about creating the root folder
if (!CreateFolder(pszRootFolder))
return;
}
while (GetElementStat(pEnum, &Stat)) {
char szFullPath[MAX_PATH];
CStr cszName(Stat.pwcsName); // convert to Multi-Byte
CoTaskMemFree(GetStatName());
if (cszName.psz[0] == '#' || cszName.psz[0] == '$') {
continue; // we don't decompile system files
}
if (Stat.type == STGTY_STORAGE) {
strcpy(szFullPath, pszRootFolder);
AddTrailingBackslash(szFullPath);
strcat(szFullPath, cszName);
WCHAR wszTemp[MAX_PATH];
wszTemp[0] = NULL;
if (wszFSName)
{
lstrcpyW(wszTemp,wszFSName);
lstrcatW(wszTemp, L"\\");
}
lstrcatW(wszTemp, Stat.pwcsName);
WriteStorageContents(szFullPath, wszTemp);
}
else {
strcpy(szFullPath, pszRootFolder);
AddTrailingBackslash(szFullPath);
strcat(szFullPath, cszName);
HANDLE hf = CreateFile(szFullPath, GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hf == INVALID_HANDLE_VALUE)
continue;
CMem mem(Stat.cbSize.LowPart);
ULONG cbRead;
if (wszFSName) {
CStr cszFsName(wszFSName);
strcpy(szFullPath, cszFsName);
AddTrailingBackslash(szFullPath);
strcat(szFullPath, cszName);
cszName = szFullPath;
}
hr = OpenStream(cszName);
if (SUCCEEDED(hr)) {
hr = Read(mem, Stat.cbSize.LowPart, &cbRead);
DWORD cbWritten;
if (SUCCEEDED(hr))
WriteFile(hf, mem, cbRead, &cbWritten, NULL);
CloseStream();
}
CloseHandle(hf);
if (!SUCCEEDED(hr))
DeleteFile(szFullPath);
}
}
ReleaseObjPtr(pEnum);
if ( fDoRelease )
ReleaseObjPtr(pStorage);
}
ULONG CFSClient::GetElementStat(ULONG nNumber, STATSTG* stat, IEnumSTATSTG* pEnum)
{
ULONG nReturned = 0;
HRESULT hr;
if (pEnum == NULL) {
if (m_pEnum) {
hr = m_pEnum->Next(nNumber, stat, &nReturned);
}
else
hr = S_FALSE;
}
else {
hr = pEnum->Next(nNumber, stat, &nReturned);
}
return (SUCCEEDED(hr) ? nReturned : 0);
}
HRESULT CFSClient::Read(void* pDst, const ULONG cbRead, ULONG* pcbRead)
{
ASSERT(m_pFS);
ASSERT(m_pSubFS);
if (m_cbBuf) { // we've streamed it
*pcbRead = Read((PBYTE) pDst, cbRead);
return S_OK;
}
else
return m_pSubFS->ReadSub(pDst, cbRead, pcbRead);
}
ULONG CFSClient::Read(PBYTE pbDest, ULONG cbBytes)
{
if (!m_cbBuf)
ReadBuf();
if (m_pEndBuf - m_pbuf < m_cbBuf) { // adjust cbBytes for actual remaining size
if (m_pEndBuf - m_pCurBuf < (int) cbBytes)
cbBytes = (ULONG)(m_pEndBuf - m_pCurBuf);
}
if (m_pCurBuf + cbBytes < m_pEndBuf) {
memcpy(pbDest, m_pCurBuf, cbBytes);
m_pCurBuf += cbBytes;
return cbBytes;
}
PBYTE pbDst = (PBYTE) pbDest;
// If destination buffer is larger then our internal buffer, then
// recursively call until we have filled up the destination.
int cbRead = (int)(m_pEndBuf - m_pCurBuf);
memcpy(pbDest, m_pCurBuf, cbRead);
pbDst += cbRead;
if (!m_fEndOfFile)
ReadBuf();
if (m_fEndOfFile)
return cbRead;
return Read(pbDst, cbBytes - cbRead) + cbRead;
}
void CFSClient::ReadBuf(void)
{
ULONG cRead;
if (!m_cbBuf) {
m_cbBuf = CSTREAM_BUF_SIZE; // use constant in case we pull in read-ahead code from CStream
// +2 because we add a zero just past the buffer in case anyone expects strings
m_pbuf = (PBYTE) lcMalloc(CSTREAM_BUF_SIZE);
m_pSubFS->ReadSub(m_pbuf, m_cbBuf, &cRead);
m_pCurBuf = m_pbuf;
m_pEndBuf = m_pbuf + cRead;
m_lFilePos = cRead;
m_lFileBuf = 0;
return;
}
m_pSubFS->ReadSub(m_pbuf, m_cbBuf, &cRead);
m_lFileBuf = m_lFilePos;
m_lFilePos += cRead;
m_pCurBuf = m_pbuf;
m_pEndBuf = m_pbuf + cRead;
if (!cRead)
m_fEndOfFile = TRUE;
}
HRESULT CFSClient::seek(int pos, SEEK_TYPE seek)
{
ASSERT(seek != SK_END); // we don't support this one
if (seek == SK_CUR) // convert to SEEK_SET equivalent
pos = m_lFileBuf + (int)(m_pCurBuf - m_pbuf) + pos;
if (pos >= m_lFileBuf && pos < m_lFilePos) {
m_pCurBuf = m_pbuf + (pos - m_lFileBuf);
if (m_pCurBuf >= m_pEndBuf && m_pEndBuf < m_pbuf + m_cbBuf)
m_fEndOfFile = TRUE;
return S_OK;
}
else {
m_lFileBuf = m_pSubFS->SeekSub(pos, SK_SET);
ULONG cread;
if (FAILED(m_pSubFS->ReadSub(m_pbuf, m_cbBuf, &cread))) {
m_fEndOfFile = TRUE;
return STG_E_READFAULT;
}
m_lFilePos = m_lFileBuf + cread;
m_pCurBuf = m_pbuf;
m_pEndBuf = m_pbuf + cread;
if (cread == 0)
m_fEndOfFile = TRUE;
return S_OK;
}
}
void CFSClient::CloseStream(void)
{
if (m_pSubFS) {
delete m_pSubFS;
m_pSubFS = NULL;
}
if (m_pbuf) {
lcFree(m_pbuf);
m_pbuf = NULL;
m_cbBuf = 0;
}
}