aboutsummaryrefslogtreecommitdiff
path: root/libs/libbsarch/include
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
commit7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch)
tree27fb39be241fdb5ac2734c574de678977d1856d0 /libs/libbsarch/include
Fluorine Manager: full Linux port of Mod Organizer 2
Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'libs/libbsarch/include')
-rw-r--r--libs/libbsarch/include/libbsarch/base_types.hpp66
-rw-r--r--libs/libbsarch/include/libbsarch/bs_archive.h100
-rw-r--r--libs/libbsarch/include/libbsarch/bs_archive_auto.hpp39
-rw-r--r--libs/libbsarch/include/libbsarch/bs_archive_entries.h24
-rw-r--r--libs/libbsarch/include/libbsarch/libbsarch.h157
-rw-r--r--libs/libbsarch/include/libbsarch/libbsarch.hpp37
-rw-r--r--libs/libbsarch/include/libbsarch/utils/convertible_ostream.hpp37
-rw-r--r--libs/libbsarch/include/libbsarch/utils/convertible_string.hpp50
-rw-r--r--libs/libbsarch/include/libbsarch/utils/string_convert.hpp18
9 files changed, 528 insertions, 0 deletions
diff --git a/libs/libbsarch/include/libbsarch/base_types.hpp b/libs/libbsarch/include/libbsarch/base_types.hpp
new file mode 100644
index 0000000..2baf4be
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/base_types.hpp
@@ -0,0 +1,66 @@
+/* Copyright (C) 2019 G'k
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+#pragma once
+
+#include "libbsarch.h"
+#include "utils/convertible_string.hpp"
+#include <variant>
+
+namespace libbsarch {
+struct memory_blob : public bsa_result_buffer_t
+{
+ memory_blob(uint32_t buffer_size, bsa_buffer_t buffer_data, bsa_archive_t parent)
+ : bsa_result_buffer_t{buffer_size, buffer_data}
+ , parent_(parent)
+ {}
+
+ memory_blob(bsa_result_buffer_t buffer, bsa_archive_t parent)
+ : bsa_result_buffer_t(buffer)
+ , parent_(parent)
+ {}
+
+ bsa_archive_t parent_;
+
+ memory_blob(memory_blob const &) = default;
+ ~memory_blob() { bsa_file_data_free(parent_, *this); }
+};
+
+struct disk_blob
+{
+ disk_blob(const convertible_string &root_dir, const convertible_string &absolute_path)
+ : path_in_archive(absolute_path)
+ , path_on_disk(absolute_path)
+ {
+ path_in_archive.remove_substring(root_dir);
+ }
+
+ disk_blob(const convertible_string &path_in_archive,
+ const convertible_string &absolute_path,
+ [[maybe_unused]] bool decoy_parameter)
+ : path_in_archive(path_in_archive)
+ , path_on_disk(absolute_path)
+ {}
+
+ convertible_string path_in_archive;
+ convertible_string path_on_disk;
+};
+
+struct bs_packed_file
+{
+ bs_packed_file(const disk_blob &blob)
+ : path_in_archive(blob.path_in_archive)
+ , data(blob.path_on_disk)
+ {}
+
+ bs_packed_file(convertible_string path_in_archive, memory_blob blob)
+ : path_in_archive(std::move(path_in_archive))
+ , data(blob)
+ {}
+
+ convertible_string path_in_archive;
+ std::variant<memory_blob, convertible_string> data;
+};
+
+} // namespace libbsarch
diff --git a/libs/libbsarch/include/libbsarch/bs_archive.h b/libs/libbsarch/include/libbsarch/bs_archive.h
new file mode 100644
index 0000000..1954e99
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/bs_archive.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include "bs_archive_entries.h"
+#include "libbsarch.hpp"
+
+namespace libbsarch {
+class bs_archive
+{
+public:
+ bs_archive();
+ bs_archive(const bsa_archive_type_t &type);
+ virtual ~bs_archive();
+
+ /* Properties */
+ convertible_string get_filename();
+ bsa_archive_type_t get_type();
+ uint32_t get_version();
+ convertible_string get_format_name();
+ uint32_t get_file_count();
+
+ uint32_t get_archive_flags();
+ void set_archive_flags(uint32_t flags);
+
+ uint32_t get_file_flags();
+ void set_file_flags(uint32_t flags);
+
+ void set_compressed(bool value);
+ bool get_compressed();
+
+ void set_share_data(bool value);
+ bool get_share_data();
+
+ /* Input-Output */
+ virtual void load_from_disk(const convertible_string &archive_path);
+ virtual void create(const convertible_string &archiveName, const bs_archive_entries &entries);
+ virtual void create(const convertible_string &archiveName,
+ const bs_archive_entries &entries,
+ const bsa_archive_type_t type);
+ void save() const;
+
+ /* Add to archive */
+ virtual void add_file_from_disk(const disk_blob &blob);
+ virtual void add_file_from_memory(const convertible_string &path_in_archive, const memory_blob &memory_data);
+
+ /* Extract */
+ memory_blob extract_to_memory(bsa_file_record_t record);
+ memory_blob extract_to_memory(const convertible_string &filename);
+ void extract_to_disk(const convertible_string &filename, const convertible_string &save_as) const;
+
+ /* Selectors */
+ bsa_file_record_t find_file_record(const convertible_string &filename);
+ std::vector<convertible_string> list_files() const;
+
+ /* Other */
+
+ /*! \brief Sets the DDS callback. It is required to use Fallout 4 DDS archives. You do not have
+ * to manage the lifetime of the provided context
+ * \example
+ void dds_callback([[maybe_unused]] bsa_archive_t archive,
+ const wchar_t *file_path,
+ bsa_dds_info_t *dds_info,
+ void *context)
+ {
+ const auto &path = *static_cast<convertible_string *>(context) + '/' + convertible_string(file_path);
+
+ auto image = std::make_unique<DirectX::ScratchImage>();
+ DirectX::TexMetadata info;
+
+ const auto hr = LoadFromDDSFile(PREPARE_PATH_LIBBSARCH(path), DirectX::DDS_FLAGS_BAD_DXTN_TAILS, &info, *image);
+ if (FAILED(hr))
+ {
+ //Do not throw here. Exceptions will be ignored
+ return;
+ }
+
+ dds_info->width = info.width;
+ dds_info->height = info.height;
+ dds_info->mipmaps = info.mipLevels;
+ }
+ */
+ template<typename context_type>
+ void set_dds_callback(bsa_file_dds_info_proc_t dds_function, const context_type &context)
+ {
+ debug_log() << "Setting DDS callback for archive: " << archive_ << "\nCallback adress: " << &dds_function;
+
+ auto heap_context = new context_type(context);
+ callback_contexts_.emplace_back(heap_context);
+ bsa_file_dds_info_callback_set(archive_, dds_function, callback_contexts_.back());
+ }
+
+ bsa_archive_t get_archive() const;
+
+protected:
+ bsa_archive_t archive_;
+ bsa_archive_type_t type_;
+
+private:
+ std::vector<void *> callback_contexts_;
+};
+} // namespace libbsarch
diff --git a/libs/libbsarch/include/libbsarch/bs_archive_auto.hpp b/libs/libbsarch/include/libbsarch/bs_archive_auto.hpp
new file mode 100644
index 0000000..c288f68
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/bs_archive_auto.hpp
@@ -0,0 +1,39 @@
+/* Copyright (C) 2019 G'k
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+#pragma once
+
+#include "bs_archive.h"
+
+namespace libbsarch {
+/*!
+ * \brief The bs_archive_auto class is a convenience class. It manages both bs_archive and bs_archive_entries.
+ * It is recommended when packing from disk/extracting to disk
+ * Otherwise, if using memory, the use of these two separate classes is recommended
+ */
+class bs_archive_auto : public bs_archive
+{
+protected:
+ bs_archive_entries entries_;
+
+public:
+ bs_archive_auto() = default;
+ bs_archive_auto(const bsa_archive_type_t &type);
+
+ void add_file_from_disk(const disk_blob &blob) override;
+ void add_file_from_disk(const std::vector<disk_blob> &blobs);
+ void add_file_from_memory(const convertible_string &path_in_archive, const memory_blob &memory_data) override;
+ void add_file(const bs_packed_file &file);
+
+ void extract_all(const convertible_string &directory, bool overwrite_current_files);
+
+ void load_from_disk(const convertible_string &archive_path) override;
+ void save_to_disk(const convertible_string &archive_path);
+
+private:
+ using bs_archive::create; //Use save_to_disk instead
+ using bs_archive::save; //Use save_to_disk instead
+ std::vector<bs_packed_file> files_;
+};
+} // namespace libbsarch
diff --git a/libs/libbsarch/include/libbsarch/bs_archive_entries.h b/libs/libbsarch/include/libbsarch/bs_archive_entries.h
new file mode 100644
index 0000000..7df2f40
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/bs_archive_entries.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "libbsarch.hpp"
+#include <vector>
+
+namespace libbsarch {
+class bs_archive_entries
+{
+public:
+ bs_archive_entries();
+ explicit bs_archive_entries(const std::vector<convertible_string> &entries);
+ explicit bs_archive_entries(const bsa_entry_list_t &entries);
+ ~bs_archive_entries();
+
+ void add(const convertible_string &filepath);
+ uint32_t count();
+ std::vector<convertible_string> list();
+
+ bsa_entry_list_t getEntries() const;
+
+protected:
+ bsa_entry_list_t _entries;
+};
+} // namespace libbsarch
diff --git a/libs/libbsarch/include/libbsarch/libbsarch.h b/libs/libbsarch/include/libbsarch/libbsarch.h
new file mode 100644
index 0000000..bda7ca0
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/libbsarch.h
@@ -0,0 +1,157 @@
+#pragma once
+
+#include <dxgiformat.h>
+
+#include <DDS.h>
+
+#include <stdint.h>
+
+#ifdef _WIN32
+ #ifdef BSARCH_DLL_EXPORT
+ #define BSARCH_DLL_API(ReturnType) extern "C" __declspec(dllexport) ReturnType __stdcall
+ #else
+ #define BSARCH_DLL_API(ReturnType) extern "C" __declspec(dllimport) ReturnType __stdcall
+ #endif
+#else
+ #ifdef BSARCH_DLL_EXPORT
+ #define BSARCH_DLL_API(ReturnType) extern "C" __attribute__((visibility("default"))) ReturnType
+ #else
+ #define BSARCH_DLL_API(ReturnType) extern "C" ReturnType
+ #endif
+#endif
+
+#ifdef __GNUC__
+#define PACKED(datastructure) datastructure __attribute__((__packed__))
+#else
+#define PACKED(datastructure) __pragma(pack(push, 1)) datastructure __pragma(pack(pop))
+#endif
+
+typedef enum bsa_result_code_e
+{
+ BSA_RESULT_NONE = 0,
+ BSA_RESULT_EXCEPTION = -1
+} bsa_result_code_t;
+
+typedef void *bsa_buffer_t;
+typedef void *bsa_archive_t;
+typedef void *bsa_entry_list_t;
+typedef void *bsa_file_record_t;
+typedef void *bsa_folder_record_t;
+
+typedef struct bsa_dds_info_s
+{
+ uint32_t width, height, mipmaps;
+} bsa_dds_info_t;
+
+PACKED(struct bsa_dds_header_s {
+ uint32_t magic; // DDS_MAGIC
+ DirectX::DDS_HEADER header;
+});
+
+typedef struct bsa_dds_header_s bsa_dds_header_t;
+
+PACKED(struct bsa_result_message_s {
+ int8_t code; // bsa_result_code_t
+ wchar_t text[1024];
+});
+
+typedef struct bsa_result_message_s bsa_result_message_t;
+
+PACKED(struct bsa_result_buffer_s {
+ uint32_t size;
+ bsa_buffer_t data;
+});
+
+typedef struct bsa_result_buffer_s bsa_result_buffer_t;
+
+PACKED(struct bsa_result_message_buffer_s {
+ bsa_result_buffer_t buffer;
+ bsa_result_message_t message;
+});
+
+typedef struct bsa_result_message_buffer_s bsa_result_message_buffer_t;
+
+typedef enum bsa_archive_state_e
+{
+ stReading,
+ stWriting
+} bsa_archive_state_t;
+
+typedef enum bsa_archive_type_e
+{
+ baNone,
+ baTES3,
+ baTES4,
+ baFO3,
+ baSSE,
+ baFO4,
+ baFO4dds,
+ baSF,
+ baSFdds
+} bsa_archive_type_t;
+
+typedef void (*bsa_file_dds_info_proc_t)(bsa_archive_t archive,
+ const wchar_t *file_path,
+ bsa_dds_info_t *dds_info,
+ void *context);
+typedef bool (*bsa_file_iteration_proc_t)(bsa_archive_t archive,
+ const wchar_t *file_path,
+ bsa_file_record_t file_record,
+ bsa_folder_record_t folder_record,
+ void *context);
+
+BSARCH_DLL_API(bsa_entry_list_t) bsa_entry_list_create();
+BSARCH_DLL_API(bsa_result_message_t) bsa_entry_list_free(bsa_entry_list_t entry_list);
+BSARCH_DLL_API(uint32_t) bsa_entry_list_count(bsa_entry_list_t entry_list);
+BSARCH_DLL_API(bsa_result_message_t) bsa_entry_list_add(bsa_entry_list_t entry_list, const wchar_t *entry_string);
+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);
+
+BSARCH_DLL_API(bsa_archive_t) bsa_create();
+BSARCH_DLL_API(bsa_result_message_t) bsa_free(bsa_archive_t archive);
+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_create_archive(bsa_archive_t archive,
+ const wchar_t *file_path,
+ bsa_archive_type_t _archivetype,
+ bsa_entry_list_t entry_list);
+BSARCH_DLL_API(bsa_result_message_t) bsa_save(bsa_archive_t archive);
+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);
+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_result_message_t)
+bsa_add_file_from_memory(bsa_archive_t archive, const wchar_t *file_path, uint32_t size, bsa_buffer_t data);
+BSARCH_DLL_API(bsa_file_record_t) bsa_find_file_record(bsa_archive_t archive, const wchar_t *file_path);
+BSARCH_DLL_API(bsa_result_message_buffer_t)
+bsa_extract_file_data_by_record(bsa_archive_t archive, bsa_file_record_t file_record);
+BSARCH_DLL_API(bsa_result_message_buffer_t)
+bsa_extract_file_data_by_filename(bsa_archive_t archive, const wchar_t *file_path);
+BSARCH_DLL_API(bsa_result_message_t) bsa_file_data_free(bsa_archive_t archive, bsa_result_buffer_t file_data_result);
+BSARCH_DLL_API(bsa_result_message_t)
+bsa_extract_file(bsa_archive_t archive, const wchar_t *file_path, const wchar_t *save_as);
+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 archive, const wchar_t *file_path);
+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);
+BSARCH_DLL_API(bsa_result_message_t) bsa_close(bsa_archive_t archive);
+
+BSARCH_DLL_API(uint32_t)
+bsa_filename_get(bsa_archive_t archive, uint32_t string_buffer_size, wchar_t *string_buffer);
+BSARCH_DLL_API(bsa_archive_type_t) bsa_archive_type_get(bsa_archive_t archive);
+BSARCH_DLL_API(uint32_t) bsa_version_get(bsa_archive_t archive);
+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(uint32_t) bsa_file_count_get(bsa_archive_t archive);
+BSARCH_DLL_API(uint32_t) bsa_archive_flags_get(bsa_archive_t archive);
+BSARCH_DLL_API(void) bsa_archive_flags_set(bsa_archive_t archive, uint32_t flags);
+BSARCH_DLL_API(uint32_t) bsa_file_flags_get(bsa_archive_t archive);
+BSARCH_DLL_API(void) bsa_file_flags_set(bsa_archive_t archive, uint32_t flags);
+BSARCH_DLL_API(bool) bsa_compress_get(bsa_archive_t archive);
+BSARCH_DLL_API(void) bsa_compress_set(bsa_archive_t archive, bool flags);
+BSARCH_DLL_API(bool) bsa_share_data_get(bsa_archive_t archive);
+BSARCH_DLL_API(void) bsa_share_data_set(bsa_archive_t archive, bool flags);
+
+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);
diff --git a/libs/libbsarch/include/libbsarch/libbsarch.hpp b/libs/libbsarch/include/libbsarch/libbsarch.hpp
new file mode 100644
index 0000000..2a6acce
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/libbsarch.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "base_types.hpp"
+#include "utils/convertible_ostream.hpp"
+#include "utils/convertible_string.hpp"
+
+#include <cstring>
+
+namespace libbsarch {
+constexpr bool enable_debug_log = true;
+[[maybe_unused]] constexpr int max_string_buffer_size = 1024;
+
+inline convertible_ostream &debug_log()
+{
+ static convertible_ostream ostr;
+ if constexpr (enable_debug_log)
+ return ostr << "[libbsarch] " << __FUNCTION__ << ' ';
+}
+
+inline void checkResult(const bsa_result_message_s &result)
+{
+ if (result.code == BSA_RESULT_EXCEPTION)
+ {
+ // Copy from packed struct to aligned local buffer to avoid UB
+ wchar_t aligned_text[1024];
+ std::memcpy(aligned_text, result.text, sizeof(aligned_text));
+ const std::string error = to_string(std::wstring(aligned_text));
+ debug_log() << error;
+ throw std::runtime_error(error);
+ }
+}
+
+inline void checkResult(const bsa_result_message_buffer_s &result)
+{
+ checkResult(result.message);
+}
+} // namespace libbsarch
diff --git a/libs/libbsarch/include/libbsarch/utils/convertible_ostream.hpp b/libs/libbsarch/include/libbsarch/utils/convertible_ostream.hpp
new file mode 100644
index 0000000..80babb0
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/utils/convertible_ostream.hpp
@@ -0,0 +1,37 @@
+/* Copyright (C) 2019 G'k
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+#pragma once
+
+#include "convertible_string.hpp"
+#include <iostream>
+
+namespace libbsarch {
+class convertible_ostream
+{
+public:
+ convertible_ostream &operator<<(const std::string &rh);
+ convertible_ostream &operator<<(const char *rh);
+ convertible_ostream &operator<<(const char rh);
+ convertible_ostream &operator<<(const std::wstring &rh);
+ convertible_ostream &operator<<(const void *rh);
+ convertible_ostream &operator<<(const convertible_string &rh);
+
+ template<typename number, //real type
+ typename = typename std::enable_if<std::is_arithmetic<number>::value, number>::type>
+ convertible_ostream &operator<<(const number &num)
+ {
+ std::cout << num;
+ return *this;
+ }
+
+ operator std::ostream &();
+ operator std::wostream &();
+
+#ifdef LIBBSARCH_QT_SUPPORT
+ operator QDebug();
+ convertible_ostream &operator<<(const QString &rh);
+#endif
+};
+} // namespace libbsarch
diff --git a/libs/libbsarch/include/libbsarch/utils/convertible_string.hpp b/libs/libbsarch/include/libbsarch/utils/convertible_string.hpp
new file mode 100644
index 0000000..e6b996d
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/utils/convertible_string.hpp
@@ -0,0 +1,50 @@
+/* Copyright (C) 2019 G'k
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+#pragma once
+
+//See https://stackoverflow.com/questions/4804298/how-to-convert-wstring-into-string
+
+#ifdef LIBBSARCH_QT_SUPPORT
+#include <QString>
+#endif
+
+#include "string_convert.hpp"
+
+namespace libbsarch {
+
+template<typename String>
+class convertible_string_converter;
+
+class convertible_string
+{
+public:
+ // default ctor
+ convertible_string() = default;
+
+ /* conversion ctors */
+ convertible_string(std::string value, bool to_native_path = true);
+ convertible_string(const char *const val_array, bool to_native_path = true);
+ convertible_string(const std::wstring &wvalue, bool to_native_path = true);
+ convertible_string(const wchar_t *const wval_array, bool to_native_path = true);
+
+ /* assignment operators */
+ convertible_string &operator=(const std::string &value);
+ convertible_string &operator=(const std::wstring &wvalue);
+ convertible_string &operator=(const wchar_t *wvalue);
+
+ /* implicit conversion operators */
+ operator std::string() const;
+ operator std::wstring() const;
+ operator const wchar_t *() const;
+
+ /* Util */
+ bool remove_substring(const convertible_string &sub_str);
+ convertible_string &to_native_path();
+
+private:
+ std::string str_;
+ bool auto_convert_to_native_path = true;
+};
+} // namespace libbsarch
diff --git a/libs/libbsarch/include/libbsarch/utils/string_convert.hpp b/libs/libbsarch/include/libbsarch/utils/string_convert.hpp
new file mode 100644
index 0000000..6086fe1
--- /dev/null
+++ b/libs/libbsarch/include/libbsarch/utils/string_convert.hpp
@@ -0,0 +1,18 @@
+/* Copyright (C) 2019 G'k
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+#pragma once
+
+#ifdef LIBBSARCH_QT_SUPPORT
+#include <QDebug>
+#endif
+
+#include <codecvt>
+#include <locale>
+#include <string>
+
+namespace libbsarch {
+std::string to_string(const std::wstring &str);
+std::wstring to_wstring(const std::string &str);
+} // namespace libbsarch