mtk_pkg: add LZHS decompression support for partitions

This commit is contained in:
theubusu
2025-12-23 14:51:15 +01:00
parent 36bde3a802
commit 942767e806
4 changed files with 609 additions and 3 deletions
+11 -2
View File
@@ -5,6 +5,7 @@ use binrw::{BinRead, BinReaderExt};
use crate::utils::common; use crate::utils::common;
use crate::utils::aes::{decrypt_aes128_cbc_nopad}; use crate::utils::aes::{decrypt_aes128_cbc_nopad};
use crate::utils::lzhs::{decompress_lzhs_fs_file2file};
use crate::keys; use crate::keys;
#[derive(BinRead)] #[derive(BinRead)]
@@ -156,11 +157,19 @@ pub fn extract_mtk_pkg(mut file: &File, output_folder: &str) -> Result<(), Box<d
0 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)?; 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..])?; 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!"); println!("-- Saved file!");
} }
+3 -1
View File
@@ -6,4 +6,6 @@ pub mod lzop;
pub mod sparse; pub mod sparse;
pub mod compression; pub mod compression;
pub mod android_ota_update_metadata; pub mod android_ota_update_metadata;
pub mod mtk_crypto; pub mod mtk_crypto;
pub mod lzhs;
pub mod huffman_tables;
+326
View File
@@ -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),
];
+269
View File
@@ -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
}