diff --git a/src/cue_sheet/mod.rs b/src/cue_sheet/mod.rs new file mode 100644 index 0000000..c625757 --- /dev/null +++ b/src/cue_sheet/mod.rs @@ -0,0 +1,78 @@ +//! Module to extract the cue sheet from the NRG metadata. + +use ::error::NrgError; +use ::metadata::metadata::NrgMetadata; + + +pub fn write_cue_sheet(image_name: &String, nm: &NrgMetadata) + -> Result<(), NrgError> { + if nm.cuex_chunk.is_none() { + return Err(NrgError::NoNrgCue); + } + let cuex_tracks = &nm.cuex_chunk.as_ref().unwrap().tracks; + + let file_name = try!(make_cue_sheet_name(image_name)); + + println!("FILE \"{}\" RAW", image_name); + + let mut index0_pos = -1; + for track in cuex_tracks { + // Ignore lead-in and lead-out areas + if track.track_number == 0 || track.track_number == 0xAA { + continue; + } + + // Ignore negative positions + if track.position_sectors < 0 { + continue; + } + + // Store/skip index0 + if track.index_number == 0 { + index0_pos = track.position_sectors; + continue; + } + + // Write track info + println!(" TRACK {:02} AUDIO", track.track_number); + + // Write index0 if we stored it and it's before the current index's + // position (i.e., it indicates a pre-gap) + if index0_pos >= 0 && index0_pos < track.position_sectors { + try!(write_cue_index(0, index0_pos)); + index0_pos = -1; + } + + // Write current index + try!(write_cue_index(track.index_number, track.position_sectors)); + } + + Ok(()) +} + + +/// Generates the cue sheet's name from the NRG image's name. +/// +/// If `image_name`'s extension is `.nrg` (case-insensitive), the cue sheet's +/// name will be the same as `image_name` with a `.cue` extension instead of +/// `.nrg`. Otherwise, the cue sheet's name will be `image_name.cue`. +fn make_cue_sheet_name(image_name: &String) -> Result { + Ok("image.cue".to_string()) +} + + +fn write_cue_index(index: u8, position_sectors: i32) + -> Result<(), NrgError> { + assert!(position_sectors >= 0); + + // Audio CDs are played at a 75 sectors per second rate: + let mut seconds: u32 = position_sectors as u32 / 75; + let remaining_sectors = position_sectors % 75; + let minutes = seconds / 60; + seconds %= 60; + + println!(" INDEX {:02} {:02}:{:02}:{:02}", + index, minutes, seconds, remaining_sectors); + + Ok(()) +} diff --git a/src/error.rs b/src/error.rs index 38c4635..c16ac81 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,6 +11,7 @@ pub enum NrgError { NrgFormat, NrgFormatV1, NrgChunkId, + NoNrgCue, } impl fmt::Display for NrgError { @@ -20,6 +21,7 @@ impl fmt::Display for NrgError { NrgError::NrgFormat => write!(f, "NRG format unknown."), NrgError::NrgFormatV1 => write!(f, "NRG v1 format is not handled."), NrgError::NrgChunkId => write!(f, "NRG chunk ID unknown."), + NrgError::NoNrgCue => write!(f, "NRG cue sheet chunk absent."), } } } @@ -31,6 +33,7 @@ impl Error for NrgError { NrgError::NrgFormat => "NRG format", NrgError::NrgFormatV1 => "NRG format v1", NrgError::NrgChunkId => "NRG chunk ID", + NrgError::NoNrgCue => "No NRG cue", } } @@ -40,6 +43,7 @@ impl Error for NrgError { NrgError::NrgFormat => None, NrgError::NrgFormatV1 => None, NrgError::NrgChunkId => None, + NrgError::NoNrgCue => None, } } } diff --git a/src/lib.rs b/src/lib.rs index eebe062..b19f5a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ //! Extracts audio data and metadata from an NRG image of an audio CD. -pub mod metadata; pub mod error; +pub mod metadata; +pub mod cue_sheet; diff --git a/src/main.rs b/src/main.rs index eeab0e3..f6aaf57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ fn main() { exit_usage(&prog_name); } - println!("NRG image name: {}", img_name); + println!("NRG image name: \"{}\"", img_name); // We don't support more than one input file if argv.next().is_some() { @@ -31,18 +31,25 @@ fn main() { // Open the image file let fd = File::open(&img_name); if fd.is_err() { - println!("Can't open \"{}\": {}", + println!("Can't open image file \"{}\": {}", img_name, fd.unwrap_err().to_string()); process::exit(1); } let mut fd = fd.unwrap(); - // Read the image's metadata - match nrgrip::metadata::read_nrg_metadata(&mut fd) { - Err(err) => println!("Error reading \"{}\": {}", - img_name, err.to_string()), - Ok(metadata) => println!("\n\ - *** Metadata ***\n\ - {}", metadata), + // Read and display the image's metadata + let metadata = nrgrip::metadata::read_nrg_metadata(&mut fd); + if metadata.is_err() { + println!("Error reading \"{}\": {}", + img_name, metadata.unwrap_err().to_string()); + process::exit(1); + } + let metadata = metadata.unwrap(); + println!("\n{}", metadata); + + // Read and write the cue sheet + if let Err(err) = nrgrip::cue_sheet::write_cue_sheet(&img_name, &metadata) { + println!("Error writing cue sheet: {}", err.to_string()); + process::exit(1); } } diff --git a/src/metadata/mod.rs b/src/metadata/mod.rs index 8383005..19403b7 100644 --- a/src/metadata/mod.rs +++ b/src/metadata/mod.rs @@ -5,7 +5,7 @@ use std::io::{Seek, SeekFrom}; use ::error::NrgError; -mod metadata; +pub mod metadata; mod cuex; mod daox; mod sinf;