mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
TPV TIMG extractor added
This commit is contained in:
Generated
+35
@@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
@@ -192,6 +198,15 @@ version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
@@ -218,6 +233,16 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
@@ -291,6 +316,15 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
@@ -368,6 +402,7 @@ dependencies = [
|
||||
"aes",
|
||||
"cbc",
|
||||
"clap",
|
||||
"flate2",
|
||||
"lz4",
|
||||
"lzma-rs",
|
||||
"md5",
|
||||
|
||||
+2
-1
@@ -10,4 +10,5 @@ lzma-rs = "0.3"
|
||||
aes = "0.8.4"
|
||||
cbc = "0.1.2"
|
||||
md5 = "0.7"
|
||||
sha1 = "0.10"
|
||||
sha1 = "0.10"
|
||||
flate2 = "1.0"
|
||||
@@ -6,5 +6,7 @@ pub fn read_file(mut file: &File, offset: u64, size: usize) -> Result<Vec<u8>, B
|
||||
let mut buffer = vec![0u8; size];
|
||||
let _bytes_read = file.read(&mut buffer)?;
|
||||
|
||||
// reset seek (!
|
||||
file.seek(SeekFrom::Start(offset))?;
|
||||
Ok(buffer)
|
||||
}
|
||||
+2
-1
@@ -1,2 +1,3 @@
|
||||
pub mod mstar;
|
||||
pub mod samsung_old;
|
||||
pub mod samsung_old;
|
||||
pub mod tpv_timg;
|
||||
@@ -147,6 +147,8 @@ pub fn extract_samsung_old(path: &PathBuf, output_folder: &str) -> Result<(), Bo
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Extraction finished!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
use std::str;
|
||||
use std::path::{Path};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
|
||||
use flate2::read::GzDecoder;
|
||||
|
||||
use crate::common;
|
||||
|
||||
pub fn is_tpv_timg_file(file: &File) -> 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 == "TIMG"{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn decompress_gzip(compressed_data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
let mut decoder = GzDecoder::new(compressed_data);
|
||||
let mut decompressed = Vec::new();
|
||||
decoder.read_to_end(&mut decompressed)?;
|
||||
Ok(decompressed)
|
||||
}
|
||||
|
||||
fn read_exact<R: Read>(reader: &mut R, size: usize) -> io::Result<Vec<u8>> {
|
||||
let mut buf = vec![0u8; size];
|
||||
reader.read_exact(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn string_from_bytes(buf: &[u8]) -> String {
|
||||
let end = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
|
||||
String::from_utf8_lossy(&buf[..end]).to_string()
|
||||
}
|
||||
|
||||
pub fn extract_tpv_timg(mut file: &File, output_folder: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
//TIMG header
|
||||
let _timg = read_exact(&mut file, 288)?;
|
||||
|
||||
loop {
|
||||
//PIMG
|
||||
let mut pimg = [0u8; 4];
|
||||
if file.read_exact(&mut pimg).is_err() {
|
||||
break; //EOF
|
||||
} else {
|
||||
assert!(&pimg == b"PIMG", "Invalid PIMG section!");
|
||||
}
|
||||
|
||||
//4 bytes 00
|
||||
let _ = read_exact(&mut file, 4)?;
|
||||
|
||||
//4 bytes size
|
||||
let size_bytes = read_exact(&mut file, 4)?;
|
||||
let size = u32::from_le_bytes(size_bytes.try_into().unwrap());
|
||||
|
||||
//4 bytes nothing
|
||||
let _ = read_exact(&mut file, 4)?;
|
||||
|
||||
//16 bytes checksum? or maybe signature
|
||||
let _checksum = read_exact(&mut file, 16)?;
|
||||
|
||||
//16 bytes name
|
||||
let name_bytes = read_exact(&mut file, 16)?;
|
||||
let name = string_from_bytes(&name_bytes);
|
||||
|
||||
//64 bytes destination device
|
||||
let dev_bytes = read_exact(&mut file, 64)?;
|
||||
let dev = string_from_bytes(&dev_bytes);
|
||||
|
||||
//16 bytes compression type
|
||||
let comp_bytes = read_exact(&mut file, 16)?;
|
||||
let comp_type = string_from_bytes(&comp_bytes);
|
||||
|
||||
//1032 bytes maybe comment? skip this
|
||||
let _ = read_exact(&mut file, 1032)?;
|
||||
|
||||
//actual data
|
||||
let data = read_exact(&mut file, size as usize)?;
|
||||
|
||||
println!("PIMG - Name: {} Size: {} Dest: {} Compression: {}", name, size, dev, comp_type);
|
||||
|
||||
let out_data;
|
||||
|
||||
if comp_type == "gzip" {
|
||||
println!("- Decompressing gzip...");
|
||||
out_data = decompress_gzip(&data)?;
|
||||
} else if comp_type == "none" {
|
||||
out_data = data;
|
||||
} else {
|
||||
println!("- Warning: unsupported compression type!");
|
||||
out_data = data;
|
||||
}
|
||||
|
||||
let output_path = Path::new(&output_folder).join(name + ".bin");
|
||||
|
||||
fs::create_dir_all(&output_folder)?;
|
||||
let mut out_file = OpenOptions::new()
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(output_path)?;
|
||||
|
||||
out_file.write_all(&out_data)?;
|
||||
|
||||
println!("- Saved file!");
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Extraction finished!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+5
-1
@@ -34,7 +34,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
println!();
|
||||
|
||||
if formats::mstar::is_mstar_file(&file) {
|
||||
if formats::tpv_timg::is_tpv_timg_file(&file) {
|
||||
println!("TPV TIMG file detected!");
|
||||
println!();
|
||||
formats::tpv_timg::extract_tpv_timg(&file, &output_path)?;
|
||||
} else if formats::mstar::is_mstar_file(&file) {
|
||||
println!("Mstar upgrade file detected!");
|
||||
println!();
|
||||
formats::mstar::extract_mstar(&file, &output_path)?;
|
||||
|
||||
Reference in New Issue
Block a user