Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1023 lines
23 KiB

//+----------------------------------------------------------------------------
// File: util.cxx
//
// Synopsis:
//
//-----------------------------------------------------------------------------
// Includes -------------------------------------------------------------------
#include <core.hxx>
// Globals --------------------------------------------------------------------
const UCHAR SZ_NEWLINE[] = "\n\r";
//+----------------------------------------------------------------------------
// Function: CopyStream
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT
CopyStream(
IStream * pstmDest,
IStream * pstmSrc,
ULARGE_INTEGER cbCopy,
ULARGE_INTEGER * pcbRead,
ULARGE_INTEGER * pcbWritten)
{
DWORD cb = cbCopy.LowPart;
DWORD cbStep = min(cb, 0xFFFF);
DWORD cbRead, cbWritten;
DWORD cbTotalRead = 0;
DWORD cbTotalWritten = 0;
void * pv = NULL;
HRESULT hr = S_OK;
if (cbCopy.HighPart)
return E_INVALIDARG;
pv = new BYTE[cbStep];
if (!pv)
return E_OUTOFMEMORY;
while (cb)
{
cbRead = min(cbStep, cb);
hr = pstmSrc->Read(pv, cbRead, &cbRead);
if (hr || !cbRead)
break;
cbTotalRead += cbRead;
hr = pstmDest->Write(pv, cbRead, &cbWritten);
if (S_OK != hr)
break;
cbTotalWritten += cbWritten;
if (cbWritten != cbRead)
{
hr = E_UNEXPECTED;
break;
}
cb -= cbRead;
}
if (pcbRead)
{
pcbRead->HighPart = 0;
pcbRead->LowPart = cbTotalRead;
}
if (pcbWritten)
{
pcbWritten->HighPart = 0;
pcbWritten->LowPart = cbTotalWritten;
}
delete [] pv;
return hr;
}
//+----------------------------------------------------------------------------
// Member: Read
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CMemoryStream::Read(
void * pv,
ULONG cb,
ULONG * pcbRead)
{
Assert(_pbData);
Assert(_ibPos <= _cbSize);
cb = min(cb, _cbSize - _ibPos);
::memcpy(pv, _pbData + _ibPos, cb);
_ibPos += cb;
if (pcbRead)
{
*pcbRead = cb;
}
return S_OK;
}
//+----------------------------------------------------------------------------
// Member: Write
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CMemoryStream::Write(
const void * pv,
ULONG cb,
ULONG * pcbWritten)
{
HRESULT hr = S_OK;
Assert(_pbData);
Assert(_ibPos <= _cbSize);
if ((_ibPos + cb) > _cbSize)
{
hr = STG_E_MEDIUMFULL;
goto Cleanup;
}
::memcpy(_pbData + _ibPos, pv, cb);
_ibPos += cb;
Cleanup:
if (pcbWritten)
{
*pcbWritten = (SUCCEEDED(hr) ? cb : 0);
}
return hr;
}
//+----------------------------------------------------------------------------
// Member: Seek
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CMemoryStream::Seek(
LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER * plibNewPosition)
{
LONG ibOffset = (LONG)dlibMove.LowPart;
Assert(_pbData);
// Ensure only 32-bits is in-use
if (!(dlibMove.HighPart == 0 && ibOffset >= 0) &&
!(dlibMove.HighPart == -1 && ibOffset < 0))
return E_INVALIDARG;
switch (dwOrigin)
{
case STREAM_SEEK_SET:
break;
case STREAM_SEEK_CUR:
ibOffset = (LONG)_ibPos + ibOffset;
break;
case STREAM_SEEK_END:
ibOffset = (LONG)_cbSize + ibOffset;
break;
default:
return E_INVALIDARG;
}
// Ensure the new offset is within the correct range
if ((ULONG)ibOffset > _cbSize)
return E_INVALIDARG;
// Store the new offset and return it
_ibPos = (ULONG)ibOffset;
if (plibNewPosition)
{
plibNewPosition->HighPart = 0;
plibNewPosition->LowPart = _ibPos;
}
return S_OK;
}
//+----------------------------------------------------------------------------
// Member: SetSize
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CMemoryStream::SetSize(
ULARGE_INTEGER libNewSize)
{
if (libNewSize.HighPart)
return STG_E_MEDIUMFULL;
if (libNewSize.LowPart <= _cbSize)
{
_cbSize = libNewSize.LowPart;
}
else
{
BYTE * pbData = new BYTE[libNewSize.LowPart];
if (!pbData)
return STG_E_MEDIUMFULL;
if (_pbData && _cbSize)
{
::memcpy(pbData, _pbData, _cbSize);
}
delete [] _pbData;
_cbSize = libNewSize.LowPart;
_pbData = pbData;
}
return S_OK;
}
//+----------------------------------------------------------------------------
// Member: CopyTo
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CMemoryStream::CopyTo(
IStream * pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER * pcbRead,
ULARGE_INTEGER * pcbWritten)
{
if (!pstm)
return STG_E_INVALIDPOINTER;
if (cb.HighPart || ((_ibPos + cb.LowPart) > _cbSize))
return E_INVALIDARG;
Assert(_pbData);
return ::CopyStream(pstm, this, cb, pcbRead, pcbWritten);
}
//+----------------------------------------------------------------------------
// Member: CBufferedStream
//
// Synopsis:
//
//-----------------------------------------------------------------------------
CBufferedStream::CBufferedStream(
IStream * pstm,
ULONG cbNewLine,
BOOL fRead)
{
Assert(_pstm);
_fRead = fRead;
_pb = NULL;
_cb = 0;
_ib = 0;
_cbLine = 0;
_cbNewLine = cbNewLine;
_cbTotal = 0;
_pstm = ::SAddRef(pstm);
}
//+----------------------------------------------------------------------------
// Member: ~CBufferedStream
//
// Synopsis:
//
//-----------------------------------------------------------------------------
CBufferedStream::~CBufferedStream()
{
Verify(SUCCEEDED(Flush()));
::SRelease(_pstm);
delete [] _pb;
}
//+----------------------------------------------------------------------------
// Member: Flush
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT
CBufferedStream::Flush(
ULONG * pcbWritten)
{
ULONG cbWritten;
HRESULT hr = S_OK;
Assert(_pstm);
Implies(_cbNewLine, _ib <= (_cb + CB_NEWLINE));
Implies(!_cbNewLine, _ib <= _cb);
if (!pcbWritten)
{
pcbWritten = &cbWritten;
}
*pcbWritten = 0;
// For read-only streams, "read" the rest of the buffer by setting the buffer index
// (This will force a re-load during the next read)
if (_fRead)
{
_ib = _cb;
}
// For write-only streams, write the buffer to the stream
else if (_ib)
{
Assert(!_fRead);
hr = _pstm->Write(_pb, _ib, pcbWritten);
_cbTotal += *pcbWritten;
if (S_OK == hr)
{
Assert(*pcbWritten == _ib);
_ib = 0;
}
}
return hr;
}
//+----------------------------------------------------------------------------
// Member: Load
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT
CBufferedStream::Load()
{
HRESULT hr;
Assert(_fRead);
hr = _pstm->Read(_pb, _cb, &_cbTotal);
if (S_OK != hr)
goto Cleanup;
_ib = 0;
Cleanup:
return hr;
}
//+----------------------------------------------------------------------------
// Member: SetBufferSize
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT
CBufferedStream::SetBufferSize(
ULONG cb)
{
// The buffer size cannot be changed once it has been set
// Also, it is illegal to use a zero-sized buffer
if (_pb || !cb)
return E_FAIL;
// Allocate a new buffer of the requested size
// (If the caller requested automatic interjection of NEWLINEs, slightly increase
// allocated buffer; the remembered size will continue to be that which they
// requested)
_pb = new BYTE[cb + (_cbNewLine ? CB_NEWLINE : 0)];
if (!_pb)
return E_OUTOFMEMORY;
_cb = cb;
_ib = (_fRead ? _cb : 0);
return S_OK;
}
//+----------------------------------------------------------------------------
// Member: Read
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CBufferedStream::Read(
void * pv,
ULONG cb,
ULONG * pcbRead)
{
ULONG cbTotalRead;
ULONG cbRead;
HRESULT hr = S_OK;
Assert(_pb);
Assert(_cb);
Assert(_ib <= _cb);
if (!pv)
return E_INVALIDARG;
if (!pcbRead)
{
pcbRead = &cbTotalRead;
}
*pcbRead = 0;
// If bytes remain in the buffer, "read" those first
if (_ib < _cbTotal)
{
cbRead = min(cb, _cbTotal-_ib);
::memcpy(pv, _pb+_ib, cbRead);
_ib += cbRead;
cb -= cbRead;
pv = (void *)(((const BYTE *)pv) + cbRead);
*pcbRead += cbRead;
}
// If bytes remain to be read, fetch them now
if (cb)
{
Assert(_ib >= _cbTotal);
Assert(_cbTotal <= _cb);
// If the request fits within half of the buffer, then load a buffer full
if (cb < (_cb/2))
{
hr = Load();
if (S_OK != hr)
goto Cleanup;
cbRead = min(cb, _cbTotal);
::memcpy(pv, _pb, cbRead);
_ib = cbRead;
*pcbRead += cbRead;
}
// Otherwise, read directly into the callers buffer
else
{
hr = _pstm->Read(pv, cb, pcbRead);
}
}
Cleanup:
return hr;
}
//+----------------------------------------------------------------------------
// Member: Write
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CBufferedStream::Write(
const void * pv,
ULONG cb,
ULONG * pcbWritten)
{
const BYTE * pbSrc = (const BYTE *)pv;
ULONG ibSrc = 0;
ULONG cbWritten;
HRESULT hr = S_OK;
Assert(_pb);
Assert(_cb);
Assert(_ib <= _cb);
if (!pv)
return E_INVALIDARG;
if (pcbWritten)
{
*pcbWritten = 0;
}
// Treat calls to write on a read-only stream as if the stream is full
if (_fRead)
{
hr = STG_E_MEDIUMFULL;
goto Cleanup;
}
// Write the bytes to the stream
while (cb)
{
// Determine the number of bytes to write this time through
cbWritten = min(cb, _cb-_ib);
if (_cbNewLine)
{
cbWritten = min(cbWritten, _cbNewLine-_cbLine);
}
// Write the bytes to the local buffer
::memcpy(_pb + _ib, pbSrc + ibSrc, cbWritten);
// Update the counters reflecting what has been written
// (Adding a newline if necessary)
cb -= cbWritten;
ibSrc += cbWritten;
_ib += cbWritten;
if (_cbNewLine)
{
_cbLine += cbWritten;
if (_cbLine >= _cbNewLine)
{
::memcpy(_pb + _ib, SZ_NEWLINE, CB_NEWLINE);
_cbLine = 0;
_ib += CB_NEWLINE;
}
}
// If the buffer is full, write it to the stream
if (_ib >= _cb)
{
hr = Flush(&cbWritten);
if (pcbWritten)
{
*pcbWritten += cbWritten;
}
if (S_OK != hr)
goto Cleanup;
}
}
Cleanup:
return hr;
}
//+----------------------------------------------------------------------------
// Member: CFileStream
//
// Synopsis:
//
//-----------------------------------------------------------------------------
CFileStream::CFileStream()
{
_hFile = NULL;
}
//+----------------------------------------------------------------------------
// Member: ~CFileStream
//
// Synopsis:
//
//-----------------------------------------------------------------------------
CFileStream::~CFileStream()
{
if (_hFile)
{
::CloseHandle(_hFile);
}
}
//+----------------------------------------------------------------------------
// Member: Init
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT
CFileStream::Init(
LPCWSTR wszFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES pSecurityAttributes,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
int len = WideCharToMultiByte(CP_ACP, 0, wszFileName, -1, 0, 0, NULL, NULL);
LPSTR psz = new CHAR[len];
if (psz)
{
if (::WideCharToMultiByte(CP_ACP, 0, wszFileName, -1, (LPSTR)psz, len, NULL, NULL))
{
_hFile = ::CreateFileA(psz, dwDesiredAccess, dwShareMode, pSecurityAttributes,
dwCreationDistribution, dwFlagsAndAttributes, hTemplateFile);
}
delete [] psz;
}
else
{
return E_OUTOFMEMORY;
}
// CreateFile succeeded if we didn't get back INVALID_HANDLE_VALUE
return ((_hFile != INVALID_HANDLE_VALUE)
? S_OK
: GetWin32Hresult());
}
//+----------------------------------------------------------------------------
// Member: GetFileSize
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT
CFileStream::GetFileSize(
ULONG * pcbSize)
{
Assert(_hFile);
Assert(pcbSize);
*pcbSize = ::GetFileSize(_hFile, NULL);
return (*pcbSize == 0xFFFFFFFF
? GetWin32Hresult()
: S_OK);
}
//+----------------------------------------------------------------------------
// Member: Read
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CFileStream::Read(
void * pv,
ULONG cb,
ULONG * pcbRead)
{
ULONG cbRead;
HRESULT hr = S_OK;
if (!pv)
return E_INVALIDARG;
if (!pcbRead)
{
pcbRead = &cbRead;
}
hr = (::ReadFile(_hFile, pv, cb, pcbRead, NULL)
? S_OK
: S_FALSE);
return hr;
}
//+----------------------------------------------------------------------------
// Member: Write
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CFileStream::Write(
const void * pv,
ULONG cb,
ULONG * pcbWritten)
{
ULONG cbWritten;
HRESULT hr;
if (!pv)
return E_INVALIDARG;
if (!pcbWritten)
{
pcbWritten = &cbWritten;
}
hr = (::WriteFile(_hFile, pv, cb, pcbWritten, NULL)
? S_OK
: STG_E_MEDIUMFULL);
return hr;
}
//+----------------------------------------------------------------------------
// Member: Seek
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CFileStream::Seek(
LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER * plibNewPosition)
{
DWORD dwMoveMethod;
ULARGE_INTEGER libNewPosition;
HRESULT hr;
if (plibNewPosition)
{
plibNewPosition->HighPart = 0;
plibNewPosition->LowPart = 0;
}
switch(dwOrigin)
{
case STREAM_SEEK_SET: dwMoveMethod = FILE_BEGIN; break;
case STREAM_SEEK_CUR: dwMoveMethod = FILE_CURRENT; break;
case STREAM_SEEK_END: dwMoveMethod = FILE_END; break;
default:
return E_INVALIDARG;
}
libNewPosition.LowPart = ::SetFilePointer(_hFile, dlibMove.LowPart, &dlibMove.HighPart, dwMoveMethod);
libNewPosition.HighPart = dlibMove.HighPart;
if (libNewPosition.LowPart == 0xFFFFFFFF &&
::GetLastError() != NO_ERROR)
{
hr = STG_E_INVALIDPOINTER;
}
else
{
if (plibNewPosition)
{
*plibNewPosition = libNewPosition;
}
hr = S_OK;
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Member: SetSize
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CFileStream::SetSize(
ULARGE_INTEGER libNewSize)
{
LONG curLow, curHigh;
BOOL fEOFSet;
curHigh = 0;
curLow = ::SetFilePointer(_hFile, 0, &curHigh, FILE_CURRENT);
if (0xFFFFFFFF == ::SetFilePointer(_hFile, libNewSize.LowPart,
(LONG *)&libNewSize.HighPart, FILE_BEGIN))
{
return STG_E_INVALIDFUNCTION;
}
fEOFSet = ::SetEndOfFile(_hFile);
#ifdef _DEBUG
Verify(0xFFFFFFFF != ::SetFilePointer(_hFile, curLow, &curHigh, FILE_BEGIN));
#else
::SetFilePointer(_hFile, curLow, &curHigh, FILE_BEGIN);
#endif
return (fEOFSet
? S_OK
: STG_E_MEDIUMFULL);
}
//+----------------------------------------------------------------------------
//
// Member: CopyTo
//
// Synopsis:
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CFileStream::CopyTo(
IStream * pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER * pcbRead,
ULARGE_INTEGER * pcbWritten)
{
if (!pstm)
return STG_E_INVALIDPOINTER;
return ::CopyStream(pstm, this, cb, pcbRead, pcbWritten);
}
//+----------------------------------------------------------------------------
//
// Member: PrivateQueryInterface
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT
CFileStream::PrivateQueryInterface(
REFIID riid,
void ** ppvObj)
{
if (riid == IID_IStream)
*ppvObj = (IStream *)this;
if (*ppvObj)
return S_OK;
else
return parent::PrivateQueryInterface(riid, ppvObj);
}
//+----------------------------------------------------------------------------
// Function: CoAlloc
//
// Synopsis:
//
//-----------------------------------------------------------------------------
void *
CoAlloc(
ULONG cb)
{
Assert(TLS(dll.pmalloc));
return TLS(dll.pmalloc)->Alloc(cb);
}
//+----------------------------------------------------------------------------
// Function: CoFree
//
// Synopsis:
//
//-----------------------------------------------------------------------------
void
CoFree(
void * pv)
{
if (!pv)
return;
Assert(TLS(dll.pmalloc));
Assert(CoDidAlloc(pv));
TLS(dll.pmalloc)->Free(pv);
}
//+----------------------------------------------------------------------------
// Function: CoGetSize
//
// Synopsis:
//
//-----------------------------------------------------------------------------
ULONG
CoGetSize(
void * pv)
{
Assert(TLS(dll.pmalloc));
Assert(CoDidAlloc(pv));
return (ULONG)(TLS(dll.pmalloc)->GetSize(pv));
}
//+----------------------------------------------------------------------------
// Function: CoDidAlloc
//
// Synopsis:
//
//-----------------------------------------------------------------------------
BOOL
CoDidAlloc(
void * pv)
{
Assert(TLS(dll.pmalloc));
return (!pv || TLS(dll.pmalloc)->DidAlloc(pv) == 1
? TRUE
: FALSE);
}
#ifdef _NOCRT
//+----------------------------------------------------------------------------
// Function: purecall
//
// Synopsis: _SHIP build replacement for CRT vtable routine
//
//-----------------------------------------------------------------------------
int __cdecl
_purecall()
{
return 0;
}
//+----------------------------------------------------------------------------
// Function: _tcslen
//
// Synopsis:
//
//-----------------------------------------------------------------------------
extern "C" size_t __cdecl
_tcslen(
const TCHAR * psz)
{
for (size_t i=0; *psz; psz++, i++);
return i;
}
//+----------------------------------------------------------------------------
// Function: memcmp
//
// Synopsis:
//
//-----------------------------------------------------------------------------
extern "C" int __cdecl
memcmp(
const void * pv1,
const void * pv2,
size_t cb)
{
size_t i;
int d;
for (i=0, d=0; i < cb && !d; i++)
d = (*(const BYTE *)pv1) - (*(const BYTE *)pv2);
return d;
}
//+----------------------------------------------------------------------------
// Function: memcpy
//
// Synopsis:
//
//-----------------------------------------------------------------------------
extern "C" void * __cdecl
memcpy(
void * pvDest,
const void * pvSrc,
size_t cb)
{
for (size_t i=0; i < cb; i++)
((BYTE *)pvDest)[i] = ((const BYTE *)pvSrc)[i];
return pvDest;
}
//+----------------------------------------------------------------------------
// Function: memset
//
// Synopsis:
//
//-----------------------------------------------------------------------------
extern "C" void * __cdecl
memset(
void * pv,
int c,
size_t cb)
{
for (size_t i=0; i < cb; i++)
((BYTE *)pv)[i] = (BYTE)c;
return pv;
}
//+----------------------------------------------------------------------------
// Function: memmove
//
// Synopsis:
//
//-----------------------------------------------------------------------------
extern "C" void * __cdecl
memmove(
void * pvDest,
const void * pvSrc,
size_t cb)
{
BYTE * pb1;
BYTE * pb2;
if (pvSrc < pvDest)
{
pb1 = (BYTE *)pvDest + cb;
pb2 = (BYTE *)pvSrc + cb;
for (; cb; cb--)
{
*pb1-- = *pb2--;
}
}
else if (pvSrc > pvDest)
{
pb1 = (BYTE *)pvDest;
pb2 = (BYTE *)pvSrc;
for (; cb; cb--)
{
*pb1++ = *pb2++;
}
}
return pvDest;
}
#endif // _NOCRT