From 3140ff5a081139200a39c5b1a57e29522bfb2a75 Mon Sep 17 00:00:00 2001 From: Lionel Flandrin Date: Thu, 23 Jun 2016 01:09:48 +0200 Subject: [PATCH] Added support for track-relative MSF --- src/cue/mod.rs | 11 ++++++--- src/internal.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 14 ++++++++++-- 3 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/cue/mod.rs b/src/cue/mod.rs index e407dfd..2daa7b0 100644 --- a/src/cue/mod.rs +++ b/src/cue/mod.rs @@ -16,6 +16,7 @@ use Image; use internal::IndexCache; use sector::{Sector, SectorBuilder, Metadata}; use msf::Msf; +use bcd::Bcd; use self::parser::CueParser; @@ -72,11 +73,11 @@ impl Image for Cue { index } else { match self.indices - .find_index1_for_track(index.track()) { - Some((_, i)) => i, + .find_index01_for_track(index.track()) { + Ok((_, i)) => i, // Shouldn't be reached, should be // caught by IndexCache's constructor - None => + Err(_) => panic!("Missing index 1 for track {}", index.track()), } @@ -130,6 +131,10 @@ impl Image for Cue { Ok(()) } + + fn track_msf(&self, track: Bcd, track_msf: Msf) -> Result { + self.indices.track_msf(track, track_msf) + } } /// Possible types for a CUE track. diff --git a/src/internal.rs b/src/internal.rs index 6e8d52a..551d389 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -200,23 +200,73 @@ impl IndexCache { /// a reference to the `Index` struct. pub fn find_index_for_track(&self, track: Bcd, - index: Bcd) -> Option<(usize, &Index)> { + index: Bcd) -> Result<(usize, &Index), + CdError> { match self.indices.binary_search_by( |idx| match idx.track().cmp(&track) { cmp::Ordering::Equal => idx.index().cmp(&index), o => o, }) { - Ok(i) => Some((i, &self.indices[i])), - Err(_) => None, + Ok(i) => Ok((i, &self.indices[i])), + Err(_) => Err(CdError::BadTrack), } } /// Locate index1 for `track` and return its position along with a /// reference to the `Index` struct. - pub fn find_index1_for_track(&self, - track: Bcd) -> Option<(usize, &Index)> { + pub fn find_index01_for_track(&self, + track: Bcd) -> Result<(usize, &Index), + CdError> { self.find_index_for_track(track, Bcd::one()) } + + /// Return the length of the given track starting at INDEX 01, not + /// counting the pregap. Also returns the position and a reference + /// to the INDEX 01 for this track. + pub fn track_length(&self, track: Bcd) -> Result<(Msf, usize, &Index), + CdError> { + let (pos01, index01) = + try!(self.find_index01_for_track(track)); + + // Iterate over the remaining indices to find the beginning of + // the next track + + let next_track = + self.indices[pos01 + 1..].iter().find(|i| i.track() != track); + + let end = + match next_track { + // We found the next track, the previous sector is the + // last one in our track. + Some(next) => next.sector_index(), + // Seems like we got the last track + None => self.lead_out, + }; + + let len = + Msf::from_sector_index(end - index01.sector_index()).unwrap(); + + Ok((len, pos01, index01)) + } + + /// Return the absolute Msf for the position `track_msf` in + /// `track`. Will return an error if the `track_msf` is outside of + /// the track or if `track` doesn't exist. + pub fn track_msf(&self, + track: Bcd, + track_msf: Msf) -> Result { + + // We need to make sure that `track_msf` is not bigger than + // this tracks' length. + let (len, _, index01) = + try!(self.track_length(track)); + + if track_msf < len { + Ok(index01.msf() + track_msf) + } else { + Err(CdError::EndOfTrack) + } + } } impl fmt::Debug for IndexCache { diff --git a/src/lib.rs b/src/lib.rs index 0355af4..58187b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ use std::io; use std::fmt; use sector::Sector; use msf::Msf; +use bcd::Bcd; pub mod bcd; pub mod msf; @@ -34,6 +35,11 @@ pub trait Image { /// Read a single sector at the given MSF fn read_sector(&mut self, &mut Sector, Msf) -> Result<(), CdError>; + + /// Return the absolute Msf for the position `track_msf` in + /// `track`. Will return an error if the `track_msf` is outside of + /// the track or if `track` doesn't exist. + fn track_msf(&self, track: Bcd, track_msf: Msf) -> Result; } /// Possible session formats. @@ -68,6 +74,8 @@ pub enum TrackFormat { /// Error type for disc operations. #[derive(Debug)] pub enum CdError { + /// Generic I/O error + IoError(io::Error), /// Format missmatch. For instance when one attempts to retrieve /// CD-ROM payloads on an audio track. BadFormat, @@ -81,8 +89,10 @@ pub enum CdError { /// track, absurd index etc...). Contains the path of the file and /// a `String` describing the problem. BadImage(PathBuf, String), - /// Generic I/O error - IoError(io::Error), + /// Attempted to access an invalid track number + BadTrack, + /// Attempted to access a track past its end + EndOfTrack, } impl fmt::Display for CdError {