use crate::settings::Settings;
use anyhow::{bail, Result};
use larian_formats::{
bg3::{raw::Version, ModPakLsx, ModuleInfo},
lsf,
lspk::{self, DecompressedLspk},
};
use std::{fs::File, path::PathBuf};
impl Settings {
pub(crate) fn dump_helper(path: PathBuf) -> Result<()> {
parse_inner(std::iter::once(path), Style::Dump)
}
pub(crate) fn parse_helper(
paths: impl IntoIterator<Item = PathBuf>,
verbose: bool,
) -> Result<()> {
let style = if verbose {
Style::Verbose
} else {
Style::Basic
};
parse_inner(paths, style)
}
}
#[derive(Debug, Clone, Copy)]
enum Style {
Basic,
Dump,
Verbose,
}
impl Style {
const fn is_print(self) -> bool {
matches!(self, Self::Basic | Self::Verbose)
}
}
fn parse_inner(paths: impl IntoIterator<Item = PathBuf>, style: Style) -> Result<()> {
for path in paths {
if style.is_print() {
let displayed_path = path.display().to_string();
println!("{displayed_path}");
for _ in displayed_path.chars() {
print!("-");
}
println!();
}
let file = File::open(&path)?;
match path.extension().map(|s| s.to_string_lossy()).as_deref() {
Some("zip") => {
let data = lspk::entry_from_zipfile(&file)?;
print_lspk(data.1, style)?;
}
Some("lsf") => {
let data = lsf::Reader::new(file)?.read()?;
if style.is_print() {
data.print_summary();
}
}
Some("pak") => {
let data = lspk::Reader::new(file)?.read()?;
print_lspk(data, style)?;
}
_other => {
if style.is_print() {
bail!("expected .lsf or .pak file");
}
bail!("expected .pak file");
}
}
if style.is_print() {
println!();
}
}
Ok(())
}
fn print_lspk(data: DecompressedLspk, style: Style) -> Result<()> {
let meta_lsx = data.extract_meta_lsx()?;
let raw = String::from_utf8_lossy(&meta_lsx.decompressed_bytes);
if !style.is_print() {
println!("{raw}");
return Ok(());
}
let ModPakLsx {
version,
module_info,
} = meta_lsx.deserialize_as_mod_pak()?;
let Version {
major,
minor,
revision,
build,
} = version;
println!("Game version : {major}.{minor}.{revision}.{build}");
let ModuleInfo {
author,
description,
folder,
md5,
name,
num_players,
module_type,
uuid,
version,
} = module_info;
println!("Name : {name}");
println!("Folder : {folder}");
println!("Version64 : {version}");
println!("UUID : {uuid}");
if !matches!(style, Style::Verbose) {
return Ok(());
}
if let Some(author) = author {
println!("Author : {author}");
}
if let Some(description) = description {
println!("Description : {description}");
}
if let Some(md5) = md5 {
println!("MD5 : {md5}");
}
if let Some(num_players) = num_players {
println!("NumPlayers : {num_players}");
}
if let Some(module_type) = module_type {
println!("Type : {module_type}");
}
Ok(())
}