From c2eb47cca0300b9ecaae69473f03539a9e1e4662 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Tue, 8 Jul 2025 21:44:51 -0400 Subject: [PATCH] Port the useful Excel API from SqPackResource to Resource --- examples/extractor.rs | 4 +-- src/resource/mod.rs | 53 +++++++++++++++++++++++++++++++- src/resource/sqpack.rs | 68 +----------------------------------------- 3 files changed, 55 insertions(+), 70 deletions(-) diff --git a/examples/extractor.rs b/examples/extractor.rs index e0dc553..1655f70 100644 --- a/examples/extractor.rs +++ b/examples/extractor.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later use physis::common::Platform; -use physis::resource::SqPackResource; +use physis::resource::{Resource, SqPackResource}; use std::env; use std::fs::File; use std::io::Write; @@ -24,7 +24,7 @@ fn main() { let mut game_data = SqPackResource::from_existing(Platform::Win32, game_dir); // Extract said file: - let Some(game_file) = game_data.extract(file_path) else { + let Some(game_file) = game_data.read(file_path) else { println!("File {} not found!", file_path); return; }; diff --git a/src/resource/mod.rs b/src/resource/mod.rs index e2ba470..01b1fcd 100644 --- a/src/resource/mod.rs +++ b/src/resource/mod.rs @@ -7,7 +7,7 @@ pub use sqpack::SqPackResource; mod unpacked; pub use unpacked::UnpackedResource; -use crate::ByteBuffer; +use crate::{ByteBuffer, common::Language, exd::EXD, exh::EXH, exl::EXL}; /// Represents a source of files for reading. /// This abstracts away some of the nitty-gritty of where files come from. These could be coming from a compressed archive like SqPack, unpacked files on disk, or even a network. @@ -46,3 +46,54 @@ pub trait Resource { /// ``` fn exists(&mut self, path: &str) -> bool; } + +/// Read an excel sheet by name (e.g. "Achievement") +pub fn read_excel_sheet_header(resource: &mut T, name: &str) -> Option { + let root_exl_file = resource.read("exd/root.exl")?; + + let root_exl = EXL::from_existing(&root_exl_file)?; + + for (row, _) in root_exl.entries { + if row == name { + let new_filename = name.to_lowercase(); + + let path = format!("exd/{new_filename}.exh"); + + return EXH::from_existing(&resource.read(&path)?); + } + } + + None +} + +/// Returns all known sheet names listed in the root list +pub fn get_all_sheet_names(resource: &mut T) -> Option> { + let root_exl_file = resource.read("exd/root.exl")?; + + let root_exl = EXL::from_existing(&root_exl_file)?; + + let mut names = vec![]; + for (row, _) in root_exl.entries { + names.push(row); + } + + Some(names) +} + +/// Read an excel sheet +pub fn read_excel_sheet( + resource: &mut T, + name: &str, + exh: &EXH, + language: Language, + page: usize, +) -> Option { + let exd_path = format!( + "exd/{}", + EXD::calculate_filename(name, language, &exh.pages[page]) + ); + + let exd_file = resource.read(&exd_path)?; + + EXD::from_existing(exh, &exd_file) +} diff --git a/src/resource/sqpack.rs b/src/resource/sqpack.rs index 2e5dfa5..7c74564 100644 --- a/src/resource/sqpack.rs +++ b/src/resource/sqpack.rs @@ -6,10 +6,7 @@ use std::{ use crate::{ ByteBuffer, - common::{Language, Platform, read_version}, - exd::EXD, - exh::EXH, - exl::EXL, + common::{Platform, read_version}, patch::{PatchError, ZiPatch}, repository::{Category, Repository, string_to_category}, sqpack::{IndexEntry, SqPackData, SqPackIndex}, @@ -118,18 +115,6 @@ impl SqPackResource { SqPackData::from_existing(dat_path.to_str()?) } - pub fn extract(&mut self, path: &str) -> Option { - let slice = self.find_entry(path); - match slice { - Some((entry, chunk)) => { - let mut dat_file = self.get_dat_file(path, chunk, entry.data_file_id.into())?; - - dat_file.read_from_offset(entry.offset) - } - None => None, - } - } - /// Finds the offset inside of the DAT file for `path`. pub fn find_offset(&mut self, path: &str) -> Option { let slice = self.find_entry(path); @@ -188,57 +173,6 @@ impl SqPackResource { Some(index_filenames) } - /// Read an excel sheet by name (e.g. "Achievement") - pub fn read_excel_sheet_header(&mut self, name: &str) -> Option { - let root_exl_file = self.extract("exd/root.exl")?; - - let root_exl = EXL::from_existing(&root_exl_file)?; - - for (row, _) in root_exl.entries { - if row == name { - let new_filename = name.to_lowercase(); - - let path = format!("exd/{new_filename}.exh"); - - return EXH::from_existing(&self.extract(&path)?); - } - } - - None - } - - /// Returns all known sheet names listed in the root list - pub fn get_all_sheet_names(&mut self) -> Option> { - let root_exl_file = self.extract("exd/root.exl")?; - - let root_exl = EXL::from_existing(&root_exl_file)?; - - let mut names = vec![]; - for (row, _) in root_exl.entries { - names.push(row); - } - - Some(names) - } - - /// Read an excel sheet - pub fn read_excel_sheet( - &mut self, - name: &str, - exh: &EXH, - language: Language, - page: usize, - ) -> Option { - let exd_path = format!( - "exd/{}", - EXD::calculate_filename(name, language, &exh.pages[page]) - ); - - let exd_file = self.extract(&exd_path)?; - - EXD::from_existing(exh, &exd_file) - } - /// Applies the patch to game data and returns any errors it encounters. This function will not update the version in the GameData struct. pub fn apply_patch(&self, patch_path: &str) -> Result<(), PatchError> { ZiPatch::apply(&self.game_directory, patch_path)