Filesystem now stores the primary volume descriptor.

This commit is contained in:
Filipe Rodrigues 2021-01-18 15:39:40 +00:00
parent c15ab13007
commit 733879ee82
5 changed files with 104 additions and 33 deletions

View File

@ -6,15 +6,20 @@
// Modules
pub mod error;
pub mod iter;
pub mod sector;
// Exports
pub use error::SectorError;
pub use error::ReadSectorError;
pub use iter::SectorsRangeIter;
pub use sector::Sector;
// Imports
use dcb_bytes::Bytes;
use std::io::{Read, Seek, SeekFrom};
use std::{
io::{Read, Seek, SeekFrom},
ops::RangeBounds,
};
/// A CD-ROM/XA Mode 2 Form 1 wrapper
pub struct CdRom<R> {
@ -40,16 +45,21 @@ impl<R> CdRom<R> {
// Read
impl<R: Read + Seek> CdRom<R> {
/// Reads the `n`th sector
pub fn sector(&mut self, n: u64) -> Result<Sector, SectorError> {
pub fn read_sector(&mut self, n: u64) -> Result<Sector, ReadSectorError> {
// Seek to the sector.
self.reader.seek(SeekFrom::Start(Self::SECTOR_SIZE * n)).map_err(SectorError::Seek)?;
self.reader.seek(SeekFrom::Start(Self::SECTOR_SIZE * n)).map_err(ReadSectorError::Seek)?;
// Read it
let mut bytes = [0; 2352];
self.reader.read_exact(&mut bytes).map_err(SectorError::Read)?;
self.reader.read_exact(&mut bytes).map_err(ReadSectorError::Read)?;
// And parse it
let sector = Sector::from_bytes(&bytes).map_err(SectorError::Parse)?;
let sector = Sector::from_bytes(&bytes).map_err(ReadSectorError::Parse)?;
Ok(sector)
}
/// Returns an iterator over a range of sectors
pub fn read_sectors_range(&mut self, range: impl RangeBounds<u64>) -> SectorsRangeIter<R> {
SectorsRangeIter::new(self, range)
}
}

View File

@ -5,7 +5,7 @@ use super::sector;
/// Error type for [`CdRom::sector`](super::CdRom::sector)
#[derive(Debug, thiserror::Error)]
pub enum SectorError {
pub enum ReadSectorError {
/// Unable to seek to sector
#[error("Unable to seek to sector")]
Seek(#[source] std::io::Error),

View File

@ -0,0 +1,55 @@
//! Iterators
// Imports
use super::{ReadSectorError, Sector};
use crate::CdRom;
use std::{
io,
ops::{Bound, Range, RangeBounds},
};
/// Iterator over sectors
pub struct SectorsRangeIter<'a, R: io::Read + io::Seek> {
/// The cdrom
cdrom: &'a mut CdRom<R>,
/// Sector range
range: Range<u64>,
}
impl<'a, R: io::Read + io::Seek> SectorsRangeIter<'a, R> {
/// Creates a new sector range iterator
pub(crate) fn new(cdrom: &'a mut CdRom<R>, range: impl RangeBounds<u64>) -> Self {
let start = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(n) => n.saturating_add(1),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(n) => n.saturating_add(1),
Bound::Excluded(&n) => n,
Bound::Unbounded => u64::MAX,
};
Self { cdrom, range: start..end }
}
}
impl<'a, R: io::Read + io::Seek> Iterator for SectorsRangeIter<'a, R> {
type Item = Result<Sector, ReadSectorError>;
fn next(&mut self) -> Option<Self::Item> {
// TODO: Maybe only seek once and them keep reading?
// If our range is empty, return None
if self.range.is_empty() {
return None;
}
// Else read the next sector and advance our range
let n = self.range.start;
self.range.start += 1;
Some(self.cdrom.read_sector(n))
}
}

View File

@ -16,6 +16,7 @@ pub use string::{StrArrA, StrArrD};
pub use volume_descriptor::VolumeDescriptor;
// Imports
use self::volume_descriptor::PrimaryVolumeDescriptor;
use crate::CdRom;
use dcb_bytes::Bytes;
use std::io;
@ -23,29 +24,30 @@ use std::io;
/// The filesystem
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Filesystem {
/// Root directory
root_dir_entry: DirRecord,
/// Primary volume descriptor
primary_volume_descriptor: PrimaryVolumeDescriptor,
}
impl Filesystem {
/// Reads the filesystem from a game file
pub fn new<R: io::Read + io::Seek>(file: &mut CdRom<R>) -> Result<Self, NewError> {
// Read the primary volume descriptor from sector `0x10`
// Start reading volume descriptors from sector `0x10` until we hit the primary one
// Note: First `32 kiB` (= 16 sectors) are reserved for arbitrary data.
let sector = file.sector(0x10).map_err(NewError::ReadPrimaryVolumeSector)?;
let _primary_volume_descriptor = VolumeDescriptor::from_bytes(&sector.data).map_err(NewError::ParsePrimaryVolume)?;
todo!();
/*
// Try to get the root directory entry
let root_dir_entry = match primary_volume_descriptor {
VolumeDescriptor::Primary { root_dir_entry, .. } => root_dir_entry,
_ => return Err(NewError::FirstVolumeNotPrimary(primary_volume_descriptor.type_code())),
let mut sectors = file.read_sectors_range(0x10..);
let primary_volume_descriptor = loop {
match sectors.next() {
Some(Ok(sector)) => match VolumeDescriptor::from_bytes(&sector.data) {
Ok(VolumeDescriptor::Primary(primary)) => break primary,
Ok(VolumeDescriptor::SetTerminator) => return Err(NewError::MissingPrimaryVolumeBeforeSetTerminator),
Ok(volume_descriptor) => log::debug!("Skipping {:?} volume descriptor before primary", volume_descriptor.kind()),
Err(err) => return Err(NewError::InvalidVolumeDescriptor(err)),
},
Some(Err(err)) => return Err(NewError::InvalidSectorBeforeSetTerminator(err)),
None => return Err(NewError::EofBeforeSetTerminator),
}
};
Ok(Self { root_dir_entry })
*/
Ok(Self { primary_volume_descriptor })
}
/// Prints a tree of all files

View File

@ -1,21 +1,25 @@
//! Errors
// Imports
use super::volume_descriptor::{self, DescriptorKind};
use crate::cdrom::SectorError;
use super::volume_descriptor::{self};
use crate::cdrom::ReadSectorError;
/// Error type for [`Filesystem::new`](super::Filesystem::new)
#[derive(Debug, thiserror::Error)]
pub enum NewError {
/// Unable to read primary volume sector
#[error("Unable to read primary volume sector")]
ReadPrimaryVolumeSector(#[source] SectorError),
/// Missing primary volume
#[error("No primary volume found before set terminator")]
MissingPrimaryVolumeBeforeSetTerminator,
/// Unable to parse primary volume
#[error("Unable to parse primary volume")]
ParsePrimaryVolume(#[source] volume_descriptor::FromBytesError),
/// Eof before set terminator
#[error("Found eof before set terminator")]
EofBeforeSetTerminator,
/// First volume was not the primary volume
#[error("First volume was not the primary volume, was {_0:?}")]
FirstVolumeNotPrimary(DescriptorKind),
/// Invalid sector before set terminator
#[error("Invalid sector before set terminator")]
InvalidSectorBeforeSetTerminator(#[source] ReadSectorError),
/// Invalid volume descriptor
#[error("Invalid volume descriptor")]
InvalidVolumeDescriptor(#[source] volume_descriptor::FromBytesError),
}