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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: macasyncfile.cpp,v 1.4.36.3 2004/07/09 01:44:14 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. /*
  50.    Macintosh File buffer
  51.    This is a class which pretends to be a file, yet that reads from the file asynchronously.
  52.    It makes the file async calls which read the file, the callback of which spews into a 
  53.    buffer. This is done by using a timer callback which gets called every 1/2 second to 
  54.    spew more data into the buffer. 
  55.    The global list is meant to be used for storage of all the different file objects
  56.    which will get processed each time through the loop.  
  57.    This will significantly enhance the Macintosh when it comes to local playback of files. 
  58.  */
  59. #include "macasyncfile.h"
  60. #include "hxmm.h"
  61. #include "hxslist.h"
  62. #include "hxcore.h"
  63. #include "hxbuffer.h"
  64. #include "hxstrutl.h"
  65. //#include "../dcondev/dcon.h"
  66. //#define _LOG_DATA 1
  67. // ULONG32 HXAsyncQueueBuffer::msAllocatedBufferCount = 0;
  68. //#define LOG_MULTIPLE_DEFERRED_TASKS 1
  69. #if defined(_DEBUG) && defined (_LOG_DATA)
  70. #define DEBUGSTR(x) DebugStr(x)
  71. #else
  72. #define DEBUGSTR(x)
  73. #endif
  74. CMacAsyncFile::CMacAsyncFile() :
  75.      mReadQueue(NULL)
  76.     ,mSeekFromWhere(0)
  77.     ,mSeekPos(0)
  78.     ,mFilePos(0)
  79.     ,m_ulReadPositionInFile(0)
  80.     ,m_pResponse(NULL)
  81.     ,m_bFileDone(FALSE)
  82.     ,m_bReadPending(FALSE)
  83.     ,m_bSeekPending(FALSE)
  84.     ,m_ulPendingReadCount(FALSE)
  85.     ,mAsyncQueue(NULL)
  86.     ,mOutStandingCallbacks(0)
  87.     ,m_bSettingSeekState(FALSE)    
  88.     ,m_bCheckFromPQ(FALSE)
  89.     ,m_bInternalSeekNeeded(FALSE)
  90.     ,m_pPendingCallbackList(NULL)
  91.     ,m_pTimedPQList(NULL)
  92.     ,m_pLocationPQList(NULL)
  93.     ,m_ulTotalPQSize(0)
  94.     ,m_bDeferredTaskPending(FALSE)
  95.     ,m_bIsQuitting(FALSE)
  96.     ,m_bInEnqueueAsyncBuffers(FALSE)
  97.     ,m_bPendingAsyncSeekCompleted(FALSE)
  98.     ,m_bAllCallbacksCompleted(FALSE)
  99.     ,m_bInProcessPendingCallbacks(FALSE)
  100.     ,m_pMutex(NULL)
  101.     ,m_lRefCount(0)
  102. {
  103.     mAsyncQueue = new CHXSimpleList();
  104.     m_pPendingCallbackList = new CHXSimpleList;
  105.     m_pTimedPQList       = new CHXSimpleList;
  106.     m_pLocationPQList       = new CHXSimpleList;
  107.     mReadQueue = new CBigByteQueue(kMacAsyncBuffer, 1);
  108.     
  109.     m_DeferredTaskStruct.dtReserved = 0;
  110.     m_DeferredTaskStruct.dtFlags = 0;
  111. #ifdef _CARBON
  112.     m_DeferredTaskStruct.dtAddr = NewDeferredTaskUPP(CMacAsyncFile::DeferredTaskProc);
  113. #else
  114.     m_DeferredTaskStruct.dtAddr = NewDeferredTaskProc(CMacAsyncFile::DeferredTaskProc);
  115. #endif
  116.     m_DeferredTaskStruct.dtParam = (long) this; 
  117.     m_DeferredTaskStruct.qType = dtQType;
  118.     
  119.     m_uNumDeferredTask = 0;
  120. #if defined(THREADS_SUPPORTED)
  121.     HXMutex::MakeMutex(m_pMutex);
  122. #else
  123.     HXMutex::MakeStubMutex(m_pMutex);
  124.     
  125.     HX_ASSERT(m_pMutex);
  126. #endif // defined(THREADS_SUPPORTED) 
  127. }
  128. CMacAsyncFile::~CMacAsyncFile()
  129. {
  130.     if (m_DeferredTaskStruct.dtAddr != NULL)
  131.     {
  132. #ifdef _CARBON
  133. DisposeDeferredTaskUPP(m_DeferredTaskStruct.dtAddr);
  134. #else
  135. DisposeRoutineDescriptor(m_DeferredTaskStruct.dtAddr);
  136. #endif
  137. m_DeferredTaskStruct.dtAddr = NULL;
  138.     }    
  139.     Close();
  140.     HX_DELETE(mAsyncQueue);
  141.     HX_DELETE(m_pPendingCallbackList);
  142.     HX_DELETE(m_pTimedPQList);
  143.     HX_DELETE(m_pLocationPQList);
  144.     HX_DELETE(mReadQueue);
  145. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  146.     BOOL bWaitedForDeferred = FALSE;
  147.     if ( m_bDeferredTaskPending )
  148.     {
  149. bWaitedForDeferred = TRUE;
  150. DebugStr("pCMacAsyncFile dtor -- a deferred task is pending!;g");
  151.     }
  152. #endif
  153.     
  154.     UINT32 timeout = TickCount() + 300L;
  155.     m_bIsQuitting = TRUE;
  156.     while ( m_bDeferredTaskPending && timeout - TickCount() > 0 )
  157.     {
  158. // sit-n-spin, awaiting completion of callbacks.
  159.     }
  160.     
  161. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  162.     if ( bWaitedForDeferred )
  163.     {
  164. if ( m_bDeferredTaskPending )
  165. {
  166.     DebugStr("pdeferred task STILL pending! This is gonna hurt;g");
  167. }
  168. else
  169. {
  170.     DebugStr( "pDeferred tasks were successfully purged;g" );
  171. }
  172.     }
  173. #endif
  174.     HX_DELETE(m_pMutex);
  175. }
  176. STDMETHODIMP_(ULONG32) CMacAsyncFile::AddRef()
  177. {
  178.     return InterlockedIncrement(&m_lRefCount);
  179. }
  180. STDMETHODIMP_(ULONG32) CMacAsyncFile::Release()
  181. {
  182.     if (InterlockedDecrement(&m_lRefCount) > 0)
  183.     {
  184. return m_lRefCount;
  185.     }
  186.     
  187.     delete this;
  188.     return 0;
  189. }
  190. void CMacAsyncFile::EmptyAsyncQueue()
  191. {    
  192.     m_pMutex->Lock();
  193.     while(mAsyncQueue && mAsyncQueue->GetCount() > 0)
  194.     {
  195.         HXAsyncQueueBuffer* x = (HXAsyncQueueBuffer*) mAsyncQueue->RemoveHead();
  196.         
  197.         HX_DELETE(x);
  198.     }
  199.     
  200.     while(m_pTimedPQList && m_pTimedPQList->GetCount() > 0)
  201.     {
  202.         HXAsyncQueueBuffer* x = (HXAsyncQueueBuffer*) m_pTimedPQList->RemoveHead();
  203.         
  204.         HX_DELETE(x);
  205.     }  
  206.     
  207.     if (m_pLocationPQList)
  208.     {
  209.         m_pLocationPQList->RemoveAll();
  210.     }
  211.     
  212.     m_ulTotalPQSize = 0;
  213.     
  214.     while(m_pPendingCallbackList && m_pPendingCallbackList->GetCount() > 0)
  215.     {
  216.         HXParamBlockRec* pb = (HXParamBlockRec*) m_pPendingCallbackList->RemoveHead();
  217.         
  218.         HX_DELETE(pb);
  219.     }
  220.     m_pMutex->Unlock();
  221. }
  222. void
  223. CMacAsyncFile::DeleteAsyncQueueBuffer(HXAsyncQueueBuffer* x, LISTPOSITION pos)
  224. {
  225.     m_pMutex->Lock();
  226.     BOOL bInserted;
  227.     
  228.     mAsyncQueue->RemoveAt(pos);
  229.     
  230.     /* we only keep full buffers around*/
  231.     if (x->state != AB_STATE_FULL)
  232.     {
  233.         goto discard;
  234.     }
  235.     
  236.     x->current_size    = x->size;
  237.     x->current_buf_ptr = x->buffer;
  238.     // insert in location list
  239.     pos = m_pLocationPQList->GetTailPosition();
  240.     bInserted = FALSE;
  241.     while (pos)
  242.     {
  243.          HXAsyncQueueBuffer* pNode  = (HXAsyncQueueBuffer*) m_pLocationPQList->GetAt(pos);
  244.          if (x->position_in_file >= pNode->position_in_file+pNode->size)
  245.          {
  246.              m_pLocationPQList->InsertAfter(pos, x);
  247.              bInserted = TRUE;
  248.              break;
  249.          }
  250.          
  251.          m_pLocationPQList->GetPrev(pos);
  252.     }
  253.     
  254.     if (!bInserted)
  255.     {
  256.         m_pLocationPQList->AddHead(x);
  257.     }
  258.     
  259.     m_pTimedPQList->AddTail(x);
  260.     m_ulTotalPQSize += x->size;
  261.     
  262.     //dfprintf("mem","PQ Add: %p %lu, %lu, %lun", this, x->position_in_file, x->size, m_ulTotalPQSize);
  263.     // time to expire some -- keep a max of 4*48K in memory?
  264.     if (m_ulTotalPQSize > 4*kMacAsyncBuffer)
  265.     {
  266.         x = (HXAsyncQueueBuffer*) m_pTimedPQList->RemoveHead();
  267.         
  268.         // remove from location list
  269.         pos = m_pLocationPQList->Find((void*)x);
  270.         HX_ASSERT(pos != NULL);
  271.         m_pLocationPQList->RemoveAt(pos);
  272.         
  273.         m_ulTotalPQSize -= x->size;
  274.         //dfprintf("mem", "PQ Remove: %lu, %lu, %lun", x->position_in_file, x->size, m_ulTotalPQSize);
  275.     }
  276.     else
  277.     {
  278.         // early exit
  279.         m_pMutex->Unlock();
  280.         return;
  281.     }
  282. discard:    
  283.     delete x;
  284.     m_pMutex->Unlock();
  285. }
  286. BOOL
  287. CMacAsyncFile::FillBufferFromPQ(UINT32 ulFillPosition)
  288. {
  289.     m_pMutex->Lock();
  290.     BOOL bFilled = FALSE;
  291.     
  292.     LISTPOSITION pos = m_pLocationPQList->GetHeadPosition();
  293.     UINT32 ulEmptyCount = mReadQueue->GetAvailableElements();
  294.     UINT32 ulOrigFillPosition = ulFillPosition;
  295.     while(pos && ulEmptyCount > 0)
  296.     {
  297.         HXAsyncQueueBuffer* x = (HXAsyncQueueBuffer*) m_pLocationPQList->GetAt(pos);
  298.         
  299.         // find the starting byte
  300.         if (x->position_in_file <= ulFillPosition && 
  301.             x->position_in_file+x->size > ulFillPosition)
  302.         {
  303.             UINT32 ulBytesToCopy = x->position_in_file+x->size - ulFillPosition;
  304.             if (ulBytesToCopy > ulEmptyCount)
  305.             {
  306.                 ulBytesToCopy = ulEmptyCount;
  307.             }
  308.             
  309.             HX_ASSERT(ulBytesToCopy > 0);
  310.             HX_VERIFY(mReadQueue->EnQueue(x->buffer+ulFillPosition-x->position_in_file, 
  311.              ulBytesToCopy) == ulBytesToCopy);
  312.             ulEmptyCount -= ulBytesToCopy;
  313.             bFilled = TRUE;
  314.             ulFillPosition += ulBytesToCopy;
  315.             LISTPOSITION timedPos = m_pTimedPQList->Find((void*) x);
  316.             HX_ASSERT(timedPos != NULL);
  317.             m_pTimedPQList->RemoveAt(timedPos);
  318.             m_pTimedPQList->AddTail(x);
  319.             
  320.             m_ulReadPositionInFile = ulFillPosition;
  321.             
  322.     //dfprintf("mem","FillNoSeek: %lu, %lu, %lu %lun", x->position_in_file, x->size, ulOrigFillPosition, ulEmptyCount);
  323.         }
  324.         else if (x->position_in_file > ulFillPosition)
  325.         {
  326.             break;
  327.         }
  328.         
  329.         (void) m_pLocationPQList->GetNext(pos);
  330.     }
  331.     
  332.     // continue to read data form stores buffers if we were succesfully able
  333.     // to fill buffers this time
  334.     m_bCheckFromPQ = bFilled;
  335.     m_pMutex->Unlock();
  336.     return bFilled;
  337. }
  338. //
  339. //      Pump as many of the Asynchronous buffers into the mReadQueue
  340. //      as is possible.
  341. //
  342. void CMacAsyncFile::EnqueueAsyncBuffers()
  343. {
  344.     LISTPOSITION pos = NULL;
  345.     
  346.     m_pMutex->Lock();
  347.     if (m_bInEnqueueAsyncBuffers)
  348.     {
  349.         m_pMutex->Unlock();
  350.         return;
  351.     }
  352.     
  353.     m_bInEnqueueAsyncBuffers = TRUE;
  354.     /* See if there are any pending callbacks */
  355.     ProcessPendingCallbacks();
  356.     
  357.     pos = mAsyncQueue->GetHeadPosition();
  358.     while(pos)
  359.     {
  360. HXAsyncQueueBuffer *x =(HXAsyncQueueBuffer *) mAsyncQueue->GetAt(pos);
  361. if(x)
  362. {
  363.     if(x->state == AB_STATE_IGNORED)
  364.     {
  365. //
  366. //      Due to a seek this buffer has now become out of context
  367. //      So dispose of it and then check the next buffer.
  368. //
  369. DeleteAsyncQueueBuffer(x, pos);
  370. pos = mAsyncQueue->GetHeadPosition();
  371. continue;
  372.     }
  373.     if(x->state == AB_STATE_FULL)
  374.     {
  375.         UINT32 ulEmptyCount = mReadQueue->GetAvailableElements();
  376.         
  377.         /* This assumes that the pending count can NEVER be greater than
  378.          * the total size of the byte queue i.e. the size of the
  379.          * byte queue is the max read size we allow
  380.          * currently it is set to 48K (odd number eh?)
  381.          */
  382.         
  383.         if (m_bReadPending && ulEmptyCount > 0)
  384.         {
  385.             if (ulEmptyCount > x->current_size)
  386.             {
  387.                 ulEmptyCount = x->current_size;
  388.             }
  389.             
  390.             HX_ASSERT(ulEmptyCount > 0);
  391.             // This used to have a HX_VERIFY on the result. After the
  392.             // most recent change, though, where the "m_bReadPending"
  393.             // if statement was changed, the assert started yelling.
  394.             // Nobody's very comfortable about forcibly ignoring the
  395.             // verify, but it seems to function.
  396.             HX_VERIFY(mReadQueue->EnQueue(x->current_buf_ptr, ulEmptyCount) == ulEmptyCount);
  397.             
  398.             x->current_size    -= ulEmptyCount;
  399.             x->current_buf_ptr += ulEmptyCount;
  400.             
  401.             if (x->current_size == 0)
  402.             {
  403. //dfprintf("mem","Done with buffern");
  404. DeleteAsyncQueueBuffer(x, pos);
  405.     }
  406.     else
  407.     {
  408.         break;
  409.     }
  410. }
  411. else
  412. {
  413.     break;
  414. }
  415.     }
  416.     else
  417.     {
  418. //
  419. //      In this case we have to break, because there isn't a buffer available.
  420. //
  421. break;
  422.     }
  423. }
  424. pos = mAsyncQueue->GetHeadPosition();
  425.     }
  426.     m_bInEnqueueAsyncBuffers = FALSE;
  427.     m_pMutex->Unlock();
  428. }
  429. CHXDataFile *CMacAsyncFile::Construct()
  430. {
  431.     CMacAsyncFile *result = new CMacAsyncFile();
  432.     
  433.     result->AddRef();
  434.     return result;
  435. }
  436. HX_RESULT CMacAsyncFile::Open(const char *filename, UINT16 mode, BOOL textflag)
  437. {
  438.     return HXR_NOTIMPL;
  439. }
  440. HX_RESULT CMacAsyncFile::SafeOpen (const char *filename, UINT16 mode, BOOL textflag, BOOL bAtInterrupt)
  441. {
  442. #if defined(_DEBUG) && defined (_LOG_DATA)
  443.     char str[255]; /* Flawfinder: ignore */
  444.    ::sprintf(str, "SafeOpen %d;g", (int) bAtInterrupt); /* Flawfinder: ignore */
  445.     DEBUGSTR(c2pstr(str));
  446. #endif
  447.  
  448.    m_pMutex->Lock();
  449.    HX_RESULT result = CMacFile::Open(filename, mode, textflag);
  450.    ULONG32 count = 0;
  451.     mFilePos = 0;
  452.     m_ulReadPositionInFile = 0;
  453.     if(result == HXR_OK)
  454.     {
  455.     ReadAsyncData(bAtInterrupt);
  456.     }
  457.     //
  458.     //   Set it to null.
  459.     //
  460.     mFilePos = 0;
  461.     
  462.     m_pMutex->Unlock();
  463.     return result;
  464. }
  465.  
  466. HX_RESULT CMacAsyncFile::Close(void)
  467. {
  468.     m_pMutex->Lock();
  469.     HX_RESULT result = CMacFile::Close();
  470.     EmptyAsyncQueue();
  471.     mReadQueue->FlushQueue();
  472.     m_pMutex->Unlock();
  473.     return result;
  474. }
  475. HX_RESULT CMacAsyncFile::Seek(ULONG32 offset, UINT16 fromWhere)
  476. {
  477.     return HXR_NOTIMPL;
  478. }
  479. void
  480. CMacAsyncFile::PerformInternalSeek(BOOL ASYNC)
  481. {
  482.     m_pMutex->Lock();
  483.     mSeekFromWhere = fsFromStart;
  484.     mSeekPos = m_ulReadPositionInFile;
  485.     UpdateFilePos(ASYNC, TRUE);
  486.     m_pMutex->Unlock();
  487. }
  488. HX_RESULT
  489. CMacAsyncFile::SafeSeek(ULONG32 offset, UINT16 fromWhere, BOOL bAtInterrupt)
  490. {
  491. #if defined(_DEBUG) && defined (_LOG_DATA)
  492.     char str[255]; /* Flawfinder: ignore */
  493.    ::sprintf(str, "SafeSeek: %lu %u %d;g", offset, fromWhere, (int) bAtInterrupt); /* Flawfinder: ignore */
  494.     DEBUGSTR(c2pstr(str));
  495. #endif
  496.     if (m_pMutex) m_pMutex->Lock();
  497.     //dfprintf("mem","SafeSeek: %lu, %u, %dn", offset, fromWhere, (int) bAtInterrupt);
  498.     m_bFileDone  = FALSE;
  499.     m_bReadPending = FALSE;
  500.      
  501.     LISTPOSITION pos = NULL;
  502.     /* If we get a read deferred callback while setting the state for buffers in
  503.      * async queue, ignore it
  504.      */
  505.     m_bSettingSeekState = TRUE;
  506.     pos = mAsyncQueue->GetHeadPosition();
  507.     while(pos)
  508.     {
  509. HXAsyncQueueBuffer *x =(HXAsyncQueueBuffer *) mAsyncQueue->GetAt(pos);
  510. if(x->state == AB_STATE_FULL)
  511. {
  512.     DeleteAsyncQueueBuffer(x, pos);
  513.     pos = mAsyncQueue->GetHeadPosition();
  514.     continue;
  515.     //x->state = AB_STATE_IGNORED;
  516. }
  517. /* All other states are pending states and result in AB_STATE_OUTOFCONTEXT */
  518. else if(x->state != AB_STATE_IGNORED)
  519. {
  520.     x->state = AB_STATE_OUTOFCONTEXT;
  521. }
  522. mAsyncQueue->GetNext(pos);
  523.     }
  524.     m_bSettingSeekState = FALSE;
  525.     mReadQueue->FlushQueue();
  526.     m_bSeekPending = TRUE;
  527.     if(BufferedWrite())
  528.     {
  529. CMacFile::Seek(offset, fromWhere);
  530. PendingAsyncSeekDone();
  531.     }
  532.     else
  533.     {
  534.         UINT32 ulSeekPosition = 0;
  535.         BOOL bSeekNeeded = FALSE;
  536.         
  537. switch(fromWhere)
  538. {
  539. case SEEK_SET:
  540.     fromWhere = fsFromStart;
  541.     mSeekFromWhere = fromWhere;
  542.     mSeekPos = offset;
  543.     ulSeekPosition = m_ulReadPositionInFile = offset;
  544.     break;
  545. case SEEK_CUR:
  546.     fromWhere = fsFromMark;
  547.     mSeekFromWhere = fromWhere;
  548.     mSeekPos = offset;
  549.     ulSeekPosition = m_ulReadPositionInFile = mFilePos+offset;
  550.     break;
  551. case SEEK_END:
  552.     //HX_ASSERT(!"Need to add support for seek from end -- XXXRA");
  553.     fromWhere = fsFromLEOF;
  554.     mSeekFromWhere = fromWhere;
  555.     mSeekPos = offset;
  556.     bSeekNeeded = TRUE;
  557.     break;
  558. }
  559.         if (!bSeekNeeded)
  560.         {
  561.             bSeekNeeded = !(FillBufferFromPQ(ulSeekPosition));
  562.         }
  563.         
  564.         if (bSeekNeeded)
  565.         {
  566.     UpdateFilePos(bAtInterrupt);
  567. }
  568. else
  569. {
  570.     mFilePos     = ulSeekPosition;
  571.     mSeekFromWhere = 0;
  572.             m_bInternalSeekNeeded = TRUE;
  573.     PendingAsyncSeekDone();
  574. }
  575.     }
  576.     DEBUGSTR("p EXIT SafeSeek;g");
  577.     
  578.     if (m_pMutex) m_pMutex->Unlock();
  579.     return HXR_OK;
  580. }
  581. HX_RESULT
  582. CMacAsyncFile::SafeRead(ULONG32 count, BOOL bAtInterrupt)
  583. {
  584.     AddRef();
  585.     m_pMutex->Lock();
  586.     HX_ASSERT(m_bReadPending == FALSE);
  587.     if(!mReadQueue || m_bReadPending)
  588.     {
  589.         DEBUGSTR("p SafeRead UNEXPECTED;g");
  590.         //dfprintf("mem", "SafeRead UNEXPECTEDn");
  591.         m_pMutex->Unlock();
  592.         Release();
  593. return HXR_UNEXPECTED;
  594.     }
  595. #if defined(_DEBUG) && defined (_LOG_DATA)
  596.     char str[255]; /* Flawfinder: ignore */
  597.    ::sprintf(str, "SafeRead: %lu %d;g", count, (int) bAtInterrupt); /* Flawfinder: ignore */
  598.     DEBUGSTR(c2pstr(str));
  599. #endif
  600.     
  601.     //dfprintf("mem","SafeRead: %lu, %dn", count, (int) bAtInterrupt);
  602.     m_bReadPending  = TRUE;
  603.     m_ulPendingReadCount = count;
  604.     EnqueueAsyncBuffers();
  605.     ReadAsyncData(bAtInterrupt);
  606.     EnqueueAsyncBuffers();
  607.     
  608.     ProcessPendingRead();
  609.     
  610.    DEBUGSTR("p EXIT SafeRead;g");
  611.    
  612.    m_pMutex->Unlock();
  613.    Release();
  614.    return HXR_OK;
  615. }
  616. ULONG32
  617. CMacAsyncFile::SafeWrite(IHXBuffer* pBuffer, BOOL bAtInterrupt)
  618. {
  619.     m_pMutex->Lock();
  620.     HX_ASSERT(m_bReadPending == FALSE);
  621.     ULONG32 outWrittenSize = 0;
  622.     if(m_bReadPending)
  623.     {
  624.         DEBUGSTR("p SafeWrite UNEXPECTED;g");
  625.         m_pMutex->Unlock();
  626. return outWrittenSize;
  627.     }
  628. #if defined(_DEBUG) && defined (_LOG_DATA)
  629.     char str[255]; /* Flawfinder: ignore */
  630.    ::sprintf(str, "SafeWrite: %d;g", (int) bAtInterrupt); /* Flawfinder: ignore */
  631.     DEBUGSTR(c2pstr(str));
  632. #endif
  633.     
  634.     outWrittenSize = WriteAsyncData(pBuffer, bAtInterrupt);
  635.     DEBUGSTR("p EXIT SafeWrite;g");
  636.     m_pMutex->Unlock();
  637.     return outWrittenSize;
  638. }
  639. ULONG32 CMacAsyncFile::Read(char *buf, ULONG32 count)
  640. {
  641.     return HXR_NOTIMPL;
  642. }
  643. //
  644. //      Static Initializers
  645. //
  646. #ifdef _CARBON
  647. IOCompletionUPP CMacAsyncFile::zmIOCallbackUPP = NewIOCompletionUPP((IOCompletionProcPtr)CMacAsyncFile::zmIOCallback);
  648. #else
  649. IOCompletionUPP CMacAsyncFile::zmIOCallbackUPP = NewIOCompletionProc(CMacAsyncFile::zmIOCallback);
  650. #endif
  651. //
  652. //      Tell
  653. //
  654. ULONG32 CMacAsyncFile::Tell(void)
  655. {
  656.     return mFilePos;
  657. }
  658. //
  659. //       This is the zmIOCompletion callback.
  660. //       When this is done, the data is then pumped into the buffer for this file.
  661. //
  662. pascal void CMacAsyncFile::zmIOCallback(HXParamBlockRec * pb)
  663. {
  664.     HXMM_INTERRUPTON();
  665.     /*
  666.      * Setup and then install a deferred task 
  667.      */
  668.     if (pb != NULL &&  pb->param != NULL)
  669.     {
  670.     
  671. CMacAsyncFile* fileobj = (CMacAsyncFile*) pb->param;
  672. fileobj->m_pMutex->Lock();
  673. if (fileobj->m_DeferredTaskStruct.dtAddr != NULL)
  674. {
  675. #if defined(_DEBUG) && defined (_LOG_DATA)
  676.      char tmpStr1[255]; /* Flawfinder: ignore */
  677.      ::sprintf(tmpStr1, "ENTER INterrupt Callback %p ;g", fileobj); /* Flawfinder: ignore */
  678.      DEBUGSTR(c2pstr(tmpStr1));
  679. #endif
  680.     fileobj->AddToThePendingList((void*) pb);
  681.     
  682.     fileobj->m_uNumDeferredTask++;
  683. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  684.     /*
  685.     if (fileobj->m_uNumDeferredTask > 1)
  686.     {
  687.         char tmpStr[255];
  688.         ::sprintf(tmpStr, "More than one pending DeferredTask: %u;g", fileobj->m_uNumDeferredTask);
  689.         DebugStr(c2pstr(tmpStr));
  690.     }
  691.     */
  692. #endif
  693.     
  694.     if (!fileobj->m_bDeferredTaskPending)
  695.     {
  696.         if ( !fileobj->m_bIsQuitting )
  697.         {
  698.     fileobj->m_bDeferredTaskPending = TRUE;
  699. #ifdef _CARBON
  700.     DeferredTaskProc(fileobj->m_DeferredTaskStruct.dtParam);
  701. #else
  702.     DTInstall(&fileobj->m_DeferredTaskStruct);
  703. #endif
  704.         }
  705.     }
  706. }
  707. fileobj->m_pMutex->Unlock();
  708.     }
  709.     
  710.     HXMM_INTERRUPTOFF();
  711. }
  712. pascal void CMacAsyncFile::DeferredTaskProc(long inParam)
  713. {
  714.     HXMM_INTERRUPTON();
  715.     DEBUGSTR("pENTER CMacAsyncFile::DeferredTaskProc;g");
  716.     CMacAsyncFile*   fileobj = (CMacAsyncFile*) inParam;;
  717.     if(fileobj)
  718.     {
  719. #if defined(_DEBUG) && defined (_LOG_DATA)
  720.         char tmpStr[255]; /* Flawfinder: ignore */
  721.         sprintf(tmpStr, " This pointer: %p;g", fileobj); /* Flawfinder: ignore */
  722.         DEBUGSTR(c2pstr(tmpStr));
  723. #endif
  724. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  725.     /*
  726.     if (fileobj->m_uNumDeferredTask != 1)
  727.     {
  728.         char tmpStr[255];
  729.         ::sprintf(tmpStr, "(In DeferredTaskProc) m_uNumDeferredTask != 1: %u;g", fileobj->m_uNumDeferredTask);
  730.         DebugStr(c2pstr(tmpStr));
  731.     }
  732.     */
  733.     if ( !fileobj->m_bDeferredTaskPending )
  734.     {
  735.      DebugStr( "p(In DeferredTaskProc) m_bDeferredTaskPending is false!;g" );
  736.     }
  737. #endif
  738. if ( !fileobj->m_bIsQuitting )
  739. {
  740.     fileobj->ProcessPendingCallbacks();
  741. }
  742.         fileobj->m_bDeferredTaskPending = FALSE;
  743.     }
  744.     
  745.     DEBUGSTR("pLEAVE CMacAsyncFile::DeferredTaskProc;g");
  746.     HXMM_INTERRUPTOFF();
  747. }
  748. void CMacAsyncFile::ProcessPendingCallbacks()
  749. {
  750.     m_pMutex->Lock();
  751.     if (m_bInProcessPendingCallbacks)
  752.     {
  753.         m_pMutex->Unlock();
  754.         return;
  755.     }
  756.  
  757.  start:   
  758.     m_bInProcessPendingCallbacks = TRUE;
  759.     
  760.     while (m_pPendingCallbackList && m_pPendingCallbackList->GetCount() > 0)
  761.     {
  762.         m_uNumDeferredTask--;
  763.         HXParamBlockRec* pb = (HXParamBlockRec*) m_pPendingCallbackList->RemoveHead();
  764.         if (pb && pb->param)
  765.         {
  766.             ProcessBlock(pb);
  767.         }
  768.         HX_DELETE(pb);
  769.     }
  770.     
  771.     EnqueueAsyncBuffers();
  772.     if (m_bPendingAsyncSeekCompleted)
  773.     {
  774.         m_bPendingAsyncSeekCompleted = FALSE;
  775. PendingAsyncSeekDone();
  776.     }
  777.     
  778.     if (mOutStandingCallbacks == 0 && m_bAllCallbacksCompleted)
  779.     {
  780.         m_bAllCallbacksCompleted = FALSE;
  781.         AllPendingCallbacksDone();
  782.     }    
  783.     
  784.     m_bInProcessPendingCallbacks = FALSE;
  785.     
  786.     /* Do we still have more pending callbacks to process? */
  787.     if (m_pPendingCallbackList && m_pPendingCallbackList->GetCount() > 0)
  788.     {
  789.         goto start;
  790.     }
  791.     m_pMutex->Unlock();
  792. }        
  793. void CMacAsyncFile::ProcessBlock(HXParamBlockRec* pb)
  794. {
  795. m_pMutex->Lock();
  796. if (mOutStandingCallbacks > 0)
  797. {
  798.     mOutStandingCallbacks--;
  799. }
  800. if(pb->entry->state == AB_STATE_OUTOFCONTEXT ||
  801.    m_bSettingSeekState)
  802. {
  803.     //
  804.     //      Don't need to do anything with this data
  805.     //      just ignore it. 
  806.     //              
  807.     pb->entry->state = AB_STATE_IGNORED;
  808. }
  809. else if (pb->entry->state == AB_STATE_ASYNC_INTERNAL_SEEK)
  810. {
  811.     m_ulReadPositionInFile = pb->io.ioParam.ioPosOffset;
  812.     pb->entry->state = AB_STATE_IGNORED;
  813. }
  814. else if (pb->entry->state == AB_STATE_ASYNC_SEEK)
  815. {
  816.     mFilePos = pb->io.ioParam.ioPosOffset;
  817.     m_ulReadPositionInFile = mFilePos;
  818.     pb->entry->state = AB_STATE_IGNORED;
  819.     m_bPendingAsyncSeekCompleted = TRUE;     
  820. }
  821. else if (pb->entry->state == AB_STATE_WRITE)
  822. {
  823.     HX_VECTOR_DELETE(pb->entry->buffer);
  824.     pb->entry->state = AB_STATE_IGNORED;
  825. }
  826. else
  827. {
  828.     /* Are we at the end of the file? */
  829.     if (pb->io.ioParam.ioActCount < pb->entry->size)
  830.     {
  831.         m_bFileDone = TRUE;
  832. #if defined(_DEBUG) && defined (_LOG_DATA)
  833.         char tmpStr[255]; /* Flawfinder: ignore */
  834.         sprintf(tmpStr, "ProcessBlock %d %d;g", pb->io.ioParam.ioActCount, pb->entry->size); /* Flawfinder: ignore */
  835.         DEBUGSTR(c2pstr(tmpStr));
  836. #endif
  837.     }
  838.     pb->entry->size = pb->io.ioParam.ioActCount;
  839.     pb->entry->current_size = pb->io.ioParam.ioActCount;
  840.     if(pb->io.ioParam.ioBuffer && pb->entry->size > 0)
  841.     {
  842.         pb->entry->state = AB_STATE_FULL;
  843.         m_ulReadPositionInFile += pb->entry->size;
  844.     }
  845.     else
  846.     {
  847.         pb->entry->state = AB_STATE_IGNORED;
  848.     }
  849. }
  850. if (mOutStandingCallbacks == 0)
  851. {
  852.             m_bAllCallbacksCompleted = TRUE;
  853. }
  854. m_pMutex->Unlock();
  855. }
  856. void CMacAsyncFile::AddToThePendingList(void* pNode)
  857. {
  858.     m_pMutex->Lock();
  859.     /* Atleast one of the list MUST be free to operate on */
  860.     HX_ASSERT(m_pPendingCallbackList != NULL);
  861.     if (m_pPendingCallbackList)
  862.     {
  863.         m_pPendingCallbackList->AddTail(pNode);
  864.     }
  865.     m_pMutex->Unlock();
  866. }
  867. //
  868. //
  869. //      Start the Async file IO call which physically reads the data into the buffer.
  870. //
  871. //
  872. void CMacAsyncFile::ReadAsyncData(BOOL ASYNC)
  873. {
  874.     m_pMutex->Lock();
  875.     OSErr e = noErr;
  876. #if defined(_DEBUG) && defined (_LOG_DATA)
  877.     char str[255]; /* Flawfinder: ignore */
  878.    ::sprintf(str, "ReadAsyncData: %d;g", (int) ASYNC); /* Flawfinder: ignore */
  879.     DEBUGSTR(c2pstr(str));
  880. #endif
  881.  
  882.     // mOutStandingCallbacks: if there are any, then we bail right
  883.     // now 'cause we don't want scads of pending callbacks... the math
  884.     // will work out in the end because subsequent calls will have us
  885.     // read more bytes.
  886.     
  887.     if(!mRefNum || m_bFileDone || mOutStandingCallbacks > 0)
  888.     {
  889.         m_pMutex->Unlock();
  890. return;
  891.     }
  892.     ULONG32 emptysize = mReadQueue->GetAvailableElements();
  893.     if(emptysize < kNeedToReadThreshhold)
  894.     {
  895.         m_pMutex->Unlock();
  896.         DEBUGSTR("p ReadAsyncData: emptysize < kNeedToReadThreshhold ;g");
  897.   return;
  898.     }
  899.     
  900.     if (m_bCheckFromPQ)
  901.     {
  902.         BOOL bFilled = FillBufferFromPQ(m_ulReadPositionInFile);
  903.         if (bFilled)
  904.         {
  905.             emptysize = mReadQueue->GetAvailableElements();
  906.             if(emptysize < kNeedToReadThreshhold)
  907.             {
  908.                 m_pMutex->Unlock();
  909.                 return;
  910.             }
  911.         }
  912.     }
  913.     
  914.     if (emptysize > kMacMaxChunkToRead)
  915.     {
  916. emptysize = kMacMaxChunkToRead;
  917.     }
  918.     
  919.     if (m_bInternalSeekNeeded)
  920.     {
  921.         m_bInternalSeekNeeded = FALSE;
  922.         PerformInternalSeek(ASYNC);
  923.         // more stuff will be done once we get async callback for internal seek
  924.         if (ASYNC)
  925.         {
  926.             m_pMutex->Unlock();
  927.             return;
  928.         }
  929.     }
  930.     HXParamBlockRec *pb = new HXParamBlockRec;
  931.     memset(pb, 0, sizeof(HXParamBlockRec));
  932.     pb->param = this;
  933.     pb->io.ioParam.ioCompletion = zmIOCallbackUPP;
  934.     pb->io.ioParam.ioRefNum = mRefNum;
  935.     pb->entry = new HXAsyncQueueBuffer;
  936.     memset(pb->entry, 0, sizeof(HXAsyncQueueBuffer));
  937.     pb->entry->size = emptysize;
  938.     pb->entry->current_size = emptysize;
  939.     
  940.     pb->entry->position_in_file = m_ulReadPositionInFile;
  941.     char* tempbuffer = new char[emptysize];
  942.     pb->entry->buffer  = tempbuffer;
  943.     pb->entry->current_buf_ptr  = tempbuffer;
  944.     pb->entry->state = AB_STATE_EMPTY;
  945.     pb->io.ioParam.ioBuffer = tempbuffer;
  946.     pb->io.ioParam.ioReqCount = emptysize;
  947.     HX_ASSERT(mSeekFromWhere == 0);
  948.     e = ReadData(pb, ASYNC);
  949.     if (!ASYNC)
  950.     {
  951.          if (e == noErr)
  952.          {
  953.      pb->entry->state = AB_STATE_FULL;
  954.      pb->entry->size = pb->io.ioParam.ioActCount;
  955.      pb->entry->current_size = pb->io.ioParam.ioActCount;
  956.      m_ulReadPositionInFile += pb->entry->size;
  957.      mAsyncQueue->AddTail(pb->entry);
  958.  }
  959.  else
  960.  {
  961.      HX_DELETE(pb->entry);
  962.  }
  963.        
  964.  HX_DELETE(pb);
  965.     }
  966.     else
  967.     {
  968.         if (e != noErr)
  969.         {
  970.     HX_DELETE(pb->entry);
  971.     HX_DELETE(pb);
  972.         }
  973.     }    
  974.     DEBUGSTR("p ReadAsyncData EXIT; g");
  975.     m_pMutex->Unlock();
  976.     return;
  977. }
  978. ULONG32 CMacAsyncFile::WriteAsyncData(IHXBuffer* pBuffer, BOOL ASYNC)
  979. {
  980.     ULONG32 outWrittenSize = 0;
  981.     OSErr e = noErr;
  982. #if defined(_DEBUG) && defined (_LOG_DATA)
  983.     char str[255]; /* Flawfinder: ignore */
  984.    ::sprintf(str, "WriteAsyncData: %d;g", (int) ASYNC); /* Flawfinder: ignore */
  985.     DEBUGSTR(c2pstr(str));
  986. #endif
  987.  
  988.     if(!mRefNum)
  989.     {
  990. return outWrittenSize;
  991.     }
  992.     pBuffer->AddRef();
  993.     HXParamBlockRec *pb = new HXParamBlockRec;
  994.     memset(pb, 0, sizeof(HXParamBlockRec));
  995.     pb->param = this;
  996.     pb->io.ioParam.ioCompletion = zmIOCallbackUPP;
  997.     pb->io.ioParam.ioRefNum = mRefNum;
  998.     pb->entry = new HXAsyncQueueBuffer;
  999.     memset(pb->entry, 0, sizeof(HXAsyncQueueBuffer));
  1000.     
  1001.     outWrittenSize = pBuffer->GetSize();
  1002.     pb->entry->size = outWrittenSize;
  1003.     pb->entry->current_size = outWrittenSize;
  1004.     pb->entry->state = AB_STATE_WRITE;
  1005.     char* tempbuffer = NULL;
  1006.     if (ASYNC)
  1007.     {
  1008.      tempbuffer = new char[outWrittenSize];
  1009.      BlockMoveData(pBuffer->GetBuffer(), tempbuffer, outWrittenSize);
  1010.      pb->entry->buffer = tempbuffer;
  1011.      pb->entry->current_buf_ptr = tempbuffer;
  1012. pb->io.ioParam.ioBuffer = tempbuffer;
  1013.     }
  1014.     else
  1015.     {
  1016. pb->io.ioParam.ioBuffer = ( char* ) pBuffer->GetBuffer();
  1017.     }
  1018.     pb->io.ioParam.ioReqCount = outWrittenSize;
  1019.     HX_ASSERT(mSeekFromWhere == 0);
  1020.     e = WriteData(pb, ASYNC);
  1021.     if (!ASYNC)
  1022.     {
  1023.  HX_DELETE(pb->entry);
  1024.  HX_DELETE(pb);
  1025.     }
  1026.     else
  1027.     {
  1028.         if (e != noErr)
  1029.         {
  1030.     HX_DELETE(pb->entry);
  1031.     HX_DELETE(pb);
  1032.         }
  1033.     }    
  1034.     DEBUGSTR("p WriteAsyncData EXIT; g");
  1035.     pBuffer->Release();
  1036.     return outWrittenSize;
  1037. }
  1038. void CMacAsyncFile::UpdateFilePos(BOOL bASync, BOOL bInternal)
  1039. {
  1040.     AddRef();
  1041.     m_pMutex->Lock();
  1042.      DEBUGSTR("p UpdateFilePos;g");
  1043.    OSErr e = noErr;
  1044.     if(!mRefNum)
  1045.     {
  1046. m_pMutex->Unlock();
  1047. Release();
  1048. return;
  1049.     }
  1050.     HXParamBlockRec *pb = new HXParamBlockRec;
  1051.     memset(pb, 0, sizeof(HXParamBlockRec));
  1052.     pb->param = this;
  1053.     pb->io.ioParam.ioRefNum = mRefNum;
  1054.     pb->io.ioParam.ioReqCount = 0;
  1055.     pb->io.ioParam.ioCompletion = zmIOCallbackUPP;
  1056.     pb->entry = new HXAsyncQueueBuffer;
  1057.     memset(pb->entry, 0, sizeof(HXAsyncQueueBuffer));
  1058.     HX_ASSERT(mSeekFromWhere > 0);
  1059.     if(mSeekFromWhere)
  1060.     {
  1061. pb->io.ioParam.ioPosMode = mSeekFromWhere;
  1062. pb->io.ioParam.ioPosOffset = mSeekPos;
  1063. mSeekFromWhere = 0;
  1064. mSeekPos = 0;
  1065. if (bInternal)
  1066. {
  1067.             pb->entry->state = AB_STATE_ASYNC_INTERNAL_SEEK;
  1068.         }
  1069.         else
  1070.         {
  1071.             pb->entry->state = AB_STATE_ASYNC_SEEK;
  1072.         }
  1073.     }
  1074.     e = SeekData(pb, bASync);
  1075.     if (!bASync)
  1076.     {
  1077.          if (e == noErr)
  1078.          {
  1079.      m_ulReadPositionInFile = pb->io.ioParam.ioPosOffset;
  1080.              if (!bInternal)
  1081.              {
  1082.          mFilePos = pb->io.ioParam.ioPosOffset;
  1083.      }
  1084.  }
  1085.      
  1086.  HX_DELETE(pb->entry);
  1087.  HX_DELETE(pb);
  1088.     }
  1089.     else
  1090.     {
  1091.         if (e != noErr)
  1092.         {
  1093.     HX_DELETE(pb->entry);
  1094.     HX_DELETE(pb);
  1095.         }
  1096.     }    
  1097.     if (!bASync && !bInternal)
  1098.     {
  1099. PendingAsyncSeekDone();
  1100.     }
  1101.     m_pMutex->Unlock();
  1102.     Release();
  1103.     return;
  1104. }
  1105. OSErr
  1106. CMacAsyncFile::ReadData(HXParamBlockRec* pb, BOOL ASYNC)
  1107. {
  1108.     m_pMutex->Lock();
  1109.     OSErr e = noErr;
  1110.     if(ASYNC)
  1111.     {
  1112. mAsyncQueue->AddTail(pb->entry);
  1113. mOutStandingCallbacks++;
  1114.     }
  1115.     
  1116.     // xxxbobclark large PBRead's on SMB-mounted volumes are failing here.
  1117.     // That's why we reduced the constants in the .h file for carbon builds.
  1118.     e = PBRead((ParmBlkPtr) pb, ASYNC);
  1119.     if (e == eofErr)
  1120.     {
  1121.     m_bFileDone = TRUE;
  1122.     
  1123.         DEBUGSTR("pFIle Done in ReadData;g");
  1124.     /* Mask this error if this is the last read */
  1125.     /* If either we are in aysnc mode OR we actually read some data */
  1126.     if (ASYNC ||  pb->io.ioParam.ioActCount > 0)
  1127.     {
  1128.      e = noErr;
  1129.     }
  1130.     }
  1131.     if(e != noErr && ASYNC && mOutStandingCallbacks > 0)
  1132.     {
  1133.         mAsyncQueue->RemoveTail();
  1134.         mOutStandingCallbacks--;
  1135.     }
  1136.     m_pMutex->Unlock();
  1137.     return e;
  1138. }
  1139. OSErr
  1140. CMacAsyncFile::WriteData(HXParamBlockRec* pb, BOOL ASYNC)
  1141. {
  1142.     m_pMutex->Lock();
  1143.     OSErr e = noErr;
  1144.     if(ASYNC)
  1145.     {
  1146. mAsyncQueue->AddTail(pb->entry);
  1147. mOutStandingCallbacks++;
  1148.     }
  1149.     e = PBWrite((ParmBlkPtr) pb, ASYNC);
  1150.     if(e != noErr && ASYNC && mOutStandingCallbacks > 0)
  1151.     {
  1152.         mAsyncQueue->RemoveTail();
  1153.         mOutStandingCallbacks--;
  1154.     }
  1155.     m_pMutex->Unlock();
  1156.     return e;
  1157. }
  1158. OSErr
  1159. CMacAsyncFile::SeekData(HXParamBlockRec* pb, BOOL ASYNC)
  1160. {
  1161.     m_pMutex->Lock();
  1162.     OSErr e = noErr;
  1163.     if(ASYNC)
  1164.     {
  1165.     mAsyncQueue->AddTail(pb->entry);
  1166.     mOutStandingCallbacks++;
  1167.     }
  1168.     e = PBSetFPos((ParmBlkPtr) pb, ASYNC);
  1169.     if (e == eofErr)
  1170.     {
  1171. DEBUGSTR("p File done in SeekData");
  1172. m_bFileDone = TRUE;
  1173. e = noErr;
  1174.     }
  1175.     if(e != noErr && ASYNC && mOutStandingCallbacks > 0)
  1176.     {
  1177.         mAsyncQueue->RemoveTail();
  1178. mOutStandingCallbacks--;
  1179.     }
  1180.     m_pMutex->Unlock();
  1181.     return e;
  1182. }
  1183. void
  1184. CMacAsyncFile::PendingAsyncSeekDone()
  1185. {
  1186.     AddRef();
  1187.     m_pMutex->Lock();
  1188.     HX_ASSERT(m_bSeekPending == TRUE);
  1189.     m_bSeekPending = FALSE;
  1190.      DEBUGSTR("p PendingAsyncSeekDone;g");
  1191.    // ? should check status
  1192.     m_pResponse->AsyncSeekDone(HXR_OK);
  1193.     m_pMutex->Unlock();
  1194.     Release();
  1195. }
  1196. void
  1197. CMacAsyncFile::AllPendingCallbacksDone()
  1198. {   
  1199.     DEBUGSTR("p AllPendingCallbacksDone;g");
  1200.     m_pMutex->Lock();
  1201.     
  1202.     HX_ASSERT(m_pPendingCallbackList->GetCount() == 0);
  1203.             
  1204.     if(m_bReadPending)
  1205.     {
  1206.         EnqueueAsyncBuffers();
  1207. ProcessPendingRead();
  1208.     }
  1209.     /* If there is still a pending read and no outstanding reads
  1210.      * issue one more read
  1211.      */
  1212.     if(m_bReadPending && mOutStandingCallbacks == 0)
  1213.     {
  1214.         DEBUGSTR("pm_bReadPending && mOutStandingCallbacks == 0;g");
  1215. ReadAsyncData(TRUE);
  1216.     }
  1217.     m_pMutex->Unlock();
  1218. }
  1219. void
  1220. CMacAsyncFile::ProcessPendingRead()
  1221. {
  1222.     AddRef();
  1223.     m_pMutex->Lock();
  1224.     
  1225.     ULONG32 totalinqueue = mReadQueue->GetQueuedItemCount();
  1226.     ULONG32 numberInPendingCallbackList = m_pPendingCallbackList->GetCount();
  1227.     if(m_bReadPending &&
  1228.        ((m_bFileDone && numberInPendingCallbackList == 0) ||
  1229.        (totalinqueue >= m_ulPendingReadCount)))
  1230.     {
  1231. m_bReadPending = FALSE;
  1232. if (totalinqueue == 0)
  1233. {
  1234.        DEBUGSTR("p AsyncReadDone FAIL;g");
  1235.       m_pResponse->AsyncReadDone(HXR_FAIL, NULL);
  1236. }
  1237. else
  1238. {
  1239.         UINT32 count = m_ulPendingReadCount;
  1240.     if (count > totalinqueue)
  1241.     {
  1242. count = totalinqueue;
  1243.     }
  1244.     IHXBuffer *pBuffer = new CHXBuffer;
  1245.     pBuffer->AddRef();
  1246.     pBuffer->SetSize(count);
  1247.     char *buf = (char*) pBuffer->GetBuffer();
  1248.     mFilePos += mReadQueue->DeQueue(buf, count);
  1249.     
  1250. #if defined(_DEBUG) && defined (_LOG_DATA)
  1251.        char str[255]; /* Flawfinder: ignore */
  1252.        ::sprintf(str, "AsyncReadDone: HXR_OK: %d;g", (int) count); /* Flawfinder: ignore */
  1253.         DEBUGSTR(c2pstr(str));
  1254. #endif     
  1255.     m_pResponse->AsyncReadDone(HXR_OK, pBuffer);
  1256.     pBuffer->Release();
  1257. }
  1258.     }
  1259.     m_pMutex->Unlock();
  1260.     Release();
  1261. }
  1262. HX_RESULT
  1263. CMacAsyncFile::SetAsyncResponse(CMacAsyncFileResponse * pResponse)
  1264. {
  1265.     if(!pResponse)
  1266.     {
  1267. return HXR_UNEXPECTED;
  1268.     }
  1269.     m_pMutex->Lock();
  1270.     m_pResponse = pResponse;
  1271.     m_pMutex->Unlock();
  1272.     return HXR_OK;
  1273. }