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:
parent
5d0973f5ae
commit
4b92eb0239
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -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!");
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue