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.
|
//! Module to extract the cue sheet from the NRG metadata.
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use ::error::NrgError;
|
use ::error::NrgError;
|
||||||
use ::metadata::metadata::NrgMetadata;
|
use ::metadata::metadata::NrgMetadata;
|
||||||
use ::metadata::cuex::NrgCuexTrack;
|
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.
|
/// - `img_path` is the name of the input NRG file.
|
||||||
/// - `metadata` is the metadata extracted from `image_name` by
|
/// - `metadata` is the metadata extracted from `img_path` by nrgrip::metadata.
|
||||||
/// nrgrip::metadata.
|
|
||||||
///
|
///
|
||||||
/// The output file's name is derived from `image_name`.
|
/// The output file's name will be `img_path`'s base name stripped for its
|
||||||
pub fn write_cue_sheet(image_name: &String, metadata: &NrgMetadata)
|
/// extension (if any), with a ".cue" extension.
|
||||||
|
pub fn write_cue_sheet(img_path: &String, metadata: &NrgMetadata)
|
||||||
-> Result<(), NrgError> {
|
-> Result<(), NrgError> {
|
||||||
if metadata.cuex_chunk.is_none() {
|
// Make sure we have a cue sheet in the metadata
|
||||||
return Err(NrgError::NoNrgCue);
|
let cuex_tracks = match metadata.cuex_chunk {
|
||||||
}
|
None => return Err(NrgError::NoNrgCue),
|
||||||
let cuex_tracks = &metadata.cuex_chunk.as_ref().unwrap().tracks;
|
Some(ref chunk) => &chunk.tracks,
|
||||||
|
};
|
||||||
|
|
||||||
let file_name = make_cue_sheet_name(image_name);
|
// Get the image's base name
|
||||||
let mut fd = try!(File::create(file_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
|
// 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));
|
try!(write_cue_tracks(&mut fd, cuex_tracks));
|
||||||
|
|
||||||
Ok(())
|
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`.
|
/// Writes a list of cue tracks to `fd`.
|
||||||
fn write_cue_tracks(fd: &mut File, cuex_tracks: &Vec<NrgCuexTrack>)
|
fn write_cue_tracks(fd: &mut File, cuex_tracks: &Vec<NrgCuexTrack>)
|
||||||
-> Result<(), NrgError> {
|
-> Result<(), NrgError> {
|
||||||
|
|
|
@ -34,8 +34,9 @@ pub enum NrgError {
|
||||||
NrgFormatV1,
|
NrgFormatV1,
|
||||||
NrgChunkId,
|
NrgChunkId,
|
||||||
NoNrgCue,
|
NoNrgCue,
|
||||||
|
FileName,
|
||||||
AudioReadError,
|
AudioReadError,
|
||||||
AudioWriteError
|
AudioWriteError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for NrgError {
|
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::NrgFormatV1 => write!(f, "NRG v1 format is not handled."),
|
||||||
NrgError::NrgChunkId => write!(f, "NRG chunk ID unknown."),
|
NrgError::NrgChunkId => write!(f, "NRG chunk ID unknown."),
|
||||||
NrgError::NoNrgCue => write!(f, "NRG cue sheet chunk absent."),
|
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::AudioReadError => write!(f, "Error reading raw audio."),
|
||||||
NrgError::AudioWriteError => write!(f, "Error writing raw audio."),
|
NrgError::AudioWriteError => write!(f, "Error writing raw audio."),
|
||||||
}
|
}
|
||||||
|
@ -60,6 +62,7 @@ impl Error for NrgError {
|
||||||
NrgError::NrgFormatV1 => "NRG format v1",
|
NrgError::NrgFormatV1 => "NRG format v1",
|
||||||
NrgError::NrgChunkId => "NRG chunk ID",
|
NrgError::NrgChunkId => "NRG chunk ID",
|
||||||
NrgError::NoNrgCue => "No NRG cue",
|
NrgError::NoNrgCue => "No NRG cue",
|
||||||
|
NrgError::FileName => "File name",
|
||||||
NrgError::AudioReadError => "Audio read error",
|
NrgError::AudioReadError => "Audio read error",
|
||||||
NrgError::AudioWriteError => "Audio write error",
|
NrgError::AudioWriteError => "Audio write error",
|
||||||
}
|
}
|
||||||
|
@ -72,6 +75,7 @@ impl Error for NrgError {
|
||||||
NrgError::NrgFormatV1 => None,
|
NrgError::NrgFormatV1 => None,
|
||||||
NrgError::NrgChunkId => None,
|
NrgError::NrgChunkId => None,
|
||||||
NrgError::NoNrgCue => None,
|
NrgError::NoNrgCue => None,
|
||||||
|
NrgError::FileName => None,
|
||||||
NrgError::AudioReadError => None,
|
NrgError::AudioReadError => None,
|
||||||
NrgError::AudioWriteError => 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 prog_name = argv.next().unwrap_or("nrgrip".to_string());
|
||||||
|
|
||||||
let img_name = argv.next().unwrap_or("".to_string());
|
let img_path = argv.next().unwrap_or("".to_string());
|
||||||
if img_name == "" {
|
if img_path == "" {
|
||||||
exit_usage(&prog_name);
|
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
|
// We don't support more than one input file
|
||||||
if argv.next().is_some() {
|
if argv.next().is_some() {
|
||||||
|
@ -51,10 +51,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the image file
|
// Open the image file
|
||||||
let fd = File::open(&img_name);
|
let fd = File::open(&img_path);
|
||||||
if fd.is_err() {
|
if fd.is_err() {
|
||||||
println!("Can't open image file \"{}\": {}",
|
println!("Can't open image file \"{}\": {}",
|
||||||
img_name, fd.unwrap_err().to_string());
|
img_path, fd.unwrap_err().to_string());
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
let mut fd = fd.unwrap();
|
let mut fd = fd.unwrap();
|
||||||
|
@ -63,7 +63,7 @@ fn main() {
|
||||||
let metadata = nrgrip::metadata::read_nrg_metadata(&mut fd);
|
let metadata = nrgrip::metadata::read_nrg_metadata(&mut fd);
|
||||||
if metadata.is_err() {
|
if metadata.is_err() {
|
||||||
println!("Error reading \"{}\": {}",
|
println!("Error reading \"{}\": {}",
|
||||||
img_name, metadata.unwrap_err().to_string());
|
img_path, metadata.unwrap_err().to_string());
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
let metadata = metadata.unwrap();
|
let metadata = metadata.unwrap();
|
||||||
|
@ -71,7 +71,7 @@ fn main() {
|
||||||
|
|
||||||
// Read and write the cue sheet
|
// Read and write the cue sheet
|
||||||
println!("\nNow extracting 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());
|
println!("Error writing cue sheet: {}", err.to_string());
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ fn main() {
|
||||||
// Extract raw audio data
|
// Extract raw audio data
|
||||||
println!("Now extracting raw audio data...");
|
println!("Now extracting raw audio data...");
|
||||||
if let Err(err) = nrgrip::raw_audio::extract_nrg_raw_audio(
|
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!("Error extracting raw audio data: {}", err.to_string());
|
||||||
}
|
}
|
||||||
println!("OK!");
|
println!("OK!");
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Seek, SeekFrom, Read, Write};
|
use std::io::{Seek, SeekFrom, Read, Write};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use ::error::NrgError;
|
use ::error::NrgError;
|
||||||
use ::metadata::metadata::NrgMetadata;
|
use ::metadata::metadata::NrgMetadata;
|
||||||
|
@ -32,22 +33,23 @@ use ::metadata::metadata::NrgMetadata;
|
||||||
/// Extracts the raw audio data from an NRG image.
|
/// Extracts the raw audio data from an NRG image.
|
||||||
///
|
///
|
||||||
/// - `in_fd` is the handler to the NRG image file.
|
/// - `in_fd` is the handler to the NRG image file.
|
||||||
/// - `image_name` is the name of the input NRG file.
|
/// - `img_path` is the name of the input NRG file.
|
||||||
/// - `metadata` is the metadata extracted from `image_name` by
|
/// - `metadata` is the metadata extracted from `img_path` by nrgrip::metadata.
|
||||||
/// 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,
|
pub fn extract_nrg_raw_audio(in_fd: &mut File,
|
||||||
image_name: &String,
|
img_path: &String,
|
||||||
metadata: &NrgMetadata)
|
metadata: &NrgMetadata)
|
||||||
-> Result<(), NrgError> {
|
-> Result<(), NrgError> {
|
||||||
|
// Seek to the first audio byte
|
||||||
let skip_bytes = get_daox_track1_index1(metadata);
|
let skip_bytes = get_daox_track1_index1(metadata);
|
||||||
|
|
||||||
try!(in_fd.seek(SeekFrom::Start(skip_bytes)));
|
try!(in_fd.seek(SeekFrom::Start(skip_bytes)));
|
||||||
|
|
||||||
let file_name = make_output_file_name(image_name);
|
// Open output file
|
||||||
let mut out_fd = try!(File::create(file_name));
|
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;
|
let mut cur_offset = skip_bytes;
|
||||||
while cur_offset < metadata.chunk_offset {
|
while cur_offset < metadata.chunk_offset {
|
||||||
let mut audio_buf = [0u8; 2352];
|
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.
|
/// 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 output file's name will be `img_path`'s base name stripped for its
|
||||||
/// the same as `image_name` with a `.raw` extension instead of `.nrg`.
|
/// extension (if any), with a ".raw" extension.
|
||||||
/// Otherwise, it will be `image_name.raw`.
|
fn make_output_file_name(img_path: &String) -> Result<String, NrgError> {
|
||||||
fn make_output_file_name(image_name: &String) -> String {
|
let mut name = PathBuf::from(img_path);
|
||||||
let mut name = image_name.clone();
|
name.set_extension("raw");
|
||||||
if name.to_lowercase().ends_with(".nrg") {
|
let name = PathBuf::from(name);
|
||||||
let newlen = name.len() - 4;
|
let name = try!(name.file_name().ok_or(NrgError::FileName));
|
||||||
name.truncate(newlen);
|
|
||||||
|
// 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