chunkres.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:45k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: chunkres.cpp,v 1.14.32.4 2004/07/09 01:44:51 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hxslist.h"
  50. #include "chunkres.h"
  51. #include "hlxclib/stdlib.h" // needed for MAX_PATH
  52. #include "hlxclib/stdio.h" // for fopen(), etc.
  53. #include "hlxclib/limits.h" // for INT_MAX, etc.
  54. #include "hlxclib/fcntl.h" // for O_CREAT, etc.
  55. #include "hlxclib/io.h"
  56. #include "hlxclib/windows.h"
  57. #include "chxdataf.h" // cross platform file object
  58. #ifdef _MACINTOSH
  59. #ifdef _MAC_MACHO
  60. #include <unistd.h> // for unlink call
  61. #else
  62. #include <unix.h> // for unlink call
  63. #undef _UNIX //defined in unixmac.h
  64. #endif
  65. #endif
  66. #ifdef _UNIX
  67. #include <unistd.h>  // for unlink
  68. #ifndef _MAX_PATH
  69. #define _MAX_PATH 256
  70. #endif
  71. #endif
  72. #ifdef _SYMBIAN
  73. #include <unistd.h> //for unlink
  74. #endif
  75. #include "hxheap.h"
  76. #ifdef _DEBUG
  77. #undef HX_THIS_FILE
  78. static const char HX_THIS_FILE[] = __FILE__;
  79. #endif
  80. /////////////////////////////////////////////////////////////////////////////
  81. //
  82. // Method:
  83. //
  84. // CChunkyResMgr::OpenResource()
  85. //
  86. // Purpose:
  87. //
  88. // Opens an existing resource or creates a new resource.
  89. //
  90. // Parameters:
  91. //
  92. // CChunkyRes** ppChunkyRes
  93. // Memory location that will be filled in on output with the pointer
  94. // to the opened CChunkRes object.
  95. //
  96. // const char* pResName
  97. // Unique name of the resource to open or create.
  98. //
  99. // Return:
  100. //
  101. // HX_RESULT
  102. // Possible errors include: TBD.
  103. //
  104. HX_RESULT CChunkyResMgr::OpenResource(CChunkyRes** ppChunkyRes, const char* pResName)
  105. {
  106.     HX_RESULT theErr = HXR_OK;
  107.     HX_ASSERT(ppChunkyRes && pResName);
  108.     
  109.     void* pData;
  110.     if (m_OpenResources.Lookup(pResName, pData))
  111.     {
  112. *ppChunkyRes = (CChunkyRes*)pData;
  113.     }
  114.     else if (m_ClosedResources.Lookup(pResName, pData))
  115.     {
  116. *ppChunkyRes = (CChunkyRes*)pData;
  117. HX_VERIFY(m_ClosedResources.RemoveKey(pResName));
  118. m_OpenResources.SetAt(pResName, pData);
  119. RemoveFromLRU(pResName);
  120.     }
  121.     else
  122.     {
  123. *ppChunkyRes = new CChunkyRes;
  124. if (*ppChunkyRes)
  125. {
  126.     m_OpenResources.SetAt(pResName, (void*)*ppChunkyRes);
  127. }
  128. else
  129. {
  130.     theErr = HXR_OUTOFMEMORY;
  131. }
  132.     }
  133.     return theErr;
  134. }
  135. /////////////////////////////////////////////////////////////////////////////
  136. //
  137. // Method:
  138. //
  139. // CChunkyResMgr::CloseResource()
  140. //
  141. // Purpose:
  142. //
  143. // Closes an existing resource. Closed resources may be discarded.
  144. //
  145. // Parameters:
  146. //
  147. // CChunkyRes* pChunkyRes
  148. // Pointer to a previously opened CChunkRes object.
  149. //
  150. // Return:
  151. //
  152. // HX_RESULT
  153. // Possible errors include: TBD.
  154. //
  155. HX_RESULT CChunkyResMgr::CloseResource(CChunkyRes* pChunkyRes)
  156. {
  157.     HX_RESULT theErr = HXR_FAIL;
  158.     POSITION pPos = m_OpenResources.GetStartPosition();
  159.     while (pPos)
  160.     {
  161. CHXString key;
  162. void* pData;
  163. m_OpenResources.GetNextAssoc(pPos, key, pData);
  164. if (pData == (void*)pChunkyRes)
  165. {
  166.     HX_VERIFY(m_OpenResources.RemoveKey(key));
  167.     m_ClosedResources.SetAt(key, pData);
  168.     HX_ASSERT(!m_LRUResources.FindString(key));
  169.     m_LRUResources.AddTailString(key);
  170.     theErr = HXR_OK;
  171. }
  172.     }
  173.     if (theErr == HXR_OK)
  174.     {
  175. DiscardDiskData();
  176.     }
  177.     return theErr;
  178. }
  179. /////////////////////////////////////////////////////////////////////////////
  180. //
  181. // Method:
  182. //
  183. // CChunkyResMgr::CloseResource()
  184. //
  185. // Purpose:
  186. //
  187. // Closes an existing resource. Closed resources may be discarded.
  188. //
  189. // Parameters:
  190. //
  191. // const char* pResName
  192. // Unique name of a previously opened resource.
  193. //
  194. // Return:
  195. //
  196. // HX_RESULT
  197. // Possible errors include: TBD.
  198. //
  199. HX_RESULT CChunkyResMgr::CloseResource(const char* pResName)
  200. {
  201.     HX_RESULT theErr = HXR_FAIL;
  202.     void* pData;
  203.     if (m_OpenResources.Lookup(pResName, pData))
  204.     {
  205. HX_VERIFY(m_OpenResources.RemoveKey(pResName));
  206. m_ClosedResources.SetAt(pResName, pData);
  207. HX_ASSERT(!m_LRUResources.FindString(pResName));
  208. m_LRUResources.AddTailString(pResName);
  209. theErr = HXR_OK;
  210.     }
  211.     if (theErr == HXR_OK)
  212.     {
  213. DiscardDiskData();
  214.     }
  215.     return theErr;
  216. }
  217. /////////////////////////////////////////////////////////////////////////////
  218. //
  219. // Method:
  220. //
  221. // CChunkyResMgr::DiscardResource()
  222. //
  223. // Purpose:
  224. //
  225. // Discards a resource. Closed resources may be discarded.
  226. //
  227. // Parameters:
  228. //
  229. // const char* pResName
  230. // Unique name of a previously opened resource.
  231. //
  232. // Return:
  233. //
  234. // HX_RESULT
  235. // Possible errors include: TBD.
  236. //
  237. HX_RESULT CChunkyResMgr::DiscardResource(const char* pResName)
  238. {
  239.     HX_RESULT theErr = HXR_FAIL;
  240.     void* pData;
  241.     if (m_OpenResources.Lookup(pResName, pData))
  242.     {
  243. HX_VERIFY(m_OpenResources.RemoveKey(pResName));
  244. CChunkyRes* pRes = (CChunkyRes*)pData;
  245. delete pRes;
  246. theErr = HXR_OK;
  247.     }
  248.     if (m_ClosedResources.Lookup(pResName, pData))
  249.     {
  250. HX_VERIFY(m_ClosedResources.RemoveKey(pResName));
  251. RemoveFromLRU(pResName);
  252. CChunkyRes* pRes = (CChunkyRes*)pData;
  253. delete pRes;
  254. theErr = HXR_OK;
  255.     }
  256.     return theErr;
  257. }
  258. /////////////////////////////////////////////////////////////////////////////
  259. //
  260. // Method:
  261. //
  262. // CChunkyResMgr::FindResource()
  263. //
  264. // Purpose:
  265. //
  266. // Looks to see if the resource exists.
  267. //
  268. // Parameters:
  269. //
  270. // const char* pResName
  271. // Unique name of a previously opened resource.
  272. //
  273. // Return:
  274. //
  275. // HX_RESULT
  276. HX_RESULT
  277. CChunkyResMgr::FindResource(const char* pResName)
  278. {
  279.     void* pData;
  280.     if (m_OpenResources.Lookup(pResName, pData) ||
  281. m_ClosedResources.Lookup(pResName, pData))
  282.     {
  283. return HXR_OK;
  284.     }
  285.     return HXR_FAIL;
  286. }
  287. /////////////////////////////////////////////////////////////////////////////
  288. //
  289. // Method:
  290. //
  291. // CChunkyResMgr::SetDiskUsageThreshold()
  292. //
  293. // Purpose:
  294. //
  295. // Sets the Disk Usage threshold for the chunky resource manager.
  296. // If closed resources amount to more than the threshold, then they
  297. // will be discarded.
  298. //
  299. // Parameters:
  300. //
  301. // ULONG32 diskUsage
  302. // Disk usage in bytes which will be allowed for closed resources.
  303. //
  304. // Return:
  305. //
  306. // None.
  307. //
  308. void CChunkyResMgr::SetDiskUsageThreshold(ULONG32 diskUsage)
  309. {
  310.     m_ulDiskUsage = diskUsage;
  311.     DiscardDiskData();
  312. }
  313. void CChunkyResMgr::DiscardDiskData()
  314. {
  315.     void* pData = NULL;
  316.     CChunkyRes* pRes = NULL;
  317.     ULONG32 ulTotal = 0;
  318.     // Count the total disk usage
  319.     POSITION pPos = m_ClosedResources.GetStartPosition();
  320.     while (pPos)
  321.     {
  322. CHXString key;
  323. m_ClosedResources.GetNextAssoc(pPos, key, pData);
  324. HX_ASSERT(pData);
  325. pRes = (CChunkyRes*)pData;
  326. ulTotal += pRes->GetDiskUsage();
  327.     }
  328.     // Trim as much as we need until we're under the disk usage threshold.
  329.     pPos = m_LRUResources.GetHeadPosition();
  330.     while (pPos && ulTotal > m_ulDiskUsage)
  331.     {
  332. CHXString* pResName = m_LRUResources.GetNext(pPos);
  333. HX_ASSERT(pResName);
  334. if (m_ClosedResources.Lookup(*pResName, pData))
  335. {
  336.     HX_ASSERT(pData);
  337.     pRes = (CChunkyRes*)pData;
  338.     ULONG32 ulSize = pRes->GetDiskUsage();
  339.     if (ulSize)
  340.     {
  341. HX_ASSERT(ulSize <= ulTotal);
  342. ulTotal -= ulSize;
  343. m_ClosedResources.RemoveKey(*pResName);
  344. RemoveFromLRU(*pResName);
  345. delete pRes;
  346.     }
  347. }
  348.     }
  349. }
  350. void CChunkyResMgr::RemoveFromLRU(const char* pResName)
  351. {
  352.     POSITION pPos = m_LRUResources.GetHeadPosition();
  353.     POSITION pPrev; 
  354.     while (pPos)
  355.     {
  356. pPrev = pPos;
  357. CHXString* pStr = m_LRUResources.GetNext(pPos);
  358. if (!strcmp(*pStr, pResName))
  359. {
  360.     m_LRUResources.RemoveAt(pPrev);
  361. }
  362.     }
  363. }
  364. /////////////////////////////////////////////////////////////////////////////
  365. //
  366. // Method:
  367. //
  368. // CChunkyResMgr::CChunkyResMgr()
  369. //
  370. // Purpose:
  371. //
  372. // Construtor for chunky resource manager.
  373. //
  374. // Parameters:
  375. //
  376. // None.
  377. //
  378. // Return:
  379. //
  380. // N/A
  381. //
  382. CChunkyResMgr::CChunkyResMgr()
  383.     : m_ulDiskUsage(0)
  384. {
  385. }
  386. /////////////////////////////////////////////////////////////////////////////
  387. //
  388. // Method:
  389. //
  390. // CChunkyResMgr::~CChunkyResMgr()
  391. //
  392. // Purpose:
  393. //
  394. // Destructor for chunky resource manager.
  395. //
  396. // Parameters:
  397. //
  398. // None.
  399. //
  400. // Return:
  401. //
  402. // N/A
  403. //
  404. CChunkyResMgr::~CChunkyResMgr()
  405. {
  406.     CHXString key;
  407.     CChunkyRes* pRes;
  408.     POSITION p;
  409.     
  410.     p = m_OpenResources.GetStartPosition();
  411.     while (p)
  412.     {
  413. m_OpenResources.GetNextAssoc(p, key, (void*&)pRes);
  414. HX_DELETE(pRes);
  415.     }
  416.     p = m_ClosedResources.GetStartPosition();
  417.     while (p)
  418.     {
  419. m_ClosedResources.GetNextAssoc(p, key, (void*&)pRes);
  420. HX_DELETE(pRes);
  421.     }
  422. }
  423. /////////////////////////////////////////////////////////////////////////////
  424. //
  425. // Method:
  426. //
  427. // CChunkyRes::DiscardRange()
  428. //
  429. // Purpose:
  430. //
  431. // Discards the specified range of the file.
  432. //
  433. // Parameters:
  434. //
  435. // The location and length of the range to be discarded.
  436. //
  437. // Return:
  438. //
  439. // HX_RESULT
  440. // Possible errors include: TBD.
  441. //
  442. HX_RESULT CChunkyRes::DiscardRange( ULONG32 offset, ULONG32 count )
  443. {
  444.     HX_RESULT theErr = HXR_OK;
  445.     
  446.     // Big picture of this function is that it takes
  447.     // care of the end cases, where part of a chunk may
  448.     // be invalidated; then it totally removes all the
  449.     // chunks wholly contained by the range.
  450.     
  451.     ULONG32 ulOffsetIntoChunk;
  452.     
  453.     ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE;
  454.     
  455.     ulOffsetIntoChunk = offset % DEF_CHUNKYRES_CHUNK_SIZE;
  456.     
  457.     ULONG32 ulLastChunk  = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE;
  458.     
  459.     if (ulFirstChunk == ulLastChunk)
  460.     {
  461. // if the range is all in one chunk, deal with that simplest
  462. // case and ignore the more complicated scenarios.
  463. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ulFirstChunk];
  464. HX_ASSERT(pChunk);
  465. pChunk->AddValidRange(ulOffsetIntoChunk, count, FALSE);
  466. return theErr;
  467.     }
  468.     
  469.     if (ulOffsetIntoChunk)
  470.     {
  471.         // OK, we have a chunk that needs to be partially invalidated.
  472.         
  473. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ulFirstChunk];
  474. HX_ASSERT(pChunk);
  475. pChunk->AddValidRange(ulOffsetIntoChunk, DEF_CHUNKYRES_CHUNK_SIZE - ulOffsetIntoChunk, FALSE);
  476.         ulFirstChunk++;
  477.     }
  478.     
  479.     ulOffsetIntoChunk = (offset+count) % DEF_CHUNKYRES_CHUNK_SIZE;
  480.     if (ulOffsetIntoChunk)
  481.     {
  482.         // OK, the final chunk needs to be partially invalidated.
  483.         
  484. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ulLastChunk];
  485. HX_ASSERT(pChunk);
  486. pChunk->AddValidRange(0, ulOffsetIntoChunk, FALSE);
  487.     }
  488.     
  489.     for (ULONG32 ulWhichChunk = ulFirstChunk; ulWhichChunk < ulLastChunk; ulWhichChunk++)
  490.     {
  491. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ulWhichChunk];
  492. // if the chunk doesn't (yet?) exist, then it's considered invalid.
  493. if (pChunk)
  494. {
  495.     ULONG32 ulTempOffset = pChunk->GetTempFileOffset();
  496.     if (ulTempOffset)
  497.     {
  498. m_FreeDiskOffsets.AddHead((void*)ulTempOffset);
  499.     }
  500.     
  501.     delete pChunk;
  502.     m_Chunks[ulWhichChunk] = NULL;
  503. }
  504.     }
  505.     
  506.     return theErr;
  507. }
  508. /////////////////////////////////////////////////////////////////////////////
  509. //
  510. // Method:
  511. //
  512. // CChunkyRes::GetDiskUsage()
  513. //
  514. // Purpose:
  515. //
  516. // Returns the entire disk usage of a resource.
  517. //
  518. // Parameters:
  519. //
  520. // None.
  521. //
  522. // Return:
  523. //
  524. // ULONG32
  525. // Total amount of diskspace the resource's chunks consume.
  526. //
  527. ULONG32 CChunkyRes::GetDiskUsage() const
  528. {
  529. return (m_Chunks.GetSize() * DEF_CHUNKYRES_CHUNK_SIZE);
  530. }
  531. BOOL CChunkyRes::HasPartialData(ULONG32 length, ULONG32 offset /* = 0 */)
  532. {
  533. return (GetContiguousLength(offset) >= length);
  534. }
  535. ULONG32 CChunkyRes::GetContiguousLength(ULONG32 offset /* = 0 */)
  536. {
  537. ULONG32 contiguousLength = 0;
  538. int ndx;
  539. int startNdx = offset / DEF_CHUNKYRES_CHUNK_SIZE;
  540. if (startNdx < m_Chunks.GetSize())
  541. {
  542. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[startNdx];
  543. if (!pChunk) goto exit;
  544. contiguousLength = pChunk->GetValidLength(offset % DEF_CHUNKYRES_CHUNK_SIZE);
  545. if (contiguousLength != DEF_CHUNKYRES_CHUNK_SIZE - (offset % DEF_CHUNKYRES_CHUNK_SIZE))
  546. {
  547. goto exit;
  548. }
  549. }
  550. startNdx++;
  551. for (ndx = startNdx; ndx < m_Chunks.GetSize(); ndx++)
  552. {
  553. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
  554. // if there is no chunk then we are no longer contiguous.
  555. if (!pChunk)
  556. {
  557. break;
  558. }
  559. ULONG32 chunkLength = pChunk->GetValidLength();
  560. contiguousLength += chunkLength;
  561. // if this chunk is not the max length then we are no longer contiguous
  562. if (chunkLength < DEF_CHUNKYRES_CHUNK_SIZE)
  563. {
  564. break;
  565. }
  566. }
  567. exit:
  568. return contiguousLength;
  569. }
  570. /////////////////////////////////////////////////////////////////////////////
  571. //
  572. // Method:
  573. //
  574. // CChunkyRes::GetData()
  575. //
  576. // Purpose:
  577. //
  578. // Gets a block of data out of a resource.
  579. //
  580. // Parameters:
  581. //
  582. // ULONG32 offset
  583. // char* buf
  584. // ULONG32 count
  585. // ULONG32* actual
  586. //
  587. // Return:
  588. //
  589. // HX_RESULT
  590. // Possible errors include: TBD.
  591. //
  592. HX_RESULT CChunkyRes::GetData(ULONG32 offset, char* buf, ULONG32 count, ULONG32* actual)
  593. {
  594. HX_RESULT theErr = HXR_OK;
  595. int ndx;
  596. ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE;
  597. ULONG32 ulLastChunk  = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE;
  598. HX_ASSERT(ulFirstChunk < INT_MAX);
  599. HX_ASSERT(ulLastChunk < INT_MAX);
  600. int nFirstChunk  = (int)ulFirstChunk;
  601. int nLastChunk   = (int)ulLastChunk;
  602. HX_ASSERT(m_Chunks.GetSize() >= nLastChunk+1);
  603. ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE);
  604. ULONG32 chunkCount  = count;
  605. ULONG32 baseOffset  = 0;
  606. *actual = 0; // -fst
  607. for (ndx = nFirstChunk; (ndx <= nLastChunk) && chunkCount; ndx++)
  608. {
  609. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
  610. if (!pChunk)
  611. {
  612.     // with random access, it's feasible that there's a null chunk.
  613.     
  614.     theErr = HXR_CHUNK_MISSING;
  615.     goto exit;
  616. }
  617. HX_ASSERT_VALID_PTR(pChunk);
  618. ULONG32 chunkActual = 0;
  619. // Actually get the data from the chunk!
  620. ULONG32 chunkAmount = min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset,chunkCount);
  621. theErr = pChunk->GetData(chunkOffset,buf+baseOffset,chunkAmount,&chunkActual);
  622. if (theErr != HXR_OK)
  623. {
  624. goto exit;
  625. }
  626. // What?!?!
  627. HX_ASSERT(chunkActual == chunkAmount);
  628. *actual += chunkActual; // -fst
  629. // reduce the chunk count...
  630. chunkCount -= chunkAmount;
  631. baseOffset += chunkAmount;
  632. // only the first chunk has an offset!
  633. chunkOffset = 0;
  634. }
  635. // Remember how many bytes have been served to the user,
  636. // in case they want us to discard used data
  637. m_ulUsedBytes = offset + *actual;
  638. // Discard chunks that have been fully served to the user
  639. if (m_bDiscardUsedData)
  640. {
  641. nLastChunk = (int)(m_ulUsedBytes/DEF_CHUNKYRES_CHUNK_SIZE);
  642. for (ndx = m_ulFirstChunkIdx; ndx < nLastChunk - 1; ndx++)
  643. {
  644. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
  645. HX_ASSERT_VALID_PTR(pChunk);
  646. UINT32 ulTempOffset = pChunk->GetTempFileOffset();
  647. pChunk->DiscardDiskData();
  648. // Increment the first valid chunk index
  649. m_ulFirstChunkIdx++;
  650. if (ulTempOffset)
  651. {
  652.     // Add the disk space to the free space list
  653.     m_FreeDiskOffsets.AddHead((void*)ulTempOffset);
  654. }
  655. }
  656. }
  657. exit:
  658. return theErr;
  659. }
  660. HX_RESULT 
  661. CChunkyRes::GetContiguousDataPointer(ULONG32 offset, char*& buf, ULONG32 count)
  662. {
  663.     HX_RESULT theErr = HXR_OK;
  664.     HX_ASSERT(m_bDiscardUsedData == FALSE && m_bDisableDiskIO == FALSE);
  665.     ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE;
  666.     ULONG32 ulLastChunk  = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE;
  667.     HX_ASSERT(ulFirstChunk < INT_MAX);
  668.     HX_ASSERT(ulLastChunk < INT_MAX);
  669.     // if the required data length spans two chunks, we cannot have 
  670.     // contiguous memory
  671.     if (ulFirstChunk != ulLastChunk)
  672.     {
  673. return HXR_FAIL;
  674.     }
  675.     int nFirstChunk  = (int)ulFirstChunk;
  676.     if (m_Chunks.GetSize() < nFirstChunk+1)
  677.     {
  678. m_Chunks.SetSize(nFirstChunk+1);
  679.     }
  680.     
  681.     CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[nFirstChunk];
  682.     if (!pChunk)
  683.     {
  684. pChunk = new CChunkyResChunk(this);
  685. if (m_bDisableDiskIO)
  686. {
  687.     pChunk->DisableDiskIO();
  688. }
  689. m_Chunks[nFirstChunk] = pChunk;
  690.     }
  691.     HX_ASSERT(m_Chunks.GetSize() >= nFirstChunk+1);
  692.     HX_ASSERT_VALID_PTR(pChunk);
  693.     ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE);
  694.     // Actually get the data from the chunk!
  695.     ULONG32 chunkAmount = min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset, count);
  696.     theErr = pChunk->GetContiguousDataPointer(chunkOffset,buf,chunkAmount);
  697.     return theErr;
  698. }
  699. /////////////////////////////////////////////////////////////////////////////
  700. //
  701. // Method:
  702. //
  703. // CChunkyRes::SetData()
  704. //
  705. // Purpose:
  706. //
  707. // Sets a block of data in a resource.
  708. //
  709. // Parameters:
  710. //
  711. // ULONG32 offset
  712. // const char* buf
  713. // ULONG32 count
  714. //
  715. // Return:
  716. //
  717. // HX_RESULT
  718. // Possible errors include: TBD.
  719. //
  720. HX_RESULT CChunkyRes::SetData(ULONG32 offset, const char* buf, ULONG32 count)
  721. {
  722. HX_RESULT theErr = HXR_OK;
  723. ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE;
  724. ULONG32 ulLastChunk  = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE;
  725. HX_ASSERT(ulFirstChunk < INT_MAX);
  726. HX_ASSERT(ulLastChunk < INT_MAX);
  727. int nFirstChunk  = (int)ulFirstChunk;
  728. int nLastChunk   = (int)ulLastChunk;
  729. if (m_Chunks.GetSize() < nLastChunk+1)
  730. {
  731. m_Chunks.SetSize(nLastChunk+1);
  732. }
  733. ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE);
  734. ULONG32 chunkCount  = count;
  735. ULONG32 baseOffset  = 0;
  736. for (int ndx = nFirstChunk; ndx <= nLastChunk; ndx++)
  737. {
  738. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
  739. if (!pChunk)
  740. {
  741. pChunk = new CChunkyResChunk(this);
  742. if (m_bDisableDiskIO)
  743. {
  744.     pChunk->DisableDiskIO();
  745. }
  746. m_Chunks[ndx] = pChunk;
  747. }
  748. // Actually set the data for the chunk!
  749. theErr = pChunk->SetData(chunkOffset,buf+baseOffset,min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset,chunkCount));
  750. if (theErr != HXR_OK)
  751. {
  752. goto exit;
  753. }
  754. // reduce the chunk count...
  755. chunkCount -= (DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset);
  756. baseOffset += (DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset);
  757. // only the first chunk has an offset!
  758. chunkOffset = 0;
  759. }
  760. exit:
  761. return theErr;
  762. }
  763. void CChunkyRes::TrimDownMemoryMRU()
  764. {
  765. // If we have just reduced our allowed memory usage, then
  766. // discard the least recently used chunks till we are under
  767. // the ne threshold...
  768. if (m_CurMemUsage > m_MemUsageThreshold)
  769. {
  770. while (!m_ChunksMemoryMRU->IsEmpty() && (m_CurMemUsage > m_MemUsageThreshold))
  771. {
  772. // Get the least recently used chunk.
  773. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_ChunksMemoryMRU->GetTail();
  774. HX_ASSERT_VALID_PTR(pChunk);
  775. // Discount its usage.
  776. m_CurMemUsage -= pChunk->GetSize();
  777. // Spill this chunk to disk...
  778. pChunk->SpillToDisk();
  779. // Remove the chunk from the end of the Memory MRU
  780. m_ChunksMemoryMRU->RemoveTail();
  781. // And add the chunk to the front of the Disk MRU
  782. m_ChunksDiskMRU->AddHead(pChunk);
  783. }
  784. // How can this be?!?! Did you really mean to set the memory usage such
  785. // that there are no chunks in memory?!?
  786. HX_ASSERT(!m_ChunksMemoryMRU->IsEmpty());
  787. }
  788. }
  789. /////////////////////////////////////////////////////////////////////////////
  790. //
  791. // Method:
  792. //
  793. // CChunkyResChunk::SetMemUsageThreshold()
  794. //
  795. // Purpose:
  796. //
  797. // Sets the memory usage threshold for the chunky resource chunks.
  798. // If if chunk sizes amount to more than the threshold, then the
  799. // least recently used ones will be spilled to disk.
  800. //
  801. // Parameters:
  802. //
  803. // ULONG32 memUsage
  804. // Memory usage in bytes which will be allowed for all chunks before
  805. // least recently used chunks will be spilled to disk.
  806. //
  807. // Return:
  808. //
  809. // None.
  810. //
  811. void CChunkyRes::SetMemUsageThreshold(ULONG32 memUsage)
  812. {
  813. m_MemUsageThreshold = memUsage;
  814. TrimDownMemoryMRU();
  815. }
  816. /////////////////////////////////////////////////////////////////////////////
  817. //
  818. // Method:
  819. //
  820. // CChunkyRes::CChunkyRes()
  821. //
  822. // Purpose:
  823. //
  824. // Constructor for a chunky resource.
  825. //
  826. // Parameters:
  827. //
  828. // None.
  829. //
  830. // Return:
  831. //
  832. // N/A
  833. //
  834. CChunkyRes::CChunkyRes()
  835. : m_Chunks()
  836. , m_strTempFileName()
  837. , m_ulNextTempFileChunk(DEF_START_CHUNK_OFFSET)
  838. , m_bHasBeenOpened(FALSE)
  839. , m_bDisableDiskIO(FALSE)
  840. , m_bDiscardUsedData(FALSE)
  841. , m_ulFirstChunkIdx(0)
  842. , m_ulUsedBytes(0)
  843. , m_pMutex(0)
  844. , m_MemUsageThreshold(DEF_CHUNKYRES_MEM_THRESHOLD)
  845. , m_CurMemUsage(0)
  846. , m_ChunksMemoryMRU(NULL)
  847. , m_ChunksDiskMRU(NULL)
  848. , m_ChunkSize(DEF_CHUNKYRES_CHUNK_SIZE)
  849. {
  850. #if defined(THREADS_SUPPORTED)
  851.     HXMutex::MakeMutex(m_pMutex);
  852. #else
  853.     HXMutex::MakeStubMutex(m_pMutex);
  854. #endif
  855.     HX_ASSERT(m_pMutex);
  856.     m_ChunksMemoryMRU = new CHXSimpleList;
  857.     m_ChunksDiskMRU = new CHXSimpleList;
  858.     HX_ASSERT(m_ChunksMemoryMRU);
  859.     HX_ASSERT(m_ChunksDiskMRU);
  860. }
  861. /////////////////////////////////////////////////////////////////////////////
  862. //
  863. // Method:
  864. //
  865. // CChunkyRes::~CChunkyRes()
  866. //
  867. // Purpose:
  868. //
  869. // Destructor for a chunky resource.
  870. //
  871. // Parameters:
  872. //
  873. // None.
  874. //
  875. // Return:
  876. //
  877. // N/A
  878. //
  879. CChunkyRes::~CChunkyRes()
  880. {
  881. // If we are getting rid of the resource, then
  882. // we should discard all of the chunks...
  883. for (int ndx = 0; ndx < m_Chunks.GetSize(); ndx++)
  884. {
  885. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
  886. if (pChunk)
  887. {
  888. delete pChunk;
  889. }
  890. }
  891. HX_RESULT theErr = DiscardDiskData();
  892. HX_ASSERT(theErr == HXR_OK);
  893. if(m_ChunksMemoryMRU)
  894. {
  895.     HX_ASSERT(m_ChunksMemoryMRU->GetCount() == 0);
  896.     delete m_ChunksMemoryMRU;
  897.     m_ChunksMemoryMRU = NULL;
  898. }
  899. if(m_ChunksDiskMRU)
  900. {
  901.     HX_ASSERT(m_ChunksDiskMRU->GetCount() == 0);
  902.     delete m_ChunksDiskMRU;
  903.     m_ChunksDiskMRU = NULL;
  904. }
  905. HX_DELETE(m_pMutex);
  906. }
  907. /////////////////////////////////////////////////////////////////////////////
  908. //
  909. // Method:
  910. //
  911. // CChunkyResChunk::MakeSureChunkIsInMemory()
  912. //
  913. // Purpose:
  914. //
  915. // Get a portion of the data for a chunk.
  916. //
  917. // Parameters:
  918. //
  919. // ULONG32 offset
  920. // char* buf
  921. // ULONG32 count
  922. // ULONG32* actual
  923. //
  924. // Return:
  925. //
  926. // HX_RESULT
  927. // Possible errors include: TBD.
  928. //
  929. HX_RESULT CChunkyResChunk::MakeSureChunkIsInMemory()
  930. {
  931. HX_RESULT theErr = HXR_OK;
  932. // If we don't have a chunk pointer, then we aren't in
  933. // memory...
  934. if (!m_pChunkData)
  935. {
  936. // Find ourselves in the MRU list for Disk chunks...
  937. LISTPOSITION pos = m_pChunkRes->m_ChunksDiskMRU->Find(this);
  938. // If were found in the disk MRU list, then we have
  939. // some work to do...
  940. if (pos)
  941. {
  942. // First, remove ourselves from the disk list...
  943. m_pChunkRes->m_ChunksDiskMRU->RemoveAt(pos);
  944. // Load from disk...
  945. theErr = LoadFromDisk();
  946. if (theErr != HXR_OK)
  947. {
  948. goto exit;
  949. }
  950. }
  951. else
  952. {
  953. #ifdef _DEBUG
  954. {
  955. // We shouldn't find ourselves in the MRU list
  956. // for memory chunks... but we want to check!
  957. LISTPOSITION pos = m_pChunkRes->m_ChunksMemoryMRU->Find(this);
  958. // We shouldn't be in this list!!!!
  959. HX_ASSERT(pos == NULL);
  960. }
  961. #endif // end _DEBUG section
  962. m_pChunkData = new UCHAR[m_pChunkRes->m_ChunkSize];
  963. if (!m_pChunkData) theErr = HXR_OUTOFMEMORY;
  964. if (theErr != HXR_OK)
  965. {
  966. goto exit;
  967. }
  968.  
  969. HX_ASSERT(GetValidLength() == 0);
  970. }
  971. // Add to the front of the Memory list...
  972. m_pChunkRes->m_ChunksMemoryMRU->AddHead(this);
  973. m_pChunkRes->m_CurMemUsage += GetSize();
  974. // Make sure we don't have to much info in memory...
  975. if (!m_bDisableDiskIO)
  976. {
  977.     m_pChunkRes->TrimDownMemoryMRU();
  978.     HX_ASSERT(m_pChunkData);
  979. }
  980. }
  981. // If we are already in memory, then make sure we are at the
  982. // top of the Memory MRU list!!!
  983. else
  984. {
  985. // We should find ourselves in the MRU list
  986. // for memory chunks... but we want to check!
  987. LISTPOSITION pos = m_pChunkRes->m_ChunksMemoryMRU->Find(this);
  988. // XXXNH: If we aren't in this list it means we were paged out,
  989. // so we only need to put ourselves at the top of the MRU list
  990. if (pos)
  991. {
  992.     // First, remove ourselves from wherever we are in the
  993.     // Memory MRU list...
  994.     m_pChunkRes->m_ChunksMemoryMRU->RemoveAt(pos);
  995. }
  996. // And add ourselves to the top of the list!
  997. m_pChunkRes->m_ChunksMemoryMRU->AddHead(this);
  998. }
  999. exit:
  1000. return theErr;
  1001. }
  1002. /////////////////////////////////////////////////////////////////////////////
  1003. //
  1004. // Method:
  1005. //
  1006. // CChunkyResChunk::GetValidLength()
  1007. //
  1008. // Purpose:
  1009. //
  1010. // Determines how much of a chunk is valid
  1011. //
  1012. // Parameters:
  1013. //
  1014. // ULONG32 offset
  1015. //
  1016. // Return:
  1017. //
  1018. // HX_RESULT
  1019. // Possible errors include: TBD.
  1020. //
  1021. ULONG32 CChunkyResChunk::GetValidLength(ULONG32 offset /* = 0 */) const
  1022. {
  1023.     
  1024.     HX_ASSERT(offset < GetSize());
  1025.     
  1026.     ULONG32 ulValidLength = 0;
  1027.     
  1028. LISTPOSITION rangePos = m_ValidRanges.GetHeadPosition();
  1029. if (rangePos)
  1030. {
  1031. do
  1032. {
  1033. ValidRange* pRange = (ValidRange*)m_ValidRanges.GetNext(rangePos);
  1034. HX_ASSERT(pRange);
  1035. // see if the offset points into this particular range
  1036. if (offset >= pRange->offset
  1037. && offset <= pRange->offset + pRange->length)
  1038. {
  1039.     ulValidLength = pRange->offset + pRange->length - offset;
  1040. }
  1041. }
  1042. while (rangePos);
  1043. }
  1044.     return ulValidLength;
  1045. }
  1046. /////////////////////////////////////////////////////////////////////////////
  1047. //
  1048. // Method:
  1049. //
  1050. // CChunkyResChunk::GetData()
  1051. //
  1052. // Purpose:
  1053. //
  1054. // Get a portion of the data for a chunk.
  1055. //
  1056. // Parameters:
  1057. //
  1058. // ULONG32 offset
  1059. // char* buf
  1060. // ULONG32 count
  1061. // ULONG32* actual
  1062. //
  1063. // Return:
  1064. //
  1065. // HX_RESULT
  1066. // Possible errors include: TBD.
  1067. //
  1068. HX_RESULT CChunkyResChunk::GetData(ULONG32 offset, char* buf, ULONG32 count, ULONG32* actual)
  1069. {
  1070. HX_RESULT theErr;
  1071. if(!count)
  1072. {
  1073. *actual = count;
  1074. return HXR_OK;
  1075. }
  1076. // We should have a non-zero valid size
  1077. if (!GetValidLength(offset))
  1078. {
  1079. // This chunk must have been discarded
  1080. theErr = HXR_CHUNK_MISSING;
  1081. goto exit;
  1082. }
  1083. // Make sure this chunk is in memory!
  1084. theErr = MakeSureChunkIsInMemory();
  1085. if (theErr != HXR_OK)
  1086. {
  1087. goto exit;
  1088. }
  1089. // You can't read more than there is room in this chunk.
  1090. // CChunkyRes should prevent this case...
  1091. HX_ASSERT(offset+count <= GetSize());
  1092. // The call to MakeSureChunkIsInMemory() should have handled this!
  1093. HX_ASSERT_VALID_PTR(m_pChunkData);
  1094. *actual = min(count,GetValidLength(offset));
  1095. HX_ASSERT(*actual < UINT_MAX);
  1096. memcpy(buf,m_pChunkData+offset,(int)(*actual)); /* Flawfinder: ignore */
  1097. exit:
  1098. return theErr;
  1099. }
  1100. HX_RESULT 
  1101. CChunkyResChunk::GetContiguousDataPointer(ULONG32 offset, char*& buf, ULONG32 count)
  1102. {
  1103.     HX_RESULT theErr = HXR_OK;
  1104.     if(!count)
  1105.     {
  1106. theErr = HXR_FAIL;
  1107. goto exit;
  1108.     }
  1109.     // First, make sure this chunk is in memory!
  1110.     theErr = MakeSureChunkIsInMemory();
  1111.     if (theErr != HXR_OK)
  1112.     {
  1113. goto exit;
  1114.     }
  1115.     // You can't write more than there is room in this chunk.
  1116.     // CChunkyRes should prevent this case...
  1117.     HX_ASSERT(offset+count <= GetSize());
  1118.     // Currently, you must write to chunks in order from the
  1119.     // start of the chunk first. Random access may come in the
  1120.     // future...
  1121.     HX_ASSERT(GetValidLength(offset) > 0); // needed still at all?
  1122.     // The call to MakeSureChunkIsInMemory() should have handled this!
  1123.     HX_ASSERT_VALID_PTR(m_pChunkData);
  1124.     AddValidRange(offset, count);
  1125.     
  1126.     HX_ASSERT(count < UINT_MAX);
  1127.     buf = (char*) (m_pChunkData+offset);
  1128.     m_bModified = TRUE;
  1129. exit:
  1130.     return theErr;
  1131. }
  1132. /////////////////////////////////////////////////////////////////////////////
  1133. //
  1134. // Method:
  1135. //
  1136. // CChunkyResChunk::AddValidRange()
  1137. //
  1138. // Purpose:
  1139. //
  1140. // Mark a part of this CChunkyResChunk as valid
  1141. // Called from SetData.
  1142. //
  1143. // Parameters:
  1144. //
  1145. // ULONG32 offset
  1146. // ULONG32 length
  1147. // BOOL bValid
  1148. //
  1149. // Return:
  1150. //
  1151. // HX_RESULT
  1152. // Possible errors include: TBD.
  1153. //
  1154. HX_RESULT CChunkyResChunk::AddValidRange(ULONG32 offset, ULONG32 length, BOOL bValid /* = TRUE */)
  1155. {
  1156. HX_RESULT theErr = HXR_OK;
  1157.     int nCount = m_ValidRanges.GetCount();
  1158.     LISTPOSITION pos = m_ValidRanges.GetHeadPosition();
  1159.     if (bValid)
  1160. {
  1161. // I don't think we need to ensure that the chunk is in
  1162. // memory, although it always probably will be if this is
  1163. // called from SetData.
  1164. // Ensure that it's saying that a legal range is valid.
  1165. HX_ASSERT(offset+length <= GetSize());
  1166. // Create a new range element.
  1167. ValidRange* pNewRange = new ValidRange;
  1168. pNewRange->offset = offset;
  1169. pNewRange->length = length;
  1170. // Iterate through the valid ranges to ensure that
  1171. // none of them overlap the range we're adding now.
  1172.         for (int i=0; i<nCount; i++)
  1173. {
  1174.             ValidRange* pRange = (ValidRange*)m_ValidRanges.GetAt(pos);
  1175.             BOOL bNeedToMerge = FALSE;
  1176.             // See if this range element overlaps the front end of the
  1177.             // new range element.
  1178.             if (pRange->offset <= pNewRange->offset
  1179.             && pRange->offset + pRange->length >= pNewRange->offset)
  1180.             {
  1181.             bNeedToMerge = TRUE;
  1182.             }
  1183.             // see if this range element overlaps the back end of the
  1184.             // new range element.
  1185.             if (pRange->offset <= pNewRange->offset + pNewRange->length
  1186.             && pRange->offset + pRange->length >= pNewRange->offset + pNewRange->length)
  1187.             {
  1188.             bNeedToMerge = TRUE;
  1189.             }
  1190. // if an overlap happened, make the new range element hold
  1191. // the union of both ranges.
  1192.             if (bNeedToMerge)
  1193.             {
  1194.                 ULONG32 ulStartOfRange = min(pNewRange->offset, pRange->offset);
  1195.                 ULONG32 ulEndOfRange = max(pNewRange->offset+pNewRange->length,
  1196.                 pRange->offset+pRange->length);
  1197.                 HX_ASSERT(ulEndOfRange >= ulStartOfRange);
  1198.                 pNewRange->offset = ulStartOfRange;
  1199.                 pNewRange->length = ulEndOfRange-ulStartOfRange;
  1200.                 // delete the one we overlap with since we've ensured
  1201.                 // that pNewRange's range covers both.
  1202.                 pos = m_ValidRanges.RemoveAt(pos);
  1203.                 delete pRange;
  1204. }
  1205.             else
  1206.                 m_ValidRanges.GetAtNext(pos);
  1207. }
  1208. // Now that we're sure that nobody overlaps us, we can
  1209. // add this range.
  1210. m_ValidRanges.AddTail((void*)pNewRange);
  1211. }
  1212.     else
  1213.     {
  1214.         // bValid is false, so we're INVALIDATING a range.
  1215.         // iterate through the list of valid ranges, and for each of them
  1216.         // that overlaps the incoming range, either trim it appropriately
  1217.         // or delete it entirely.
  1218.         for (int i=0; i<nCount; i++)
  1219.         {
  1220.             ValidRange* pRange = (ValidRange*)m_ValidRanges.GetAt(pos);
  1221.             HX_ASSERT(pRange);
  1222.             // see if it's totally covered by the incoming range
  1223.             if (offset <= pRange->offset && offset+length >= pRange->offset + pRange->length)
  1224.             {
  1225.                 pos = m_ValidRanges.RemoveAt(pos);
  1226.                 delete pRange;
  1227.             }
  1228.             else
  1229.             {
  1230.                 // see if it needs to be trimmed
  1231.                 ULONG32 ulCurrentRangeEnd = pRange->offset + pRange->length;
  1232.                 ULONG32 ulRangeEnd = offset + length;
  1233.                 BOOL bNeedToTrimOffBackEnd = pRange->offset < offset && ulCurrentRangeEnd >= offset;
  1234.                 BOOL bNeedToTrimOffFrontEnd = pRange->offset < ulRangeEnd
  1235.                 && ulCurrentRangeEnd > ulRangeEnd;
  1236.                 if (bNeedToTrimOffBackEnd)
  1237.                 {
  1238.                     pRange->length = offset - pRange->offset;
  1239.                 }
  1240.                 if (bNeedToTrimOffFrontEnd)
  1241.                 {
  1242.                     // if we've also trimmed off the back end
  1243.                     // then we need to create a new range element
  1244.                     // to hold this sans-front-end element.
  1245.                     if (bNeedToTrimOffBackEnd)
  1246.                     {
  1247.                         pRange = new ValidRange;
  1248.                         m_ValidRanges.AddHead(pRange);
  1249.                     }
  1250.                     pRange->offset = ulRangeEnd;
  1251.                     pRange->length = ulCurrentRangeEnd - pRange->offset;
  1252.                 }
  1253.                 m_ValidRanges.GetAtNext(pos);
  1254.             }
  1255. }
  1256.     }
  1257.     return theErr;
  1258. }
  1259. /////////////////////////////////////////////////////////////////////////////
  1260. //
  1261. // Method:
  1262. //
  1263. // CChunkyResChunk::SetData()
  1264. //
  1265. // Purpose:
  1266. //
  1267. // Set a portion of the data for a chunk.
  1268. //
  1269. // Parameters:
  1270. //
  1271. // ULONG32 offset
  1272. // const char* buf
  1273. // ULONG32 count
  1274. //
  1275. // Return:
  1276. //
  1277. // HX_RESULT
  1278. // Possible errors include: TBD.
  1279. //
  1280. HX_RESULT CChunkyResChunk::SetData(ULONG32 offset, const char* buf, ULONG32 count)
  1281. {
  1282. // First, make sure this chunk is in memory!
  1283. HX_RESULT theErr = MakeSureChunkIsInMemory();
  1284. if (theErr != HXR_OK)
  1285. {
  1286. goto exit;
  1287. }
  1288. // You can't write more than there is room in this chunk.
  1289. // CChunkyRes should prevent this case...
  1290. HX_ASSERT(offset+count <= GetSize());
  1291. // The call to MakeSureChunkIsInMemory() should have handled this!
  1292. HX_ASSERT_VALID_PTR(m_pChunkData);
  1293. HX_ASSERT(count < UINT_MAX);
  1294.         memcpy(m_pChunkData+offset,buf,(int)(offset+count <= GetSize() ? count : GetSize() - offset));
  1295. m_bModified = TRUE;
  1296. // Make sure that it remembers that this is now a valid
  1297. // range.
  1298. AddValidRange(offset, count);
  1299. exit:
  1300. return theErr;
  1301. }
  1302. /////////////////////////////////////////////////////////////////////////////
  1303. //
  1304. // Method:
  1305. //
  1306. // CChunkyResChunk::SpillToDisk()
  1307. //
  1308. // Purpose:
  1309. //
  1310. // Spills to disk the data of a chunk.
  1311. //
  1312. // Parameters:
  1313. //
  1314. // None.
  1315. //
  1316. // Return:
  1317. //
  1318. // HX_RESULT
  1319. // Possible errors include: TBD.
  1320. //
  1321. HX_RESULT CChunkyResChunk::SpillToDisk()
  1322. {
  1323. Lock();
  1324. HX_RESULT theErr = HXR_OK;
  1325. CHXDataFile* pFile = NULL;
  1326. ULONG32 actualCount = 0;
  1327. // Don't waste any time unless we are actually modified.
  1328. // And only actually spill, if there is something to spill
  1329. if (!m_bModified || !m_pChunkData)
  1330. {
  1331. goto exit;
  1332. }
  1333. // If we have never spilled to disk, then ask the ChunkyRes
  1334. // for the temp file name and a slot to spill to.
  1335. if (!m_bPreviouslySpilled)
  1336. {
  1337. theErr = m_pChunkRes->GetTempFileChunk(pFile,m_ulTempFileOffset);
  1338. }
  1339. // Otherwise, just get the temp file name.
  1340. else
  1341. {
  1342. theErr = m_pChunkRes->GetTempFile(pFile);
  1343. }
  1344. // If we failed to open the file, then set the valid
  1345. // size to 0. If the user wants to use the data, they
  1346. // will need to handle the case of not having the data!
  1347. if (theErr != HXR_OK)
  1348. {
  1349. HX_ASSERT(pFile == NULL);
  1350. theErr = HXR_TEMP_FILE;
  1351. goto exit;
  1352. }
  1353. theErr = pFile->Seek(m_ulTempFileOffset,SEEK_SET);
  1354. if (theErr != HXR_OK)
  1355. {
  1356. theErr = HXR_TEMP_FILE;
  1357. goto exit;
  1358. }
  1359. HX_ASSERT(m_pChunkData);
  1360. actualCount = pFile->Write((char *)m_pChunkData, m_pChunkRes->m_ChunkSize);
  1361. m_bPreviouslySpilled = TRUE;
  1362. if (actualCount != m_pChunkRes->m_ChunkSize)
  1363. {
  1364. theErr = HXR_TEMP_FILE;
  1365. }
  1366. exit:
  1367. // If we created a file, then clean it up!
  1368. if (pFile)
  1369. {
  1370. delete pFile;
  1371. }
  1372. // If we had an error then record that our size is now invalid.
  1373. if (theErr != HXR_OK)
  1374. {
  1375. AddValidRange(0, m_pChunkRes->m_ChunkSize, FALSE);
  1376. m_bPreviouslySpilled = FALSE;
  1377. }
  1378. // Never the less, we do get rid of the data!
  1379. if (m_pChunkData)
  1380. {
  1381. delete[] m_pChunkData;
  1382. m_pChunkData = NULL;
  1383. }
  1384. Unlock();
  1385. return theErr;
  1386. }
  1387. /////////////////////////////////////////////////////////////////////////////
  1388. //
  1389. // Method:
  1390. //
  1391. // CChunkyResChunk::LoadFromDisk()
  1392. //
  1393. // Purpose:
  1394. //
  1395. // Loads into memory the data from the chunk previously spilled to
  1396. // disk.
  1397. //
  1398. // Parameters:
  1399. //
  1400. // None.
  1401. //
  1402. // Return:
  1403. //
  1404. // HX_RESULT
  1405. // Possible errors include: TBD.
  1406. //
  1407. HX_RESULT CChunkyResChunk::LoadFromDisk()
  1408. {
  1409. Lock();
  1410. HX_RESULT theErr = HXR_OK;
  1411. CHXDataFile* pFile = NULL;
  1412. ULONG32 amountRead = 0;
  1413. // We shouldn't be here if we have memory already allocated!
  1414. HX_ASSERT(m_pChunkData == NULL);
  1415. // If we have never spilled to disk, then there is nothing to
  1416. // load from disk!
  1417. if (!m_bPreviouslySpilled)
  1418. {
  1419. // Even if we've never been spilled, we need to make
  1420. // sure we have memory available...
  1421. m_pChunkData = new UCHAR[m_pChunkRes->m_ChunkSize];
  1422. if(!m_pChunkData)
  1423. {
  1424. theErr = HXR_OUTOFMEMORY;
  1425. goto exit;
  1426. }
  1427. goto exit;
  1428. }
  1429. // Get the temp file name.
  1430. theErr = m_pChunkRes->GetTempFile(pFile);
  1431. // If we failed to open the file, then set the valid
  1432. // size to 0. If the user wants to use the data, they
  1433. // will need to handle the case of not having the data!
  1434. if (theErr != HXR_OK)
  1435. {
  1436. HX_ASSERT(pFile == NULL);
  1437. theErr = HXR_TEMP_FILE;
  1438. goto exit;
  1439. }
  1440. theErr = pFile->Seek(m_ulTempFileOffset,SEEK_SET);
  1441. if (theErr != HXR_OK)
  1442. {
  1443. theErr = HXR_TEMP_FILE;
  1444. goto exit;
  1445. }
  1446. m_pChunkData = new UCHAR[m_pChunkRes->m_ChunkSize];
  1447. if(!m_pChunkData)
  1448. {
  1449. theErr = HXR_OUTOFMEMORY;
  1450. goto exit;
  1451. }
  1452. amountRead = pFile->Read((char *)m_pChunkData, m_pChunkRes->m_ChunkSize);
  1453. if(amountRead != m_pChunkRes->m_ChunkSize)
  1454. {
  1455. theErr = HXR_TEMP_FILE;
  1456. delete[] m_pChunkData;
  1457. m_pChunkData = NULL;
  1458. goto exit;
  1459. }
  1460. exit:
  1461. // If we actually, loaded the data from disk, then
  1462. // we are not modified!
  1463. if (theErr == HXR_OK)
  1464. {
  1465. m_bModified = FALSE;
  1466. }
  1467. // If we created a file, then clean it up!
  1468. if (pFile)
  1469. {
  1470. delete pFile;
  1471. }
  1472. // If we had an error then record that our size is now invalid.
  1473. if (theErr != HXR_OK)
  1474. {
  1475. AddValidRange(0, m_pChunkRes->m_ChunkSize, FALSE);
  1476. m_bPreviouslySpilled = FALSE;
  1477. }
  1478. Unlock();
  1479. return theErr;
  1480. }
  1481. /////////////////////////////////////////////////////////////////////////////
  1482. //
  1483. // Method:
  1484. //
  1485. // CChunkyResChunk::CChunkyResChunk()
  1486. //
  1487. // Purpose:
  1488. //
  1489. // Constructor for CChunkyResChunk.
  1490. //
  1491. // Parameters:
  1492. //
  1493. // None.
  1494. //
  1495. // Return:
  1496. //
  1497. // N/A
  1498. //
  1499. CChunkyResChunk::CChunkyResChunk(CChunkyRes* pChunkyRes)
  1500. : m_ChunkOffset(0)
  1501. , m_pChunkData(NULL)
  1502. , m_ulTempFileOffset(0)
  1503. , m_bPreviouslySpilled(FALSE)
  1504. , m_bModified(FALSE)
  1505. , m_pChunkRes(pChunkyRes)
  1506. , m_bDisableDiskIO(FALSE)
  1507. {
  1508.     HX_ASSERT(m_pChunkRes);
  1509. }
  1510. /////////////////////////////////////////////////////////////////////////////
  1511. //
  1512. // Method:
  1513. //
  1514. // CChunkyResChunk::~CChunkyResChunk()
  1515. //
  1516. // Purpose:
  1517. //
  1518. // Destructor for CChunkyResChunk.
  1519. //
  1520. // Parameters:
  1521. //
  1522. // N/A
  1523. //
  1524. // Return:
  1525. //
  1526. // N/A
  1527. //
  1528. CChunkyResChunk::~CChunkyResChunk()
  1529. {
  1530. HX_RESULT theErr = DiscardDiskData();
  1531. HX_ASSERT(theErr == HXR_OK);
  1532. if (m_pChunkData)
  1533. {
  1534. delete[] m_pChunkData;
  1535. m_pChunkData = NULL;
  1536. }
  1537. while (!m_ValidRanges.IsEmpty())
  1538. {
  1539. ValidRange* pRange = (ValidRange*)m_ValidRanges.RemoveHead();
  1540. delete pRange;
  1541. }
  1542. }
  1543. HX_RESULT CChunkyRes::GetTempFileChunk(CHXDataFile*& pFile,ULONG32& ulTempFileOffset)
  1544. {
  1545. // You should set this to NULL on input.
  1546. HX_ASSERT(pFile == NULL);
  1547. // Get the temporary file...
  1548. HX_RESULT theErr = GetTempFile(pFile);
  1549. if (theErr == HXR_OK)
  1550. {
  1551. // If there are free chunk spaces in the file, use those first
  1552. if (!m_FreeDiskOffsets.IsEmpty())
  1553. {
  1554. ulTempFileOffset = (UINT32)(PTR_INT)m_FreeDiskOffsets.GetTail();
  1555. m_FreeDiskOffsets.RemoveTail();
  1556. }
  1557. else
  1558. {
  1559.     // return the previous next chunk offset...
  1560.     ulTempFileOffset = m_ulNextTempFileChunk;
  1561.     // bump the next chunk offset
  1562.     m_ulNextTempFileChunk += m_ChunkSize;
  1563. }
  1564. }
  1565. return theErr;
  1566. }
  1567. /////////////////////////////////////////////////////////////////////////////
  1568. //
  1569. // Method:
  1570. //
  1571. // CChunkyResChunk::DiscardDiskData()
  1572. //
  1573. // Purpose:
  1574. //
  1575. // Discard the disk data for a chunk. This is normally done on
  1576. // destruction of the chunk when the resource associated with this
  1577. // chunk is discarded from disk, but can also be done when we
  1578. // are downloading a live stream and want to discard chunks that
  1579. // have already been served up to the user.
  1580. //
  1581. // Parameters:
  1582. //
  1583. // None.
  1584. //
  1585. // Return:
  1586. //
  1587. // HX_RESULT
  1588. // Possible errors include: TBD.
  1589. //
  1590. HX_RESULT CChunkyResChunk::DiscardDiskData()
  1591. {
  1592. HX_RESULT theErr = HXR_OK;
  1593. // Remove ourselves from the Memory MRU list...
  1594. LISTPOSITION posMem = m_pChunkRes->m_ChunksMemoryMRU->Find(this);
  1595. if (posMem)
  1596. {
  1597. m_pChunkRes->m_ChunksMemoryMRU->RemoveAt(posMem);
  1598. m_pChunkRes->m_CurMemUsage -= GetSize();
  1599. }
  1600. // Remove ourselves from the Disks MRU list...
  1601. LISTPOSITION posDisk = m_pChunkRes->m_ChunksDiskMRU->Find(this);
  1602. if (posDisk)
  1603. {
  1604. m_pChunkRes->m_ChunksDiskMRU->RemoveAt(posDisk);
  1605. }
  1606. // Reset a bunch of our members in case someone tries
  1607. // to access this chunk after its data has been discarded
  1608. m_ChunkOffset = 0;
  1609. AddValidRange(0, m_pChunkRes->m_ChunkSize, FALSE);
  1610. HX_VECTOR_DELETE(m_pChunkData);
  1611. m_ulTempFileOffset = 0;
  1612. m_bPreviouslySpilled = FALSE;
  1613. m_bModified = FALSE;
  1614. m_bDisableDiskIO = TRUE;
  1615. return theErr;
  1616. }
  1617. /////////////////////////////////////////////////////////////////////////////
  1618. //
  1619. // Method:
  1620. //
  1621. // CChunkyRes::DiscardDiskData()
  1622. //
  1623. // Purpose:
  1624. //
  1625. // Discard the disk data for a chunk. This is normally done on
  1626. // destruction of the chunk when the resource associated with this
  1627. // chunk is discarded from disk.
  1628. //
  1629. // Parameters:
  1630. //
  1631. // None.
  1632. //
  1633. // Return:
  1634. //
  1635. // HX_RESULT
  1636. // Possible errors include: TBD.
  1637. //
  1638. HX_RESULT CChunkyRes::DiscardDiskData()
  1639. {
  1640. HX_RESULT theErr = HXR_OK;
  1641. const char* pFileName = m_strTempFileName;
  1642. if (pFileName && *pFileName)
  1643. {
  1644. #if defined (_MACINTOSH) || defined (_UNIX) || defined(_SYMBIAN) || defined(_OPENWAVE)
  1645. int nRet = unlink(pFileName);
  1646. #else
  1647. int nRet = -1;
  1648. if (DeleteFile(OS_STRING(pFileName)))
  1649.     nRet = 0;
  1650. #endif
  1651. HX_ASSERT(nRet == 0);
  1652. m_strTempFileName = "";
  1653. }
  1654. return theErr;
  1655. }
  1656. HX_RESULT CChunkyRes::GetTempFile(CHXDataFile*& pFile)
  1657. {
  1658. // You should set this to NULL on input.
  1659. HX_ASSERT(pFile == NULL);
  1660. HX_RESULT theErr = HXR_OK;
  1661. const char* pFileName = m_strTempFileName;
  1662. char szTempFileName[_MAX_PATH]; /* Flawfinder: ignore */
  1663. // Create the OS Specific File object...
  1664. pFile = CHXDataFile::Construct();
  1665. if (!pFile)
  1666. {
  1667. theErr = HXR_TEMP_FILE;
  1668. goto exit;
  1669. }
  1670. // If we don't have a filename, then we need to
  1671. // get a temp filename, and we know we are creating
  1672. // a file.
  1673. if (!pFileName || !*pFileName)
  1674. {
  1675. #if defined(_MAC_MACHO) || defined(_MAC_CFM) // GR 7/15/03 other platforms may want a clearer name here too, since 8.3 restrictions don't apply
  1676.   if(!pFile->GetTemporaryFileName("Helix", szTempFileName, _MAX_PATH))
  1677. #else
  1678. if(!pFile->GetTemporaryFileName("PNX",szTempFileName, _MAX_PATH))
  1679. #endif
  1680. {
  1681. goto exit;
  1682. }
  1683. m_strTempFileName = szTempFileName;
  1684. pFileName = m_strTempFileName;
  1685. }
  1686. // Open the file...
  1687. if (!pFileName)
  1688. {
  1689. theErr = HXR_TEMP_FILE;
  1690. goto exit;
  1691. }
  1692. if (!m_bHasBeenOpened)
  1693. {
  1694. // Note: _O_RDWR does not work on the mac. O_RDWR is standard ANSI.
  1695. theErr = pFile->Open(pFileName,O_CREAT + O_RDWR);
  1696. if (!theErr)
  1697. {
  1698. m_bHasBeenOpened = TRUE;
  1699. }
  1700. }
  1701. else
  1702. {
  1703. // Note: _O_RDWR does not work on the mac. O_RDWR is standard ANSI.
  1704. theErr = pFile->Open(pFileName, O_RDWR);
  1705. }
  1706. exit:
  1707. return theErr;
  1708. }