MailTmpFile.cpp
上传用户:weimei12
上传日期:2022-08-11
资源大小:185k
文件大小:13k
源码类别:

Email客户端

开发平台:

Visual C++

  1. #include "StdAfx.h"
  2. #include "MailStruct.h"
  3. #include "MailTmpFile.h"
  4. CMailTmpFile::CMailTmpFile(void)
  5. {
  6. m_pTmpFile = NULL;
  7. m_bOpenToWrite = FALSE;
  8. m_pMailCluster = NULL;
  9. memset(&m_fileHeader, 0, sizeof(SMailFileHeader));
  10. }
  11. CMailTmpFile::~CMailTmpFile(void)
  12. {
  13. if(m_pTmpFile != NULL)
  14. {
  15. m_pTmpFile->Close();
  16. delete m_pTmpFile;
  17. m_pTmpFile = NULL;
  18. }
  19. if(m_pMailCluster != NULL)
  20. {
  21. delete m_pMailCluster;
  22. m_pMailCluster = NULL;
  23. }
  24. }
  25. ///<summary>
  26. ///   Open a file to save mails
  27. ///</summary>
  28. BOOL CMailTmpFile::Open(LPCTSTR szFileName, BOOL bCanWrite)
  29. {
  30. ASSERT(szFileName != NULL);
  31. if (NULL == szFileName)
  32. {
  33. return FALSE;
  34. }
  35. if (IsOpened())
  36. {
  37. ASSERT(FALSE);
  38. return FALSE;
  39. }
  40. CFile* pFile = new CFile();
  41. UINT nOpenFlag = CFile::modeRead;
  42. if (bCanWrite)
  43. {
  44. nOpenFlag = CFile::modeReadWrite;
  45. }
  46. if (!pFile->Open(szFileName, nOpenFlag))
  47. {
  48. delete pFile;
  49. pFile = NULL;
  50. return FALSE;
  51. }
  52. m_bOpenToWrite = bCanWrite;
  53. m_pTmpFile = pFile;
  54. m_strFileName = szFileName;
  55. //read the content according to the format
  56. if (!LoadFromTmpFile())
  57. {
  58. delete pFile;
  59. m_pTmpFile = NULL;
  60. m_strFileName.Empty();
  61. m_bOpenToWrite = FALSE;
  62. return FALSE;
  63. }
  64. CloseFile(TRUE);
  65. return TRUE;
  66. }
  67. ///<summary>
  68. ///   Create an empty temporary file at first
  69. ///</summary>
  70. BOOL CMailTmpFile::CreateEmptyFile(LPCTSTR szFileName)
  71. {
  72. ASSERT(szFileName != NULL);
  73. if (NULL == szFileName)
  74. {
  75. return FALSE;
  76. }
  77. if (IsOpened())
  78. {
  79. ASSERT(FALSE);
  80. return FALSE;
  81. }
  82. CFile* pFile = new CFile();
  83. if (!pFile->Open(szFileName, CFile::modeCreate | CFile::modeReadWrite))
  84. {
  85. delete pFile;
  86. pFile = NULL;
  87. return FALSE;
  88. }
  89. m_bOpenToWrite = TRUE;
  90. m_pTmpFile = pFile;
  91. m_strFileName= szFileName;
  92. //create the file header
  93. memset(&m_fileHeader, 0, sizeof(SMailFileHeader));
  94. m_fileHeader.m_nHeadSize = sizeof(SMailFileHeader);
  95. m_fileHeader.m_nVersion = CUR_MAILFILE_VERSION;
  96. memcpy(m_fileHeader.m_szIdentity, SZ_MAILFILE_IDENTITY, 8 * sizeof(TCHAR));
  97. m_fileHeader.m_mailClusterHeadPos = sizeof(SMailFileHeader);
  98. m_fileHeader.m_endFilePos = sizeof(SMailFileHeader);
  99. MAILFILEPOS dataPos = sizeof(SMailFileHeader);
  100. //create a data cluster
  101. CDataCluster* pNewDataCluster = new CDataCluster();
  102. memset(&pNewDataCluster->m_dataCluster, 0, sizeof(SMailCluster));
  103. m_pMailCluster = pNewDataCluster;
  104. pNewDataCluster->m_selfFilePos = dataPos;
  105. pNewDataCluster->m_dataCluster.m_nMailBlockSize = MAIL_BLOCK_SIZE;
  106. pNewDataCluster->m_dataCluster.m_nUseHeapCount = 1;
  107. dataPos += sizeof(SMailCluster);
  108. pNewDataCluster->m_dataCluster.m_HeapPos[0] = dataPos;
  109. ASSERT(pNewDataCluster->m_pDataHeaps == NULL);
  110. pNewDataCluster->m_pDataHeaps = new SDataHeap[1];
  111. memset(&pNewDataCluster->m_pDataHeaps[0], 0, sizeof(SDataHeap));
  112. //initial the first heap
  113. dataPos += sizeof(SDataHeap);
  114. pNewDataCluster->m_pDataHeaps[0].m_blockDataStartPos = dataPos;
  115. dataPos += MAIL_HEAP_CAPACITY * MAIL_BLOCK_SIZE;
  116. m_fileHeader.m_endFilePos = dataPos;
  117. //begin to write into the file
  118. TRY
  119. {
  120. ASSERT(m_pTmpFile != NULL);
  121. m_pTmpFile->SeekToBegin();
  122. m_pTmpFile->Write(&m_fileHeader, sizeof(SMailFileHeader));
  123. m_pTmpFile->Seek(m_fileHeader.m_mailClusterHeadPos, CFile::begin);
  124. m_pTmpFile->Write(&m_pMailCluster->m_dataCluster, sizeof(SMailCluster));
  125. UINT i = 0;
  126. for (; i < m_pMailCluster->m_dataCluster.m_nUseHeapCount; i++)
  127. {
  128. m_pTmpFile->Seek(m_pMailCluster->m_dataCluster.m_HeapPos[i], CFile::begin);
  129. m_pTmpFile->Write(&m_pMailCluster->m_pDataHeaps[i], sizeof(SDataHeap));
  130. }
  131. m_pTmpFile->SetLength(m_fileHeader.m_endFilePos);
  132. }
  133. CATCH_ALL(ex)
  134. {
  135. ex->Delete();
  136. delete m_pTmpFile;
  137. m_pTmpFile = NULL;
  138. m_strFileName.Empty();
  139. m_bOpenToWrite = FALSE;
  140. return FALSE;
  141. }
  142. END_CATCH_ALL;
  143. CloseFile(TRUE);
  144. return TRUE;
  145. }
  146. ///<summary>
  147. ///   read the specified block
  148. ///</summary>
  149. BOOL CMailTmpFile::ReadMailBlock(const UINT nBlockIndex, const UINT nLen, void* pBuf)
  150. {
  151. ASSERT(pBuf != NULL);
  152. if (NULL == pBuf)
  153. {
  154. return FALSE;
  155. }
  156. if (nLen > m_pMailCluster->m_dataCluster.m_nMailBlockSize)
  157. {
  158. ASSERT(FALSE);
  159. return FALSE;
  160. }
  161. //calculate the position of the block
  162. //the block index is counted as a whole, despite different heaps
  163. int nHeapIndex = nBlockIndex / MAIL_HEAP_CAPACITY;
  164. int nRealBlockIndex = nBlockIndex % MAIL_HEAP_CAPACITY;
  165. ASSERT(nHeapIndex < MAIL_CLUSTER_CAPACITY);
  166. BOOL bNeedClose = ReOpenFile();
  167. ASSERT(m_pTmpFile != NULL);
  168. TRY
  169. {
  170. MAILFILEPOS filePos = m_pMailCluster->m_pDataHeaps[nHeapIndex].m_blockDataStartPos
  171. + nRealBlockIndex * m_pMailCluster->m_dataCluster.m_nMailBlockSize;
  172. m_pTmpFile->Seek(filePos, CFile::begin);
  173. m_pTmpFile->Read(pBuf, nLen);
  174. }
  175. CATCH_ALL(ex)
  176. {
  177. ex->Delete();
  178. CloseFile(bNeedClose);
  179. return FALSE;
  180. }
  181. END_CATCH_ALL;
  182. CloseFile(bNeedClose);
  183. return TRUE;
  184. }
  185. ///<summary>
  186. ///   write the specified block
  187. ///</summary>
  188. BOOL CMailTmpFile::WriteMailBlock(const UINT nBlockIndex, void* pBuf, const UINT nLen)
  189. {
  190. ASSERT(pBuf != NULL);
  191. if (NULL == pBuf)
  192. {
  193. return FALSE;
  194. }
  195. if (nLen > m_pMailCluster->m_dataCluster.m_nMailBlockSize)
  196. {
  197. ASSERT(FALSE);
  198. return FALSE;
  199. }
  200. //calculate the position of the block
  201. //the block index is counted as a whole, despite different heaps
  202. int nHeapIndex = nBlockIndex / MAIL_HEAP_CAPACITY;
  203. int nRealBlockIndex = nBlockIndex % MAIL_HEAP_CAPACITY;
  204. ASSERT(nHeapIndex < MAIL_CLUSTER_CAPACITY);
  205. BOOL bNeedClose = ReOpenFile();
  206. ASSERT(m_pTmpFile != NULL);
  207. TRY 
  208. {
  209. MAILFILEPOS filePos = m_pMailCluster->m_pDataHeaps[nHeapIndex].m_blockDataStartPos 
  210. + nRealBlockIndex * m_pMailCluster->m_dataCluster.m_nMailBlockSize;
  211. m_pTmpFile->Seek(filePos, CFile::begin);
  212. m_pTmpFile->Write(pBuf, nLen);
  213. }
  214. CATCH_ALL(ex)
  215. {
  216. ex->Delete();
  217. CloseFile(bNeedClose);
  218. return FALSE;
  219. }
  220. END_CATCH_ALL;
  221. CloseFile(bNeedClose);
  222. return TRUE;
  223. }
  224. ///<summary>
  225. ///   apply specified number of blocks to save the mails
  226. ///</summary>
  227. UINT CMailTmpFile::ApplyMailBlocks(const UINT nCount, const UINT nStartBlockIndex /* = 0 */)
  228. {
  229. ASSERT(nStartBlockIndex >= 0);
  230. ASSERT(nCount > 0);
  231. BOOL bNeedClose = ReOpenFile();
  232. //find the first continuous blocks to apply
  233. UINT nUseHeapCount = m_pMailCluster->m_dataCluster.m_nUseHeapCount;
  234. UINT nNoUseCount = 0;
  235. UINT nStartIndex = 0;
  236. BOOL bFound = FALSE;
  237. for (UINT i = 0; i < nUseHeapCount; i++)
  238. {
  239. for (UINT j = 0; j < MAIL_HEAP_CAPACITY; j++)
  240. {
  241. if (j + i * MAIL_HEAP_CAPACITY < nStartBlockIndex)
  242. {//seek to the nStartBlockIndex
  243. continue;
  244. }
  245. //find continuous blocks without use
  246. if (FLAG_NO_USE == m_pMailCluster->m_pDataHeaps[i].m_UseFlags[j])
  247. {
  248. if (0 == nNoUseCount)
  249. {
  250. nStartIndex = i * MAIL_HEAP_CAPACITY + j;
  251. }
  252. nNoUseCount++;
  253. if (nNoUseCount >= nCount)
  254. {
  255. bFound = TRUE;
  256. break;
  257. }
  258. }
  259. else
  260. {
  261. nNoUseCount = 0;
  262. }
  263. }
  264. if (bFound)
  265. {
  266. break;
  267. }
  268. }
  269. //change the flags to denote that those blocks will be used
  270. if (bFound)
  271. {
  272. ASSERT(nNoUseCount == nCount || nCount == 0);
  273. for (UINT i = 0; i < nCount; i++)
  274. {
  275. m_pMailCluster->m_pDataHeaps[(nStartIndex + i) / MAIL_HEAP_CAPACITY].m_UseFlags[(nStartIndex + i) % MAIL_HEAP_CAPACITY] = FLAG_IS_USE;
  276. }
  277. TRY 
  278. {
  279. ASSERT(m_pTmpFile != NULL);
  280. UINT nDataHeap = nStartIndex / MAIL_HEAP_CAPACITY;
  281. while (TRUE)
  282. {
  283. ASSERT(m_pMailCluster->m_dataCluster.m_HeapPos[nDataHeap] != 0);
  284. m_pTmpFile->Seek(m_pMailCluster->m_dataCluster.m_HeapPos[nDataHeap], CFile::begin);
  285. m_pTmpFile->Write(&m_pMailCluster->m_pDataHeaps[nDataHeap], sizeof(SDataHeap));
  286. nDataHeap++;
  287. if ((nDataHeap * MAIL_HEAP_CAPACITY) > (nStartIndex + nCount) || nDataHeap >= nUseHeapCount)
  288. {
  289. break;
  290. }
  291. }
  292. }
  293. CATCH_ALL (ex)
  294. {
  295. ex->Delete();
  296. }
  297. END_CATCH_ALL;
  298. CloseFile(bNeedClose);
  299. return nStartIndex;
  300. }
  301. //create a new heap if needed
  302. int nCreateHeapCount = (nCount - nNoUseCount) / MAIL_HEAP_CAPACITY + 1;
  303. SDataHeap* pNewHeaps = new SDataHeap[nUseHeapCount + nCreateHeapCount];
  304. memcpy(pNewHeaps, m_pMailCluster->m_pDataHeaps, sizeof(SDataHeap) * nUseHeapCount);
  305. memset(pNewHeaps + nUseHeapCount, 0 , sizeof(SDataHeap) * nCreateHeapCount);
  306. delete []m_pMailCluster->m_pDataHeaps;
  307. m_pMailCluster->m_pDataHeaps = pNewHeaps;
  308. //save the relevant information 
  309. ASSERT(m_pTmpFile != NULL);
  310. MAILFILEPOS curFilePos = m_fileHeader.m_endFilePos;
  311. for (int i = 0; i < nCreateHeapCount; i++)
  312. {
  313. m_pMailCluster->m_dataCluster.m_HeapPos[nUseHeapCount + i] = curFilePos;
  314. curFilePos += sizeof(SDataHeap);
  315. pNewHeaps[nUseHeapCount + i].m_blockDataStartPos = curFilePos;
  316. curFilePos += MAIL_HEAP_CAPACITY * m_pMailCluster->m_dataCluster.m_nMailBlockSize;
  317. m_pTmpFile->Seek(m_pMailCluster->m_dataCluster.m_HeapPos[nUseHeapCount + i], CFile::begin);
  318. m_pTmpFile->Write(&pNewHeaps[nUseHeapCount + i], sizeof(SDataHeap));
  319. }
  320. m_fileHeader.m_endFilePos = curFilePos;
  321. m_pMailCluster->m_dataCluster.m_nUseHeapCount = nUseHeapCount + nCreateHeapCount;
  322. m_pTmpFile->Seek(m_pMailCluster->m_selfFilePos, CFile::begin);
  323. m_pTmpFile->Write(&m_pMailCluster->m_dataCluster, sizeof(SMailCluster));
  324. m_pTmpFile->SeekToBegin();
  325. m_pTmpFile->Write(&m_fileHeader, sizeof(SMailFileHeader));
  326. m_pTmpFile->SetLength(m_fileHeader.m_endFilePos);
  327. //apply with the new heap added
  328. UINT nAppliedBlock = ApplyMailBlocks(nCount, nStartBlockIndex);
  329. CloseFile(bNeedClose);
  330. return nAppliedBlock;
  331. }
  332. ///<summary>
  333. ///   release the specified blocks that will not be used
  334. ///</summary>
  335. BOOL CMailTmpFile::ReleaseMailBlocks(IN const UINT nStartIndex, IN const UINT nCount)
  336. {
  337. ASSERT(nStartIndex >= 0);
  338. ASSERT(nCount > 0);
  339. ASSERT(nStartIndex / MAIL_HEAP_CAPACITY < m_pMailCluster->m_dataCluster.m_nUseHeapCount);
  340. BOOL bNeedClose = ReOpenFile();
  341. //just change the flags
  342. for (UINT i = 0; i < nCount; i++)
  343. {
  344. m_pMailCluster->m_pDataHeaps[(nStartIndex + i) / MAIL_HEAP_CAPACITY].m_UseFlags[(nStartIndex + i) % MAIL_HEAP_CAPACITY] = FLAG_NO_USE;
  345. }
  346. TRY 
  347. {
  348. ASSERT(m_pTmpFile != NULL);
  349. UINT nDataHeap = nStartIndex / MAIL_HEAP_CAPACITY;
  350. while (TRUE)
  351. {
  352. ASSERT(m_pMailCluster->m_dataCluster.m_HeapPos[nDataHeap] != 0);
  353. m_pTmpFile->Seek(m_pMailCluster->m_dataCluster.m_HeapPos[nDataHeap], CFile::begin);
  354. m_pTmpFile->Write(&m_pMailCluster->m_pDataHeaps[nDataHeap], sizeof(SDataHeap));
  355. nDataHeap++;
  356. if ((nDataHeap * MAIL_HEAP_CAPACITY) > (nStartIndex + nCount) ||
  357. nDataHeap >= m_pMailCluster->m_dataCluster.m_nUseHeapCount)
  358. {
  359. break;
  360. }
  361. }
  362. }
  363. CATCH_ALL (ex)
  364. {
  365. ex->Delete();
  366. CloseFile(bNeedClose);
  367. return FALSE;
  368. }
  369. END_CATCH_ALL;
  370. CloseFile(bNeedClose);
  371. return TRUE;
  372. }
  373. ///<summary>
  374. ///   Test if the file to save mails has been opened
  375. ///</summary>
  376. BOOL CMailTmpFile::IsOpened()
  377. {
  378. return m_pTmpFile != NULL;
  379. }
  380. ///<summary>
  381. ///   load the mails from the file
  382. ///</summary>
  383. BOOL CMailTmpFile::LoadFromTmpFile()
  384. {
  385. TRY
  386. {
  387. ASSERT(m_pTmpFile != NULL);
  388. //read the file header first
  389. m_pTmpFile->SeekToBegin();
  390. m_pTmpFile->Read(&m_fileHeader, sizeof(SMailFileHeader));
  391. //validate something, no use now, preserved for future use
  392. if (memcmp(m_fileHeader.m_szIdentity, SZ_MAILFILE_IDENTITY, 8) != 0)
  393. {
  394. return FALSE;
  395. }
  396. if (m_fileHeader.m_nVersion > CUR_MAILFILE_VERSION)
  397. {
  398. return FALSE;
  399. }
  400. //read the data cluster
  401. if(!LoadMailCluster(m_fileHeader.m_mailClusterHeadPos))
  402. {
  403. return FALSE;
  404. }
  405. }
  406. CATCH_ALL(ex)
  407. {
  408. ex->Delete();
  409. return FALSE;
  410. }
  411. END_CATCH_ALL;
  412. return TRUE;
  413. }
  414. ///<summary>
  415. ///   close the file to save the mails
  416. ///</summary>
  417. void CMailTmpFile::CloseFile(BOOL bRealClose)
  418. {
  419. if (!bRealClose)
  420. {
  421. return;
  422. }
  423. if (m_pTmpFile != NULL)
  424. {
  425. m_pTmpFile->Close();
  426. CFile *pDbFile = m_pTmpFile;
  427. m_pTmpFile =NULL;
  428. delete pDbFile;
  429. }
  430. }
  431. ///<summary>
  432. ///   load the mails from the specified cluster
  433. ///</summary>
  434. BOOL CMailTmpFile::LoadMailCluster(MAILFILEPOS filePos/*, CDataCluster *pParentMailCluster*/)
  435. {
  436. ASSERT(m_pTmpFile != NULL);
  437. CDataCluster* pNewDataCluster = new CDataCluster();
  438. pNewDataCluster->m_selfFilePos = filePos;
  439. m_pTmpFile->Seek(filePos, CFile::begin);
  440. m_pTmpFile->Read(&pNewDataCluster->m_dataCluster, sizeof(SMailCluster));
  441. ASSERT(pNewDataCluster->m_pDataHeaps == NULL);
  442. ASSERT(pNewDataCluster->m_dataCluster.m_nUseHeapCount > 0 &&
  443. pNewDataCluster->m_dataCluster.m_nUseHeapCount < MAIL_CLUSTER_CAPACITY);
  444. pNewDataCluster->m_pDataHeaps = new SDataHeap[pNewDataCluster->m_dataCluster.m_nUseHeapCount];
  445. int nHeapCount = pNewDataCluster->m_dataCluster.m_nUseHeapCount;
  446. int i = 0;
  447. for (; i < nHeapCount; i++)
  448. {
  449. m_pTmpFile->Seek(pNewDataCluster->m_dataCluster.m_HeapPos[i], CFile::begin);
  450. m_pTmpFile->Read(&pNewDataCluster->m_pDataHeaps[i], sizeof(SDataHeap));
  451. }
  452. m_pMailCluster = pNewDataCluster;
  453. return TRUE;
  454. }
  455. ///<summary>
  456. ///   reopen the file if it is closed
  457. ///</summary>
  458. BOOL CMailTmpFile::ReOpenFile()
  459. {
  460. if (IsOpened())
  461. {
  462. return FALSE;
  463. }
  464. CFile* pTmpFile = new CFile();
  465. UINT nOpenFlag = CFile::modeRead;
  466. if (m_bOpenToWrite)
  467. {
  468. nOpenFlag = CFile::modeReadWrite;
  469. }
  470. ASSERT(!m_strFileName.IsEmpty());
  471. if (!pTmpFile->Open(m_strFileName, nOpenFlag))
  472. {
  473. delete pTmpFile;
  474. pTmpFile = NULL;
  475. return FALSE;
  476. }
  477. m_pTmpFile = pTmpFile;
  478. return TRUE;
  479. }