diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 3e71d96..7f047c9 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -95,7 +95,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -172,9 +172,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block" @@ -434,6 +434,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -574,7 +586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -584,7 +596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -608,7 +620,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -619,7 +631,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -734,6 +746,12 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -818,9 +836,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -931,7 +949,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -1152,6 +1170,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "glam" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" + [[package]] name = "glib" version = "0.15.12" @@ -1596,6 +1620,18 @@ dependencies = [ "cfb", ] +[[package]] +name = "insta" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "similar", +] + [[package]] name = "instant" version = "0.1.12" @@ -1786,6 +1822,24 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "league-toolkit" +version = "0.1.0" +source = "git+https://github.com/LeagueToolkit/league-toolkit?branch=main#72b8e1280695e102b13ae28e4d1e0caa5b4710cb" +dependencies = [ + "bitflags 2.6.0", + "byteorder", + "flate2", + "glam", + "insta", + "lazy_static", + "log", + "memchr", + "num_enum 0.7.2", + "thiserror", + "zstd 0.13.2", +] + [[package]] name = "libc" version = "0.2.151" @@ -1798,7 +1852,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "libc", "redox_syscall", ] @@ -1812,6 +1866,12 @@ dependencies = [ "safemem", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.12" @@ -1830,9 +1890,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "loom" @@ -1909,9 +1969,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -2100,11 +2160,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.7.1", + "num_enum_derive 0.7.2", ] [[package]] @@ -2121,14 +2181,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -2192,8 +2252,9 @@ dependencies = [ "indexmap 2.1.0", "itertools", "lazy_static", + "league-toolkit", "memchr", - "num_enum 0.7.1", + "num_enum 0.7.2", "octocrab", "open 5.0.1", "parking_lot", @@ -2212,7 +2273,7 @@ dependencies = [ "uuid", "walkdir", "xxhash-rust", - "zstd", + "zstd 0.12.4", ] [[package]] @@ -2285,7 +2346,7 @@ version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -2302,7 +2363,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -2509,7 +2570,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -2556,7 +2617,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -2674,9 +2735,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -2692,9 +2753,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -2960,7 +3021,7 @@ version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -3146,7 +3207,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -3178,7 +3239,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -3228,7 +3289,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -3289,6 +3350,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "similar" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" + [[package]] name = "simple_asn1" version = "0.6.2" @@ -3465,9 +3532,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", @@ -3740,7 +3807,7 @@ version = "0.1.0" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#4aa61dcc9e9abcfba5709cca9770f08aa578a3e3" dependencies = [ "bincode", - "bitflags 2.4.1", + "bitflags 2.6.0", "log", "serde", "serde_json", @@ -3862,22 +3929,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" [[package]] name = "thiserror" -version = "1.0.51" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.51" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -4096,7 +4163,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "bytes", "futures-core", "futures-util", @@ -4155,7 +4222,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", ] [[package]] @@ -4397,7 +4464,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", "wasm-bindgen-shared", ] @@ -4431,7 +4498,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.70", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5070,7 +5137,16 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" dependencies = [ - "zstd-safe", + "zstd-safe 6.0.6", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe 7.2.0", ] [[package]] @@ -5083,11 +5159,20 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.12+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" dependencies = [ "cc", "pkg-config", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 9294618..8a600e5 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -24,7 +24,7 @@ serde_json = "1.0" byteorder = "1.4.3" thiserror = "1.0.49" num_enum = "0.7.0" -flate2 = "1.0" +flate2 = "1.0.30" zstd = "0.12.4" tracing = "0.1.37" tracing-subscriber = "0.3.17" @@ -47,6 +47,7 @@ chrono = { version = "0.4.31", features = ["std", "clock"] } tracing-appender = "0.2.3" lazy_static = "1.4.0" fst = { version = "0.4.7", features = ['levenshtein'] } +league-toolkit = { git = "https://github.com/LeagueToolkit/league-toolkit", branch = "main" } [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/src-tauri/src/api/wad/commands.rs b/src-tauri/src/api/wad/commands.rs index df491fc..0ee1397 100644 --- a/src-tauri/src/api/wad/commands.rs +++ b/src-tauri/src/api/wad/commands.rs @@ -2,6 +2,7 @@ mod extract_wad_items; mod search_wad; pub use extract_wad_items::*; +use league_toolkit::core::wad::Wad; pub use search_wad::*; use super::{ @@ -11,10 +12,7 @@ use crate::core::wad; use crate::core::wad::tree::{WadTree, WadTreeItem}; use crate::{ api::error::ApiError, - core::wad::{ - tree::{WadTreeParent, WadTreePathable, WadTreeSelectable}, - Wad, - }, + core::wad::tree::{WadTreeParent, WadTreePathable, WadTreeSelectable}, state::{MountedWadsState, SettingsState, WadHashtableState}, utils::actions::emit_action_progress, }; diff --git a/src-tauri/src/api/wad/commands/extract_wad_items.rs b/src-tauri/src/api/wad/commands/extract_wad_items.rs index f7a2af0..25023bb 100644 --- a/src-tauri/src/api/wad/commands/extract_wad_items.rs +++ b/src-tauri/src/api/wad/commands/extract_wad_items.rs @@ -1,15 +1,13 @@ -use std::iter; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::str::FromStr; -use color_eyre::eyre::{eyre, Context, ContextCompat}; +use color_eyre::eyre::{Context, ContextCompat}; use itertools::Itertools; -use tauri::Manager; use uuid::Uuid; use crate::api::wad::commands::ApiError; -use crate::core::wad::tree::{WadTreeItem, WadTreeParent, WadTreePathable}; -use crate::core::wad::{self, WadChunk}; +use crate::core::wad::tree::{WadTreeItem, WadTreePathable}; +use crate::core::wad::{self}; use crate::state::SettingsState; use crate::utils::actions::emit_action_progress; use crate::{MountedWadsState, WadHashtableState}; diff --git a/src-tauri/src/api/wad/commands/search_wad.rs b/src-tauri/src/api/wad/commands/search_wad.rs index 1366fdb..461b281 100644 --- a/src-tauri/src/api/wad/commands/search_wad.rs +++ b/src-tauri/src/api/wad/commands/search_wad.rs @@ -3,6 +3,7 @@ use std::{collections::HashMap, str, sync::Arc}; use color_eyre::eyre::{Context, ContextCompat}; use fst::{self, IntoStreamer, Streamer}; use itertools::Itertools; +use league_toolkit::core::wad::WadChunk; use uuid::Uuid; use crate::{ @@ -10,10 +11,7 @@ use crate::{ error::ApiError, wad::{guess_file_kind, SearchWadResponse, SearchWadResponseItem}, }, - core::wad::{ - tree::{WadTreeItem, WadTreeParent, WadTreePathable}, - WadChunk, - }, + core::wad::tree::{WadTreeItem, WadTreePathable}, state::{MountedWadsState, WadHashtableState}, }; diff --git a/src-tauri/src/api/wad/mod.rs b/src-tauri/src/api/wad/mod.rs index 6e8a5ee..73d19bf 100644 --- a/src-tauri/src/api/wad/mod.rs +++ b/src-tauri/src/api/wad/mod.rs @@ -1,6 +1,7 @@ mod commands; pub use commands::*; +use league_toolkit::core::wad::WadChunkCompression; use std::path::Path; @@ -9,10 +10,7 @@ use uuid::Uuid; use crate::core::{ league_file::{get_league_file_kind_from_extension, LeagueFileKind}, - wad::{ - tree::{WadTreeDirectory, WadTreeFile, WadTreeItem, WadTreePathable}, - WadChunk, WadChunkCompression, - }, + wad::tree::{WadTreeDirectory, WadTreeFile, WadTreeItem, WadTreePathable}, }; #[derive(Serialize, Deserialize)] diff --git a/src-tauri/src/core/wad/error.rs b/src-tauri/src/core/wad/error.rs deleted file mode 100644 index 70ef65b..0000000 --- a/src-tauri/src/core/wad/error.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::io; - -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum WadError { - #[error("invalid header")] - InvalidHeader { expected: String, actual: String }, - - #[error("invalid version {major:?}.{minor:?}")] - InvalidVersion { major: u8, minor: u8 }, - - #[error("invalid chunk compression: {compression:?}")] - InvalidChunkCompression { compression: u8 }, - - #[error("duplicate chunk: {path_hash:#08x}")] - DuplicateChunk { path_hash: u64 }, - - #[error("failed to decompress chunk (path: {path_hash:#08x}, reason: {reason:?})")] - DecompressionFailure { path_hash: u64, reason: String }, - - #[error("io error")] - IoError(#[from] io::Error), - - #[error("error: `{0}`")] - Other(String), -} diff --git a/src-tauri/src/core/wad/extractor.rs b/src-tauri/src/core/wad/extractor.rs index 976e3af..078926b 100644 --- a/src-tauri/src/core/wad/extractor.rs +++ b/src-tauri/src/core/wad/extractor.rs @@ -1,12 +1,12 @@ use crate::{ - core::{ - league_file::{get_extension_from_league_file_kind, identify_league_file, LeagueFileKind}, - wad::{WadChunk, WadDecoder}, + core::league_file::{ + get_extension_from_league_file_kind, identify_league_file, LeagueFileKind, }, state::WadHashtable, }; use color_eyre::eyre::{self, Ok}; use eyre::Context; +use league_toolkit::core::wad::{WadChunk, WadDecoder}; use std::{ collections::HashMap, ffi::OsStr, diff --git a/src-tauri/src/core/wad/mod.rs b/src-tauri/src/core/wad/mod.rs index 1ce96d4..48cda98 100644 --- a/src-tauri/src/core/wad/mod.rs +++ b/src-tauri/src/core/wad/mod.rs @@ -1,237 +1,5 @@ -use byteorder::{ReadBytesExt, LE}; -use flate2::read::GzDecoder; -use memchr::memmem; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use std::{ - collections::HashMap, - io::{BufReader, Read, Seek, SeekFrom}, - vec, -}; - -mod error; mod extractor; + pub mod tree; -pub use error::*; pub use extractor::*; - -#[derive(Debug)] -pub struct Wad { - chunks: HashMap, - source: TSource, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct WadChunk { - path_hash: u64, - data_offset: usize, - compressed_size: usize, - uncompressed_size: usize, - compression_type: WadChunkCompression, - is_duplicated: bool, - frame_count: u8, - start_frame: u16, - checksum: u64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] -#[repr(u8)] -pub enum WadChunkCompression { - None = 0, - GZip = 1, - Satellite = 2, - Zstd = 3, - ZstdMulti = 4, -} - -const ZSTD_MAGIC: [u8; 4] = [0x28, 0xB5, 0x2F, 0xFD]; - -impl Wad { - pub fn chunks(&self) -> &HashMap { - &self.chunks - } - - pub fn mount(mut source: TSource) -> Result, WadError> { - let mut reader = BufReader::new(&mut source); - - // 0x5752 = "RW" - let magic = reader.read_u16::()?; - if magic != 0x5752 { - return Err(WadError::InvalidHeader { - expected: String::from("RW"), - actual: format!("0x{:x}", magic), - }); - } - - let major = reader.read_u8()?; - let minor = reader.read_u8()?; - if major > 3 { - return Err(WadError::InvalidVersion { major, minor }); - } - - if major == 2 { - let _ecdsa_length = reader.seek(SeekFrom::Current(1))?; - let _ecdsa_signature = reader.seek(SeekFrom::Current(83))?; - let _data_checksum = reader.seek(SeekFrom::Current(8))?; - } else if major == 3 { - let _ecdsa_signature = reader.seek(SeekFrom::Current(256))?; - let _data_checksum = reader.seek(SeekFrom::Current(8))?; - } - - if major == 1 || major == 2 { - let _toc_start_offset = reader.seek(SeekFrom::Current(2))?; - let _toc_chunk_size = reader.seek(SeekFrom::Current(2))?; - } - - let chunk_count = reader.read_i32::()? as usize; - let mut chunks = HashMap::::with_capacity(chunk_count); - for _ in 0..chunk_count { - let chunk = WadChunk::read(&mut reader).expect("failed to read chunk"); - chunks - .insert(chunk.path_hash(), chunk) - .map_or(Ok(()), |chunk| { - Err(WadError::DuplicateChunk { - path_hash: chunk.path_hash(), - }) - })?; - } - - Ok(Wad { chunks, source }) - } - - pub fn decode<'wad>(&'wad mut self) -> (WadDecoder<'wad, TSource>, &HashMap) { - ( - WadDecoder { - source: &mut self.source, - }, - &self.chunks, - ) - } -} - -impl WadChunk { - fn read(reader: &mut BufReader) -> Result { - let path_hash = reader.read_u64::()?; - let data_offset = reader.read_u32::()? as usize; - let compressed_size = reader.read_i32::()? as usize; - let uncompressed_size = reader.read_i32::()? as usize; - - let type_frame_count = reader.read_u8()?; - let frame_count = type_frame_count >> 4; - let compression_type = WadChunkCompression::try_from_primitive(type_frame_count & 0xF) - .expect("failed to read chunk compression"); - - let is_duplicated = reader.read_u8()? == 1; - let start_frame = reader.read_u16::()?; - let checksum = reader.read_u64::()?; - - Ok(WadChunk { - path_hash, - data_offset, - compressed_size, - uncompressed_size, - compression_type, - is_duplicated, - frame_count, - start_frame, - checksum, - }) - } - - pub fn path_hash(&self) -> u64 { - self.path_hash - } - pub fn data_offset(&self) -> usize { - self.data_offset - } - pub fn compressed_size(&self) -> usize { - self.compressed_size - } - pub fn uncompressed_size(&self) -> usize { - self.uncompressed_size - } - pub fn compression_type(&self) -> WadChunkCompression { - self.compression_type - } - pub fn checksum(&self) -> u64 { - self.checksum - } -} - -pub struct WadDecoder<'wad, TSource: Read + Seek> { - source: &'wad mut TSource, -} - -impl<'wad, TSource> WadDecoder<'wad, TSource> -where - TSource: Read + Seek, -{ - pub fn load_chunk_raw(&mut self, chunk: &WadChunk) -> Result, WadError> { - let mut data = vec![0; chunk.compressed_size]; - - self.source - .seek(SeekFrom::Start(chunk.data_offset as u64))?; - self.source.read_exact(&mut data)?; - - Ok(data.into_boxed_slice()) - } - pub fn load_chunk_decompressed(&mut self, chunk: &WadChunk) -> Result, WadError> { - match chunk.compression_type { - WadChunkCompression::None => self.load_chunk_raw(chunk), - WadChunkCompression::GZip => self.decode_gzip_chunk(chunk), - WadChunkCompression::Satellite => Err(WadError::Other(String::from( - "satellite chunks are not supported", - ))), - WadChunkCompression::Zstd => self.decode_zstd_chunk(chunk), - WadChunkCompression::ZstdMulti => self.decode_zstd_multi_chunk(chunk), - } - } - - fn decode_gzip_chunk(&mut self, chunk: &WadChunk) -> Result, WadError> { - self.source - .seek(SeekFrom::Start(chunk.data_offset as u64))?; - - let mut data = vec![0; chunk.uncompressed_size]; - GzDecoder::new(&mut self.source).read_exact(&mut data)?; - - Ok(data.into_boxed_slice()) - } - fn decode_zstd_chunk(&mut self, chunk: &WadChunk) -> Result, WadError> { - self.source - .seek(SeekFrom::Start(chunk.data_offset as u64))?; - - let mut data: Vec = vec![0; chunk.uncompressed_size]; - zstd::Decoder::new(&mut self.source) - .expect("failed to create zstd decoder") - .read_exact(&mut data)?; - - Ok(data.into_boxed_slice()) - } - fn decode_zstd_multi_chunk(&mut self, chunk: &WadChunk) -> Result, WadError> { - let raw_data = self.load_chunk_raw(chunk)?; - let mut data: Vec = vec![0; chunk.uncompressed_size]; - - let zstd_magic_offset = - memmem::find(&raw_data, &ZSTD_MAGIC).ok_or(WadError::DecompressionFailure { - path_hash: chunk.path_hash, - reason: String::from("failed to find zstd magic"), - })?; - - // copy raw uncompressed data which exists before first zstd frame - for (i, value) in raw_data[0..zstd_magic_offset].iter().enumerate() { - data[i] = *value; - } - - // seek to start of first zstd frame - self.source.seek(SeekFrom::Start( - (chunk.data_offset + zstd_magic_offset) as u64, - ))?; - - // decode zstd data - zstd::Decoder::new(&mut self.source) - .expect("failed to create zstd decoder") - .read_exact(&mut data[zstd_magic_offset..])?; - - Ok(data.into_boxed_slice()) - } -} diff --git a/src-tauri/src/core/wad/tree/mod.rs b/src-tauri/src/core/wad/tree/mod.rs index 6d95b27..e6fa039 100644 --- a/src-tauri/src/core/wad/tree/mod.rs +++ b/src-tauri/src/core/wad/tree/mod.rs @@ -1,5 +1,4 @@ use std::{ - clone, collections::HashMap, io::{Read, Seek}, path::{self, Path, PathBuf}, @@ -7,6 +6,7 @@ use std::{ }; use itertools::Itertools; +use league_toolkit::core::wad::{Wad, WadChunk, WadDecoder, WadError}; use thiserror::Error; use tracing::info; use uuid::Uuid; @@ -17,14 +17,11 @@ pub use item::*; use crate::{ core::league_file::{ - get_extension_from_league_file_kind, get_league_file_kind_from_extension, - identify_league_file, LeagueFileKind, + get_extension_from_league_file_kind, identify_league_file, LeagueFileKind, }, state::WadHashtable, }; -use super::{Wad, WadChunk, WadDecoder, WadError}; - #[derive(Error, Debug)] pub enum WadTreeError { #[error("invalid item name (chunk_path: {chunk_path:#0x})")] diff --git a/src-tauri/src/error.rs b/src-tauri/src/error.rs index 99aef24..927724a 100644 --- a/src-tauri/src/error.rs +++ b/src-tauri/src/error.rs @@ -11,7 +11,7 @@ pub enum Error { #[error("http error: {0}")] Http(#[from] reqwest::Error), #[error("wad error: {0}")] - Wad(#[from] crate::core::wad::WadError), + Wad(#[from] league_toolkit::core::wad::WadError), #[error("error: {0}")] Other(#[from] Box), } diff --git a/src-tauri/src/state/mounted_wads.rs b/src-tauri/src/state/mounted_wads.rs index 29a4ea9..2f47b59 100644 --- a/src-tauri/src/state/mounted_wads.rs +++ b/src-tauri/src/state/mounted_wads.rs @@ -1,14 +1,12 @@ use indexmap::IndexMap; +use league_toolkit::core::wad::Wad; use parking_lot::Mutex; use std::{collections::HashMap, fs::File, sync::Arc}; use tracing::info; use uuid::Uuid; -use crate::core::wad::{ - tree::{WadTree, WadTreeError}, - Wad, -}; +use crate::core::wad::tree::{WadTree, WadTreeError}; use super::WadHashtable;