Implement WindowsFix. TODO: Endianness will be moved to a separate library.
This commit is contained in:
@@ -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)
|
||||
|
139
include/ReArchive/Endianness.h
Normal file
139
include/ReArchive/Endianness.h
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <bit>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
|
||||
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 <typename T>
|
||||
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 <typename T>
|
||||
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 <typename T> T HostToNetworkOrder(T host) { return HostToNetworkOrder(host);}
|
||||
|
||||
template<> inline u16 HostToNetworkOrder<u16>(u16 host) { return HostToNetworkOrder(host);}
|
||||
template<> inline u32 HostToNetworkOrder<u32>(u32 host) { return HostToNetworkOrder(host);}
|
||||
template<> inline u64 HostToNetworkOrder<u64>(u64 host) { return HostToNetworkOrder(host);}
|
||||
template<> inline s16 HostToNetworkOrder<s16>(s16 host) { return HostToNetworkOrder(host);}
|
||||
template<> inline s32 HostToNetworkOrder<s32>(s32 host) { return HostToNetworkOrder(host);}
|
||||
template<> inline s64 HostToNetworkOrder<s64>(s64 host) { return HostToNetworkOrder(host);}
|
||||
template<> inline float HostToNetworkOrder<float>(float host) { return HostToNetworkOrder(host);}
|
||||
template<> inline double HostToNetworkOrder<double>(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 <typename T> T NetworkToHostOrder(T network) { return NetworkToHostOrder(network);}
|
||||
|
||||
template<> inline u16 NetworkToHostOrder<u16>(u16 network) { return NetworkToHostOrder(network);}
|
||||
template<> inline u32 NetworkToHostOrder<u32>(u32 network) { return NetworkToHostOrder(network);}
|
||||
template<> inline u64 NetworkToHostOrder<u64>(u64 network) { return NetworkToHostOrder(network);}
|
||||
template<> inline s16 NetworkToHostOrder<s16>(s16 network) { return NetworkToHostOrder(network);}
|
||||
template<> inline s32 NetworkToHostOrder<s32>(s32 network) { return NetworkToHostOrder(network);}
|
||||
template<> inline s64 NetworkToHostOrder<s64>(s64 network) { return NetworkToHostOrder(network);}
|
||||
template<> inline float NetworkToHostOrder<float>(float network) { return NetworkToHostOrder(network);}
|
||||
template<> inline double NetworkToHostOrder<double>(double network) { return NetworkToHostOrder(network);}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@@ -3,6 +3,7 @@
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <ReArchive/Endianness.h>
|
||||
|
||||
|
||||
namespace ReArchive {
|
||||
|
59
src/Endianness.cpp
Normal file
59
src/Endianness.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifdef WIN32
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <socket.h>
|
||||
#endif
|
||||
|
||||
#include <ReArchive/Endianness.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@
|
||||
#include <ReArchive/types/FileTable.h>
|
||||
#include <ReArchive/types/FileEntry.h>
|
||||
#include <cassert>
|
||||
#include <ReArchive/Endianness.h>
|
||||
|
||||
using ReArchive::Header;
|
||||
using ReArchive::FileTable;
|
||||
@@ -29,7 +30,9 @@ FileTable GetFileTable(const Header& header, std::ifstream& in) {
|
||||
in.read(reinterpret_cast<char *>(buffer.data()), buffer.size());
|
||||
|
||||
unsigned char* ptr = buffer.data();
|
||||
int64_t file_table_entry_count = be64toh(*reinterpret_cast<int64_t*>(ptr));
|
||||
Endianness::NetworkToHostOrder(128u);
|
||||
s64 wtf = *reinterpret_cast<const int64_t*>(ptr);
|
||||
int64_t file_table_entry_count = Endianness::NetworkToHostOrder<s64>(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<const int64_t*>(ptr));
|
||||
int64_t string_size = Endianness::NetworkToHostOrder(*reinterpret_cast<const int64_t*>(ptr)); //be64toh(*reinterpret_cast<const int64_t*>(ptr));
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
std::string path(reinterpret_cast<const char*>(ptr), string_size);
|
||||
ptr += string_size;
|
||||
|
||||
int64_t data_size = be64toh(*reinterpret_cast<const int64_t*>(ptr));
|
||||
int64_t data_size = Endianness::NetworkToHostOrder(*reinterpret_cast<const int64_t*>(ptr));
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
int64_t data_offset = be64toh(*reinterpret_cast<const int64_t*>(ptr));
|
||||
int64_t data_offset = Endianness::NetworkToHostOrder(*reinterpret_cast<const int64_t*>(ptr));
|
||||
ptr += sizeof(int64_t);
|
||||
|
||||
result.Append({ data_size, data_offset, path });
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <ReArchive/types/FileEntry.h>
|
||||
#include <cstring>
|
||||
#include <ReArchive/Endianness.h>
|
||||
|
||||
|
||||
using namespace ReArchive;
|
||||
@@ -11,18 +12,18 @@ std::vector<unsigned char> FileEntry::Serialize(const FileEntry& file) {
|
||||
std::vector<unsigned char> 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;
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <ReArchive/types/FileTable.h>
|
||||
#include <cstring>
|
||||
#include <ReArchive/Endianness.h>
|
||||
|
||||
using namespace ReArchive;
|
||||
|
||||
@@ -19,7 +20,7 @@ void FileTable::Remove(const FileEntry& file_entry) {
|
||||
std::vector<unsigned char> 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<unsigned char> result(reinterpret_cast<unsigned char*>(&network_count), reinterpret_cast<unsigned char*>(&network_count) + sizeof(network_count));
|
||||
|
||||
if (files->empty())
|
||||
|
@@ -10,7 +10,7 @@ std::vector<unsigned char> 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)};
|
||||
}
|
||||
|
Reference in New Issue
Block a user