From 6f4b3ccb53a45dd54e58750d594b5b28cdae2e67 Mon Sep 17 00:00:00 2001 From: theubusu <80545678+theubusu@users.noreply.github.com> Date: Tue, 7 Oct 2025 00:04:47 +0200 Subject: [PATCH] Add novatek extractor --- src/formats.rs | 3 +- src/formats/epk1.rs | 11 ++----- src/formats/novatek.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ src/formats/pfl_upg.rs | 21 +++---------- src/main.rs | 4 +++ 5 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 src/formats/novatek.rs diff --git a/src/formats.rs b/src/formats.rs index 87d1020..f5802d8 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -2,4 +2,5 @@ pub mod mstar; pub mod samsung_old; pub mod tpv_timg; pub mod pfl_upg; -pub mod epk1; \ No newline at end of file +pub mod epk1; +pub mod novatek; \ No newline at end of file diff --git a/src/formats/epk1.rs b/src/formats/epk1.rs index d5553eb..a37c2e7 100644 --- a/src/formats/epk1.rs +++ b/src/formats/epk1.rs @@ -22,7 +22,6 @@ struct Pak { } pub fn extract_epk1(mut file: &File, output_folder: &str) -> Result<(), Box> { - //check type of epk1 let epk1_type; let init_pak_count_bytes = common::read_file(&file, 8, 4)?; @@ -46,14 +45,11 @@ pub fn extract_epk1(mut file: &File, output_folder: &str) -> Result<(), Box = Vec::new(); if epk1_type == "be" { - //epak magic - let _epak = common::read_exact(&mut file, 4)?; + let _epak = common::read_exact(&mut file, 4)?; //epak magic - //file size let file_size_bytes = common::read_exact(&mut file, 4)?; let file_size = u32::from_be_bytes(file_size_bytes.try_into().unwrap()); - //pak count let pak_count_bytes = common::read_exact(&mut file, 4)?; let pak_count = u32::from_be_bytes(pak_count_bytes.try_into().unwrap()); @@ -79,14 +75,11 @@ pub fn extract_epk1(mut file: &File, output_folder: &str) -> Result<(), Box bool { + let header = common::read_file(&file, 0, 4).expect("Failed to read from file."); + let header_string = String::from_utf8_lossy(&header); + + if header_string == "NFWB"{ + true + } else { + false + } +} + +pub fn extract_novatek(mut file: &File, output_folder: &str) -> Result<(), Box> { + let _magic = common::read_exact(&mut file, 4)?; //NFWB magic + let _flags = common::read_exact(&mut file, 4)?; + let _header_size = common::read_exact(&mut file, 4)?; + let _ = common::read_exact(&mut file, 40)?; //unknown + + let part_count_bytes = common::read_exact(&mut file, 4)?; + let part_count = u32::from_le_bytes(part_count_bytes.try_into().unwrap()); + + let _first_part_offset = common::read_exact(&mut file, 4)?; + + println!("Part count: {}", part_count); + + let _ = common::read_exact(&mut file, 116)?; + + for i in 0..part_count { + let _ = common::read_exact(&mut file, 16)?; //unknown + + let index_bytes = common::read_exact(&mut file, 4)?; + let index = u32::from_le_bytes(index_bytes.try_into().unwrap()); + + let size_bytes = common::read_exact(&mut file, 4)?; + let size = u32::from_le_bytes(size_bytes.try_into().unwrap()); + + let offset_bytes = common::read_exact(&mut file, 4)?; + let offset = u32::from_le_bytes(offset_bytes.try_into().unwrap()); + + let current_pos = file.stream_position()?; + + let data = common::read_file(&file, offset as u64, size as usize)?; + + println!("- Part {}: index: {}, size: {}, offset: {}", i + 1, index, size, offset); + + let output_path = Path::new(&output_folder).join(format!("part_{}.bin", i + 1)); + + fs::create_dir_all(&output_folder)?; + let mut out_file = OpenOptions::new() + .write(true) + .create(true) + .open(output_path)?; + + out_file.write_all(&data)?; + + println!("-- Saved file!"); + + file.seek(std::io::SeekFrom::Start(current_pos))?; + + } + + Ok(()) +} \ No newline at end of file diff --git a/src/formats/pfl_upg.rs b/src/formats/pfl_upg.rs index 49f17bf..0c7d8b5 100644 --- a/src/formats/pfl_upg.rs +++ b/src/formats/pfl_upg.rs @@ -61,41 +61,30 @@ fn decrypt_aes256_ecb(key: &[u8], ciphertext: &[u8]) -> Result, Box Result<(), Box> { - //2SWU3TXV magic - let _ = common::read_exact(&mut file, 8)?; + let _ = common::read_exact(&mut file, 8)?; //2SWU3TXV magic - //header size let header_size_bytes = common::read_exact(&mut file, 4)?; let header_size = u32::from_le_bytes(header_size_bytes.try_into().unwrap()); - //data size let data_size_bytes = common::read_exact(&mut file, 4)?; let data_size = u32::from_le_bytes(data_size_bytes.try_into().unwrap()); - //crc32 - let _ = common::read_exact(&mut file, 4)?; + let _crc32 = common::read_exact(&mut file, 4)?; - //mask let mask_bytes = common::read_exact(&mut file, 4)?; let mask = u32::from_le_bytes(mask_bytes.try_into().unwrap()); - //data size decompressed - let _ = common::read_exact(&mut file, 4)?; + let _data_size_decompressed = common::read_exact(&mut file, 4)?; - //padding2? - let _ = common::read_exact(&mut file, 4)?; + let _padding2 = common::read_exact(&mut file, 4)?; - //description let description_bytes = common::read_exact(&mut file, 512)?; let description = common::string_from_bytes(&description_bytes); - //signature let signature = common::read_exact(&mut file, 128)?; - //unknown - let _ = common::read_exact(&mut file, 32)?; + let _ = common::read_exact(&mut file, 32)?; //unknown - //version string let version_bytes = common::read_exact(&mut file, header_size as usize - 704)?; let version = common::string_from_bytes(&version_bytes); diff --git a/src/main.rs b/src/main.rs index 0ab48d7..6e833b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,10 @@ fn main() -> Result<(), Box> { println!("TPV TIMG file detected!"); println!(); formats::tpv_timg::extract_tpv_timg(&file, &output_path)?; + } else if formats::novatek::is_novatek_file(&file) { + println!("Novatek file detected!"); + println!(); + formats::novatek::extract_novatek(&file, &output_path)?; } else if formats::epk1::is_epk1_file(&file) { println!("EPK1 file detected!"); println!();