pub mod dos33;
pub mod prodos;
pub mod applesoft;
pub mod integer;
pub mod merlin;
pub mod walker;
pub mod disk_base;
pub mod img_do;
pub mod img_po;
pub mod img_woz;
pub mod img_woz1;
pub mod img_woz2;
pub mod disk525;
use crate::disk_base::{DiskImage,A2Disk};
use std::io::Read;
use std::fmt::Write;
use log::{info};
pub fn update_img_and_save(img: &mut Box<dyn DiskImage>,disk: &Box<dyn A2Disk>,img_path: &str) -> Result<(),Box<dyn std::error::Error>> {
let temp_po = match disk.get_ordering() {
disk_base::DiskImageType::DO => {
let temp_do = img_do::DO::from_bytes(&disk.to_img()).expect("unexpected file system metrics");
temp_do.to_po().expect("unexpected file system metrics")
},
disk_base::DiskImageType::PO => disk.to_img(),
_ => panic!("unexpected ordering in file system layer")
};
match img.update_from_po(&temp_po) {
Ok(()) => {
std::fs::write(img_path,img.to_bytes()).expect("could not write disk image to disk");
Ok(())
},
Err(e) => Err(e)
}
}
fn try_img(img: &impl DiskImage) -> Option<Box<dyn A2Disk>> {
if let Ok(bytestream) = img.to_do() {
if let Some(disk) = dos33::Disk::from_img(&bytestream) {
info!("identified DOS 3.3 file system");
return Some(Box::new(disk));
}
}
if let Ok(bytestream) = img.to_po() {
if let Some(disk) = prodos::Disk::from_img(&bytestream) {
info!("identified ProDOS file system");
return Some(Box::new(disk));
}
}
return None;
}
pub fn create_img_and_disk_from_bytestream(disk_img_data: &Vec<u8>) -> Option<(Box<dyn DiskImage>,Box<dyn A2Disk>)> {
if let Some(img) = img_woz1::Woz1::from_bytes(disk_img_data) {
info!("identified woz1 image");
if let Some(disk) = try_img(&img) {
return Some((Box::new(img),disk));
}
}
if let Some(img) = img_woz2::Woz2::from_bytes(disk_img_data) {
info!("identified woz2 image");
if let Some(disk) = try_img(&img) {
return Some((Box::new(img),disk));
}
}
if let Some(img) = img_do::DO::from_bytes(disk_img_data) {
info!("Possible DO image");
if let Some(disk) = try_img(&img) {
return Some((Box::new(img),disk));
}
}
if let Some(img) = img_po::PO::from_bytes(disk_img_data) {
info!("Possible PO image");
if let Some(disk) = try_img(&img) {
return Some((Box::new(img),disk));
}
}
return None;
}
pub fn create_img_from_bytestream(disk_img_data: &Vec<u8>) -> Option<Box<dyn DiskImage>> {
if let Some(img) = img_woz1::Woz1::from_bytes(disk_img_data) {
info!("identified woz1 image");
return Some(Box::new(img));
}
if let Some(img) = img_woz2::Woz2::from_bytes(disk_img_data) {
info!("identified woz2 image");
return Some(Box::new(img));
}
if let Some(img) = img_do::DO::from_bytes(disk_img_data) {
info!("Possible DO image");
return Some(Box::new(img));
}
if let Some(img) = img_po::PO::from_bytes(disk_img_data) {
info!("Possible PO image");
return Some(Box::new(img));
}
return None;
}
pub fn create_img_from_file(img_path: &str) -> Option<Box<dyn DiskImage>> {
let disk_img_data = std::fs::read(img_path).expect("failed to read file");
return create_img_from_bytestream(&disk_img_data);
}
pub fn create_img_and_disk_from_file(img_path: &str) -> Option<(Box<dyn DiskImage>,Box<dyn A2Disk>)> {
let disk_img_data = std::fs::read(img_path).expect("failed to read file");
return create_img_and_disk_from_bytestream(&disk_img_data);
}
#[deprecated(since="0.2.0", note="will be modified to return an Option")]
pub fn create_disk_from_bytestream(disk_img_data: &Vec<u8>) -> Box<dyn A2Disk> {
if let Some((_img,disk)) = create_img_and_disk_from_bytestream(disk_img_data) {
return disk;
}
panic!("could not interpret disk image data");
}
#[deprecated(since="0.2.0", note="will be modified to return an Option")]
pub fn create_disk_from_stdin() -> Box<dyn A2Disk> {
let mut disk_img_data = Vec::new();
std::io::stdin().read_to_end(&mut disk_img_data).expect("failed to read input stream");
return create_disk_from_bytestream(&disk_img_data);
}
#[deprecated(since="0.2.0", note="will be modified to return an Option")]
pub fn create_disk_from_file(img_path: &str) -> Box<dyn A2Disk> {
let disk_img_data = std::fs::read(img_path).expect("failed to read file");
return create_disk_from_bytestream(&disk_img_data);
}
pub fn display_chunk(start_addr: u16,chunk: &Vec<u8>) {
let mut slice_start = 0;
loop {
let row_label = start_addr as usize + slice_start;
let mut slice_end = slice_start + 16;
if slice_end > chunk.len() {
slice_end = chunk.len();
}
let slice = chunk[slice_start..slice_end].to_vec();
let txt: Vec<u8> = slice.iter().map(|c| match *c {
x if x<32 => '.' as u8,
x if x<127 => x,
_ => '.' as u8
}).collect();
let neg_txt: Vec<u8> = slice.iter().map(|c| match *c {
x if x>=160 && x<255 => x - 128,
_ => 46
}).collect();
print!("{:04X} : ",row_label);
for byte in slice {
print!("{:02X} ",byte);
}
for _blank in slice_end..slice_start+16 {
print!(" ");
}
print!("|+| {} ",String::from_utf8_lossy(&txt));
for _blank in slice_end..slice_start+16 {
print!(" ");
}
println!("|-| {}",String::from_utf8_lossy(&neg_txt));
slice_start += 16;
if slice_end==chunk.len() {
break;
}
}
}
pub fn display_track(start_addr: u16,trk: &Vec<u8>) {
let mut slice_start = 0;
let mut addr_count = 0;
let mut err_count = 0;
loop {
let row_label = start_addr as usize + slice_start;
let mut slice_end = slice_start + 16;
if slice_end > trk.len() {
slice_end = trk.len();
}
let mut mnemonics = String::new();
for i in slice_start..slice_end {
let bak = match i {
x if x>0 => trk[x-1],
_ => 0
};
let fwd = match i {
x if x+1<trk.len() => trk[x+1],
_ => 0
};
if !disk525::DISK_BYTES_62.contains(&trk[i]) && trk[i]!=0xaa && trk[i]!=0xd5 {
mnemonics += "?";
err_count += 1;
} else if addr_count>0 {
if addr_count%2==1 {
write!(&mut mnemonics,"{:X}",disk525::decode_44([trk[i],fwd]) >> 4).unwrap();
} else {
write!(&mut mnemonics,"{:X}",disk525::decode_44([bak,trk[i]]) & 0x0f).unwrap();
}
addr_count += 1;
} else {
mnemonics += match (bak,trk[i],fwd) {
(0xff,0xff,_) => ">",
(_,0xff,0xff) => ">",
(_,0xd5,0xaa) => "(",
(0xd5,0xaa,0x96) => "A",
(0xaa,0x96,_) => {addr_count=1;":"},
(0xd5,0xaa,0xad) => "D",
(0xaa,0xad,_) => ":",
(_,0xde,0xaa) => ":",
(0xde,0xaa,0xeb) => ":",
(0xaa,0xeb,_) => ")",
(_,0xd5,_) => "R",
(_,0xaa,_) => "R",
_ => "."
};
}
if addr_count==9 {
addr_count = 0;
}
}
for _i in mnemonics.len()..16 {
mnemonics += " ";
}
print!("{:04X} : ",row_label);
for byte in trk[slice_start..slice_end].to_vec() {
print!("{:02X} ",byte);
}
for _blank in slice_end..slice_start+16 {
print!(" ");
}
println!("|{}|",mnemonics);
slice_start += 16;
if slice_end==trk.len() {
break;
}
}
if err_count > 0 {
println!();
println!("Encountered {} invalid bytes",err_count);
}
}