use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::string::ToString;
use cpclib_common::bitflags::bitflags;
use cpclib_common::itertools::zip;
use delegate::delegate;
use getset::Getters;
use crate::amsdos::{AmsdosError, AmsdosFile};
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
pub fn convert_real_sector_size_to_fdc_sector_size(mut size: u16) -> u8 {
let mut n = 0;
while size > 0x80 {
size >>= 1;
n += 1
}
n as _
}
pub fn convert_fdc_sector_size_to_real_sector_size(size: u8) -> u16 {
0x80 << size
}
#[derive(Debug, PartialEq, Copy, Clone, Ord, PartialOrd, Eq)]
pub enum Head {
A,
B,
Unspecified
}
#[allow(missing_docs)]
impl From<u8> for Head {
fn from(val: u8) -> Self {
match val {
0 => Self::A,
1 => Self::B,
_ => Self::Unspecified
}
}
}
#[allow(missing_docs)]
impl Into<u8> for Head {
fn into(self) -> u8 {
match self {
Self::A | Self::Unspecified => 0,
Self::B => 1
}
}
}
#[allow(missing_docs)]
impl Into<u8> for &Head {
fn into(self) -> u8 {
match self {
Head::A | &Head::Unspecified => 0,
Head::B => 1
}
}
}
#[derive(Getters, Debug, Default, PartialEq, Clone)]
pub struct DiscInformation {
#[get = "pub"]
pub(crate) creator_name: String,
#[get = "pub"]
pub(crate) number_of_tracks: u8,
#[get = "pub"]
pub(crate) number_of_heads: u8,
#[get = "pub"]
pub(crate) track_size_table: Vec<u8>
}
#[allow(missing_docs)]
impl DiscInformation {
fn creator_name_as_bytes(&self) -> [u8; 14] {
let mut data = [0; 14];
for (idx, byte) in self.creator_name.as_bytes()[0..14].iter().enumerate() {
data[idx] = *byte;
}
data
}
pub fn from_buffer(buffer: &[u8]) -> Self {
assert_eq!(buffer.len(), 256);
assert_eq!(
String::from_utf8_lossy(&buffer[..34]).to_ascii_uppercase(),
"EXTENDED CPC DSK File\r\nDisk-Info\r\n".to_ascii_uppercase()
);
let creator_name = String::from_utf8_lossy(&buffer[0x22..=0x2F]);
let number_of_tracks = buffer[0x30];
let number_of_heads = buffer[0x31];
let track_size_table = &buffer[0x34..(0x34 + number_of_tracks * number_of_heads) as usize];
assert!(number_of_heads == 1 || number_of_heads == 2);
Self {
creator_name: creator_name.to_string(),
number_of_tracks,
number_of_heads,
track_size_table: track_size_table.to_vec()
}
}
fn to_buffer(&self, buffer: &mut Vec<u8>) {
buffer.extend_from_slice("EXTENDED CPC DSK File\r\nDisk-Info\r\n".as_bytes());
assert_eq!(buffer.len(), 34);
buffer.extend_from_slice(&self.creator_name_as_bytes());
assert_eq!(buffer.len(), 34 + 14);
buffer.push(self.number_of_tracks);
buffer.push(self.number_of_heads);
assert_eq!(buffer.len(), 34 + 14 + 1 + 1);
buffer.push(0);
buffer.push(0);
assert_eq!(buffer.len(), 34 + 14 + 1 + 1 + 2);
buffer.extend_from_slice(&self.track_size_table);
assert_eq!(
buffer.len(),
34 + 14 + 1 + 1 + 2 + self.track_size_table.len()
);
assert!(buffer.len() <= 256);
buffer.resize(256, 0x00);
assert_eq!(buffer.len(), 256);
let from_buffer = Self::from_buffer(&buffer);
assert_eq!(self, &from_buffer);
}
pub fn is_double_head(&self) -> bool {
self.number_of_heads == 2
}
pub fn is_single_head(&self) -> bool {
!self.is_double_head()
}
pub fn track_length(&self, track: u8, head: u8) -> u16 {
assert!(head < self.number_of_heads);
let track = track as usize;
let head = head as usize;
let idx = if self.is_single_head() {
track
}
else {
track * 2 + head
};
self.track_length_at_idx(idx)
}
pub fn is_formatted(&self, track: u8, head: u8) -> bool {
self.track_length(track, head) > 0
}
pub fn track_length_at_idx(&self, idx: usize) -> u16 {
256 * u16::from(self.track_size_table[idx])
}
pub fn total_tracks_lengths(&self) -> usize {
(0..self.number_of_distinct_tracks())
.map(|idx: usize| self.track_length_at_idx(idx) as usize)
.sum::<usize>()
}
pub fn number_of_distinct_tracks(&self) -> usize {
self.track_size_table.len()
}
}
#[allow(missing_docs)]
#[derive(Getters, Debug, Default, PartialEq, Clone)]
pub struct TrackInformation {
#[get = "pub"]
pub(crate) track_number: u8,
#[get = "pub"]
pub(crate) head_number: u8,
#[get = "pub"]
pub(crate) sector_size: u8, #[get = "pub"]
pub(crate) number_of_sectors: u8,
#[get = "pub"]
pub(crate) gap3_length: u8,
#[get = "pub"]
pub(crate) filler_byte: u8,
#[get = "pub"]
pub(crate) data_rate: DataRate,
#[get = "pub"]
pub(crate) recording_mode: RecordingMode,
#[get = "pub"]
pub(crate) sector_information_list: SectorInformationList,
#[get = "pub"]
pub(crate) track_size: u16
}
#[allow(missing_docs)]
impl TrackInformation {
pub fn unformatted() -> Self {
Self::default()
}
pub fn real_track_size(&self) -> u16 {
self.track_size() - 256
}
}
#[allow(missing_docs)]
impl TrackInformation {
delegate! {
to self.sector_information_list {
pub fn sector(&self, sector_id: u8) -> Option<&Sector>;
pub fn sector_mut(&mut self, sector_id: u8) -> Option<&mut Sector>;
}
}
#[deprecated(
note = "Note sure it should be used as each sector store this information and different sizes are possible"
)]
pub fn sector_size_human_readable(&self) -> u16 {
convert_fdc_sector_size_to_real_sector_size(self.sector_size)
}
pub fn next_sector_id(&self, sector: u8) -> Option<u8> {
for idx in 0..(self.number_of_sectors() - 1) {
let current_sector = &self.sector_information_list.sectors[idx as usize];
let next_sector = &self.sector_information_list.sectors[idx as usize + 1];
if *current_sector.sector_id() == sector {
return Some(*next_sector.sector_id());
}
}
None
}
pub fn min_sector(&self) -> u8 {
self.sector_information_list
.sectors()
.iter()
.map(|s| s.sector_information_bloc.sector_id)
.min()
.unwrap()
}
pub fn data_sum(&self) -> usize {
self.sector_information_list
.sectors
.iter()
.map(Sector::data_sum)
.sum::<usize>()
}
pub fn corresponds_to(&self, track: u8, head: u8) -> bool {
self.track_number == track && self.head_number == head
}
#[allow(clippy::cast_possible_truncation)]
pub fn from_buffer(buffer: &[u8]) -> Self {
if String::from_utf8_lossy(&buffer[..0xC]).to_ascii_uppercase()
!= "Track-info\r\n".to_ascii_uppercase()
{
panic!(
"Track buffer does not seem coherent\n{:?}...",
&buffer[..0xC]
);
}
let track_size = buffer.len() as u16;
let track_number = buffer[0x10];
let head_number = buffer[0x11];
let sector_size = buffer[0x14];
let number_of_sectors = buffer[0x15];
let gap3_length = buffer[0x16];
let filler_byte = buffer[0x17];
let data_rate: DataRate = buffer[0x12].into();
let recording_mode = buffer[0x13].into();
println!(
"Track {} Head {} sector_size {} nb_sectors {} gap length {:x}, filler_byte {:x}",
track_number, head_number, sector_size, number_of_sectors, gap3_length, filler_byte
);
let sector_information_list =
SectorInformationList::from_buffer(&buffer[0x18..], number_of_sectors);
let track_info = Self {
track_number,
head_number,
sector_size,
number_of_sectors,
gap3_length,
filler_byte,
data_rate,
recording_mode,
sector_information_list,
track_size
};
assert!(track_info.track_size != 0);
assert_eq!(
track_info.real_track_size(),
track_info.compute_track_size() as u16,
"Wrong track_info {:?}",
track_info
);
track_info
}
pub fn to_buffer(&self, buffer: &mut Vec<u8>) {
let start_size = buffer.len();
assert_eq!(start_size % 256, 0);
buffer.extend_from_slice(&"Track-Info\r\n".as_bytes()[..12]);
assert_eq!(buffer.len() - start_size, 12);
buffer.push(0);
buffer.push(0);
buffer.push(0);
buffer.push(0);
buffer.push(self.track_number);
buffer.push(self.head_number);
buffer.push(self.data_rate.into());
buffer.push(self.recording_mode.into());
buffer.push(self.sector_size);
buffer.push(self.number_of_sectors);
buffer.push(self.gap3_length);
buffer.push(self.filler_byte);
assert_eq!(buffer.len() - start_size, 0x18);
self.sector_information_list.sectors.iter().for_each(|s| {
s.sector_information_bloc.to_buffer(buffer);
});
let added_bytes = buffer.len() - start_size;
let missing_bytes = 256 - added_bytes;
buffer.resize(buffer.len() + missing_bytes, 0);
assert_eq!(buffer.len() % 256, 0);
self.sector_information_list.sectors.iter().for_each(|s| {
buffer.extend_from_slice(&s.values);
});
assert!(buffer.len() % 256 == 0);
}
pub fn total_size(&self) -> usize {
self.sector_information_list
.sectors
.iter()
.map(|info| dbg!(info.sector_information_bloc.data_length) as usize)
.sum()
}
pub fn compute_track_size(&self) -> usize {
let size = self.total_size();
if size % 256 == 0 {
size
}
else {
let mut s = dbg!(size);
while s % 256 != 0 {
s += 1;
}
s
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum DataRate {
Unknown = 0,
SingleOrDoubleDensity = 1,
HighDensity = 2,
ExtendedDensity = 3
}
#[allow(missing_docs)]
impl Default for DataRate {
fn default() -> Self {
Self::Unknown
}
}
#[allow(missing_docs)]
impl From<u8> for DataRate {
fn from(b: u8) -> Self {
match b {
0 => Self::Unknown,
1 => Self::SingleOrDoubleDensity,
2 => Self::HighDensity,
3 => Self::ExtendedDensity,
_ => unreachable!()
}
}
}
#[allow(missing_docs)]
impl Into<u8> for DataRate {
fn into(self) -> u8 {
match self {
Self::Unknown => 0,
Self::SingleOrDoubleDensity => 1,
Self::HighDensity => 2,
Self::ExtendedDensity => 3
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(missing_docs)]
pub enum RecordingMode {
Unknown = 0,
FM = 1,
MFM = 2
}
#[allow(missing_docs)]
impl Default for RecordingMode {
fn default() -> Self {
Self::Unknown
}
}
#[allow(missing_docs)]
impl From<u8> for RecordingMode {
fn from(b: u8) -> Self {
match b {
0 => Self::Unknown,
1 => Self::FM,
2 => Self::MFM,
_ => unreachable!()
}
}
}
#[allow(missing_docs)]
impl Into<u8> for RecordingMode {
fn into(self) -> u8 {
match self {
Self::Unknown => 0,
Self::FM => 1,
Self::MFM => 2
}
}
}
#[derive(Getters, Debug, Default, PartialEq, Clone, Copy)]
#[allow(missing_docs)]
pub struct SectorInformation {
#[get = "pub"]
pub(crate) track: u8,
#[get = "pub"]
pub(crate) head: u8,
#[get = "pub"]
pub(crate) sector_id: u8,
#[get = "pub"]
pub(crate) sector_size: u8,
#[get = "pub"]
pub(crate) fdc_status_register_1: u8,
#[get = "pub"]
pub(crate) fdc_status_register_2: u8,
#[get = "pub"]
pub(crate) data_length: u16 }
#[allow(missing_docs)]
#[allow(clippy::trivially_copy_pass_by_ref)]
impl SectorInformation {
pub fn len(&self) -> usize {
self.sector_size as usize * 256
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn from_buffer(buffer: &[u8]) -> Self {
Self {
track: buffer[0x00],
head: buffer[0x01],
sector_id: buffer[0x02],
sector_size: buffer[0x03],
fdc_status_register_1: buffer[0x04],
fdc_status_register_2: buffer[0x05],
data_length: u16::from(buffer[0x06]) + (u16::from(buffer[0x07]) * 256)
}
}
#[allow(clippy::cast_possible_truncation)]
pub fn to_buffer(&self, buffer: &mut Vec<u8>) {
buffer.push(self.track);
buffer.push(self.head);
buffer.push(self.sector_id);
buffer.push(self.sector_size);
buffer.push(self.fdc_status_register_1);
buffer.push(self.fdc_status_register_2);
buffer.push((self.data_length % 256) as u8);
buffer.push((self.data_length / 256) as u8);
}
}
#[derive(Debug, Default, PartialEq, Clone)]
#[allow(missing_docs)]
pub struct SectorInformationList {
pub(crate) sectors: Vec<Sector>
}
#[allow(missing_docs)]
impl SectorInformationList {
pub fn sectors(&self) -> &[Sector] {
&self.sectors
}
pub fn len(&self) -> usize {
self.sectors.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn add_sector(&mut self, sector: Sector) {
self.sectors.push(sector);
}
pub fn from_buffer(buffer: &[u8], number_of_sectors: u8) -> Self {
let mut list_info = Vec::new();
let mut list_data = Vec::new();
let mut consummed_bytes = 0;
for _sector_number in 0..number_of_sectors {
let current_buffer = &buffer[consummed_bytes..];
let sector = SectorInformation::from_buffer(current_buffer);
consummed_bytes += 8;
list_info.push(sector);
}
dbg!(&list_info);
consummed_bytes = 256 - 0x18; for sector in &list_info {
let current_sector_size = sector.data_length as usize;
let current_buffer = &buffer[consummed_bytes..consummed_bytes + current_sector_size];
let sector_bytes = current_buffer.to_vec();
assert_eq!(sector_bytes.len(), current_sector_size);
list_data.push(sector_bytes);
consummed_bytes += current_sector_size;
}
let info_drain = list_info.drain(..);
let data_drain = list_data.drain(..);
let sectors = zip(info_drain, data_drain)
.map(|(info, data)| {
assert_eq!(info.data_length as usize, data.len());
Sector {
sector_information_bloc: info,
values: data
}
})
.collect::<Vec<Sector>>();
Self { sectors }
}
pub fn sector(&self, sector_id: u8) -> Option<&Sector> {
self.sectors
.iter()
.find(|sector| sector.sector_information_bloc.sector_id == sector_id)
}
pub fn sector_mut(&mut self, sector_id: u8) -> Option<&mut Sector> {
self.sectors
.iter_mut()
.find(|sector| sector.sector_information_bloc.sector_id == sector_id)
}
#[allow(clippy::cast_possible_truncation)]
pub fn fill_with(
&mut self,
ids: &[u8],
heads: &[u8],
track_number: u8,
sector_size: u8,
filler_byte: u8
) {
assert_eq!(ids.len(), heads.len());
assert_eq!(self.len(), 0);
for idx in 0..ids.len() {
let mut sector = Sector::default();
sector.sector_information_bloc.track = track_number;
sector.sector_information_bloc.sector_size = sector_size;
sector.sector_information_bloc.sector_id = ids[idx];
sector.sector_information_bloc.head = heads[idx];
let data_size = convert_fdc_sector_size_to_real_sector_size(
sector.sector_information_bloc.sector_size
) as usize;
sector.values.resize(data_size, filler_byte);
sector.sector_information_bloc.data_length = sector.values.len() as u16;
self.add_sector(sector);
}
}
}
bitflags! {
struct FdcStatusRegister1: u8 {
const END_OF_CYLINDER = 1<<7;
const DATA_ERROR = 1<<5;
const NO_DATA = 1<<2;
const MISSING_ADDRESS_MARK = 1<<0;
}
}
bitflags! {
struct FdcStatusRegister2: u8 {
const CONTROL_MARK = 1<<5;
const DATA_ERROR_IN_DATA_FIELD = 1<<5;
const MISSING_ADDRESS_MARK_IN_DATA_FIELD = 1<<0;
}
}
#[derive(Debug, Default, PartialEq, Clone)]
#[allow(missing_docs)]
#[allow(unused)]
pub struct Sector {
#[get]
pub(crate) sector_information_bloc: SectorInformation,
pub(crate) values: Vec<u8>
}
#[allow(missing_docs)]
impl Sector {
delegate! {
to self.sector_information_bloc {
pub fn sector_id(&self) -> &u8;
}
}
#[allow(clippy::cast_possible_truncation)]
pub fn real_size(&self) -> u16 {
self.values.len() as u16
}
pub fn len(&self) -> u16 {
self.sector_information_bloc.len() as u16
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn data_sum(&self) -> usize {
self.values().iter().map(|&v| v as usize).sum::<usize>()
}
pub fn values(&self) -> &[u8] {
&self.values[..self.len() as usize]
}
pub fn values_mut(&mut self) -> &mut [u8] {
let idx = dbg!(self.len() as usize);
&mut self.values[..idx]
}
pub fn set_values(&mut self, data: &[u8]) -> Result<(), String> {
if data.len() < self.len() as usize {
return Err(format!(
"You cannot insert {} bytes in a sector of size {}.",
data.len(),
self.len()
));
}
if data.len() > self.len() as usize {
return Err(format!(
"Smaller data of {} bytes to put in a sector of size {}.",
data.len(),
self.len()
));
}
self.values[..].clone_from_slice(data);
Ok(())
}
}
#[derive(Default, PartialEq, Debug, Clone)]
#[allow(missing_docs)]
pub struct TrackInformationList {
pub(crate) list: Vec<TrackInformation>
}
#[allow(missing_docs)]
impl TrackInformationList {
fn from_buffer_and_disc_information(buffer: &[u8], disc_info: &DiscInformation) -> Self {
let mut consummed_bytes: usize = 0;
let mut list = Vec::new();
for track_number in 0..disc_info.number_of_tracks {
for head_nb in 0..disc_info.number_of_heads {
let current_track_size = disc_info.track_length(track_number, head_nb) as usize;
let track_buffer = &buffer[consummed_bytes..(consummed_bytes + current_track_size)];
if current_track_size > 0 {
list.push(TrackInformation::from_buffer(track_buffer));
}
else {
eprintln!("Track {} is unformatted", track_number);
list.push(TrackInformation::unformatted());
}
consummed_bytes += current_track_size;
}
}
Self { list }
}
fn to_buffer(&self, buffer: &mut Vec<u8>) {
for track in &self.list {
track.to_buffer(buffer);
}
}
pub fn add_empty_track(&mut self) -> &mut TrackInformation {
let track = TrackInformation::default();
self.list.push(track);
self.list.last_mut().unwrap()
}
pub fn tracks_for_head(&self, head: Head) -> impl Iterator<Item = &TrackInformation> {
let head: u8 = head.into();
self.list
.iter()
.filter(move |info| info.head_number == head)
}
pub fn next_track(&self, track: &TrackInformation) -> Option<&TrackInformation> {
for idx in 0..(self.list.len() - 1) {
let current_track = &self.list[idx];
let next_track = &self.list[idx + 1];
if current_track == track {
return Some(next_track);
}
}
None
}
}
#[derive(Default, PartialEq, Debug, Clone)]
#[allow(missing_docs)]
pub struct ExtendedDsk {
pub(crate) disc_information_bloc: DiscInformation,
pub(crate) track_list: TrackInformationList
}
#[allow(missing_docs)]
impl ExtendedDsk {
pub fn open<P>(path: P) -> io::Result<Self>
where P: AsRef<Path> {
let buffer = {
let mut f = File::open(path)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
buffer
};
Ok(Self::from_buffer(&buffer))
}
pub fn from_buffer(buffer: &[u8]) -> Self {
let disc_info = DiscInformation::from_buffer(&buffer[..256]);
println!(
"Disc info {:?} / total {} / nb_tracks {}",
disc_info,
disc_info.total_tracks_lengths(),
disc_info.number_of_distinct_tracks()
);
let track_list =
TrackInformationList::from_buffer_and_disc_information(&buffer[256..], &disc_info);
Self {
disc_information_bloc: disc_info,
track_list
}
}
pub fn add_amsdos_file(&mut self, _file: &AmsdosFile) -> Result<(), AmsdosError> {
eprintln!("{}: ExtedendDsk::add_amsdos_file not implemented. need to do it (but in the amsdos.rs file", file!());
Ok(())
}
pub fn add_file_sequentially(
&mut self,
head: u8,
track: u8,
sector: u8,
buffer: &[u8]
) -> Result<(u8, u8, u8), String> {
let mut pos = (head, track, sector);
let mut consummed = 0;
while consummed < buffer.len() {
let current_sector = self
.sector_mut(pos.0, pos.1, pos.2)
.ok_or_else(|| "Sector not found".to_owned())?;
let sector_size = current_sector.len() as usize;
let current_data = &buffer[consummed..consummed + sector_size];
current_sector.set_values(current_data)?;
consummed += sector_size;
let next_pos = self
.next_position(pos.0, pos.1, pos.2)
.ok_or_else(|| "No more position available".to_owned())?;
pos = next_pos;
}
Ok(pos)
}
fn next_position(&self, head: u8, track: u8, sector: u8) -> Option<(u8, u8, u8)> {
let current_track = self.get_track_information(
head, track
)?;
if let Some(next_sector) = current_track.next_sector_id(sector) {
return Some((head, track, next_sector));
}
let next_track = self.track_list.next_track(¤t_track)?;
Some((
*next_track.head_number(), *next_track.track_number(),
next_track.min_sector()
))
}
pub fn save<P>(&self, path: P) -> io::Result<()>
where P: AsRef<Path> {
let mut file_buffer = File::create(path)?;
let mut memory_buffer = Vec::new();
self.to_buffer(&mut memory_buffer);
file_buffer.write_all(&memory_buffer)
}
pub fn to_buffer(&self, buffer: &mut Vec<u8>) {
self.disc_information_bloc.to_buffer(buffer);
self.track_list.to_buffer(buffer);
}
pub fn is_double_head(&self) -> bool {
self.disc_information_bloc.is_double_head()
}
#[allow(clippy::cast_possible_truncation)]
pub fn nb_tracks_per_head(&self) -> u8 {
let val = if self.disc_information_bloc.is_single_head() {
self.track_list.list.len()
}
else {
self.track_list.list.len() / 2
};
(val & 0xFF) as u8
}
#[deprecated]
pub fn nb_tracks_per_side(&self) -> u8 {
self.nb_tracks_per_head()
}
pub fn nb_heads(&self) -> u8 {
self.disc_information_bloc.number_of_heads
}
pub fn get_track_information<S: Into<Head>>(
&self,
head: S,
track: u8
) -> Option<&TrackInformation> {
let idx = self.get_track_idx(head.into(), track);
self.track_list.list.get(idx)
}
pub fn get_track_information_mut<S: Into<Head>>(
&mut self,
head: S,
track: u8
) -> Option<&mut TrackInformation> {
let idx = self.get_track_idx(head.into(), track);
self.track_list.list.get_mut(idx)
}
pub fn sector<S: Into<Head>>(&self, head: S, track: u8, sector_id: u8) -> Option<&Sector> {
self.get_track_information(head.into(), track)
.and_then(|track| track.sector(sector_id))
}
pub fn sector_mut<S: Into<Head>>(
&mut self,
head: S,
track: u8,
sector_id: u8
) -> Option<&mut Sector> {
self.get_track_information_mut(head.into(), track)
.and_then(|track| track.sector_mut(sector_id))
}
fn get_track_idx(&self, head: Head, track: u8) -> usize {
if self.disc_information_bloc.is_double_head() {
let head = match head {
Head::A => 0,
Head::B => 1,
Head::Unspecified => panic!("You must specify a Head for a double Headed disc.")
};
track as usize * 2 + head
}
else {
if let Head::B = head {
panic!("You cannot select Head B in a single Headd disc");
}
track as usize
}
}
pub fn sectors_bytes<S: Into<Head>>(
&self,
head: S,
track: u8,
sector_id: u8,
nb_sectors: u8
) -> Option<Vec<u8>> {
let mut res = Vec::new();
let head = head.into();
for count in 0..nb_sectors {
match self.sector(head, track, sector_id + count) {
None => return None,
Some(s) => res.extend(s.values.iter())
}
}
Some(res)
}
pub fn track_bytes<H: Into<Head>>(&self, head: H, track: u8) -> Option<Vec<u8>> {
match self.get_track_information(head, track) {
Some(track) => {
let mut bytes = Vec::new();
for sector in track.sector_information_list.sectors() {
bytes.extend(sector.values().iter());
}
Some(bytes)
}
_ => None
}
}
pub fn data_sum(&self, head: Head) -> usize {
self.track_list
.tracks_for_head(head)
.map(TrackInformation::data_sum)
.sum()
}
pub fn tracks(&self) -> &[TrackInformation] {
&self.track_list.list
}
pub fn nb_tracks(&self) -> usize {
self.tracks().len()
}
pub fn min_sector<S: Into<Head>>(&self, _size: &S) -> u8 {
self.tracks()
.iter()
.map(TrackInformation::min_sector)
.min()
.unwrap()
}
}