diff --git a/Cargo.lock b/Cargo.lock index c709bb1..fbf4dd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -260,15 +260,6 @@ version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "arboard" version = "3.6.1" @@ -285,7 +276,7 @@ dependencies = [ "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "wl-clipboard-rs", "x11rb", ] @@ -1804,7 +1795,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -2458,17 +2449,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "derive_builder" version = "0.20.2" @@ -2607,7 +2587,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2874,7 +2854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3835,7 +3815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b305d85504de270ad3525d726a6b69cc59ee7b2269b014387651107ab9f0755b" dependencies = [ "bstr", - "hashbrown 0.15.5", + "hashbrown 0.17.1", ] [[package]] @@ -6397,7 +6377,7 @@ dependencies = [ "which", "windows", "wiremock", - "zip 3.0.0", + "zip", ] [[package]] @@ -6540,7 +6520,7 @@ dependencies = [ "tokio", "tracing", "wiremock", - "zip 8.6.0", + "zip", ] [[package]] @@ -7398,7 +7378,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -7663,20 +7643,20 @@ dependencies = [ [[package]] name = "office_oxide" -version = "0.1.6" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673fefe70a9e53a74d4e4b2797cbe9fc2d778cfc1734956727db9e5b7d809e98" +checksum = "96174357b389a992d7864db7a7a10a1254b82716cdfc40bee54f1da1234291bf" dependencies = [ "atoi_simd", "encoding_rs", "fast-float2", - "libc", + "flate2", "log", - "quick-xml 0.41.0", + "quick-xml 0.42.0", "serde", "serde_json", "thiserror 2.0.18", - "zip 8.6.0", + "zip", ] [[package]] @@ -7802,7 +7782,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -8684,6 +8664,15 @@ name = "quick-xml" version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b" dependencies = [ "memchr", "serde", @@ -8743,7 +8732,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -9338,7 +9327,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -9408,7 +9397,7 @@ dependencies = [ "security-framework 3.7.0", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -10628,10 +10617,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -11505,9 +11494,9 @@ dependencies = [ [[package]] name = "typed-path" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" +checksum = "9ce898823d8cd0f028662d2f349694b1af0a5cc9be83f1d213a00d3147445e1e" [[package]] name = "typenum" @@ -12255,7 +12244,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -12977,28 +12966,18 @@ dependencies = [ [[package]] name = "zip" -version = "3.0.0" +version = "9.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" -dependencies = [ - "arbitrary", - "crc32fast", - "flate2", - "indexmap", - "memchr", -] - -[[package]] -name = "zip" -version = "8.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +checksum = "1156b39d142a34b999c2310a50455e0cb3760bf7efad0122f796d813bee26ccb" dependencies = [ "crc32fast", "flate2", + "getrandom 0.4.3", "indexmap", "memchr", + "nix 0.31.3", "typed-path", + "windows-sys 0.61.2", "zopfli", ] diff --git a/Cargo.toml b/Cargo.toml index 43c8f55..a529792 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -294,7 +294,7 @@ kigi-tool-runtime = { path = "crates/common/kigi-tool-runtime" } kigi-tool-types = { path = "crates/common/kigi-tool-types" } kigi-tty-utils = { path = "crates/codegen/kigi-tty-utils" } zbus = { version = "5" } -zip = { version = "8", default-features = false, features = ["deflate"] } +zip = { version = "9", default-features = false, features = ["deflate"] } zstd = "0.13" [profile.release] diff --git a/crates/codegen/kigi-tools/Cargo.toml b/crates/codegen/kigi-tools/Cargo.toml index 83db639..c7ff3dc 100644 --- a/crates/codegen/kigi-tools/Cargo.toml +++ b/crates/codegen/kigi-tools/Cargo.toml @@ -31,11 +31,7 @@ infer = { workspace = true } globset = { workspace = true } image = { workspace = true, features = ["png", "jpeg", "gif", "webp", "bmp", "tiff", "ico"] } pdf_oxide = { workspace = true } -# PPTX text extraction (implementations/read_file/pptx.rs). Deliberately NOT -# `workspace = true`: the workspace `zip` pin has default features on, which -# drag aes/bzip2/lzma/zstd into the shipped pager binary. PPTX entries are -# only ever stored or deflated. -zip = { version = "3", default-features = false, features = ["deflate-flate2"] } +zip = { workspace = true } quick-xml = { workspace = true } indexmap = { workspace = true, features = ["serde"] } minijinja = { version = "2", features = ["custom_syntax"] } diff --git a/crates/codegen/kigi-tools/src/implementations/read_file/pptx.rs b/crates/codegen/kigi-tools/src/implementations/read_file/pptx.rs index 686bfcb..93487ab 100644 --- a/crates/codegen/kigi-tools/src/implementations/read_file/pptx.rs +++ b/crates/codegen/kigi-tools/src/implementations/read_file/pptx.rs @@ -31,10 +31,14 @@ pub(crate) fn extract_pptx_text_from_bytes(bytes: &[u8]) -> Result, _>>() + .map_err(|e| format!("Failed to read PPTX entry names: {e}"))?; // Collect slide numbers from `ppt/slides/slideN.xml` entries and sort // numerically so slide ordering matches the presentation. - let mut slide_numbers: Vec = archive - .file_names() + let mut slide_numbers: Vec = names + .iter() .filter_map(|name| { name.strip_prefix("ppt/slides/slide")? .strip_suffix(".xml")? diff --git a/crates/codegen/kigi-update/src/auto_update.rs b/crates/codegen/kigi-update/src/auto_update.rs index f26e1d7..e8ebb18 100644 --- a/crates/codegen/kigi-update/src/auto_update.rs +++ b/crates/codegen/kigi-update/src/auto_update.rs @@ -1108,7 +1108,7 @@ fn extract_kigi_binary_blocking(archive: &Path, dest_tmp: &Path) -> Result<()> { for i in 0..zip.len() { let mut entry = zip.by_index(i)?; let base_name = entry - .name() + .name()? .rsplit(['/', '\\']) .next() .unwrap_or_default() @@ -2798,6 +2798,52 @@ mod tests { assert!(extract_kigi_binary(&archive, &out).await.is_err()); } + // Archive extraction (Windows: zip) + + #[cfg(windows)] + fn make_zip(entries: &[(&str, &[u8])]) -> Vec { + use std::io::Write as _; + let mut writer = zip::ZipWriter::new(std::io::Cursor::new(Vec::new())); + for (name, data) in entries { + writer + .start_file(*name, zip::write::SimpleFileOptions::default()) + .unwrap(); + writer.write_all(data).unwrap(); + } + writer.finish().unwrap().into_inner() + } + + #[cfg(windows)] + #[tokio::test] + async fn test_extract_kigi_binary_finds_kigi_exe_entry() { + let dir = tempfile::tempdir().unwrap(); + let archive = dir.path().join("kigi-0.1.0-test.zip"); + std::fs::write( + &archive, + make_zip(&[("LICENSE", b"license text"), ("kigi.exe", b"MZ binary")]), + ) + .unwrap(); + + let out = dir.path().join("kigi-extracted"); + extract_kigi_binary(&archive, &out).await.unwrap(); + assert_eq!(std::fs::read(&out).unwrap(), b"MZ binary"); + } + + #[cfg(windows)] + #[tokio::test] + async fn test_extract_kigi_binary_missing_exe_errors() { + let dir = tempfile::tempdir().unwrap(); + let archive = dir.path().join("kigi-0.1.0-test.zip"); + std::fs::write(&archive, make_zip(&[("LICENSE", b"license only")])).unwrap(); + + let out = dir.path().join("kigi-extracted"); + let err = extract_kigi_binary(&archive, &out).await.unwrap_err(); + assert!( + format!("{err}").contains("no 'kigi.exe' binary"), + "err: {err}" + ); + } + // UpdateStatus serialization (camelCase contract for --json clients) fn make_status() -> UpdateStatus {