diff --git a/src/Tools/cdtypes/src/types/time.rs b/src/Tools/cdtypes/src/types/time.rs index c818c758..ada18a65 100644 --- a/src/Tools/cdtypes/src/types/time.rs +++ b/src/Tools/cdtypes/src/types/time.rs @@ -25,6 +25,10 @@ impl Time { Time{minute: 0, second: 2, sector: 0} } + pub const fn from_mss(minute: u8, second: u8, sector: u8) -> Time { + Time{minute, second, sector} + } + pub fn add_sectors(&mut self, sector: usize) -> Result<(), Error> { let sector = self.sector as usize + sector; let second = self.second as usize + (sector/Self::MAX_SECTORS); diff --git a/src/Tools/psxcdgen_ex/src/config_reader/mod.rs b/src/Tools/psxcdgen_ex/src/config_reader/mod.rs index a6ff6481..4d49eb5c 100644 --- a/src/Tools/psxcdgen_ex/src/config_reader/mod.rs +++ b/src/Tools/psxcdgen_ex/src/config_reader/mod.rs @@ -9,15 +9,16 @@ pub enum LZ4State { } pub struct Configuration { - pub publisher: Option, - pub license_path: Option, - pub root: Directory, - pub cd_audio_files: Vec, + pub publisher: Option, + pub license_path: Option, + pub root: Directory, + pub cd_audio_files: Vec, + pub lead_out_sectors: Option, } impl Configuration { pub fn new() -> Configuration { - Configuration{publisher: None, license_path: None, root: Directory::new("root", false), cd_audio_files: Vec::new()} + Configuration{publisher: None, license_path: None, root: Directory::new("root", false), cd_audio_files: Vec::new(), lead_out_sectors: None} } } diff --git a/src/Tools/psxcdgen_ex/src/config_reader/xml.rs b/src/Tools/psxcdgen_ex/src/config_reader/xml.rs index 2e8e84bc..32e25fe4 100644 --- a/src/Tools/psxcdgen_ex/src/config_reader/xml.rs +++ b/src/Tools/psxcdgen_ex/src/config_reader/xml.rs @@ -1,5 +1,6 @@ +use cdtypes::types::time::Time; use std::path::PathBuf; -use tool_helper::{format_if_error, path_with_env_from, string_with_env_from}; +use tool_helper::{format_if_error, path_with_env_from, print_warning, string_with_env_from}; use crate::config_reader::Directory; use super::{CommonProperties, Configuration, Error, File, FileKind, LZ4State}; @@ -27,11 +28,23 @@ pub fn parse(xml: String) -> Result { } fn parse_iso_project(iso_project: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { + let mut parsed_track = false; + for node in iso_project.children() { if node.is_element() { match node.tag_name().name() { "Description" => parse_description(node, config), - "Track" => parse_track(node, config), + "Track" => { + if !parsed_track { + parsed_track = true; + parse_track(node, config) + } + + else { + print_warning("Found more than 1 track. Track will be ignored".to_owned()); + Ok(()) + } + }, "CD_Audio" => parse_cd_audio(node, config), _ => Ok(()) }?; @@ -125,6 +138,38 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), Ok(()) } + fn get_lead_out_sectors(track: roxmltree::Node) -> Result, Error> { + const ATTRIBUTE_NAME:&'static str = "lead-out"; + const MIN_OPTION_NAME:&'static str = "minutes"; + const SECOND_OPTION_NAME:&'static str = "seconds"; + const SECTOR_OPTION_NAME:&'static str = "sectors"; + + 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))) + } + } + + //--------------------------------------------------------------------- + + if let Some(length_str) = track.attribute(ATTRIBUTE_NAME) { + let mut pieces = length_str.split(':'); + let (mins, seconds, sectors) = ( + parse_split(MIN_OPTION_NAME, pieces.next())?, + parse_split(SECOND_OPTION_NAME, pieces.next())?, + parse_split(SECTOR_OPTION_NAME, pieces.next())? + ); + + Ok(Some(Time::from_mss(mins, seconds, sectors).as_sectors())) + } + + else { + Ok(None) + } + } + + config.lead_out_sectors = get_lead_out_sectors(track)?; parse_file_system(track, &mut config.root, false) } diff --git a/src/Tools/psxcdgen_ex/src/encoder/psx.rs b/src/Tools/psxcdgen_ex/src/encoder/psx.rs index bd0c18b6..2d8e0f6d 100644 --- a/src/Tools/psxcdgen_ex/src/encoder/psx.rs +++ b/src/Tools/psxcdgen_ex/src/encoder/psx.rs @@ -121,11 +121,7 @@ pub fn encode_psx_image(cd_desc: &CDDesc, sec_writer: &mut dyn SectorWriter) -> fn process_system_area(system_area: &SystemArea, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { fn write_license_file(sec_writer: &mut dyn SectorWriter, mut license_file: BufferedInputFile) -> Result<(), Error> { fn write_data_zeros(sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - for _ in 0..4 { - sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?; - } - - Ok(()) + write_dummy(sec_writer, 4) } fn write_license_string(sec_writer: &mut dyn SectorWriter, license_file: &mut BufferedInputFile) -> Result<(), Error> { @@ -206,11 +202,7 @@ fn process_system_area(system_area: &SystemArea, sec_writer: &mut dyn SectorWrit else { // No license specified - filling it with zeros print_warning("WARNING: No license file provided. Some emulators (like No$PSX) will not boot this CD.".to_owned()); - for _ in 0..SYSTEM_AREA_SECTOR_COUNT { - sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?; - } - - Ok(()) + write_dummy(sec_writer, SYSTEM_AREA_SECTOR_COUNT) } } @@ -323,11 +315,7 @@ fn process_directory_record(dir: &Directory, sec_writer: &mut dyn SectorWriter) } let extended_sector_count = sector_count_mode2_form1(dir.properties.borrow().get_padded_size()) - dir_record_sector_count; - for _ in 0..extended_sector_count { - sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?; - } - - Ok(()) + write_dummy(sec_writer, extended_sector_count) } fn process_file(file: &File, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { @@ -340,11 +328,7 @@ fn process_file(file: &File, sec_writer: &mut dyn SectorWriter) -> Result<(), Er } let extended_sector_count = sector_count_mode2_form1(padded_size) - content_sector_count; - for _ in 0..extended_sector_count { - sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?; - } - - Ok(()) + write_dummy(sec_writer, extended_sector_count) } fn process_cd_xa_file(content: &Vec, sec_writer: &mut dyn SectorWriter, padded_size: usize) -> Result<(), Error> { @@ -370,21 +354,24 @@ fn process_file(file: &File, sec_writer: &mut dyn SectorWriter) -> Result<(), Er } match &file.content { - FileType::Regular(raw) => process_regular_file(raw, sec_writer, file.properties.get_padded_size()), - FileType::XAAudio(raw) => process_cd_xa_file(raw, sec_writer, file.properties.get_padded_size()), - FileType::Main(_, _) => Err(Error::from_str("Trying to encode an unprocessed main file")), - FileType::Overlay(_, _) => Err(Error::from_str("Trying to encode an unprocessed overlay file")), + FileType::Regular(raw) => process_regular_file(raw, sec_writer, file.properties.get_padded_size()), + FileType::XAAudio(raw) => process_cd_xa_file(raw, sec_writer, file.properties.get_padded_size()), + FileType::Main(_, _) => Err(Error::from_str("Trying to encode an unprocessed main file")), + FileType::Overlay(_, _) => Err(Error::from_str("Trying to encode an unprocessed overlay file")), } } -fn process_end_dummy_section(padding: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - for _ in 0..sector_count_mode2_form1(padding) { +fn write_dummy(sec_writer: &mut dyn SectorWriter, sectors: usize) -> Result<(), Error> { + for _ in 0..sectors { sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?; } - Ok(()) } +fn process_end_dummy_section(padding: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + write_dummy(sec_writer, sector_count_mode2_form1(padding)) +} + fn process_cd_da(cd_da_tracks: &Vec>, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { for cd_da_track in cd_da_tracks { sec_writer.cd_da_start()?; diff --git a/src/Tools/psxcdgen_ex/src/types/mod.rs b/src/Tools/psxcdgen_ex/src/types/mod.rs index b32b68b0..af17414a 100644 --- a/src/Tools/psxcdgen_ex/src/types/mod.rs +++ b/src/Tools/psxcdgen_ex/src/types/mod.rs @@ -24,6 +24,7 @@ pub struct CDDesc { pub(super) root: SharedPtr, pub(super) cd_da_tracks: Vec>, pub(super) vol_sector_count: usize, + pub(super) lead_out_sectors: Option, pub(super) end_dummy_padding: usize } @@ -37,6 +38,7 @@ impl CDDesc { root: new_shared_ptr(root), cd_da_tracks: Vec::new(), vol_sector_count: 0, + lead_out_sectors: None, end_dummy_padding: 0 }, Err(error) => panic!("Creating root directory failed with: {}", error)