nod-rs/nod/src/io/iso.rs

98 lines
2.8 KiB
Rust

use std::{
io,
io::{BufRead, Read, Seek, SeekFrom},
};
use crate::{
common::Format,
disc::{
reader::DiscReader,
writer::{DataCallback, DiscWriter},
SECTOR_SIZE,
},
io::block::{Block, BlockKind, BlockReader},
read::{DiscMeta, DiscStream},
util::digest::DigestManager,
write::{DiscFinalization, DiscWriterWeight, ProcessOptions},
Result, ResultContext,
};
#[derive(Clone)]
pub struct BlockReaderISO {
inner: Box<dyn DiscStream>,
disc_size: u64,
}
impl BlockReaderISO {
pub fn new(mut inner: Box<dyn DiscStream>) -> Result<Box<Self>> {
let disc_size = inner.seek(SeekFrom::End(0)).context("Determining stream length")?;
Ok(Box::new(Self { inner, disc_size }))
}
}
impl BlockReader for BlockReaderISO {
fn read_block(&mut self, out: &mut [u8], sector: u32) -> io::Result<Block> {
let pos = sector as u64 * SECTOR_SIZE as u64;
if pos >= self.disc_size {
// End of file
return Ok(Block::sector(sector, BlockKind::None));
}
self.inner.seek(SeekFrom::Start(pos))?;
if pos + SECTOR_SIZE as u64 > self.disc_size {
// If the last block is not a full sector, fill the rest with zeroes
let read = (self.disc_size - pos) as usize;
self.inner.read_exact(&mut out[..read])?;
out[read..].fill(0);
} else {
self.inner.read_exact(out)?;
}
Ok(Block::sector(sector, BlockKind::Raw))
}
fn block_size(&self) -> u32 { SECTOR_SIZE as u32 }
fn meta(&self) -> DiscMeta {
DiscMeta {
format: Format::Iso,
lossless: true,
disc_size: Some(self.disc_size),
..Default::default()
}
}
}
impl DiscWriter for DiscReader {
fn process(
&self,
data_callback: &mut DataCallback,
options: &ProcessOptions,
) -> Result<DiscFinalization> {
let mut reader = self.clone();
let digest = DigestManager::new(options);
loop {
let pos = reader.position();
let data = reader
.fill_buf_internal()
.with_context(|| format!("Reading disc data at offset {pos}"))?;
let len = data.len();
if len == 0 {
break;
}
// Update hashers
digest.send(data.clone());
data_callback(data, pos + len as u64, reader.disc_size())
.context("Failed to write disc data")?;
reader.consume(len);
}
let mut finalization = DiscFinalization::default();
finalization.apply_digests(&digest.finish());
Ok(finalization)
}
fn progress_bound(&self) -> u64 { self.disc_size() }
fn weight(&self) -> DiscWriterWeight { DiscWriterWeight::Light }
}