mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
mtk_pkg: add LZHS decompression support for partitions
This commit is contained in:
+11
-2
@@ -5,6 +5,7 @@ use binrw::{BinRead, BinReaderExt};
|
||||
|
||||
use crate::utils::common;
|
||||
use crate::utils::aes::{decrypt_aes128_cbc_nopad};
|
||||
use crate::utils::lzhs::{decompress_lzhs_fs_file2file};
|
||||
use crate::keys;
|
||||
|
||||
#[derive(BinRead)]
|
||||
@@ -156,11 +157,19 @@ pub fn extract_mtk_pkg(mut file: &File, output_folder: &str) -> Result<(), Box<d
|
||||
0
|
||||
};
|
||||
|
||||
let output_path = Path::new(&output_folder).join(part_entry.name() + ".bin");
|
||||
//for compressed part create temp file
|
||||
let output_path = Path::new(&output_folder).join(part_entry.name() + if part_entry.is_compressed() {".lzhs"} else {".bin"});
|
||||
fs::create_dir_all(&output_folder)?;
|
||||
let mut out_file = OpenOptions::new().write(true).create(true).open(output_path)?;
|
||||
let mut out_file = OpenOptions::new().write(true).read(true)/* for lzhs */.create(true).open(&output_path)?;
|
||||
out_file.write_all(&out_data[48 + extra_header_len as usize..])?;
|
||||
|
||||
if part_entry.is_compressed() {
|
||||
let lzhs_out_path = Path::new(&output_folder).join(part_entry.name() + ".bin");
|
||||
decompress_lzhs_fs_file2file(&out_file, lzhs_out_path)?;
|
||||
//after decompression remove the temporary .lzhs file
|
||||
fs::remove_file(&output_path)?;
|
||||
}
|
||||
|
||||
println!("-- Saved file!");
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -6,4 +6,6 @@ pub mod lzop;
|
||||
pub mod sparse;
|
||||
pub mod compression;
|
||||
pub mod android_ota_update_metadata;
|
||||
pub mod mtk_crypto;
|
||||
pub mod mtk_crypto;
|
||||
pub mod lzhs;
|
||||
pub mod huffman_tables;
|
||||
@@ -0,0 +1,326 @@
|
||||
pub const CHARLEN: [(u32,u32); 288] = [
|
||||
//key, pos
|
||||
(0x00000002u32, 0x00000005u32),
|
||||
(0x00000003u32, 0x00000005u32),
|
||||
(0x0000000au32, 0x00000006u32),
|
||||
(0x00000028u32, 0x00000007u32),
|
||||
(0x00000029u32, 0x00000007u32),
|
||||
(0x0000002au32, 0x00000007u32),
|
||||
(0x0000002bu32, 0x00000007u32),
|
||||
(0x0000002cu32, 0x00000007u32),
|
||||
(0x0000002du32, 0x00000007u32),
|
||||
(0x0000002eu32, 0x00000007u32),
|
||||
(0x0000002fu32, 0x00000007u32),
|
||||
(0x0000008au32, 0x00000008u32),
|
||||
(0x0000008bu32, 0x00000008u32),
|
||||
(0x0000008cu32, 0x00000008u32),
|
||||
(0x0000008du32, 0x00000008u32),
|
||||
(0x0000008eu32, 0x00000008u32),
|
||||
(0x00000030u32, 0x00000007u32),
|
||||
(0x0000008fu32, 0x00000008u32),
|
||||
(0x00000090u32, 0x00000008u32),
|
||||
(0x00000180u32, 0x00000009u32),
|
||||
(0x00000091u32, 0x00000008u32),
|
||||
(0x00000181u32, 0x00000009u32),
|
||||
(0x00000182u32, 0x00000009u32),
|
||||
(0x00000183u32, 0x00000009u32),
|
||||
(0x00000031u32, 0x00000007u32),
|
||||
(0x00000092u32, 0x00000008u32),
|
||||
(0x00000093u32, 0x00000008u32),
|
||||
(0x00000094u32, 0x00000008u32),
|
||||
(0x0000000bu32, 0x00000006u32),
|
||||
(0x00000184u32, 0x00000009u32),
|
||||
(0x00000185u32, 0x00000009u32),
|
||||
(0x00000186u32, 0x00000009u32),
|
||||
(0x0000000cu32, 0x00000006u32),
|
||||
(0x00000032u32, 0x00000007u32),
|
||||
(0x00000033u32, 0x00000007u32),
|
||||
(0x00000095u32, 0x00000008u32),
|
||||
(0x00000096u32, 0x00000008u32),
|
||||
(0x00000097u32, 0x00000008u32),
|
||||
(0x00000187u32, 0x00000009u32),
|
||||
(0x00000188u32, 0x00000009u32),
|
||||
(0x00000034u32, 0x00000007u32),
|
||||
(0x00000098u32, 0x00000008u32),
|
||||
(0x00000099u32, 0x00000008u32),
|
||||
(0x00000189u32, 0x00000009u32),
|
||||
(0x0000009au32, 0x00000008u32),
|
||||
(0x0000009bu32, 0x00000008u32),
|
||||
(0x0000018au32, 0x00000009u32),
|
||||
(0x0000018bu32, 0x00000009u32),
|
||||
(0x00000035u32, 0x00000007u32),
|
||||
(0x0000009cu32, 0x00000008u32),
|
||||
(0x0000009du32, 0x00000008u32),
|
||||
(0x0000018cu32, 0x00000009u32),
|
||||
(0x0000018du32, 0x00000009u32),
|
||||
(0x0000018eu32, 0x00000009u32),
|
||||
(0x0000018fu32, 0x00000009u32),
|
||||
(0x00000190u32, 0x00000009u32),
|
||||
(0x0000009eu32, 0x00000008u32),
|
||||
(0x00000191u32, 0x00000009u32),
|
||||
(0x00000192u32, 0x00000009u32),
|
||||
(0x00000193u32, 0x00000009u32),
|
||||
(0x00000194u32, 0x00000009u32),
|
||||
(0x00000195u32, 0x00000009u32),
|
||||
(0x00000196u32, 0x00000009u32),
|
||||
(0x00000197u32, 0x00000009u32),
|
||||
(0x00000036u32, 0x00000007u32),
|
||||
(0x0000009fu32, 0x00000008u32),
|
||||
(0x00000037u32, 0x00000007u32),
|
||||
(0x00000038u32, 0x00000007u32),
|
||||
(0x00000198u32, 0x00000009u32),
|
||||
(0x00000199u32, 0x00000009u32),
|
||||
(0x000000a0u32, 0x00000008u32),
|
||||
(0x0000019au32, 0x00000009u32),
|
||||
(0x00000039u32, 0x00000007u32),
|
||||
(0x0000003au32, 0x00000007u32),
|
||||
(0x0000003bu32, 0x00000007u32),
|
||||
(0x000000a1u32, 0x00000008u32),
|
||||
(0x000000a2u32, 0x00000008u32),
|
||||
(0x000000a3u32, 0x00000008u32),
|
||||
(0x0000019bu32, 0x00000009u32),
|
||||
(0x0000019cu32, 0x00000009u32),
|
||||
(0x0000019du32, 0x00000009u32),
|
||||
(0x0000019eu32, 0x00000009u32),
|
||||
(0x0000019fu32, 0x00000009u32),
|
||||
(0x000001a0u32, 0x00000009u32),
|
||||
(0x000001a1u32, 0x00000009u32),
|
||||
(0x000003b0u32, 0x0000000au32),
|
||||
(0x000003b1u32, 0x0000000au32),
|
||||
(0x000003b2u32, 0x0000000au32),
|
||||
(0x000001a2u32, 0x00000009u32),
|
||||
(0x000001a3u32, 0x00000009u32),
|
||||
(0x000001a4u32, 0x00000009u32),
|
||||
(0x000003b3u32, 0x0000000au32),
|
||||
(0x000001a5u32, 0x00000009u32),
|
||||
(0x000003b4u32, 0x0000000au32),
|
||||
(0x000003b5u32, 0x0000000au32),
|
||||
(0x000003b6u32, 0x0000000au32),
|
||||
(0x0000003cu32, 0x00000007u32),
|
||||
(0x000000a4u32, 0x00000008u32),
|
||||
(0x000000a5u32, 0x00000008u32),
|
||||
(0x000000a6u32, 0x00000008u32),
|
||||
(0x000000a7u32, 0x00000008u32),
|
||||
(0x000000a8u32, 0x00000008u32),
|
||||
(0x000001a6u32, 0x00000009u32),
|
||||
(0x000003b7u32, 0x0000000au32),
|
||||
(0x0000000du32, 0x00000006u32),
|
||||
(0x000000a9u32, 0x00000008u32),
|
||||
(0x000001a7u32, 0x00000009u32),
|
||||
(0x000001a8u32, 0x00000009u32),
|
||||
(0x000001a9u32, 0x00000009u32),
|
||||
(0x000001aau32, 0x00000009u32),
|
||||
(0x000001abu32, 0x00000009u32),
|
||||
(0x000001acu32, 0x00000009u32),
|
||||
(0x0000003du32, 0x00000007u32),
|
||||
(0x000001adu32, 0x00000009u32),
|
||||
(0x000000aau32, 0x00000008u32),
|
||||
(0x000001aeu32, 0x00000009u32),
|
||||
(0x000001afu32, 0x00000009u32),
|
||||
(0x000001b0u32, 0x00000009u32),
|
||||
(0x000003b8u32, 0x0000000au32),
|
||||
(0x000003b9u32, 0x0000000au32),
|
||||
(0x0000003eu32, 0x00000007u32),
|
||||
(0x000001b1u32, 0x00000009u32),
|
||||
(0x000001b2u32, 0x00000009u32),
|
||||
(0x000001b3u32, 0x00000009u32),
|
||||
(0x000003bau32, 0x0000000au32),
|
||||
(0x000003bbu32, 0x0000000au32),
|
||||
(0x000003bcu32, 0x0000000au32),
|
||||
(0x000003bdu32, 0x0000000au32),
|
||||
(0x0000003fu32, 0x00000007u32),
|
||||
(0x000000abu32, 0x00000008u32),
|
||||
(0x000001b4u32, 0x00000009u32),
|
||||
(0x000001b5u32, 0x00000009u32),
|
||||
(0x000001b6u32, 0x00000009u32),
|
||||
(0x000003beu32, 0x0000000au32),
|
||||
(0x000003bfu32, 0x0000000au32),
|
||||
(0x000003c0u32, 0x0000000au32),
|
||||
(0x000000acu32, 0x00000008u32),
|
||||
(0x000000adu32, 0x00000008u32),
|
||||
(0x000001b7u32, 0x00000009u32),
|
||||
(0x000001b8u32, 0x00000009u32),
|
||||
(0x000001b9u32, 0x00000009u32),
|
||||
(0x000003c1u32, 0x0000000au32),
|
||||
(0x000003c2u32, 0x0000000au32),
|
||||
(0x000003c3u32, 0x0000000au32),
|
||||
(0x000000aeu32, 0x00000008u32),
|
||||
(0x000000afu32, 0x00000008u32),
|
||||
(0x000000b0u32, 0x00000008u32),
|
||||
(0x000003c4u32, 0x0000000au32),
|
||||
(0x000003c5u32, 0x0000000au32),
|
||||
(0x000003c6u32, 0x0000000au32),
|
||||
(0x000003c7u32, 0x0000000au32),
|
||||
(0x000003c8u32, 0x0000000au32),
|
||||
(0x00000040u32, 0x00000007u32),
|
||||
(0x000000b1u32, 0x00000008u32),
|
||||
(0x000001bau32, 0x00000009u32),
|
||||
(0x000001bbu32, 0x00000009u32),
|
||||
(0x000003c9u32, 0x0000000au32),
|
||||
(0x000003cau32, 0x0000000au32),
|
||||
(0x000003cbu32, 0x0000000au32),
|
||||
(0x000003ccu32, 0x0000000au32),
|
||||
(0x000000b2u32, 0x00000008u32),
|
||||
(0x000000b3u32, 0x00000008u32),
|
||||
(0x000003cdu32, 0x0000000au32),
|
||||
(0x000003ceu32, 0x0000000au32),
|
||||
(0x000003cfu32, 0x0000000au32),
|
||||
(0x000003d0u32, 0x0000000au32),
|
||||
(0x000003d1u32, 0x0000000au32),
|
||||
(0x000007deu32, 0x0000000bu32),
|
||||
(0x000000b4u32, 0x00000008u32),
|
||||
(0x000001bcu32, 0x00000009u32),
|
||||
(0x000001bdu32, 0x00000009u32),
|
||||
(0x000001beu32, 0x00000009u32),
|
||||
(0x000003d2u32, 0x0000000au32),
|
||||
(0x000003d3u32, 0x0000000au32),
|
||||
(0x000007dfu32, 0x0000000bu32),
|
||||
(0x000007e0u32, 0x0000000bu32),
|
||||
(0x000000b5u32, 0x00000008u32),
|
||||
(0x000003d4u32, 0x0000000au32),
|
||||
(0x000003d5u32, 0x0000000au32),
|
||||
(0x000007e1u32, 0x0000000bu32),
|
||||
(0x000003d6u32, 0x0000000au32),
|
||||
(0x000000b6u32, 0x00000008u32),
|
||||
(0x000003d7u32, 0x0000000au32),
|
||||
(0x000007e2u32, 0x0000000bu32),
|
||||
(0x000003d8u32, 0x0000000au32),
|
||||
(0x000007e3u32, 0x0000000bu32),
|
||||
(0x000007e4u32, 0x0000000bu32),
|
||||
(0x000007e5u32, 0x0000000bu32),
|
||||
(0x000003d9u32, 0x0000000au32),
|
||||
(0x000000b7u32, 0x00000008u32),
|
||||
(0x000007e6u32, 0x0000000bu32),
|
||||
(0x000007e7u32, 0x0000000bu32),
|
||||
(0x000000b8u32, 0x00000008u32),
|
||||
(0x000001bfu32, 0x00000009u32),
|
||||
(0x000003dau32, 0x0000000au32),
|
||||
(0x000003dbu32, 0x0000000au32),
|
||||
(0x000003dcu32, 0x0000000au32),
|
||||
(0x000007e8u32, 0x0000000bu32),
|
||||
(0x000007e9u32, 0x0000000bu32),
|
||||
(0x000007eau32, 0x0000000bu32),
|
||||
(0x000001c0u32, 0x00000009u32),
|
||||
(0x000001c1u32, 0x00000009u32),
|
||||
(0x000003ddu32, 0x0000000au32),
|
||||
(0x000007ebu32, 0x0000000bu32),
|
||||
(0x000003deu32, 0x0000000au32),
|
||||
(0x000007ecu32, 0x0000000bu32),
|
||||
(0x000007edu32, 0x0000000bu32),
|
||||
(0x000007eeu32, 0x0000000bu32),
|
||||
(0x0000000eu32, 0x00000006u32),
|
||||
(0x0000000fu32, 0x00000006u32),
|
||||
(0x000001c2u32, 0x00000009u32),
|
||||
(0x000001c3u32, 0x00000009u32),
|
||||
(0x000003dfu32, 0x0000000au32),
|
||||
(0x000001c4u32, 0x00000009u32),
|
||||
(0x000007efu32, 0x0000000bu32),
|
||||
(0x000007f0u32, 0x0000000bu32),
|
||||
(0x000001c5u32, 0x00000009u32),
|
||||
(0x000001c6u32, 0x00000009u32),
|
||||
(0x000003e0u32, 0x0000000au32),
|
||||
(0x000003e1u32, 0x0000000au32),
|
||||
(0x000001c7u32, 0x00000009u32),
|
||||
(0x000003e2u32, 0x0000000au32),
|
||||
(0x000007f1u32, 0x0000000bu32),
|
||||
(0x000007f2u32, 0x0000000bu32),
|
||||
(0x00000010u32, 0x00000006u32),
|
||||
(0x000001c8u32, 0x00000009u32),
|
||||
(0x000001c9u32, 0x00000009u32),
|
||||
(0x000003e3u32, 0x0000000au32),
|
||||
(0x000003e4u32, 0x0000000au32),
|
||||
(0x000001cau32, 0x00000009u32),
|
||||
(0x000001cbu32, 0x00000009u32),
|
||||
(0x00000041u32, 0x00000007u32),
|
||||
(0x000001ccu32, 0x00000009u32),
|
||||
(0x000001cdu32, 0x00000009u32),
|
||||
(0x000001ceu32, 0x00000009u32),
|
||||
(0x000003e5u32, 0x0000000au32),
|
||||
(0x000003e6u32, 0x0000000au32),
|
||||
(0x000003e7u32, 0x0000000au32),
|
||||
(0x000003e8u32, 0x0000000au32),
|
||||
(0x000003e9u32, 0x0000000au32),
|
||||
(0x00000042u32, 0x00000007u32),
|
||||
(0x000000b9u32, 0x00000008u32),
|
||||
(0x000007f3u32, 0x0000000bu32),
|
||||
(0x000007f4u32, 0x0000000bu32),
|
||||
(0x000003eau32, 0x0000000au32),
|
||||
(0x000007f5u32, 0x0000000bu32),
|
||||
(0x000001cfu32, 0x00000009u32),
|
||||
(0x000001d0u32, 0x00000009u32),
|
||||
(0x000000bau32, 0x00000008u32),
|
||||
(0x000001d1u32, 0x00000009u32),
|
||||
(0x000001d2u32, 0x00000009u32),
|
||||
(0x000001d3u32, 0x00000009u32),
|
||||
(0x000001d4u32, 0x00000009u32),
|
||||
(0x000001d5u32, 0x00000009u32),
|
||||
(0x000000bbu32, 0x00000008u32),
|
||||
(0x00000043u32, 0x00000007u32),
|
||||
(0x00000000u32, 0x00000004u32),
|
||||
(0x00000004u32, 0x00000005u32),
|
||||
(0x00000011u32, 0x00000006u32),
|
||||
(0x00000012u32, 0x00000006u32),
|
||||
(0x00000013u32, 0x00000006u32),
|
||||
(0x00000044u32, 0x00000007u32),
|
||||
(0x000000bcu32, 0x00000008u32),
|
||||
(0x000000bdu32, 0x00000008u32),
|
||||
(0x000000beu32, 0x00000008u32),
|
||||
(0x000001d6u32, 0x00000009u32),
|
||||
(0x000001d7u32, 0x00000009u32),
|
||||
(0x000003ebu32, 0x0000000au32),
|
||||
(0x000003ecu32, 0x0000000au32),
|
||||
(0x000003edu32, 0x0000000au32),
|
||||
(0x000003eeu32, 0x0000000au32),
|
||||
(0x000007f6u32, 0x0000000bu32),
|
||||
(0x000007f7u32, 0x0000000bu32),
|
||||
(0x000007f8u32, 0x0000000bu32),
|
||||
(0x000007f9u32, 0x0000000bu32),
|
||||
(0x000007fau32, 0x0000000bu32),
|
||||
(0x000007fbu32, 0x0000000bu32),
|
||||
(0x00000ff8u32, 0x0000000cu32),
|
||||
(0x00000ff9u32, 0x0000000cu32),
|
||||
(0x00000ffau32, 0x0000000cu32),
|
||||
(0x00000ffbu32, 0x0000000cu32),
|
||||
(0x00001ffcu32, 0x0000000du32),
|
||||
(0x00000ffcu32, 0x0000000cu32),
|
||||
(0x00001ffdu32, 0x0000000du32),
|
||||
(0x00000ffdu32, 0x0000000cu32),
|
||||
(0x00001ffeu32, 0x0000000du32),
|
||||
(0x00001fffu32, 0x0000000du32),
|
||||
(0x000000bfu32, 0x00000008u32),
|
||||
];
|
||||
|
||||
pub const POS: [(u32,u32); 32] = [
|
||||
(0x00000000u32, 0x00000002u32),
|
||||
(0x00000002u32, 0x00000003u32),
|
||||
(0x00000006u32, 0x00000004u32),
|
||||
(0x0000000eu32, 0x00000005u32),
|
||||
(0x0000000fu32, 0x00000005u32),
|
||||
(0x00000010u32, 0x00000005u32),
|
||||
(0x00000011u32, 0x00000005u32),
|
||||
(0x00000012u32, 0x00000005u32),
|
||||
(0x00000013u32, 0x00000005u32),
|
||||
(0x00000014u32, 0x00000005u32),
|
||||
(0x0000002au32, 0x00000006u32),
|
||||
(0x0000002bu32, 0x00000006u32),
|
||||
(0x0000002cu32, 0x00000006u32),
|
||||
(0x0000002du32, 0x00000006u32),
|
||||
(0x0000002eu32, 0x00000006u32),
|
||||
(0x0000002fu32, 0x00000006u32),
|
||||
(0x00000030u32, 0x00000006u32),
|
||||
(0x00000031u32, 0x00000006u32),
|
||||
(0x00000032u32, 0x00000006u32),
|
||||
(0x00000033u32, 0x00000006u32),
|
||||
(0x00000034u32, 0x00000006u32),
|
||||
(0x00000035u32, 0x00000006u32),
|
||||
(0x00000036u32, 0x00000006u32),
|
||||
(0x00000037u32, 0x00000006u32),
|
||||
(0x00000038u32, 0x00000006u32),
|
||||
(0x00000039u32, 0x00000006u32),
|
||||
(0x0000003au32, 0x00000006u32),
|
||||
(0x0000003bu32, 0x00000006u32),
|
||||
(0x0000003cu32, 0x00000006u32),
|
||||
(0x0000003du32, 0x00000006u32),
|
||||
(0x0000003eu32, 0x00000006u32),
|
||||
(0x0000003fu32, 0x00000006u32),
|
||||
];
|
||||
@@ -0,0 +1,269 @@
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Write, Cursor, Seek, SeekFrom, Read};
|
||||
use binrw::{BinRead, BinReaderExt};
|
||||
use std::path::{PathBuf};
|
||||
|
||||
use crate::utils::huffman_tables::{CHARLEN, POS};
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct LzhsHeader {
|
||||
uncompressed_size: u32,
|
||||
compressed_size: u32,
|
||||
checksum_or_seg_idx: u16, //as checksum in normal lzhs header, as index in lzhs_fs header
|
||||
#[br(count = 6)] _padding: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn decompress_lzhs_fs_file2file(mut file: &File, output_file: PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let file_size = file.metadata()?.len();
|
||||
let mut out_file = OpenOptions::new().append(true).create(true).open(output_file)?;
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
let mut uncompressed_heading = vec![0u8; 0x100000]; //first 1mb is uncompressed
|
||||
file.read_exact(&mut uncompressed_heading)?;
|
||||
out_file.write_all(&uncompressed_heading)?;
|
||||
|
||||
while file.stream_position().unwrap() < file_size {
|
||||
let segment_header: LzhsHeader = file.read_le()?;
|
||||
let lzhs_header: LzhsHeader = file.read_le()?;
|
||||
println!("[LZHS] Segment {} - Compressed size: {}, Decompressed size: {}, Expected Checksum: 0x{:02x?}",
|
||||
segment_header.checksum_or_seg_idx, lzhs_header.compressed_size, lzhs_header.uncompressed_size, lzhs_header.checksum_or_seg_idx);
|
||||
|
||||
let mut compressed_data = vec![0u8; lzhs_header.compressed_size as usize];
|
||||
file.read_exact(&mut compressed_data)?;
|
||||
|
||||
println!("- Decompressing...");
|
||||
let out_huff = unhuff(&compressed_data);
|
||||
let mut out_data = unlzss(&out_huff, lzhs_header.uncompressed_size as usize);
|
||||
arm_thumb_convert(&mut out_data, 0, false);
|
||||
|
||||
let checksum = calc_checksum(&out_data);
|
||||
println!("-- Calculated checksum: 0x{:02x?}", checksum);
|
||||
if u16::from(checksum) != lzhs_header.checksum_or_seg_idx {
|
||||
println!("--- Checksum mismatch! Expected: 0x{:02x?}, Got: 0x{:02x?}!", lzhs_header.checksum_or_seg_idx, checksum);
|
||||
} else {
|
||||
println!("--- Checksum OK!")
|
||||
}
|
||||
|
||||
out_file.write_all(&out_data)?;
|
||||
|
||||
//padded to 16 bytes
|
||||
let pad_pos = (file.stream_position().unwrap() + 15) & !15;
|
||||
file.seek(SeekFrom::Start(pad_pos))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct HuffmanCtx {
|
||||
c: u8,
|
||||
code: u32,
|
||||
len: u32,
|
||||
bitno: u8,
|
||||
code_buf: [u8; 32],
|
||||
code_buf_ptr: usize,
|
||||
mask: u8,
|
||||
}
|
||||
|
||||
fn get_byte<Cursor: Read>(ctx: &mut HuffmanCtx, input: &mut Cursor) -> bool {
|
||||
if ctx.bitno > 7 {
|
||||
ctx.bitno = 0;
|
||||
let mut buf = [0u8; 1];
|
||||
if input.read_exact(&mut buf).is_err() {
|
||||
return false;
|
||||
}
|
||||
ctx.c = buf[0];
|
||||
}
|
||||
let bit = ((ctx.c >> (7 - ctx.bitno)) & 1) as u32;
|
||||
ctx.code = (ctx.code << 1) | bit;
|
||||
ctx.len += 1;
|
||||
ctx.bitno += 1;
|
||||
true
|
||||
}
|
||||
|
||||
fn unhuff(data: &[u8]) -> Vec<u8> {
|
||||
let charlen = &CHARLEN;
|
||||
let pos = &POS;
|
||||
|
||||
let mut ctx = HuffmanCtx {
|
||||
c: 0,
|
||||
code: 0,
|
||||
len: 0,
|
||||
bitno: 8,
|
||||
code_buf: [0u8; 32],
|
||||
code_buf_ptr: 1,
|
||||
mask: 1,
|
||||
};
|
||||
let mut lookup_charlen = vec![-1i16; 131072];
|
||||
let mut lookup_charpos = vec![-1i16; 512];
|
||||
|
||||
let mut in_cur = Cursor::new(data);
|
||||
let mut out: Vec<u8> = Vec::with_capacity(data.len());
|
||||
|
||||
loop {
|
||||
if !get_byte(&mut ctx, &mut in_cur) { /*println!("break1");*/break; }
|
||||
if ctx.len < 4 { continue; }
|
||||
let key = (((ctx.len & 0xF) as usize) << 13) | ((ctx.code & 0x1FFF) as usize);
|
||||
let mut idx = lookup_charlen[key];
|
||||
if idx == -2 { continue; }
|
||||
if idx == -1 {
|
||||
let mut found = false;
|
||||
for (i, &(code, len)) in charlen.iter().enumerate() {
|
||||
if len == ctx.len && code == ctx.code {
|
||||
lookup_charlen[key] = i as i16;
|
||||
idx = i as i16; found = true; break;
|
||||
}
|
||||
}
|
||||
if !found { lookup_charlen[key] = -2; continue; }
|
||||
}
|
||||
let i = idx as i32;
|
||||
if i > 255 {
|
||||
let val = (i - 256) as u8;
|
||||
if ctx.code_buf_ptr < ctx.code_buf.len() { ctx.code_buf[ctx.code_buf_ptr] = val; ctx.code_buf_ptr += 1; }
|
||||
ctx.code = 0; ctx.len = 0;
|
||||
|
||||
let found_j: i32;
|
||||
loop {
|
||||
if !get_byte(&mut ctx, &mut in_cur) {
|
||||
//println!("retA");
|
||||
//flush
|
||||
if ctx.code_buf_ptr > 1 { for j in 0..ctx.code_buf_ptr { out.push(ctx.code_buf[j]); } };
|
||||
return out;
|
||||
}
|
||||
if ctx.len < 2 { continue; }
|
||||
let keyp = (((ctx.len & 0x7) as usize) << 6) | ((ctx.code & 0x3F) as usize);
|
||||
let mut jdx = lookup_charpos[keyp];
|
||||
if jdx == -2 { continue; }
|
||||
if jdx == -1 {
|
||||
let mut found = false;
|
||||
for (j, &(code, len)) in pos.iter().enumerate() {
|
||||
if len == ctx.len && code == ctx.code {
|
||||
lookup_charpos[keyp] = j as i16; jdx = j as i16; found = true; break;
|
||||
}
|
||||
}
|
||||
if !found { lookup_charpos[keyp] = -2; continue; }
|
||||
}
|
||||
found_j = jdx as i32;
|
||||
let b = ((jdx as i32) >> 1) as u8;
|
||||
if ctx.code_buf_ptr < ctx.code_buf.len() { ctx.code_buf[ctx.code_buf_ptr] = b; ctx.code_buf_ptr += 1; }
|
||||
break;
|
||||
}
|
||||
ctx.code = 0;
|
||||
for _ in 0..7 { if !get_byte(&mut ctx, &mut in_cur) {
|
||||
//println!("retB");
|
||||
//flush
|
||||
if ctx.code_buf_ptr > 1 { for j in 0..ctx.code_buf_ptr { out.push(ctx.code_buf[j]); } };
|
||||
return out;
|
||||
}
|
||||
}
|
||||
let combined = (ctx.code | ((found_j as u32) << 7)) as u32;
|
||||
if ctx.code_buf_ptr < ctx.code_buf.len() { ctx.code_buf[ctx.code_buf_ptr] = (combined & 0xFF) as u8; ctx.code_buf_ptr += 1; }
|
||||
ctx.code = 0; ctx.len = 0;
|
||||
} else {
|
||||
ctx.code_buf[0] |= ctx.mask;
|
||||
if ctx.code_buf_ptr < ctx.code_buf.len() { ctx.code_buf[ctx.code_buf_ptr] = i as u8; ctx.code_buf_ptr += 1; }
|
||||
ctx.code = 0; ctx.len = 0;
|
||||
}
|
||||
ctx.mask = ctx.mask.wrapping_shl(1);
|
||||
if ctx.mask == 0 {
|
||||
for j in 0..ctx.code_buf_ptr { out.push(ctx.code_buf[j]); }
|
||||
ctx.code_buf[0] = 0; ctx.code_buf_ptr = 1; ctx.mask = 1;
|
||||
}
|
||||
}
|
||||
if ctx.code_buf_ptr > 1 { for j in 0..ctx.code_buf_ptr { out.push(ctx.code_buf[j]); } }
|
||||
out
|
||||
}
|
||||
|
||||
fn unlzss(data: &[u8], expected_size: usize) -> Vec<u8> {
|
||||
let mut window = [0u8; 0x1000];
|
||||
let mut dst = Vec::with_capacity(expected_size);
|
||||
let mut src_i = 0;
|
||||
let mut win_pos = 0usize;
|
||||
let mut flags = 0u32;
|
||||
|
||||
while dst.len() < expected_size {
|
||||
flags >>= 1;
|
||||
if (flags & 0x100) == 0 {
|
||||
if src_i >= data.len() {
|
||||
break;
|
||||
}
|
||||
flags = data[src_i] as u32 | 0xFF00;
|
||||
src_i += 1;
|
||||
}
|
||||
|
||||
if (flags & 1) != 0 {
|
||||
// literal
|
||||
if src_i >= data.len() {
|
||||
break;
|
||||
}
|
||||
let c = data[src_i];
|
||||
src_i += 1;
|
||||
dst.push(c);
|
||||
window[win_pos] = c;
|
||||
win_pos = (win_pos + 1) & 0xFFF;
|
||||
} else {
|
||||
// backreference
|
||||
if src_i + 2 >= data.len() {
|
||||
break;
|
||||
}
|
||||
let j = data[src_i] as usize;
|
||||
let off = ((data[src_i + 1] as usize) << 8) | data[src_i + 2] as usize;
|
||||
src_i += 3;
|
||||
|
||||
let count = j + 3;
|
||||
for _ in 0..count {
|
||||
if dst.len() >= expected_size {
|
||||
break;
|
||||
}
|
||||
let c = window[(win_pos.wrapping_sub(off)) & 0xFFF];
|
||||
dst.push(c);
|
||||
window[win_pos] = c;
|
||||
win_pos = (win_pos + 1) & 0xFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst
|
||||
}
|
||||
|
||||
fn arm_thumb_convert(data: &mut [u8], now_pos: u32, encoding: bool) {
|
||||
let size = data.len() as u32;
|
||||
let mut i: u32 = 0;
|
||||
|
||||
while i + 4 <= size {
|
||||
let idx = i as usize;
|
||||
|
||||
if (data[idx + 1] & 0xF8) == 0xF0 && (data[idx + 3] & 0xF8) == 0xF8 {
|
||||
let mut src: u32 =
|
||||
((data[idx + 1] as u32 & 0x7) << 19) |
|
||||
((data[idx + 0] as u32) << 11) |
|
||||
((data[idx + 3] as u32 & 0x7) << 8) |
|
||||
(data[idx + 2] as u32);
|
||||
|
||||
src <<= 1;
|
||||
|
||||
let dest = if encoding {
|
||||
now_pos + i + 4 + src
|
||||
} else {
|
||||
src.wrapping_sub(now_pos + i + 4)
|
||||
} >> 1;
|
||||
|
||||
data[idx + 1] = 0xF0 | ((dest >> 19) & 0x7) as u8;
|
||||
data[idx + 0] = ((dest >> 11) & 0xFF) as u8;
|
||||
data[idx + 3] = 0xF8 | ((dest >> 8) & 0x7) as u8;
|
||||
data[idx + 2] = (dest & 0xFF) as u8;
|
||||
|
||||
i += 2;
|
||||
}
|
||||
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_checksum(data: &[u8]) -> u8 {
|
||||
let mut checksum: u8 = 0;
|
||||
for &bt in data {
|
||||
checksum = checksum.wrapping_add(bt);
|
||||
}
|
||||
checksum
|
||||
}
|
||||
Reference in New Issue
Block a user