/*++ Copyright (C) Microsoft Corporation, 1998 - 1999 All rights reserved. Module Name: Stream.cxx Abstract: implements TStream class methods Author: Adina Trufinescu (AdinaTru) 4-Nov-1998 Revision History: --*/ #include "precomp.h" #pragma hdrstop #include "stream.hxx" /*++ Title: TStream Routine Description: Initialize the TStream class; note the class is initaliy in an in valid state until a read or write occurs in which case the file handle is created and then the class becomes valid. Arguments: None Return Value: Nothing --*/ TStream:: TStream( IN TString& strFileName ) : m_strFileName(strFileName), m_hFileHandle(INVALID_HANDLE_VALUE), m_dwAccess(0), m_bCreated(FALSE) { m_uliStreamSize.QuadPart = 0; } /*++ Title: ~TStream Routine Description: Releases the stream file handle. Arguments: None Return Value: Nothing --*/ TStream:: ~TStream( VOID ) { if(m_hFileHandle != INVALID_HANDLE_VALUE) { CloseHandle(m_hFileHandle); } } /*++ Title: bValid Routine Description: check class member validity : file handle invalid Arguments: None Return Value: TRUE if class is in a valid state. --*/ BOOL TStream:: bValid( VOID ) { return (m_hFileHandle != INVALID_HANDLE_VALUE); } /*++ Title: Read Routine Description: Reads cb bytes into pv , from current position of file. Number of actual reded bytes stored in pbcRead Arguments: Return Value: The error code from ReadFile API is converted to HRESULT --*/ HRESULT TStream:: Read( VOID *pv, ULONG cb, ULONG *pcbRead ) { TStatusH hr; if(!bValid()) { m_hFileHandle = PCreateFile(&m_dwAccess); if(!bValid()) { hr DBGCHK = E_UNEXPECTED; goto End; } } if(bValid()) { if(pv) { if(!ReadFile( m_hFileHandle, reinterpret_cast(pv), static_cast(cb), reinterpret_cast(pcbRead), NULL)) { *pcbRead = 0; hr DBGCHK = MapWin32ErrorCodeToHRes(GetLastError()); goto End; } hr DBGCHK = ((*pcbRead) == cb) && (*pcbRead != 0 && cb != 0) ? S_OK : E_FAIL; } else { hr DBGCHK = STG_E_INVALIDPOINTER; } } End: return hr; } /*++ Title: Write Routine Description: Writes cb bytes from pv , at current position of file. Number of actual written bytes stored in pcbWritten Arguments: Return Value: The error code from WriteFile API is converted to HRESULT --*/ HRESULT TStream:: Write( VOID const* pv, ULONG cb, ULONG * pcbWritten ) { HRESULT hr = E_UNEXPECTED; if(!bValid()) { m_hFileHandle = PCreateFile(&m_dwAccess); if(!bValid()) { goto End; } } if(bValid()) { if(pv) { if(!WriteFile(m_hFileHandle, static_cast(pv), static_cast(cb), reinterpret_cast(pcbWritten), NULL)) { if (pcbWritten) { *pcbWritten = 0; } hr = MapWin32ErrorCodeToHRes(GetLastError()); } if (pcbWritten) { hr = (*pcbWritten == cb) ? S_OK : hr; } else { hr = STG_E_INVALIDPOINTER; } if(SUCCEEDED(hr)) { DBGMSG( DBG_NONE, ( "TPrnStream::Write OK !!!\n" )); } } else { hr = STG_E_INVALIDPOINTER; } } End: return hr; } /*++ Title: Seek Routine Description: Set stream pointer Arguments: dlibMove - Offset relative to dwOrigin dwOrigin - Specifies the origin for the offset plibNewPosition - Pointer to location containing new seek Return Value: The error code from SetFilePointer API is converted to HRESULT --*/ HRESULT TStream:: Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER * plibNewPosition ) { DWORD dwMoveMethod; DWORD dwCurrentFilePosition ; LONG lDistanceToMoveHigh; TStatusB bStatus; TStatusH hr; DWORD dwError; static const DWORD adwMoveMethode[] = { FILE_BEGIN, FILE_CURRENT, FILE_END, }; dwMoveMethod = adwMoveMethode[dwOrigin]; if(!bValid()) { m_hFileHandle = PCreateFile(&m_dwAccess); if(!bValid()) { hr DBGCHK = E_UNEXPECTED; goto End; } } lDistanceToMoveHigh = dlibMove.HighPart; dwCurrentFilePosition = SetFilePointer( m_hFileHandle, static_cast(dlibMove.LowPart), &lDistanceToMoveHigh, dwMoveMethod ); DBGMSG( DBG_NONE, ( "Seek: Current pos: high %d low %d\n" ,lDistanceToMoveHigh, dwCurrentFilePosition) ); if (dwCurrentFilePosition == 0xFFFFFFFF && (dwError = GetLastError()) != NO_ERROR ) { hr DBGCHK = MapWin32ErrorCodeToHRes(dwError); } else { if(plibNewPosition) { plibNewPosition->HighPart = static_cast(lDistanceToMoveHigh); plibNewPosition->LowPart = dwCurrentFilePosition; } hr DBGNOCHK = S_OK; } End: return hr; } /*++ Title: PCreateFile Routine Description: If file doesn't exists , create it with write / read access If file exists , try open it with read wrire access ; if fail , try to open with read Arguments: pdwAccess - access rights if succeeded , 0 if failed Return Value: The error code from SetFilePointer API is converted to HRESULT --*/ HANDLE TStream:: PCreateFile( OUT LPDWORD pdwAccess ) { HANDLE hFileHandle; DWORD dwAccess; *pdwAccess = 0; // // try to open an existing file with read/write access // dwAccess = GENERIC_WRITE | GENERIC_READ; hFileHandle = CreateFile( m_strFileName, dwAccess, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFileHandle == INVALID_HANDLE_VALUE) { // // if last error is access denied , try to open only with read access // if(GetLastError() == ERROR_ACCESS_DENIED) { dwAccess = GENERIC_READ; hFileHandle = CreateFile( m_strFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else if(GetLastError() == ERROR_FILE_NOT_FOUND) { dwAccess = GENERIC_WRITE | GENERIC_READ; // // if last error was file don't exist , try to create it // hFileHandle = CreateFile( m_strFileName, dwAccess, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); m_bCreated = TRUE; } } if(hFileHandle != INVALID_HANDLE_VALUE) { *pdwAccess = dwAccess; m_uliStreamSize.LowPart = GetFileSize(hFileHandle, &m_uliStreamSize.HighPart); } return hFileHandle; } /*++ Title: DestroyFile Routine Description: If file handle is invalid , it means that file wasn't creaded - return TRUE If file handle is valid , close it and delete file Arguments: None Return Value: TRUE if succeeded --*/ HRESULT TStream:: DestroyFile( VOID ) { TStatusB bStatus; bStatus DBGNOCHK = TRUE; if(m_hFileHandle != INVALID_HANDLE_VALUE) { CloseHandle(m_hFileHandle); m_hFileHandle = INVALID_HANDLE_VALUE; bStatus DBGCHK = DeleteFile(m_strFileName); } return bStatus ? S_OK : MapWin32ErrorCodeToHRes(GetLastError()); } /*++ Title: bSetEndOfFile Routine Description: If file handle is valid , set end of file Needed it for truncating the file in case of overwritting Called at the end of every successfull storing Arguments: None Return Value: TRUE if succeeded --*/ BOOL TStream:: bSetEndOfFile( VOID ) { TStatusB bStatus; bStatus DBGCHK = (m_hFileHandle != INVALID_HANDLE_VALUE); if(bStatus) { bStatus DBGCHK = SetEndOfFile(m_hFileHandle); } return bStatus; } /*++ Title: MapWin32ErrorCodeToHRes Routine Description: maps file error codes to HRESULT errors Arguments: Error value to convert Return Value: Converted error value to an HRESULT Last Error: --*/ HRESULT TStream:: MapWin32ErrorCodeToHRes( IN DWORD dwErrorCode ) { return MAKE_HRESULT( SEVERITY_ERROR, FACILITY_STORAGE, dwErrorCode); }