From a49108c4d2b596f7e1377e599fd0b240f0916998 Mon Sep 17 00:00:00 2001 From: josh Date: Wed, 4 Jun 2025 16:27:43 -0500 Subject: [PATCH] Implement WindowsFix. TODO: Endianness will be moved to a separate library. --- CMakeLists.txt | 8 +- include/ReArchive/Endianness.h | 139 +++++++++++++++++++++++++++++++ include/ReArchive/types/Header.h | 1 + src/Endianness.cpp | 59 +++++++++++++ src/ReArchive.cpp | 11 ++- src/types/FileEntry.cpp | 7 +- src/types/FileTable.cpp | 3 +- src/types/Header.cpp | 4 +- 8 files changed, 221 insertions(+), 11 deletions(-) create mode 100644 include/ReArchive/Endianness.h create mode 100644 src/Endianness.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c0f546..0fc8fca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,13 @@ set(CMAKE_CXX_STANDARD 20) file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp") file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp") -add_library(ReArchive SHARED ${SOURCES}) +if(UNIX) + add_library(ReArchive SHARED ${SOURCES}) +endif() + +if(WIN32) + add_library(ReArchive STATIC ${SOURCES}) +endif() set_target_properties(ReArchive PROPERTIES LINKER_LANGUAGE CXX) target_include_directories(ReArchive PUBLIC ${PROJECT_SOURCE_DIR}/include) diff --git a/include/ReArchive/Endianness.h b/include/ReArchive/Endianness.h new file mode 100644 index 0000000..30ec303 --- /dev/null +++ b/include/ReArchive/Endianness.h @@ -0,0 +1,139 @@ + +#pragma once +#include +#include +#include +#include +#include + +namespace IntegerLiterals +{ + using u8 = uint8_t; using ub = u8; + using u16 = uint16_t; using us = u16; + using u32 = uint32_t; //using ul = u32; + using u64 = uint64_t; using ud = u64; + + using s8 = int8_t; using sb = s8; + using s16 = int16_t; using ss = s16; + using s32 = int32_t; using sl = s32; + using s64 = int64_t; using sd = s64; + + constexpr inline u8 operator ""_u8(unsigned long long int value) { return value;} + constexpr inline ub operator ""_ub(unsigned long long int value) { return value;} + constexpr inline u16 operator ""_u16(unsigned long long int value) { return value;} + constexpr inline us operator ""_us(unsigned long long int value) { return value;} + constexpr inline u32 operator ""_u32(unsigned long long int value) { return value;} + constexpr inline u32 operator ""_ul(unsigned long long int value) { return value;} + constexpr inline u64 operator ""_u64(unsigned long long int value) { return value;} + constexpr inline u64 operator ""_ud(unsigned long long int value) { return value;} + + constexpr inline s8 operator ""_s8(long double value) { return value;} + constexpr inline s8 operator ""_sb(long double value) { return value;} + constexpr inline s16 operator ""_s16(long double value) { return value;} + constexpr inline s16 operator ""_ss(long double value) { return value;} + constexpr inline s32 operator ""_s32(long double value) { return value;} + constexpr inline s32 operator ""_sl(long double value) { return value;} + constexpr inline s64 operator ""_s64(long double value) { return value;} + constexpr inline s64 operator ""_sd(long double value) { return value;} +} + +using namespace IntegerLiterals; + +/// https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html + + +/// Platform-independent functions for swapping the byte order of common data types. +namespace Endianness +{ + + + // TODO: It seems these can't have their implementation put into + // a separate .cpp file else the compiler throws undefined reference + // is it because they're constexpr? + constexpr bool IsBigEndian() { return (std::endian::native == std::endian::big); } + + constexpr bool IsLittleEndian() { return (std::endian::native == std::endian::little); } + + template + T ReverseByteOrder(T val) + { + T retVal; + char* pVal = (char*)&val; + char* pRetVal = (char*)&retVal; + int size = sizeof(T); + for (int i = 0; i < size; i++) + { + pRetVal[size - 1 - i] = pVal[i]; + } + return retVal; + + //return byteswap(val); + } + + + template + T ReverseByteOrderIfLittleEndian(T val) + { + if (IsLittleEndian()) + return ReverseByteOrder(val); + else return val; + + } + + /// Returns the given values converted into network byte order. + /// Generally on x86, numbers are stored in 'little-endian' order. + /// Network order is 'big-endian'. Supposing a big-endian host machine, + /// no conversion will take place and the original value will be returned. + + + + u16 HostToNetworkOrder(u16 host); + u32 HostToNetworkOrder(u32 host); + u64 HostToNetworkOrder(u64 host); + s16 HostToNetworkOrder(s16 host); + s32 HostToNetworkOrder(s32 host); + s64 HostToNetworkOrder(s64 host); + float HostToNetworkOrder(float host); + double HostToNetworkOrder(double host); + + template T HostToNetworkOrder(T host) { return HostToNetworkOrder(host);} + + template<> inline u16 HostToNetworkOrder(u16 host) { return HostToNetworkOrder(host);} + template<> inline u32 HostToNetworkOrder(u32 host) { return HostToNetworkOrder(host);} + template<> inline u64 HostToNetworkOrder(u64 host) { return HostToNetworkOrder(host);} + template<> inline s16 HostToNetworkOrder(s16 host) { return HostToNetworkOrder(host);} + template<> inline s32 HostToNetworkOrder(s32 host) { return HostToNetworkOrder(host);} + template<> inline s64 HostToNetworkOrder(s64 host) { return HostToNetworkOrder(host);} + template<> inline float HostToNetworkOrder(float host) { return HostToNetworkOrder(host);} + template<> inline double HostToNetworkOrder(double host) { return HostToNetworkOrder(host);} + + /// Returns the given values converted into host-byte order. + /// On x86, this will usually be 'little-endian' + /// On ARM (and other RISC architectures), it is often big-endian. + /// Supposing a big-endian host machine, no conversion will take place and the original value will be returned. + u16 NetworkToHostOrder(u16 network); + u32 NetworkToHostOrder(u32 network); + u64 NetworkToHostOrder(u64 network); + s16 NetworkToHostOrder(s16 network); + s32 NetworkToHostOrder(s32 network); + s64 NetworkToHostOrder(s64 network); + float NetworkToHostOrder(float network); + double NetworkToHostOrder(double network); + + + template T NetworkToHostOrder(T network) { return NetworkToHostOrder(network);} + + template<> inline u16 NetworkToHostOrder(u16 network) { return NetworkToHostOrder(network);} + template<> inline u32 NetworkToHostOrder(u32 network) { return NetworkToHostOrder(network);} + template<> inline u64 NetworkToHostOrder(u64 network) { return NetworkToHostOrder(network);} + template<> inline s16 NetworkToHostOrder(s16 network) { return NetworkToHostOrder(network);} + template<> inline s32 NetworkToHostOrder(s32 network) { return NetworkToHostOrder(network);} + template<> inline s64 NetworkToHostOrder(s64 network) { return NetworkToHostOrder(network);} + template<> inline float NetworkToHostOrder(float network) { return NetworkToHostOrder(network);} + template<> inline double NetworkToHostOrder(double network) { return NetworkToHostOrder(network);} + + + + + +} diff --git a/include/ReArchive/types/Header.h b/include/ReArchive/types/Header.h index 2819d0f..7f25193 100644 --- a/include/ReArchive/types/Header.h +++ b/include/ReArchive/types/Header.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace ReArchive { diff --git a/src/Endianness.cpp b/src/Endianness.cpp new file mode 100644 index 0000000..202c5e8 --- /dev/null +++ b/src/Endianness.cpp @@ -0,0 +1,59 @@ +#ifdef WIN32 +#pragma comment(lib, "Ws2_32.lib") + #define WIN32_LEAN_AND_MEAN + #include + +#endif + +#ifdef __linux__ + #include +#endif + +#include + +namespace Endianness +{ + + // TODO: Manually swap bytes so we can depend less on clunky include directives. + u16 HostToNetworkOrder(u16 host) { return htons(host); } + u16 NetworkToHostOrder(u16 network) { return ntohs(network); } + s16 HostToNetworkOrder(s16 host) { return htons( host); } + s16 NetworkToHostOrder(s16 network) { return ntohs(network);} + u32 HostToNetworkOrder(u32 host) { return htonl(host); } + u32 NetworkToHostOrder(u32 network) { return ntohl(network); } + s32 HostToNetworkOrder(s32 host) { return htonl(host);} + s32 NetworkToHostOrder(s32 network) { return ntohl(network);} + u64 HostToNetworkOrder(u64 host) { return ReverseByteOrderIfLittleEndian(host); } + u64 NetworkToHostOrder(u64 network) { return ReverseByteOrderIfLittleEndian(network); } + s64 HostToNetworkOrder(s64 host) { return ReverseByteOrderIfLittleEndian(host); } + s64 NetworkToHostOrder(s64 network) { return ReverseByteOrderIfLittleEndian(network); } + + + float HostToNetworkOrder(float host) { + if (IsLittleEndian()) + return ReverseByteOrder(host); + else + return host; + } + + float NetworkToHostOrder(float network) { + if (IsLittleEndian()) + return ReverseByteOrder(network); + else + return network; + } + + double HostToNetworkOrder(double host) { + if (IsLittleEndian()) + return ReverseByteOrder(host); + else + return host; + } + + double NetworkToHostOrder(double network) { + if (IsLittleEndian()) + return ReverseByteOrder(network); + else + return network; + } +} \ No newline at end of file diff --git a/src/ReArchive.cpp b/src/ReArchive.cpp index e414975..467bc56 100644 --- a/src/ReArchive.cpp +++ b/src/ReArchive.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using ReArchive::Header; using ReArchive::FileTable; @@ -29,7 +30,9 @@ FileTable GetFileTable(const Header& header, std::ifstream& in) { in.read(reinterpret_cast(buffer.data()), buffer.size()); unsigned char* ptr = buffer.data(); - int64_t file_table_entry_count = be64toh(*reinterpret_cast(ptr)); + Endianness::NetworkToHostOrder(128u); + s64 wtf = *reinterpret_cast(ptr); + int64_t file_table_entry_count = Endianness::NetworkToHostOrder(wtf); ptr += sizeof(int64_t); FileTable result; @@ -37,16 +40,16 @@ FileTable GetFileTable(const Header& header, std::ifstream& in) { // Out of bounds. assert(ptr < (buffer.data() + buffer.size())); - int64_t string_size = be64toh(*reinterpret_cast(ptr)); + int64_t string_size = Endianness::NetworkToHostOrder(*reinterpret_cast(ptr)); //be64toh(*reinterpret_cast(ptr)); ptr += sizeof(int64_t); std::string path(reinterpret_cast(ptr), string_size); ptr += string_size; - int64_t data_size = be64toh(*reinterpret_cast(ptr)); + int64_t data_size = Endianness::NetworkToHostOrder(*reinterpret_cast(ptr)); ptr += sizeof(int64_t); - int64_t data_offset = be64toh(*reinterpret_cast(ptr)); + int64_t data_offset = Endianness::NetworkToHostOrder(*reinterpret_cast(ptr)); ptr += sizeof(int64_t); result.Append({ data_size, data_offset, path }); diff --git a/src/types/FileEntry.cpp b/src/types/FileEntry.cpp index fb848da..da62f34 100644 --- a/src/types/FileEntry.cpp +++ b/src/types/FileEntry.cpp @@ -1,5 +1,6 @@ #include #include +#include using namespace ReArchive; @@ -11,18 +12,18 @@ std::vector FileEntry::Serialize(const FileEntry& file) { std::vector result(sizeof(int64_t) + path_size + 2 * sizeof(int64_t)); unsigned char* ptr = result.data(); - auto network_path_size = htobe64(path_size); + auto network_path_size = Endianness::HostToNetworkOrder(path_size); memcpy(ptr, &network_path_size, sizeof(int64_t)); ptr += sizeof(int64_t); memcpy(ptr, path_string.data(), path_size); ptr += path_size; - auto network_data_size = htobe64(file.data_size); + auto network_data_size = Endianness::HostToNetworkOrder(file.data_size); memcpy(ptr, &network_data_size, sizeof(int64_t)); ptr += sizeof(int64_t); - auto network_data_offset = htobe64(file.data_offset); + auto network_data_offset = Endianness::HostToNetworkOrder(file.data_offset); memcpy(ptr, &network_data_offset, sizeof(int64_t)); return result; } diff --git a/src/types/FileTable.cpp b/src/types/FileTable.cpp index dcb861e..b4603e5 100644 --- a/src/types/FileTable.cpp +++ b/src/types/FileTable.cpp @@ -1,5 +1,6 @@ #include #include +#include using namespace ReArchive; @@ -19,7 +20,7 @@ void FileTable::Remove(const FileEntry& file_entry) { std::vector FileTable::Serialize(const FileTable& file_table) { auto files = file_table.GetEntries(); int64_t count = files->size(); - auto network_count = htobe64(count); + auto network_count = Endianness::HostToNetworkOrder(count); std::vector result(reinterpret_cast(&network_count), reinterpret_cast(&network_count) + sizeof(network_count)); if (files->empty()) diff --git a/src/types/Header.cpp b/src/types/Header.cpp index 2223fd1..e4b5dac 100644 --- a/src/types/Header.cpp +++ b/src/types/Header.cpp @@ -10,7 +10,7 @@ std::vector ReArchive::Header::Serialize(const ReArchive::Header& size_t current_size = result.size(); result.resize(current_size + sizeof(int64_t)); - auto network_file_table_offset = htobe64(header.file_table_offset); + auto network_file_table_offset = Endianness::HostToNetworkOrder(header.file_table_offset);//htobe64(header.file_table_offset); memcpy(result.data() + current_size, &network_file_table_offset, sizeof(int64_t)); return result; @@ -22,5 +22,5 @@ ReArchive::Header ReArchive::Header::DeSerialize(const unsigned char* serialized use_c = serialized_header[ReArchive::magic.size()]; memcpy(&file_table_off, serialized_header + ReArchive::Header::Size() - sizeof(int64_t), sizeof(int64_t)); - return { use_c, (int64_t) be64toh(file_table_off)}; + return { use_c, (int64_t) Endianness::HostToNetworkOrder(file_table_off)};//be64toh(file_table_off)}; }