Skip to content

Commit

Permalink
Add LZO and LZ4 de/compression
Browse files Browse the repository at this point in the history
Right now just for the un/lz CLI subcommands but in the future for
Ubisoft and Asobo BigFiles.
  • Loading branch information
widberg committed Oct 13, 2023
1 parent 42e1fd0 commit be06893
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 13 deletions.
31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 14 additions & 3 deletions bff-cli/src/lz.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::{self, Cursor, Read, Write};

use bff::lz::compress_data_with_header_writer;
use bff::lz::{compress_data_with_header_writer, lz4_compress, lzo_compress};
use bff::Endian;
use clap::ValueEnum;

Expand All @@ -12,7 +12,14 @@ pub enum LzEndian {
Little,
}

pub fn lz(endian: &LzEndian) -> BffCliResult<()> {
#[derive(ValueEnum, Clone)]
pub enum LzAlgorithm {
Lzrs,
Lzo,
Lz4,
}

pub fn lz(endian: &LzEndian, algorithm: &LzAlgorithm) -> BffCliResult<()> {
let endian = match endian {
LzEndian::Big => Endian::Big,
LzEndian::Little => Endian::Little,
Expand All @@ -25,7 +32,11 @@ pub fn lz(endian: &LzEndian) -> BffCliResult<()> {
let mut compressed: Vec<u8> = Vec::new();
let mut writer = Cursor::new(&mut compressed);

compress_data_with_header_writer(&buf, &mut writer, endian)?;
match algorithm {
LzAlgorithm::Lzrs => compress_data_with_header_writer(&buf, &mut writer, endian)?,
LzAlgorithm::Lzo => lzo_compress(&buf, &mut writer, endian)?,
LzAlgorithm::Lz4 => lz4_compress(&buf, &mut writer, endian)?,
};

let stdout = io::stdout();
stdout.lock().write_all(writer.into_inner())?;
Expand Down
20 changes: 14 additions & 6 deletions bff-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use error::BffCliResult;
use lz::LzEndian;
use reverse_crc32::DEFAULT_CHARACTER_SET;

use crate::lz::LzAlgorithm;

mod crc32;
mod crc64;
mod error;
Expand Down Expand Up @@ -95,13 +97,19 @@ enum Commands {
},
Unlz {
#[clap(value_enum)]
#[arg(short, long, default_value_t = LzEndian::Little)]
endian: lz::LzEndian,
#[arg(short = 'e', long = "endian", default_value_t = LzEndian::Little)]
endian: LzEndian,
#[clap(value_enum)]
#[arg(short = 'a', long = "algorithm", default_value_t = LzAlgorithm::Lzrs)]
algorithm: LzAlgorithm,
},
Lz {
#[clap(value_enum)]
#[arg(short, long, default_value_t = LzEndian::Little)]
endian: lz::LzEndian,
#[arg(short = 'e', long = "endian", default_value_t = LzEndian::Little)]
endian: LzEndian,
#[clap(value_enum)]
#[arg(short = 'a', long = "algorithm", default_value_t = LzAlgorithm::Lzrs)]
algorithm: LzAlgorithm,
},
}

Expand Down Expand Up @@ -137,8 +145,8 @@ fn main() -> BffCliResult<()> {
mode,
format,
} => crc64::crc64(string, starting, algorithm, mode, format),
Commands::Unlz { endian } => unlz::unlz(endian),
Commands::Lz { endian } => lz::lz(endian),
Commands::Unlz { endian, algorithm } => unlz::unlz(endian, algorithm),
Commands::Lz { endian, algorithm } => lz::lz(endian, algorithm),
Commands::ReverseCrc32 {
string,
target,
Expand Down
12 changes: 8 additions & 4 deletions bff-cli/src/unlz.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::io::{self, Cursor, Read, Write};

use bff::lz::decompress_data_with_header_parser;
use bff::lz::{decompress_data_with_header_parser, lz4_decompress, lzo_decompress};
use bff::{BufReader, Endian};

use crate::error::BffCliResult;
use crate::lz::LzEndian;
use crate::lz::{LzAlgorithm, LzEndian};

pub fn unlz(endian: &LzEndian) -> BffCliResult<()> {
pub fn unlz(endian: &LzEndian, algorithm: &LzAlgorithm) -> BffCliResult<()> {
let endian = match endian {
LzEndian::Big => Endian::Big,
LzEndian::Little => Endian::Little,
Expand All @@ -17,7 +17,11 @@ pub fn unlz(endian: &LzEndian) -> BffCliResult<()> {
stdin.lock().read_to_end(&mut buf)?;
let mut reader = BufReader::new(Cursor::new(buf));

let decompressed = decompress_data_with_header_parser(&mut reader, endian)?;
let decompressed = match algorithm {
LzAlgorithm::Lzrs => decompress_data_with_header_parser(&mut reader, endian)?,
LzAlgorithm::Lzo => lzo_decompress(&mut reader, endian)?,
LzAlgorithm::Lz4 => lz4_decompress(&mut reader, endian)?,
};

let stdout = io::stdout();
Ok(stdout.lock().write_all(&decompressed)?)
Expand Down
2 changes: 2 additions & 0 deletions bff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ derive_more = "0.99.17"
impl-trait-for-tuples = "0.2.2"
indexmap = { version = "2.0.0", features = ["serde"] }
itertools = { version = "0.11.0", features = [] }
lz4 = "1.24.0"
minilzo-rs = "0.6.0"
num-traits = "0.2.15"
once_cell = { version = "1.18.0", features = [] }
rayon = { version = "1.8.0", features = [] }
Expand Down
1 change: 1 addition & 0 deletions bff/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ pub enum Error {
UnimplementedClass(UnimplementedClassError),
UnimplementedVersionPlatform(UnimplementedVersionPlatformError),
Utf8(std::string::FromUtf8Error),
MiniLzo(minilzo_rs::Error),
}
30 changes: 30 additions & 0 deletions bff/src/lz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::io::{Read, Seek, SeekFrom, Write};
use std::ptr::null_mut;

use binrw::{BinReaderExt, BinResult, BinWriterExt};
use lz4::{Decoder, EncoderBuilder};
use minilzo_rs::LZO;

use crate::{BffResult, Endian};

Expand Down Expand Up @@ -397,3 +399,31 @@ pub fn compress_data_writer(data: &[u8]) -> BinResult<()> {

Ok(())
}

pub fn lzo_compress<W: Write>(data: &[u8], writer: &mut W, _endian: Endian) -> BffResult<()> {
let mut lzo = LZO::init()?;
let compressed = lzo.compress(data)?;
writer.write_all(&compressed)?;
Ok(())
}

pub fn lzo_decompress<R: Read>(reader: &mut R, _endian: Endian) -> BffResult<Vec<u8>> {
let lzo = LZO::init()?;
let mut compressed: Vec<u8> = Vec::new();
reader.read_to_end(&mut compressed)?;
let decompressed = lzo.decompress_safe(&compressed, 0x1000000)?;
Ok(decompressed)
}

pub fn lz4_compress<W: Write>(data: &[u8], writer: &mut W, _endian: Endian) -> BffResult<()> {
let mut encoder = EncoderBuilder::new().build(writer)?;
encoder.write_all(data)?;
Ok(())
}

pub fn lz4_decompress<R: Read>(reader: &mut R, _endian: Endian) -> BffResult<Vec<u8>> {
let mut decoder = Decoder::new(reader)?;
let mut decompressed: Vec<u8> = Vec::new();
decoder.read_to_end(&mut decompressed)?;
Ok(decompressed)
}

0 comments on commit be06893

Please sign in to comment.