mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
mtk_pkg_old: add support for LZHS compression old variant
This commit is contained in:
@@ -5,6 +5,7 @@ use binrw::{BinRead, BinReaderExt};
|
||||
|
||||
use crate::utils::common;
|
||||
use crate::utils::mtk_crypto::{decrypt};
|
||||
use crate::utils::lzhs::{decompress_lzhs_fs_file2file_old};
|
||||
|
||||
static KEY: u32 = 0x94102909; //09 29 10 94
|
||||
// first 4 bytes of header and content are additionally XORed, they have different masks although only differ by half a byte
|
||||
@@ -47,6 +48,9 @@ impl PartEntry {
|
||||
fn is_encrypted(&self) -> bool {
|
||||
(self.flags & 1 << 0) == 1 << 0
|
||||
}
|
||||
fn is_compressed(&self) -> bool { //lzhs fs
|
||||
(self.flags & 1 << 8) != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_mtk_pkg_old_file(mut file: &File) -> bool {
|
||||
@@ -82,7 +86,8 @@ pub fn extract_mtk_pkg_old(mut file: &File, output_folder: &str) -> Result<(), B
|
||||
part_n += 1;
|
||||
let part_entry: PartEntry = file.read_le()?;
|
||||
|
||||
println!("\n#{} - {}, Size: {} {}", part_n, part_entry.name(), part_entry.size, if part_entry.is_encrypted() {"[ENCRYPTED]"} else {""} );
|
||||
println!("\n#{} - {}, Size: {}{} {}",
|
||||
part_n, part_entry.name(), part_entry.size, if part_entry.is_compressed() {" [COMPRESSED]"} else {""}, if part_entry.is_encrypted() {"[ENCRYPTED]"} else {""} );
|
||||
|
||||
let data = common::read_exact(&mut file, part_entry.size as usize)?;
|
||||
let out_data;
|
||||
@@ -108,14 +113,27 @@ pub fn extract_mtk_pkg_old(mut file: &File, output_folder: &str) -> Result<(), B
|
||||
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[extra_header_len as usize..])?;
|
||||
|
||||
if part_entry.is_compressed() {
|
||||
let lzhs_out_path = Path::new(&output_folder).join(part_entry.name() + ".bin");
|
||||
match decompress_lzhs_fs_file2file_old(&out_file, lzhs_out_path) {
|
||||
Ok(()) => {
|
||||
println!("- Decompressed Successfully!");
|
||||
//after successfull decompression remove the temporary .lzhs file
|
||||
fs::remove_file(&output_path)?;
|
||||
},
|
||||
Err(e) => {
|
||||
eprintln!("Failed to decompress partition!, Error: {}. Saving compressed data...", e);
|
||||
//if the decompression is not successfull leave out compressed data.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("-- Saved file!");
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@ struct LzhsHeader {
|
||||
#[br(count = 6)] padding: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct LzhsOldSegmentHdr {
|
||||
_uncompressed_size: u32,
|
||||
_compressed_size: u32,
|
||||
}
|
||||
|
||||
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)?;
|
||||
@@ -82,6 +88,45 @@ pub fn decompress_lzhs_fs_file2file(mut file: &File, output_file: PathBuf) -> Re
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// OLD VARIANT use in old mtk pkg
|
||||
pub fn decompress_lzhs_fs_file2file_old(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; 0x200]; //first 512b is uncompressed
|
||||
file.read_exact(&mut uncompressed_heading)?;
|
||||
out_file.write_all(&uncompressed_heading)?;
|
||||
|
||||
while file.stream_position().unwrap() < file_size {
|
||||
let _segment_header: LzhsOldSegmentHdr = file.read_le()?;
|
||||
let lzhs_header: LzhsHeader = file.read_le()?;
|
||||
|
||||
println!("[LZHS] Segment - Compressed size: {}, Decompressed size: {}, Expected Checksum: 0x{:02x?}",
|
||||
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)?;
|
||||
let mut out_data;
|
||||
let out_huff = unhuff(&compressed_data);
|
||||
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);
|
||||
return Err("Checksum mismatch!".into());
|
||||
} else {
|
||||
println!("--- Checksum OK!")
|
||||
}
|
||||
|
||||
out_file.write_all(&out_data)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct HuffmanCtx {
|
||||
c: u8,
|
||||
|
||||
Reference in New Issue
Block a user