From 0e7def869d3df504dbb694b2ef413e4fee271d24 Mon Sep 17 00:00:00 2001 From: theubusu <80545678+theubusu@users.noreply.github.com> Date: Thu, 22 Jan 2026 21:56:34 +0100 Subject: [PATCH] nvt_timg: add sparse support + some extra changes --- src/formats/nvt_timg.rs | 51 ++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/formats/nvt_timg.rs b/src/formats/nvt_timg.rs index a6ddf33..7739502 100644 --- a/src/formats/nvt_timg.rs +++ b/src/formats/nvt_timg.rs @@ -1,23 +1,36 @@ use std::str; use std::path::{Path}; -use std::io::{Write}; +use std::io::{Seek, Write}; use std::fs::{self, File, OpenOptions}; use binrw::{BinRead, BinReaderExt}; use crate::utils::common; use crate::utils::compression::{decompress_gzip}; +use crate::utils::sparse::{unsparse_to_file}; + +#[derive(Debug, BinRead)] +struct TIMG { + #[br(count = 4)] _magic_bytes: Vec, //TIMG + _unused1: u32, + data_size: u32, + _unused2: u32, + #[br(count = 16)] _md5_checksum: Vec, + #[br(count = 256)] _signature: Vec, +} #[derive(Debug, BinRead)] struct PIMG { - #[br(count = 4)] magic_bytes: Vec, - _unknown1: u32, + #[br(count = 4)] magic_bytes: Vec, //PIMG + _unused1: u32, size: u32, - _unknown2: u32, - #[br(count = 16)] _checksum: Vec, + _unused2: u32, + #[br(count = 16)] _md5_checksum: Vec, #[br(count = 16)] name_bytes: Vec, #[br(count = 64)] dest_dev_bytes: Vec, #[br(count = 16)] comp_type_bytes: Vec, - #[br(count = 1032)] _comment: Vec, + _unknown1: u32, + #[br(count = 1024)] _comment: Vec, + _unknown2: u32, } impl PIMG { fn name(&self) -> String { @@ -41,15 +54,14 @@ pub fn is_nvt_timg_file(file: &File) -> bool { } pub fn extract_nvt_timg(mut file: &File, output_folder: &str) -> Result<(), Box> { - let _timg = common::read_exact(&mut file, 288)?; //TIMG magic + header + let file_size = file.metadata()?.len(); + let timg: TIMG = file.read_le()?; + println!("File info:\nData size: {}", timg.data_size); - let mut pimg_i = 1; - loop { - let pimg = match file.read_le::() { - Ok(val) => val, - Err(_) => break, // EOF - }; - //there is an old format of TIMG, this is just temporary fix to prevent false extraction until i implement it. + let mut pimg_i = 0; + while file.stream_position()? < file_size as u64 { + pimg_i += 1; + let pimg: PIMG = file.read_le()?; if pimg.magic_bytes != b"PIMG" { println!("Invalid PIMG magic!"); return Ok(()); @@ -60,19 +72,23 @@ pub fn extract_nvt_timg(mut file: &File, output_folder: &str) -> Result<(), Box< println!("\n#{} - {}, Size: {}, Dest: {}, Compression: {}", pimg_i, pimg.name(), pimg.size, pimg.dest_dev(), pimg.comp_type()); let out_data; + let output_path = Path::new(&output_folder).join(pimg.name() + ".bin"); if pimg.comp_type() == "gzip" && data.starts_with(b"\x1F\x8B") { //additionally check for gzip header, because sometimes its deceptive println!("- Decompressing gzip..."); out_data = decompress_gzip(&data)?; - } else if pimg.comp_type() == "none" { + } else if pimg.comp_type() == "none" || pimg.comp_type() == "" { out_data = data; + } else if pimg.comp_type() == "sparse" { + println!("- Unsparsing..."); + unsparse_to_file(&data, output_path)?; + println!("-- Saved file!"); + continue } else { println!("- Warning: unsupported compression type!"); out_data = data; } - let output_path = Path::new(&output_folder).join(pimg.name() + ".bin"); - fs::create_dir_all(&output_folder)?; let mut out_file = OpenOptions::new() .write(true) @@ -82,7 +98,6 @@ pub fn extract_nvt_timg(mut file: &File, output_folder: &str) -> Result<(), Box< out_file.write_all(&out_data)?; println!("-- Saved file!"); - pimg_i += 1; } println!("\nExtraction finished!");