Improve handling of output file names

* Use PathBuf operations to generate output file names.
* Output files are now written to the working directory.
* The cue sheet contains only the image's base name, not the full path.
This commit is contained in:
Matteo Cypriani 2016-12-07 16:06:10 -05:00
parent 5d0973f5ae
commit 4b92eb0239
4 changed files with 65 additions and 56 deletions

View File

@ -23,54 +23,54 @@
//! Module to extract the cue sheet from the NRG metadata.
use std::io::Write;
use std::ffi::OsStr;
use std::fs::File;
use std::path::PathBuf;
use ::error::NrgError;
use ::metadata::metadata::NrgMetadata;
use ::metadata::cuex::NrgCuexTrack;
/// Writes the cue sheet for `image_name` into a file.
/// Writes the cue sheet for `img_path` into a file.
///
/// - `image_name` is the name of the input NRG file.
/// - `metadata` is the metadata extracted from `image_name` by
/// nrgrip::metadata.
/// - `img_path` is the name of the input NRG file.
/// - `metadata` is the metadata extracted from `img_path` by nrgrip::metadata.
///
/// The output file's name is derived from `image_name`.
pub fn write_cue_sheet(image_name: &String, metadata: &NrgMetadata)
/// The output file's name will be `img_path`'s base name stripped for its
/// extension (if any), with a ".cue" extension.
pub fn write_cue_sheet(img_path: &String, metadata: &NrgMetadata)
-> Result<(), NrgError> {
if metadata.cuex_chunk.is_none() {
return Err(NrgError::NoNrgCue);
}
let cuex_tracks = &metadata.cuex_chunk.as_ref().unwrap().tracks;
// Make sure we have a cue sheet in the metadata
let cuex_tracks = match metadata.cuex_chunk {
None => return Err(NrgError::NoNrgCue),
Some(ref chunk) => &chunk.tracks,
};
let file_name = make_cue_sheet_name(image_name);
let mut fd = try!(File::create(file_name));
// Get the image's base name
let img_name = PathBuf::from(img_path);
let img_name = match img_name.file_name() {
Some(name) => name,
None => return Err(NrgError::FileName),
};
// Set the cue sheet file's name
let mut cue_name = PathBuf::from(img_name);
if cue_name.extension().unwrap_or(OsStr::new("")) == "cue" {
// img_path's extension was already .cue: problem!
return Err(NrgError::FileName);
}
cue_name.set_extension("cue");
// Write cue sheet
try!(writeln!(fd, "FILE \"{}\" RAW", image_name));
let mut fd = try!(File::create(cue_name));
try!(writeln!(fd, "FILE \"{}\" RAW", img_name.to_string_lossy()));
try!(write_cue_tracks(&mut fd, cuex_tracks));
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) -> String {
let mut name = image_name.clone();
if name.to_lowercase().ends_with(".nrg") {
let newlen = name.len() - 4;
name.truncate(newlen);
}
name.push_str(".cue");
name
}
/// Writes a list of cue tracks to `fd`.
fn write_cue_tracks(fd: &mut File, cuex_tracks: &Vec<NrgCuexTrack>)
-> Result<(), NrgError> {

View File

@ -34,8 +34,9 @@ pub enum NrgError {
NrgFormatV1,
NrgChunkId,
NoNrgCue,
FileName,
AudioReadError,
AudioWriteError
AudioWriteError,
}
impl fmt::Display for NrgError {
@ -46,6 +47,7 @@ impl fmt::Display for NrgError {
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."),
NrgError::FileName => write!(f, "Invalid file name."),
NrgError::AudioReadError => write!(f, "Error reading raw audio."),
NrgError::AudioWriteError => write!(f, "Error writing raw audio."),
}
@ -60,6 +62,7 @@ impl Error for NrgError {
NrgError::NrgFormatV1 => "NRG format v1",
NrgError::NrgChunkId => "NRG chunk ID",
NrgError::NoNrgCue => "No NRG cue",
NrgError::FileName => "File name",
NrgError::AudioReadError => "Audio read error",
NrgError::AudioWriteError => "Audio write error",
}
@ -72,6 +75,7 @@ impl Error for NrgError {
NrgError::NrgFormatV1 => None,
NrgError::NrgChunkId => None,
NrgError::NoNrgCue => None,
NrgError::FileName => None,
NrgError::AudioReadError => None,
NrgError::AudioWriteError => None,
}

View File

@ -38,12 +38,12 @@ fn main() {
let prog_name = argv.next().unwrap_or("nrgrip".to_string());
let img_name = argv.next().unwrap_or("".to_string());
if img_name == "" {
let img_path = argv.next().unwrap_or("".to_string());
if img_path == "" {
exit_usage(&prog_name);
}
println!("NRG image name: \"{}\"", img_name);
println!("NRG image path: \"{}\"", img_path);
// We don't support more than one input file
if argv.next().is_some() {
@ -51,10 +51,10 @@ fn main() {
}
// Open the image file
let fd = File::open(&img_name);
let fd = File::open(&img_path);
if fd.is_err() {
println!("Can't open image file \"{}\": {}",
img_name, fd.unwrap_err().to_string());
img_path, fd.unwrap_err().to_string());
process::exit(1);
}
let mut fd = fd.unwrap();
@ -63,7 +63,7 @@ fn main() {
let metadata = nrgrip::metadata::read_nrg_metadata(&mut fd);
if metadata.is_err() {
println!("Error reading \"{}\": {}",
img_name, metadata.unwrap_err().to_string());
img_path, metadata.unwrap_err().to_string());
process::exit(1);
}
let metadata = metadata.unwrap();
@ -71,7 +71,7 @@ fn main() {
// Read and write the cue sheet
println!("\nNow extracting cue sheet...");
if let Err(err) = nrgrip::cue_sheet::write_cue_sheet(&img_name, &metadata) {
if let Err(err) = nrgrip::cue_sheet::write_cue_sheet(&img_path, &metadata) {
println!("Error writing cue sheet: {}", err.to_string());
process::exit(1);
}
@ -79,7 +79,7 @@ fn main() {
// Extract raw audio data
println!("Now extracting raw audio data...");
if let Err(err) = nrgrip::raw_audio::extract_nrg_raw_audio(
&mut fd, &img_name, &metadata) {
&mut fd, &img_path, &metadata) {
println!("Error extracting raw audio data: {}", err.to_string());
}
println!("OK!");

View File

@ -24,6 +24,7 @@
use std::fs::File;
use std::io::{Seek, SeekFrom, Read, Write};
use std::path::PathBuf;
use ::error::NrgError;
use ::metadata::metadata::NrgMetadata;
@ -32,22 +33,23 @@ use ::metadata::metadata::NrgMetadata;
/// Extracts the raw audio data from an NRG image.
///
/// - `in_fd` is the handler to the NRG image file.
/// - `image_name` is the name of the input NRG file.
/// - `metadata` is the metadata extracted from `image_name` by
/// nrgrip::metadata.
/// - `img_path` is the name of the input NRG file.
/// - `metadata` is the metadata extracted from `img_path` by nrgrip::metadata.
///
/// The output file's name is derived from `image_name`.
/// The output file's name is derived from `img_path`.
pub fn extract_nrg_raw_audio(in_fd: &mut File,
image_name: &String,
img_path: &String,
metadata: &NrgMetadata)
-> Result<(), NrgError> {
// Seek to the first audio byte
let skip_bytes = get_daox_track1_index1(metadata);
try!(in_fd.seek(SeekFrom::Start(skip_bytes)));
let file_name = make_output_file_name(image_name);
let mut out_fd = try!(File::create(file_name));
// Open output file
let audio_name = try!(make_output_file_name(img_path));
let mut out_fd = try!(File::create(audio_name));
// Read/write audio data
let mut cur_offset = skip_bytes;
while cur_offset < metadata.chunk_offset {
let mut audio_buf = [0u8; 2352];
@ -85,15 +87,18 @@ fn get_daox_track1_index1(metadata: &NrgMetadata) -> u64 {
/// Generates the output file's name from the NRG image's name.
///
/// If `image_name`'s extension is `.nrg` (case-insensitive), the name will be
/// the same as `image_name` with a `.raw` extension instead of `.nrg`.
/// Otherwise, it will be `image_name.raw`.
fn make_output_file_name(image_name: &String) -> String {
let mut name = image_name.clone();
if name.to_lowercase().ends_with(".nrg") {
let newlen = name.len() - 4;
name.truncate(newlen);
/// The output file's name will be `img_path`'s base name stripped for its
/// extension (if any), with a ".raw" extension.
fn make_output_file_name(img_path: &String) -> Result<String, NrgError> {
let mut name = PathBuf::from(img_path);
name.set_extension("raw");
let name = PathBuf::from(name);
let name = try!(name.file_name().ok_or(NrgError::FileName));
// Make sure the new name and the original name are different
if name == img_path.as_str() {
return Err(NrgError::FileName);
}
name.push_str(".raw");
name
Ok(name.to_string_lossy().into_owned())
}