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; }
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; }