mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
improve append file handling + misc change
This commit is contained in:
@@ -45,6 +45,10 @@ pub fn extract_android_ota_payload(app_ctx: &AppContext, _ctx: Box<dyn Any>) ->
|
||||
println!("\n#{} - {}, Size: {}, Operations: {}",
|
||||
i + 1, partition.partition_name, partition.new_partition_info.unwrap().size.unwrap(), operation_count);
|
||||
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", partition.partition_name));
|
||||
let mut out_file = OpenOptions::new().write(true).create(true).truncate(true).open(output_path)?;
|
||||
|
||||
for (i, operation) in partition.operations.into_iter().enumerate() {
|
||||
let operation_name_str = match install_operation::Type::try_from(operation.r#type) {
|
||||
Ok(t) => t.as_str_name(),
|
||||
@@ -76,9 +80,6 @@ pub fn extract_android_ota_payload(app_ctx: &AppContext, _ctx: Box<dyn Any>) ->
|
||||
break
|
||||
}
|
||||
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", partition.partition_name));
|
||||
let mut out_file = OpenOptions::new().append(true).create(true).open(output_path)?;
|
||||
out_file.write_all(&out_data)?;
|
||||
}
|
||||
println!("\n-- Saved!");
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
use crate::utils::common;
|
||||
use binrw::BinRead;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum Epk1Type {
|
||||
LittleEndian,
|
||||
BigEndian,
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
pub struct CommonHeader {
|
||||
_magic_bytes: [u8; 4],
|
||||
|
||||
@@ -25,16 +25,16 @@ pub fn is_epk1_file(app_ctx: &AppContext) -> Result<Option<Box<dyn Any>>, Box<dy
|
||||
pub fn extract_epk1(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut file = app_ctx.file().ok_or("Extractor expected file")?;
|
||||
//check type of epk1
|
||||
let epk1_type;
|
||||
let epk1_type: Epk1Type;
|
||||
let init_pak_count_bytes = common::read_file(&file, 8, 4)?;
|
||||
let init_pak_count = u32::from_le_bytes(init_pak_count_bytes.try_into().unwrap());
|
||||
|
||||
if init_pak_count > 256 {
|
||||
println!("\nBig endian EPK1 detected.");
|
||||
epk1_type = "be";
|
||||
epk1_type = Epk1Type::BigEndian;
|
||||
} else if init_pak_count < 33 {
|
||||
println!("\nLittle endian EPK1 detected.");
|
||||
epk1_type = "le";
|
||||
epk1_type = Epk1Type::LittleEndian;
|
||||
} else {
|
||||
return Err("Unknown EPK1 variant!".into());
|
||||
}
|
||||
@@ -43,7 +43,7 @@ pub fn extract_epk1(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
|
||||
|
||||
let mut paks: Vec<Pak> = Vec::new();
|
||||
|
||||
if epk1_type == "be" {
|
||||
if epk1_type == Epk1Type::BigEndian {
|
||||
let header: CommonHeader = file.read_be()?;
|
||||
|
||||
for _i in 0..10 { //header can fit max 10 pak entries
|
||||
@@ -63,7 +63,7 @@ pub fn extract_epk1(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
|
||||
println!("EPK info -\nData size: {}\nPak count: {}\nVersion: {:02x?}.{:02x?}.{:02x?}",
|
||||
header.file_size, header.pak_count, version[1], version[2], version[3]);
|
||||
|
||||
} else if epk1_type == "le" {
|
||||
} else if epk1_type == Epk1Type::LittleEndian {
|
||||
let header: CommonHeader = file.read_le()?;
|
||||
|
||||
//this is to make an odd variant with 32 max pak entries work
|
||||
@@ -97,7 +97,7 @@ pub fn extract_epk1(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
|
||||
|
||||
for (i, pak) in paks.iter().enumerate() {
|
||||
file.seek(SeekFrom::Start(pak.offset as u64))?;
|
||||
let pak_header: PakHeader = if epk1_type == "be" {file.read_be()?} else {file.read_le()?};
|
||||
let pak_header: PakHeader = if epk1_type == Epk1Type::BigEndian {file.read_be()?} else {file.read_le()?};
|
||||
|
||||
println!("\n({}/{}) - {}, Offset: {}, Size: {}, Platform: {}",
|
||||
i + 1, paks.len(), pak_header.pak_name(), pak.offset, pak_header.image_size, pak_header.platform_id());
|
||||
|
||||
@@ -98,6 +98,10 @@ pub fn extract_epk2(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
|
||||
println!("\n({}/{}) - {}, Size: {}, Segment count: {}, Platform: {}",
|
||||
pak_n + 1, paks.len(), pak.name, pak_header.image_size, pak_header.segment_count, pak_header.platform_id());
|
||||
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", pak.name));
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().write(true).create(true).truncate(true).open(output_path)?;
|
||||
|
||||
for i in 0..pak_header.segment_count {
|
||||
// for first segment we already read the header so skip doing that for it
|
||||
if i > 0 {
|
||||
@@ -137,9 +141,6 @@ pub fn extract_epk2(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
|
||||
let segment_data = common::read_exact(&mut file, actual_segment_size as usize)?;
|
||||
let out_data = decrypt_aes_ecb_auto(&matching_key_bytes, &segment_data)?;
|
||||
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", pak.name));
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().append(true).create(true).open(output_path)?;
|
||||
out_file.write_all(&out_data)?;
|
||||
|
||||
println!("-- Saved to file!");
|
||||
|
||||
@@ -52,6 +52,10 @@ pub fn extract_epk2b(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
|
||||
println!("\n({}/{}) - {}, Size: {}, Segment count: {}, Platform: {}",
|
||||
i + 1, paks.len(), pak_header.pak_name(), pak_header.image_size, pak_header.segment_count, pak_header.platform_id());
|
||||
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", pak_header.pak_name()));
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().write(true).create(true).truncate(true).open(output_path)?;
|
||||
|
||||
for i in 0..pak_header.segment_count {
|
||||
// for first segment we already read the header so skip doing that for it
|
||||
if i > 0 {
|
||||
@@ -74,9 +78,6 @@ pub fn extract_epk2b(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
|
||||
pak_header.segment_size
|
||||
};
|
||||
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", pak_header.pak_name()));
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().append(true).create(true).open(output_path)?;
|
||||
out_file.write_all(&out_data[..segment_limit as usize])?;
|
||||
|
||||
println!("-- Saved to file!");
|
||||
|
||||
@@ -92,6 +92,10 @@ pub fn extract_epk3(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
|
||||
println!("\n({}) - {}, Size: {}, Segments: {}",
|
||||
pak_i, entry.package_name(), entry.package_size, entry.segment_count);
|
||||
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", entry.package_name()));
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().write(true).create(true).truncate(true).open(output_path)?;
|
||||
|
||||
for i in 0..entry.segment_count {
|
||||
if i > 0 {
|
||||
entry = pkg_info_reader.read_le()?;
|
||||
@@ -104,9 +108,6 @@ pub fn extract_epk3(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
|
||||
let encrypted_data = common::read_exact(&mut file, entry.segment_size as usize + extra_segment_size)?;
|
||||
let out_data = decrypt_aes_ecb_auto(matching_key_bytes, &encrypted_data)?;
|
||||
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", entry.package_name()));
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
let mut out_file = OpenOptions::new().append(true).create(true).open(output_path)?;
|
||||
out_file.write_all(&out_data[extra_segment_size..])?;
|
||||
|
||||
println!("-- Saved to file!");
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum CompressionType {
|
||||
None,
|
||||
Lzma,
|
||||
DoubleLzma,
|
||||
Lz4,
|
||||
Lzo,
|
||||
Sparse,
|
||||
}
|
||||
|
||||
pub fn parse_number(s: &str) -> Option<u64> {
|
||||
if let Some(hex_str) = s.strip_prefix("0x") {
|
||||
u64::from_str_radix(hex_str, 16).ok()
|
||||
|
||||
+13
-13
@@ -69,7 +69,7 @@ pub fn extract_mstar(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
|
||||
// "unknown"
|
||||
//};
|
||||
let mut partname = "unknown";
|
||||
let mut compression = "none";
|
||||
let mut compression: CompressionType = CompressionType::None;
|
||||
let mut lz4_expect_size = 0;
|
||||
let mut j = i + 1;
|
||||
|
||||
@@ -77,20 +77,20 @@ pub fn extract_mstar(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
|
||||
while j < lines.len() && !lines[j].starts_with("filepartload") {
|
||||
//get compression method
|
||||
if lines[j].starts_with("mscompress7"){
|
||||
if compression == "none" {
|
||||
compression = "lzma";
|
||||
} else if compression == "lzma" {
|
||||
if compression == CompressionType::None {
|
||||
compression = CompressionType::Lzma;
|
||||
} else if compression == CompressionType::Lzma {
|
||||
//thank the turks
|
||||
compression = "double_lzma";
|
||||
compression = CompressionType::DoubleLzma;
|
||||
}
|
||||
}
|
||||
if lines[j].starts_with("lz4"){
|
||||
compression = "lz4";
|
||||
compression = CompressionType::Lz4;
|
||||
let parts: Vec<&str> = lines[j].split_whitespace().collect();
|
||||
lz4_expect_size = parse_number(parts[5]).unwrap_or(0);
|
||||
}
|
||||
if lines[j].starts_with("mmc unlzo"){
|
||||
compression = "lzo";
|
||||
compression = CompressionType::Lzo;
|
||||
let parts: Vec<&str> = lines[j].split_whitespace().collect();
|
||||
// get part name from mmc unlzo
|
||||
if partname == "unknown" {
|
||||
@@ -98,7 +98,7 @@ pub fn extract_mstar(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
|
||||
}
|
||||
}
|
||||
if lines[j].starts_with("sparse_write"){
|
||||
compression = "sparse"; //its not really compression but anyway
|
||||
compression = CompressionType::Sparse; //its not really compression but anyway
|
||||
let parts: Vec<&str> = lines[j].split_whitespace().collect();
|
||||
// get part name from sparse_write
|
||||
if partname == "unknown" {
|
||||
@@ -133,24 +133,24 @@ pub fn extract_mstar(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box
|
||||
let out_data;
|
||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", partname));
|
||||
|
||||
if compression == "lzma" {
|
||||
if compression == CompressionType::Lzma {
|
||||
println!("- Decompressing LZMA...");
|
||||
out_data = decompress_lzma(&data)?;
|
||||
} else if compression == "double_lzma" {
|
||||
} else if compression == CompressionType::DoubleLzma {
|
||||
println!("- Decompressing LZMA (Pass 1)...");
|
||||
let pass_1 = decompress_lzma(&data)?;
|
||||
println!("- Decompressing LZMA (Pass 2)...");
|
||||
out_data = decompress_lzma(&pass_1)?;
|
||||
} else if compression == "lz4" {
|
||||
} else if compression == CompressionType::Lz4 {
|
||||
println!("- Decompressing lz4, expected size: {}", lz4_expect_size);
|
||||
out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?;
|
||||
} else if compression == "lzo" {
|
||||
} else if compression == CompressionType::Lzo {
|
||||
println!("- Decompessing LZO..");
|
||||
unlzop_to_file(&data, output_path)?;
|
||||
println!("-- Saved file!");
|
||||
i += 1;
|
||||
continue
|
||||
} else if compression == "sparse" {
|
||||
} else if compression == CompressionType::Sparse {
|
||||
println!("- Unsparsing...");
|
||||
unsparse_to_file(&data, output_path)?;
|
||||
println!("-- Saved file!");
|
||||
|
||||
@@ -196,6 +196,7 @@ fn extract_main(file_reader: &mut Cursor<Vec<u8>>, key: [u8; 8], output_path: &P
|
||||
}
|
||||
|
||||
let mut maine_i = 0;
|
||||
let mut main_out_file = OpenOptions::new().write(true).create(true).truncate(true).open(&output_path)?;
|
||||
for entry in &main_entries {
|
||||
maine_i += 1;
|
||||
let mut data = common::read_exact(file_reader, entry.size as usize)?;
|
||||
@@ -216,8 +217,7 @@ fn extract_main(file_reader: &mut Cursor<Vec<u8>>, key: [u8; 8], output_path: &P
|
||||
print!("\nMAIN ({}/{}) - ", maine_i, main_entries.len());
|
||||
let decompressed_data = decompress_data(&data)?;
|
||||
|
||||
let mut out_file = OpenOptions::new().append(true).create(true).open(&output_path)?;
|
||||
out_file.write_all(&decompressed_data)?;
|
||||
main_out_file.write_all(&decompressed_data)?;
|
||||
|
||||
println!("-- Saved to MAIN!");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user