use super::*;
use crate::io_buffers::IoBuffer;
use miniz_oxide::inflate::core::{decompress as inflate, DecompressorOxide};
use miniz_oxide::inflate::TINFLStatus;
impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F> {
pub(super) async fn read_compressed_cluster(
&self,
buf: &mut [u8],
compressed_offset: HostOffset,
compressed_length: u64,
) -> io::Result<()> {
debug_assert!(buf.len() == self.header.cluster_size());
let storage = self.storage();
let compressed_length = compressed_length.try_into().map_err(io::Error::other)?;
let mut compressed_buf = IoBuffer::new(compressed_length, storage.mem_align())?;
storage
.read(&mut compressed_buf, compressed_offset.0)
.await?;
let mut dec_ox = DecompressorOxide::new();
let (status, _read, written) =
inflate(&mut dec_ox, compressed_buf.as_ref().into_slice(), buf, 0, 0);
if status != TINFLStatus::Done && status != TINFLStatus::HasMoreOutput {
return Err(io::Error::other(format!(
"Failed to decompress cluster (host offset {compressed_offset}+{compressed_length}): {status:?}",
)));
}
if written < buf.len() {
return Err(io::Error::other(format!(
"Failed to decompress cluster (host offset {compressed_offset}+{compressed_length}): Decompressed {written} bytes, expected {}",
buf.len(),
)));
}
Ok(())
}
}