Prepare to support enconding of LZ4
This commit is contained in:
parent
a2c7af2e12
commit
1dd145abea
|
@ -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<String>,
|
||||
pub license_path: Option<PathBuf>,
|
||||
|
@ -17,6 +23,7 @@ impl Configuration {
|
|||
pub struct CommonProperties {
|
||||
pub name: String,
|
||||
pub is_hidden: bool,
|
||||
pub lz4_state: LZ4State,
|
||||
pub padded_size: Option<usize>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Configuration, Error> {
|
||||
|
@ -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<File, Error> {
|
||||
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<File, Error> {
|
||||
fn parse_main_file(file: roxmltree::Node) -> Result<File, Error> {
|
||||
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<File, Error> {
|
||||
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<CommonProperties, Error> {
|
||||
fn read_common_properties(xml: &roxmltree::Node, is_hidden: bool, force_lz4_state: Option<LZ4State>) -> Result<CommonProperties, Error> {
|
||||
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)?
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -316,7 +316,8 @@ pub struct Properties {
|
|||
pub(super) lba: LBA,
|
||||
pub(super) size_bytes: usize,
|
||||
pub(super) padded_size_bytes: Option<usize>,
|
||||
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}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<File, Error> {
|
||||
let content = read_file(&file_path)?;
|
||||
pub fn load_from(file_name: &str, file_path: &PathBuf, lba_source: PathBuf) -> Result<File, Error> {
|
||||
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<u8>, 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<u8>, lba_names: &LBANameVec, file_map: &
|
|||
pub fn update_content_for_main(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<Vec<u8>, 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<F: FnMut(usize, (usize, usize)) -> Result<(), Error>>(lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction, mut functor: F) -> Result<(), Error> {
|
||||
fn for_each_lba_name<F: FnMut(usize, (usize, usize), bool) -> 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue