mstar: further code optimizations + lzop optimization. fix memory issue by writing directly to file

This commit is contained in:
theubusu
2025-11-23 22:37:03 +01:00
parent faad86f5a7
commit 7637cdfe68
2 changed files with 106 additions and 113 deletions
+9 -18
View File
@@ -5,12 +5,12 @@ use lz4::block::decompress;
use lzma_rs::lzma_decompress; use lzma_rs::lzma_decompress;
use crate::common; use crate::common;
use crate::utils::lzop::{decompress_lzop}; use crate::utils::lzop::{unlzop_to_file};
use crate::utils::sparse::{unsparse_to_file}; use crate::utils::sparse::{unsparse_to_file};
//change whether the "userdata" partition is skipped //change whether the "userdata" partition is skipped
// this is because the userdata partition is sometimes enourmous sizes like 27gb, and it will fail to allocate memory on most computers // this is because the userdata partition is sometimes enourmous sizes like 27gb, and it is empty anyways
// if you want to attempt to extract "userdata" you can enable the option // if you want to extract "userdata" you can disable the option
static CONFIG_SKIP_USERDATA: bool = true; static CONFIG_SKIP_USERDATA: bool = true;
pub fn is_mstar_file(file: &File) -> bool { pub fn is_mstar_file(file: &File) -> bool {
@@ -76,13 +76,9 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std
let lines: Vec<&str> = script_string.lines().map(|l| l.trim()).collect(); let lines: Vec<&str> = script_string.lines().map(|l| l.trim()).collect();
let mut i = 0; let mut i = 0;
while i < lines.len() { for line in &lines {
let line = lines[i];
if line.starts_with("filepartload") { if line.starts_with("filepartload") {
let parts: Vec<&str> = line.split_whitespace().collect(); let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 5 {
let offset = parse_number(parts[3]).unwrap_or(0); let offset = parse_number(parts[3]).unwrap_or(0);
let size = parse_number(parts[4]).unwrap_or(0); let size = parse_number(parts[4]).unwrap_or(0);
@@ -93,7 +89,6 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std
// "unknown" // "unknown"
//}; //};
let mut partname = "unknown"; let mut partname = "unknown";
let mut compression = "none"; let mut compression = "none";
let mut lz4_expect_size = 0; let mut lz4_expect_size = 0;
let mut j = i + 1; let mut j = i + 1;
@@ -173,30 +168,26 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box<dyn std
out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?; out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?;
} else if compression == "lzo" { } else if compression == "lzo" {
println!("- Decompessing LZO.."); println!("- Decompessing LZO..");
out_data = decompress_lzop(&data)?; unlzop_to_file(&data, output_path)?;
println!("-- Saved file!");
i += 1;
continue
} else if compression == "sparse" { } else if compression == "sparse" {
println!("- Unsparsing..."); println!("- Unsparsing...");
unsparse_to_file(&data, output_path)?; unsparse_to_file(&data, output_path)?;
println!("-- Saved file!"); println!("-- Saved file!");
i += 1; i += 1;
continue continue
//out_data = unsparse(&data)?;
} else { } else {
out_data = data; out_data = data;
} }
fs::create_dir_all(&output_folder)?; fs::create_dir_all(&output_folder)?;
let mut out_file = OpenOptions::new() let mut out_file = OpenOptions::new().append(true).create(true).open(output_path)?;
.append(true)
.create(true)
.open(output_path)?;
out_file.write_all(&out_data)?; out_file.write_all(&out_data)?;
println!("-- Saved file!"); println!("-- Saved file!");
} }
} }
}
i += 1; i += 1;
} }
+7 -5
View File
@@ -1,5 +1,7 @@
use binrw::{BinRead, BinReaderExt}; use binrw::{BinRead, BinReaderExt};
use std::io::{Cursor}; use std::fs::OpenOptions;
use std::path::{PathBuf};
use std::io::{Cursor, Write};
use simd_adler32::adler32; use simd_adler32::adler32;
use crate::common; use crate::common;
@@ -28,7 +30,7 @@ struct SegmentHeader {
checksum: u32, checksum: u32,
} }
pub fn decompress_lzop(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> { pub fn unlzop_to_file(data: &[u8], file_path: PathBuf) -> Result<(), Box<dyn std::error::Error>> {
let mut data_reader = Cursor::new(data); let mut data_reader = Cursor::new(data);
let header: LzopHeader = data_reader.read_be()?; let header: LzopHeader = data_reader.read_be()?;
if header.magic_bytes != b"\x89LZO\x00\x0D\x0A\x1A\x0A" { if header.magic_bytes != b"\x89LZO\x00\x0D\x0A\x1A\x0A" {
@@ -39,7 +41,7 @@ pub fn decompress_lzop(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error
} }
let lzo = minilzo_rs::LZO::init()?; let lzo = minilzo_rs::LZO::init()?;
let mut decompressed_output = Vec::new(); let mut out_file = OpenOptions::new().create(true).append(true).open(file_path)?;
loop { loop {
if (data.len() as u64 - data_reader.position()) < 12 { //check if there are enough bytes to read a segment header if (data.len() as u64 - data_reader.position()) < 12 { //check if there are enough bytes to read a segment header
break; break;
@@ -66,8 +68,8 @@ pub fn decompress_lzop(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error
return Err("Invalid segment checksum! Data corrupted?".into()); return Err("Invalid segment checksum! Data corrupted?".into());
}; };
decompressed_output.extend_from_slice(&out_data); out_file.write_all(&out_data)?;
} }
Ok(decompressed_output) Ok(())
} }