2
Fork 0
This repository has been archived on 2022-11-09. You can view files and clone it, but cannot push or open issues or pull requests.
oodle-cli/oodle-cli.cpp

160 lines
4.7 KiB
C++

// 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";
void usage() {
std::cerr <<
"Usage: oodle-cli <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"
"The following environmental variables are recognized:\n"
" VERBOSITY: An integer between 0 and 3, with 0 being no logging and 3 being maximum logging.\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";
}
int main(int argc, char* argv[])
{
if (argc < 4) {
std::cerr << "Arguments missing!\n\n";
usage();
return 1;
}
char* var;
size_t len;
int verbosity = 0;
if (_dupenv_s(&var, &len, "VERBOSITY") == 0) {
if (var) {
verbosity = std::stoi(std::string(var, len));
std::cout << "Setting Oodle verbosity to " << verbosity << ".\n";
free(var);
}
}
else {
std::cerr << "Failed to read environment variable 'VERBOSITY'. Falling back to default.\n";
}
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 << "Failed to add DLL search path: '" << token << "'!\n";
}
else {
std::cout << "Added DLL search path: '" << path << "'.\n";
}
}
load_flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
free(var);
}
}
else {
std::cerr << "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 = (decltype(OodleLZ_Decompress)*)GetProcAddress((HMODULE)hDLL, "OodleLZ_Decompress");
if (decompress == NULL) {
std::cerr << "ERROR: The library is incompatible!\n";
return 1;
}
std::string in_name = argv[1];
std::string out_name = argv[2];
size_t raw_buffer_size = std::stoi(argv[3]);
std::cout << "Attempting to decompress from '" << in_name << "' to '" << out_name << "' (" << raw_buffer_size << " bytes).\n";
std::ifstream in_file(in_name, std::ios::binary | std::ios::ate);
if (!in_file) {
std::cerr << "Failed to open compressed file!\n";
return 1;
}
std::ofstream out_file(out_name, std::ios::binary);
if (!out_file) {
std::cerr << "Failed to open output 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 << "Failed to read compressed file!\n";
return 1;
}
std::vector<char> raw_buffer(raw_buffer_size);
int res = decompress(
compressed_buffer.data(),
compressed_buffer_size,
raw_buffer.data(),
raw_buffer_size,
OodleLZ_FuzzSafe_Yes,
OodleLZ_CheckCRC_No,
(OodleLZ_Verbosity)verbosity,
nullptr,
0,
nullptr,
nullptr,
nullptr,
0,
OodleLZ_Decode_Unthreaded
);
out_file.write(raw_buffer.data(), res);
if (out_file.fail()) {
std::cerr << "Failed to write output file!\n";
return 1;
}
if (res != raw_buffer_size) {
std::cerr << "Failed to decompress. Expected " << raw_buffer_size << " bytes, got " << res << "!\n";
return 1;
}
std::cout << "Done!\n";
}