diff --git a/README.md b/README.md index b040e71..90e234e 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,8 @@ Options: **Notes:** Pre-2011 files are not supported. **Options:** `sddl_sec:save_extra` - Save SDIT.FDI and .TXT files that are not extracted by default. -`sddl_sec:split_peaks` - Split PEAKS module into partitions (only on older files). +`sddl_sec:split_peaks` - Split PEAKS module into partitions (only on older files). This will also automatically decompress compressed partitions. +`sddl_sec:no_decomp_peaks` - Do not automatically decompress partitions when splitting PEAKS with above option. ## SLP **Used in:** Samsung Tizen-based NX series cameras diff --git a/src/formats/sddl_sec/mod.rs b/src/formats/sddl_sec/mod.rs index 6bf6c63..90f1513 100644 --- a/src/formats/sddl_sec/mod.rs +++ b/src/formats/sddl_sec/mod.rs @@ -70,6 +70,7 @@ pub fn extract_sddl_sec(app_ctx: &AppContext, _ctx: Box) -> Result<(), let mut file = app_ctx.file().ok_or("Extractor expected file")?; let save_extra = app_ctx.options.iter().any(|e| e == "sddl_sec:save_extra"); let split_peaks = app_ctx.options.iter().any(|e| e == "sddl_sec:split_peaks"); + let decomp_peaks = !app_ctx.options.iter().any(|e| e == "sddl_sec:no_decomp_peaks"); let mut secfile_hdr_reader = Cursor::new(decipher(&common::read_exact(&mut file, 32)?)); let secfile_header: SecHeader = secfile_hdr_reader.read_be()?; @@ -164,7 +165,7 @@ pub fn extract_sddl_sec(app_ctx: &AppContext, _ctx: Box) -> Result<(), if split_peaks && module.module_name() == "PEAKS" { println!("\n- Splitting PEAKS"); if let Some(ref path) = final_out_path { - split_peaks_file(path, &app_ctx.output_dir)?; + split_peaks_file(path, &app_ctx.output_dir, decomp_peaks)?; } } } diff --git a/src/formats/sddl_sec/util.rs b/src/formats/sddl_sec/util.rs index 6e90091..f9b9a6e 100644 --- a/src/formats/sddl_sec/util.rs +++ b/src/formats/sddl_sec/util.rs @@ -1,7 +1,10 @@ +use binrw::{BinReaderExt, Endian}; use crate::utils::common; -use std::{fs::{self, File, OpenOptions}, io::Write, path::{Path, PathBuf}}; +use std::{fs::{self, File, OpenOptions}, io::{Cursor, Seek, SeekFrom, Write}, path::{Path, PathBuf}}; -pub fn split_peaks_file(path: &PathBuf, out_path: &PathBuf) -> Result<(), Box> { +use crate::utils::compression::decompress_zlib; + +pub fn split_peaks_file(path: &PathBuf, out_path: &PathBuf, do_decomp: bool) -> Result<(), Box> { let mut file = File::open(path)?; let file_size = file.metadata()?.len(); let output_folder = Path::new(&out_path).join("PEAKS"); @@ -70,14 +73,70 @@ pub fn split_peaks_file(path: &PathBuf, out_path: &PathBuf) -> Result<(), Box Result<(), Box> { + let mut reader = Cursor::new(data); + let mut out_file = OpenOptions::new().append(true).create(true).open(out_path)?; + + //detect endianness, we can safely assume uncomp size wontbe larger than 4294901760 + let uncomp_chen = common::read_exact(&mut reader, 4)?; + let endianness = if uncomp_chen[0..2] == *b"\x00\x00" { + Endian::Little + } else { + Endian::Big + }; + + reader.seek(SeekFrom::Start(0))?; + let uncompressed_size: u32 = reader.read_type(endianness)?; + let first_blk: u32 = reader.read_type(endianness)?; + let count_blks = (first_blk - 4) / 4; + + println!("[INFO] Endianness: {}, Uncompressed size: {}, First block loc: {}, Block count: {}", + endianness, uncompressed_size, first_blk, count_blks); + + reader.seek(SeekFrom::Start(4))?; + + let mut block_locs: Vec = Vec::new(); + + for _ in 0..count_blks { + let loc: u32 = reader.read_type(endianness)?; + block_locs.push(loc); + } + + for (n, blk) in block_locs.iter().enumerate() { + reader.seek(SeekFrom::Start(*blk as u64))?; + + print!("\rDecompressing... {}/{}", + n + 1, count_blks); + std::io::stdout().flush()?; + + //special handling for last block since there is no next block to check, just assume 16k + let blk_size = if n == count_blks as usize - 1 {16384} else {block_locs[n + 1] - blk}; + + let compressed = common::read_exact(&mut reader, blk_size as usize)?; + let decompressed = decompress_zlib(&compressed)?; + + out_file.write_all(&decompressed)?; + } + + println!(); + Ok(()) } \ No newline at end of file