From 892070f3dec1dc690983fd862880e37e711c2516 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Sun, 12 Apr 2026 17:55:56 -0500 Subject: Add BSA in-memory extraction and nested preview support bsatk: - Archive::extractToMemory() extracts a file directly into a byte buffer instead of a filesystem path, backed by a std::ostringstream sink. - Archive::findFile() locates a file by relative path, case-insensitive and separator-agnostic, walking the folder tree recursively. - extractDirect/extractCompressed now take std::ostream& so both the ofstream and ostringstream paths share the same implementation. libbsarch: shim rewrite on Linux to map the Windows API surface onto bsatk::Archive, enabling preview_bsa to open vanilla BSAs via the same interface as other plugins. preview_bsa: double-click on a file in the BSA tree now extracts the bytes via extractToMemory() and hands them to IOrganizer::previewFileData for nested preview rendering (e.g. NIF inside a BSA). uibase + organizerproxy + organizercore: new IOrganizer::previewFileData virtual that routes in-memory file bytes through the first registered IPluginPreview matching the extension. Uses heap + WA_DeleteOnClose + open() to avoid nested exec() softlock from mod info filetree -> preview_bsa tree -> nif preview. docker/build-inner.sh: stage preview_nif shaders into plugin_data/shaders so ShaderManager can load them via IOrganizer::getPluginDataPath(). Co-Authored-By: Claude Opus 4.6 (1M context) --- libs/libbsarch/src/libbsarch.cpp | 514 +++++++++++++++++++++++++++++---------- 1 file changed, 386 insertions(+), 128 deletions(-) (limited to 'libs/libbsarch/src/libbsarch.cpp') diff --git a/libs/libbsarch/src/libbsarch.cpp b/libs/libbsarch/src/libbsarch.cpp index 52ded9f..1f98ddc 100644 --- a/libs/libbsarch/src/libbsarch.cpp +++ b/libs/libbsarch/src/libbsarch.cpp @@ -1,206 +1,464 @@ #ifdef BSARCH_DLL_EXPORT #include "libbsarch.h" -namespace libbsarch { +#include +#include +#include +#include -BSARCH_DLL_API(bsa_entry_list_t) bsa_entry_list_create() -{ - return nullptr; -} +#ifndef _WIN32 +#include -BSARCH_DLL_API(bsa_result_message_t) bsa_entry_list_free(bsa_entry_list_t entry_list) -{ - return {0}; -} - -BSARCH_DLL_API(uint32_t) bsa_entry_list_count(bsa_entry_list_t entry_list) -{ - return 0; -} +#include +#include +#include +#endif -BSARCH_DLL_API(bsa_result_message_t) bsa_entry_list_add(bsa_entry_list_t entry_list, const wchar_t *entry_string) -{ - return {0}; -} +namespace libbsarch { -BSARCH_DLL_API(uint32_t) -bsa_entry_list_get(bsa_entry_list_t entry_list, uint32_t index, uint32_t string_buffer_size, wchar_t *string_buffer) -{ - return 0; -} +#ifndef _WIN32 + +// --------------------------------------------------------------------------- +// Linux implementation backed by bsatk. +// +// libbsarch is a Delphi-based archive library on Windows. Upstream MO2 uses +// a prebuilt DLL from vcpkg. On Linux we have no such runtime, so previously +// this file was a set of no-op stubs — which meant anything that went through +// the C++ wrappers (bs_archive::load_from_disk / extract_to_memory, used e.g. +// by the data-tab preview pipeline in OrganizerCore) silently returned empty. +// +// This replacement wires the read path through BSA::Archive from libs/bsatk, +// which is a pure C++ BSA reader already built and linked in MO2. The write +// side (creating archives, adding files, saving) is still stubbed; bsapacker +// linked against that stub before and keeps linking against it now. +// --------------------------------------------------------------------------- + +struct LinuxArchive +{ + BSA::Archive archive; + std::string filename; + bool loaded = false; + + // Keep shared_ptrs alive so we can hand out a raw File* as an opaque + // record id and safely dereference it later from *_by_record calls. + std::unordered_map fileRecords; +}; + +static LinuxArchive* as_archive(bsa_archive_t handle) +{ + return static_cast(handle); +} + +static std::string wchar_to_utf8(const wchar_t* ws) +{ + if (!ws) return {}; + std::mbstate_t state{}; + const wchar_t* src = ws; + std::size_t len = std::wcsrtombs(nullptr, &src, 0, &state); + if (len == static_cast(-1)) { + // Fallback: BSA paths are ASCII, just truncate each wchar to its low + // byte. Good enough for any real Bethesda archive path. + std::string out; + for (const wchar_t* p = ws; *p; ++p) { + out.push_back(static_cast(*p & 0x7F)); + } + return out; + } + std::string out(len, '\0'); + state = {}; + src = ws; + std::wcsrtombs(out.data(), &src, len + 1, &state); + return out; +} + +static void copy_to_wbuffer(const std::string& src, uint32_t buf_size, wchar_t* buf) +{ + if (!buf || buf_size == 0) return; + std::mbstate_t state{}; + const char* p = src.c_str(); + std::size_t len = std::mbsrtowcs(buf, &p, buf_size - 1, &state); + if (len == static_cast(-1)) { + // ASCII fallback + std::size_t i = 0; + for (; i + 1 < buf_size && i < src.size(); ++i) { + buf[i] = static_cast(static_cast(src[i])); + } + buf[i] = 0; + return; + } + const std::size_t last = std::min(len, buf_size - 1); + buf[last] = 0; +} + +static bsa_result_message_t make_message(bsa_result_code_t code) +{ + bsa_result_message_t r{}; + r.code = static_cast(code); + return r; +} + +static bsa_result_message_buffer_t make_extract_result( + const std::vector& data) +{ + bsa_result_message_buffer_t out{}; + out.message.code = BSA_RESULT_NONE; + out.buffer.size = static_cast(data.size()); + if (!data.empty()) { + auto* copy = new unsigned char[data.size()]; + std::memcpy(copy, data.data(), data.size()); + out.buffer.data = copy; + } else { + out.buffer.data = nullptr; + } + return out; +} + +static bsa_result_message_buffer_t make_extract_error() +{ + bsa_result_message_buffer_t out{}; + out.message.code = BSA_RESULT_EXCEPTION; + out.buffer.size = 0; + out.buffer.data = nullptr; + return out; +} + +// --- Lifecycle --- BSARCH_DLL_API(bsa_archive_t) bsa_create() { - return nullptr; + return static_cast(new LinuxArchive()); } -BSARCH_DLL_API(bsa_result_message_t) bsa_free(bsa_archive_t archive) +BSARCH_DLL_API(bsa_result_message_t) bsa_free(bsa_archive_t handle) { - return {0}; + delete as_archive(handle); + return make_message(BSA_RESULT_NONE); } -BSARCH_DLL_API(bsa_result_message_t) bsa_load_from_file(bsa_archive_t archive, const wchar_t *file_path) +BSARCH_DLL_API(bsa_result_message_t) bsa_close(bsa_archive_t handle) { - return {0}; + if (auto* wrapper = as_archive(handle)) { + wrapper->archive.close(); + wrapper->fileRecords.clear(); + wrapper->loaded = false; + } + return make_message(BSA_RESULT_NONE); } -BSARCH_DLL_API(bsa_result_message_t) -bsa_create_archive(bsa_archive_t archive, - const wchar_t *file_path, - bsa_archive_type_t archive_type, - bsa_entry_list_t entry_list) -{ - return {0}; -} - -BSARCH_DLL_API(bsa_result_message_t) bsa_save(bsa_archive_t archive) -{ - return {0}; -} +// --- Reading --- BSARCH_DLL_API(bsa_result_message_t) -bsa_add_file_from_disk(bsa_archive_t archive, const wchar_t *file_path, const wchar_t *source_path) +bsa_load_from_file(bsa_archive_t handle, const wchar_t* file_path) { - return {0}; + auto* wrapper = as_archive(handle); + if (!wrapper || !file_path) { + return make_message(BSA_RESULT_EXCEPTION); + } + wrapper->filename = wchar_to_utf8(file_path); + const BSA::EErrorCode rc = + wrapper->archive.read(wrapper->filename.c_str(), false); + if (rc != BSA::ERROR_NONE && rc != BSA::ERROR_INVALIDHASHES) { + return make_message(BSA_RESULT_EXCEPTION); + } + wrapper->loaded = true; + return make_message(BSA_RESULT_NONE); } -BSARCH_DLL_API(bsa_result_message_t) -bsa_add_file_from_disk_root(bsa_archive_t archive, const wchar_t *root_dir, const wchar_t *source_path) +BSARCH_DLL_API(bsa_file_record_t) +bsa_find_file_record(bsa_archive_t handle, const wchar_t* file_path) { - return {0}; -} + auto* wrapper = as_archive(handle); + if (!wrapper || !wrapper->loaded || !file_path) return nullptr; -BSARCH_DLL_API(bsa_result_message_t) -bsa_add_file_from_memory(bsa_archive_t archive, const wchar_t *file_path, uint32_t size, bsa_buffer_t data) -{ - return {0}; -} + BSA::File::Ptr file = wrapper->archive.findFile(wchar_to_utf8(file_path)); + if (!file) return nullptr; -BSARCH_DLL_API(bsa_file_record_t) bsa_find_file_record(bsa_archive_t archive, const wchar_t *file_path) -{ - return nullptr; + BSA::File* raw = file.get(); + wrapper->fileRecords[raw] = file; + return static_cast(raw); } BSARCH_DLL_API(bsa_result_message_buffer_t) -bsa_extract_file_data_by_record(bsa_archive_t archive, bsa_file_record_t file_record) -{ - return {0}; +bsa_extract_file_data_by_filename(bsa_archive_t handle, const wchar_t* file_path) +{ + auto* wrapper = as_archive(handle); + if (!wrapper || !wrapper->loaded || !file_path) { + return make_extract_error(); + } + BSA::File::Ptr file = wrapper->archive.findFile(wchar_to_utf8(file_path)); + if (!file) { + return make_extract_error(); + } + std::vector data; + if (wrapper->archive.extractToMemory(file, data) != BSA::ERROR_NONE) { + return make_extract_error(); + } + return make_extract_result(data); } BSARCH_DLL_API(bsa_result_message_buffer_t) -bsa_extract_file_data_by_filename(bsa_archive_t archive, const wchar_t *file_path) -{ - return {0}; -} - -BSARCH_DLL_API(bsa_result_message_t) bsa_file_data_free(bsa_archive_t archive, bsa_result_buffer_t file_data_result) -{ - return {0}; +bsa_extract_file_data_by_record(bsa_archive_t handle, bsa_file_record_t record) +{ + auto* wrapper = as_archive(handle); + if (!wrapper || !wrapper->loaded || !record) { + return make_extract_error(); + } + auto it = wrapper->fileRecords.find(static_cast(record)); + if (it == wrapper->fileRecords.end()) { + return make_extract_error(); + } + std::vector data; + if (wrapper->archive.extractToMemory(it->second, data) != BSA::ERROR_NONE) { + return make_extract_error(); + } + return make_extract_result(data); } BSARCH_DLL_API(bsa_result_message_t) -bsa_extract_file(bsa_archive_t archive, const wchar_t *file_path, const wchar_t *save_as) +bsa_file_data_free(bsa_archive_t, bsa_result_buffer_t buffer) { - return {0}; + delete[] static_cast(buffer.data); + return make_message(BSA_RESULT_NONE); } -BSARCH_DLL_API(bsa_result_message_t) -bsa_iterate_files(bsa_archive_t archive, bsa_file_iteration_proc_t file_iteration_proc, void *context) +BSARCH_DLL_API(bool) +bsa_file_exists(bsa_archive_t handle, const wchar_t* file_path) { - return {0}; + auto* wrapper = as_archive(handle); + if (!wrapper || !wrapper->loaded || !file_path) return false; + return wrapper->archive.findFile(wchar_to_utf8(file_path)) != nullptr; } -BSARCH_DLL_API(bool) bsa_file_exists(bsa_archive_t archive, const wchar_t *file_path) -{ - return false; -} +// --- Metadata --- -BSARCH_DLL_API(bsa_result_message_t) -bsa_get_resource_list(bsa_archive_t archive, bsa_entry_list_t entry_result_list, const wchar_t *folder) -{ - return {0}; +BSARCH_DLL_API(uint32_t) +bsa_filename_get(bsa_archive_t handle, uint32_t buf_size, wchar_t* buf) +{ + auto* wrapper = as_archive(handle); + if (!wrapper) return 0; + copy_to_wbuffer(wrapper->filename, buf_size, buf); + return static_cast(wrapper->filename.size()); +} + +BSARCH_DLL_API(bsa_archive_type_t) +bsa_archive_type_get(bsa_archive_t handle) +{ + auto* wrapper = as_archive(handle); + if (!wrapper || !wrapper->loaded) return baNone; + switch (wrapper->archive.getType()) { + case TYPE_MORROWIND: + return baTES3; + case TYPE_OBLIVION: + return baTES4; + case TYPE_FALLOUT3: + return baFO3; + case TYPE_SKYRIMSE: + return baSSE; + case TYPE_FALLOUT4: + case TYPE_FALLOUT4NG_7: + case TYPE_FALLOUT4NG_8: + return baFO4; + case TYPE_STARFIELD: + return baSF; + case TYPE_STARFIELD_LZ4_TEXTURE: + return baSFdds; + default: + return baNone; + } +} + +BSARCH_DLL_API(uint32_t) bsa_version_get(bsa_archive_t handle) +{ + auto* wrapper = as_archive(handle); + if (!wrapper || !wrapper->loaded) return 0; + return static_cast(wrapper->archive.getType()); } -BSARCH_DLL_API(bsa_result_message_t) -bsa_resolve_hash(bsa_archive_t archive, uint64_t hash, bsa_entry_list_t entry_result_list) +BSARCH_DLL_API(uint32_t) +bsa_format_name_get(bsa_archive_t handle, uint32_t buf_size, wchar_t* buf) +{ + auto* wrapper = as_archive(handle); + if (!wrapper) return 0; + const char* name = "BSA"; + if (wrapper->loaded) { + switch (wrapper->archive.getType()) { + case TYPE_MORROWIND: + name = "Morrowind"; + break; + case TYPE_OBLIVION: + name = "Oblivion"; + break; + case TYPE_FALLOUT3: + name = "Fallout 3"; + break; + case TYPE_SKYRIMSE: + name = "Skyrim Special Edition"; + break; + case TYPE_FALLOUT4: + case TYPE_FALLOUT4NG_7: + case TYPE_FALLOUT4NG_8: + name = "Fallout 4"; + break; + case TYPE_STARFIELD: + name = "Starfield"; + break; + case TYPE_STARFIELD_LZ4_TEXTURE: + name = "Starfield DDS"; + break; + default: + break; + } + } + const std::string s(name); + copy_to_wbuffer(s, buf_size, buf); + return static_cast(s.size()); +} + +BSARCH_DLL_API(uint32_t) bsa_file_count_get(bsa_archive_t handle) +{ + auto* wrapper = as_archive(handle); + if (!wrapper || !wrapper->loaded) return 0; + BSA::Folder::Ptr root = wrapper->archive.getRoot(); + return root ? root->countFiles() : 0; +} + +BSARCH_DLL_API(uint32_t) bsa_archive_flags_get(bsa_archive_t handle) +{ + auto* wrapper = as_archive(handle); + if (!wrapper || !wrapper->loaded) return 0; + return wrapper->archive.getFlags(); +} + +// --- Write-side + misc no-ops (bsapacker links these; writes are not +// implemented on Linux yet, same as before this refactor). --- + +BSARCH_DLL_API(bsa_entry_list_t) bsa_entry_list_create() { - return {0}; + return nullptr; } - -BSARCH_DLL_API(bsa_result_message_t) bsa_close(bsa_archive_t archive) +BSARCH_DLL_API(bsa_result_message_t) bsa_entry_list_free(bsa_entry_list_t) { - return {0}; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(uint32_t) bsa_filename_get(bsa_archive_t archive, uint32_t string_buffer_size, wchar_t *string_buffer) +BSARCH_DLL_API(uint32_t) bsa_entry_list_count(bsa_entry_list_t) { return 0; } - -BSARCH_DLL_API(bsa_archive_type_t) bsa_archive_type_get(bsa_archive_t archive) +BSARCH_DLL_API(bsa_result_message_t) +bsa_entry_list_add(bsa_entry_list_t, const wchar_t*) { - return bsa_archive_type_t::baNone; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(uint32_t) bsa_version_get(bsa_archive_t archive) +BSARCH_DLL_API(uint32_t) +bsa_entry_list_get(bsa_entry_list_t, uint32_t, uint32_t, wchar_t*) { return 0; } - -BSARCH_DLL_API(uint32_t) bsa_format_name_get(bsa_archive_t archive, uint32_t string_buffer_size, wchar_t *string_buffer) +BSARCH_DLL_API(bsa_result_message_t) +bsa_create_archive(bsa_archive_t, const wchar_t*, bsa_archive_type_t, + bsa_entry_list_t) { - return 0; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(uint32_t) bsa_file_count_get(bsa_archive_t archive) +BSARCH_DLL_API(bsa_result_message_t) bsa_save(bsa_archive_t) { - return 0; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(uint32_t) bsa_archive_flags_get(bsa_archive_t archive) +BSARCH_DLL_API(bsa_result_message_t) +bsa_add_file_from_disk(bsa_archive_t, const wchar_t*, const wchar_t*) { - return 0; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(void) bsa_archive_flags_set(bsa_archive_t archive, uint32_t flags) +BSARCH_DLL_API(bsa_result_message_t) +bsa_add_file_from_disk_root(bsa_archive_t, const wchar_t*, const wchar_t*) { - return; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(uint32_t) bsa_file_flags_get(bsa_archive_t archive) +BSARCH_DLL_API(bsa_result_message_t) +bsa_add_file_from_memory(bsa_archive_t, const wchar_t*, uint32_t, bsa_buffer_t) { - return 0; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(void) bsa_file_flags_set(bsa_archive_t archive, uint32_t flags) +BSARCH_DLL_API(bsa_result_message_t) +bsa_extract_file(bsa_archive_t, const wchar_t*, const wchar_t*) { - return; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(bool) bsa_compress_get(bsa_archive_t archive) +BSARCH_DLL_API(bsa_result_message_t) +bsa_iterate_files(bsa_archive_t, bsa_file_iteration_proc_t, void*) { - return false; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(void) bsa_compress_set(bsa_archive_t archive, bool flags) +BSARCH_DLL_API(bsa_result_message_t) +bsa_get_resource_list(bsa_archive_t, bsa_entry_list_t, const wchar_t*) { - return; + return make_message(BSA_RESULT_NONE); } - -BSARCH_DLL_API(bool) bsa_share_data_get(bsa_archive_t archive) +BSARCH_DLL_API(void) bsa_archive_flags_set(bsa_archive_t, uint32_t) {} +BSARCH_DLL_API(uint32_t) bsa_file_flags_get(bsa_archive_t) { - return false; + return 0; } - -BSARCH_DLL_API(void) bsa_share_data_set(bsa_archive_t archive, bool flags) +BSARCH_DLL_API(void) bsa_file_flags_set(bsa_archive_t, uint32_t) {} +BSARCH_DLL_API(bool) bsa_compress_get(bsa_archive_t) { - return; + return false; } - -BSARCH_DLL_API(void) -bsa_file_dds_info_callback_set(bsa_archive_t archive, bsa_file_dds_info_proc_t file_dds_info_proc, void *context) +BSARCH_DLL_API(void) bsa_compress_set(bsa_archive_t, bool) {} +BSARCH_DLL_API(bool) bsa_share_data_get(bsa_archive_t) { - return; + return false; } -} // namespace libbsarch -#endif +BSARCH_DLL_API(void) bsa_share_data_set(bsa_archive_t, bool) {} +BSARCH_DLL_API(void) +bsa_file_dds_info_callback_set(bsa_archive_t, bsa_file_dds_info_proc_t, void*) +{ +} + +#else // _WIN32 + +// Windows path: upstream MO2 uses a prebuilt libbsarch DLL from vcpkg; this +// local tree is a compatibility stub that matches the exported symbol names. +// Keep it byte-compatible with previous behavior. + +BSARCH_DLL_API(bsa_entry_list_t) bsa_entry_list_create() { return nullptr; } +BSARCH_DLL_API(bsa_result_message_t) bsa_entry_list_free(bsa_entry_list_t) { return {0}; } +BSARCH_DLL_API(uint32_t) bsa_entry_list_count(bsa_entry_list_t) { return 0; } +BSARCH_DLL_API(bsa_result_message_t) bsa_entry_list_add(bsa_entry_list_t, const wchar_t*) { return {0}; } +BSARCH_DLL_API(uint32_t) bsa_entry_list_get(bsa_entry_list_t, uint32_t, uint32_t, wchar_t*) { return 0; } +BSARCH_DLL_API(bsa_archive_t) bsa_create() { return nullptr; } +BSARCH_DLL_API(bsa_result_message_t) bsa_free(bsa_archive_t) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_load_from_file(bsa_archive_t, const wchar_t*) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_create_archive(bsa_archive_t, const wchar_t*, bsa_archive_type_t, bsa_entry_list_t) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_save(bsa_archive_t) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_add_file_from_disk(bsa_archive_t, const wchar_t*, const wchar_t*) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_add_file_from_disk_root(bsa_archive_t, const wchar_t*, const wchar_t*) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_add_file_from_memory(bsa_archive_t, const wchar_t*, uint32_t, bsa_buffer_t) { return {0}; } +BSARCH_DLL_API(bsa_file_record_t) bsa_find_file_record(bsa_archive_t, const wchar_t*) { return nullptr; } +BSARCH_DLL_API(bsa_result_message_buffer_t) bsa_extract_file_data_by_record(bsa_archive_t, bsa_file_record_t) { return {0}; } +BSARCH_DLL_API(bsa_result_message_buffer_t) bsa_extract_file_data_by_filename(bsa_archive_t, const wchar_t*) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_file_data_free(bsa_archive_t, bsa_result_buffer_t) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_extract_file(bsa_archive_t, const wchar_t*, const wchar_t*) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_iterate_files(bsa_archive_t, bsa_file_iteration_proc_t, void*) { return {0}; } +BSARCH_DLL_API(bool) bsa_file_exists(bsa_archive_t, const wchar_t*) { return false; } +BSARCH_DLL_API(bsa_result_message_t) bsa_get_resource_list(bsa_archive_t, bsa_entry_list_t, const wchar_t*) { return {0}; } +BSARCH_DLL_API(bsa_result_message_t) bsa_close(bsa_archive_t) { return {0}; } +BSARCH_DLL_API(uint32_t) bsa_filename_get(bsa_archive_t, uint32_t, wchar_t*) { return 0; } +BSARCH_DLL_API(bsa_archive_type_t) bsa_archive_type_get(bsa_archive_t) { return bsa_archive_type_t::baNone; } +BSARCH_DLL_API(uint32_t) bsa_version_get(bsa_archive_t) { return 0; } +BSARCH_DLL_API(uint32_t) bsa_format_name_get(bsa_archive_t, uint32_t, wchar_t*) { return 0; } +BSARCH_DLL_API(uint32_t) bsa_file_count_get(bsa_archive_t) { return 0; } +BSARCH_DLL_API(uint32_t) bsa_archive_flags_get(bsa_archive_t) { return 0; } +BSARCH_DLL_API(void) bsa_archive_flags_set(bsa_archive_t, uint32_t) {} +BSARCH_DLL_API(uint32_t) bsa_file_flags_get(bsa_archive_t) { return 0; } +BSARCH_DLL_API(void) bsa_file_flags_set(bsa_archive_t, uint32_t) {} +BSARCH_DLL_API(bool) bsa_compress_get(bsa_archive_t) { return false; } +BSARCH_DLL_API(void) bsa_compress_set(bsa_archive_t, bool) {} +BSARCH_DLL_API(bool) bsa_share_data_get(bsa_archive_t) { return false; } +BSARCH_DLL_API(void) bsa_share_data_set(bsa_archive_t, bool) {} +BSARCH_DLL_API(void) bsa_file_dds_info_callback_set(bsa_archive_t, bsa_file_dds_info_proc_t, void*) {} + +#endif // !_WIN32 + +} // namespace libbsarch +#endif // BSARCH_DLL_EXPORT -- cgit v1.3.1