From 1dd145abeaa369f8814721502bf6c594cbb12f1d Mon Sep 17 00:00:00 2001 From: Jaby Date: Thu, 13 Apr 2023 21:06:24 +0200 Subject: [PATCH] Prepare to support enconding of LZ4 --- .../psxcdgen_ex/src/config_reader/mod.rs | 7 ++++ .../psxcdgen_ex/src/config_reader/xml.rs | 39 +++++++++++++++---- src/Tools/psxcdgen_ex/src/lib.rs | 15 +++++-- src/Tools/psxcdgen_ex/src/types/mod.rs | 5 ++- .../psxcdgen_ex/src/types/overlay/mod.rs | 22 ++++++----- 5 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/Tools/psxcdgen_ex/src/config_reader/mod.rs b/src/Tools/psxcdgen_ex/src/config_reader/mod.rs index e497e2a7..566db654 100644 --- a/src/Tools/psxcdgen_ex/src/config_reader/mod.rs +++ b/src/Tools/psxcdgen_ex/src/config_reader/mod.rs @@ -2,6 +2,12 @@ use super::Error; use std::path::PathBuf; mod xml; +pub enum LZ4State { + None, + AlreadyCompressed, + Compress, +} + pub struct Configuration { pub publisher: Option, pub license_path: Option, @@ -17,6 +23,7 @@ impl Configuration { pub struct CommonProperties { pub name: String, pub is_hidden: bool, + pub lz4_state: LZ4State, pub padded_size: Option, } diff --git a/src/Tools/psxcdgen_ex/src/config_reader/xml.rs b/src/Tools/psxcdgen_ex/src/config_reader/xml.rs index 9f6c49bc..991e7eb8 100644 --- a/src/Tools/psxcdgen_ex/src/config_reader/xml.rs +++ b/src/Tools/psxcdgen_ex/src/config_reader/xml.rs @@ -2,13 +2,14 @@ use std::path::PathBuf; use tool_helper::{format_if_error, path_with_env_from}; use crate::config_reader::Directory; -use super::{CommonProperties, Configuration, Error, File, FileKind}; +use super::{CommonProperties, Configuration, Error, File, FileKind, LZ4State}; mod attribute_names { pub const NAME: &'static str = "name"; pub const HIDDEN: &'static str = "hidden"; pub const PADDED_SIZE: &'static str = "padded_size"; pub const LBA_SOURCE: &'static str = "lba_source"; + pub const LZ4_STATE: &'static str = "lz4"; } pub fn parse(xml: String) -> Result { @@ -57,27 +58,28 @@ fn parse_description(description: roxmltree::Node, config: &mut Configuration) - fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { fn parse_regular_file(file: roxmltree::Node, is_hidden: bool) -> Result { - let common = read_common_properties(&file, is_hidden)?; + let common = read_common_properties(&file, is_hidden, None)?; let path = path_from_node(&file, &common.name)?; Ok(File{common, path, kind: FileKind::Regular}) } - fn parse_main_file(file: roxmltree::Node, is_hidden: bool) -> Result { + fn parse_main_file(file: roxmltree::Node) -> Result { if let Some(lba_path) = file.attribute(attribute_names::LBA_SOURCE) { - let common = read_common_properties(&file, is_hidden)?; + let common = read_common_properties(&file, false, Some(LZ4State::None))?; let path = path_from_node(&file, &common.name)?; Ok(File{common, path, kind: FileKind::Main(PathBuf::from(lba_path))}) } else { - parse_regular_file(file, is_hidden) + parse_regular_file(file, false) } } fn parse_overlay_file(file: roxmltree::Node, is_hidden: bool) -> Result { - let common = read_common_properties(&file, is_hidden)?; + // v they will be compressed automatically + let common = read_common_properties(&file, is_hidden, Some(LZ4State::AlreadyCompressed))?; let path = path_from_node(&file, &common.name)?; Ok(File{common, path, kind: FileKind::Overlay(PathBuf::from(file.attribute(attribute_names::LBA_SOURCE).unwrap_or_default()))}) @@ -88,7 +90,7 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), 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, is_hidden)?), + "Main" => root.add_file(parse_main_file(node)?), "Overlay" => root.add_file(parse_overlay_file(node, is_hidden)?), "Directory" => { is_hidden |= parse_boolean_attribute(&node, attribute_names::HIDDEN)?; @@ -108,10 +110,31 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), parse_file_system(track, &mut config.root, false) } -fn read_common_properties(xml: &roxmltree::Node, is_hidden: bool) -> Result { +fn read_common_properties(xml: &roxmltree::Node, is_hidden: bool, force_lz4_state: Option) -> Result { + let lz4_state = { + if let Some(forced_lz4_state) = force_lz4_state { + forced_lz4_state + } + + else { + if let Some(state_str) = xml.attribute(attribute_names::LZ4_STATE) { + match state_str.to_lowercase().as_str() { + "yes" => LZ4State::Compress, + "already" => LZ4State::AlreadyCompressed, + _ => LZ4State::None, + } + } + + else { + LZ4State::None + } + } + }; + Ok(CommonProperties{ name: String::from(xml.attribute(attribute_names::NAME).unwrap_or_default()), is_hidden: is_hidden | parse_boolean_attribute(&xml, attribute_names::HIDDEN)?, + lz4_state, padded_size: read_padded_size(&xml)? }) } diff --git a/src/Tools/psxcdgen_ex/src/lib.rs b/src/Tools/psxcdgen_ex/src/lib.rs index 388478f1..028acab7 100644 --- a/src/Tools/psxcdgen_ex/src/lib.rs +++ b/src/Tools/psxcdgen_ex/src/lib.rs @@ -5,6 +5,7 @@ pub mod encoder; pub mod file_writer; pub mod types; +use config_reader::LZ4State; use encoder::{LbaCalculatorFunction, LengthCalculatorFunction}; use tool_helper::{format_if_error, Output, read_file}; use types::{layout::Layout, CDDesc, Directory, File, FileType, FileSystemMap, Properties, SharedPtr}; @@ -158,15 +159,23 @@ fn parse_configuration(config: config_reader::Configuration) -> Result<(CDDesc, config_reader::DirMember::File(file) => { let (mut desc_file, needs_treatment) = { match file.kind { - config_reader::FileKind::Regular => (types::File::new_regular(file.common.name.as_str(), read_file(&file.path)?)?, false), - config_reader::FileKind::Main(lba_source) => (types::overlay::load_for_main(file.common.name.as_str(), read_file(&file.path)?, lba_source)?, true), - config_reader::FileKind::Overlay(lba_source) => (types::overlay::load_from(file.common.name.as_str(), file.path, lba_source)?, true), + config_reader::FileKind::Regular => (types::File::new_regular(file.common.name.as_str(), read_file(&file.path)?)?, false), + config_reader::FileKind::Main(lba_source) => (types::overlay::load_for_main(file.common.name.as_str(), read_file(&file.path)?, lba_source)?, true), + config_reader::FileKind::Overlay(lba_source) => (types::overlay::load_from(file.common.name.as_str(), &file.path, lba_source)?, true), } }; desc_file.properties.padded_size_bytes = file.common.padded_size; desc_file.properties.is_hidden = file.common.is_hidden; + match file.common.lz4_state { + LZ4State::None => desc_file.properties.is_lz4 = false, + LZ4State::AlreadyCompressed => desc_file.properties.is_lz4 = true, + LZ4State::Compress => { + return Err(Error::from_text(format!("LZ4 compression requested for file {} but feature is not supported yet", &file.path.to_string_lossy()))); + } + } + let new_file = dst_dir.add_file(desc_file); if needs_treatment { lba_embedded_files.push(new_file); diff --git a/src/Tools/psxcdgen_ex/src/types/mod.rs b/src/Tools/psxcdgen_ex/src/types/mod.rs index 60023c9e..a25af325 100644 --- a/src/Tools/psxcdgen_ex/src/types/mod.rs +++ b/src/Tools/psxcdgen_ex/src/types/mod.rs @@ -316,7 +316,8 @@ pub struct Properties { pub(super) lba: LBA, pub(super) size_bytes: usize, pub(super) padded_size_bytes: Option, - pub(super) is_hidden: bool + pub(super) is_hidden: bool, + pub(super) is_lz4: bool, } impl Properties { @@ -341,7 +342,7 @@ impl Properties { impl Default for Properties { fn default() -> Self { - Properties{lba: LBA::default(), size_bytes: 0, padded_size_bytes: None, is_hidden: false} + Properties{lba: LBA::default(), size_bytes: 0, padded_size_bytes: None, is_hidden: false, is_lz4: false} } } diff --git a/src/Tools/psxcdgen_ex/src/types/overlay/mod.rs b/src/Tools/psxcdgen_ex/src/types/overlay/mod.rs index 6bca45e0..140e7824 100644 --- a/src/Tools/psxcdgen_ex/src/types/overlay/mod.rs +++ b/src/Tools/psxcdgen_ex/src/types/overlay/mod.rs @@ -23,7 +23,7 @@ impl LBAEntry { const _IS_LZ4_COMPRESSED:Bit = Bit::at(19); const LBA_VALUE_RANGE:BitRange = BitRange::from_to(0, 18); - pub fn write_entry(&mut self, lba: usize, size_bytes: usize) -> Result<(), Error> { + pub fn write_entry(&mut self, lba: usize, size_bytes: usize, _is_lz4: bool) -> Result<(), Error> { if lba > Self::LBA_VALUE_RANGE.max_value() { return Err(Error::from_text(format!("LBA of value {} is impossible and can not be encoded! Maximum LBA value is: {}", lba, Self::LBA_VALUE_RANGE.max_value()))); } @@ -45,8 +45,8 @@ impl LBAEntry { } } -pub fn load_from(file_name: &str, file_path: PathBuf, lba_source: PathBuf) -> Result { - let content = read_file(&file_path)?; +pub fn load_from(file_name: &str, file_path: &PathBuf, lba_source: PathBuf) -> Result { + let content = read_file(file_path)?; let lba_names = load_lba_names(lba_source)?; let content_size = format_if_error!(tool_helper::compress::psx_default::lz4(&content), "Compressing {} failed with \"{error_text}\"", file_path.to_string_lossy())?.len(); @@ -61,8 +61,8 @@ pub fn update_content(content: &mut Vec, lba_names: &LBANameVec, file_map: & let lba_header = skip_to_lba_header(content); let lba_header = unsafe{std::slice::from_raw_parts_mut(lba_header.as_mut_ptr() as *mut LBAEntry, lba_names.len())}; - for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes)| { - lba_header[idx].write_entry(lba, bytes) + for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes), is_lz4| { + lba_header[idx].write_entry(lba, bytes, is_lz4) })?; Ok(tool_helper::compress::psx_default::lz4(content)?) @@ -71,20 +71,22 @@ pub fn update_content(content: &mut Vec, lba_names: &LBANameVec, file_map: & pub fn update_content_for_main(content: &mut Vec, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result, Error> { let lba_header = unsafe{std::slice::from_raw_parts_mut(main::skip_to_lba_area(content).as_mut_ptr() as *mut LBAEntry, lba_names.len())}; - for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes)| { - lba_header[idx].write_entry(lba, bytes) + for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes), is_lz4| { + lba_header[idx].write_entry(lba, bytes, is_lz4) })?; Ok(content.clone()) } -fn for_each_lba_name Result<(), Error>>(lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction, mut functor: F) -> Result<(), Error> { +fn for_each_lba_name Result<(), Error>>(lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction, mut functor: F) -> Result<(), Error> { let mut idx = 0; for lba_name in lba_names { if let Some(file) = file_map.get(lba_name) { - let (lba, bytes) = (format_if_error_drop_cause!(file.try_borrow(), "Failed accessing file \"{}\" for writing LBA information.\nNote: You can not inject the LBA information of a file into itself.", lba_name)?.get_absolute_lba(), length_func(&Layout::File(file.clone())).bytes); + let file_ref = format_if_error_drop_cause!(file.try_borrow(), "Failed accessing file \"{}\" for writing LBA information.\nNote: You can not inject the LBA information of a file into itself.", lba_name)?; + let (lba, bytes) = (file_ref.get_absolute_lba(), length_func(&Layout::File(file.clone())).bytes); + let is_lz4 = file_ref.properties.is_lz4; - functor(idx, (lba, bytes.ok_or(Error::from_text(format!("{} does not contain a size!", lba_name)))?))?; + functor(idx, (lba, bytes.ok_or(Error::from_text(format!("{} does not contain a size!", lba_name)))?), is_lz4)?; idx += 1; }