use std::io;
use bytes::Bytes;
use crate::{
Error, Result,
common::{Compression, Format},
disc,
read::DiscReader,
};
#[derive(Default, Debug, Clone)]
pub struct FormatOptions {
pub format: Format,
pub compression: Compression,
pub block_size: u32,
}
impl FormatOptions {
#[inline]
pub fn new(format: Format) -> FormatOptions {
FormatOptions {
format,
compression: format.default_compression(),
block_size: format.default_block_size(),
}
}
}
#[derive(Default, Debug, Clone)]
pub struct ProcessOptions {
#[cfg(feature = "threading")]
pub processor_threads: usize,
pub digest_crc32: bool,
pub digest_md5: bool,
pub digest_sha1: bool,
pub digest_xxh64: bool,
pub scrub: ScrubLevel,
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScrubLevel {
#[default]
None,
UpdatePartition,
}
pub type DataCallback<'a> = dyn FnMut(Bytes, u64, u64) -> io::Result<()> + 'a;
#[derive(Clone)]
#[repr(transparent)]
pub struct DiscWriter(Box<dyn disc::writer::DiscWriter>);
impl DiscWriter {
#[inline]
pub fn new(disc: DiscReader, options: &FormatOptions) -> Result<DiscWriter> {
let mut options = options.clone();
options.compression.validate_level()?;
let mut reader = disc.into_inner();
reader.reset();
let inner = match options.format {
Format::Iso => {
if options.compression != Compression::None {
return Err(Error::Other("ISO/GCM does not support compression".to_string()));
}
Box::new(reader)
}
Format::Ciso => crate::io::ciso::DiscWriterCISO::new(reader, &options)?,
#[cfg(feature = "compress-zlib")]
Format::Gcz => crate::io::gcz::DiscWriterGCZ::new(reader, &options)?,
Format::Tgc => crate::io::tgc::DiscWriterTGC::new(reader, &options)?,
Format::Wbfs => crate::io::wbfs::DiscWriterWBFS::new(reader, &options)?,
Format::Wia | Format::Rvz => crate::io::wia::DiscWriterWIA::new(reader, &options)?,
format => return Err(Error::Other(format!("Unsupported write format: {format}"))),
};
Ok(DiscWriter(inner))
}
#[inline]
pub fn process(
&self,
mut data_callback: impl FnMut(Bytes, u64, u64) -> io::Result<()>,
options: &ProcessOptions,
) -> Result<DiscFinalization> {
self.0.process(&mut data_callback, options)
}
#[inline]
pub fn progress_bound(&self) -> u64 { self.0.progress_bound() }
#[inline]
pub fn weight(&self) -> DiscWriterWeight { self.0.weight() }
}
#[derive(Default, Clone)]
pub struct DiscFinalization {
pub header: Bytes,
pub crc32: Option<u32>,
pub md5: Option<[u8; 16]>,
pub sha1: Option<[u8; 20]>,
pub xxh64: Option<u64>,
}
pub enum DiscWriterWeight {
Light,
Medium,
Heavy,
}