mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-19 23:32:55 -05:00
Compare commits
2 commits
4d58df5d15
...
263a990e6e
Author | SHA1 | Date | |
---|---|---|---|
263a990e6e | |||
db52e23ef7 |
6 changed files with 154 additions and 163 deletions
199
cz/src/binio.rs
199
cz/src/binio.rs
|
@ -1,70 +1,80 @@
|
||||||
use std::io::{self, Read, Write};
|
pub struct BitIo {
|
||||||
|
data: Vec<u8>,
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
|
||||||
|
|
||||||
/// A simple way to write individual bits to an input implementing [Write].
|
|
||||||
pub struct BitWriter<'a, O: Write + WriteBytesExt> {
|
|
||||||
output: &'a mut O,
|
|
||||||
|
|
||||||
current_byte: u8,
|
|
||||||
|
|
||||||
byte_offset: usize,
|
byte_offset: usize,
|
||||||
bit_offset: usize,
|
bit_offset: usize,
|
||||||
|
|
||||||
byte_size: usize,
|
byte_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, O: Write + WriteBytesExt> BitWriter<'a, O> {
|
impl BitIo {
|
||||||
/// Create a new BitWriter wrapper around something which
|
/// Create a new BitIO reader and writer over some data
|
||||||
/// implements [Write].
|
pub fn new(data: Vec<u8>) -> Self {
|
||||||
pub fn new(output: &'a mut O) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
output,
|
data,
|
||||||
|
|
||||||
current_byte: 0,
|
|
||||||
|
|
||||||
byte_offset: 0,
|
byte_offset: 0,
|
||||||
bit_offset: 0,
|
bit_offset: 0,
|
||||||
|
|
||||||
byte_size: 0,
|
byte_size: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of whole bytes written to the stream.
|
/// Get the byte offset of the reader
|
||||||
|
pub fn byte_offset(&self) -> usize {
|
||||||
|
self.byte_offset
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the byte size of the reader
|
||||||
pub fn byte_size(&self) -> usize {
|
pub fn byte_size(&self) -> usize {
|
||||||
self.byte_size
|
self.byte_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the bit offset within the current byte.
|
/// Get the current bytes up to `byte_size` in the reader
|
||||||
pub fn bit_offset(&self) -> u8 {
|
pub fn bytes(&self) -> Vec<u8> {
|
||||||
self.bit_offset as u8
|
self.data[..self.byte_size].to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the stream is aligned to a byte.
|
/// Read some bits from the buffer
|
||||||
pub fn aligned(&self) -> bool {
|
pub fn read_bit(&mut self, bit_len: usize) -> u64 {
|
||||||
self.bit_offset() == 0
|
if bit_len > 8 * 8 {
|
||||||
|
panic!("Cannot read more than 64 bits")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Align the writer to the nearest byte by padding with zero bits.
|
if bit_len % 8 == 0 && self.bit_offset == 0 {
|
||||||
///
|
return self.read(bit_len / 8);
|
||||||
/// Returns the number of zero bits
|
}
|
||||||
pub fn flush(&mut self) -> Result<usize, io::Error> {
|
|
||||||
|
let mut result = 0;
|
||||||
|
for i in 0..bit_len {
|
||||||
|
let bit_value = ((self.data[self.byte_offset] as usize >> self.bit_offset) & 1) as u64;
|
||||||
|
self.bit_offset += 1;
|
||||||
|
|
||||||
|
if self.bit_offset == 8 {
|
||||||
self.byte_offset += 1;
|
self.byte_offset += 1;
|
||||||
|
|
||||||
// Write out the current byte unfinished
|
|
||||||
self.output.write_u8(self.current_byte).unwrap();
|
|
||||||
self.current_byte = 0;
|
|
||||||
self.bit_offset = 0;
|
self.bit_offset = 0;
|
||||||
|
|
||||||
Ok(8 - self.bit_offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write some bits to the output.
|
result |= bit_value << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read some bytes from the buffer
|
||||||
|
pub fn read(&mut self, byte_len: usize) -> u64 {
|
||||||
|
if byte_len > 8 {
|
||||||
|
panic!("Cannot read more than 8 bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut padded_slice = [0u8; 8];
|
||||||
|
padded_slice.copy_from_slice(&self.data[self.byte_offset..self.byte_offset + byte_len]);
|
||||||
|
self.byte_offset += byte_len;
|
||||||
|
|
||||||
|
u64::from_le_bytes(padded_slice)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write some bits to the buffer
|
||||||
pub fn write_bit(&mut self, data: u64, bit_len: usize) {
|
pub fn write_bit(&mut self, data: u64, bit_len: usize) {
|
||||||
if bit_len > 64 {
|
if bit_len > 8 * 8 {
|
||||||
panic!("Cannot write more than 64 bits at once.");
|
panic!("Cannot write more than 64 bits");
|
||||||
} else if bit_len == 0 {
|
|
||||||
panic!("Must write 1 or more bits.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if bit_len % 8 == 0 && self.bit_offset == 0 {
|
if bit_len % 8 == 0 && self.bit_offset == 0 {
|
||||||
|
@ -75,115 +85,32 @@ impl<'a, O: Write + WriteBytesExt> BitWriter<'a, O> {
|
||||||
for i in 0..bit_len {
|
for i in 0..bit_len {
|
||||||
let bit_value = (data >> i) & 1;
|
let bit_value = (data >> i) & 1;
|
||||||
|
|
||||||
self.current_byte &= !(1 << self.bit_offset);
|
self.data[self.byte_offset] &= !(1 << self.bit_offset);
|
||||||
|
|
||||||
self.current_byte |= (bit_value << self.bit_offset) as u8;
|
self.data[self.byte_offset] |= (bit_value << self.bit_offset) as u8;
|
||||||
|
|
||||||
self.bit_offset += 1;
|
self.bit_offset += 1;
|
||||||
if self.bit_offset >= 8 {
|
|
||||||
self.byte_offset += 1;
|
|
||||||
self.bit_offset = 0;
|
|
||||||
|
|
||||||
self.output.write_u8(self.current_byte).unwrap();
|
|
||||||
self.current_byte = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.byte_size = self.byte_offset + (self.bit_offset + 7) / 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write some bytes to the output.
|
|
||||||
pub fn write(&mut self, data: u64, byte_len: usize) {
|
|
||||||
if byte_len > 8 {
|
|
||||||
panic!("Cannot write more than 8 bytes at once.")
|
|
||||||
} else if byte_len == 0 {
|
|
||||||
panic!("Must write 1 or more bytes.")
|
|
||||||
}
|
|
||||||
|
|
||||||
self.output
|
|
||||||
.write_all(&data.to_le_bytes()[..byte_len])
|
|
||||||
.unwrap();
|
|
||||||
self.byte_offset += byte_len;
|
|
||||||
|
|
||||||
self.byte_size = self.byte_offset + (self.bit_offset + 7) / 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simple way to read individual bits from an input implementing [Read].
|
|
||||||
pub struct BitReader<'a, I: Read + ReadBytesExt> {
|
|
||||||
input: &'a mut I,
|
|
||||||
|
|
||||||
current_byte: Option<u8>,
|
|
||||||
|
|
||||||
byte_offset: usize,
|
|
||||||
bit_offset: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I: Read + ReadBytesExt> BitReader<'a, I> {
|
|
||||||
/// Create a new BitReader wrapper around something which
|
|
||||||
/// implements [Write].
|
|
||||||
pub fn new(input: &'a mut I) -> Self {
|
|
||||||
let first = input.read_u8().unwrap();
|
|
||||||
Self {
|
|
||||||
input,
|
|
||||||
|
|
||||||
current_byte: Some(first),
|
|
||||||
|
|
||||||
byte_offset: 0,
|
|
||||||
bit_offset: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the number of whole bytes read from the stream.
|
|
||||||
pub fn byte_offset(&self) -> usize {
|
|
||||||
self.byte_offset
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read some bits from the input.
|
|
||||||
pub fn read_bit(&mut self, bit_len: usize) -> u64 {
|
|
||||||
if bit_len > 64 {
|
|
||||||
panic!("Cannot read more than 64 bits at once.")
|
|
||||||
} else if bit_len == 0 {
|
|
||||||
panic!("Must read 1 or more bits.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if bit_len % 8 == 0 && self.bit_offset == 0 {
|
|
||||||
return self.read(bit_len / 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = 0;
|
|
||||||
for i in 0..bit_len {
|
|
||||||
let bit_value = ((self.current_byte.unwrap() as usize >> self.bit_offset) & 1) as u64;
|
|
||||||
self.bit_offset += 1;
|
|
||||||
|
|
||||||
if self.bit_offset == 8 {
|
if self.bit_offset == 8 {
|
||||||
self.byte_offset += 1;
|
self.byte_offset += 1;
|
||||||
self.bit_offset = 0;
|
self.bit_offset = 0;
|
||||||
|
}
|
||||||
self.current_byte = Some(self.input.read_u8().unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result |= bit_value << i;
|
self.byte_size = self.byte_offset + (self.bit_offset + 7) / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
pub fn write(&mut self, data: u64, byte_len: usize) {
|
||||||
}
|
|
||||||
|
|
||||||
/// Read some bytes from the input.
|
|
||||||
pub fn read(&mut self, byte_len: usize) -> u64 {
|
|
||||||
if byte_len > 8 {
|
if byte_len > 8 {
|
||||||
panic!("Cannot read more than 8 bytes at once.")
|
panic!("Cannot write more than 8 bytes")
|
||||||
} else if byte_len == 0 {
|
|
||||||
panic!("Must read 1 or more bytes")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut padded_slice = vec![0u8; byte_len];
|
let mut padded_slice = [0u8; 8];
|
||||||
self.input.read_exact(&mut padded_slice).unwrap();
|
padded_slice.copy_from_slice(&data.to_le_bytes());
|
||||||
|
|
||||||
|
self.data[self.byte_offset..self.byte_offset + byte_len]
|
||||||
|
.copy_from_slice(&padded_slice[..byte_len]);
|
||||||
self.byte_offset += byte_len;
|
self.byte_offset += byte_len;
|
||||||
|
|
||||||
let extra_length = padded_slice.len() - byte_len;
|
self.byte_size = self.byte_offset + (self.bit_offset + 7) / 8;
|
||||||
padded_slice.extend_from_slice(&vec![0u8; extra_length]);
|
|
||||||
|
|
||||||
u64::from_le_bytes(padded_slice.try_into().unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
|
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io::{Cursor, Read, Seek, Write},
|
io::{Read, Seek, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::binio::{BitReader, BitWriter};
|
use crate::binio::BitIo;
|
||||||
use crate::common::CzError;
|
use crate::common::CzError;
|
||||||
|
|
||||||
/// The size of compressed data in each chunk
|
/// The size of compressed data in each chunk
|
||||||
|
@ -163,7 +163,7 @@ pub fn decompress2<T: Seek + ReadBytesExt + Read>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decompress_lzw2(input_data: &[u8], size: usize) -> Vec<u8> {
|
fn decompress_lzw2(input_data: &[u8], size: usize) -> Vec<u8> {
|
||||||
let mut data = Cursor::new(input_data);
|
let data = input_data;
|
||||||
let mut dictionary = HashMap::new();
|
let mut dictionary = HashMap::new();
|
||||||
for i in 0..256 {
|
for i in 0..256 {
|
||||||
dictionary.insert(i as u64, vec![i as u8]);
|
dictionary.insert(i as u64, vec![i as u8]);
|
||||||
|
@ -172,7 +172,7 @@ fn decompress_lzw2(input_data: &[u8], size: usize) -> Vec<u8> {
|
||||||
let mut result = Vec::with_capacity(size);
|
let mut result = Vec::with_capacity(size);
|
||||||
|
|
||||||
let data_size = input_data.len();
|
let data_size = input_data.len();
|
||||||
let mut bit_io = BitReader::new(&mut data);
|
let mut bit_io = BitIo::new(data.to_vec());
|
||||||
let mut w = dictionary.get(&0).unwrap().clone();
|
let mut w = dictionary.get(&0).unwrap().clone();
|
||||||
|
|
||||||
let mut element;
|
let mut element;
|
||||||
|
@ -362,9 +362,8 @@ fn compress_lzw2(data: &[u8], last: Vec<u8>) -> (usize, Vec<u8>, Vec<u8>) {
|
||||||
element = last
|
element = last
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_buf = Vec::new();
|
let mut bit_io = BitIo::new(vec![0u8; 0xF0000]);
|
||||||
let mut bit_io = BitWriter::new(&mut output_buf);
|
let write_bit = |bit_io: &mut BitIo, code: u64| {
|
||||||
let write_bit = |bit_io: &mut BitWriter<Vec<u8>>, code: u64| {
|
|
||||||
if code > 0x7FFF {
|
if code > 0x7FFF {
|
||||||
bit_io.write_bit(1, 1);
|
bit_io.write_bit(1, 1);
|
||||||
bit_io.write_bit(code, 18);
|
bit_io.write_bit(code, 18);
|
||||||
|
@ -403,17 +402,14 @@ fn compress_lzw2(data: &[u8], last: Vec<u8>) -> (usize, Vec<u8>, Vec<u8>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_io.flush().unwrap();
|
return (count, bit_io.bytes(), Vec::new());
|
||||||
return (count, output_buf, Vec::new());
|
|
||||||
} else if bit_io.byte_size() < 0x87BDF {
|
} else if bit_io.byte_size() < 0x87BDF {
|
||||||
if !last_element.is_empty() {
|
if !last_element.is_empty() {
|
||||||
write_bit(&mut bit_io, *dictionary.get(&last_element).unwrap());
|
write_bit(&mut bit_io, *dictionary.get(&last_element).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_io.flush().unwrap();
|
return (count, bit_io.bytes(), Vec::new());
|
||||||
return (count, output_buf, Vec::new());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_io.flush().unwrap();
|
(count, bit_io.bytes(), last_element)
|
||||||
(count, output_buf, last_element)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
[package]
|
[package]
|
||||||
name = "utils"
|
name = "utils"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "czutil"
|
name = "czutil"
|
||||||
|
@ -16,7 +17,10 @@ cz = { path = "../cz/", features = ["png"] }
|
||||||
luca_pak = { path = "../luca_pak/" }
|
luca_pak = { path = "../luca_pak/" }
|
||||||
|
|
||||||
image = { version = "0.25", default-features = false, features = ["png"] }
|
image = { version = "0.25", default-features = false, features = ["png"] }
|
||||||
clap = { version = "4.5.9", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive", "error-context"] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
vergen-git2 = { version = "1.0", features = ["build", "cargo", "rustc", "si"] }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
17
utils/build.rs
Normal file
17
utils/build.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
use vergen_git2::{BuildBuilder, CargoBuilder, Emitter, Git2Builder, RustcBuilder, SysinfoBuilder};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let build = BuildBuilder::all_build().unwrap();
|
||||||
|
let cargo = CargoBuilder::all_cargo().unwrap();
|
||||||
|
let git2 = Git2Builder::all_git().unwrap();
|
||||||
|
let rustc = RustcBuilder::all_rustc().unwrap();
|
||||||
|
let si = SysinfoBuilder::all_sysinfo().unwrap();
|
||||||
|
|
||||||
|
Emitter::default()
|
||||||
|
.add_instructions(&build).unwrap()
|
||||||
|
.add_instructions(&cargo).unwrap()
|
||||||
|
.add_instructions(&git2).unwrap()
|
||||||
|
.add_instructions(&rustc).unwrap()
|
||||||
|
.add_instructions(&si).unwrap()
|
||||||
|
.emit().unwrap();
|
||||||
|
}
|
|
@ -1,17 +1,22 @@
|
||||||
use clap::{error::ErrorKind, Error, Parser, Subcommand};
|
use clap::{error::ErrorKind, Command, Error, Parser, Subcommand};
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf}, process::exit,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Utility to maniuplate CZ image files from the LUCA System game engine by
|
/// Utility to maniuplate CZ image files from the LUCA System game engine by
|
||||||
/// Prototype Ltd.
|
/// Prototype Ltd.
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "CZ Utility")]
|
#[command(name = "CZ Utility")]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(author, version, about, long_about = None, disable_version_flag = true)]
|
||||||
|
#[command(arg_required_else_help(true))]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
/// Show program version information
|
||||||
|
#[arg(short('V'), long)]
|
||||||
|
version: bool,
|
||||||
|
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Commands,
|
command: Option<Commands>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
|
@ -63,8 +68,24 @@ enum Commands {
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
|
if cli.version {
|
||||||
|
println!(
|
||||||
|
"{}, {} v{}-{}",
|
||||||
|
env!("CARGO_BIN_NAME"),
|
||||||
|
env!("CARGO_PKG_NAME"),
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
&env!("VERGEN_GIT_SHA")[0..=6]
|
||||||
|
);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let command = match cli.command {
|
||||||
|
Some(c) => c,
|
||||||
|
None => exit(0),
|
||||||
|
};
|
||||||
|
|
||||||
// Check what subcommand was run
|
// Check what subcommand was run
|
||||||
match &cli.command {
|
match &command {
|
||||||
Commands::Decode {
|
Commands::Decode {
|
||||||
input,
|
input,
|
||||||
output,
|
output,
|
||||||
|
|
|
@ -3,19 +3,23 @@ use clap::{
|
||||||
Parser, Subcommand,
|
Parser, Subcommand,
|
||||||
};
|
};
|
||||||
use luca_pak::Pak;
|
use luca_pak::Pak;
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf, process::exit};
|
||||||
|
|
||||||
/// Utility to maniuplate PAK archive files from the LUCA System game engine by
|
/// Utility to maniuplate PAK archive files from the LUCA System game engine by
|
||||||
/// Prototype Ltd.
|
/// Prototype Ltd.
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "PAK Utility")]
|
#[command(name = "PAK Utility")]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(author, version, about, long_about = None, disable_version_flag = true)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[arg(value_name = "PAK FILE")]
|
/// Show program version information
|
||||||
input: PathBuf,
|
#[arg(short('V'), long)]
|
||||||
|
version: bool,
|
||||||
|
|
||||||
|
#[arg(value_name = "PAK FILE", required_unless_present("version"))]
|
||||||
|
input: Option<PathBuf>,
|
||||||
|
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Commands,
|
command: Option<Commands>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
|
@ -59,12 +63,30 @@ enum Commands {
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
let mut pak = match Pak::open(&cli.input) {
|
if cli.version {
|
||||||
|
println!(
|
||||||
|
"{}, {} v{}-{}",
|
||||||
|
env!("CARGO_BIN_NAME"),
|
||||||
|
env!("CARGO_PKG_NAME"),
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
&env!("VERGEN_GIT_SHA")[0..=6]
|
||||||
|
);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pak = match Pak::open(&cli.input.unwrap()) {
|
||||||
Ok(pak) => pak,
|
Ok(pak) => pak,
|
||||||
Err(err) => fmt_error(&format!("Could not open PAK file: {}", err)).exit(),
|
Err(err) => fmt_error(&format!("Could not open PAK file: {}", err)).exit(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match cli.command {
|
let command = match cli.command {
|
||||||
|
Some(c) => c,
|
||||||
|
None => {
|
||||||
|
exit(0);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
match command {
|
||||||
Commands::Extract { output } => {
|
Commands::Extract { output } => {
|
||||||
if output.exists() && !output.is_dir() {
|
if output.exists() && !output.is_dir() {
|
||||||
fmt_error("The output given was not a directory").exit()
|
fmt_error("The output given was not a directory").exit()
|
||||||
|
@ -74,7 +96,11 @@ fn main() {
|
||||||
|
|
||||||
for entry in pak.entries() {
|
for entry in pak.entries() {
|
||||||
let mut outpath = output.clone();
|
let mut outpath = output.clone();
|
||||||
outpath.push(entry.display_name());
|
if let Some(n) = entry.name() {
|
||||||
|
outpath.push(n);
|
||||||
|
} else {
|
||||||
|
outpath.push(entry.index().to_string())
|
||||||
|
}
|
||||||
entry.save(&outpath).unwrap();
|
entry.save(&outpath).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue