home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / filemem.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-16  |  8.2 KB  |  378 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE3_SEG
  14. #pragma code_seg(AFX_CORE3_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. ////////////////////////////////////////////////////////////////////////////
  25. // CMemFile implementation
  26.  
  27. CMemFile::CMemFile(UINT nGrowBytes)
  28. {
  29.     ASSERT(nGrowBytes <= UINT_MAX);
  30.  
  31.     m_nGrowBytes = nGrowBytes;
  32.     m_nPosition = 0;
  33.     m_nBufferSize = 0;
  34.     m_nFileSize = 0;
  35.     m_lpBuffer = NULL;
  36.     m_bAutoDelete = TRUE;
  37. }
  38.  
  39. CMemFile::CMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes)
  40. {
  41.     ASSERT(nGrowBytes <= UINT_MAX);
  42.  
  43.     m_nGrowBytes = nGrowBytes;
  44.     m_nPosition = 0;
  45.     m_nBufferSize = nBufferSize;
  46.     m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0;
  47.     m_lpBuffer = lpBuffer;
  48.     m_bAutoDelete = FALSE;
  49. }
  50.  
  51. void CMemFile::Attach(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes)
  52. {
  53.     ASSERT(m_lpBuffer == NULL);
  54.  
  55.     m_nGrowBytes = nGrowBytes;
  56.     m_nPosition = 0;
  57.     m_nBufferSize = nBufferSize;
  58.     m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0;
  59.     m_lpBuffer = lpBuffer;
  60.     m_bAutoDelete = FALSE;
  61. }
  62.  
  63. BYTE* CMemFile::Detach()
  64. {
  65.     BYTE* lpBuffer = m_lpBuffer;
  66.     m_lpBuffer = NULL;
  67.     m_nFileSize = 0;
  68.     m_nBufferSize = 0;
  69.     m_nPosition = 0;
  70.  
  71.     return lpBuffer;
  72. }
  73.  
  74. CMemFile::~CMemFile()
  75. {
  76.     // Close should have already been called, but we check anyway
  77.     if (m_lpBuffer)
  78.         Close();
  79.     ASSERT(m_lpBuffer == NULL);
  80.  
  81.     m_nGrowBytes = 0;
  82.     m_nPosition = 0;
  83.     m_nBufferSize = 0;
  84.     m_nFileSize = 0;
  85. }
  86.  
  87. BYTE* CMemFile::Alloc(DWORD nBytes)
  88. {
  89.     return (BYTE*)malloc((UINT)nBytes);
  90. }
  91.  
  92. BYTE* CMemFile::Realloc(BYTE* lpMem, DWORD nBytes)
  93. {
  94.     return (BYTE*)realloc(lpMem, (UINT)nBytes);
  95. }
  96.  
  97. #pragma intrinsic(memcpy)
  98. BYTE* CMemFile::Memcpy(BYTE* lpMemTarget, const BYTE* lpMemSource,
  99.     UINT nBytes)
  100. {
  101.     ASSERT(lpMemTarget != NULL);
  102.     ASSERT(lpMemSource != NULL);
  103.  
  104.     ASSERT(AfxIsValidAddress(lpMemTarget, nBytes));
  105.     ASSERT(AfxIsValidAddress(lpMemSource, nBytes, FALSE));
  106.  
  107.     return (BYTE*)memcpy(lpMemTarget, lpMemSource, nBytes);
  108. }
  109. #pragma function(memcpy)
  110.  
  111. void CMemFile::Free(BYTE* lpMem)
  112. {
  113.     ASSERT(lpMem != NULL);
  114.  
  115.     free(lpMem);
  116. }
  117.  
  118. DWORD CMemFile::GetPosition() const
  119. {
  120.     ASSERT_VALID(this);
  121.     return m_nPosition;
  122. }
  123.  
  124. void CMemFile::GrowFile(DWORD dwNewLen)
  125. {
  126.     ASSERT_VALID(this);
  127.  
  128.     if (dwNewLen > m_nBufferSize)
  129.     {
  130.         // grow the buffer
  131.         DWORD dwNewBufferSize = (DWORD)m_nBufferSize;
  132.  
  133.         // watch out for buffers which cannot be grown!
  134.         ASSERT(m_nGrowBytes != 0);
  135.         if (m_nGrowBytes == 0)
  136.             AfxThrowMemoryException();
  137.  
  138.         // determine new buffer size
  139.         while (dwNewBufferSize < dwNewLen)
  140.             dwNewBufferSize += m_nGrowBytes;
  141.  
  142.         // allocate new buffer
  143.         BYTE* lpNew;
  144.         if (m_lpBuffer == NULL)
  145.             lpNew = Alloc(dwNewBufferSize);
  146.         else
  147.             lpNew = Realloc(m_lpBuffer, dwNewBufferSize);
  148.  
  149.         if (lpNew == NULL)
  150.             AfxThrowMemoryException();
  151.  
  152.         m_lpBuffer = lpNew;
  153.         m_nBufferSize = dwNewBufferSize;
  154.     }
  155.     ASSERT_VALID(this);
  156. }
  157.  
  158. void CMemFile::SetLength(DWORD dwNewLen)
  159. {
  160.     ASSERT_VALID(this);
  161.  
  162.     if (dwNewLen > m_nBufferSize)
  163.         GrowFile(dwNewLen);
  164.  
  165.     if (dwNewLen < m_nPosition)
  166.         m_nPosition = dwNewLen;
  167.  
  168.     m_nFileSize = dwNewLen;
  169.     ASSERT_VALID(this);
  170. }
  171.  
  172. UINT CMemFile::Read(void* lpBuf, UINT nCount)
  173. {
  174.     ASSERT_VALID(this);
  175.  
  176.     if (nCount == 0)
  177.         return 0;
  178.  
  179.     ASSERT(lpBuf != NULL);
  180.     ASSERT(AfxIsValidAddress(lpBuf, nCount));
  181.  
  182.     if (m_nPosition > m_nFileSize)
  183.         return 0;
  184.  
  185.     UINT nRead;
  186.     if (m_nPosition + nCount > m_nFileSize)
  187.         nRead = (UINT)(m_nFileSize - m_nPosition);
  188.     else
  189.         nRead = nCount;
  190.  
  191.     Memcpy((BYTE*)lpBuf, (BYTE*)m_lpBuffer + m_nPosition, nRead);
  192.     m_nPosition += nRead;
  193.  
  194.     ASSERT_VALID(this);
  195.  
  196.     return nRead;
  197. }
  198.  
  199. void CMemFile::Write(const void* lpBuf, UINT nCount)
  200. {
  201.     ASSERT_VALID(this);
  202.  
  203.     if (nCount == 0)
  204.         return;
  205.  
  206.     ASSERT(lpBuf != NULL);
  207.     ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE));
  208.  
  209.     if (m_nPosition + nCount > m_nBufferSize)
  210.         GrowFile(m_nPosition + nCount);
  211.  
  212.     ASSERT(m_nPosition + nCount <= m_nBufferSize);
  213.  
  214.     Memcpy((BYTE*)m_lpBuffer + m_nPosition, (BYTE*)lpBuf, nCount);
  215.  
  216.     m_nPosition += nCount;
  217.  
  218.     if (m_nPosition > m_nFileSize)
  219.         m_nFileSize = m_nPosition;
  220.  
  221.     ASSERT_VALID(this);
  222. }
  223.  
  224. LONG CMemFile::Seek(LONG lOff, UINT nFrom)
  225. {
  226.     ASSERT_VALID(this);
  227.     ASSERT(nFrom == begin || nFrom == end || nFrom == current);
  228.  
  229.     LONG lNewPos = m_nPosition;
  230.  
  231.     if (nFrom == begin)
  232.         lNewPos = lOff;
  233.     else if (nFrom == current)
  234.         lNewPos += lOff;
  235.     else if (nFrom == end)
  236.         lNewPos = m_nFileSize + lOff;
  237.     else
  238.         return -1;
  239.  
  240.     if (lNewPos < 0)
  241.         AfxThrowFileException(CFileException::badSeek);
  242.  
  243.     m_nPosition = lNewPos;
  244.  
  245.     ASSERT_VALID(this);
  246.     return m_nPosition;
  247. }
  248.  
  249. void CMemFile::Flush()
  250. {
  251.     ASSERT_VALID(this);
  252. }
  253.  
  254. void CMemFile::Close()
  255. {
  256.     ASSERT((m_lpBuffer == NULL && m_nBufferSize == 0) ||
  257.         !m_bAutoDelete || AfxIsValidAddress(m_lpBuffer, (UINT)m_nBufferSize, FALSE));
  258.     ASSERT(m_nFileSize <= m_nBufferSize);
  259.  
  260.     m_nGrowBytes = 0;
  261.     m_nPosition = 0;
  262.     m_nBufferSize = 0;
  263.     m_nFileSize = 0;
  264.     if (m_lpBuffer && m_bAutoDelete)
  265.         Free(m_lpBuffer);
  266.     m_lpBuffer = NULL;
  267. }
  268.  
  269. void CMemFile::Abort()
  270. {
  271.     ASSERT_VALID(this);
  272.  
  273.     Close();
  274. }
  275.  
  276. void CMemFile::LockRange(DWORD /* dwPos */, DWORD /* dwCount */)
  277. {
  278.     ASSERT_VALID(this);
  279.     AfxThrowNotSupportedException();
  280. }
  281.  
  282.  
  283. void CMemFile::UnlockRange(DWORD /* dwPos */, DWORD /* dwCount */)
  284. {
  285.     ASSERT_VALID(this);
  286.     AfxThrowNotSupportedException();
  287. }
  288.  
  289. CFile* CMemFile::Duplicate() const
  290. {
  291.     ASSERT_VALID(this);
  292.     AfxThrowNotSupportedException();
  293.     return NULL;
  294. }
  295.  
  296. // only CMemFile supports "direct buffering" interaction with CArchive
  297. UINT CMemFile::GetBufferPtr(UINT nCommand, UINT nCount,
  298.     void** ppBufStart, void**ppBufMax)
  299. {
  300.     ASSERT(nCommand == bufferCheck || nCommand == bufferCommit ||
  301.         nCommand == bufferRead || nCommand == bufferWrite);
  302.  
  303.     if (nCommand == bufferCheck)
  304.         return 1;   // just a check for direct buffer support
  305.  
  306.     if (nCommand == bufferCommit)
  307.     {
  308.         // commit buffer
  309.         ASSERT(ppBufStart == NULL);
  310.         ASSERT(ppBufMax == NULL);
  311.         m_nPosition += nCount;
  312.         if (m_nPosition > m_nFileSize)
  313.             m_nFileSize = m_nPosition;
  314.         return 0;
  315.     }
  316.  
  317.     ASSERT(nCommand == bufferWrite || nCommand == bufferRead);
  318.     ASSERT(ppBufStart != NULL);
  319.     ASSERT(ppBufMax != NULL);
  320.  
  321.     // when storing, grow file as necessary to satisfy buffer request
  322.     if (nCommand == bufferWrite && m_nPosition + nCount > m_nBufferSize)
  323.         GrowFile(m_nPosition + nCount);
  324.  
  325.     // store buffer max and min
  326.     *ppBufStart = m_lpBuffer + m_nPosition;
  327.  
  328.     // end of buffer depends on whether you are reading or writing
  329.     if (nCommand == bufferWrite)
  330.         *ppBufMax = m_lpBuffer + min(m_nBufferSize, m_nPosition + nCount);
  331.     else
  332.     {
  333.         if (nCount == (UINT)-1)
  334.             nCount = m_nBufferSize - m_nPosition;
  335.         *ppBufMax = m_lpBuffer + min(m_nFileSize, m_nPosition + nCount);
  336.         m_nPosition += LPBYTE(*ppBufMax) - LPBYTE(*ppBufStart);
  337.     }
  338.  
  339.     // return number of bytes in returned buffer space (may be <= nCount)
  340.     return LPBYTE(*ppBufMax) - LPBYTE(*ppBufStart);
  341. }
  342.  
  343. /////////////////////////////////////////////////////////////////////////////
  344. // CMemFile diagonstics
  345.  
  346. #ifdef _DEBUG
  347. void CMemFile::Dump(CDumpContext& dc) const
  348. {
  349.     CFile::Dump(dc);
  350.  
  351.     dc << "m_nFileSize = " << m_nFileSize;
  352.     dc << "\nm_nBufferSize = " << m_nBufferSize;
  353.     dc << "\nm_nPosition = " << m_nPosition;
  354.     dc << "\nm_nGrowBytes = " << m_nGrowBytes;
  355.  
  356.     dc << "\n";
  357. }
  358.  
  359. void CMemFile::AssertValid() const
  360. {
  361.     CFile::AssertValid();
  362.  
  363.     ASSERT((m_lpBuffer == NULL && m_nBufferSize == 0) ||
  364.         AfxIsValidAddress(m_lpBuffer, (UINT)m_nBufferSize, FALSE));
  365.     ASSERT(m_nFileSize <= m_nBufferSize);
  366.     // m_nPosition might be after the end of file, so we cannot ASSERT
  367.     // its validity
  368. }
  369. #endif // _DEBUG
  370.  
  371. #ifdef AFX_INIT_SEG
  372. #pragma code_seg(AFX_INIT_SEG)
  373. #endif
  374.  
  375. IMPLEMENT_DYNAMIC(CMemFile, CFile)
  376.  
  377. /////////////////////////////////////////////////////////////////////////////
  378.