home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / arccore.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  21KB  |  843 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. #include <afxtempl.h>
  13.  
  14. #ifdef AFX_CORE2_SEG
  15. #pragma code_seg(AFX_CORE2_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. ////////////////////////////////////////////////////////////////////////////
  26. // Serialize member functions for low level classes put here
  27. // for code swapping improvements
  28.  
  29. #ifdef _AFX_BYTESWAP
  30. CArchive& CArchive::operator<<(WORD w)
  31. {
  32.     if (m_lpBufCur + sizeof(WORD) > m_lpBufMax)
  33.         Flush();
  34.  
  35.     if (!(m_nMode & bNoByteSwap))
  36.         _AfxByteSwap(w, m_lpBufCur);
  37.     else
  38.         *(WORD*)m_lpBufCur = w;
  39.  
  40.     m_lpBufCur += sizeof(WORD);
  41.     return *this;
  42. }
  43.  
  44. CArchive& CArchive::operator<<(LONG l)
  45. {
  46.     ASSERT(sizeof(LONG) == sizeof(DWORD));
  47.     return operator<<((DWORD) l);
  48. }
  49.  
  50. CArchive& CArchive::operator<<(DWORD dw)
  51. {
  52.     if (m_lpBufCur + sizeof(DWORD) > m_lpBufMax)
  53.         Flush();
  54.  
  55.     if (!(m_nMode & bNoByteSwap))
  56.         _AfxByteSwap(dw, m_lpBufCur);
  57.     else
  58.         *(DWORD*)m_lpBufCur = dw;
  59.  
  60.     m_lpBufCur += sizeof(DWORD);
  61.     return *this;
  62. }
  63.  
  64. CArchive& CArchive::operator<<(float f)
  65. {
  66.     if (m_lpBufCur + sizeof(float) > m_lpBufMax)
  67.         Flush();
  68.  
  69.     if (!(m_nMode & bNoByteSwap))
  70.         _AfxByteSwap(f, m_lpBufCur);
  71.     else
  72.         *(_AFXFLOAT*)m_lpBufCur = *(_AFXFLOAT*)&f;
  73.  
  74.     m_lpBufCur += sizeof(float);
  75.     return *this;
  76. }
  77.  
  78. CArchive& CArchive::operator<<(double d)
  79. {
  80.     if (m_lpBufCur + sizeof(double) > m_lpBufMax)
  81.         Flush();
  82.  
  83.     if (!(m_nMode & bNoByteSwap))
  84.         _AfxByteSwap(d, m_lpBufCur);
  85.     else
  86.         *(_AFXDOUBLE*)m_lpBufCur = *(_AFXDOUBLE*)&d;
  87.  
  88.     m_lpBufCur += sizeof(double);
  89.     return *this;
  90. }
  91.  
  92. CArchive& CArchive::operator>>(WORD& w)
  93. {
  94.     if (m_lpBufCur + sizeof(WORD) > m_lpBufMax)
  95.         FillBuffer(sizeof(WORD) - (UINT)(m_lpBufMax - m_lpBufCur));
  96.  
  97.     w = *(WORD*)m_lpBufCur;
  98.     m_lpBufCur += sizeof(WORD);
  99.  
  100.     if (!(m_nMode & bNoByteSwap))
  101.         _AfxByteSwap(w, (BYTE*)&w);
  102.  
  103.     return *this;
  104. }
  105.  
  106. CArchive& CArchive::operator>>(LONG& l)
  107. {
  108.     ASSERT(sizeof(LONG) == sizeof(DWORD));
  109.     return operator>>((DWORD&) l);
  110. }
  111.  
  112. CArchive& CArchive::operator>>(DWORD& dw)
  113. {
  114.     if (m_lpBufCur + sizeof(DWORD) > m_lpBufMax)
  115.         FillBuffer(sizeof(DWORD) - (UINT)(m_lpBufMax - m_lpBufCur));
  116.  
  117.     dw = *(DWORD*)m_lpBufCur;
  118.     m_lpBufCur += sizeof(DWORD);
  119.  
  120.     if (!(m_nMode & bNoByteSwap))
  121.         _AfxByteSwap(dw, (BYTE*)&dw);
  122.  
  123.     return *this;
  124. }
  125.  
  126. CArchive& CArchive::operator>>(float& f)
  127. {
  128.     if (m_lpBufCur + sizeof(float) > m_lpBufMax)
  129.         FillBuffer(sizeof(float) - (UINT)(m_lpBufMax - m_lpBufCur));
  130.  
  131.     *(_AFXFLOAT*)&f = *(_AFXFLOAT*)m_lpBufCur;
  132.     m_lpBufCur += sizeof(float);
  133.  
  134.     if (!(m_nMode & bNoByteSwap))
  135.         _AfxByteSwap(f, (BYTE*)&f);
  136.  
  137.     return *this;
  138. }
  139.  
  140. CArchive& CArchive::operator>>(double& d)
  141. {
  142.     if (m_lpBufCur + sizeof(double) > m_lpBufMax)
  143.         FillBuffer(sizeof(double) - (UINT)(m_lpBufMax - m_lpBufCur));
  144.  
  145.     *(_AFXDOUBLE*)&d = *(_AFXDOUBLE*)m_lpBufCur;
  146.     m_lpBufCur += sizeof(double);
  147.  
  148.     if (!(m_nMode & bNoByteSwap))
  149.         _AfxByteSwap(d, (BYTE*)&d);
  150.  
  151.     return *this;
  152. }
  153. #endif //_AFX_BYTESWAP
  154.  
  155. // CString serialization code
  156. // String format:
  157. //      UNICODE strings are always prefixed by 0xff, 0xfffe
  158. //      if < 0xff chars: len:BYTE, TCHAR chars
  159. //      if >= 0xff characters: 0xff, len:WORD, TCHAR chars
  160. //      if >= 0xfffe characters: 0xff, 0xffff, len:DWORD, TCHARs
  161.  
  162. CArchive& AFXAPI operator<<(CArchive& ar, const CString& string)
  163. {
  164.     // special signature to recognize unicode strings
  165. #ifdef _UNICODE
  166.     ar << (BYTE)0xff;
  167.     ar << (WORD)0xfffe;
  168. #endif
  169.  
  170.     if (string.GetData()->nDataLength < 255)
  171.     {
  172.         ar << (BYTE)string.GetData()->nDataLength;
  173.     }
  174.     else if (string.GetData()->nDataLength < 0xfffe)
  175.     {
  176.         ar << (BYTE)0xff;
  177.         ar << (WORD)string.GetData()->nDataLength;
  178.     }
  179.     else
  180.     {
  181.         ar << (BYTE)0xff;
  182.         ar << (WORD)0xffff;
  183.         ar << (DWORD)string.GetData()->nDataLength;
  184.     }
  185.     ar.Write(string.m_pchData, string.GetData()->nDataLength*sizeof(TCHAR));
  186.     return ar;
  187. }
  188.  
  189. // return string length or -1 if UNICODE string is found in the archive
  190. AFX_STATIC UINT AFXAPI _AfxReadStringLength(CArchive& ar)
  191. {
  192.     DWORD nNewLen;
  193.  
  194.     // attempt BYTE length first
  195.     BYTE bLen;
  196.     ar >> bLen;
  197.  
  198.     if (bLen < 0xff)
  199.         return bLen;
  200.  
  201.     // attempt WORD length
  202.     WORD wLen;
  203.     ar >> wLen;
  204.     if (wLen == 0xfffe)
  205.     {
  206.         // UNICODE string prefix (length will follow)
  207.         return (UINT)-1;
  208.     }
  209.     else if (wLen == 0xffff)
  210.     {
  211.         // read DWORD of length
  212.         ar >> nNewLen;
  213.         return (UINT)nNewLen;
  214.     }
  215.     else
  216.         return wLen;
  217. }
  218.  
  219. CArchive& AFXAPI operator>>(CArchive& ar, CString& string)
  220. {
  221. #ifdef _UNICODE
  222.     int nConvert = 1;   // if we get ANSI, convert
  223. #else
  224.     int nConvert = 0;   // if we get UNICODE, convert
  225. #endif
  226.  
  227.     UINT nNewLen = _AfxReadStringLength(ar);
  228.     if (nNewLen == (UINT)-1)
  229.     {
  230.         nConvert = 1 - nConvert;
  231.         nNewLen = _AfxReadStringLength(ar);
  232.         ASSERT(nNewLen != -1);
  233.     }
  234.  
  235.     // set length of string to new length
  236.     UINT nByteLen = nNewLen;
  237. #ifdef _UNICODE
  238.     string.GetBufferSetLength((int)nNewLen);
  239.     nByteLen += nByteLen * (1 - nConvert);  // bytes to read
  240. #else
  241.     nByteLen += nByteLen * nConvert;    // bytes to read
  242.     if (nNewLen == 0)
  243.         string.GetBufferSetLength(0);
  244.     else
  245.         string.GetBufferSetLength((int)nByteLen+nConvert);
  246. #endif
  247.  
  248.     // read in the characters
  249.     if (nNewLen != 0)
  250.     {
  251.         ASSERT(nByteLen != 0);
  252.  
  253.         // read new data
  254.         if (ar.Read(string.m_pchData, nByteLen) != nByteLen)
  255.             AfxThrowArchiveException(CArchiveException::endOfFile);
  256.  
  257.         // convert the data if as necessary
  258.         if (nConvert != 0)
  259.         {
  260. #ifdef _UNICODE
  261.             CStringData* pOldData = string.GetData();
  262.             LPSTR lpsz = (LPSTR)string.m_pchData;
  263. #else
  264.             CStringData* pOldData = string.GetData();
  265.             LPWSTR lpsz = (LPWSTR)string.m_pchData;
  266. #endif
  267.             lpsz[nNewLen] = '\0';    // must be NUL terminated
  268.             string.Init();   // don't delete the old data
  269.             string = lpsz;   // convert with operator=(LPWCSTR)
  270.             delete[] (BYTE*)pOldData;
  271.         }
  272.     }
  273.     return ar;
  274. }
  275.  
  276. // specialized version of SerializeElements for CString (used in collections)
  277. #if _MSC_VER >= 1100
  278. template <> void AFXAPI SerializeElements<CString> (CArchive& ar, CString* pElements, int nCount)
  279. #else
  280. void AFXAPI SerializeElements(CArchive& ar, CString* pElements, int nCount)
  281. #endif
  282. {
  283.     ASSERT(nCount == 0 ||
  284.         AfxIsValidAddress(pElements, nCount * sizeof(CString)));
  285.  
  286.     if (ar.IsStoring())
  287.     {
  288.         for (; nCount--; ++pElements)
  289.             ar << *pElements;
  290.     }
  291.     else
  292.     {
  293.         for (; nCount--; ++pElements)
  294.             ar >> *pElements;
  295.     }
  296. }
  297.  
  298. // Runtime class serialization code
  299. CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum)
  300.     // loads a runtime class description
  301. {
  302.     WORD nLen;
  303.     char szClassName[64];
  304.     CRuntimeClass* pClass;
  305.  
  306.     WORD wTemp;
  307.     ar >> wTemp; *pwSchemaNum = wTemp;
  308.     ar >> nLen;
  309.  
  310.     if (nLen >= _countof(szClassName) ||
  311.         ar.Read(szClassName, nLen*sizeof(char)) != nLen*sizeof(char))
  312.     {
  313.         return NULL;
  314.     }
  315.     szClassName[nLen] = '\0';
  316.  
  317.     // search app specific classes
  318.     AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
  319.     AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
  320.     for (pClass = pModuleState->m_classList; pClass != NULL;
  321.         pClass = pClass->m_pNextClass)
  322.     {
  323.         if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)
  324.         {
  325.             AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
  326.             return pClass;
  327.         }
  328.     }
  329.     AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
  330. #ifdef _AFXDLL
  331.     // search classes in shared DLLs
  332.     AfxLockGlobals(CRIT_DYNLINKLIST);
  333.     for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
  334.         pDLL = pDLL->m_pNextDLL)
  335.     {
  336.         for (pClass = pDLL->m_classList; pClass != NULL;
  337.             pClass = pClass->m_pNextClass)
  338.         {
  339.             if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)
  340.             {
  341.                 AfxUnlockGlobals(CRIT_DYNLINKLIST);
  342.                 return pClass;
  343.             }
  344.         }
  345.     }
  346.     AfxUnlockGlobals(CRIT_DYNLINKLIST);
  347. #endif
  348.  
  349.     TRACE1("Warning: Cannot load %hs from archive.  Class not defined.\n",
  350.         szClassName);
  351.  
  352.     return NULL; // not found
  353. }
  354.  
  355. void CRuntimeClass::Store(CArchive& ar) const
  356.     // stores a runtime class description
  357. {
  358.     WORD nLen = (WORD)lstrlenA(m_lpszClassName);
  359.     ar << (WORD)m_wSchema << nLen;
  360.     ar.Write(m_lpszClassName, nLen*sizeof(char));
  361. }
  362.  
  363. ////////////////////////////////////////////////////////////////////////////
  364. // Archive object input/output
  365.  
  366. // minimum buffer size
  367. enum { nBufSizeMin = 128 };
  368.  
  369. // default amount to grow m_pLoadArray upon insert
  370. enum { nGrowSize = 64 };
  371. // default size of hash table in m_pStoreMap when storing
  372. enum { nHashSize = 137 };
  373. // default size to grow collision blocks when storing
  374. enum { nBlockSize = 16 };
  375.  
  376. ////////////////////////////////////////////////////////////////////////////
  377.  
  378. CArchive::CArchive(CFile* pFile, UINT nMode, int nBufSize, void* lpBuf) :
  379.     m_strFileName(pFile->GetFilePath())
  380. {
  381.     ASSERT_VALID(pFile);
  382.  
  383.     // initialize members not dependent on allocated buffer
  384.     m_nMode = nMode;
  385.     m_pFile = pFile;
  386.     m_pSchemaMap = NULL;
  387.     m_pLoadArray = NULL;
  388.     m_pDocument = NULL;
  389.     m_bForceFlat = TRUE;
  390.     m_nObjectSchema = (UINT)-1; // start with invalid schema
  391.     if (IsStoring())
  392.         m_nGrowSize = nBlockSize;
  393.     else
  394.         m_nGrowSize = nGrowSize;
  395.     m_nHashSize = nHashSize;
  396.  
  397.     // initialize the buffer.  minimum size is 128
  398.     m_lpBufStart = (BYTE*)lpBuf;
  399.     m_bUserBuf = TRUE;
  400.     m_bDirectBuffer = FALSE;
  401.  
  402.     if (nBufSize < nBufSizeMin)
  403.     {
  404.         // force use of private buffer of minimum size
  405.         m_nBufSize = nBufSizeMin;
  406.         m_lpBufStart = NULL;
  407.     }
  408.     else
  409.         m_nBufSize = nBufSize;
  410.  
  411.     nBufSize = m_nBufSize;
  412.     if (m_lpBufStart == NULL)
  413.     {
  414.         // check for CFile providing buffering support
  415.         m_bDirectBuffer = m_pFile->GetBufferPtr(CFile::bufferCheck);
  416.         if (!m_bDirectBuffer)
  417.         {
  418.             // no support for direct buffering, allocate new buffer
  419.             m_lpBufStart = new BYTE[m_nBufSize];
  420.             m_bUserBuf = FALSE;
  421.         }
  422.         else
  423.         {
  424.             // CFile* supports direct buffering!
  425.             nBufSize = 0;   // will trigger initial FillBuffer
  426.         }
  427.     }
  428.  
  429.     if (!m_bDirectBuffer)
  430.     {
  431.         ASSERT(m_lpBufStart != NULL);
  432.         ASSERT(AfxIsValidAddress(m_lpBufStart, nBufSize, IsStoring()));
  433.     }
  434.     m_lpBufMax = m_lpBufStart + nBufSize;
  435.     m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;
  436.  
  437.     ASSERT(m_pStoreMap == NULL);        // same as m_pLoadArray
  438. }
  439.  
  440. CArchive::~CArchive()
  441. {
  442.     // Close makes m_pFile NULL. If it is not NULL, we must Close the CArchive
  443.     if (m_pFile != NULL && !(m_nMode & bNoFlushOnDelete))
  444.         Close();
  445.  
  446.     Abort();    // abort completely shuts down the archive
  447. }
  448.  
  449. void CArchive::Abort()
  450. {
  451.     ASSERT(m_bDirectBuffer || m_lpBufStart == NULL ||
  452.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, IsStoring()));
  453.     ASSERT(m_bDirectBuffer || m_lpBufCur == NULL ||
  454.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, IsStoring()));
  455.  
  456.     // disconnect from the file
  457.     m_pFile = NULL;
  458.  
  459.     if (!m_bUserBuf)
  460.     {
  461.         ASSERT(!m_bDirectBuffer);
  462.         delete[] m_lpBufStart;
  463.         m_lpBufStart = NULL;
  464.         m_lpBufCur = NULL;
  465.     }
  466.  
  467.     delete m_pSchemaMap;
  468.     m_pSchemaMap = NULL;
  469.  
  470.     // m_pStoreMap and m_pLoadArray are unioned, so we only need to delete one
  471.     ASSERT((CObject*)m_pStoreMap == (CObject*)m_pLoadArray);
  472.     delete (CObject*)m_pLoadArray;
  473.     m_pLoadArray = NULL;
  474. }
  475.  
  476. void CArchive::Close()
  477. {
  478.     ASSERT_VALID(m_pFile);
  479.  
  480.     Flush();
  481.     m_pFile = NULL;
  482. }
  483.  
  484. UINT CArchive::Read(void* lpBuf, UINT nMax)
  485. {
  486.     ASSERT_VALID(m_pFile);
  487.  
  488.     if (nMax == 0)
  489.         return 0;
  490.  
  491.     ASSERT(lpBuf != NULL);
  492.     ASSERT(AfxIsValidAddress(lpBuf, nMax));
  493.     ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  494.     ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  495.     ASSERT(m_lpBufStart == NULL ||
  496.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, FALSE));
  497.     ASSERT(m_lpBufCur == NULL ||
  498.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, FALSE));
  499.     ASSERT(IsLoading());
  500.  
  501.     // try to fill from buffer first
  502.     UINT nMaxTemp = nMax;
  503.     UINT nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));
  504.     memcpy(lpBuf, m_lpBufCur, nTemp);
  505.     m_lpBufCur += nTemp;
  506.     lpBuf = (BYTE*)lpBuf + nTemp;
  507.     nMaxTemp -= nTemp;
  508.  
  509.     if (nMaxTemp != 0)
  510.     {
  511.         ASSERT(m_lpBufCur == m_lpBufMax);
  512.  
  513.         // read rest in buffer size chunks
  514.         nTemp = nMaxTemp - (nMaxTemp % m_nBufSize);
  515.         UINT nRead = 0;
  516.  
  517.         UINT nLeft = nTemp;
  518.         UINT nBytes;
  519.         do
  520.         {
  521.             nBytes = m_pFile->Read(lpBuf, nLeft);
  522.             lpBuf = (BYTE*)lpBuf + nBytes;
  523.             nRead += nBytes;
  524.             nLeft -= nBytes;
  525.         }
  526.         while ((nBytes > 0) && (nLeft > 0));
  527.  
  528.         nMaxTemp -= nRead;
  529.  
  530.         // read last chunk into buffer then copy
  531.         if (nRead == nTemp)
  532.         {
  533.             ASSERT(m_lpBufCur == m_lpBufMax);
  534.             ASSERT(nMaxTemp < (UINT)m_nBufSize);
  535.  
  536.             // fill buffer (similar to CArchive::FillBuffer, but no exception)
  537.             if (!m_bDirectBuffer)
  538.             {
  539.                 UINT nLeft = max(nMaxTemp, (UINT)m_nBufSize);
  540.                 UINT nBytes;
  541.                 BYTE* lpTemp = m_lpBufStart;
  542.                 nRead = 0;
  543.                 do
  544.                 {
  545.                     nBytes = m_pFile->Read(lpTemp, nLeft);
  546.                     lpTemp = lpTemp + nBytes;
  547.                     nRead += nBytes;
  548.                     nLeft -= nBytes;
  549.                 }
  550.                 while ((nBytes > 0) && (nLeft > 0) && nRead < nMaxTemp);
  551.  
  552.                 m_lpBufCur = m_lpBufStart;
  553.                 m_lpBufMax = m_lpBufStart + nRead;
  554.             }
  555.             else
  556.             {
  557.                 nRead = m_pFile->GetBufferPtr(CFile::bufferRead, m_nBufSize,
  558.                     (void**)&m_lpBufStart, (void**)&m_lpBufMax);
  559.                 ASSERT(nRead == (UINT)(m_lpBufMax - m_lpBufStart));
  560.                 m_lpBufCur = m_lpBufStart;
  561.             }
  562.  
  563.             // use first part for rest of read
  564.             nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));
  565.             memcpy(lpBuf, m_lpBufCur, nTemp);
  566.             m_lpBufCur += nTemp;
  567.             nMaxTemp -= nTemp;
  568.         }
  569.     }
  570.     return nMax - nMaxTemp;
  571. }
  572.  
  573. void CArchive::Write(const void* lpBuf, UINT nMax)
  574. {
  575.     ASSERT_VALID(m_pFile);
  576.  
  577.     if (nMax == 0)
  578.         return;
  579.  
  580.     ASSERT(lpBuf != NULL);
  581.     ASSERT(AfxIsValidAddress(lpBuf, nMax, FALSE));  // read-only access needed
  582.     ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  583.     ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  584.     ASSERT(m_lpBufStart == NULL ||
  585.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart));
  586.     ASSERT(m_lpBufCur == NULL ||
  587.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur));
  588.     ASSERT(IsStoring());
  589.  
  590.     // copy to buffer if possible
  591.     UINT nTemp = min(nMax, (UINT)(m_lpBufMax - m_lpBufCur));
  592.     memcpy(m_lpBufCur, lpBuf, nTemp);
  593.     m_lpBufCur += nTemp;
  594.     lpBuf = (BYTE*)lpBuf + nTemp;
  595.     nMax -= nTemp;
  596.  
  597.     if (nMax > 0)
  598.     {
  599.         Flush();    // flush the full buffer
  600.  
  601.         // write rest of buffer size chunks
  602.         nTemp = nMax - (nMax % m_nBufSize);
  603.         m_pFile->Write(lpBuf, nTemp);
  604.         lpBuf = (BYTE*)lpBuf + nTemp;
  605.         nMax -= nTemp;
  606.  
  607.         if (m_bDirectBuffer)
  608.         {
  609.             // sync up direct mode buffer to new file position
  610.             VERIFY(m_pFile->GetBufferPtr(CFile::bufferWrite, m_nBufSize,
  611.                 (void**)&m_lpBufStart, (void**)&m_lpBufMax) == (UINT)m_nBufSize);
  612.             ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
  613.             m_lpBufCur = m_lpBufStart;
  614.         }
  615.  
  616.         // copy remaining to active buffer
  617.         ASSERT(nMax < (UINT)m_nBufSize);
  618.         ASSERT(m_lpBufCur == m_lpBufStart);
  619.         memcpy(m_lpBufCur, lpBuf, nMax);
  620.         m_lpBufCur += nMax;
  621.     }
  622. }
  623.  
  624. void CArchive::Flush()
  625. {
  626.     ASSERT_VALID(m_pFile);
  627.     ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  628.     ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  629.     ASSERT(m_lpBufStart == NULL ||
  630.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, IsStoring()));
  631.     ASSERT(m_lpBufCur == NULL ||
  632.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, IsStoring()));
  633.  
  634.     if (IsLoading())
  635.     {
  636.         // unget the characters in the buffer, seek back unused amount
  637.         if (m_lpBufMax != m_lpBufCur)
  638.             m_pFile->Seek(-(m_lpBufMax - m_lpBufCur), CFile::current);
  639.         m_lpBufCur = m_lpBufMax;    // empty
  640.     }
  641.     else
  642.     {
  643.         if (!m_bDirectBuffer)
  644.         {
  645.             // write out the current buffer to file
  646.             if (m_lpBufCur != m_lpBufStart)
  647.                 m_pFile->Write(m_lpBufStart, m_lpBufCur - m_lpBufStart);
  648.         }
  649.         else
  650.         {
  651.             // commit current buffer
  652.             if (m_lpBufCur != m_lpBufStart)
  653.                 m_pFile->GetBufferPtr(CFile::bufferCommit, m_lpBufCur - m_lpBufStart);
  654.             // get next buffer
  655.             VERIFY(m_pFile->GetBufferPtr(CFile::bufferWrite, m_nBufSize,
  656.                 (void**)&m_lpBufStart, (void**)&m_lpBufMax) == (UINT)m_nBufSize);
  657.             ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
  658.         }
  659.         m_lpBufCur = m_lpBufStart;
  660.     }
  661. }
  662.  
  663. void CArchive::FillBuffer(UINT nBytesNeeded)
  664. {
  665.     ASSERT_VALID(m_pFile);
  666.     ASSERT(IsLoading());
  667.     ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  668.     ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  669.     ASSERT(nBytesNeeded > 0);
  670.     ASSERT(nBytesNeeded <= (UINT)m_nBufSize);
  671.     ASSERT(m_lpBufStart == NULL ||
  672.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, FALSE));
  673.     ASSERT(m_lpBufCur == NULL ||
  674.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, FALSE));
  675.  
  676.     UINT nUnused = m_lpBufMax - m_lpBufCur;
  677.     ULONG nTotalNeeded = ((ULONG)nBytesNeeded) + nUnused;
  678.  
  679.     // fill up the current buffer from file
  680.     if (!m_bDirectBuffer)
  681.     {
  682.         ASSERT(m_lpBufCur != NULL);
  683.         ASSERT(m_lpBufStart != NULL);
  684.         ASSERT(m_lpBufMax != NULL);
  685.  
  686.         if (m_lpBufCur > m_lpBufStart)
  687.         {
  688.             // copy unused
  689.             if ((int)nUnused > 0)
  690.             {
  691.                 memmove(m_lpBufStart, m_lpBufCur, nUnused);
  692.                 m_lpBufCur = m_lpBufStart;
  693.                 m_lpBufMax = m_lpBufStart + nUnused;
  694.             }
  695.  
  696.             // read to satisfy nBytesNeeded or nLeft if possible
  697.             UINT nRead = nUnused;
  698.             UINT nLeft = m_nBufSize-nUnused;
  699.             UINT nBytes;
  700.             BYTE* lpTemp = m_lpBufStart + nUnused;
  701.             do
  702.             {
  703.                 nBytes = m_pFile->Read(lpTemp, nLeft);
  704.                 lpTemp = lpTemp + nBytes;
  705.                 nRead += nBytes;
  706.                 nLeft -= nBytes;
  707.             }
  708.             while (nBytes > 0 && nLeft > 0 && nRead < nBytesNeeded);
  709.  
  710.             m_lpBufCur = m_lpBufStart;
  711.             m_lpBufMax = m_lpBufStart + nRead;
  712.         }
  713.     }
  714.     else
  715.     {
  716.         // seek to unused portion and get the buffer starting there
  717.         if (nUnused != 0)
  718.             m_pFile->Seek(-(LONG)nUnused, CFile::current);
  719.         UINT nActual = m_pFile->GetBufferPtr(CFile::bufferRead, m_nBufSize,
  720.             (void**)&m_lpBufStart, (void**)&m_lpBufMax);
  721.         ASSERT(nActual == (UINT)(m_lpBufMax - m_lpBufStart));
  722.         m_lpBufCur = m_lpBufStart;
  723.     }
  724.  
  725.     // not enough data to fill request?
  726.     if ((ULONG)(m_lpBufMax - m_lpBufCur) < nTotalNeeded)
  727.         AfxThrowArchiveException(CArchiveException::endOfFile);
  728. }
  729.  
  730. void CArchive::WriteCount(DWORD dwCount)
  731. {
  732.     if (dwCount < 0xFFFF)
  733.         *this << (WORD)dwCount;
  734.     else
  735.     {
  736.         *this << (WORD)0xFFFF;
  737.         *this << dwCount;
  738.     }
  739. }
  740.  
  741. DWORD CArchive::ReadCount()
  742. {
  743.     WORD wCount;
  744.     *this >> wCount;
  745.     if (wCount != 0xFFFF)
  746.         return wCount;
  747.  
  748.     DWORD dwCount;
  749.     *this >> dwCount;
  750.     return dwCount;
  751. }
  752.  
  753. // special functions for text file input and output
  754.  
  755. void CArchive::WriteString(LPCTSTR lpsz)
  756. {
  757.     ASSERT(AfxIsValidString(lpsz));
  758.     Write(lpsz, lstrlen(lpsz) * sizeof(TCHAR));
  759. }
  760.  
  761. LPTSTR CArchive::ReadString(LPTSTR lpsz, UINT nMax)
  762. {
  763.     // if nMax is negative (such a large number doesn't make sense given today's
  764.     // 2gb address space), then assume it to mean "keep the newline".
  765.     int nStop = (int)nMax < 0 ? -(int)nMax : (int)nMax;
  766.     ASSERT(AfxIsValidAddress(lpsz, (nStop+1) * sizeof(TCHAR)));
  767.  
  768.     _TUCHAR ch;
  769.     int nRead = 0;
  770.  
  771.     TRY
  772.     {
  773.         while (nRead < nStop)
  774.         {
  775.             *this >> ch;
  776.  
  777.             // stop and end-of-line (trailing '\n' is ignored)
  778.             if (ch == '\n' || ch == '\r')
  779.             {
  780.                 if (ch == '\r')
  781.                     *this >> ch;
  782.                 // store the newline when called with negative nMax
  783.                 if ((int)nMax != nStop)
  784.                     lpsz[nRead++] = ch;
  785.                 break;
  786.             }
  787.             lpsz[nRead++] = ch;
  788.         }
  789.     }
  790.     CATCH(CArchiveException, e)
  791.     {
  792.         if (e->m_cause == CArchiveException::endOfFile)
  793.         {
  794.             DELETE_EXCEPTION(e);
  795.             if (nRead == 0)
  796.                 return NULL;
  797.         }
  798.         else
  799.         {
  800.             THROW_LAST();
  801.         }
  802.     }
  803.     END_CATCH
  804.  
  805.     lpsz[nRead] = '\0';
  806.     return lpsz;
  807. }
  808.  
  809. BOOL CArchive::ReadString(CString& rString)
  810. {
  811.     rString = &afxChNil;    // empty string without deallocating
  812.     const int nMaxSize = 128;
  813.     LPTSTR lpsz = rString.GetBuffer(nMaxSize);
  814.     LPTSTR lpszResult;
  815.     int nLen;
  816.     for (;;)
  817.     {
  818.         lpszResult = ReadString(lpsz, (UINT)-nMaxSize); // store the newline
  819.         rString.ReleaseBuffer();
  820.  
  821.         // if string is read completely or EOF
  822.         if (lpszResult == NULL ||
  823.             (nLen = lstrlen(lpsz)) < nMaxSize ||
  824.             lpsz[nLen-1] == '\n')
  825.         {
  826.             break;
  827.         }
  828.  
  829.         nLen = rString.GetLength();
  830.         lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
  831.     }
  832.  
  833.     // remove '\n' from end of string if present
  834.     lpsz = rString.GetBuffer(0);
  835.     nLen = rString.GetLength();
  836.     if (nLen != 0 && lpsz[nLen-1] == '\n')
  837.         rString.GetBufferSetLength(nLen-1);
  838.  
  839.     return lpszResult != NULL;
  840. }
  841.  
  842. /////////////////////////////////////////////////////////////////////////////
  843.