size_t VSICachedFile::Read( void * pBuffer, size_t nSize, size_t nCount )

{
    if( nOffset >= nFileSize )
        return 0;

/* ==================================================================== */
/*      Make sure the cache is loaded for the whole request region.     */
/* ==================================================================== */
    size_t nStartBlock = (size_t) (nOffset / CHUNK_SIZE);
    size_t nEndBlock = (size_t) ((nOffset + nSize * nCount - 1) / CHUNK_SIZE);
    
    for( size_t iBlock = nStartBlock; iBlock <= nEndBlock; iBlock++ )
    {
        if( apoCache.size() <= iBlock || apoCache[iBlock] == NULL )
        {
            size_t nBlocksToLoad = 1;
            while( iBlock + nBlocksToLoad <= nEndBlock
                   && (apoCache.size() <= iBlock+nBlocksToLoad 
                       || apoCache[iBlock+nBlocksToLoad] == NULL) )
                nBlocksToLoad++;

            LoadBlocks( iBlock, nBlocksToLoad, pBuffer, nSize * nCount );
        }
    }
    
/* ==================================================================== */
/*      Copy data into the target buffer to the extent possible.        */
/* ==================================================================== */
    size_t nAmountCopied = 0;

    while( nAmountCopied < nSize * nCount )
    {
        size_t iBlock = (size_t) ((nOffset + nAmountCopied) / CHUNK_SIZE);
        size_t nThisCopy;
        VSICacheChunk *poBlock = apoCache[iBlock];

        nThisCopy = (size_t)
            ((iBlock * CHUNK_SIZE + poBlock->nDataFilled) 
             - nAmountCopied - nOffset);
        
        if( nThisCopy > nSize * nCount - nAmountCopied )
            nThisCopy = nSize * nCount - nAmountCopied;

        if( nThisCopy == 0 )
            break;

        memcpy( ((GByte *) pBuffer) + nAmountCopied,
                poBlock->abyData 
                + (nOffset + nAmountCopied) - iBlock * CHUNK_SIZE, 
                nThisCopy );

        nAmountCopied += nThisCopy;
    }
    
    nOffset += nAmountCopied;

/* -------------------------------------------------------------------- */
/*      Ensure the cache is reduced to our limit.                       */
/* -------------------------------------------------------------------- */
    while( nCacheUsed > nCacheMax )
        FlushLRU();
        
    return nAmountCopied / nSize;
}
Beispiel #2
0
size_t VSICachedFile::Read( void * pBuffer, size_t nSize, size_t nCount )

{
    if( nOffset >= nFileSize )
    {
        bEOF = TRUE;
        return 0;
    }

/* ==================================================================== */
/*      Make sure the cache is loaded for the whole request region.     */
/* ==================================================================== */
    vsi_l_offset nStartBlock = nOffset / nChunkSize;
    vsi_l_offset nEndBlock = (nOffset + nSize * nCount - 1) / nChunkSize;

    for( vsi_l_offset iBlock = nStartBlock; iBlock <= nEndBlock; iBlock++ )
    {
        if( apoCache.size() <= iBlock || apoCache[iBlock] == NULL )
        {
            size_t nBlocksToLoad = 1;
            while( iBlock + nBlocksToLoad <= nEndBlock
                   && (apoCache.size() <= iBlock+nBlocksToLoad 
                       || apoCache[iBlock+nBlocksToLoad] == NULL) )
                nBlocksToLoad++;

            LoadBlocks( iBlock, nBlocksToLoad, pBuffer, nSize * nCount );
        }
    }
    
/* ==================================================================== */
/*      Copy data into the target buffer to the extent possible.        */
/* ==================================================================== */
    size_t nAmountCopied = 0;

    while( nAmountCopied < nSize * nCount )
    {
        vsi_l_offset iBlock = (nOffset + nAmountCopied) / nChunkSize;
        size_t nThisCopy;
        VSICacheChunk *poBlock = apoCache[iBlock];
        if( poBlock == NULL )
        {
            /* We can reach that point when the amount to read exceeds */
            /* the cache size */
            LoadBlocks( iBlock, 1, ((GByte *) pBuffer) + nAmountCopied,
                        MIN(nSize * nCount - nAmountCopied, nChunkSize) );
            poBlock = apoCache[iBlock];
            CPLAssert(poBlock != NULL);
        }

        vsi_l_offset nStartOffset = (vsi_l_offset)iBlock * nChunkSize;
        nThisCopy = (size_t)
            ((nStartOffset + poBlock->nDataFilled) 
             - nAmountCopied - nOffset);
        
        if( nThisCopy > nSize * nCount - nAmountCopied )
            nThisCopy = nSize * nCount - nAmountCopied;

        if( nThisCopy == 0 )
            break;

        memcpy( ((GByte *) pBuffer) + nAmountCopied,
                poBlock->pabyData 
                + (nOffset + nAmountCopied) - nStartOffset, 
                nThisCopy );

        nAmountCopied += nThisCopy;
    }
    
    nOffset += nAmountCopied;

/* -------------------------------------------------------------------- */
/*      Ensure the cache is reduced to our limit.                       */
/* -------------------------------------------------------------------- */
    while( nCacheUsed > nCacheMax )
        FlushLRU();

    size_t nRet = nAmountCopied / nSize;
    if (nRet != nCount)
        bEOF = TRUE;
    return nRet;
}