//+---------------------------------------------------------------------------- // File: util.cxx // // Synopsis: // //----------------------------------------------------------------------------- // Includes ------------------------------------------------------------------- #include // 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