filecache.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:43k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hxtypes.h"
  36. #include "hxcom.h"      // IUnknown
  37. #include "hxiids.h"     // GUIDs
  38. #include "hxslist.h"    // CHXSimpleList
  39. #include "hxthread.h"   // HXMutex
  40. #include "hxstring.h"   // memcpy()
  41. #include "hxcomm.h"     // IHXCommonClassFactory
  42. #include "ihxpckts.h"   // IHXBuffer
  43. #include "hxcache2.h"   // IHXCache2, IHXCacheObject, IHXCacheObjectResponse
  44. #include "filecache.h"
  45. #include "multilog.h"   
  46. #include "mlog_http.h"  // MLOG_HTTP()
  47. /****************************************************************************
  48.  *  CHXFileCacheObject::CHXFileCacheObject
  49.  *
  50.  *  Constructor
  51.  */
  52. CHXFileCacheObject::CHXFileCacheObject(IHXCommonClassFactory* /*IN*/ pClassFactory,
  53.                                        UINT32   /*IN*/      ulFileLength,
  54.                                        char*   /*IN*/       pFileName)
  55.     : m_RefCount                (0),
  56.       m_pCacheObjectResponse    (NULL),
  57.       m_pClassFactory           (NULL),
  58.       m_ulCapacity              (0),
  59.       m_lThreshold              (50),
  60.       m_ulUsedCapacity          (0),
  61.       m_pList                   (NULL),
  62.       m_ulCurrentWriteOffset    (0),
  63.       m_pPendingAddBlock        (NULL),
  64.       m_bInAddBlockDone         (FALSE),
  65.       m_bInReadBlockDone        (FALSE),
  66.       m_pMutex                  (NULL),
  67.       m_ulCurrentReadOffset     (0),
  68.       m_ulFileLength            (0),
  69.       m_pFileName               (NULL),
  70.       m_ulFileWriteOffset       (0),
  71.       m_pCacheFileHandle        (NULL),
  72.       m_ulHighestByteNotRead    (0)
  73. {
  74.     MLOG_HTTP("CHXFileCacheObject::CHXFileCacheObject(FileLen = %u, FileName = %s)n", ulFileLength, pFileName);
  75.     m_pPendingReadInfo.ulOffset = 0;
  76.     m_pPendingReadInfo.ulLength = 0;
  77.     m_pPendingReadInfo.pBlock = NULL;
  78.     if(pClassFactory != NULL)
  79.     {
  80.         m_pClassFactory = pClassFactory;
  81.         m_pClassFactory->AddRef();
  82.     }
  83.     m_ulFileLength = ulFileLength;
  84.     m_pFileName = pFileName;
  85.     m_pList = new CHXSimpleList;
  86.     #if defined(THREADS_SUPPORTED) || defined(_UNIX_THREADS_SUPPORTED)
  87.         HXMutex::MakeMutex(m_pMutex);
  88.     #else
  89.         HXMutex::MakeStubMutex(m_pMutex);
  90.     #endif
  91. }
  92. /****************************************************************************
  93.  *  CHXFileCacheObject::~CHXFileCacheObject
  94.  *
  95.  *  Destructor
  96.  */
  97. CHXFileCacheObject::~CHXFileCacheObject()
  98. {
  99.     MLOG_HTTP("CHXFileCacheObject::~CHXFileCacheObject()n");
  100.     m_pMutex->Lock();
  101.     // Close the cache file and delete if necessary
  102.     if(m_pCacheFileHandle != NULL)
  103.     {
  104.         // If full media clip not played, delete cache file
  105.         if(m_ulHighestByteNotRead != m_ulFileLength)
  106.         {
  107.             fclose(m_pCacheFileHandle);
  108.             remove(m_pFileName);
  109.         }
  110.         else
  111.         {
  112.             _CopyAllDataToFile();
  113.             fclose(m_pCacheFileHandle);
  114.         }
  115.     }
  116.     // Destroy the list
  117.     if(m_pList)
  118.     {
  119.         LISTPOSITION currPos = m_pList->GetHeadPosition();
  120.         Info* currInfo;
  121.         while(currPos != NULL)
  122.         {
  123.             currInfo = (Info *)m_pList->GetNext(currPos);
  124.             currInfo->pBlock->Release();
  125.             delete currInfo;
  126.         }
  127.         delete m_pList;
  128.     }
  129.     m_pMutex->Unlock();
  130.     HX_DELETE(m_pMutex);
  131. } // ~CHXFileCacheObject()
  132. // IUnknown COM Interface Methods
  133. /****************************************************************************
  134.  *  IUnknown::AddRef
  135.  *
  136.  *  This routine increases the object reference count in a thread safe
  137.  *  manner. The reference count is used to manage the lifetime of an object.
  138.  *  This method must be explicitly called by the user whenever a new
  139.  *  reference to an object is used.
  140.  */
  141. STDMETHODIMP_(UINT32) CHXFileCacheObject::AddRef(void)
  142. {
  143.     MLOG_HTTP("CHXFileCacheObject::AddRef()n");
  144.     return InterlockedIncrement(&m_RefCount);
  145. }
  146. /****************************************************************************
  147.  *  IUnknown::Release
  148.  *
  149.  *  This routine decreases the object reference count in a thread safe
  150.  *  manner, and deletes the object if no more references to it exist. It must
  151.  *  be called explicitly by the user whenever an object is no longer needed.
  152.  */
  153. STDMETHODIMP_(UINT32) CHXFileCacheObject::Release(void)
  154. {
  155.     MLOG_HTTP("CHXFileCacheObject::Release()n");
  156.     if (InterlockedDecrement(&m_RefCount) > 0)
  157.     {
  158. return m_RefCount;
  159.     }
  160.     delete this;
  161.     return 0;
  162. }
  163. /****************************************************************************
  164.  *  IUnknown::QueryInterface
  165.  *
  166.  *  This routine indicates which interfaces this object supports. If a given
  167.  *  interface is supported, the object's reference count is incremented, and
  168.  *  a reference to that interface is returned. Otherwise a NULL object and
  169.  *  error code are returned. This method is called by other objects to
  170.  *  discover the functionality of this object.
  171.  */
  172. STDMETHODIMP CHXFileCacheObject::QueryInterface(REFIID interfaceID,
  173.        void** ppInterfaceObj)
  174. {
  175.     MLOG_HTTP("CHXFileCacheObject::QueryInterface()n");
  176.     // By definition all COM objects support the IUnknown interface
  177.     if (IsEqualIID(interfaceID, IID_IUnknown))
  178.     {
  179. AddRef();
  180. *ppInterfaceObj = (IUnknown*)(IHXCacheObject*)this;
  181. return HXR_OK;
  182.     }
  183.     // IHXCacheObject interface is supported
  184.     else if (IsEqualIID(interfaceID, IID_IHXCacheObject))
  185.     {
  186. AddRef();
  187. *ppInterfaceObj = (IHXCacheObject*)this;
  188. return HXR_OK;
  189.     }
  190.     // No other interfaces are supported
  191.     *ppInterfaceObj = NULL;
  192.     return HXR_NOINTERFACE;
  193. }
  194. //IHXCacheObject methods
  195. /************************************************************************
  196.  * Method:
  197.  *
  198.  *     IHXCacheObject::Init
  199.  *
  200.  * Purpose:
  201.  *
  202.  *     Associates a cache object with the response object
  203.  *     it should notify of operation completeness.
  204.  */
  205. STDMETHODIMP
  206. CHXFileCacheObject::Init(IHXCacheObjectResponse*   /*IN*/  pCacheObjectResponse,
  207.                          UINT32   /*IN*/      ulCapacity,
  208.                          UINT32   /*IN*/      lThreshold)
  209. {
  210.     MLOG_HTTP("CHXFileCacheObject::Init(Capacity = %u, Threshold = %d)n", ulCapacity, lThreshold);
  211.     HX_RESULT res = HXR_OK;
  212.     if(pCacheObjectResponse != NULL)
  213.     {
  214.         // Release any previous response objects
  215.         if(m_pCacheObjectResponse != NULL)
  216.         {
  217.             m_pCacheObjectResponse->Release();
  218.         }
  219.         m_pCacheObjectResponse = pCacheObjectResponse;
  220.         pCacheObjectResponse->AddRef();
  221.     
  222.     }
  223.     else
  224.     {
  225.         res = HXR_INVALID_PARAMETER;
  226.     }
  227.     m_ulCapacity = ulCapacity;
  228.     if( (lThreshold < 0) || (lThreshold >= 100) ) 
  229.     {
  230.         res = HXR_INVALID_PARAMETER;
  231.     }
  232.     else
  233.     {
  234.         m_lThreshold = lThreshold;
  235.     }
  236.     // Open the cache file for writing.
  237.     m_pCacheFileHandle = fopen(m_pFileName, "wb+");
  238.     if( m_pCacheFileHandle == NULL )
  239.         res = HXR_FAIL;
  240.     m_pCacheObjectResponse->InitDone(res);
  241.     // HXR_OK from this function indicates InitDone() will be called.
  242.     // Since this statement is executed only after the above InitDone()
  243.     // we return HXR_OK instead of res. 
  244.     return HXR_OK;
  245. } // Init()
  246. /************************************************************************
  247.      * Method:
  248.      *
  249.      *     IHXCacheObject::GetThreshold
  250.      *
  251.      * Purpose:
  252.      *
  253.      *     Obtain the threshold of the cache object.
  254.      */
  255. STDMETHODIMP_(UINT32)
  256. CHXFileCacheObject::GetThreshold(void)
  257. {
  258.     MLOG_HTTP("CHXFileCacheObject::GetThreshold()n"); 
  259.     return m_lThreshold;
  260. } // GetThreshold()
  261. /************************************************************************
  262.  * Method:
  263.  *
  264.  *     IHXCacheObject::ChangeThreshold
  265.  *
  266.  * Purpose:
  267.  *
  268.  *     The object keeps caching data until it is full (exhausts its 
  269.  *      capacity). Once it is full, it will overwite existing cached data
  270.  *      with new data ONLY if the percentage of cached data which has been
  271.  *      read from the cache using the ReadBlock() method is *greater* than a
  272.  *      given percentage of Capacity.. This percentage is set using the SetThreshold()
  273.  *      method. In case the threshold is exceeded, the oldest added data
  274.  *      (the data with the the least offset) will be discarded and the 
  275.  *      amount of data discarded is so that the remaining cached data just
  276.  *      satisfies the threshold condidtion (approximately).
  277.  *
  278.  *      This cache object is used in the HTTP/1.0 file system plugin for
  279.  *      mobile devices and in this case, the threshold is set to 70%
  280.  *      i.e., utilizedDataPercentage = 0.7
  281.  *
  282.  */
  283. STDMETHODIMP
  284. CHXFileCacheObject::ChangeThreshold(UINT32  /*IN*/ lNewThreshold)
  285. {
  286.     MLOG_HTTP("CHXFileCacheObject::ChangeThreshold(%d)n", lNewThreshold);
  287.     if( (lNewThreshold < 0) || (lNewThreshold >= 100) )
  288.     {
  289.         return HXR_INVALID_PARAMETER;
  290.     }
  291.     m_pMutex->Lock();
  292.     UINT32 lOldThreshold = m_lThreshold;
  293.     m_lThreshold = lNewThreshold;
  294.     HX_RESULT res = _CheckForThresholdCondition();
  295.     if(HXR_OK != res)
  296.     {
  297.         // Revert back as something got messed up.
  298.         m_lThreshold = lOldThreshold;
  299.     }
  300.     m_pMutex->Unlock();
  301.     return res;
  302. } // ChangeThreshold()
  303. /************************************************************************
  304.  * Method:
  305.  *
  306.  *     IHXCacheObject::GetCapacity
  307.  *
  308.  * Purpose:
  309.  *
  310.  *     Obtain the capacity in bytes of the cache object.
  311.  */
  312. STDMETHODIMP_(UINT32)
  313. CHXFileCacheObject::GetCapacity(void)
  314. {
  315.     MLOG_HTTP("CHXFileCacheObject::GetCapacity()n"); 
  316.     return m_ulCapacity;
  317. } // GetCapacity()
  318. /************************************************************************
  319.  * Method:
  320.  *
  321.  *     IHXCacheObject::ChangeCapacity
  322.  *
  323.  * Purpose:
  324.  *
  325.  *     Change the capacity of the cache object.
  326.  */
  327. STDMETHODIMP
  328. CHXFileCacheObject::ChangeCapacity(UINT32  /*IN*/ newByteCount) 
  329. {
  330.    MLOG_HTTP("CHXFileCacheObject::ChangeCapacity(%u)n", newByteCount);
  331.    HX_RESULT res = HXR_OK;
  332.     
  333.    m_pMutex->Lock();
  334.    UINT32 ulOldCapacity = m_ulCapacity;
  335.    m_ulCapacity = newByteCount;
  336.    int nExcessData = m_ulUsedCapacity - newByteCount;
  337.    
  338.    if(nExcessData > 0)
  339.    {
  340.        // Discard the excess data writing to the cache file if necessary
  341.        res = _DiscardDataFromHead((UINT32)nExcessData, TRUE);
  342.        if(HXR_OK != res)
  343.        {
  344.            // Revert back to old capacity if you couldn't
  345.            // discard data.
  346.            m_ulCapacity = ulOldCapacity;    
  347.        }
  348.        else
  349.        {
  350.            // Capacity has changed, so threshold might have been exceeded.
  351.            res = _CheckForThresholdCondition();
  352.        }
  353.    }
  354.    m_pMutex->Unlock();
  355.    m_pCacheObjectResponse->ChangeCapacityDone(res);
  356.    
  357.    // HXR_OK from this function indicates ChangeCapacityDone() will be called.
  358.    // Since this statement is executed only after the above ChangeCapacityDone()
  359.    // we return HXR_OK instead of res. 
  360.    return HXR_OK;
  361. } // ChangeCapacity()
  362. /************************************************************************
  363.  * Method:
  364.  *
  365.  *     IHXCacheObject::GetUnusedCapacity
  366.  *
  367.  * Purpose:
  368.  *
  369.  *     Obtain the unused capacity in bytes of the cache object.
  370.  */
  371. STDMETHODIMP_(UINT32)
  372. CHXFileCacheObject::GetUnusedCapacity()
  373. {
  374.     MLOG_HTTP("CHXFileCacheObject::GetUnusedCapacity()n");
  375.     UINT32 ulUnusedCapacity = 0;
  376.     m_pMutex->Lock();
  377.     // There's data in the cache file which will be used to
  378.     // populate the list. Will accept more data from outside
  379.     // once I use up all data in the file.
  380.     if(m_ulFileWriteOffset > m_ulCurrentWriteOffset)
  381.     {
  382.         ulUnusedCapacity = 0;
  383.     }
  384.     else
  385.     {
  386.         ulUnusedCapacity = m_ulCapacity - m_ulUsedCapacity;
  387.     }
  388.     
  389.     m_pMutex->Unlock();
  390.     return ulUnusedCapacity;
  391. } // GetUnusedCapacity()
  392. /************************************************************************
  393.  * Method:
  394.  *
  395.  *     IHXCacheObject::AddBlock
  396.  *
  397.  * Purpose:
  398.  *
  399.  *     Adds a block of data to the cache.
  400.  */
  401. STDMETHODIMP
  402. CHXFileCacheObject::AddBlock(IHXBuffer* /*IN*/ pBlock) 
  403. {
  404.     MLOG_HTTP("CHXFileCacheObject::AddBlock()n");
  405.     if(pBlock == NULL)
  406.     {
  407.         return HXR_INVALID_PARAMETER;
  408.     }
  409.     if(m_pList == NULL)
  410.         return HXR_UNEXPECTED;
  411.             
  412.     if(m_pPendingAddBlock != NULL)
  413.     {
  414.         return HXR_UNEXPECTED;
  415.     }
  416.     else
  417.     {
  418.         m_pPendingAddBlock = pBlock;
  419.         m_pPendingAddBlock->AddRef();
  420.     }
  421.     if(!m_bInAddBlockDone)
  422.     {
  423.         while(m_pPendingAddBlock)
  424.         {
  425.             IHXBuffer* pTempBlock = m_pPendingAddBlock;
  426.             m_pPendingAddBlock = NULL;
  427.             UINT32 ulBlockSize = pTempBlock->GetSize();
  428.             Info *pNewInfo = NULL;
  429.             HX_RESULT res = HXR_OK;
  430.             if(ulBlockSize != 0)
  431.             {
  432.                 m_pMutex->Lock(); 
  433.            
  434.                 // Can you accomodate this data?
  435.                 if(m_ulUsedCapacity + ulBlockSize > m_ulCapacity)
  436.                 {
  437.                     pTempBlock->Release();
  438.                     res = HXR_OUTOFMEMORY;
  439.                 }
  440.                 else
  441.                 {
  442.                     pNewInfo = new Info;
  443.                     if(pNewInfo == NULL)
  444.                         res = HXR_OUTOFMEMORY;
  445.                 }
  446.                 if(HXR_OK == res)
  447.                 {
  448.                     // The new block should be contiguous
  449.                     pNewInfo->ulOffset = m_ulCurrentWriteOffset;
  450.                     pNewInfo->ulSize = ulBlockSize;
  451.                     pNewInfo->pBlock = pTempBlock;
  452.                     m_ulUsedCapacity += ulBlockSize;
  453.                     m_ulCurrentWriteOffset += ulBlockSize;
  454.                     m_pList->AddTail( (void *)pNewInfo );
  455.                 }
  456.             
  457.                 m_pMutex->Unlock();
  458.             }
  459.             else
  460.             {
  461.                 pTempBlock->Release();
  462.             }
  463.             m_bInAddBlockDone = TRUE;
  464.             m_pCacheObjectResponse->AddBlockDone(res);
  465.             m_bInAddBlockDone = FALSE;
  466.         } // while
  467.     }
  468.     return HXR_OK;
  469. } // AddBlock()
  470. /************************************************************************
  471.  * Method:
  472.  *
  473.  *     IHXCacheObject::VerifyBlock
  474.  *
  475.  * Purpose:
  476.  *
  477.  *     Verify that a block of data is in the cache.
  478.  */
  479. STDMETHODIMP
  480. CHXFileCacheObject::VerifyBlock(UINT32 /*IN*/ ulBlockOffset,
  481.  UINT32 /*IN*/ ulBlockLength)
  482. {
  483.     MLOG_HTTP("CHXFileCacheObject::VeifyBlock()n");
  484.     if(m_pList == NULL)
  485.         return HXR_UNEXPECTED;
  486.     m_pMutex->Lock();
  487.     
  488.     // Critical Section starts
  489.     BOOL bExists = TRUE;
  490.     if(m_ulUsedCapacity == 0)
  491.     {
  492.         bExists = FALSE;
  493.     }
  494.     else
  495.     {
  496.         UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity;
  497.         UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
  498.         
  499.         BOOL bStartExists = (ulBlockOffset >= ulLeastOffset) && 
  500.                             (ulBlockOffset <= ulHighestOffset);
  501.         BOOL bEndExists = (ulBlockOffset + ulBlockLength - 1 >= ulLeastOffset) &&
  502.                           (ulBlockOffset + ulBlockLength - 1 <= ulHighestOffset);
  503.         bExists = bStartExists && bEndExists;
  504.     }
  505.     // Critical section ends
  506.     m_pMutex->Unlock();
  507.     m_pCacheObjectResponse->VerifyBlockDone(bExists);
  508.     return HXR_OK;
  509. } // VerifyBlock()
  510. /************************************************************************
  511.  * Method:
  512.  *
  513.  *     IHXCacheObject::ReadBlock
  514.  *
  515.  * Purpose:
  516.  *
  517.  *     Read a block out of the cache.
  518.  */
  519. STDMETHODIMP
  520. CHXFileCacheObject::ReadBlock(UINT32    /*IN*/ ulBlockOffset,
  521.       UINT32    /*IN*/ ulBlockLength)
  522. {
  523.     MLOG_HTTP("CHXFileCacheObject::ReadBlock(Offset = %u, Length = %u)n", ulBlockOffset, ulBlockLength);
  524.     if(m_pList == NULL)
  525.         return HXR_UNEXPECTED;
  526.     if(m_pPendingReadInfo.pBlock != NULL)
  527.         return HXR_UNEXPECTED;
  528.     m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  529.                      (void **) &m_pPendingReadInfo.pBlock);
  530.     if(m_pPendingReadInfo.pBlock == NULL)
  531.         return HXR_OUTOFMEMORY;
  532.     HX_RESULT res = m_pPendingReadInfo.pBlock->SetSize(ulBlockLength);
  533.     if(res != HXR_OK)
  534.     {
  535.         m_pPendingReadInfo.pBlock->Release();
  536.         m_pPendingReadInfo.pBlock = NULL;
  537.         return res;
  538.     }
  539.     m_pPendingReadInfo.ulLength = ulBlockLength;
  540.     m_pPendingReadInfo.ulOffset = ulBlockOffset;
  541.     if(!m_bInReadBlockDone)
  542.     {
  543.         while(m_pPendingReadInfo.pBlock)
  544.         {
  545.             HX_RESULT res2 = HXR_OK;
  546.             // To prepare for the possibilty of ReadBlock()
  547.             // being called from ReadBlockDone()
  548.             IHXBuffer* pTempBlock = m_pPendingReadInfo.pBlock;
  549.             m_pPendingReadInfo.pBlock = NULL;
  550.             UINT32 ulTempLength = m_pPendingReadInfo.ulLength;
  551.             m_pPendingReadInfo.ulLength = 0;
  552.             UINT32 ulTempOffset = m_pPendingReadInfo.ulOffset;
  553.             m_pPendingReadInfo.ulOffset = 0;
  554.             m_pMutex->Lock();
  555.             UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity; 
  556.             UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
  557.             if( (m_ulUsedCapacity == 0) && (m_ulCurrentWriteOffset == 0) )
  558.             {
  559.                 res2 = HXR_INCOMPLETE;
  560.                 HX_RELEASE(pTempBlock);
  561.                 pTempBlock = NULL;
  562.             }
  563.             else if(ulTempOffset < ulLeastOffset)
  564.             {
  565.                 res2 = HXR_INCOMPLETE;
  566.                 HX_RELEASE(pTempBlock);
  567.                 pTempBlock = NULL;
  568.                 // Flush data to file and then read the required (past)
  569.                 // data from the file.
  570.                 _CopyAllDataToFile();
  571.                 UINT32 ulGap = ulLeastOffset - ulTempOffset;
  572.                 UINT32 ulDiscardData = 0;
  573.                 if(ulGap >= m_ulCapacity)
  574.                     ulDiscardData = m_ulUsedCapacity;
  575.                 else
  576.                 {
  577.                     int nRemovableData = m_ulCurrentWriteOffset - 
  578.                                          (ulTempOffset + m_ulCapacity);
  579.                     ulDiscardData = (nRemovableData > 0)? (UINT32)nRemovableData: 0;
  580.                 }
  581.                 if(ulDiscardData >0)
  582.                 {
  583.                     _DiscardDataFromTail(ulDiscardData, FALSE);
  584.                 }
  585.                 if(ulGap >= m_ulCapacity)
  586.                 {
  587.                     _CopyFromFileToHead(ulTempOffset, m_ulCapacity);
  588.                     m_ulCurrentWriteOffset = ulTempOffset + m_ulCapacity;
  589.                     m_ulCurrentReadOffset = ulTempOffset;
  590.                     m_ulUsedCapacity = m_ulCapacity;
  591.                 }
  592.                 else
  593.                 {
  594.                     m_ulCurrentWriteOffset = ulTempOffset + ulGap + m_ulUsedCapacity;
  595.                     //if(ulDiscardData != 0)
  596.                     //{
  597.                         _CopyFromFileToHead(ulTempOffset, ulGap);
  598.                     //}
  599.                     
  600.                     m_ulCurrentReadOffset = ulTempOffset;
  601.                 }
  602.             }
  603.             else if(ulTempOffset > ulHighestOffset)
  604.             {
  605.                 res2 = HXR_INCOMPLETE;
  606.                 HX_RELEASE(pTempBlock);
  607.                 pTempBlock = NULL;
  608.                 // If 'forward data' requested, mark all data as read so
  609.                 // that old data can be discarded to make space for new data.
  610.                 m_ulCurrentReadOffset = ulTempOffset;
  611.                 _CheckForThresholdCondition();
  612.             }
  613.             else
  614.             {
  615.                 // Fill the pTempBlock with data from the list
  616.             
  617.                 UCHAR* ucTempBlockData = pTempBlock->GetBuffer();
  618.                 UINT32 ulBytesReadFromList = 0;
  619.                 LISTPOSITION currPos = m_pList->GetHeadPosition();
  620.                 Info* currInfo;
  621.                 while(currPos != NULL)
  622.                 {   
  623.                     currInfo = (Info *)m_pList->GetNext(currPos);
  624.                     UINT32 ulCurrLowOffset = currInfo->ulOffset;
  625.                     UINT32 ulCurrHighOffset = currInfo->ulOffset + currInfo->ulSize - 1;
  626.                     UCHAR* ucCurrBlockData = currInfo->pBlock->GetBuffer();
  627.                     if( (ulTempOffset >= ulCurrLowOffset) && (ulTempOffset <= ulCurrHighOffset) )
  628.                     {
  629.                         UINT32 ulMatchSize = ( (ulCurrHighOffset - ulTempOffset + 1) < ulTempLength ) ?
  630.                                                 ulCurrHighOffset - ulTempOffset + 1 : ulTempLength;
  631.                         memcpy((void*)(ucTempBlockData + ulBytesReadFromList),
  632.                                 (void*)(ucCurrBlockData + ulTempOffset - ulCurrLowOffset), ulMatchSize);
  633.                         ulBytesReadFromList += ulMatchSize;
  634.                         ulTempOffset += ulMatchSize;
  635.                         ulTempLength -= ulMatchSize;
  636.                         if(0 == ulTempLength)
  637.                             break;
  638.                     }
  639.                 }
  640.                 if(ulTempLength > 0)
  641.                 {
  642.                     res2 = HXR_INCOMPLETE;
  643.                     pTempBlock->SetSize(ulBytesReadFromList);   
  644.                 }
  645.                 else
  646.                 {
  647.                     res2 = HXR_OK;
  648.                 }
  649.                 m_ulCurrentReadOffset = ulTempOffset;
  650.                 _CheckForThresholdCondition();
  651.             }
  652.             m_pMutex->Unlock();
  653.             if(m_ulHighestByteNotRead < m_ulCurrentReadOffset)
  654.                 m_ulHighestByteNotRead = m_ulCurrentReadOffset;
  655.             m_bInReadBlockDone = TRUE;
  656.             m_pCacheObjectResponse->ReadBlockDone(res2, pTempBlock);
  657.             m_bInReadBlockDone = FALSE;
  658.             
  659.             HX_RELEASE(pTempBlock);
  660.         }
  661.     }
  662.     return HXR_OK;
  663. } // ReadBlock()
  664. /************************************************************************
  665.  * Method:
  666.  *     IHXCacheObject::Flush
  667.  *
  668.  * Purpose:
  669.  *
  670.  *     Flushes all data to the cache file AND releases all data buffers 
  671.  *          in the memory.After flushing, the object can be used for reading/writing
  672.  *          as before.
  673.  */
  674. STDMETHODIMP
  675. CHXFileCacheObject::Flush(void) 
  676. {
  677.     MLOG_HTTP("CHXFileCacheObject::Flush()n");
  678.     
  679.     if(!m_pList)
  680.         return HXR_UNEXPECTED;
  681.     
  682.     m_pMutex->Lock();
  683.     _DiscardDataFromHead(m_ulUsedCapacity, TRUE);
  684.     m_ulUsedCapacity = 0;
  685.     m_pMutex->Unlock();
  686.     m_pCacheObjectResponse->FlushDone(HXR_OK);
  687.     return HXR_OK;
  688. } // Flush()
  689. /************************************************************************
  690.  * Method:
  691.  *
  692.  *     IHXCacheObject::IsFull
  693.  *
  694.  * Purpose:
  695.  *
  696.  *     Can the cache object accept any more data for storage?
  697.  */
  698. STDMETHODIMP_(BOOL)
  699. CHXFileCacheObject::IsFull()
  700. {
  701.     MLOG_HTTP("CHXFileCacheObject::IsFull()n");
  702.     if(GetUnusedCapacity() == 0)
  703.         return TRUE;
  704.     else
  705.         return FALSE;
  706. } // IsFull()
  707. /************************************************************************
  708.  * Method:
  709.  *
  710.  *     IHXCacheObject::IsEmpty
  711.  *
  712.  * Purpose:
  713.  *
  714.  *     Does the cache object have any data stored?
  715.  */
  716. STDMETHODIMP_(BOOL)
  717. CHXFileCacheObject::IsEmpty()
  718. {
  719.     MLOG_HTTP("CHXFileCacheObject::IsEmpty()n");
  720.     if(m_ulUsedCapacity == 0)
  721.         return TRUE;
  722.     else
  723.         return FALSE;
  724. } // IsEmpty()
  725. // Discards exactly 'byteCount' amount of data from the head.
  726. // Note that this method is not thread safe. The caller has to take 
  727. // care of locking common data structures before calling this method.
  728. HX_RESULT CHXFileCacheObject::_DiscardDataFromHead(UINT32 byteCount, BOOL bWriteToFile)
  729. {
  730.     MLOG_HTTP("CHXFileCacheObject::_DiscardDataFromHead(%u, %d)n", byteCount, bWriteToFile);
  731.     HX_RESULT res = HXR_UNEXPECTED;
  732.     UINT32 ulDiscardedData = 0;
  733.     Info *headInfo = NULL;
  734.     LISTPOSITION currHead = m_pList->GetHeadPosition();
  735.     while(currHead != NULL) 
  736.     {
  737.         headInfo = (Info*)m_pList->RemoveHead();
  738.         UINT32 ulHeadBlockOffset = headInfo->ulOffset;
  739.         UINT32 ulHeadBlockSize = headInfo->ulSize;
  740.         // This whole block should be discarded
  741.         if(ulDiscardedData + ulHeadBlockSize <= byteCount)
  742.         {
  743.             if(bWriteToFile == TRUE)
  744.             {
  745.                 // If data already written to file, no need to write again.
  746.                 if( (m_ulFileWriteOffset >= ulHeadBlockOffset) &&
  747.                     (m_ulFileWriteOffset <= ulHeadBlockOffset + ulHeadBlockSize - 1) )
  748.                 {
  749.                     UINT32 ulDataAlreadyWritten = m_ulFileWriteOffset - ulHeadBlockOffset;
  750.                     UINT32 ulDataToWrite = ulHeadBlockSize - ulDataAlreadyWritten;
  751.                     fseek(m_pCacheFileHandle, m_ulFileWriteOffset, SEEK_SET);
  752.                     int nBytesWritten = fwrite( (void*)(headInfo->pBlock->GetBuffer() + ulDataAlreadyWritten),
  753.                                 sizeof(UCHAR), ulDataToWrite, m_pCacheFileHandle);
  754.                     fflush(m_pCacheFileHandle);
  755.                     m_ulFileWriteOffset += ulDataToWrite;
  756.                 }
  757.             }
  758.             headInfo->pBlock->Release();
  759.             delete headInfo;
  760.             
  761.             ulDiscardedData += ulHeadBlockSize;
  762.         }
  763.         else // Only part of the block needs to be discarded.
  764.         {
  765.             if(ulDiscardedData + ulHeadBlockSize > byteCount) // >>> Redundant condition
  766.             {
  767.                 UINT32 ulValidDataSize = (ulDiscardedData + ulHeadBlockSize - byteCount);
  768.                 UINT32 ulInvalidDataSize = ulHeadBlockSize - ulValidDataSize;
  769.                 if(bWriteToFile == TRUE)
  770.                 {
  771.                     // If data already written to file, no need to write again.
  772.                     if( (m_ulFileWriteOffset >= ulHeadBlockOffset) && 
  773.                         (m_ulFileWriteOffset <= ulHeadBlockOffset + ulInvalidDataSize - 1) )
  774.                     {
  775.                         UINT32 ulDataAlreadyWritten = m_ulFileWriteOffset - ulHeadBlockOffset;
  776.                         UINT32 ulDataToWrite = ulInvalidDataSize - ulDataAlreadyWritten;
  777.                         fseek(m_pCacheFileHandle, m_ulFileWriteOffset, SEEK_SET);
  778.                         int nBytesWritten = fwrite( (void*)(headInfo->pBlock->GetBuffer() + ulDataAlreadyWritten),
  779.                                     sizeof(UCHAR), ulDataToWrite, m_pCacheFileHandle);
  780.                         fflush(m_pCacheFileHandle);
  781.                         m_ulFileWriteOffset += ulDataToWrite;
  782.                     }
  783.                     
  784.                 }
  785.                 Info *pNewInfo = new Info;
  786.                 if(pNewInfo == NULL)
  787.                 {
  788.                    res = HXR_OUTOFMEMORY;
  789.                    break;
  790.                 }
  791.                 m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  792.                                                (void **) &(pNewInfo->pBlock));
  793.                 if(pNewInfo->pBlock == NULL)
  794.                     break;
  795.                 res = pNewInfo->pBlock->SetSize(ulValidDataSize);
  796.                 if(res != HXR_OK)
  797.                     break;
  798.                 memcpy( (void*)(pNewInfo->pBlock->GetBuffer()),
  799.                         (void*)(headInfo->pBlock->GetBuffer()+ ulInvalidDataSize),
  800.                         ulValidDataSize );
  801.                 pNewInfo->ulOffset = headInfo->ulOffset + ulInvalidDataSize;
  802.                 pNewInfo->ulSize = ulValidDataSize;
  803.                 m_pList->AddHead( (void *)pNewInfo );
  804.                 headInfo->pBlock->Release();
  805.                 delete headInfo;
  806.             }
  807.             ulDiscardedData = byteCount;
  808.             headInfo = NULL;
  809.             res = HXR_OK;
  810.             break;
  811.         }
  812.         currHead = m_pList->GetHeadPosition();
  813.     }
  814.     m_ulUsedCapacity -= ulDiscardedData;
  815.     return res;
  816. } // _DiscardDataFromHead()
  817. // Check if utilizedData has exceeded THRESHOLD. If yes, discard 
  818. // appropriate amount of data. Note that this
  819. // method is not thread safe. The caller has to take care of 
  820. // locking common data structures before calling this method.
  821. HX_RESULT CHXFileCacheObject::_CheckForThresholdCondition()
  822. {
  823.     MLOG_HTTP("CHXFileCacheObject::_CheckForThresholdCondition()n");
  824.     if(m_ulUsedCapacity == 0)
  825.     {
  826.         return HXR_OK;
  827.     }
  828.     UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity;
  829.     UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
  830.     HX_RESULT res = HXR_OK;
  831.     INT32 nExcess = (m_ulCurrentReadOffset - ulLeastOffset) - 
  832.                       (INT32)(m_lThreshold * m_ulCapacity * 0.01);
  833.     if(nExcess > 0)
  834.     {
  835.         if(nExcess > m_ulUsedCapacity)
  836.             nExcess = m_ulUsedCapacity; 
  837.         res = _DiscardDataFromHead(nExcess, TRUE);
  838.         INT32 nExtraFileData = m_ulFileWriteOffset - m_ulCurrentWriteOffset;
  839.         if(nExtraFileData > 0)
  840.         {
  841.             UINT32 ulUnusedCapacity = m_ulCapacity - m_ulUsedCapacity;
  842.             UINT32 ulFileReadData = ((UINT32)nExtraFileData > ulUnusedCapacity) ?
  843.                                       ulUnusedCapacity: nExtraFileData;
  844.             res = _CopyFromFileToTail(m_ulCurrentWriteOffset, ulFileReadData);
  845.         }
  846.     }
  847.     return res;
  848. } // _CheckForThresholdCondition()
  849. // Discards exactly 'byteCount' amount of data from the tail.
  850. // Note that this method is not thread safe. The caller has to take 
  851. // care of locking common data structures before calling this method.
  852. HX_RESULT CHXFileCacheObject::_DiscardDataFromTail(UINT32 byteCount, BOOL bWriteToFile)
  853. {
  854.     MLOG_HTTP("CHXFileCacheObject::_DiscardDataFromTail(%u, %d)n", byteCount, bWriteToFile);
  855.     HX_RESULT res = HXR_OK;
  856.     if( (bWriteToFile) && (m_ulFileWriteOffset < m_ulCurrentWriteOffset) )
  857.     {
  858.         LISTPOSITION currPos = m_pList->GetTailPosition();
  859.         while(currPos != NULL)
  860.         {
  861.             Info* pCurrInfo = (Info*)(m_pList->GetPrev(currPos));
  862.             if( (m_ulFileWriteOffset >= pCurrInfo->ulOffset) &&
  863.                 (m_ulFileWriteOffset >= pCurrInfo->ulOffset + pCurrInfo->ulSize - 1) )
  864.             {
  865.                 break;
  866.             }
  867.         }
  868.         if(currPos != NULL)
  869.         {
  870.             Info* pCurrInfo = (Info*)(m_pList->GetAtNext(currPos));
  871.             UINT32 ulValidData = m_ulFileWriteOffset - (pCurrInfo->ulOffset);
  872.             UINT32 ulInvalidData = pCurrInfo->ulSize - ulValidData;
  873.             fseek(m_pCacheFileHandle, m_ulFileWriteOffset, SEEK_SET);
  874.             int nBytesWritten = fwrite( (void*)(pCurrInfo->pBlock->GetBuffer() + ulValidData),
  875.                                 sizeof(UCHAR), ulInvalidData, m_pCacheFileHandle);
  876.             fflush(m_pCacheFileHandle);
  877.             m_ulFileWriteOffset += ulInvalidData;
  878.             pCurrInfo = (Info*)(m_pList->GetNext(currPos));
  879.             while(pCurrInfo != NULL)
  880.             {
  881.                 int nBytesWritten = fwrite( (void*)(pCurrInfo->pBlock->GetBuffer()),
  882.                                 sizeof(UCHAR), pCurrInfo->ulSize, m_pCacheFileHandle);
  883.                 fflush(m_pCacheFileHandle);
  884.                 m_ulFileWriteOffset += pCurrInfo->ulSize;
  885.                 pCurrInfo = (Info*)(m_pList->GetNext(currPos));
  886.             }
  887.         }
  888.         else
  889.         {
  890.             res = HXR_UNEXPECTED;
  891.         }
  892.     }
  893.     if(res != HXR_OK)
  894.         return res;
  895.     UINT32 ulDiscardedData = 0;
  896.     Info *tailInfo = NULL;
  897.     res = HXR_UNEXPECTED;
  898.     LISTPOSITION currTail = m_pList->GetTailPosition();
  899.     while(currTail != NULL)
  900.     {
  901.         tailInfo = (Info*)(m_pList->RemoveTail());
  902.         UINT32 ulTailBlockSize = tailInfo->ulSize;
  903.         if(ulDiscardedData + ulTailBlockSize <= byteCount)
  904.         {
  905.             tailInfo->pBlock->Release();
  906.             delete tailInfo;
  907.             
  908.             ulDiscardedData += ulTailBlockSize;
  909.         }
  910.         else
  911.         {
  912.             if(ulDiscardedData + ulTailBlockSize > byteCount)
  913.             {
  914.                 UINT32 ulValidDataSize = (ulDiscardedData + ulTailBlockSize - byteCount);
  915.                 Info *pNewInfo = new Info;
  916.                 if(pNewInfo == NULL)
  917.                 {
  918.                    res = HXR_OUTOFMEMORY;
  919.                    break;
  920.                 }
  921.                 m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  922.                                                (void **) &(pNewInfo->pBlock));
  923.                 if(pNewInfo->pBlock == NULL)
  924.                     break;
  925.                 res = pNewInfo->pBlock->SetSize(ulValidDataSize);
  926.                 if(res != HXR_OK)
  927.                     break;
  928.                 memcpy( (void*)(pNewInfo->pBlock->GetBuffer()),
  929.                         (void*)(tailInfo->pBlock->GetBuffer()),
  930.                         ulValidDataSize );
  931.                 pNewInfo->ulOffset = tailInfo->ulOffset;
  932.                 pNewInfo->ulSize = ulValidDataSize;
  933.                 m_pList->AddTail( (void *)pNewInfo );
  934.                 tailInfo->pBlock->Release();
  935.                 delete tailInfo;
  936.             }
  937.             ulDiscardedData = byteCount;
  938.             tailInfo = NULL;
  939.             res = HXR_OK;
  940.             break;
  941.         }
  942.         currTail = m_pList->GetTailPosition();
  943.     }
  944.     m_ulUsedCapacity -= ulDiscardedData;
  945.     m_ulCurrentWriteOffset -= ulDiscardedData; 
  946.     return res;
  947. } // _DiscardDataFromTail()
  948. // Copies 'ulSize' amount of data from offset 'ulOffset' from
  949. // the cache file. The blocks are added to the Tail of the list.
  950. // The data is copied in blocks of size determined
  951. // by CAPACITY_BLOCKSIZE_RATIO. Requires that the data is present
  952. // in the file.
  953. HX_RESULT CHXFileCacheObject::_CopyFromFileToTail(UINT32 ulOffset, UINT32 ulSize)
  954. {
  955.     MLOG_HTTP("CHXFileCacheObject::_CopyFromFileToTail(Offset = %u, Size = %u)n", ulOffset, ulSize);
  956.     if(ulSize == 0)
  957.         return HXR_OK;
  958.     m_ulCurrentWriteOffset = ulOffset;
  959.     UINT32 ulBlockSize = m_ulCapacity/CAPACITY_BLOCKSIZE_RATIO;
  960.     UINT32 ulRemainderBlockSize = 0;
  961.     UINT32 ulNumFullBlocks = ulSize/ulBlockSize;
  962.     if((ulSize%ulBlockSize) > 0)
  963.     {
  964.         ulRemainderBlockSize = ulSize - ulNumFullBlocks * ulBlockSize;
  965.     }
  966.     HX_RESULT res = HXR_OK;
  967.     fseek(m_pCacheFileHandle, ulOffset, SEEK_SET);
  968.     if(ulRemainderBlockSize > 0)
  969.     {
  970.         IHXBuffer* pRemainderBlock = NULL;
  971.         m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  972.                          (void **) &pRemainderBlock);
  973.         if(pRemainderBlock != NULL)
  974.         {
  975.             res = pRemainderBlock->SetSize(ulRemainderBlockSize);
  976.         }
  977.         else
  978.         {
  979.             res = HXR_OUTOFMEMORY;
  980.         }
  981.         if(res == HXR_OK)
  982.         {
  983.             fread( (void*)(pRemainderBlock->GetBuffer()),
  984.                                     sizeof(UCHAR), ulRemainderBlockSize, m_pCacheFileHandle );
  985.             Info* pNewInfo = new Info;
  986.             if(pNewInfo == NULL)
  987.             {
  988.                 res = HXR_OUTOFMEMORY;
  989.             }
  990.             else
  991.             {
  992.                 // The new block should be contiguous
  993.                 pNewInfo->ulOffset = m_ulCurrentWriteOffset;
  994.                 pNewInfo->ulSize = ulRemainderBlockSize;
  995.                 pNewInfo->pBlock = pRemainderBlock;
  996.                 m_pList->AddTail( (void *)pNewInfo );
  997.                 m_ulUsedCapacity += ulRemainderBlockSize;
  998.                 m_ulCurrentWriteOffset += ulRemainderBlockSize;
  999.             }
  1000.         }
  1001.     }
  1002.     if(res != HXR_OK)
  1003.         return res;
  1004.     for(int i = 0; i < ulNumFullBlocks; i++)
  1005.     {
  1006.         IHXBuffer* pTempBlock = NULL;
  1007.         m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  1008.                          (void **) &pTempBlock);
  1009.         if(pTempBlock != NULL)
  1010.         {
  1011.             res = pTempBlock->SetSize(ulBlockSize);
  1012.         }
  1013.         else
  1014.         {
  1015.             res = HXR_OUTOFMEMORY;
  1016.         }
  1017.         if(res == HXR_OK)
  1018.         {
  1019.             fread( (void*)(pTempBlock->GetBuffer()),
  1020.                                     sizeof(UCHAR), ulBlockSize, m_pCacheFileHandle );
  1021.             Info* pNewInfo = new Info;
  1022.             if(pNewInfo == NULL)
  1023.             {
  1024.                 res = HXR_OUTOFMEMORY;
  1025.             }
  1026.             else
  1027.             {
  1028.                 // The new block should be contiguous
  1029.                 pNewInfo->ulOffset = m_ulCurrentWriteOffset;
  1030.                 pNewInfo->ulSize = ulBlockSize;
  1031.                 pNewInfo->pBlock = pTempBlock;
  1032.                 m_ulUsedCapacity += ulBlockSize;
  1033.                 m_ulCurrentWriteOffset += ulBlockSize;
  1034.                 m_pList->AddTail( (void *)pNewInfo );
  1035.             }
  1036.         }
  1037.     }
  1038.     return res;
  1039. } // _CopyFromFileToTail()
  1040. // Copies 'ulSize' amount of data from offset 'ulOffset' from
  1041. // the cache file. The blocks are added to the Head of the list.
  1042. // The data is copied in blocks of size determined
  1043. // by CAPACITY_BLOCKSIZE_RATIO. Requires that the data is present
  1044. // in the file.
  1045. HX_RESULT CHXFileCacheObject::_CopyFromFileToHead(UINT32 ulOffset, UINT32 ulSize)
  1046. {
  1047.     MLOG_HTTP("CHXFileCacheObject::_CopyFromFileToHead(Offset = %u, Size = %u)n", ulOffset, ulSize);
  1048.     if(ulSize == 0)
  1049.         return HXR_OK;
  1050.     UINT32 ulBlockSize = m_ulCapacity/CAPACITY_BLOCKSIZE_RATIO;
  1051.     UINT32 ulRemainderBlockSize = 0;
  1052.     UINT32 ulNumFullBlocks = ulSize/ulBlockSize;
  1053.     if((ulSize%ulBlockSize) > 0)
  1054.     {
  1055.         ulRemainderBlockSize = ulSize - ulNumFullBlocks * ulBlockSize;
  1056.     }
  1057.     HX_RESULT res = HXR_OK;
  1058.     fseek(m_pCacheFileHandle, ulOffset + ulSize, SEEK_SET);
  1059.     UINT32 ulCurrBlockOffset = ulOffset + ulSize;
  1060.     if(ulRemainderBlockSize > 0)
  1061.     {
  1062.         IHXBuffer* pRemainderBlock = NULL;
  1063.         m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  1064.                          (void **) &pRemainderBlock);
  1065.         if(pRemainderBlock != NULL)
  1066.         {
  1067.             res = pRemainderBlock->SetSize(ulRemainderBlockSize);
  1068.         }
  1069.         else
  1070.         {
  1071.             res = HXR_OUTOFMEMORY;
  1072.         }
  1073.         if(res == HXR_OK)
  1074.         {
  1075.             ulCurrBlockOffset -= ulRemainderBlockSize;
  1076.             fseek(m_pCacheFileHandle, ulCurrBlockOffset , SEEK_SET);
  1077.             fread( (void*)(pRemainderBlock->GetBuffer()),
  1078.                                     sizeof(UCHAR), ulRemainderBlockSize, m_pCacheFileHandle );
  1079.             fseek(m_pCacheFileHandle, ulCurrBlockOffset , SEEK_SET);
  1080.             Info* pNewInfo = new Info;
  1081.             if(pNewInfo == NULL)
  1082.             {
  1083.                 res = HXR_OUTOFMEMORY;
  1084.             }
  1085.             else
  1086.             {
  1087.                 // The new block should be contiguous
  1088.                 pNewInfo->ulOffset = ulCurrBlockOffset;
  1089.                 pNewInfo->ulSize = ulRemainderBlockSize;
  1090.                 pNewInfo->pBlock = pRemainderBlock;
  1091.                 m_pList->AddHead( (void *)pNewInfo );
  1092.                 m_ulUsedCapacity += ulRemainderBlockSize;
  1093.             }
  1094.         }
  1095.     }
  1096.     if(res != HXR_OK)
  1097.         return res;
  1098.     for(int i = 0; i < ulNumFullBlocks; i++)
  1099.     {
  1100.         IHXBuffer* pTempBlock = NULL;
  1101.         m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  1102.                          (void **) &pTempBlock);
  1103.         if(pTempBlock != NULL)
  1104.         {
  1105.             res = pTempBlock->SetSize(ulBlockSize);
  1106.         }
  1107.         else
  1108.         {
  1109.             res = HXR_OUTOFMEMORY;
  1110.         }
  1111.         if(res == HXR_OK)
  1112.         {
  1113.             ulCurrBlockOffset -= ulBlockSize;
  1114.             fseek(m_pCacheFileHandle, ulCurrBlockOffset, SEEK_SET);
  1115.             fread( (void*)(pTempBlock->GetBuffer()),
  1116.                                     sizeof(UCHAR), ulBlockSize, m_pCacheFileHandle );
  1117.             fseek(m_pCacheFileHandle, ulCurrBlockOffset, SEEK_SET);
  1118.             Info* pNewInfo = new Info;
  1119.             if(pNewInfo == NULL)
  1120.             {
  1121.                 res = HXR_OUTOFMEMORY;
  1122.             }
  1123.             else
  1124.             {
  1125.                 // The new block should be contiguous
  1126.                 pNewInfo->ulOffset = ulCurrBlockOffset;
  1127.                 pNewInfo->ulSize = ulBlockSize;
  1128.                 pNewInfo->pBlock = pTempBlock;
  1129.                 m_pList->AddHead( (void *)pNewInfo );
  1130.                 m_ulUsedCapacity += ulBlockSize;
  1131.             }
  1132.         }
  1133.     }
  1134.     return res;
  1135. } // _CopyFromFileToHead()
  1136. // Copy all the data present in the list to the local file
  1137. HX_RESULT CHXFileCacheObject::_CopyAllDataToFile()
  1138. {
  1139.     MLOG_HTTP("CHXFileCacheObject::_CopyAllDataToFile()n");
  1140.     if(m_pList == NULL)
  1141.         return HXR_UNEXPECTED;
  1142.     LISTPOSITION currPos = m_pList->GetHeadPosition();
  1143.     Info* pCurrInfo;
  1144.     while(currPos != NULL)
  1145.     {
  1146.         pCurrInfo = (Info *)m_pList->GetNext(currPos);
  1147.         UINT32 ulCurrBlockOffset = pCurrInfo->ulOffset;
  1148.         UINT32 ulCurrBlockSize = pCurrInfo->ulSize;
  1149.         // If data already written to file, no need to write again.
  1150.         if( (m_ulFileWriteOffset >= ulCurrBlockOffset) &&
  1151.             (m_ulFileWriteOffset <= ulCurrBlockOffset + ulCurrBlockSize - 1) )
  1152.         {
  1153.             UINT32 ulDataAlreadyWritten = m_ulFileWriteOffset - ulCurrBlockOffset;
  1154.             UINT32 ulDataToWrite = ulCurrBlockSize - ulDataAlreadyWritten;
  1155.             fseek(m_pCacheFileHandle, m_ulFileWriteOffset, SEEK_SET);
  1156.             int nBytesWritten = fwrite( (void*)(pCurrInfo->pBlock->GetBuffer() +
  1157.                                         ulDataAlreadyWritten), sizeof(UCHAR), 
  1158.                                         ulDataToWrite, m_pCacheFileHandle);
  1159.             fflush(m_pCacheFileHandle);
  1160.             m_ulFileWriteOffset += ulDataToWrite;
  1161.         }
  1162.     }
  1163.     return HXR_OK;
  1164. } // _CopyAllDataToFile()