Files
unixtract/src/formats/tpv_timg.rs
T

106 lines
2.9 KiB
Rust
Raw Normal View History

2025-09-25 17:49:02 +02:00
use std::str;
use std::path::{Path};
2025-09-27 00:31:18 +02:00
use std::io::{Read, Write};
2025-09-25 17:49:02 +02:00
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)
}
pub fn extract_tpv_timg(mut file: &File, output_folder: &str) -> Result<(), Box<dyn std::error::Error>> {
//TIMG header
2025-09-27 00:31:18 +02:00
let _timg = common::read_exact(&mut file, 288)?;
2025-09-25 17:49:02 +02:00
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
2025-09-27 00:31:18 +02:00
let _ = common::read_exact(&mut file, 4)?;
2025-09-25 17:49:02 +02:00
//4 bytes size
2025-09-27 00:31:18 +02:00
let size_bytes = common::read_exact(&mut file, 4)?;
2025-09-25 17:49:02 +02:00
let size = u32::from_le_bytes(size_bytes.try_into().unwrap());
//4 bytes nothing
2025-09-27 00:31:18 +02:00
let _ = common::read_exact(&mut file, 4)?;
2025-09-25 17:49:02 +02:00
//16 bytes checksum? or maybe signature
2025-09-27 00:31:18 +02:00
let _checksum = common::read_exact(&mut file, 16)?;
2025-09-25 17:49:02 +02:00
//16 bytes name
2025-09-27 00:31:18 +02:00
let name_bytes = common::read_exact(&mut file, 16)?;
let name = common::string_from_bytes(&name_bytes);
2025-09-25 17:49:02 +02:00
//64 bytes destination device
2025-09-27 00:31:18 +02:00
let dev_bytes = common::read_exact(&mut file, 64)?;
let dev = common::string_from_bytes(&dev_bytes);
2025-09-25 17:49:02 +02:00
//16 bytes compression type
2025-09-27 00:31:18 +02:00
let comp_bytes = common::read_exact(&mut file, 16)?;
let comp_type = common::string_from_bytes(&comp_bytes);
2025-09-25 17:49:02 +02:00
//1032 bytes maybe comment? skip this
2025-09-27 00:31:18 +02:00
let _ = common::read_exact(&mut file, 1032)?;
2025-09-25 17:49:02 +02:00
//actual data
2025-09-27 00:31:18 +02:00
let data = common::read_exact(&mut file, size as usize)?;
2025-09-25 17:49:02 +02:00
2025-10-06 22:44:30 +02:00
println!("- PIMG: Name: {} Size: {} Dest: {} Compression: {}", name, size, dev, comp_type);
2025-09-25 17:49:02 +02:00
let out_data;
if comp_type == "gzip" {
2025-10-06 22:44:30 +02:00
println!("-- Decompressing gzip...");
2025-09-25 17:49:02 +02:00
out_data = decompress_gzip(&data)?;
} else if comp_type == "none" {
out_data = data;
} else {
2025-10-06 22:44:30 +02:00
println!("-- Warning: unsupported compression type!");
2025-09-25 17:49:02 +02:00
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()
2025-10-06 22:44:30 +02:00
.write(true)
2025-09-25 17:49:02 +02:00
.create(true)
.open(output_path)?;
out_file.write_all(&out_data)?;
2025-10-06 22:44:30 +02:00
println!("-- Saved file!");
2025-09-25 17:49:02 +02:00
}
println!();
println!("Extraction finished!");
Ok(())
}