SpArchive.cpp
上传用户:zhanglf88
上传日期:2013-11-19
资源大小:6036k
文件大小:13k
源码类别:

金融证券系统

开发平台:

Visual C++

  1. /*
  2. Cross Platform Core Code.
  3. Copyright(R) 2001-2002 Balang Software.
  4. All rights reserved.
  5. Using:
  6. class CSPArchive;
  7. */
  8. #include "StdAfx.h"
  9. #ifdef _DEBUG
  10. #undef THIS_FILE
  11. static char THIS_FILE[] = __FILE__;
  12. #endif
  13. #ifdef _DEBUG
  14. #define new DEBUG_NEW
  15. #endif
  16. #ifndef _SP_ENABLE_INLINES
  17. #define _SPARCHIVE_INLINE
  18. #include "../Include/SpArchive.inl"
  19. #undef _SPARCHIVE_INLINE
  20. #endif
  21. ////////////////////////////////////////////////////////////////////////////
  22. // Archive object input/output
  23. // minimum buffer size
  24. enum { nBufSizeMin = 128 };
  25. // default amount to grow m_pLoadArray upon insert
  26. enum { nGrowSize = 64 };
  27. // default size of hash table in m_pStoreMap when storing
  28. enum { nHashSize = 137 };
  29. // default size to grow collision blocks when storing
  30. enum { nBlockSize = 16 };
  31. ////////////////////////////////////////////////////////////////////////////
  32. CSPArchive::CSPArchive(CSPFile* pFile, UINT nMode, int nBufSize, void* lpBuf)
  33. {
  34. SP_ASSERT_VALID(pFile);
  35. // initialize members not dependent on allocated buffer
  36. m_nMode = nMode;
  37. m_pFile = pFile;
  38. m_bForceFlat = TRUE;
  39. // initialize the buffer.  minimum size is 128
  40. m_lpBufStart = (BYTE*)lpBuf;
  41. m_bUserBuf = TRUE;
  42. m_bDirectBuffer = FALSE;
  43. if (nBufSize < nBufSizeMin)
  44. {
  45. // force use of private buffer of minimum size
  46. m_nBufSize = nBufSizeMin;
  47. m_lpBufStart = NULL;
  48. }
  49. else
  50. m_nBufSize = nBufSize;
  51. nBufSize = m_nBufSize;
  52. if (m_lpBufStart == NULL)
  53. {
  54. // check for CSPFile providing buffering support
  55. m_bDirectBuffer = m_pFile->GetBufferPtr(CSPFile::bufferCheck);
  56. if (!m_bDirectBuffer)
  57. {
  58. // no support for direct buffering, allocate new buffer
  59. m_lpBufStart = new BYTE[m_nBufSize];
  60. m_bUserBuf = FALSE;
  61. }
  62. else
  63. {
  64. // CSPFile* supports direct buffering!
  65. nBufSize = 0;   // will trigger initial FillBuffer
  66. }
  67. }
  68. if (!m_bDirectBuffer)
  69. {
  70. SP_ASSERT(m_lpBufStart != NULL);
  71. SP_ASSERT(SP_IsValidAddress(m_lpBufStart, nBufSize, IsStoring()));
  72. }
  73. m_lpBufMax = m_lpBufStart + nBufSize;
  74. m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;
  75. }
  76. CSPArchive::~CSPArchive()
  77. {
  78. // Close makes m_pFile NULL. If it is not NULL, we must Close the CSPArchive
  79. if (m_pFile != NULL && !(m_nMode & bNoFlushOnDelete))
  80. Close();
  81. Abort();    // abort completely shuts down the archive
  82. }
  83. void CSPArchive::Abort()
  84. {
  85. SP_ASSERT(m_bDirectBuffer || m_lpBufStart == NULL ||
  86. SP_IsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, IsStoring()));
  87. SP_ASSERT(m_bDirectBuffer || m_lpBufCur == NULL ||
  88. SP_IsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, IsStoring()));
  89. // disconnect from the file
  90. m_pFile = NULL;
  91. if (!m_bUserBuf)
  92. {
  93. SP_ASSERT(!m_bDirectBuffer);
  94. delete[] m_lpBufStart;
  95. m_lpBufStart = NULL;
  96. m_lpBufCur = NULL;
  97. }
  98. }
  99. void CSPArchive::Close()
  100. {
  101. SP_ASSERT_VALID(m_pFile);
  102. Flush();
  103. m_pFile = NULL;
  104. }
  105. UINT CSPArchive::Read(void* lpBuf, UINT nMax)
  106. {
  107. SP_ASSERT_VALID(m_pFile);
  108. if (nMax == 0)
  109. return 0;
  110. SP_ASSERT(lpBuf != NULL);
  111. SP_ASSERT(SP_IsValidAddress(lpBuf, nMax));
  112. SP_ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  113. SP_ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  114. SP_ASSERT(m_lpBufStart == NULL ||
  115. SP_IsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, FALSE));
  116. SP_ASSERT(m_lpBufCur == NULL ||
  117. SP_IsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, FALSE));
  118. SP_ASSERT(IsLoading());
  119. // try to fill from buffer first
  120. UINT nMaxTemp = nMax;
  121. UINT nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));
  122. memcpy(lpBuf, m_lpBufCur, nTemp);
  123. m_lpBufCur += nTemp;
  124. lpBuf = (BYTE*)lpBuf + nTemp;
  125. nMaxTemp -= nTemp;
  126. if (nMaxTemp != 0)
  127. {
  128. SP_ASSERT(m_lpBufCur == m_lpBufMax);
  129. // read rest in buffer size chunks
  130. nTemp = nMaxTemp - (nMaxTemp % m_nBufSize);
  131. UINT nRead = 0;
  132. UINT nLeft = nTemp;
  133. UINT nBytes;
  134. do
  135. {
  136. nBytes = m_pFile->Read(lpBuf, nLeft);
  137. lpBuf = (BYTE*)lpBuf + nBytes;
  138. nRead += nBytes;
  139. nLeft -= nBytes;
  140. }
  141. while ((nBytes > 0) && (nLeft > 0));
  142. nMaxTemp -= nRead;
  143. // read last chunk into buffer then copy
  144. if (nRead == nTemp)
  145. {
  146. SP_ASSERT(m_lpBufCur == m_lpBufMax);
  147. SP_ASSERT(nMaxTemp < (UINT)m_nBufSize);
  148. // fill buffer (similar to CSPArchive::FillBuffer, but no exception)
  149. if (!m_bDirectBuffer)
  150. {
  151. UINT nLeft = max(nMaxTemp, (UINT)m_nBufSize);
  152. UINT nBytes;
  153. BYTE* lpTemp = m_lpBufStart;
  154. nRead = 0;
  155. do
  156. {
  157. nBytes = m_pFile->Read(lpTemp, nLeft);
  158. lpTemp = lpTemp + nBytes;
  159. nRead += nBytes;
  160. nLeft -= nBytes;
  161. }
  162. while ((nBytes > 0) && (nLeft > 0) && nRead < nMaxTemp);
  163. m_lpBufCur = m_lpBufStart;
  164. m_lpBufMax = m_lpBufStart + nRead;
  165. }
  166. else
  167. {
  168. nRead = m_pFile->GetBufferPtr(CSPFile::bufferRead, m_nBufSize,
  169. (void**)&m_lpBufStart, (void**)&m_lpBufMax);
  170. SP_ASSERT(nRead == (UINT)(m_lpBufMax - m_lpBufStart));
  171. m_lpBufCur = m_lpBufStart;
  172. }
  173. // use first part for rest of read
  174. nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));
  175. memcpy(lpBuf, m_lpBufCur, nTemp);
  176. m_lpBufCur += nTemp;
  177. nMaxTemp -= nTemp;
  178. }
  179. }
  180. return nMax - nMaxTemp;
  181. }
  182. void CSPArchive::Write(const void* lpBuf, UINT nMax)
  183. {
  184. SP_ASSERT_VALID(m_pFile);
  185. if (nMax == 0)
  186. return;
  187. SP_ASSERT(lpBuf != NULL);
  188. SP_ASSERT(SP_IsValidAddress((void*)lpBuf, nMax, FALSE));  // read-only access needed
  189. SP_ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  190. SP_ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  191. SP_ASSERT(m_lpBufStart == NULL ||
  192. SP_IsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart));
  193. SP_ASSERT(m_lpBufCur == NULL ||
  194. SP_IsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur));
  195. SP_ASSERT(IsStoring());
  196. // copy to buffer if possible
  197. UINT nTemp = min(nMax, (UINT)(m_lpBufMax - m_lpBufCur));
  198. memcpy(m_lpBufCur, lpBuf, nTemp);
  199. m_lpBufCur += nTemp;
  200. lpBuf = (BYTE*)lpBuf + nTemp;
  201. nMax -= nTemp;
  202. if (nMax > 0)
  203. {
  204. Flush();    // flush the full buffer
  205. // write rest of buffer size chunks
  206. nTemp = nMax - (nMax % m_nBufSize);
  207. m_pFile->Write(lpBuf, nTemp);
  208. lpBuf = (BYTE*)lpBuf + nTemp;
  209. nMax -= nTemp;
  210. if (m_bDirectBuffer)
  211. {
  212. // sync up direct mode buffer to new file position
  213. SP_VERIFY(m_pFile->GetBufferPtr(CSPFile::bufferWrite, m_nBufSize,
  214. (void**)&m_lpBufStart, (void**)&m_lpBufMax) == (UINT)m_nBufSize);
  215. SP_ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
  216. m_lpBufCur = m_lpBufStart;
  217. }
  218. // copy remaining to active buffer
  219. SP_ASSERT(nMax < (UINT)m_nBufSize);
  220. SP_ASSERT(m_lpBufCur == m_lpBufStart);
  221. memcpy(m_lpBufCur, lpBuf, nMax);
  222. m_lpBufCur += nMax;
  223. }
  224. }
  225. void CSPArchive::Flush()
  226. {
  227. SP_ASSERT_VALID(m_pFile);
  228. SP_ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  229. SP_ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  230. SP_ASSERT(m_lpBufStart == NULL ||
  231. SP_IsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, IsStoring()));
  232. SP_ASSERT(m_lpBufCur == NULL ||
  233. SP_IsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, IsStoring()));
  234. if (IsLoading())
  235. {
  236. // unget the characters in the buffer, seek back unused amount
  237. if (m_lpBufMax != m_lpBufCur)
  238. m_pFile->Seek(-(m_lpBufMax - m_lpBufCur), CSPFile::current);
  239. m_lpBufCur = m_lpBufMax;    // empty
  240. }
  241. else
  242. {
  243. if (!m_bDirectBuffer)
  244. {
  245. // write out the current buffer to file
  246. if (m_lpBufCur != m_lpBufStart)
  247. m_pFile->Write(m_lpBufStart, m_lpBufCur - m_lpBufStart);
  248. }
  249. else
  250. {
  251. // commit current buffer
  252. if (m_lpBufCur != m_lpBufStart)
  253. m_pFile->GetBufferPtr(CSPFile::bufferCommit, m_lpBufCur - m_lpBufStart);
  254. // get next buffer
  255. SP_VERIFY(m_pFile->GetBufferPtr(CSPFile::bufferWrite, m_nBufSize,
  256. (void**)&m_lpBufStart, (void**)&m_lpBufMax) == (UINT)m_nBufSize);
  257. SP_ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
  258. }
  259. m_lpBufCur = m_lpBufStart;
  260. }
  261. }
  262. void CSPArchive::FillBuffer(UINT nBytesNeeded)
  263. {
  264. SP_ASSERT_VALID(m_pFile);
  265. SP_ASSERT(IsLoading());
  266. SP_ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
  267. SP_ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
  268. SP_ASSERT(nBytesNeeded > 0);
  269. SP_ASSERT(nBytesNeeded <= (UINT)m_nBufSize);
  270. SP_ASSERT(m_lpBufStart == NULL ||
  271. SP_IsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, FALSE));
  272. SP_ASSERT(m_lpBufCur == NULL ||
  273. SP_IsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, FALSE));
  274. UINT nUnused = m_lpBufMax - m_lpBufCur;
  275. ULONG nTotalNeeded = ((ULONG)nBytesNeeded) + nUnused;
  276. // fill up the current buffer from file
  277. if (!m_bDirectBuffer)
  278. {
  279. SP_ASSERT(m_lpBufCur != NULL);
  280. SP_ASSERT(m_lpBufStart != NULL);
  281. SP_ASSERT(m_lpBufMax != NULL);
  282. if (m_lpBufCur > m_lpBufStart)
  283. {
  284. // copy unused
  285. if ((int)nUnused > 0)
  286. {
  287. memmove(m_lpBufStart, m_lpBufCur, nUnused);
  288. m_lpBufCur = m_lpBufStart;
  289. m_lpBufMax = m_lpBufStart + nUnused;
  290. }
  291. // read to satisfy nBytesNeeded or nLeft if possible
  292. UINT nRead = nUnused;
  293. UINT nLeft = m_nBufSize-nUnused;
  294. UINT nBytes;
  295. BYTE* lpTemp = m_lpBufStart + nUnused;
  296. do
  297. {
  298. nBytes = m_pFile->Read(lpTemp, nLeft);
  299. lpTemp = lpTemp + nBytes;
  300. nRead += nBytes;
  301. nLeft -= nBytes;
  302. }
  303. while (nBytes > 0 && nLeft > 0 && nRead < nBytesNeeded);
  304. m_lpBufCur = m_lpBufStart;
  305. m_lpBufMax = m_lpBufStart + nRead;
  306. }
  307. }
  308. else
  309. {
  310. // seek to unused portion and get the buffer starting there
  311. if (nUnused != 0)
  312. m_pFile->Seek(-(LONG)nUnused, CSPFile::current);
  313. UINT nActual = m_pFile->GetBufferPtr(CSPFile::bufferRead, m_nBufSize,
  314. (void**)&m_lpBufStart, (void**)&m_lpBufMax);
  315. SP_ASSERT(nActual == (UINT)(m_lpBufMax - m_lpBufStart));
  316. m_lpBufCur = m_lpBufStart;
  317. }
  318. }
  319. void CSPArchive::WriteCount(DWORD dwCount)
  320. {
  321. if (dwCount < 0xFFFF)
  322. *this << (WORD)dwCount;
  323. else
  324. {
  325. *this << (WORD)0xFFFF;
  326. *this << dwCount;
  327. }
  328. }
  329. DWORD CSPArchive::ReadCount()
  330. {
  331. WORD wCount;
  332. *this >> wCount;
  333. if (wCount != 0xFFFF)
  334. return wCount;
  335. DWORD dwCount;
  336. *this >> dwCount;
  337. return dwCount;
  338. }
  339. // special functions for text file input and output
  340. void CSPArchive::WriteString(LPCTSTR lpsz)
  341. {
  342. SP_ASSERT(SP_IsValidString(lpsz));
  343. Write(lpsz, lstrlen(lpsz) * sizeof(TCHAR));
  344. }
  345. LPTSTR CSPArchive::ReadString(LPTSTR lpsz, UINT nMax)
  346. {
  347. // if nMax is negative (such a large number doesn't make sense given today's
  348. // 2gb address space), then assume it to mean "keep the newline".
  349. int nStop = (int)nMax < 0 ? -(int)nMax : (int)nMax;
  350. SP_ASSERT(SP_IsValidAddress(lpsz, (nStop+1) * sizeof(TCHAR)));
  351. TCHAR ch;
  352. int nRead = 0;
  353. while (nRead < nStop)
  354. {
  355. *this >> ch;
  356. // stop and end-of-line (trailing 'n' is ignored)
  357. if (ch == 'n' || ch == 'r')
  358. {
  359. if (ch == 'r')
  360. *this >> ch;
  361. // store the newline when called with negative nMax
  362. if ((int)nMax != nStop)
  363. lpsz[nRead++] = ch;
  364. break;
  365. }
  366. lpsz[nRead++] = ch;
  367. }
  368. lpsz[nRead] = '';
  369. return lpsz;
  370. }
  371. BOOL CSPArchive::ReadString(CSPString& rString)
  372. {
  373. rString.Empty();
  374. const int nMaxSize = 128;
  375. LPTSTR lpsz = rString.GetBuffer(nMaxSize);
  376. LPTSTR lpszResult;
  377. int nLen;
  378. for (;;)
  379. {
  380. lpszResult = ReadString(lpsz, (UINT)-nMaxSize); // store the newline
  381. rString.ReleaseBuffer();
  382. // if string is read completely or EOF
  383. if (lpszResult == NULL ||
  384. (nLen = lstrlen(lpsz)) < nMaxSize ||
  385. lpsz[nLen-1] == 'n')
  386. {
  387. break;
  388. }
  389. nLen = rString.GetLength();
  390. lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
  391. }
  392. // remove 'n' from end of string if present
  393. lpsz = rString.GetBuffer(0);
  394. nLen = rString.GetLength();
  395. if (nLen != 0 && lpsz[nLen-1] == 'n')
  396. rString.GetBufferSetLength(nLen-1);
  397. return lpszResult != NULL;
  398. }
  399. ///////////////////////////////////////////////////////////////////////////////
  400. // CString serialization code
  401. // String format:
  402. //      UNICODE strings are always prefixed by 0xff, 0xfffe
  403. //      if < 0xff chars: len:BYTE, TCHAR chars
  404. //      if >= 0xff characters: 0xff, len:WORD, TCHAR chars
  405. //      if >= 0xfffe characters: 0xff, 0xffff, len:DWORD, TCHARs
  406. CSPArchive& operator<<(CSPArchive& ar, CSPString& string)
  407. {
  408. if (string.GetLength() < 255)
  409. {
  410. ar << (BYTE)string.GetLength();
  411. }
  412. else if (string.GetLength() < 0xfffe)
  413. {
  414. ar << (BYTE)0xff;
  415. ar << (WORD)string.GetLength();
  416. }
  417. else
  418. {
  419. ar << (BYTE)0xff;
  420. ar << (WORD)0xffff;
  421. ar << (DWORD)string.GetLength();
  422. }
  423. ar.Write(string.GetBuffer(string.GetLength()), string.GetLength()*sizeof(TCHAR));
  424. return ar;
  425. }
  426. // return string length or -1 if UNICODE string is found in the archive
  427. UINT _AfxReadStringLength(CSPArchive& ar)
  428. {
  429. DWORD nNewLen;
  430. // attempt BYTE length first
  431. BYTE bLen;
  432. ar >> bLen;
  433. if (bLen < 0xff)
  434. return bLen;
  435. // attempt WORD length
  436. WORD wLen;
  437. ar >> wLen;
  438. if (wLen == 0xfffe)
  439. {
  440. // UNICODE string prefix (length will follow)
  441. return (UINT)-1;
  442. }
  443. else if (wLen == 0xffff)
  444. {
  445. // read DWORD of length
  446. ar >> nNewLen;
  447. return (UINT)nNewLen;
  448. }
  449. else
  450. return wLen;
  451. }
  452. CSPArchive& operator>>(CSPArchive& ar, CSPString& string)
  453. {
  454. UINT nNewLen = _AfxReadStringLength(ar);
  455. if (nNewLen == (UINT)-1)
  456. SP_ASSERT(FALSE);
  457. // set length of string to new length
  458. string.Empty();
  459. char * lpBuf = string.GetBufferSetLength((int)nNewLen);
  460. // read in the characters
  461. if (nNewLen != 0)
  462. {
  463. // read new data
  464. if (ar.Read(lpBuf, nNewLen) != nNewLen)
  465. {
  466. SP_ASSERT( FALSE );
  467. //AfxThrowArchiveException(CArchiveException::endOfFile);
  468. return ar;
  469. }
  470. }
  471. return ar;
  472. }