/****************************************************************************** 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; }