mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-06 17:35:40 +00:00
Filesystem now stores the primary volume descriptor.
This commit is contained in:
parent
c15ab13007
commit
733879ee82
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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),
|
||||
|
||||
55
dcb-iso9660/src/cdrom/iter.rs
Normal file
55
dcb-iso9660/src/cdrom/iter.rs
Normal 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))
|
||||
}
|
||||
}
|
||||
@ -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(§or.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(§or.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
|
||||
|
||||
@ -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),
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user