2
Fork 0

Compare commits

..

2 commits

Author SHA1 Message Date
e53b2faa0f
feat: Re-implement in Rust 2022-11-09 09:24:49 +01:00
04979ce11d
feat: Implement compress operation 2022-11-09 09:13:06 +01:00
15 changed files with 1333 additions and 727 deletions

9
.gitignore vendored
View file

@ -1,5 +1,4 @@
/.vs
/x64
/test
/oo2core_8_win64.dll
/oo2net_9_win64.dll
/target
/data
oo2core_8_win64.dll
oo2net_9_win64.dll

546
Cargo.lock generated Normal file
View file

@ -0,0 +1,546 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "backtrace"
version = "0.3.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "426eed9136e68a14d9de937db20cfd79fcc25c09709872e8005897c618a8365e"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"once_cell",
"strsim",
"termcolor",
"unicase",
"unicode-width",
]
[[package]]
name = "clap_derive"
version = "4.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685fbc59da060ed2cd3d79c86970ee95386b5e5fc69d9cad881912dca0c18807"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "color-eyre"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204"
dependencies = [
"backtrace",
"color-spantrace",
"eyre",
"indenter",
"once_cell",
"owo-colors",
"tracing-error",
]
[[package]]
name = "color-spantrace"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce"
dependencies = [
"once_cell",
"owo-colors",
"tracing-core",
"tracing-error",
]
[[package]]
name = "eyre"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
dependencies = [
"indenter",
"once_cell",
]
[[package]]
name = "gimli"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "miniz_oxide"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
dependencies = [
"adler",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "object"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "oodle-cli"
version = "0.1.0"
dependencies = [
"byteorder",
"clap",
"color-eyre",
"libloading",
"tracing",
"tracing-error",
"tracing-subscriber",
]
[[package]]
name = "os_str_bytes"
version = "6.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owo-colors"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
dependencies = [
"lazy_static",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thread_local"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
dependencies = [
"once_cell",
]
[[package]]
name = "tracing"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-error"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
dependencies = [
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tracing-log"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
"lazy_static",
"log",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

23
Cargo.toml Normal file
View file

@ -0,0 +1,23 @@
[package]
name = "oodle-cli"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
byteorder = "1.4.3"
clap = { version = "4.0.20", features = ["cargo", "color", "unicode", "std", "derive"] }
color-eyre = "0.6.2"
libloading = "0.7.4"
tracing = "0.1.37"
tracing-error = "0.2.0"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
[profile.release]
strip = "debuginfo"
lto = true
#debug-assertions = true
#overflow-checks = true
#opt-level = 0

View file

@ -1,230 +0,0 @@
// oodle-cli.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <locale>
#include <codecvt>
#include <filesystem>
#include <stdlib.h>
#include <windows.h>
#include <libloaderapi.h>
#include "oodle2.h"
const LPCWSTR LIB_NAME = L"oo2core_8_win64";
// Printing a `LPCWSTR` is a pain, so it's much easier to just have this second variable.
// It's not like this is going to change often.
const char* LIB_FILE = "oo2core_8_win64.dll";
typedef decltype(OodleLZ_Decompress)* decompress_func;
typedef decltype(OodleCore_Plugins_SetPrintf)* setprintf_func;
void usage() {
std::cerr <<
"Usage: oodle-cli [OPTIONS] [--] <in_file> <out_file> <uncompressed_size>\n"
"Decompress a <in_file> to <out_file> using the Oodle algorithm.\n"
"The size of the uncompressed data must be known.\n"
"\n"
"Options:\n"
" -v Increase Oodle's verbosity. May be specified up to three times.\n"
" -c Only check if the library can be found and used.\n"
" --fuzz-safe Use fuzz safe decompression.\n"
" --check-crc Check CRC during decompression.\n"
"\n"
"The following environmental variables are recognized:\n"
" DLL_SEARCH_PATH: A color (':') separated list of directories to search for the Oodle library. May be relative to the current working directory.\n";
}
void printf_callback(int verboseLevel, const char* file, int line, const char* fmt, ...) {
std::cout << "[OODLE] ";
// For some reason, this doesn't actually map to the config value.
switch (verboseLevel) {
case 0:
std::cout << "EXTRAORDINARILY IMPORTANT: ";
break;
case 1:
std::cout << "EXTERMELY IMPORTANT: ";
break;
case 2:
std::cout << "VERY IMPORTANT: ";
break;
}
va_list args;
va_start(args, fmt);
vfprintf(stdout, fmt, args);
}
int main(int argc, char* argv[])
{
int verbosity = 0;
bool check_lib = FALSE;
OodleLZ_FuzzSafe fuzz_safe = OodleLZ_FuzzSafe_No;
OodleLZ_CheckCRC check_crc = OodleLZ_CheckCRC_No;
int i = 1;
for (; i < argc; i++) {
char* arg = argv[i];
if (strcmp(arg, "--") == 0 || arg[0] != '-') {
break;
}
if (strcmp(arg, "--help") == 0) {
usage();
return 0;
}
else if (strcmp(arg, "-c") == 0) {
check_lib = TRUE;
}
else if (strcmp(arg, "-v") == 0) {
verbosity++;
}
else if (strcmp(arg, "--fuzz-safe") == 0) {
fuzz_safe = OodleLZ_FuzzSafe_Yes;
}
else if (strcmp(arg, "--check-crc") == 0) {
check_crc = OodleLZ_CheckCRC_Yes;
}
else {
std::cerr << "ERROR: Unknown option '" << arg << "'!\n\n";
usage();
return 1;
}
}
char* var;
size_t len;
DWORD load_flags = 0;
if (_dupenv_s(&var, &len, "DLL_SEARCH_PATH") == 0) {
if (var) {
std::string search_path(var, len);
std::istringstream ss(search_path);
std::string token;
while (std::getline(ss, token, ':')) {
auto path = std::filesystem::path(token);
if (!path.is_absolute()) {
path = std::filesystem::absolute(path);
}
if (!path.is_absolute() || !AddDllDirectory(path.c_str())) {
std::cerr << "WARN: Failed to add DLL search path: '" << token << "'!\n";
}
else {
std::cout << "INFO: Added DLL search path: '" << path << "'.\n";
}
}
load_flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
free(var);
}
}
else {
std::cerr << "ERROR: Failed to read environment variable 'DLL_SEARCH_PATH'. Skipping.\n";
}
HINSTANCE hDLL = LoadLibraryEx(LIB_NAME, NULL, load_flags);
if (hDLL == NULL) {
std::cerr << "ERROR: Couldn't find library file '" << LIB_FILE << "'!\n";
return 1;
}
auto decompress = reinterpret_cast<decompress_func>(GetProcAddress((HMODULE)hDLL, "OodleLZ_Decompress"));
if (decompress == NULL) {
std::cerr << "ERROR: The library is incompatible!\n";
return 1;
}
if (check_lib) {
std::cout << "INFO: '" << LIB_FILE << "' found and loaded.\n";
return 0;
}
if (argc - i < 3) {
std::cerr << "ERROR: Arguments missing!\n\n";
usage();
return 1;
}
std::string in_name = argv[i];
std::string out_name = argv[i + 1];
size_t raw_buffer_size = std::stoi(argv[i + 2]);
std::cout << "INFO: Attempting to decompress from '" << in_name << "' to '" << out_name << "' (" << raw_buffer_size << " bytes).\n";
if (verbosity > 0) {
auto fn = reinterpret_cast<setprintf_func>(GetProcAddress((HMODULE)hDLL, "OodleCore_Plugins_SetPrintf"));
if (fn == NULL) {
std::cerr << "ERROR: The library is incompatible!\n";
return 1;
}
reinterpret_cast<void*>(fn(printf_callback));
}
std::ifstream in_file(in_name, std::ios::binary | std::ios::ate);
if (!in_file) {
std::cerr << "ERROR: Failed to open compressed file!\n";
return 1;
}
std::streamsize compressed_buffer_size = in_file.tellg();
in_file.seekg(0, std::ios::beg);
std::vector<char> compressed_buffer(compressed_buffer_size);
in_file.read(compressed_buffer.data(), compressed_buffer_size);
if (in_file.fail()) {
std::cerr << "ERROR: Failed to read compressed file!\n";
return 1;
}
std::vector<char> raw_buffer(raw_buffer_size);
intptr_t res = decompress(
compressed_buffer.data(),
compressed_buffer.size(),
raw_buffer.data(),
raw_buffer_size,
fuzz_safe,
check_crc,
(OodleLZ_Verbosity)verbosity,
nullptr,
0,
nullptr,
nullptr,
nullptr,
0,
OodleLZ_Decode_Unthreaded
);
if (res != raw_buffer_size) {
std::cerr << "ERROR: Failed to decompress!\n";
return 1;
}
std::ofstream out_file(out_name, std::ios::binary);
if (!out_file) {
std::cerr << "ERROR: Failed to open output file!\n";
return 1;
}
out_file.write(raw_buffer.data(), res);
if (out_file.fail()) {
std::cerr << "ERROR: Failed to write output file!\n";
return 1;
}
std::cout << "INFO: Done!\n";
}

View file

@ -1,31 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32929.385
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oodle-cli", "oodle-cli.vcxproj", "{59D962DA-674C-48D9-ADB5-DE09A89E449A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{59D962DA-674C-48D9-ADB5-DE09A89E449A}.Debug|x64.ActiveCfg = Debug|x64
{59D962DA-674C-48D9-ADB5-DE09A89E449A}.Debug|x64.Build.0 = Debug|x64
{59D962DA-674C-48D9-ADB5-DE09A89E449A}.Debug|x86.ActiveCfg = Debug|Win32
{59D962DA-674C-48D9-ADB5-DE09A89E449A}.Debug|x86.Build.0 = Debug|Win32
{59D962DA-674C-48D9-ADB5-DE09A89E449A}.Release|x64.ActiveCfg = Release|x64
{59D962DA-674C-48D9-ADB5-DE09A89E449A}.Release|x64.Build.0 = Release|x64
{59D962DA-674C-48D9-ADB5-DE09A89E449A}.Release|x86.ActiveCfg = Release|Win32
{59D962DA-674C-48D9-ADB5-DE09A89E449A}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {21081A0D-BD2A-41A1-AE1D-90EBE2E6E87F}
EndGlobalSection
EndGlobal

View file

@ -1,140 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{59d962da-674c-48d9-adb5-de09a89e449a}</ProjectGuid>
<RootNamespace>oodlecli</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="oodle-cli.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="oodle2.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="oodle-cli.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="oodle2.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments> -v -v -v test\compressed.data 100</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

287
oodle2.h
View file

@ -1,287 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
// header version :
// the DLL is incompatible when MAJOR is bumped
// MINOR is for internal revs and bug fixes that don't affect API compatibility
// TODO: Check if the DLL gives a minor version
#define OODLE2_VERSION_MAJOR 8
#define OODLE2_VERSION_MINOR 14
// OodleVersion string is 1 . MAJOR . MINOR
#define OodleVersion "2.8.14"
// Default verbosity selection of 0 will not even log when it sees corruption
// Verbosity of LZ functions
typedef enum OodleLZ_Verbosity {
OodleLZ_Verbosity_None = 0,
OodleLZ_Verbosity_Minimal = 1,
OodleLZ_Verbosity_Some = 2,
OodleLZ_Verbosity_Lots = 3,
OodleLZ_Verbosity_Force32 = 0x40000000
} OodleLZ_Verbosity;
typedef enum OodleLZ_Compressor {
OodleLZ_Compressor_Invalid = -1,
OodleLZ_Compressor_None = 3, // None = memcpy, pass through uncompressed bytes
// NEW COMPRESSORS :
OodleLZ_Compressor_Kraken = 8, // Fast decompression and high compression ratios, amazing!
OodleLZ_Compressor_Leviathan = 13,// Leviathan = Kraken's big brother with higher compression, slightly slower decompression.
OodleLZ_Compressor_Mermaid = 9, // Mermaid is between Kraken & Selkie - crazy fast, still decent compression.
OodleLZ_Compressor_Selkie = 11, // Selkie is a super-fast relative of Mermaid. For maximum decode speed.
OodleLZ_Compressor_Hydra = 12, // Hydra, the many-headed beast = Leviathan, Kraken, Mermaid, or Selkie (see $OodleLZ_About_Hydra)
OodleLZ_Compressor_BitKnit = 10,
OodleLZ_Compressor_LZB16 = 4, // DEPRECATED but still supported
OodleLZ_Compressor_LZNA = 7,
OodleLZ_Compressor_LZH = 0,
OodleLZ_Compressor_LZHLW = 1,
OodleLZ_Compressor_LZNIB = 2,
OodleLZ_Compressor_LZBLW = 5,
OodleLZ_Compressor_LZA = 6,
OodleLZ_Compressor_Count = 14,
OodleLZ_Compressor_Force32 = 0x40000000
} OodleLZ_Compressor;
typedef enum OodleLZ_CheckCRC {
OodleLZ_CheckCRC_No = 0,
OodleLZ_CheckCRC_Yes = 1,
OodleLZ_CheckCRC_Force32 = 0x40000000
} OodleLZ_CheckCRC;
/* Selection of compression encoder complexity
Higher numerical value of CompressionLevel = slower compression, but smaller compressed data.
The compressed stream is always decodable with the same decompressors.
CompressionLevel controls the amount of work the encoder does to find the best compressed bit stream.
CompressionLevel does not primary affect decode speed, it trades off encode speed for compressed bit stream quality.
I recommend starting with OodleLZ_CompressionLevel_Normal, then try up or down if you want
faster encoding or smaller output files.
The Optimal levels are good for distribution when you compress rarely and decompress often;
they provide very high compression ratios but are slow to encode. Optimal2 is the recommended level
to start with of the optimal levels.
Optimal4 and 5 are not recommended for common use, they are very slow and provide the maximum compression ratio,
but the gain over Optimal3 is usually small.
The HyperFast levels have negative numeric CompressionLevel values.
They are faster than SuperFast for when you're encoder CPU time constrained or want
something closer to symmetric compression vs. decompression time.
The HyperFast levels are currently only available in Kraken, Mermaid & Selkie.
Higher levels of HyperFast are faster to encode, eg. HyperFast4 is the fastest.
The CompressionLevel does not affect decode speed much. Higher compression level does not mean
slower to decode. To trade off decode speed vs ratio, use _spaceSpeedTradeoffBytes_ in $OodleLZ_CompressOptions
*/
typedef enum OodleLZ_CompressionLevel {
OodleLZ_CompressionLevel_None = 0, // don't compress, just copy raw bytes
OodleLZ_CompressionLevel_SuperFast = 1, // super fast mode, lower compression ratio
OodleLZ_CompressionLevel_VeryFast = 2, // fastest LZ mode with still decent compression ratio
OodleLZ_CompressionLevel_Fast = 3, // fast - good for daily use
OodleLZ_CompressionLevel_Normal = 4, // standard medium speed LZ mode
OodleLZ_CompressionLevel_Optimal1 = 5, // optimal parse level 1 (faster optimal encoder)
OodleLZ_CompressionLevel_Optimal2 = 6, // optimal parse level 2 (recommended baseline optimal encoder)
OodleLZ_CompressionLevel_Optimal3 = 7, // optimal parse level 3 (slower optimal encoder)
OodleLZ_CompressionLevel_Optimal4 = 8, // optimal parse level 4 (very slow optimal encoder)
OodleLZ_CompressionLevel_Optimal5 = 9, // optimal parse level 5 (don't care about encode speed, maximum compression)
OodleLZ_CompressionLevel_HyperFast1 = -1, // faster than SuperFast, less compression
OodleLZ_CompressionLevel_HyperFast2 = -2, // faster than HyperFast1, less compression
OodleLZ_CompressionLevel_HyperFast3 = -3, // faster than HyperFast2, less compression
OodleLZ_CompressionLevel_HyperFast4 = -4, // fastest, less compression
// aliases :
OodleLZ_CompressionLevel_HyperFast = OodleLZ_CompressionLevel_HyperFast1, // alias hyperfast base level
OodleLZ_CompressionLevel_Optimal = OodleLZ_CompressionLevel_Optimal2, // alias optimal standard level
OodleLZ_CompressionLevel_Max = OodleLZ_CompressionLevel_Optimal5, // maximum compression level
OodleLZ_CompressionLevel_Min = OodleLZ_CompressionLevel_HyperFast4, // fastest compression level
OodleLZ_CompressionLevel_Force32 = 0x40000000,
OodleLZ_CompressionLevel_Invalid = OodleLZ_CompressionLevel_Force32
} OodleLZ_CompressionLevel;
typedef enum OodleLZ_Decode_ThreadPhase {
OodleLZ_Decode_ThreadPhase1 = 1,
OodleLZ_Decode_ThreadPhase2 = 2,
OodleLZ_Decode_ThreadPhaseAll = 3,
OodleLZ_Decode_Unthreaded = OodleLZ_Decode_ThreadPhaseAll
} OodleLZ_Decode_ThreadPhase;
typedef enum OodleLZ_FuzzSafe {
OodleLZ_FuzzSafe_No = 0,
OodleLZ_FuzzSafe_Yes = 1
} OodleLZ_FuzzSafe;
/* Compress some data from memory to memory, synchronously, with OodleLZ
$:compressor which OodleLZ variant to use in compression
$:rawBuf raw data to compress
$:rawLen number of bytes in rawBuf to compress
$:compBuf pointer to write compressed data to ; should be at least $OodleLZ_GetCompressedBufferSizeNeeded
$:level OodleLZ_CompressionLevel controls how much CPU effort is put into maximizing compression
$:pOptions (optional) options; if NULL, $OodleLZ_CompressOptions_GetDefault is used
$:dictionaryBase (optional) if not NULL, provides preceding data to prime the dictionary; must be contiguous with rawBuf, the data between the pointers _dictionaryBase_ and _rawBuf_ is used as the preconditioning data. The exact same precondition must be passed to encoder and decoder.
$:lrm (optional) long range matcher
$:scratchMem (optional) pointer to scratch memory
$:scratchSize (optional) size of scratch memory (see $OodleLZ_GetCompressScratchMemBound)
$:return size of compressed data written, or $OODLELZ_FAILED for failure
Performs synchronous memory to memory LZ compression.
In tools, you should generally use $OodleXLZ_Compress_AsyncAndWait instead to get parallelism. (in the Oodle2 Ext lib)
You can compress a large buffer in several calls by setting _dictionaryBase_ to the start
of the buffer, and then making _rawBuf_ and _rawLen_ select portions of that buffer. As long
as _rawLen_ is a multiple of $OODLELZ_BLOCK_LEN , the compressed chunks can simply be
concatenated together.
If _scratchMem_ is provided, it will be used for the compressor's scratch memory needs before OodleMalloc is
called. If the scratch is big enough, no malloc will be done. If the scratch is not big enough, the compress
will not fail, instead OodleMalloc will be used. OodleMalloc should not return null. There is currently no way
to make compress fail cleanly due to using too much memory, it must either succeed or abort the process.
If _scratchSize_ is at least $OodleLZ_GetCompressScratchMemBound , additional allocations will not be needed.
See $OodleLZ_About for tips on setting the compression options.
If _dictionaryBase_ is provided, the backup distance from _rawBuf_ must be a multiple of $OODLELZ_BLOCK_LEN
If $(OodleLZ_CompressOptions:seekChunkReset) is enabled, and _dictionaryBase_ is not NULL or _rawBuf_ , then the
seek chunk boundaries are relative to _dictionaryBase_, not to _rawBuf_.
*/
extern "C" intptr_t __stdcall OodleLZ_Compress(
OodleLZ_Compressor compressor,
const void* raw_buffer,
size_t raw_len,
void* compressed_buffer,
OodleLZ_CompressionLevel level,
void* options, // Default: null
size_t dictionary_base, // Default: null
const void* lrm, // Default: null
void* scratch_memory, // Default: null
size_t scratch_size // Default: null
);
// Decompress returns raw (decompressed) len received
// Decompress returns 0 (OODLELZ_FAILED) if it detects corruption
/* Decompress a some data from memory to memory, synchronously.
$:compBuf pointer to compressed data
$:compBufSize number of compressed bytes available (must be greater or equal to the number consumed)
$:rawBuf pointer to output uncompressed data into
$:rawLen number of uncompressed bytes to output
$:fuzzSafe (optional) should the decode fail if it contains non-fuzz safe codecs?
$:checkCRC (optional) if data could be corrupted and you want to know about it, pass OodleLZ_CheckCRC_Yes
$:verbosity (optional) if not OodleLZ_Verbosity_None, logs some info
$:decBufBase (optional) if not NULL, provides preceding data to prime the dictionary; must be contiguous with rawBuf, the data between the pointers _dictionaryBase_ and _rawBuf_ is used as the preconditioning data. The exact same precondition must be passed to encoder and decoder. The decBufBase must be a reset point.
$:decBufSize (optional) size of decode buffer starting at decBufBase, if 0, _rawLen_ is assumed
$:fpCallback (optional) OodleDecompressCallback to call incrementally as decode proceeds
$:callbackUserData (optional) passed as userData to fpCallback
$:decoderMemory (optional) pre-allocated memory for the Decoder, of size _decoderMemorySize_
$:decoderMemorySize (optional) size of the buffer at _decoderMemory_; must be at least $OodleLZDecoder_MemorySizeNeeded bytes to be used
$:threadPhase (optional) for threaded decode; see $OodleLZ_About_ThreadPhasedDecode (default OodleLZ_Decode_Unthreaded)
$:return the number of decompressed bytes output, $OODLELZ_FAILED (0) if none can be decompressed
Decodes data encoded with any $OodleLZ_Compressor.
Note : _rawLen_ must be the actual number of bytes to output, the same as the number that were encoded with the corresponding
OodleLZ_Compress size. You must store this somewhere in your own header and pass it in to this call. _compBufSize_ does NOT
need to be the exact number of compressed bytes, is the number of bytes available in the buffer, it must be greater or equal to
the actual compressed length.
Note that the new compressors (Kraken,Mermaid,Selkie,BitKnit) are all fuzz safe and you can use OodleLZ_FuzzSafe_Yes
with them and no padding of the decode target buffer.
If checkCRC is OodleLZ_CheckCRC_Yes, then corrupt data will be detected and the decode aborted.
If checkCRC is OodleLZ_CheckCRC_No, then corruption might result in invalid data, but no detection of any error (garbage in, garbage out).
If corruption is possible, _fuzzSafe_ is No and _checkCRC_ is OodleLZ_CheckCRC_No, $OodleLZ_GetDecodeBufferSize must be used to allocate
_rawBuf_ large enough to prevent overrun.
$OodleLZ_GetDecodeBufferSize should always be used to ensure _rawBuf_ is large enough, even when corruption is not
possible (when fuzzSafe is No).
_compBuf_ and _rawBuf_ are allowed to overlap for "in place" decoding, but then _rawBuf_ must be allocated to
the size given by $OodleLZ_GetInPlaceDecodeBufferSize , and the compressed data must be at the end of that buffer.
An easy way to take the next step to parallel decoding is with $OodleXLZ_Decompress_MakeSeekTable_Wide_Async (in the Oodle2 Ext lib)
NOTE : the return value is the *total* number of decompressed bytes output so far. If rawBuf is > decBufBase, that means
the initial inset of (rawBuf - decBufBase) is included! (eg. you won't just get _rawLen_)
If _decBufBase_ is provided, the backup distance from _rawBuf_ must be a multiple of $OODLELZ_BLOCK_LEN
About fuzz safety:
OodleLZ_Decompress is guaranteed not to crash even if the data is corrupted when _fuzzSafe_ is set to OodleLZ_FuzzSafe_Yes.
When _fuzzSafe_ is Yes, the target buffer (_rawBuf_ and _rawLen_) will never be overrun. Note that corrupted data might not
be detected (the return value might indicate success).
Fuzz Safe decodes will not crash on corrupt data. They may or may not return failure, and produce garbage output.
Fuzz safe decodes will not read out of bounds. They won't put data on the stack or previously in memory
into the output buffer.
Fuzz safe decodes will not output more than the uncompressed size. (eg. the output buffer does not need to
be padded like OodleLZ_GetDecodeBufferSize)
If you ask for a fuzz safe decode and the compressor doesn't satisfy OodleLZ_Compressor_CanDecodeFuzzSafe
then it will return failure.
The _fuzzSafe_ argument should always be OodleLZ_FuzzSafe_Yes as of Oodle 2.9.0 ; older compressors did not
support fuzz safety but they now all do.
Use of OodleLZ_FuzzSafe_No is deprecated.
*/
extern "C" intptr_t __stdcall OodleLZ_Decompress(
const void* compressed_buffer,
size_t compressed_length,
void* raw_buffer,
size_t raw_length,
OodleLZ_FuzzSafe fuzz_safe, // Default: OodleLZ_FuzzSafe_Yes
OodleLZ_CheckCRC check_crc, // Default: OodleLZ_CheckCRC_No
OodleLZ_Verbosity verbosity, // Default: OodleLZ_Verbosity_None
void* decBufBase, // Default: null
size_t decBufSize, // Default: 0
void* callback, // Default: null
void* callback_user_data, // Default: null
void* decoder_memory, // Default: null
size_t decoder_memory_size, // Default: 0
OodleLZ_Decode_ThreadPhase thread_phase // Default: OodleLZ_Decode_Unthreaded
);
/* Function pointer to Oodle Core printf
$:verboseLevel verbosity of the message; 0-2 ; lower = more important
$:file C file that sent the message
$:line C line that sent the message
$:fmt vararg printf format string
The logging function installed here must parse varargs like printf.
_verboseLevel_ may be used to omit verbose messages.
*/
extern "C" typedef void(__stdcall t_fp_OodleCore_Plugin_Printf)(int verboseLevel, const char* file, int line, const char* fmt, ...);
/* Install the callback used by Oodle Core for logging
$:fp_rrRawPrintf function pointer to your log function; may be NULL to disable all logging
$:return returns the previous function pointer
Use this function to install your own printf for Oodle Core.
The default implementation in debug builds, if you install nothing, uses the C stdio printf for logging.
On Microsoft platforms, it uses OutputDebugString and not stdio.
To disable all logging, call OodleCore_Plugins_SetPrintf(NULL)
WARNING : this function is NOT thread safe! It should be done only once and done in a place where the caller can guarantee thread safety.
In the debug build of Oodle, you can install OodleCore_Plugin_Printf_Verbose to get more verbose logging
*/
t_fp_OodleCore_Plugin_Printf* __stdcall OodleCore_Plugins_SetPrintf(t_fp_OodleCore_Plugin_Printf* fp_rrRawPrintf);

2
rust-toolchain.toml Normal file
View file

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

20
rustfmt.toml Normal file
View file

@ -0,0 +1,20 @@
# Copyright (C) 2022 Lucas Schwiderski
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
unstable_features = true
hard_tabs = false
max_width = 100
edition = "2021"
use_field_init_shorthand = true

127
src/binary.rs Normal file
View file

@ -0,0 +1,127 @@
#![allow(dead_code)]
use std::io::{Read, Seek, SeekFrom, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use color_eyre::eyre::WrapErr;
use color_eyre::{Help, Result, SectionExt};
fn read_u8_impl<R>(r: &mut R) -> Result<u8>
where
R: Read,
{
r.read_u8().wrap_err("failed to read u8")
}
fn read_u32_le_impl<R>(r: &mut R) -> Result<u32>
where
R: Read,
{
r.read_u32::<LittleEndian>().wrap_err("failed to read u32")
}
fn read_u64_le_impl<R>(r: &mut R) -> Result<u64>
where
R: Read,
{
r.read_u64::<LittleEndian>().wrap_err("failed to read u64")
}
macro_rules! make_read {
($func:ident, $op:ident, $type:ty) => {
pub(crate) fn $func<R>(r: &mut R) -> Result<$type>
where
R: Read + Seek,
{
let res = $op(r);
if res.is_err() {
let pos = r.stream_position();
if pos.is_ok() {
res.with_section(|| {
format!("{pos:#X} ({pos})", pos = pos.unwrap()).header("Position: ")
})
} else {
res
}
} else {
res
}
}
};
}
fn write_u32_le_impl<W>(w: &mut W, val: u32) -> Result<()>
where
W: Write,
{
w.write_u32::<LittleEndian>(val)
.wrap_err("failed to write u32")
}
macro_rules! make_write {
($func:ident, $op:ident, $type:ty) => {
pub(crate) fn $func<W>(w: &mut W, val: $type) -> Result<()>
where
W: Write + Seek,
{
let res = $op(w, val);
if res.is_err() {
let pos = w.stream_position();
if pos.is_ok() {
res.with_section(|| {
format!("{pos:#X} ({pos})", pos = pos.unwrap()).header("Position: ")
})
} else {
res
}
} else {
res
}
}
};
}
make_read!(read_u8, read_u8_impl, u8);
make_read!(read_u32, read_u32_le_impl, u32);
make_read!(read_u64, read_u64_le_impl, u64);
make_write!(write_u32, write_u32_le_impl, u32);
pub(crate) fn read_up_to<R>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
where
R: Read + Seek,
{
let pos = r.stream_position()?;
let err = {
match r.read_exact(buf) {
Ok(_) => return Ok(buf.len()),
Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => {
r.seek(SeekFrom::Start(pos))?;
match r.read_to_end(buf) {
Ok(read) => return Ok(read),
Err(err) => err,
}
}
Err(err) => err,
}
};
Err(err).with_section(|| format!("{pos:#X} ({pos})", pos = pos).header("Position: "))
}
pub fn write_padding<W>(w: &mut W, offset: u64) -> Result<usize>
where
W: Write + Seek,
{
let pos = w.stream_position()? + offset;
let size = 16 - (pos % 16) as usize;
if size > 0 && size < 16 {
w.seek(SeekFrom::Current(size as i64))?;
Ok(size)
} else {
Ok(0)
}
}

317
src/main.rs Normal file
View file

@ -0,0 +1,317 @@
#![feature(c_size_t)]
use std::fs::File;
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use std::path::PathBuf;
use clap::{command, value_parser, Arg, ArgAction, ArgMatches, Command};
use color_eyre::eyre::{self, Context};
use color_eyre::Result;
use tracing_error::ErrorLayer;
use tracing_subscriber::prelude::*;
use tracing_subscriber::EnvFilter;
mod binary;
mod oodle;
mod types;
use binary::*;
use oodle::{Oodle, CHUNK_SIZE};
use types::*;
const LIB_NAME: &str = "oo2core_8_win64";
#[tracing::instrument]
fn main() -> Result<()> {
color_eyre::install()?;
let matches = command!()
.about("Perform Oodle 2 compression and decompression for Darktide Bitsquid bundles.")
.subcommand_required(true)
.arg(
Arg::new("verbosity")
.help("Set verbosity for the Oodle library.")
.global(true)
.short('v')
.long("verbose")
.default_value("none")
.value_parser(value_parser!(OodleLZ_Verbosity)),
)
.arg(
Arg::new("library")
.help(
"Library to load. This may either be:\n\
- A library name that will be searched for in the system's default paths.\n\
- A file path relative to the current working directory.\n\
- An absolute file path.",
)
.long("library")
.default_value(LIB_NAME),
)
.subcommand(
Command::new("compress")
.about("Compress an arbitrary binary stream in chunks.")
.arg(
Arg::new("offset")
.help(
"The offset of the compressed data stream within the full bundle file.\
\nThis needs to be known during decompression to correctly calculate \
the padding within each chunk.",
)
.long("offset")
.required(true)
.value_parser(value_parser!(u64)),
)
.arg(
Arg::new("in_file")
.help("The input file")
.required(true)
.value_parser(value_parser!(PathBuf)),
)
.arg(
Arg::new("out_file")
.help("The output file")
.required(true)
.value_parser(value_parser!(PathBuf)),
),
)
.subcommand(
Command::new("decompress")
.about("Decompress a stream of chunks.")
.arg(
Arg::new("offset")
.help(
"The offset of the compressed data stream within the full bundle file.\
\nThis needs to be known during decompression to correctly calculate \
the padding within each chunk.",
)
.long("offset")
.required(true)
.value_parser(value_parser!(u64)),
)
.arg(
Arg::new("fuzz_safe")
.long("fuzz-safe")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("check_crc")
.long("check-crc")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("in_file")
.help("The input file")
.required(true)
.value_parser(value_parser!(PathBuf)),
)
.arg(
Arg::new("out_file")
.help("The output file")
.required(true)
.value_parser(value_parser!(PathBuf)),
),
)
.get_matches();
{
let fmt_layer = tracing_subscriber::fmt::layer().pretty();
let filter_layer =
EnvFilter::try_from_default_env().or_else(|_| EnvFilter::try_new("info"))?;
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.with(ErrorLayer::new(
tracing_subscriber::fmt::format::Pretty::default(),
))
.init();
}
let lib = {
let name = matches.get_one::<String>("library").unwrap();
let lib = Oodle::new(name).wrap_err_with(|| format!("Failed to load library {}", name))?;
tracing::info!("Using library {}", name);
lib
};
match matches.subcommand() {
Some(("compress", sub_matches)) => compress(lib, sub_matches),
Some(("decompress", sub_matches)) => decompress(lib, sub_matches),
_ => unreachable!(
"clap is configured to require a subcommand, and they're all handled above"
),
}
}
fn skip_padding<S>(stream: &mut S, offset: u64) -> Result<()>
where
S: Seek,
{
let pos = stream.stream_position()? + offset;
let padding_size = 16 - (pos % 16);
tracing::trace!(pos, padding_size);
if padding_size < 16 && padding_size > 0 {
stream.seek(SeekFrom::Current(padding_size as i64))?;
}
Ok(())
}
#[tracing::instrument(skip_all)]
fn decompress(lib: Oodle, matches: &ArgMatches) -> Result<()> {
let in_path = matches.get_one::<PathBuf>("in_file").unwrap();
let out_path = matches.get_one::<PathBuf>("out_file").unwrap();
tracing::debug!("Reading from '{}'", in_path.display());
tracing::debug!("Writing to '{}'", out_path.display());
let fuzz_safe = OodleLZ_FuzzSafe::from(matches.get_flag("fuzz_safe"));
let check_crc = OodleLZ_CheckCRC::from(matches.get_flag("check_crc"));
let verbosity = *matches
.get_one::<OodleLZ_Verbosity>("verbosity")
.unwrap_or(&OodleLZ_Verbosity::None);
tracing::trace!(?fuzz_safe, ?check_crc, ?verbosity);
let offset = *matches.get_one::<u64>("offset").unwrap();
tracing::debug!(offset);
let mut in_file = File::open(in_path)
.wrap_err_with(|| format!("failed to open input file: {}", in_path.display()))?;
let mut out_file = File::create(out_path)
.wrap_err_with(|| format!("failed to open output file: {}", out_path.display()))?;
let num_chunks = read_u32(&mut in_file)?;
skip_padding(&mut in_file, offset)?;
tracing::debug!(num_chunks);
for chunk_index in 0..num_chunks {
let _span = tracing::debug_span!("Decompressing chunk", chunk_index);
let chunk_size = read_u32(&mut in_file)? as usize;
tracing::trace!(chunk_size);
skip_padding(&mut in_file, offset)?;
let mut compressed_buffer = vec![0u8; CHUNK_SIZE];
read_up_to(&mut in_file, &mut compressed_buffer)?;
// TODO: Optimize to not reallocate?
let raw_buffer = lib.decompress(&compressed_buffer, fuzz_safe, check_crc, verbosity)?;
out_file.write_all(&raw_buffer)?;
}
Ok(())
}
#[tracing::instrument(skip_all)]
fn compress(lib: Oodle, matches: &ArgMatches) -> Result<()> {
let in_path = matches.get_one::<PathBuf>("in_file").unwrap();
let out_path = matches.get_one::<PathBuf>("out_file").unwrap();
tracing::info!("Reading from '{}'", in_path.display());
tracing::info!("Writing to '{}'", out_path.display());
let offset = *matches.get_one::<u64>("offset").unwrap();
tracing::debug!(offset);
let mut out_file = File::create(out_path)
.wrap_err_with(|| format!("failed to open output file: {}", out_path.display()))?;
let mut r = {
let mut in_file = File::open(in_path)
.wrap_err_with(|| format!("failed to open input file: {}", in_path.display()))?;
// TODO: Is it faster to check metadata for size and pre-allocate?
let mut buf = Vec::new();
in_file
.read_to_end(&mut buf)
.wrap_err("failed to read input file into memory")?;
Cursor::new(buf)
};
// I'm not sure how Fatshark does this efficiently.
// Within each chunk, there is a padding whos size depends on the position where the padding is
// written.
// And that position is affected by both the size of previous chunks and the total number of
// chunks, since list of chunk sizes is written before all chunks.
// Because of that, all chunks have to be compressed and buffered before any of them can be
// written to the output.
let mut chunks: Vec<Vec<u8>> = Vec::new();
let mut chunk_index = 0;
loop {
let _span = tracing::info_span!("decompress_chunk", chunk_index);
let mut raw_buffer = vec![0u8; CHUNK_SIZE];
let read = read_up_to(&mut r, &mut raw_buffer)?;
let is_eof = read < CHUNK_SIZE;
tracing::debug!(is_eof);
{
let remaining = CHUNK_SIZE - read;
if remaining >= 4 {
for val in raw_buffer.iter_mut().skip(remaining).take(4) {
*val = 0x66;
}
} else {
eyre::bail!(
"Not enough space left in buffer to add end marker. \
Don't know how to proceed."
);
}
}
let compressed = lib
.compress(raw_buffer)
.wrap_err_with(|| format!("failed to compress chunk {}", chunk_index))?;
chunks.push(compressed);
if is_eof {
break;
}
chunk_index += 1;
}
let out = &mut out_file;
write_u32(out, chunks.len() as u32)?;
{
let _span = tracing::trace_span!("write_chunk_sizes");
for (chunk_index, chunk) in chunks.iter().enumerate() {
tracing::trace!(chunk_index);
write_u32(out, chunk.len() as u32)?;
}
}
write_padding(out, offset)?;
let unpacked_size = chunks.iter().fold(0, |total, chunk| total + chunk.len());
write_u32(out, unpacked_size as u32)?;
write_u32(out, 0)?;
{
let _span = tracing::trace_span!("write_chunk_data");
for (chunk_index, chunk) in chunks.iter().enumerate() {
tracing::trace!(chunk_index);
write_u32(out, chunk.len() as u32)?;
write_padding(out, offset)?;
out.write_all(chunk)
.wrap_err("failed to write chunk data")?;
}
}
Ok(())
}

104
src/oodle.rs Normal file
View file

@ -0,0 +1,104 @@
use std::ffi::OsStr;
use std::ptr;
use color_eyre::eyre;
use color_eyre::Result;
use libloading::{Library, Symbol};
use crate::types::*;
// Hardcoded chunk size of Bitsquid's bundle compression
pub const CHUNK_SIZE: usize = 512 * 1024;
pub struct Oodle {
lib: Library,
}
impl Oodle {
pub fn new<P>(lib: P) -> Result<Self>
where
P: AsRef<OsStr>,
{
let lib = unsafe { Library::new(lib)? };
// TODO: Register librarie's printf
Ok(Self { lib })
}
#[tracing::instrument(name = "Oodle::decompress", skip(self, data))]
pub fn decompress<I>(
&self,
data: I,
fuzz_safe: OodleLZ_FuzzSafe,
check_crc: OodleLZ_CheckCRC,
verbosity: OodleLZ_Verbosity,
) -> Result<Vec<u8>>
where
I: AsRef<[u8]>,
{
let data = data.as_ref();
let mut out = vec![0; CHUNK_SIZE];
let ret = unsafe {
let decompress: Symbol<OodleLZ_Decompress> = self.lib.get(b"OodleLZ_Decompress")?;
decompress(
data.as_ptr() as *const _,
data.len(),
out.as_mut_ptr() as *mut _,
out.len(),
fuzz_safe,
check_crc,
verbosity,
ptr::null_mut(),
0,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
0,
OodleLZ_Decode_ThreadPhase::UNTHREADED,
)
};
if ret < CHUNK_SIZE as u64 {
eyre::bail!("Failed to decompress chunk.");
}
Ok(out)
}
#[tracing::instrument(name = "Oodle::compress", skip(self, data))]
pub fn compress<I>(&self, data: I) -> Result<Vec<u8>>
where
I: AsRef<[u8]>,
{
let raw = data.as_ref();
// TODO: Query oodle for buffer size
let mut out = vec![0u8; CHUNK_SIZE];
let compressor = OodleLZ_Compressor::Kraken;
let level = OodleLZ_CompressionLevel::Optimal2;
let ret = unsafe {
let compress: Symbol<OodleLZ_Compress> = self.lib.get(b"OodleLZ_Compress")?;
compress(
compressor,
raw.as_ptr() as *const _,
raw.len(),
out.as_mut_ptr() as *mut _,
level,
ptr::null_mut(),
0,
ptr::null_mut(),
ptr::null_mut(),
0,
)
};
if ret == 0 {
eyre::bail!("Failed to compress chunk.");
}
Ok(out)
}
}

190
src/types.rs Normal file
View file

@ -0,0 +1,190 @@
#![allow(dead_code)]
use core::ffi::{c_char, c_int, c_size_t, c_ulonglong, c_void};
use clap::ValueEnum;
// Type definitions taken from Unreal Engine's `oodle2.h`
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
pub enum OodleLZ_FuzzSafe {
No = 0,
Yes = 1,
}
impl From<bool> for OodleLZ_FuzzSafe {
fn from(value: bool) -> Self {
if value {
Self::Yes
} else {
Self::No
}
}
}
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug)]
pub enum OodleLZ_CheckCRC {
No = 0,
Yes = 1,
Force32 = 0x40000000,
}
impl From<bool> for OodleLZ_CheckCRC {
fn from(value: bool) -> Self {
if value {
Self::Yes
} else {
Self::No
}
}
}
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum OodleLZ_Verbosity {
None = 0,
Minimal = 1,
Some = 2,
Lots = 3,
#[clap(hide = true)]
Force32 = 0x40000000,
}
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum OodleLZ_Decode_ThreadPhase {
Phase1 = 1,
Phase2 = 2,
PhaseAll = 3,
}
impl OodleLZ_Decode_ThreadPhase {
pub const UNTHREADED: Self = OodleLZ_Decode_ThreadPhase::PhaseAll;
}
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum OodleLZ_Compressor {
#[clap(hide = true)]
Invalid = -1,
// None = memcpy, pass through uncompressed bytes
None = 3,
// NEW COMPRESSORS:
// Fast decompression and high compression ratios, amazing!
Kraken = 8,
// Leviathan = Kraken's big brother with higher compression, slightly slower decompression.
Leviathan = 13,
// Mermaid is between Kraken & Selkie - crazy fast, still decent compression.
Mermaid = 9,
// Selkie is a super-fast relative of Mermaid. For maximum decode speed.
Selkie = 11,
// Hydra, the many-headed beast = Leviathan, Kraken, Mermaid, or Selkie (see $OodleLZ_About_Hydra)
Hydra = 12,
BitKnit = 10,
// DEPRECATED but still supported
Lzb16 = 4,
Lzna = 7,
Lzh = 0,
Lzhlw = 1,
Lznib = 2,
Lzblw = 5,
Lza = 6,
Count = 14,
#[clap(hide = true)]
Force32 = 0x40000000,
}
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum OodleLZ_CompressionLevel {
// don't compress, just copy raw bytes
None = 0,
// super fast mode, lower compression ratio
SuperFast = 1,
// fastest LZ mode with still decent compression ratio
VeryFast = 2,
// fast - good for daily use
Fast = 3,
// standard medium speed LZ mode
Normal = 4,
// optimal parse level 1 (faster optimal encoder)
Optimal1 = 5,
// optimal parse level 2 (recommended baseline optimal encoder)
Optimal2 = 6,
// optimal parse level 3 (slower optimal encoder)
Optimal3 = 7,
// optimal parse level 4 (very slow optimal encoder)
Optimal4 = 8,
// optimal parse level 5 (don't care about encode speed, maximum compression)
Optimal5 = 9,
// faster than SuperFast, less compression
HyperFast1 = -1,
// faster than HyperFast1, less compression
HyperFast2 = -2,
// faster than HyperFast2, less compression
HyperFast3 = -3,
// fastest, less compression
HyperFast4 = -4,
#[clap(hide = true)]
Force32 = 0x40000000,
}
impl OodleLZ_CompressionLevel {
// alias hyperfast base level
pub const HYPERFAST: Self = OodleLZ_CompressionLevel::HyperFast1;
// alias optimal standard level
pub const OPTIMAL: Self = OodleLZ_CompressionLevel::Optimal2;
// maximum compression level
pub const MAX: Self = OodleLZ_CompressionLevel::Optimal5;
// fastest compression level
pub const MIN: Self = OodleLZ_CompressionLevel::HyperFast4;
pub const INVALID: Self = OodleLZ_CompressionLevel::Force32;
}
#[allow(non_camel_case_types)]
pub type t_fp_OodleCore_Plugin_Printf =
extern "C" fn(level: c_int, file: *mut c_char, line: c_int, fmt: *mut c_char) -> c_void;
#[allow(non_camel_case_types)]
pub type OodleLZ_Decompress = extern "C" fn(
compressed_buffer: *const c_void,
compressed_length: c_size_t,
raw_buffer: *mut c_void,
raw_length: c_size_t,
fuzz_safe: OodleLZ_FuzzSafe,
check_crc: OodleLZ_CheckCRC,
verbosity: OodleLZ_Verbosity,
decBufBase: *mut c_void,
decBufSize: c_size_t,
callback: *const c_void,
callback_user_data: *const c_void,
decoder_memory: *mut c_void,
decoder_memory_size: c_size_t,
thread_phase: OodleLZ_Decode_ThreadPhase,
) -> c_ulonglong;
#[allow(non_camel_case_types)]
pub type OodleLZ_Compress = extern "C" fn(
compressor: OodleLZ_Compressor,
raw_buffer: *const c_void,
raw_len: c_size_t,
compressed_buffer: *mut c_void,
level: OodleLZ_CompressionLevel,
options: *const c_void,
dictionary_base: c_size_t,
lrm: *const c_void,
scratch_memory: *mut c_void,
scratch_size: c_size_t,
) -> c_ulonglong;
#[allow(non_camel_case_types)]
pub type OodleCore_Plugins_SetPrintf =
extern "C" fn(f: t_fp_OodleCore_Plugin_Printf) -> t_fp_OodleCore_Plugin_Printf;