windows-nt/Source/XPSP1/NT/admin/pchealth/client/common/pfcommon/pfstm.cpp
2020-09-26 16:20:57 +08:00

838 lines
19 KiB
C++

/******************************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name:
pchstm.h
Abstract:
This file contains the implementations of various stream objects
Revision History:
created derekm 01/19/00
******************************************************************************/
#include "stdafx.h"
#include "pfstm.h"
/////////////////////////////////////////////////////////////////////////////
// CPFStreamFile- construct / destruct
// **************************************************************************
CPFStreamFile::CPFStreamFile(void)
{
m_hFile = INVALID_HANDLE_VALUE;
m_dwAccess = 0;
}
// **************************************************************************
CPFStreamFile::~CPFStreamFile(void)
{
this->Close();
}
/////////////////////////////////////////////////////////////////////////////
// CPFStreamFile- non interface
// **************************************************************************
HRESULT CPFStreamFile::Open(LPCWSTR szFile, DWORD dwAccess,
DWORD dwDisposition, DWORD dwSharing)
{
USE_TRACING("CPFStreamFile::Open(szFile)");
HRESULT hr = NOERROR;
HANDLE hFile = INVALID_HANDLE_VALUE;
VALIDATEPARM(hr, (szFile == NULL));
if (FAILED(hr))
goto done;
hFile = ::CreateFileW(szFile, dwAccess, dwSharing, NULL, dwDisposition,
FILE_ATTRIBUTE_NORMAL, NULL);
TESTBOOL(hr, (hFile != INVALID_HANDLE_VALUE))
if (FAILED(hr))
goto done;
this->Close();
m_hFile = hFile;
m_dwAccess = dwAccess;
hFile = INVALID_HANDLE_VALUE;
done:
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
return hr;
}
// **************************************************************************
HRESULT CPFStreamFile::Open(HANDLE hFile, DWORD dwAccess)
{
USE_TRACING("CPFStreamFile::Open(hFile)");
HRESULT hr = NOERROR;
HANDLE hFileNew = INVALID_HANDLE_VALUE;
VALIDATEPARM(hr, (hFile == INVALID_HANDLE_VALUE || hFile == NULL));
if (FAILED(hr))
goto done;
TESTBOOL(hr, DuplicateHandle(GetCurrentProcess(), hFile,
GetCurrentProcess(), &hFileNew, dwAccess,
FALSE, 0));
if (FAILED(hr))
goto done;
this->Close();
m_hFile = hFileNew;
m_dwAccess = dwAccess;
hFileNew = INVALID_HANDLE_VALUE;
done:
if (hFileNew != INVALID_HANDLE_VALUE)
CloseHandle(hFileNew);
return hr;
}
// **************************************************************************
HRESULT CPFStreamFile::Close(void)
{
USE_TRACING("CPFStreamFile::Close");
if (m_hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
}
return NOERROR;
}
/////////////////////////////////////////////////////////////////////////////
// CPFStreamFile- ISequentialStream
// **************************************************************************
STDMETHODIMP CPFStreamFile::Read(void *pv, ULONG cb, ULONG *pcbRead)
{
USE_TRACING("CPFStreamFile::Read");
HRESULT hr = NOERROR;
DWORD cbRead;
if (pv == NULL || m_hFile == INVALID_HANDLE_VALUE || m_hFile == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
if (pcbRead != NULL)
*pcbRead = 0;
if (ReadFile(m_hFile, pv, cb, &cbRead, NULL) == FALSE)
{
if (GetLastError() == ERROR_ACCESS_DENIED)
hr = STG_E_ACCESSDENIED;
else
hr = S_FALSE;
goto done;
}
if (cbRead == 0 && cb != 0)
{
hr = S_FALSE;
goto done;
}
if (pcbRead != NULL)
*pcbRead = cbRead;
done:
return hr;
}
// **************************************************************************
STDMETHODIMP CPFStreamFile::Write(const void *pv, ULONG cb, ULONG *pcbWritten)
{
USE_TRACING("CPFStreamFile::Write");
HRESULT hr = NOERROR;
DWORD cbWritten;
if (pv == NULL || m_hFile == INVALID_HANDLE_VALUE || m_hFile == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
if ((m_dwAccess & GENERIC_WRITE) == 0)
{
hr = STG_E_WRITEFAULT;
goto done;
}
if (pcbWritten != NULL)
*pcbWritten = 0;
if (WriteFile(m_hFile, pv, cb, &cbWritten, NULL) == FALSE)
{
switch(GetLastError())
{
case ERROR_DISK_FULL:
hr = STG_E_MEDIUMFULL;
break;
case ERROR_ACCESS_DENIED:
hr = STG_E_ACCESSDENIED;
break;
default:
hr = STG_E_CANTSAVE;
}
goto done;
}
if (pcbWritten != NULL)
*pcbWritten = cbWritten;
done:
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CPFStreamFile- IStream
// **************************************************************************
STDMETHODIMP CPFStreamFile::Seek(LARGE_INTEGER libMove, DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition)
{
USE_TRACING("CPFStreamFile::Seek");
HRESULT hr = NOERROR;
LONG dwHigh, dwLow;
if (m_hFile == INVALID_HANDLE_VALUE || m_hFile == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
if (plibNewPosition != NULL)
{
plibNewPosition->HighPart = 0;
plibNewPosition->LowPart = 0;
}
switch(dwOrigin)
{
default:
case STREAM_SEEK_CUR:
dwOrigin = FILE_CURRENT;
break;
case STREAM_SEEK_SET:
dwOrigin = FILE_BEGIN;
break;
case STREAM_SEEK_END:
dwOrigin = FILE_END;
break;
}
TESTBOOL(hr, SetFilePointerEx(m_hFile, libMove,
(LARGE_INTEGER *)plibNewPosition, dwOrigin));
if (FAILED(hr))
{
hr = STG_E_INVALIDFUNCTION;
goto done;
}
done:
return hr;
}
// **************************************************************************
STDMETHODIMP CPFStreamFile::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
{
USE_TRACING("CPFStreamFile::Seek");
BY_HANDLE_FILE_INFORMATION fi;
HRESULT hr = NOERROR;
if (pstatstg == NULL || m_hFile == INVALID_HANDLE_VALUE ||
m_hFile == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
if (GetFileInformationByHandle(m_hFile, &fi) == FALSE)
{
hr = STG_E_ACCESSDENIED;
goto done;
}
pstatstg->pwcsName = NULL;
pstatstg->type = STGTY_STREAM;
pstatstg->cbSize.HighPart = fi.nFileSizeHigh;
pstatstg->cbSize.LowPart = fi.nFileSizeLow;
pstatstg->mtime = fi.ftCreationTime;
pstatstg->ctime = fi.ftLastAccessTime;
pstatstg->atime = fi.ftLastWriteTime;
pstatstg->clsid = CLSID_NULL;
pstatstg->grfMode = 0;
pstatstg->grfLocksSupported = 0;
pstatstg->grfStateBits = 0;
pstatstg->reserved = 0;
done:
return hr;
}
// **************************************************************************
STDMETHODIMP CPFStreamFile::Clone(IStream **ppstm)
{
USE_TRACING("CPFStreamFile::Clone");
CPFStreamFile *pstm = NULL;
HRESULT hr = NOERROR;
if (ppstm == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
// Create a new stream object.
pstm = CPFStreamFile::CreateInstance();
if (pstm == NULL)
{
hr = STG_E_INSUFFICIENTMEMORY;
goto done;
}
pstm->AddRef();
// intialize it
hr = pstm->Open(m_hFile, m_dwAccess);
if (FAILED(hr))
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
// need to hand back the IStream interface, so...
hr = pstm->QueryInterface(IID_IStream, (LPVOID *)ppstm);
_ASSERT(SUCCEEDED(hr));
pstm = NULL;
done:
if (pstm != NULL)
pstm->Release();
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CPFStreamMem- construct / destruct
// **************************************************************************
CPFStreamMem::CPFStreamMem(void)
{
m_pvData = NULL;
m_pvPtr = NULL;
m_cb = 0;
m_cbRead = 0;
m_cbGrow = 0;
}
// **************************************************************************
CPFStreamMem::~CPFStreamMem(void)
{
this->Clean();
}
/////////////////////////////////////////////////////////////////////////////
// CPFStreamMem- non interface
// **************************************************************************
HRESULT CPFStreamMem::Init(DWORD cbStart, DWORD cbGrowBy)
{
USE_TRACING("CPFStreamMem::Init");
HRESULT hr = NOERROR;
LPVOID pvNew = NULL;
// if the user passes us -1 for either of these, he means 'use default',
// which is the system page size...
if (cbStart == (DWORD)-1 || cbGrowBy == (DWORD)-1)
{
SYSTEM_INFO si;
ZeroMemory(&si, sizeof(si));
GetSystemInfo(&si);
if (cbStart == (DWORD)-1)
cbStart = si.dwPageSize;
if (cbGrowBy == (DWORD)-1)
cbGrowBy = si.dwPageSize;
}
if (cbStart > 0)
{
pvNew = MyAlloc(cbStart);
VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
if (FAILED(hr))
goto done;
}
this->Clean();
m_pvData = pvNew;
m_pvPtr = pvNew;
m_cb = cbStart;
m_cbWrite = 0;
m_cbGrow = cbGrowBy;
pvNew = NULL;
done:
if (pvNew != NULL)
MyFree(pvNew);
return hr;
}
// **************************************************************************
HRESULT CPFStreamMem::InitBinBlob(LPVOID pv, DWORD cb, DWORD cbGrow)
{
USE_TRACING("CPFStreamMem::InitBinBlob");
HRESULT hr = NOERROR;
LPVOID pvNew = NULL;
VALIDATEPARM(hr, (pv == NULL));
if (FAILED(hr))
goto done;
if (cb == 0)
goto done;
pvNew = MyAlloc(cb);
VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
if (FAILED(hr))
goto done;
CopyMemory(pvNew, pv, cb);
this->Clean();
m_pvData = pvNew;
m_pvPtr = pvNew;
m_cb = cb;
m_cbWrite = cb;
m_cbGrow = cbGrow;
pvNew = NULL;
done:
if (pvNew != NULL)
MyFree(pvNew);
return hr;
}
// **************************************************************************
HRESULT CPFStreamMem::InitTextBlob(LPCWSTR wsz, DWORD cch, BOOL fConvertToANSI)
{
USE_TRACING("CPFStreamMem::InitTextBlob(LPCWSTR)");
HRESULT hr = NOERROR;
LPVOID pvNew = NULL;
DWORD cb;
VALIDATEPARM(hr, (wsz == NULL));
if (FAILED(hr))
goto done;
if (cch == 0)
goto done;
if (fConvertToANSI)
{
cb = WideCharToMultiByte(CP_ACP, 0, wsz, -1, NULL, 0, NULL, NULL);
TESTBOOL(hr, (cb != 0));
if (FAILED(hr))
goto done;
pvNew = MyAlloc(cb);
VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
if (FAILED(hr))
goto done;
if (WideCharToMultiByte(CP_ACP, 0, wsz, -1, (LPSTR)pvNew, cb, NULL,
NULL) == 0)
TESTBOOL(hr, (cb != 0));
if (FAILED(hr))
goto done;
}
else
{
// assume cch does NOT include the NULL terminator, so gotta add 1
cb = (cch + 1) * sizeof(WCHAR);
pvNew = MyAlloc(cb);
VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
if (FAILED(hr))
goto done;
CopyMemory(pvNew, wsz, cb);
}
this->Clean();
m_pvData = pvNew;
m_pvPtr = pvNew;
m_cb = cb;
m_cbWrite = cb;
m_cbGrow = 0;
pvNew = NULL;
done:
if (pvNew != NULL)
MyFree(pvNew);
return hr;
}
// **************************************************************************
HRESULT CPFStreamMem::InitTextBlob(LPCSTR sz, DWORD cch, BOOL fConvertToWCHAR)
{
USE_TRACING("CPFStreamMem::InitTextBlob(LPCSTR)");
HRESULT hr = NOERROR;
LPVOID pvNew = NULL;
DWORD cb;
VALIDATEPARM(hr, (sz == NULL));
if (FAILED(hr))
goto done;
if (cch == 0)
goto done;
if (fConvertToWCHAR)
{
cb = MultiByteToWideChar(CP_ACP, 0, sz, -1, NULL, 0);
TESTBOOL(hr, (cb != 0));
if (FAILED(hr))
goto done;
pvNew = MyAlloc(cb);
VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
if (FAILED(hr))
goto done;
cb = MultiByteToWideChar(CP_ACP, 0, sz, -1, (LPWSTR)pvNew, cb);
TESTBOOL(hr, (cb != 0));
if (FAILED(hr))
goto done;
}
else
{
// assume cch does NOT include the NULL terminator, so gotta add 1
cb = cch + 1;
pvNew = MyAlloc(cb);
VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
if (FAILED(hr))
goto done;
CopyMemory(pvNew, sz, cb);
}
this->Clean();
m_pvData = pvNew;
m_pvPtr = pvNew;
m_cb = cb;
m_cbWrite = cb;
m_cbGrow = 0;
pvNew = NULL;
done:
if (pvNew != NULL)
MyFree(pvNew);
return hr;
}
// **************************************************************************
HRESULT CPFStreamMem::Clean(void)
{
USE_TRACING("CPFStreamMem::Clean");
if (m_pvData != NULL)
{
MyFree(m_pvData);
m_pvData = NULL;
m_pvPtr = NULL;
m_cb = 0;
m_cbRead = 0;
m_cbWrite = 0;
m_cbGrow = 0;
}
return NOERROR;
}
/////////////////////////////////////////////////////////////////////////////
// CPFStreamMem- ISequentialStream
// **************************************************************************
STDMETHODIMP CPFStreamMem::Read(void *pv, ULONG cb, ULONG *pcbRead)
{
USE_TRACING("CPFStreamMem::Read");
HRESULT hr = NOERROR;
DWORD cbRead;
if (pv == NULL || m_pvPtr == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
if (pcbRead != NULL)
*pcbRead = 0;
if (m_cbRead >= m_cbWrite)
{
hr = S_FALSE;
goto done;
}
if (m_cbRead + cb > m_cbWrite)
cbRead = m_cbWrite - m_cbRead;
else
cbRead = cb;
CopyMemory(pv, m_pvPtr, cbRead);
m_pvPtr = (LPVOID)((BYTE *)m_pvPtr + cbRead);
m_cbRead += cbRead;
if (pcbRead != NULL)
*pcbRead = cbRead;
done:
return hr;
}
// **************************************************************************
STDMETHODIMP CPFStreamMem::Write(const void *pv, ULONG cb, ULONG *pcbWritten)
{
USE_TRACING("CPFStreamMem::Write");
HRESULT hr = NOERROR;
if (pv == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
if (pcbWritten != NULL)
*pcbWritten = 0;
if (m_cbRead + cb > m_cb)
{
if (m_cbGrow > 0)
{
LPVOID pvNew = NULL, pvPtr;
DWORD cbNew;
cbNew = MyMax(m_cb + m_cbGrow, m_cbRead + cb);
if (m_pvData == NULL)
{
pvNew = MyAlloc(cbNew);
pvPtr = pvNew;
}
else
{
pvNew = MyReAlloc(m_pvData, cbNew);
pvPtr = (LPVOID)((BYTE *)m_pvPtr + m_cbRead);
}
VALIDATEEXPR(hr, (pvNew == NULL), STG_E_MEDIUMFULL);
if (FAILED(hr))
goto done;
m_pvData = pvNew;
m_pvPtr = pvPtr;
}
else
{
hr = STG_E_MEDIUMFULL;
goto done;
}
}
CopyMemory(m_pvPtr, pv, cb);
m_pvPtr = (LPVOID)((BYTE *)m_pvPtr + cb);
m_cbRead += cb;
if (m_cbRead > m_cbWrite)
m_cbWrite = m_cbRead;
if (pcbWritten != NULL)
*pcbWritten = cb;
done:
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CPFStreamFile- IStream
// **************************************************************************
STDMETHODIMP CPFStreamMem::Seek(LARGE_INTEGER libMove, DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition)
{
USE_TRACING("CPFStreamMem::Seek");
HRESULT hr = NOERROR;
LPVOID pvNew;
DWORD cbNew;
if (m_pvPtr == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
if (plibNewPosition != NULL)
{
plibNewPosition->HighPart = 0;
plibNewPosition->LowPart = 0;
}
if (libMove.HighPart != 0 && libMove.HighPart != (DWORD)-1)
{
hr = STG_E_INVALIDFUNCTION;
goto done;
}
switch(dwOrigin)
{
default:
case STREAM_SEEK_CUR:
pvNew = (LPVOID)((BYTE *)m_pvPtr + libMove.LowPart);
cbNew = m_cbRead + libMove.LowPart;
break;
case STREAM_SEEK_SET:
pvNew = (LPVOID)((BYTE *)m_pvData + libMove.LowPart);
cbNew = libMove.LowPart;
break;
case STREAM_SEEK_END:
pvNew = (LPVOID)(((BYTE *)m_pvData + m_cbWrite) - libMove.LowPart);
cbNew = m_cbWrite - libMove.LowPart;
break;
}
if (pvNew < m_pvData || cbNew > m_cbWrite)
{
hr = STG_E_INVALIDFUNCTION;
goto done;
}
m_pvPtr = pvNew;
m_cbRead = cbNew;
if (plibNewPosition != NULL)
plibNewPosition->LowPart = cbNew;
done:
return hr;
}
// **************************************************************************
STDMETHODIMP CPFStreamMem::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
{
USE_TRACING("CPFStreamMem::Stat");
HRESULT hr = NOERROR;
if (pstatstg == NULL || m_pvData == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
ZeroMemory(pstatstg, sizeof(STATSTG));
pstatstg->type = STGTY_STREAM;
pstatstg->cbSize.LowPart = m_cbWrite;
done:
return hr;
}
// **************************************************************************
STDMETHODIMP CPFStreamMem::Clone(IStream **ppstm)
{
USE_TRACING("CPFStreamMem::Clone");
CPFStreamMem *pstm = NULL;
HRESULT hr;
if (ppstm == NULL)
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
// Create a new stream object.
pstm = CPFStreamMem::CreateInstance();
if (pstm == NULL)
{
hr = STG_E_INSUFFICIENTMEMORY;
goto done;
}
pstm->AddRef();
// intialize it
hr = pstm->InitBinBlob(m_pvData, m_cbWrite);
if (FAILED(hr))
{
hr = STG_E_INVALIDPOINTER;
goto done;
}
// need to hand back the IStream interface, so...
hr = pstm->QueryInterface(IID_IStream, (LPVOID *)ppstm);
_ASSERT(SUCCEEDED(hr));
pstm = NULL;
done:
if (pstm != NULL)
pstm->Release();
return hr;
}