home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / ARCCORE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  20.4 KB  |  846 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 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 _MAC
  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
  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. static UINT AFXAPI ReadStringLength(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 = ReadStringLength(ar);
  228.     if (nNewLen == (UINT)-1)
  229.     {
  230.         nConvert = 1 - nConvert;
  231.         nNewLen = ReadStringLength(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. #ifndef _MAC
  258.         // convert the data if as necessary
  259.         if (nConvert != 0)
  260.         {
  261. #ifdef _UNICODE
  262.             CStringData* pOldData = string.GetData();
  263.             LPSTR lpsz = (LPSTR)string.m_pchData;
  264. #else
  265.             CStringData* pOldData = string.GetData();
  266.             LPWSTR lpsz = (LPWSTR)string.m_pchData;
  267. #endif
  268.             lpsz[nNewLen] = '\0';    // must be NUL terminated
  269.             string.Init();   // don't delete the old data
  270.             string = lpsz;   // convert with operator=(LPWCSTR)
  271.             delete[] (BYTE*)pOldData;
  272.         }
  273. #endif
  274.     }
  275.     return ar;
  276. }
  277.  
  278. // specialized version of SerializeElements for CString (used in collections)
  279. #if _MSC_VER >= 1100
  280. template <> void AFXAPI SerializeElements<CString> (CArchive& ar, CString* pElements, int nCount)
  281. #else
  282. void AFXAPI SerializeElements(CArchive& ar, CString* pElements, int nCount)
  283. #endif
  284. {
  285.     ASSERT(nCount == 0 ||
  286.         AfxIsValidAddress(pElements, nCount * sizeof(CString)));
  287.  
  288.     if (ar.IsStoring())
  289.     {
  290.         for (; nCount--; ++pElements)
  291.             ar << *pElements;
  292.     }
  293.     else
  294.     {
  295.         for (; nCount--; ++pElements)
  296.             ar >> *pElements;
  297.     }
  298. }
  299.  
  300. // Runtime class serialization code
  301. CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum)
  302.     // loads a runtime class description
  303. {
  304.     WORD nLen;
  305.     char szClassName[64];
  306.     CRuntimeClass* pClass;
  307.  
  308.     WORD wTemp;
  309.     ar >> wTemp; *pwSchemaNum = wTemp;
  310.     ar >> nLen;
  311.  
  312.     if (nLen >= _countof(szClassName) ||
  313.         ar.Read(szClassName, nLen*sizeof(char)) != nLen*sizeof(char))
  314.     {
  315.         return NULL;
  316.     }
  317.     szClassName[nLen] = '\0';
  318.  
  319.     // search app specific classes
  320.     AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
  321.     AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
  322.     for (pClass = pModuleState->m_classList; pClass != NULL;
  323.         pClass = pClass->m_pNextClass)
  324.     {
  325.         if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)
  326.         {
  327.             AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
  328.             return pClass;
  329.         }
  330.     }
  331.     AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
  332. #ifdef _AFXDLL
  333.     // search classes in shared DLLs
  334.     AfxLockGlobals(CRIT_DYNLINKLIST);
  335.     for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
  336.         pDLL = pDLL->m_pNextDLL)
  337.     {
  338.         for (pClass = pDLL->m_classList; pClass != NULL;
  339.             pClass = pClass->m_pNextClass)
  340.         {
  341.             if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)
  342.             {
  343.                 AfxUnlockGlobals(CRIT_DYNLINKLIST);
  344.                 return pClass;
  345.             }
  346.         }
  347.     }
  348.     AfxUnlockGlobals(CRIT_DYNLINKLIST);
  349. #endif
  350.  
  351.     TRACE1("Warning: Cannot load %hs from archive.  Class not defined.\n",
  352.         szClassName);
  353.  
  354.     return NULL; // not found
  355. }
  356.  
  357. void CRuntimeClass::Store(CArchive& ar) const
  358.     // stores a runtime class description
  359. {
  360.     WORD nLen = (WORD)lstrlenA(m_lpszClassName);
  361.     ar << (WORD)m_wSchema << nLen;
  362.     ar.Write(m_lpszClassName, nLen*sizeof(char));
  363. }
  364.  
  365. ////////////////////////////////////////////////////////////////////////////
  366. // Archive object input/output
  367.  
  368. // minimum buffer size
  369. enum { nBufSizeMin = 128 };
  370.  
  371. // default amount to grow m_pLoadArray upon insert
  372. enum { nGrowSize = 64 };
  373. // default size of hash table in m_pStoreMap when storing
  374. enum { nHashSize = 137 };
  375. // default size to grow collision blocks when storing
  376. enum { nBlockSize = 16 };
  377.  
  378. ////////////////////////////////////////////////////////////////////////////
  379.  
  380. CArchive::CArchive(CFile* pFile, UINT nMode, int nBufSize, void* lpBuf) :
  381.     m_strFileName(pFile->GetFilePath())
  382. {
  383.     ASSERT_VALID(pFile);
  384.  
  385.     // initialize members not dependent on allocated buffer
  386.     m_nMode = nMode;
  387.     m_pFile = pFile;
  388.     m_pSchemaMap = NULL;
  389.     m_pLoadArray = NULL;
  390.     m_pDocument = NULL;
  391.     m_bForceFlat = TRUE;
  392.     m_nObjectSchema = (UINT)-1; // start with invalid schema
  393.     if (IsStoring())
  394.         m_nGrowSize = nBlockSize;
  395.     else
  396.         m_nGrowSize = nGrowSize;
  397.     m_nHashSize = nHashSize;
  398.  
  399.     // initialize the buffer.  minimum size is 128
  400.     m_lpBufStart = (BYTE*)lpBuf;
  401.     m_bUserBuf = TRUE;
  402.     m_bDirectBuffer = FALSE;
  403.  
  404.     if (nBufSize < nBufSizeMin)
  405.     {
  406.         // force use of private buffer of minimum size
  407.         m_nBufSize = nBufSizeMin;
  408.         m_lpBufStart = NULL;
  409.     }
  410.     else
  411.         m_nBufSize = nBufSize;
  412.  
  413.     nBufSize = m_nBufSize;
  414.     if (m_lpBufStart == NULL)
  415.     {
  416.         // check for CFile providing buffering support
  417.         m_bDirectBuffer = m_pFile->GetBufferPtr(CFile::bufferCheck);
  418.         if (!m_bDirectBuffer)
  419.         {
  420.             // no support for direct buffering, allocate new buffer
  421.             m_lpBufStart = new BYTE[m_nBufSize];
  422.             m_bUserBuf = FALSE;
  423.         }
  424.         else
  425.         {
  426.             // CFile* supports direct buffering!
  427.             nBufSize = 0;   // will trigger initial FillBuffer
  428.         }
  429.     }
  430.  
  431.     if (!m_bDirectBuffer)
  432.     {
  433.         ASSERT(m_lpBufStart != NULL);
  434.         ASSERT(AfxIsValidAddress(m_lpBufStart, nBufSize, IsStoring()));
  435.     }
  436.     m_lpBufMax = m_lpBufStart + nBufSize;
  437.     m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;
  438.  
  439.     ASSERT(m_pStoreMap == NULL);        // same as m_pLoadArray
  440. }
  441.  
  442. CArchive::~CArchive()
  443. {
  444.     // Close makes m_pFile NULL. If it is not NULL, we must Close the CArchive
  445.     if (m_pFile != NULL && !(m_nMode & bNoFlushOnDelete))
  446.         Close();
  447.  
  448.     Abort();    // abort completely shuts down the archive
  449. }
  450.  
  451. void CArchive::Abort()
  452. {
  453.     ASSERT(m_bDirectBuffer || m_lpBufStart == NULL ||
  454.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, IsStoring()));
  455.     ASSERT(m_bDirectBuffer || m_lpBufCur == NULL ||
  456.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, IsStoring()));
  457.  
  458.     // disconnect from the file
  459.     m_pFile = NULL;
  460.  
  461.     if (!m_bUserBuf)
  462.     {
  463.         ASSERT(!m_bDirectBuffer);
  464.         delete[] m_lpBufStart;
  465.         m_lpBufStart = NULL;
  466.         m_lpBufCur = NULL;
  467.     }
  468.  
  469.     delete m_pSchemaMap;
  470.     m_pSchemaMap = NULL;
  471.  
  472.     // m_pStoreMap and m_pLoadArray are unioned, so we only need to delete one
  473.     ASSERT((CObject*)m_pStoreMap == (CObject*)m_pLoadArray);
  474.     delete (CObject*)m_pLoadArray;
  475.     m_pLoadArray = NULL;
  476. }
  477.  
  478. void CArchive::Close()
  479. {
  480.     ASSERT_VALID(m_pFile);
  481.  
  482.     Flush();
  483.     m_pFile = NULL;
  484. }
  485.  
  486. UINT CArchive::Read(void* lpBuf, UINT nMax)
  487. {
  488.     ASSERT_VALID(m_pFile);
  489.  
  490.     if (nMax == 0)
  491.         return 0;
  492.  
  493.     ASSERT(lpBuf != NULL);
  494.     ASSERT(AfxIsValidAddress(lpBuf, nMax));
  495.     ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  496.     ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  497.     ASSERT(m_lpBufStart == NULL ||
  498.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, FALSE));
  499.     ASSERT(m_lpBufCur == NULL ||
  500.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, FALSE));
  501.     ASSERT(IsLoading());
  502.  
  503.     // try to fill from buffer first
  504.     UINT nMaxTemp = nMax;
  505.     UINT nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));
  506.     memcpy(lpBuf, m_lpBufCur, nTemp);
  507.     m_lpBufCur += nTemp;
  508.     lpBuf = (BYTE*)lpBuf + nTemp;
  509.     nMaxTemp -= nTemp;
  510.  
  511.     if (nMaxTemp != 0)
  512.     {
  513.         ASSERT(m_lpBufCur == m_lpBufMax);
  514.  
  515.         // read rest in buffer size chunks
  516.         nTemp = nMaxTemp - (nMaxTemp % m_nBufSize);
  517.         UINT nRead = 0;
  518.  
  519.         UINT nLeft = nTemp;
  520.         UINT nBytes;
  521.         do
  522.         {
  523.             nBytes = m_pFile->Read(lpBuf, nLeft);
  524.             lpBuf = (BYTE*)lpBuf + nBytes;
  525.             nRead += nBytes;
  526.             nLeft -= nBytes;
  527.         }
  528.         while ((nBytes > 0) && (nLeft > 0));
  529.  
  530.         nMaxTemp -= nRead;
  531.  
  532.         // read last chunk into buffer then copy
  533.         if (nRead == nTemp)
  534.         {
  535.             ASSERT(m_lpBufCur == m_lpBufMax);
  536.             ASSERT(nMaxTemp < (UINT)m_nBufSize);
  537.  
  538.             // fill buffer (similar to CArchive::FillBuffer, but no exception)
  539.             if (!m_bDirectBuffer)
  540.             {
  541.                 UINT nLeft = max(nMaxTemp, (UINT)m_nBufSize);
  542.                 UINT nBytes;
  543.                 BYTE* lpTemp = m_lpBufStart;
  544.                 nRead = 0;
  545.                 do
  546.                 {
  547.                     nBytes = m_pFile->Read(lpTemp, nLeft);
  548.                     lpTemp = lpTemp + nBytes;
  549.                     nRead += nBytes;
  550.                     nLeft -= nBytes;
  551.                 }
  552.                 while ((nBytes > 0) && (nLeft > 0) && nRead < nMaxTemp);
  553.  
  554.                 m_lpBufCur = m_lpBufStart;
  555.                 m_lpBufMax = m_lpBufStart + nRead;
  556.             }
  557.             else
  558.             {
  559.                 nRead = m_pFile->GetBufferPtr(CFile::bufferRead, m_nBufSize,
  560.                     (void**)&m_lpBufStart, (void**)&m_lpBufMax);
  561.                 ASSERT(nRead == (UINT)(m_lpBufMax - m_lpBufStart));
  562.                 m_lpBufCur = m_lpBufStart;
  563.             }
  564.  
  565.             // use first part for rest of read
  566.             nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));
  567.             memcpy(lpBuf, m_lpBufCur, nTemp);
  568.             m_lpBufCur += nTemp;
  569.             nMaxTemp -= nTemp;
  570.         }
  571.     }
  572.     return nMax - nMaxTemp;
  573. }
  574.  
  575. void CArchive::Write(const void* lpBuf, UINT nMax)
  576. {
  577.     ASSERT_VALID(m_pFile);
  578.  
  579.     if (nMax == 0)
  580.         return;
  581.  
  582.     ASSERT(lpBuf != NULL);
  583.     ASSERT(AfxIsValidAddress(lpBuf, nMax, FALSE));  // read-only access needed
  584.     ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  585.     ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  586.     ASSERT(m_lpBufStart == NULL ||
  587.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart));
  588.     ASSERT(m_lpBufCur == NULL ||
  589.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur));
  590.     ASSERT(IsStoring());
  591.  
  592.     // copy to buffer if possible
  593.     UINT nTemp = min(nMax, (UINT)(m_lpBufMax - m_lpBufCur));
  594.     memcpy(m_lpBufCur, lpBuf, nTemp);
  595.     m_lpBufCur += nTemp;
  596.     lpBuf = (BYTE*)lpBuf + nTemp;
  597.     nMax -= nTemp;
  598.  
  599.     if (nMax > 0)
  600.     {
  601.         Flush();    // flush the full buffer
  602.  
  603.         // write rest of buffer size chunks
  604.         nTemp = nMax - (nMax % m_nBufSize);
  605.         m_pFile->Write(lpBuf, nTemp);
  606.         lpBuf = (BYTE*)lpBuf + nTemp;
  607.         nMax -= nTemp;
  608.  
  609.         if (m_bDirectBuffer)
  610.         {
  611.             // sync up direct mode buffer to new file position
  612.             VERIFY(m_pFile->GetBufferPtr(CFile::bufferWrite, m_nBufSize,
  613.                 (void**)&m_lpBufStart, (void**)&m_lpBufMax) == (UINT)m_nBufSize);
  614.             ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
  615.             m_lpBufCur = m_lpBufStart;
  616.         }
  617.  
  618.         // copy remaining to active buffer
  619.         ASSERT(nMax < (UINT)m_nBufSize);
  620.         ASSERT(m_lpBufCur == m_lpBufStart);
  621.         memcpy(m_lpBufCur, lpBuf, nMax);
  622.         m_lpBufCur += nMax;
  623.     }
  624. }
  625.  
  626. void CArchive::Flush()
  627. {
  628.     ASSERT_VALID(m_pFile);
  629.     ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  630.     ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  631.     ASSERT(m_lpBufStart == NULL ||
  632.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, IsStoring()));
  633.     ASSERT(m_lpBufCur == NULL ||
  634.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, IsStoring()));
  635.  
  636.     if (IsLoading())
  637.     {
  638.         // unget the characters in the buffer, seek back unused amount
  639.         if (m_lpBufMax - m_lpBufCur != 0)
  640.             m_pFile->Seek(-(m_lpBufMax - m_lpBufCur), CFile::current);
  641.         m_lpBufCur = m_lpBufMax;    // empty
  642.     }
  643.     else
  644.     {
  645.         if (m_lpBufStart == NULL || m_lpBufCur != m_lpBufStart)
  646.         {
  647.             if (!m_bDirectBuffer)
  648.             {
  649.                 // write out the current buffer to file
  650.                 m_pFile->Write(m_lpBufStart, m_lpBufCur - m_lpBufStart);
  651.             }
  652.             else
  653.             {
  654.                 // commit current buffer
  655.                 m_pFile->GetBufferPtr(CFile::bufferCommit, m_lpBufCur - m_lpBufStart);
  656.                 // get next buffer
  657.                 VERIFY(m_pFile->GetBufferPtr(CFile::bufferWrite, m_nBufSize,
  658.                     (void**)&m_lpBufStart, (void**)&m_lpBufMax) == (UINT)m_nBufSize);
  659.                 ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
  660.             }
  661.             m_lpBufCur = m_lpBufStart;
  662.         }
  663.     }
  664. }
  665.  
  666. void CArchive::FillBuffer(UINT nBytesNeeded)
  667. {
  668.     ASSERT_VALID(m_pFile);
  669.     ASSERT(IsLoading());
  670.     ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  671.     ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  672.     ASSERT(nBytesNeeded > 0);
  673.     ASSERT(nBytesNeeded <= (UINT)m_nBufSize);
  674.     ASSERT(m_lpBufStart == NULL ||
  675.         AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, FALSE));
  676.     ASSERT(m_lpBufCur == NULL ||
  677.         AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, FALSE));
  678.  
  679.     UINT nUnused = m_lpBufMax - m_lpBufCur;
  680.     ULONG nTotalNeeded = ((ULONG)nBytesNeeded) + nUnused;
  681.  
  682.     // fill up the current buffer from file
  683.     if (!m_bDirectBuffer)
  684.     {
  685.         ASSERT(m_lpBufCur != NULL);
  686.         ASSERT(m_lpBufStart != NULL);
  687.         ASSERT(m_lpBufMax != NULL);
  688.  
  689.         if (m_lpBufCur > m_lpBufStart)
  690.         {
  691.             // copy unused
  692.             if ((int)nUnused > 0)
  693.             {
  694.                 memmove(m_lpBufStart, m_lpBufCur, nUnused);
  695.                 m_lpBufCur = m_lpBufStart;
  696.                 m_lpBufMax = m_lpBufStart + nUnused;
  697.             }
  698.  
  699.             // read to satisfy nBytesNeeded or nLeft if possible
  700.             UINT nRead = nUnused;
  701.             UINT nLeft = m_nBufSize-nUnused;
  702.             UINT nBytes;
  703.             BYTE* lpTemp = m_lpBufStart + nUnused;
  704.             do
  705.             {
  706.                 nBytes = m_pFile->Read(lpTemp, nLeft);
  707.                 lpTemp = lpTemp + nBytes;
  708.                 nRead += nBytes;
  709.                 nLeft -= nBytes;
  710.             }
  711.             while (nBytes > 0 && nLeft > 0 && nRead < nBytesNeeded);
  712.  
  713.             m_lpBufCur = m_lpBufStart;
  714.             m_lpBufMax = m_lpBufStart + nRead;
  715.         }
  716.     }
  717.     else
  718.     {
  719.         // seek to unused portion and get the buffer starting there
  720.         if (nUnused != 0)
  721.             m_pFile->Seek(-(LONG)nUnused, CFile::current);
  722.         UINT nActual = m_pFile->GetBufferPtr(CFile::bufferRead, m_nBufSize,
  723.             (void**)&m_lpBufStart, (void**)&m_lpBufMax);
  724.         ASSERT(nActual == (UINT)(m_lpBufMax - m_lpBufStart));
  725.         m_lpBufCur = m_lpBufStart;
  726.     }
  727.  
  728.     // not enough data to fill request?
  729.     if ((ULONG)(m_lpBufMax - m_lpBufCur) < nTotalNeeded)
  730.         AfxThrowArchiveException(CArchiveException::endOfFile);
  731. }
  732.  
  733. void CArchive::WriteCount(DWORD dwCount)
  734. {
  735.     if (dwCount < 0xFFFF)
  736.         *this << (WORD)dwCount;
  737.     else
  738.     {
  739.         *this << (WORD)0xFFFF;
  740.         *this << dwCount;
  741.     }
  742. }
  743.  
  744. DWORD CArchive::ReadCount()
  745. {
  746.     WORD wCount;
  747.     *this >> wCount;
  748.     if (wCount != 0xFFFF)
  749.         return wCount;
  750.  
  751.     DWORD dwCount;
  752.     *this >> dwCount;
  753.     return dwCount;
  754. }
  755.  
  756. // special functions for text file input and output
  757.  
  758. void CArchive::WriteString(LPCTSTR lpsz)
  759. {
  760.     ASSERT(AfxIsValidString(lpsz));
  761.     Write(lpsz, lstrlen(lpsz) * sizeof(TCHAR));
  762. }
  763.  
  764. LPTSTR CArchive::ReadString(LPTSTR lpsz, UINT nMax)
  765. {
  766.     // if nMax is negative (such a large number doesn't make sense given today's
  767.     // 2gb address space), then assume it to mean "keep the newline".
  768.     int nStop = (int)nMax < 0 ? -(int)nMax : (int)nMax;
  769.     ASSERT(AfxIsValidAddress(lpsz, (nStop+1) * sizeof(TCHAR)));
  770.  
  771.     _TUCHAR ch;
  772.     int nRead = 0;
  773.  
  774.     TRY
  775.     {
  776.         while (nRead < nStop)
  777.         {
  778.             *this >> ch;
  779.  
  780.             // stop and end-of-line (trailing '\n' is ignored)
  781.             if (ch == '\n' || ch == '\r')
  782.             {
  783.                 if (ch == '\r')
  784.                     *this >> ch;
  785.                 // store the newline when called with negative nMax
  786.                 if ((int)nMax != nStop)
  787.                     lpsz[nRead++] = ch;
  788.                 break;
  789.             }
  790.             lpsz[nRead++] = ch;
  791.         }
  792.     }
  793.     CATCH(CArchiveException, e)
  794.     {
  795.         if (e->m_cause == CArchiveException::endOfFile)
  796.         {
  797.             DELETE_EXCEPTION(e);
  798.             if (nRead == 0)
  799.                 return NULL;
  800.         }
  801.         else
  802.         {
  803.             THROW_LAST();
  804.         }
  805.     }
  806.     END_CATCH
  807.  
  808.     lpsz[nRead] = '\0';
  809.     return lpsz;
  810. }
  811.  
  812. BOOL CArchive::ReadString(CString& rString)
  813. {
  814.     rString = &afxChNil;    // empty string without deallocating
  815.     const int nMaxSize = 128;
  816.     LPTSTR lpsz = rString.GetBuffer(nMaxSize);
  817.     LPTSTR lpszResult;
  818.     int nLen;
  819.     for (;;)
  820.     {
  821.         lpszResult = ReadString(lpsz, (UINT)-nMaxSize); // store the newline
  822.         rString.ReleaseBuffer();
  823.  
  824.         // if string is read completely or EOF
  825.         if (lpszResult == NULL ||
  826.             (nLen = lstrlen(lpsz)) < nMaxSize ||
  827.             lpsz[nLen-1] == '\n')
  828.         {
  829.             break;
  830.         }
  831.  
  832.         nLen = rString.GetLength();
  833.         lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
  834.     }
  835.  
  836.     // remove '\n' from end of string if present
  837.     lpsz = rString.GetBuffer(0);
  838.     nLen = rString.GetLength();
  839.     if (nLen != 0 && lpsz[nLen-1] == '\n')
  840.         rString.GetBufferSetLength(nLen-1);
  841.  
  842.     return lpszResult != NULL;
  843. }
  844.  
  845. /////////////////////////////////////////////////////////////////////////////
  846.