mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
mstar: add sparse_write and LZO compression support + some fixes
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
use binrw::{BinRead, BinReaderExt};
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::{PathBuf};
|
||||
use std::io::{Cursor, Seek, SeekFrom, Write};
|
||||
|
||||
use crate::common;
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct SparseHeader {
|
||||
#[br(count = 4)] magic_bytes: Vec<u8>,
|
||||
_major_version: u16,
|
||||
_minor_version: u16,
|
||||
_file_header_size: u16,
|
||||
_chunk_header_size: u16,
|
||||
block_size: u32,
|
||||
_total_blocks: u32,
|
||||
total_chunks: u32,
|
||||
_image_checksum: u32
|
||||
}
|
||||
|
||||
#[derive(BinRead, Debug)]
|
||||
struct ChunkHeader {
|
||||
chunk_type: u16,
|
||||
_reserved1: u16,
|
||||
chunk_size: u32,
|
||||
total_size: u32,
|
||||
}
|
||||
|
||||
pub fn unsparse_to_file(data: &[u8], file_path: PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut data_reader = Cursor::new(data);
|
||||
let file_header: SparseHeader = data_reader.read_le()?;
|
||||
if file_header.magic_bytes != b"\x3A\xFF\x26\xED" {
|
||||
return Err("Invalid magic!".into());
|
||||
}
|
||||
|
||||
let mut out_file = OpenOptions::new().create(true).read(true).write(true).open(file_path)?;
|
||||
|
||||
for _i in 0..file_header.total_chunks{
|
||||
let chunk_header: ChunkHeader = data_reader.read_le()?;
|
||||
let chunk_data = common::read_exact(&mut data_reader, chunk_header.total_size as usize - 12)?;
|
||||
|
||||
if chunk_header.chunk_type == 0xCAC1 { //"raw" type chunk (actual data)
|
||||
out_file.write_all(&chunk_data)?;
|
||||
} else if chunk_header.chunk_type == 0xCAC3 { // "dont care" type chunk (skip over)
|
||||
let skip_size = file_header.block_size as u64 * chunk_header.chunk_size as u64;
|
||||
let current_pos = out_file.stream_position()?;
|
||||
let new_pos = current_pos + skip_size;
|
||||
|
||||
//enlarge file with zeros if the seek is larger than file
|
||||
let current_file_size = out_file.metadata()?.len();
|
||||
if new_pos > current_file_size {
|
||||
out_file.set_len(new_pos)?;
|
||||
}
|
||||
|
||||
out_file.seek(SeekFrom::Start(new_pos))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user