home *** CD-ROM | disk | FTP | other *** search
/ Speccy ClassiX 1998 / Speccy ClassiX 98.iso / amiga_system / the_aminet / dev / c / asyncio.lha / AsyncIO / src / SeekAsync.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-11  |  6.1 KB  |  204 lines

  1. #include "async.h"
  2.  
  3. LibCall LONG
  4. SeekAsync( _REG( a0 ) AsyncFile *file, _REG( d0 ) LONG position, _REG( d1 ) SeekModes mode )
  5. {
  6. #ifdef ASIO_NOEXTERNALS
  7.     struct DosLibrary    *DOSBase;
  8. #endif
  9.     LONG    current, target;
  10.     LONG    minBuf, maxBuf;
  11.     LONG    bytesArrived;
  12.     LONG    diff;
  13.     LONG    filePos;
  14.     LONG    roundTarget;
  15.     D_S( struct FileInfoBlock, fib );
  16.  
  17. #ifdef ASIO_NOEXTERNALS
  18.     DOSBase = file->af_DOSBase;
  19. #endif
  20.  
  21.     bytesArrived = AS_WaitPacket( file );
  22.  
  23.     if( bytesArrived < 0 )
  24.     {
  25.         return( -1 );
  26.     }
  27.  
  28.     if( file->af_ReadMode )
  29.     {
  30.         /* figure out what the actual file position is */
  31.         filePos = Seek( file->af_File, 0, OFFSET_CURRENT );
  32.  
  33.         if( filePos < 0 )
  34.         {
  35.             AS_RecordSyncFailure( file );
  36.             return( -1 );
  37.         }
  38.  
  39.         /* figure out what the caller's file position is */
  40.         current = filePos - ( file->af_BytesLeft + bytesArrived ) + file->af_SeekOffset;
  41.         file->af_SeekOffset = 0;
  42.  
  43.         /* figure out the absolute offset within the file where we must seek to */
  44.         if( mode == MODE_CURRENT )
  45.         {
  46.             target = current + position;
  47.         }
  48.         else if( mode == MODE_START )
  49.         {
  50.             target = position;
  51.         }
  52.         else /* if( mode == MODE_END ) */
  53.         {
  54.             if( !ExamineFH( file->af_File, fib ) )
  55.             {
  56.                 AS_RecordSyncFailure( file );
  57.                 return( -1 );
  58.             }
  59.  
  60.             target = fib->fib_Size + position;
  61.         }
  62.  
  63.         /* figure out what range of the file is currently in our buffers */
  64.         minBuf = current - ( LONG ) ( file->af_Offset - file->af_Buffers[ file->af_CurrentBuf ] );
  65.         maxBuf = current + file->af_BytesLeft + bytesArrived;  /* WARNING: this is one too big */
  66.  
  67.         if( file->af_Received > 1 )
  68.         {
  69.             /* MH: Bugfix. Prevents some seeks from being slow (some buffers
  70.              * would be read twice, since the code would think the data
  71.              * wasn't in our buffers when it really was).
  72.              */
  73.             minBuf -= file->af_BufferSize;
  74.         }
  75.  
  76.         diff = target - current;
  77.  
  78.         if( ( target < minBuf ) || ( target >= maxBuf ) )
  79.         {
  80.             /* the target seek location isn't currently in our buffers, so
  81.              * move the actual file pointer to the desired location, and then
  82.              * restart the async read thing...
  83.              */
  84.  
  85.             /* this is to keep our file reading block-aligned on the device.
  86.              * block-aligned reads are generally quite a bit faster, so it is
  87.              * worth the trouble to keep things aligned
  88.              */
  89.             roundTarget = ( target / file->af_BlockSize ) * file->af_BlockSize;
  90.  
  91.             if( Seek( file->af_File, roundTarget - filePos, OFFSET_CURRENT ) < 0 )
  92.             {
  93.                 AS_RecordSyncFailure( file );
  94.                 return( -1 );
  95.             }
  96.  
  97.             AS_SendPacket( file, file->af_Buffers[ 0 ] );
  98.  
  99.             file->af_SeekOffset    = target - roundTarget;
  100.             file->af_BytesLeft    = 0;
  101.             file->af_CurrentBuf    = 0;
  102.             /* MH: Note: af_Offset need not be set here. Since af_BytesLeft == 0,
  103.              * ReadAsync will handle everything correctly.
  104.              */
  105.             /* MH: Both buffers are dropped, and we must keep track of that. */
  106.             file->af_Received    = 0;
  107.         }
  108.         else if( ( target < current ) || ( diff <= file->af_BytesLeft ) )
  109.         {
  110.             /* one of the two following things is true:
  111.              *
  112.              * 1. The target seek location is within the current read buffer,
  113.              * but before the current location within the buffer. Move back
  114.              * within the buffer and pretend we never got the pending packet,
  115.              * just to make life easier, and faster, in the read routine.
  116.              *
  117.              * 2. The target seek location is ahead within the current
  118.              * read buffer. Advance to that location. As above, pretend to
  119.              * have never received the pending packet.
  120.              */
  121.  
  122.             AS_RequeuePacket( file );
  123.  
  124.             file->af_BytesLeft    -= diff;
  125.             file->af_Offset        += diff;
  126.         }
  127.         else
  128.         {
  129.             /* at this point, we know the target seek location is within
  130.              * the buffer filled in by the packet that we just received
  131.              * at the start of this function. Throw away all the bytes in the
  132.              * current buffer, send a packet out to get the async thing going
  133.              * again, readjust buffer pointers to the seek location, and return
  134.              * with a grin on your face... :-)
  135.              */
  136.  
  137.             AS_SendPacket( file, file->af_Buffers[ 1 - file->af_CurrentBuf ] );
  138.  
  139.             diff -= file->af_BytesLeft;
  140.             file->af_Offset        = file->af_Buffers[ file->af_CurrentBuf ] + diff;
  141.             file->af_BytesLeft    = bytesArrived - diff;
  142.             /* MH: This "buffer switching" is important to do. It wasn't done!
  143.              * This explains strange read "errors" one could encounter now
  144.              * and then.
  145.              */
  146.             file->af_CurrentBuf    = 1 - file->af_CurrentBuf;
  147.         }
  148.     }
  149.     else
  150.     {
  151.         /* flush the buffers */
  152.         if( file->af_BufferSize > file->af_BytesLeft )
  153.         {
  154.             if( Write(
  155.                 file->af_File,
  156.                 file->af_Buffers[ file->af_CurrentBuf ],
  157.                 file->af_BufferSize - file->af_BytesLeft ) < 0 )
  158.             {
  159.                 AS_RecordSyncFailure( file );
  160.                 return( -1 );
  161.             }
  162.         }
  163.  
  164.         /* this will unfortunately generally result in non block-aligned file
  165.          * access. We could be sneaky and try to resync our file pos at a
  166.          * later time, but we won't bother. Seeking in write-only files is
  167.          * relatively rare (except when writing IFF files with unknown chunk
  168.          * sizes, where the chunk size has to be written after the chunk data)
  169.          */
  170.  
  171.         /* MH: Ideas on how to improve the above (not tested, since I don't need
  172.          * the SeekAsync for writing in any of my programs at the moment! ;):
  173.          *
  174.          * Add a new field to the AsyncFile struct. af_WriteOffset or something
  175.          * like that (maybe af_SeekOffset can be used). Like in the read case, we
  176.          * calculate a roundTarget, but we don't seek to that (but rather to the
  177.          * "absolute" position), and save the difference in the struct. af_BytesLeft
  178.          * and af_Offset are adjusted to point into the "middle" of the buffer,
  179.          * where the write will occur. WriteAsync then needs some minor changes.
  180.          * Instead of simply writing the buffer from the start, we add the offset
  181.          * (saved above) to the  buffer base, and write the partial buffer. The
  182.          * offset is then cleared. Voila: The file still block-aligned, at the price
  183.          * of some non-optimal buffer usage.
  184.          *
  185.          * Problem: As it is now, Arg3 in the packet is always set to the buffer size. With
  186.          * the above fix, this would have to be updated for each SendPacket.
  187.          */
  188.  
  189.         current = Seek( file->af_File, position, mode );
  190.  
  191.         if( current < 0 )
  192.         {
  193.             AS_RecordSyncFailure( file );
  194.             return( -1 );
  195.         }
  196.  
  197.         file->af_BytesLeft    = file->af_BufferSize;
  198.         file->af_CurrentBuf    = 0;
  199.         file->af_Offset        = file->af_Buffers[ 0 ];
  200.     }
  201.  
  202.     return( current );
  203. }
  204.