use crate::args::image::{ImageConvertArgs, ImageDeinterleaveArgs, ImageSwapBytesArgs};
use onerom_cli::{Error, Options};
use onerom_gen::{FileFormat, SizeHandling, Transform, decode_ihex, encode_ihex};
fn transform_file(
options: &Options,
input: &str,
output: &str,
transform: &Transform,
what: &str,
) -> Result<(), Error> {
if options.verbose {
println!("Reading ROM image from {input} ...");
}
let data = std::fs::read(input).map_err(|e| Error::io(input, e))?;
let transformed = transform
.apply(&data, &SizeHandling::None, 0)
.map_err(|e| Error::ImageTransform(input.to_string(), e.to_string()))?
.data;
std::fs::write(output, &transformed).map_err(|e| Error::io(output, e))?;
if options.verbose {
println!("Wrote {} bytes to {output} {what}", transformed.len());
} else {
println!("Written to {output}");
}
Ok(())
}
pub async fn cmd_swap_bytes(options: &Options, args: &ImageSwapBytesArgs) -> Result<(), Error> {
let len = std::fs::metadata(&args.input)
.map_err(|e| Error::io(&args.input, e))?
.len() as usize;
if !len.is_multiple_of(2) {
return Err(Error::OddLengthImage(args.input.clone(), len));
}
transform_file(
options,
&args.input,
&args.output,
&Transform::SwapBytes,
"with byte pairs swapped",
)
}
pub async fn cmd_deinterleave(
options: &Options,
args: &ImageDeinterleaveArgs,
) -> Result<(), Error> {
let transform = Transform::Deinterleave {
offset: args.offset,
stride: args.stride,
bytes: args.bytes,
};
transform.validate().map_err(|e| {
Error::InvalidArgument("--stride/--offset/--bytes".to_string(), e.to_string())
})?;
let what = format!(
"keeping lane {} of {} ({} byte{} per lane)",
args.offset,
args.stride,
args.bytes,
if args.bytes == 1 { "" } else { "s" }
);
transform_file(options, &args.input, &args.output, &transform, &what)
}
pub async fn cmd_convert(options: &Options, args: &ImageConvertArgs) -> Result<(), Error> {
let (from, to) = (args.from, args.to);
let load_address = args.load_address.unwrap_or_default();
if from == FileFormat::Binary && to == FileFormat::Binary && !load_address.is_zero() {
return Err(Error::InvalidArgument(
"--load-address".to_string(),
"load address is only valid when converting to or from ihex".to_string(),
));
}
if options.verbose {
println!("Reading {from} image from {} ...", args.input);
}
let data = std::fs::read(&args.input).map_err(|e| Error::io(&args.input, e))?;
let binary = match from {
FileFormat::Binary => data,
FileFormat::IntelHex => decode_ihex(&data, load_address.0)
.map_err(|e| Error::IhexDecode(args.input.clone(), e.to_string()))?,
};
let output_bytes = match to {
FileFormat::Binary => binary,
FileFormat::IntelHex => encode_ihex(&binary, load_address.0).into_bytes(),
};
std::fs::write(&args.output, &output_bytes).map_err(|e| Error::io(&args.output, e))?;
if options.verbose {
println!(
"Wrote {} bytes to {} ({from} -> {to})",
output_bytes.len(),
args.output
);
} else {
println!("Written to {}", args.output);
}
Ok(())
}