arccore.cpp 20 KB

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