use std::fs;
use std::io::{BufReader, Read};
use std::io::{Seek, SeekFrom};
use std::mem;
use std::path::Path;
use crate::format::D88_Header;
use crate::disk::Disk;
use crate::sector::Sector;
#[derive(Default)]
#[allow(non_snake_case)]
pub struct D88FileIO {
pub reader: Option<BufReader<std::fs::File>>,
pub disk: Disk,
}
#[allow(non_snake_case)]
impl D88FileIO {
fn _open<P: AsRef<Path>>(path: P) -> Result<BufReader<std::fs::File>, ()> {
if let Ok(fh) = fs::File::open(path) {
Ok(BufReader::new(fh))
} else {
Err(())
}
}
fn _read_disk_parameter(reader: &mut BufReader<std::fs::File>) -> Result<Disk, ()> {
let mut disk = Disk::default();
if disk.preset(reader).is_ok() {
Ok(disk)
} else {
Err(())
}
}
pub fn open<P: AsRef<Path>>(path: P) -> Self {
if let Ok(mut reader) = D88FileIO::_open(path) {
if let Ok(disk_) = D88FileIO::_read_disk_parameter(&mut reader) {
return Self {
reader: Some(reader),
disk: disk_,
};
}
}
Self {
reader: None,
disk: Disk::default(),
}
}
pub fn is_open(&self) -> bool {
self.reader.is_some()
}
#[allow(clippy::result_unit_err)]
pub fn read_d88_header(
&mut self,
) -> Result<D88_Header, ()> {
let mut buf: [u8; mem::size_of::<D88_Header>()] = [0; mem::size_of::<D88_Header>()];
if let Some(ref mut reader) = self.reader {
if reader.seek(SeekFrom::Start(0)).is_err() {
return Err(());
}
if let Ok(read_size) = reader.read(&mut buf) {
if read_size != mem::size_of::<D88_Header>() {
return Err(());
}
unsafe {
return Ok(mem::transmute::<
[u8; mem::size_of::<D88_Header>()],
D88_Header,
>(buf));
}
}
}
Err(())
}
pub fn sector_sort(&mut self) {
for track in self.disk.track_tbl.iter_mut() {
track.sector_sort();
}
}
pub fn file_offset_sort(&mut self) {
for track in self.disk.track_tbl.iter_mut() {
track.file_offset_sort();
}
}
#[allow(clippy::result_unit_err)]
pub fn get_sector(&self, track: usize, side: usize, sector: usize) -> Result<&Sector, ()> {
if (track >= self.disk.track_tbl.len())
|| (side >= 2)
|| (sector >= self.disk.track_tbl[(track * 2) + side].sector_tbl.len())
{
return Err(());
}
Ok(&self.disk.track_tbl[(track * 2) + side].sector_tbl[sector])
}
}
#[cfg(test)]
mod test {
use crate::fileio::D88FileIO;
#[test]
fn test_read_d88_header_disk_name() {
let mut d88fileio = D88FileIO::open("../../sample/HuBASIC_Format_2D.d88");
if let Ok(hdr) = d88fileio.read_d88_header() {
assert_eq!(
hdr.disk_name,
[
0x62, 0x79, 0x5f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x4f, 0x52, 0x59,
0x5a, 0x41, 0x50, 0x41
]
);
}
}
#[test]
fn test_read_d88_header_write_protect() {
let mut d88fileio = D88FileIO::open("../../sample/HuBASIC_Format_2D.d88");
if let Ok(hdr) = d88fileio.read_d88_header() {
assert_eq!(hdr.write_protect, 0x00); } else {
assert!(false);
}
}
#[test]
fn test_read_d88_header_disk_type() {
let mut d88fileio = D88FileIO::open("../../sample/HuBASIC_Format_2D.d88");
if let Ok(hdr) = d88fileio.read_d88_header() {
assert_eq!(hdr.disk_type, 0x00); } else {
assert!(false);
}
}
#[test]
fn test_read_d88_header_disk_size() {
let mut d88fileio = D88FileIO::open("../../sample/HuBASIC_Format_2D.d88");
if let Ok(hdr) = d88fileio.read_d88_header() {
assert_eq!(hdr.disk_size, 348848); } else {
assert!(false);
}
}
}