// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #ifdef AFX_CORE3_SEG #pragma code_seg(AFX_CORE3_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW //////////////////////////////////////////////////////////////////////////// // CMemFile implementation CMemFile::CMemFile(UINT nGrowBytes) { ASSERT(nGrowBytes <= UINT_MAX); m_nGrowBytes = nGrowBytes; m_nPosition = 0; m_nBufferSize = 0; m_nFileSize = 0; m_lpBuffer = NULL; m_bAutoDelete = TRUE; } CMemFile::CMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes) { ASSERT(nGrowBytes <= UINT_MAX); m_nGrowBytes = nGrowBytes; m_nPosition = 0; m_nBufferSize = nBufferSize; m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0; m_lpBuffer = lpBuffer; m_bAutoDelete = FALSE; } void CMemFile::Attach(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes) { ASSERT(m_lpBuffer == NULL); m_nGrowBytes = nGrowBytes; m_nPosition = 0; m_nBufferSize = nBufferSize; m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0; m_lpBuffer = lpBuffer; m_bAutoDelete = FALSE; } BYTE* CMemFile::Detach() { BYTE* lpBuffer = m_lpBuffer; m_lpBuffer = NULL; m_nFileSize = 0; m_nBufferSize = 0; m_nPosition = 0; return lpBuffer; } CMemFile::~CMemFile() { // Close should have already been called, but we check anyway if (m_lpBuffer) Close(); ASSERT(m_lpBuffer == NULL); m_nGrowBytes = 0; m_nPosition = 0; m_nBufferSize = 0; m_nFileSize = 0; } BYTE* CMemFile::Alloc(DWORD nBytes) { return (BYTE*)malloc((UINT)nBytes); } BYTE* CMemFile::Realloc(BYTE* lpMem, DWORD nBytes) { return (BYTE*)realloc(lpMem, (UINT)nBytes); } #pragma intrinsic(memcpy) BYTE* CMemFile::Memcpy(BYTE* lpMemTarget, const BYTE* lpMemSource, UINT nBytes) { ASSERT(lpMemTarget != NULL); ASSERT(lpMemSource != NULL); ASSERT(AfxIsValidAddress(lpMemTarget, nBytes)); ASSERT(AfxIsValidAddress(lpMemSource, nBytes, FALSE)); return (BYTE*)memcpy(lpMemTarget, lpMemSource, nBytes); } #pragma function(memcpy) void CMemFile::Free(BYTE* lpMem) { ASSERT(lpMem != NULL); free(lpMem); } DWORD CMemFile::GetPosition() const { ASSERT_VALID(this); return m_nPosition; } void CMemFile::GrowFile(DWORD dwNewLen) { ASSERT_VALID(this); if (dwNewLen > m_nBufferSize) { // grow the buffer DWORD dwNewBufferSize = (DWORD)m_nBufferSize; // watch out for buffers which cannot be grown! ASSERT(m_nGrowBytes != 0); if (m_nGrowBytes == 0) AfxThrowMemoryException(); // determine new buffer size while (dwNewBufferSize < dwNewLen) dwNewBufferSize += m_nGrowBytes; // allocate new buffer BYTE* lpNew; if (m_lpBuffer == NULL) lpNew = Alloc(dwNewBufferSize); else lpNew = Realloc(m_lpBuffer, dwNewBufferSize); if (lpNew == NULL) AfxThrowMemoryException(); m_lpBuffer = lpNew; m_nBufferSize = dwNewBufferSize; } ASSERT_VALID(this); } void CMemFile::SetLength(DWORD dwNewLen) { ASSERT_VALID(this); if (dwNewLen > m_nBufferSize) GrowFile(dwNewLen); if (dwNewLen < m_nPosition) m_nPosition = dwNewLen; m_nFileSize = dwNewLen; ASSERT_VALID(this); } UINT CMemFile::Read(void* lpBuf, UINT nCount) { ASSERT_VALID(this); if (nCount == 0) return 0; ASSERT(lpBuf != NULL); ASSERT(AfxIsValidAddress(lpBuf, nCount)); if (m_nPosition > m_nFileSize) return 0; UINT nRead; if (m_nPosition + nCount > m_nFileSize) nRead = (UINT)(m_nFileSize - m_nPosition); else nRead = nCount; Memcpy((BYTE*)lpBuf, (BYTE*)m_lpBuffer + m_nPosition, nRead); m_nPosition += nRead; ASSERT_VALID(this); return nRead; } void CMemFile::Write(const void* lpBuf, UINT nCount) { ASSERT_VALID(this); if (nCount == 0) return; ASSERT(lpBuf != NULL); ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE)); if (m_nPosition + nCount > m_nBufferSize) GrowFile(m_nPosition + nCount); ASSERT(m_nPosition + nCount <= m_nBufferSize); Memcpy((BYTE*)m_lpBuffer + m_nPosition, (BYTE*)lpBuf, nCount); m_nPosition += nCount; if (m_nPosition > m_nFileSize) m_nFileSize = m_nPosition; ASSERT_VALID(this); } LONG CMemFile::Seek(LONG lOff, UINT nFrom) { ASSERT_VALID(this); ASSERT(nFrom == begin || nFrom == end || nFrom == current); LONG lNewPos = m_nPosition; if (nFrom == begin) lNewPos = lOff; else if (nFrom == current) lNewPos += lOff; else if (nFrom == end) lNewPos = m_nFileSize + lOff; else return -1; if (lNewPos < 0) AfxThrowFileException(CFileException::badSeek); m_nPosition = lNewPos; ASSERT_VALID(this); return m_nPosition; } void CMemFile::Flush() { ASSERT_VALID(this); } void CMemFile::Close() { ASSERT((m_lpBuffer == NULL && m_nBufferSize == 0) || !m_bAutoDelete || AfxIsValidAddress(m_lpBuffer, (UINT)m_nBufferSize, FALSE)); ASSERT(m_nFileSize <= m_nBufferSize); m_nGrowBytes = 0; m_nPosition = 0; m_nBufferSize = 0; m_nFileSize = 0; if (m_lpBuffer && m_bAutoDelete) Free(m_lpBuffer); m_lpBuffer = NULL; } void CMemFile::Abort() { ASSERT_VALID(this); Close(); } void CMemFile::LockRange(DWORD /* dwPos */, DWORD /* dwCount */) { ASSERT_VALID(this); AfxThrowNotSupportedException(); } void CMemFile::UnlockRange(DWORD /* dwPos */, DWORD /* dwCount */) { ASSERT_VALID(this); AfxThrowNotSupportedException(); } CFile* CMemFile::Duplicate() const { ASSERT_VALID(this); AfxThrowNotSupportedException(); return NULL; } // only CMemFile supports "direct buffering" interaction with CArchive UINT CMemFile::GetBufferPtr(UINT nCommand, UINT nCount, void** ppBufStart, void**ppBufMax) { ASSERT(nCommand == bufferCheck || nCommand == bufferCommit || nCommand == bufferRead || nCommand == bufferWrite); if (nCommand == bufferCheck) return 1; // just a check for direct buffer support if (nCommand == bufferCommit) { // commit buffer ASSERT(ppBufStart == NULL); ASSERT(ppBufMax == NULL); m_nPosition += nCount; if (m_nPosition > m_nFileSize) m_nFileSize = m_nPosition; return 0; } ASSERT(nCommand == bufferWrite || nCommand == bufferRead); ASSERT(ppBufStart != NULL); ASSERT(ppBufMax != NULL); // when storing, grow file as necessary to satisfy buffer request if (nCommand == bufferWrite && m_nPosition + nCount > m_nBufferSize) GrowFile(m_nPosition + nCount); // store buffer max and min *ppBufStart = m_lpBuffer + m_nPosition; // end of buffer depends on whether you are reading or writing if (nCommand == bufferWrite) *ppBufMax = m_lpBuffer + min(m_nBufferSize, m_nPosition + nCount); else { if (nCount == (UINT)-1) nCount = m_nBufferSize - m_nPosition; *ppBufMax = m_lpBuffer + min(m_nFileSize, m_nPosition + nCount); m_nPosition += LPBYTE(*ppBufMax) - LPBYTE(*ppBufStart); } // return number of bytes in returned buffer space (may be <= nCount) return LPBYTE(*ppBufMax) - LPBYTE(*ppBufStart); } ///////////////////////////////////////////////////////////////////////////// // CMemFile diagonstics #ifdef _DEBUG void CMemFile::Dump(CDumpContext& dc) const { CFile::Dump(dc); dc << "m_nFileSize = " << m_nFileSize; dc << "\nm_nBufferSize = " << m_nBufferSize; dc << "\nm_nPosition = " << m_nPosition; dc << "\nm_nGrowBytes = " << m_nGrowBytes; dc << "\n"; } void CMemFile::AssertValid() const { CFile::AssertValid(); ASSERT((m_lpBuffer == NULL && m_nBufferSize == 0) || AfxIsValidAddress(m_lpBuffer, (UINT)m_nBufferSize, FALSE)); ASSERT(m_nFileSize <= m_nBufferSize); // m_nPosition might be after the end of file, so we cannot ASSERT // its validity } #endif // _DEBUG #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif IMPLEMENT_DYNAMIC(CMemFile, CFile) /////////////////////////////////////////////////////////////////////////////