diff options
Diffstat (limited to 'libs/libbsarch/include')
| -rw-r--r-- | libs/libbsarch/include/libbsarch/base_types.hpp | 66 | ||||
| -rw-r--r-- | libs/libbsarch/include/libbsarch/bs_archive.h | 100 | ||||
| -rw-r--r-- | libs/libbsarch/include/libbsarch/bs_archive_auto.hpp | 39 | ||||
| -rw-r--r-- | libs/libbsarch/include/libbsarch/bs_archive_entries.h | 24 | ||||
| -rw-r--r-- | libs/libbsarch/include/libbsarch/libbsarch.h | 157 | ||||
| -rw-r--r-- | libs/libbsarch/include/libbsarch/libbsarch.hpp | 37 | ||||
| -rw-r--r-- | libs/libbsarch/include/libbsarch/utils/convertible_ostream.hpp | 37 | ||||
| -rw-r--r-- | libs/libbsarch/include/libbsarch/utils/convertible_string.hpp | 50 | ||||
| -rw-r--r-- | libs/libbsarch/include/libbsarch/utils/string_convert.hpp | 18 |
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 |
