diff --git a/src/Tools/psxcdgen_ex/src/config_reader/mod.rs b/src/Tools/psxcdgen_ex/src/config_reader/mod.rs index 4d49eb5c..57f08955 100644 --- a/src/Tools/psxcdgen_ex/src/config_reader/mod.rs +++ b/src/Tools/psxcdgen_ex/src/config_reader/mod.rs @@ -8,11 +8,22 @@ pub enum LZ4State { Compress, } +pub struct CDAudioFile { + pub file_path: PathBuf, + pub align: bool, +} + +impl CDAudioFile { + pub fn new(file_path: PathBuf, align: bool) -> CDAudioFile { + CDAudioFile{file_path, align} + } +} + pub struct Configuration { pub publisher: Option, pub license_path: Option, pub root: Directory, - pub cd_audio_files: Vec, + pub cd_audio_files: Vec, pub lead_out_sectors: Option, } diff --git a/src/Tools/psxcdgen_ex/src/config_reader/xml.rs b/src/Tools/psxcdgen_ex/src/config_reader/xml.rs index a8a26ae1..d686dece 100644 --- a/src/Tools/psxcdgen_ex/src/config_reader/xml.rs +++ b/src/Tools/psxcdgen_ex/src/config_reader/xml.rs @@ -1,10 +1,10 @@ use attribute_names::LBA_SOURCE; use cdtypes::types::time::Time; use std::path::PathBuf; -use tool_helper::{format_if_error, path_with_env_from, print_warning, string_with_env_from}; +use tool_helper::{format_if_error, path_with_env_from, string_with_env_from}; use crate::config_reader::Directory; -use super::{CommonProperties, Configuration, Error, File, FileKind, LZ4State}; +use super::{CDAudioFile, CommonProperties, Configuration, Error, File, FileKind, LZ4State}; mod attribute_names { pub const NAME: &'static str = "name"; @@ -14,39 +14,45 @@ mod attribute_names { pub const LZ4_STATE: &'static str = "lz4"; } +mod tag_names { + pub const ROOT: &'static str = "PSXCD"; + pub const TRACK: &'static str = "Filesystem"; + pub const INTERLEAVED: &'static str = "InterleavedFile"; + pub const CDDA: &'static str = "AudioTrack"; +} + pub fn parse(xml: String) -> Result { let mut config = Configuration::new(); let parser = format_if_error!(roxmltree::Document::parse(xml.as_str()), "Parsing XML file failed with: {error_text}")?; let children = parser.root().children(); for node in children { - if node.is_element() && node.tag_name().name() == "ISO_Project" { - parse_iso_project(node, &mut config)?; + if node.is_element() && node.tag_name().name() == tag_names::ROOT { + parse_root(node, &mut config)?; } } Ok(config) } -fn parse_iso_project(iso_project: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { +fn parse_root(root: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { let mut parsed_track = false; - for node in iso_project.children() { + for node in root.children() { if node.is_element() { match node.tag_name().name() { - "Description" => parse_description(node, config), - "Track" => { + "Description" => parse_description(node, config), + tag_names::TRACK => { if !parsed_track { parsed_track = true; parse_track(node, config) } else { - print_warning("Found more than 1 track. Multi-Tracks are not supported yet. Track will be ignored".to_owned()); - Ok(()) + Err(Error::from_text(format!("Found more than 1 filesystem. Multi filesystem discs are not supported"))) } }, - "CD_Audio" => parse_cd_audio(node, config), + tag_names::CDDA => parse_cd_audio(node, config), _ => Ok(()) }?; } @@ -109,8 +115,8 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), Ok(File{common, path, kind: FileKind::Overlay(PathBuf::from(lba_source))}) } - fn parse_xa_audio(file: roxmltree::Node, is_hidden: bool) -> Result { - // v Never compress XA-Audio + fn parse_interleaved(file: roxmltree::Node, is_hidden: bool) -> Result { + // v Never compress interleaved files let common = read_common_properties(&file, is_hidden, Some(LZ4State::None))?; let channel = { let mut channel = Vec::new(); @@ -130,11 +136,11 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), for node in cur_node.children() { if node.is_element() { match node.tag_name().name() { - "File" => root.add_file(parse_regular_file(node, is_hidden)?), - "Main" => root.add_file(parse_main_file(node)?), - "Overlay" => root.add_file(parse_overlay_file(node, is_hidden)?), - "XA-Audio" => root.add_file(parse_xa_audio(node, is_hidden)?), - "Directory" => { + "File" => root.add_file(parse_regular_file(node, is_hidden)?), + "Main" => root.add_file(parse_main_file(node)?), + "Overlay" => root.add_file(parse_overlay_file(node, is_hidden)?), + tag_names::INTERLEAVED => root.add_file(parse_interleaved(node, is_hidden)?), + "Directory" => { is_hidden |= parse_boolean_attribute(&node, attribute_names::HIDDEN)?; let mut new_dir = Directory::new(node.attribute(attribute_names::NAME).unwrap_or_default(), is_hidden); @@ -158,7 +164,7 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), fn parse_split<'a>(who: &'a str, str_opt: Option<&'a str>) -> Result { match str_opt.unwrap_or("0").parse::() { Ok(num) => Ok(num), - Err(error) => Err(Error::from_text(format!("Failed converting \"{}\" option for \"Track\" attribute \"{}\": {}", who, ATTRIBUTE_NAME, error))) + Err(error) => Err(Error::from_text(format!("Failed converting \"{}\" option for \"{}\" attribute \"{}\": {}", who, tag_names::TRACK, ATTRIBUTE_NAME, error))) } } @@ -185,7 +191,7 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), } fn parse_cd_audio(cdda: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { - config.cd_audio_files.push(path_from_node(&cdda, "CD Audio file")?); + config.cd_audio_files.push(CDAudioFile::new(path_from_node(&cdda, "CD Audio file")?, parse_boolean_attribute(&cdda, "align")?)); Ok(()) } diff --git a/src/Tools/psxcdgen_ex/src/lib.rs b/src/Tools/psxcdgen_ex/src/lib.rs index e8dfb484..53b0996c 100644 --- a/src/Tools/psxcdgen_ex/src/lib.rs +++ b/src/Tools/psxcdgen_ex/src/lib.rs @@ -7,7 +7,7 @@ pub mod types; use crate::types::RawData; use cdtypes::types::sector::AudioSample; -use config_reader::LZ4State; +use config_reader::{CDAudioFile, LZ4State}; use encoder::{cd::{self, calculate_lbas, calculate_length_for}, SizeInfo}; use tool_helper::{format_if_error, Output, read_file}; use types::{layout::Layout, CDDATrack, CDDesc, Directory, File, FileType, FileSystemMap, Properties, SharedPtr}; @@ -204,7 +204,7 @@ fn parse_configuration(config: config_reader::Configuration) -> Result<(CDDesc, Ok(()) } - fn parse_cd_da(cd_da_tracks: &mut Vec, cd_da_files: Vec) -> Result<(), Error> { + fn parse_cd_da(cd_da_tracks: &mut Vec, cd_da_files: Vec) -> Result<(), Error> { fn convert_into_16(samples: hound::WavSamples, file_path: &PathBuf) -> Result, Error> { let mut sample_buffer = 0; let mut sample_id = 0; @@ -233,18 +233,18 @@ fn parse_configuration(config: config_reader::Configuration) -> Result<(CDDesc, } for cd_da_file in cd_da_files { - let mut audio_io = hound::WavReader::open(&cd_da_file)?; + let mut audio_io = hound::WavReader::open(&cd_da_file.file_path)?; let header = audio_io.spec(); if header.sample_format != hound::SampleFormat::Int { - return Err(Error::from_text(format!("{}: Only integer WAV format (PCM) is supported for Audio tracks", cd_da_file.display()))); + return Err(Error::from_text(format!("{}: Only integer WAV format (PCM) is supported for Audio tracks", cd_da_file.file_path.display()))); } if header.sample_rate != 44_100 { - return Err(Error::from_text(format!("{}: Only a sampling rate of 44.1kHz is supported for Audio tracks", cd_da_file.display()))); + return Err(Error::from_text(format!("{}: Only a sampling rate of 44.1kHz is supported for Audio tracks", cd_da_file.file_path.display()))); } - cd_da_tracks.push(CDDATrack::new(convert_into_16(audio_io.samples::(), &cd_da_file)?, false)); + cd_da_tracks.push(CDDATrack::new(convert_into_16(audio_io.samples::(), &cd_da_file.file_path)?, cd_da_file.align)); } Ok(()) }