bool SectorReader::Read(u64 offset, u64 size, u8* out_ptr) { u64 startingBlock = offset / m_blocksize; u64 remain = size; int positionInBlock = (int)(offset % m_blocksize); u64 block = startingBlock; while (remain > 0) { // Check if we are ready to do a large block read. > instead of >= so we don't bother if remain is only one block. if (positionInBlock == 0 && remain > (u64)m_blocksize) { u64 num_blocks = remain / m_blocksize; ReadMultipleAlignedBlocks(block, num_blocks, out_ptr); block += num_blocks; out_ptr += num_blocks * m_blocksize; remain -= num_blocks * m_blocksize; continue; } u32 toCopy = m_blocksize - positionInBlock; if (toCopy >= remain) { const u8* data = GetBlockData(block); if (!data) return false; // Yay, we are done! memcpy(out_ptr, data + positionInBlock, (size_t)remain); return true; } else { const u8* data = GetBlockData(block); if (!data) return false; memcpy(out_ptr, data + positionInBlock, toCopy); out_ptr += toCopy; remain -= toCopy; positionInBlock = 0; block++; } } return true; }
u32 SectorReader::ReadChunk(u8* buffer, u64 chunk_num) { u64 block_num = chunk_num * m_chunk_blocks; u32 cnt_blocks = m_chunk_blocks; // If we are reading the end of a disk, there may not be enough blocks to // read a whole chunk. We need to clamp down in that case. u64 end_block = (GetDataSize() + m_block_size - 1) / m_block_size; if (end_block) cnt_blocks = static_cast<u32>(std::min<u64>(m_chunk_blocks, end_block - block_num)); if (ReadMultipleAlignedBlocks(block_num, cnt_blocks, buffer)) { if (cnt_blocks < m_chunk_blocks) { std::fill(buffer + cnt_blocks * m_block_size, buffer + m_chunk_blocks * m_block_size, 0u); } return cnt_blocks; } // end_block may be zero on real disks if we fail to get the media size. // We have to fallback to probing the disk instead. if (!end_block) { for (u32 i = 0; i < cnt_blocks; ++i) { if (!GetBlock(block_num + i, buffer)) { std::fill(buffer, buffer + (cnt_blocks - i) * m_block_size, 0u); return i; } buffer += m_block_size; } return cnt_blocks; } return 0; }