use super::ReadSeek;
use async_std::{
io::{prelude::SeekExt, ReadExt},
sync::{Mutex, MutexGuard},
};
use hff_core::{
byteorder::ReadBytesExt, ByteOrder, Chunk, ChunkCache, ContentInfo, Ecc, Endian, Error, Header,
Result, Table, Version, BE, LE,
};
use std::mem::size_of;
pub struct AsyncStdReader {
source: Mutex<Box<dyn ReadSeek>>,
}
impl std::fmt::Debug for AsyncStdReader {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "AsyncStdReader")
}
}
impl AsyncStdReader {
pub fn new(source: impl ReadSeek + 'static) -> Self {
Self {
source: Mutex::new(Box::new(source)),
}
}
pub async fn read(&self, content: &dyn ContentInfo) -> Result<Vec<u8>> {
let mut source = self.source.lock().await;
source
.seek(std::io::SeekFrom::Start(content.offset()))
.await?;
let mut result = vec![0; content.len() as usize];
source.read_exact(result.as_mut_slice()).await?;
Ok(result)
}
pub async fn reader(
&self,
content: impl ContentInfo,
) -> Result<MutexGuard<'_, Box<dyn ReadSeek>>> {
let mut source = self.source.lock().await;
source
.seek(std::io::SeekFrom::Start(content.offset()))
.await?;
Ok(source)
}
pub(super) async fn read_header(
reader: &mut (dyn async_std::io::Read + std::marker::Unpin),
) -> Result<Header> {
let mut header = [0_u8; Header::SIZE];
reader.read_exact(&mut header).await?;
let reader: &mut dyn std::io::Read = &mut header.as_slice();
let magic = reader.read_u64::<LE>()?;
match Ecc::HFF_MAGIC.endian(magic.into()) {
Some(endian) => match endian {
Endian::Little => Ok(Header::with(
magic.into(),
Version::read::<LE>(reader)?,
reader.read_u32::<LE>()?,
Ecc::read::<LE>(reader)?,
reader.read_u32::<LE>()?,
reader.read_u32::<LE>()?,
)),
Endian::Big => Ok(Header::with(
magic.into(),
Version::read::<BE>(reader)?,
reader.read_u32::<BE>()?,
Ecc::read::<BE>(reader)?,
reader.read_u32::<BE>()?,
reader.read_u32::<BE>()?,
)),
},
None => Err(Error::Invalid("Not an HFF file.".into())),
}
}
pub(super) async fn read_tables<E: ByteOrder>(
reader: &mut (dyn async_std::io::Read + std::marker::Unpin),
count: u32,
) -> Result<Vec<Table>> {
if count > 0 {
let mut buffer = vec![0; count as usize * std::mem::size_of::<Table>()];
reader.read_exact(&mut buffer.as_mut_slice()).await?;
let mut tables = vec![];
let reader: &mut dyn std::io::Read = &mut buffer.as_slice();
for _ in 0..count {
let table = Table::read::<E>(reader)?;
tables.push(table);
}
Ok(tables)
} else {
Ok(vec![])
}
}
pub(super) async fn read_chunks<E: ByteOrder>(
reader: &mut (dyn async_std::io::Read + std::marker::Unpin),
count: u32,
) -> Result<Vec<Chunk>> {
if count > 0 {
let mut buffer = vec![0; count as usize * std::mem::size_of::<Chunk>()];
reader.read_exact(&mut buffer.as_mut_slice()).await?;
let mut chunks = vec![];
let reader: &mut dyn std::io::Read = &mut buffer.as_slice();
for _ in 0..count {
let chunk = Chunk::read::<E>(reader)?;
chunks.push(chunk);
}
Ok(chunks)
} else {
Ok(vec![])
}
}
pub(super) async fn read_body(
reader: &mut (dyn async_std::io::Read + std::marker::Unpin),
tables: usize,
chunks: usize,
) -> Result<ChunkCache> {
let mut buffer = vec![];
reader.read_to_end(&mut buffer).await?;
let offset = Header::SIZE + size_of::<Table>() * tables + size_of::<Chunk>() * chunks;
Ok(ChunkCache::new(offset, buffer))
}
}