summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbriaguya <70942617+briaguya-ai@users.noreply.github.com>2024-05-01 22:25:33 -0400
committerGitHub <noreply@github.com>2024-05-01 22:25:33 -0400
commit222cb8a23bd0fa8b901b1654ac5d6cc2ecb25a2e (patch)
tree41d4324876aa3c0c296a83a5a87910220919b0a9
parent9f9d0be3c914354ecabab3695581f1123c13ac20 (diff)
detangle utils (#21)
-rw-r--r--ZAPD/CMakeLists.txt16
-rw-r--r--ZAPD/Utils/BinaryReader.cpp178
-rw-r--r--ZAPD/Utils/BinaryReader.h41
-rw-r--r--ZAPD/Utils/BinaryWriter.cpp148
-rw-r--r--ZAPD/Utils/BinaryWriter.h41
-rw-r--r--ZAPD/Utils/BitConverter.h209
-rw-r--r--ZAPD/Utils/Directory.h60
-rw-r--r--ZAPD/Utils/DiskFile.h91
-rw-r--r--ZAPD/Utils/MemoryStream.cpp97
-rw-r--r--ZAPD/Utils/MemoryStream.h33
-rw-r--r--ZAPD/Utils/Path.h50
-rw-r--r--ZAPD/Utils/Stream.h34
-rw-r--r--ZAPD/Utils/StringHelper.cpp191
-rw-r--r--ZAPD/Utils/StringHelper.h33
-rw-r--r--ZAPD/Utils/vt.h45
15 files changed, 1259 insertions, 8 deletions
diff --git a/ZAPD/CMakeLists.txt b/ZAPD/CMakeLists.txt
index 96c42d0..908a967 100644
--- a/ZAPD/CMakeLists.txt
+++ b/ZAPD/CMakeLists.txt
@@ -230,6 +230,12 @@ set(Source_Files__Z64__ZRoom__Commands
)
source_group("Source Files\\Z64\\ZRoom\\Commands" FILES ${Source_Files__Z64__ZRoom__Commands})
+file(GLOB Source_Files__Utils RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "Utils/*.c" "Utils/*.cpp")
+source_group("Source Files\\Utils" FILES ${Source_Files__Utils})
+
+file(GLOB Header_Files__Utils RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "Utils/*.h")
+source_group("Header Files\\Utils" FILES ${Header_Files__Utils})
+
set(ALL_FILES
${Header_Files}
${Header_Files__Libraries}
@@ -238,6 +244,7 @@ set(ALL_FILES
${Header_Files__Z64}
${Header_Files__Z64__ZRoom}
${Header_Files__Z64__ZRoom__Commands}
+ ${Header_Files__Utils}
${Resource_Files}
${Source_Files}
${Source_Files__Libraries__libgfxd}
@@ -245,6 +252,7 @@ set(ALL_FILES
${Source_Files__Z64}
${Source_Files__Z64__ZRoom}
${Source_Files__Z64__ZRoom__Commands}
+ ${Source_Files__Utils}
${any__any}
)
@@ -335,10 +343,8 @@ endif()
find_package(PNG REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/ZAPDUtils
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/include
- ${CMAKE_CURRENT_SOURCE_DIR}/../../ZAPDTR/lib/tinyxml2
${CMAKE_CURRENT_SOURCE_DIR}/../../ZAPDTR/lib/libgfxd
${PNG_PNG_INCLUDE_DIR}/
.
@@ -434,7 +440,6 @@ endif()
################################################################################
add_dependencies(${PROJECT_NAME}
OTRExporter
- ZAPDUtils
libultraship
)
@@ -442,7 +447,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64")
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
- "ZAPDUtils;"
"-WHOLEARCHIVE:$<TARGET_LINKER_FILE_DIR:OTRExporter>/$<TARGET_LINKER_FILE_NAME:OTRExporter>"
"libultraship;"
storm
@@ -453,7 +457,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
- "ZAPDUtils;"
-Wl,-force_load $<TARGET_LINKER_FILE_DIR:OTRExporter>/$<TARGET_LINKER_FILE_NAME:OTRExporter>
"libultraship;"
PNG::PNG
@@ -464,7 +467,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
- "ZAPDUtils;"
-Wl,--whole-archive $<TARGET_LINKER_FILE_DIR:OTRExporter>/$<TARGET_LINKER_FILE_NAME:OTRExporter> -Wl,--no-whole-archive
"libultraship;"
PNG::PNG
@@ -472,7 +474,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
- "ZAPDUtils;"
"libultraship;"
PNG::PNG
)
@@ -480,7 +481,6 @@ else()
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
- "ZAPDUtils;"
-Wl,--whole-archive $<TARGET_LINKER_FILE_DIR:OTRExporter>/$<TARGET_LINKER_FILE_NAME:OTRExporter> -Wl,--no-whole-archive
"libultraship;"
PNG::PNG
diff --git a/ZAPD/Utils/BinaryReader.cpp b/ZAPD/Utils/BinaryReader.cpp
new file mode 100644
index 0000000..2fdff37
--- /dev/null
+++ b/ZAPD/Utils/BinaryReader.cpp
@@ -0,0 +1,178 @@
+#include "BinaryReader.h"
+#include <cmath>
+#include <stdexcept>
+#include "Stream.h"
+
+BinaryReader::BinaryReader(Stream* nStream)
+{
+ stream.reset(nStream);
+}
+
+BinaryReader::BinaryReader(std::shared_ptr<Stream> nStream)
+{
+ stream = nStream;
+}
+
+void BinaryReader::Close()
+{
+ stream->Close();
+}
+
+void BinaryReader::SetEndianness(Endianness endianness)
+{
+ this->endianness = endianness;
+}
+
+Endianness BinaryReader::GetEndianness() const
+{
+ return endianness;
+}
+
+void BinaryReader::Seek(uint32_t offset, SeekOffsetType seekType)
+{
+ stream->Seek(offset, seekType);
+}
+
+uint32_t BinaryReader::GetBaseAddress()
+{
+ return stream->GetBaseAddress();
+}
+
+void BinaryReader::Read(int32_t length)
+{
+ stream->Read(length);
+}
+
+void BinaryReader::Read(char* buffer, int32_t length)
+{
+ stream->Read(buffer, length);
+}
+
+char BinaryReader::ReadChar()
+{
+ return (char)stream->ReadByte();
+}
+
+int8_t BinaryReader::ReadByte()
+{
+ return stream->ReadByte();
+}
+
+uint8_t BinaryReader::ReadUByte()
+{
+ return (uint8_t)stream->ReadByte();
+}
+
+int16_t BinaryReader::ReadInt16()
+{
+ int16_t result = 0;
+
+ stream->Read((char*)&result, sizeof(int16_t));
+
+ if (endianness != Endianness::Native)
+ result = BSWAP16(result);
+
+ return result;
+}
+
+int32_t BinaryReader::ReadInt32()
+{
+ int32_t result = 0;
+
+ stream->Read((char*)&result, sizeof(int32_t));
+
+ if (endianness != Endianness::Native)
+ result = BSWAP32(result);
+
+ return result;
+}
+
+uint16_t BinaryReader::ReadUInt16()
+{
+ uint16_t result = 0;
+
+ stream->Read((char*)&result, sizeof(uint16_t));
+
+ if (endianness != Endianness::Native)
+ result = BSWAP16(result);
+
+ return result;
+}
+
+uint32_t BinaryReader::ReadUInt32()
+{
+ uint32_t result = 0;
+
+ stream->Read((char*)&result, sizeof(uint32_t));
+
+ if (endianness != Endianness::Native)
+ result = BSWAP32(result);
+
+ return result;
+}
+
+uint64_t BinaryReader::ReadUInt64()
+{
+ uint64_t result = 0;
+
+ stream->Read((char*)&result, sizeof(uint64_t));
+
+ if (endianness != Endianness::Native)
+ result = BSWAP64(result);
+
+ return result;
+}
+
+float BinaryReader::ReadSingle()
+{
+ float result = NAN;
+
+ stream->Read((char*)&result, sizeof(float));
+
+ if (endianness != Endianness::Native)
+ {
+ float tmp;
+ char* dst = (char*)&tmp;
+ char* src = (char*)&result;
+ dst[3] = src[0]; dst[2] = src[1]; dst[1] = src[2]; dst[0] = src[3];
+ result = tmp;
+ }
+
+ if (std::isnan(result))
+ throw std::runtime_error("BinaryReader::ReadSingle(): Error reading stream");
+
+ return result;
+}
+
+double BinaryReader::ReadDouble()
+{
+ double result = NAN;
+
+ stream->Read((char*)&result, sizeof(double));
+
+ if (endianness != Endianness::Native)
+ {
+ double tmp;
+ char* dst = (char*)&tmp;
+ char* src = (char*)&result;
+ dst[7] = src[0]; dst[6] = src[1]; dst[5] = src[2]; dst[4] = src[3];
+ dst[3] = src[4]; dst[2] = src[5]; dst[1] = src[6]; dst[0] = src[7];
+ result = tmp;
+ }
+
+ if (std::isnan(result))
+ throw std::runtime_error("BinaryReader::ReadDouble(): Error reading stream");
+
+ return result;
+}
+
+std::string BinaryReader::ReadString()
+{
+ std::string res;
+ int numChars = ReadInt32();
+
+ for (int i = 0; i < numChars; i++)
+ res += ReadChar();
+
+ return res;
+} \ No newline at end of file
diff --git a/ZAPD/Utils/BinaryReader.h b/ZAPD/Utils/BinaryReader.h
new file mode 100644
index 0000000..f4b37c9
--- /dev/null
+++ b/ZAPD/Utils/BinaryReader.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <array>
+#include <memory>
+#include <string>
+#include <vector>
+#include "BitConverter.h"
+#include "Stream.h"
+
+class BinaryReader
+{
+public:
+ BinaryReader(Stream* nStream);
+ BinaryReader(std::shared_ptr<Stream> nStream);
+
+ void Close();
+
+ void SetEndianness(Endianness endianness);
+ Endianness GetEndianness() const;
+
+ void Seek(uint32_t offset, SeekOffsetType seekType);
+ uint32_t GetBaseAddress();
+
+ void Read(int32_t length);
+ void Read(char* buffer, int32_t length);
+ char ReadChar();
+ int8_t ReadByte();
+ int16_t ReadInt16();
+ int32_t ReadInt32();
+ uint8_t ReadUByte();
+ uint16_t ReadUInt16();
+ uint32_t ReadUInt32();
+ uint64_t ReadUInt64();
+ float ReadSingle();
+ double ReadDouble();
+ std::string ReadString();
+
+protected:
+ std::shared_ptr<Stream> stream;
+ Endianness endianness = Endianness::Native;
+}; \ No newline at end of file
diff --git a/ZAPD/Utils/BinaryWriter.cpp b/ZAPD/Utils/BinaryWriter.cpp
new file mode 100644
index 0000000..34bcad0
--- /dev/null
+++ b/ZAPD/Utils/BinaryWriter.cpp
@@ -0,0 +1,148 @@
+#include "BinaryWriter.h"
+
+BinaryWriter::BinaryWriter(Stream* nStream)
+{
+ stream.reset(nStream);
+}
+
+BinaryWriter::BinaryWriter(std::shared_ptr<Stream> nStream)
+{
+ stream = nStream;
+}
+
+void BinaryWriter::SetEndianness(Endianness endianness)
+{
+ this->endianness = endianness;
+}
+
+void BinaryWriter::Close()
+{
+ stream->Close();
+}
+
+std::shared_ptr<Stream> BinaryWriter::GetStream()
+{
+ return stream;
+}
+
+uint64_t BinaryWriter::GetBaseAddress()
+{
+ return stream->GetBaseAddress();
+}
+
+uint64_t BinaryWriter::GetLength()
+{
+ return stream->GetLength();
+}
+
+void BinaryWriter::Seek(int32_t offset, SeekOffsetType seekType)
+{
+ stream->Seek(offset, seekType);
+}
+
+void BinaryWriter::Write(int8_t value)
+{
+ stream->Write((char*)&value, sizeof(int8_t));
+}
+
+void BinaryWriter::Write(uint8_t value)
+{
+ stream->Write((char*)&value, sizeof(uint8_t));
+}
+
+void BinaryWriter::Write(int16_t value)
+{
+ if (endianness != Endianness::Native)
+ value = BSWAP16(value);
+
+ stream->Write((char*)&value, sizeof(int16_t));
+}
+
+void BinaryWriter::Write(uint16_t value)
+{
+ if (endianness != Endianness::Native)
+ value = BSWAP16(value);
+
+ stream->Write((char*)&value, sizeof(uint16_t));
+}
+
+void BinaryWriter::Write(int32_t value)
+{
+ if (endianness != Endianness::Native)
+ value = BSWAP32(value);
+
+ stream->Write((char*)&value, sizeof(int32_t));
+}
+
+void BinaryWriter::Write(int32_t valueA, int32_t valueB)
+{
+ Write(valueA);
+ Write(valueB);
+}
+
+void BinaryWriter::Write(uint32_t value)
+{
+ if (endianness != Endianness::Native)
+ value = BSWAP32(value);
+
+ stream->Write((char*)&value, sizeof(uint32_t));
+}
+
+void BinaryWriter::Write(int64_t value)
+{
+ if (endianness != Endianness::Native)
+ value = BSWAP64(value);
+
+ stream->Write((char*)&value, sizeof(int64_t));
+}
+
+void BinaryWriter::Write(uint64_t value)
+{
+ if (endianness != Endianness::Native)
+ value = BSWAP64(value);
+
+ stream->Write((char*)&value, sizeof(uint64_t));
+}
+
+void BinaryWriter::Write(float value)
+{
+ if (endianness != Endianness::Native)
+ {
+ float tmp;
+ char* dst = (char*)&tmp;
+ char* src = (char*)&value;
+ dst[3] = src[0]; dst[2] = src[1]; dst[1] = src[2]; dst[0] = src[3];
+ value = tmp;
+ }
+
+ stream->Write((char*)&value, sizeof(float));
+}
+
+void BinaryWriter::Write(double value)
+{
+ if (endianness != Endianness::Native)
+ {
+ double tmp;
+ char* dst = (char*)&tmp;
+ char* src = (char*)&value;
+ dst[7] = src[0]; dst[6] = src[1]; dst[5] = src[2]; dst[4] = src[3];
+ dst[3] = src[4]; dst[2] = src[5]; dst[1] = src[6]; dst[0] = src[7];
+ value = tmp;
+ }
+
+ stream->Write((char*)&value, sizeof(double));
+}
+
+void BinaryWriter::Write(const std::string& str)
+{
+ int strLen = str.size();
+ Write(strLen);
+
+ for (char c : str)
+ stream->WriteByte(c);
+}
+
+void BinaryWriter::Write(char* srcBuffer, size_t length)
+{
+ stream->Write(srcBuffer, length);
+}
diff --git a/ZAPD/Utils/BinaryWriter.h b/ZAPD/Utils/BinaryWriter.h
new file mode 100644
index 0000000..67c8fcd
--- /dev/null
+++ b/ZAPD/Utils/BinaryWriter.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <array>
+#include <memory>
+#include <string>
+#include <vector>
+#include "BitConverter.h"
+#include "Stream.h"
+
+class BinaryWriter
+{
+public:
+ BinaryWriter(Stream* nStream);
+ BinaryWriter(std::shared_ptr<Stream> nStream);
+
+ void SetEndianness(Endianness endianness);
+
+ std::shared_ptr<Stream> GetStream();
+ uint64_t GetBaseAddress();
+ uint64_t GetLength();
+ void Seek(int32_t offset, SeekOffsetType seekType);
+ void Close();
+
+ void Write(int8_t value);
+ void Write(uint8_t value);
+ void Write(int16_t value);
+ void Write(uint16_t value);
+ void Write(int32_t value);
+ void Write(int32_t valueA, int32_t valueB);
+ void Write(uint32_t value);
+ void Write(int64_t value);
+ void Write(uint64_t value);
+ void Write(float value);
+ void Write(double value);
+ void Write(const std::string& str);
+ void Write(char* srcBuffer, size_t length);
+
+protected:
+ std::shared_ptr<Stream> stream;
+ Endianness endianness = Endianness::Native;
+}; \ No newline at end of file
diff --git a/ZAPD/Utils/BitConverter.h b/ZAPD/Utils/BitConverter.h
new file mode 100644
index 0000000..c90b3df
--- /dev/null
+++ b/ZAPD/Utils/BitConverter.h
@@ -0,0 +1,209 @@
+#pragma once
+
+#include <cstdint>
+#include <limits>
+#include <vector>
+#include <cstring>
+
+#ifdef _MSC_VER
+#define BSWAP16 _byteswap_ushort
+#define BSWAP32 _byteswap_ulong
+#define BSWAP64 _byteswap_uint64
+#else
+#define BSWAP16 __builtin_bswap16
+#define BSWAP32 __builtin_bswap32
+#define BSWAP64 __builtin_bswap64
+#endif
+
+enum class Endianness
+{
+ Little = 0,
+ Big = 1,
+
+#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || defined(__BIG_ENDIAN__)
+ Native = Big,
+#else
+ Native = Little,
+#endif
+};
+
+class BitConverter
+{
+public:
+ static inline int8_t ToInt8BE(const uint8_t* data, int32_t offset)
+ {
+ return (uint8_t)data[offset + 0];
+ }
+
+ static inline int8_t ToInt8BE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ return (uint8_t)data[offset + 0];
+ }
+
+ static inline uint8_t ToUInt8BE(const uint8_t* data, int32_t offset)
+ {
+ return (uint8_t)data[offset + 0];
+ }
+
+ static inline uint8_t ToUInt8BE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ return (uint8_t)data[offset + 0];
+ }
+
+ static inline int16_t ToInt16BE(const uint8_t* data, int32_t offset)
+ {
+ return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
+ }
+
+ static inline int16_t ToInt16BE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
+ }
+
+ static inline uint16_t ToUInt16BE(const uint8_t* data, int32_t offset)
+ {
+ return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
+ }
+
+ static inline uint16_t ToUInt16BE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1];
+ }
+
+ static inline int32_t ToInt32BE(const uint8_t* data, int32_t offset)
+ {
+ return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
+ ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
+ }
+
+ static inline int32_t ToInt32BE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
+ ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
+ }
+
+ static inline uint32_t ToUInt32BE(const uint8_t* data, int32_t offset)
+ {
+ return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
+ ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
+ }
+
+ static inline uint32_t ToUInt32BE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) +
+ ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
+ }
+
+ static inline int64_t ToInt64BE(const uint8_t* data, int32_t offset)
+ {
+ return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
+ ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
+ ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
+ ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
+ }
+
+ static inline int64_t ToInt64BE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
+ ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
+ ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
+ ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
+ }
+
+ static inline uint64_t ToUInt64BE(const uint8_t* data, int32_t offset)
+ {
+ return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
+ ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
+ ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
+ ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
+ }
+
+ static inline uint64_t ToUInt64BE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
+ ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
+ ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
+ ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
+ }
+
+ static inline float ToFloatBE(const uint8_t* data, int32_t offset)
+ {
+ float value;
+ uint32_t floatData = ((uint32_t)data[offset + 0] << 24) +
+ ((uint32_t)data[offset + 1] << 16) +
+ ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
+ static_assert(sizeof(uint32_t) == sizeof(float), "expected 32-bit float");
+ std::memcpy(&value, &floatData, sizeof(value));
+ return value;
+ }
+
+ static inline float ToFloatBE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ float value;
+ uint32_t floatData = ((uint32_t)data[offset + 0] << 24) +
+ ((uint32_t)data[offset + 1] << 16) +
+ ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3];
+ static_assert(sizeof(uint32_t) == sizeof(float), "expected 32-bit float");
+ std::memcpy(&value, &floatData, sizeof(value));
+ return value;
+ }
+
+ static inline double ToDoubleBE(const uint8_t* data, int32_t offset)
+ {
+ double value;
+ uint64_t floatData =
+ ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
+ ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
+ ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
+ ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
+ static_assert(sizeof(uint64_t) == sizeof(double), "expected 64-bit double");
+ // Checks if the float format on the platform the ZAPD binary is running on supports the
+ // same float format as the object file.
+ static_assert(std::numeric_limits<float>::is_iec559,
+ "expected IEC559 floats on host machine");
+ std::memcpy(&value, &floatData, sizeof(value));
+ return value;
+ }
+
+ static inline double ToDoubleBE(const std::vector<uint8_t>& data, int32_t offset)
+ {
+ double value;
+ uint64_t floatData =
+ ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) +
+ ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) +
+ ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) +
+ ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]);
+ static_assert(sizeof(uint64_t) == sizeof(double), "expected 64-bit double");
+ // Checks if the float format on the platform the ZAPD binary is running on supports the
+ // same float format as the object file.
+ static_assert(std::numeric_limits<double>::is_iec559,
+ "expected IEC559 doubles on host machine");
+ std::memcpy(&value, &floatData, sizeof(value));
+ return value;
+ }
+
+ // Rewrites the rom data in-place to be in BigEndian/z64 format
+ static inline void RomToBigEndian(uint8_t* rom, size_t romSize) {
+ if (romSize <= 0) {
+ return;
+ }
+
+ // Use the first byte to determine byte order
+ uint8_t firstByte = rom[0];
+
+ switch (firstByte) {
+ case 0x37: // v64
+ for (size_t pos = 0; pos < (romSize / 2); pos++) {
+ ((uint16_t*)rom)[pos] = ToUInt16BE(rom, pos * 2);
+ }
+ break;
+ case 0x40: // n64
+ for (size_t pos = 0; pos < (romSize / 4); pos++) {
+ ((uint32_t*)rom)[pos] = ToUInt32BE(rom, pos * 4);
+ }
+ break;
+ case 0x80: // z64
+ break; // Already BE, no need to swap
+ }
+ }
+};
diff --git a/ZAPD/Utils/Directory.h b/ZAPD/Utils/Directory.h
new file mode 100644
index 0000000..ea792d8
--- /dev/null
+++ b/ZAPD/Utils/Directory.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include "StringHelper.h"
+#include <iostream>
+
+#if __has_include(<filesystem>)
+#include <filesystem>
+namespace fs = std::filesystem;
+#else
+#include <experimental/filesystem>
+namespace fs = std::experimental::filesystem;
+#endif
+
+#undef GetCurrentDirectory
+#undef CreateDirectory
+
+class Directory
+{
+public:
+ #ifndef PATH_HACK
+ static std::string GetCurrentDirectory() { return fs::current_path().string(); }
+ #endif
+
+ static bool Exists(const fs::path& path) { return fs::exists(path); }
+
+ // Stupid hack because of Windows.h
+ static void MakeDirectory(const std::string& path)
+ {
+ CreateDirectory(path);
+ }
+
+ static void CreateDirectory(const std::string& path)
+ {
+ try
+ {
+ fs::create_directories(path);
+ }
+ catch (...)
+ {
+ }
+ }
+
+ static std::vector<std::string> ListFiles(const std::string& dir)
+ {
+ std::vector<std::string> lst;
+
+ if (Exists(dir))
+ {
+ for (auto& p : fs::recursive_directory_iterator(dir))
+ {
+ if (!p.is_directory())
+ lst.push_back(p.path().generic_string());
+ }
+ }
+
+ return lst;
+ }
+};
diff --git a/ZAPD/Utils/DiskFile.h b/ZAPD/Utils/DiskFile.h
new file mode 100644
index 0000000..d3ec03c
--- /dev/null
+++ b/ZAPD/Utils/DiskFile.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include "Path.h"
+#include "Utils/StringHelper.h"
+#include "Utils/Directory.h"
+
+
+class DiskFile
+{
+public:
+ static bool Exists(const fs::path& filePath)
+ {
+ std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
+ return file.good();
+ }
+
+ static std::vector<uint8_t> ReadAllBytes(const fs::path& filePath)
+ {
+ std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
+
+ if (!file)
+ return std::vector<uint8_t>();
+
+ int32_t fileSize = (int32_t)file.tellg();
+ file.seekg(0);
+ char* data = new char[fileSize];
+ file.read(data, fileSize);
+ std::vector<uint8_t> result = std::vector<uint8_t>(data, data + fileSize);
+ delete[] data;
+
+ return result;
+ };
+
+ static std::string ReadAllText(const fs::path& filePath)
+ {
+ std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
+ int32_t fileSize = (int32_t)file.tellg();
+ file.seekg(0);
+ char* data = new char[fileSize + 1];
+ memset(data, 0, fileSize + 1);
+ file.read(data, fileSize);
+ std::string str = std::string((const char*)data);
+ delete[] data;
+
+ return str;
+ };
+
+ static std::vector<std::string> ReadAllLines(const fs::path& filePath)
+ {
+ std::string text = ReadAllText(filePath);
+ std::vector<std::string> lines = StringHelper::Split(text, "\n");
+
+ return lines;
+ };
+
+ static void WriteAllBytes(const fs::path& filePath, const std::vector<uint8_t>& data)
+ {
+ std::ofstream file(filePath, std::ios::binary);
+ file.write((char*)data.data(), data.size());
+ };
+
+ static void WriteAllBytes(const std::string& filePath, const std::vector<char>& data)
+ {
+ if (!Directory::Exists(Path::GetDirectoryName(filePath))) {
+ Directory::MakeDirectory(Path::GetDirectoryName(filePath).string());
+ }
+
+ std::ofstream file(filePath, std::ios::binary);
+ file.write((char*)data.data(), data.size());
+ };
+
+ static void WriteAllBytes(const std::string& filePath, const char* data, int dataSize)
+ {
+ std::ofstream file(filePath, std::ios::binary);
+ file.write((char*)data, dataSize);
+ };
+
+ static void WriteAllText(const fs::path& filePath, const std::string& text)
+ {
+ if (!Directory::Exists(Path::GetDirectoryName(filePath))) {
+ Directory::MakeDirectory(Path::GetDirectoryName(filePath).string());
+ }
+ std::ofstream file(filePath, std::ios::out);
+ file.write(text.c_str(), text.size());
+ }
+};
diff --git a/ZAPD/Utils/MemoryStream.cpp b/ZAPD/Utils/MemoryStream.cpp
new file mode 100644
index 0000000..1c70c00
--- /dev/null
+++ b/ZAPD/Utils/MemoryStream.cpp
@@ -0,0 +1,97 @@
+#include "MemoryStream.h"
+#include <cstring>
+
+#ifndef _MSC_VER
+#define memcpy_s(dest, destSize, source, sourceSize) memcpy(dest, source, destSize)
+#endif
+
+MemoryStream::MemoryStream()
+{
+ buffer = std::vector<char>();
+ //buffer.reserve(1024 * 16);
+ bufferSize = 0;
+ baseAddress = 0;
+}
+
+MemoryStream::MemoryStream(char* nBuffer, size_t nBufferSize) : MemoryStream()
+{
+ buffer = std::vector<char>(nBuffer, nBuffer + nBufferSize);
+ bufferSize = nBufferSize;
+ baseAddress = 0;
+}
+
+MemoryStream::~MemoryStream()
+{
+}
+
+uint64_t MemoryStream::GetLength()
+{
+ return buffer.size();
+}
+
+void MemoryStream::Seek(int32_t offset, SeekOffsetType seekType)
+{
+ if (seekType == SeekOffsetType::Start)
+ baseAddress = offset;
+ else if (seekType == SeekOffsetType::Current)
+ baseAddress += offset;
+ else if (seekType == SeekOffsetType::End)
+ baseAddress = bufferSize - 1 - offset;
+}
+
+std::unique_ptr<char[]> MemoryStream::Read(size_t length)
+{
+ std::unique_ptr<char[]> result = std::make_unique<char[]>(length);
+
+ memcpy_s(result.get(), length, &buffer[baseAddress], length);
+ baseAddress += length;
+
+ return result;
+}
+
+void MemoryStream::Read(const char* dest, size_t length)
+{
+ memcpy_s((void*)dest, length, &buffer[baseAddress], length);
+ baseAddress += length;
+}
+
+int8_t MemoryStream::ReadByte()
+{
+ return buffer[baseAddress++];
+}
+
+void MemoryStream::Write(char* srcBuffer, size_t length)
+{
+ if (baseAddress + length >= buffer.size())
+ {
+ buffer.resize(baseAddress + length);
+ bufferSize += length;
+ }
+
+ memcpy_s(&buffer[baseAddress], length, srcBuffer, length);
+ baseAddress += length;
+}
+
+void MemoryStream::WriteByte(int8_t value)
+{
+ if (baseAddress >= buffer.size())
+ {
+ buffer.resize(baseAddress + 1);
+ bufferSize = baseAddress;
+ }
+
+ buffer[baseAddress++] = value;
+}
+
+std::vector<char> MemoryStream::ToVector()
+{
+ return buffer;
+}
+
+void MemoryStream::Flush()
+{
+}
+
+void MemoryStream::Close()
+{
+} \ No newline at end of file
diff --git a/ZAPD/Utils/MemoryStream.h b/ZAPD/Utils/MemoryStream.h
new file mode 100644
index 0000000..5a17bb0
--- /dev/null
+++ b/ZAPD/Utils/MemoryStream.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+#include "Stream.h"
+
+class MemoryStream : public Stream
+{
+public:
+ MemoryStream();
+ MemoryStream(char* nBuffer, size_t nBufferSize);
+ ~MemoryStream();
+
+ uint64_t GetLength() override;
+
+ void Seek(int32_t offset, SeekOffsetType seekType) override;
+
+ std::unique_ptr<char[]> Read(size_t length) override;
+ void Read(const char* dest, size_t length) override;
+ int8_t ReadByte() override;
+
+ void Write(char* srcBuffer, size_t length) override;
+ void WriteByte(int8_t value) override;
+
+ std::vector<char> ToVector();
+
+ void Flush() override;
+ void Close() override;
+
+protected:
+ std::vector<char> buffer;
+ std::size_t bufferSize;
+}; \ No newline at end of file
diff --git a/ZAPD/Utils/Path.h b/ZAPD/Utils/Path.h
new file mode 100644
index 0000000..0f7ef27
--- /dev/null
+++ b/ZAPD/Utils/Path.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <iostream>
+#include <string>
+#include "Utils/StringHelper.h"
+
+#if __has_include(<filesystem>)
+#include <filesystem>
+namespace fs = std::filesystem;
+#else
+#include <experimental/filesystem>
+namespace fs = std::experimental::filesystem;
+#endif
+
+class Path
+{
+public:
+ static std::string GetFileName(const fs::path& input)
+ {
+ // https://en.cppreference.com/w/cpp/filesystem/path/filename
+ return input.filename().string();
+ };
+
+ static std::string GetFileNameWithoutExtension(const fs::path& input)
+ {
+ // https://en.cppreference.com/w/cpp/filesystem/path/stem
+ return input.stem().string();
+ };
+
+ static std::string GetFileNameExtension(const std::string& input)
+ {
+ return input.substr(input.find_last_of("."), input.length());
+ };
+
+ static fs::path GetPath(const std::string& input)
+ {
+ std::vector<std::string> split = StringHelper::Split(input, "/");
+ fs::path output;
+
+ for (std::string str : split)
+ {
+ if (str.find_last_of(".") == std::string::npos)
+ output /= str;
+ }
+
+ return output;
+ };
+
+ static fs::path GetDirectoryName(const fs::path& path) { return path.parent_path(); };
+};
diff --git a/ZAPD/Utils/Stream.h b/ZAPD/Utils/Stream.h
new file mode 100644
index 0000000..e72d794
--- /dev/null
+++ b/ZAPD/Utils/Stream.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <cstdint>
+#include <memory>
+
+enum class SeekOffsetType
+{
+ Start,
+ Current,
+ End
+};
+
+class Stream
+{
+public:
+ virtual ~Stream() = default;
+ virtual uint64_t GetLength() = 0;
+ uint64_t GetBaseAddress() { return baseAddress; }
+
+ virtual void Seek(int32_t offset, SeekOffsetType seekType) = 0;
+
+ virtual std::unique_ptr<char[]> Read(size_t length) = 0;
+ virtual void Read(const char* dest, size_t length) = 0;
+ virtual int8_t ReadByte() = 0;
+
+ virtual void Write(char* destBuffer, size_t length) = 0;
+ virtual void WriteByte(int8_t value) = 0;
+
+ virtual void Flush() = 0;
+ virtual void Close() = 0;
+
+protected:
+ uint64_t baseAddress;
+}; \ No newline at end of file
diff --git a/ZAPD/Utils/StringHelper.cpp b/ZAPD/Utils/StringHelper.cpp
new file mode 100644
index 0000000..c55580e
--- /dev/null
+++ b/ZAPD/Utils/StringHelper.cpp
@@ -0,0 +1,191 @@
+#include "StringHelper.h"
+
+#if (_MSC_VER)
+#pragma optimize("2", on)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#ifndef _MSC_VER
+#define vsprintf_s vsprintf
+#endif
+
+std::vector<std::string> StringHelper::Split(std::string s, const std::string& delimiter)
+{
+ size_t pos_start = 0, pos_end, delim_len = delimiter.length();
+ std::string token;
+ std::vector<std::string> res;
+
+ while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
+ token = s.substr(pos_start, pos_end - pos_start);
+ pos_start = pos_end + delim_len;
+ res.push_back(token);
+ }
+
+ res.push_back(s.substr(pos_start));
+ return res;
+}
+
+std::vector<std::string_view> StringHelper::Split(std::string_view s, const std::string& delimiter)
+{
+ size_t pos_start = 0, pos_end, delim_len = delimiter.length();
+ std::string_view token;
+ std::vector<std::string_view> res;
+
+ while ((pos_end = s.find(delimiter, pos_start)) != std::string_view::npos)
+ {
+ token = s.substr(pos_start, pos_end - pos_start);
+ pos_start = pos_end + delim_len;
+ res.push_back(token);
+ }
+
+ res.push_back(s.substr(pos_start));
+ return res;
+}
+
+std::string StringHelper::Strip(std::string s, const std::string& delimiter)
+{
+ size_t pos = 0;
+ std::string token;
+
+ while ((pos = s.find(delimiter)) != std::string::npos)
+ {
+ token = s.substr(0, pos);
+ s.erase(pos, pos + delimiter.length());
+ }
+
+ return s;
+}
+
+std::string StringHelper::Replace(std::string str, const std::string& from,
+ const std::string& to)
+{
+ size_t start_pos = str.find(from);
+
+ while (start_pos != std::string::npos)
+ {
+ str.replace(start_pos, from.length(), to);
+ start_pos = str.find(from);
+ }
+
+ return str;
+}
+
+void StringHelper::ReplaceOriginal(std::string& str, const std::string& from, const std::string& to)
+{
+ size_t start_pos = str.find(from);
+
+ while (start_pos != std::string::npos)
+ {
+ str.replace(start_pos, from.length(), to);
+ start_pos = str.find(from);
+ }
+}
+
+bool StringHelper::StartsWith(const std::string& s, const std::string& input)
+{
+#if __cplusplus >= 202002L
+ return s.starts_with(input.c_str());
+#else
+ return s.rfind(input, 0) == 0;
+#endif
+}
+
+bool StringHelper::Contains(const std::string& s, const std::string& input)
+{
+ return s.find(input) != std::string::npos;
+}
+
+bool StringHelper::EndsWith(const std::string& s, const std::string& input)
+{
+ size_t inputLen = strlen(input.c_str());
+ return s.rfind(input) == (s.size() - inputLen);
+}
+
+std::string StringHelper::Sprintf(const char* format, ...)
+{
+ char buffer[32768];
+ // char buffer[2048];
+ std::string output;
+ va_list va;
+
+ va_start(va, format);
+ vsprintf_s(buffer, format, va);
+ va_end(va);
+
+ output = buffer;
+ return output;
+}
+
+std::string StringHelper::Implode(std::vector<std::string>& elements,
+ const char* const separator)
+{
+ return "";
+
+ // return std::accumulate(std::begin(elements), std::end(elements), std::string(),
+ //[separator](std::string& ss, std::string& s) {
+ // return ss.empty() ? s : ss + separator + s;
+ //});
+}
+
+int64_t StringHelper::StrToL(const std::string& str, int32_t base)
+{
+ return std::strtoull(str.c_str(), nullptr, base);
+}
+
+std::string StringHelper::BoolStr(bool b)
+{
+ return b ? "true" : "false";
+}
+
+bool StringHelper::HasOnlyDigits(const std::string& str)
+{
+ return std::all_of(str.begin(), str.end(), ::isdigit);
+}
+
+// Validate a hex string based on the c89 standard
+// https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Integer-Constants
+bool StringHelper::IsValidHex(std::string_view str)
+{
+ if (str.length() < 3)
+ {
+ return false;
+ }
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+ {
+ return std::all_of(str.begin() + 2, str.end(), ::isxdigit);
+ }
+ return false;
+}
+
+
+bool StringHelper::IsValidHex(const std::string& str)
+{
+ return IsValidHex(std::string_view(str.c_str()));
+}
+
+bool StringHelper::IsValidOffset(std::string_view str)
+{
+ if (str.length() == 1)
+ {
+ // 0 is a valid offset
+ return isdigit(str[0]);
+ }
+ return IsValidHex(str);
+}
+
+bool StringHelper::IsValidOffset(const std::string& str)
+{
+ if (str.length() == 1)
+ {
+ // 0 is a valid offset
+ return isdigit(str[0]);
+ }
+ return IsValidHex(str);
+}
+
+
+bool StringHelper::IEquals(const std::string& a, const std::string& b)
+{
+ return std::equal(a.begin(), a.end(), b.begin(), b.end(),
+ [](char a, char b) { return tolower(a) == tolower(b); });
+}
diff --git a/ZAPD/Utils/StringHelper.h b/ZAPD/Utils/StringHelper.h
new file mode 100644
index 0000000..0fc58d3
--- /dev/null
+++ b/ZAPD/Utils/StringHelper.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <algorithm>
+#include <cstdarg>
+#include <cstring>
+#include <numeric>
+#include <string>
+#include <string_view>
+#include <vector>
+#include <cstdint>
+
+class StringHelper
+{
+public:
+ static std::vector<std::string> Split(std::string s, const std::string& delimiter);
+ static std::vector<std::string_view> Split(std::string_view s, const std::string& delimiter);
+ static std::string Strip(std::string s, const std::string& delimiter);
+ static std::string Replace(std::string str, const std::string& from, const std::string& to);
+ static void ReplaceOriginal(std::string& str, const std::string& from, const std::string& to);
+ static bool StartsWith(const std::string& s, const std::string& input);
+ static bool Contains(const std::string& s, const std::string& input);
+ static bool EndsWith(const std::string& s, const std::string& input);
+ static std::string Sprintf(const char* format, ...);
+ static std::string Implode(std::vector<std::string>& elements, const char* const separator);
+ static int64_t StrToL(const std::string& str, int32_t base = 10);
+ static std::string BoolStr(bool b);
+ static bool HasOnlyDigits(const std::string& str);
+ static bool IsValidHex(std::string_view str);
+ static bool IsValidHex(const std::string& str);
+ static bool IsValidOffset(std::string_view str);
+ static bool IsValidOffset(const std::string& str);
+ static bool IEquals(const std::string& a, const std::string& b);
+}; \ No newline at end of file
diff --git a/ZAPD/Utils/vt.h b/ZAPD/Utils/vt.h
new file mode 100644
index 0000000..23f4244
--- /dev/null
+++ b/ZAPD/Utils/vt.h
@@ -0,0 +1,45 @@
+#ifndef VT_H
+#define VT_H
+
+// clang-format off
+#define VT_COLOR_BLACK 0
+#define VT_COLOR_RED 1
+#define VT_COLOR_GREEN 2
+#define VT_COLOR_YELLOW 3
+#define VT_COLOR_BLUE 4
+#define VT_COLOR_PURPLE 5
+#define VT_COLOR_CYAN 6
+#define VT_COLOR_WHITE 7
+#define VT_COLOR_LIGHTGRAY 8
+#define VT_COLOR_DARKGRAY 9
+
+#define VT_COLOR_FOREGROUND 3
+#define VT_COLOR_BACKGROUND 4
+// clang-format on
+
+#define VT_COLOR_EXPAND0(type, color) #type #color
+#define VT_COLOR_EXPAND1(type, color) VT_COLOR_EXPAND0(type, color)
+#define VT_COLOR(type, color) VT_COLOR_EXPAND1(VT_COLOR_##type, VT_COLOR_##color)
+
+#define VT_ESC "\x1b"
+#define VT_CSI "["
+#define VT_CUP(x, y) VT_ESC VT_CSI y ";" x "H"
+#define VT_ED(n) VT_ESC VT_CSI #n "J"
+#define VT_SGR(n) VT_ESC VT_CSI n "m"
+
+// Add more macros if necessary
+#define VT_COL(back, fore) VT_SGR(VT_COLOR(BACKGROUND, back) ";" VT_COLOR(FOREGROUND, fore))
+#define VT_FGCOL(color) VT_SGR(VT_COLOR(FOREGROUND, color))
+#define VT_BGCOL(color) VT_SGR(VT_COLOR(BACKGROUND, color))
+
+// Bold
+#define VT_BOLD "1"
+
+// Bold color support
+#define VT_BOLD_FGCOL(color) VT_SGR(VT_BOLD ";" VT_COLOR(FOREGROUND, color))
+#define VT_BOLD_BGCOL(color) VT_SGR(VT_BOLD ";" VT_COLOR(BACKGROUND, color))
+
+#define VT_RST VT_SGR("")
+#define VT_CLS VT_ED(2)
+
+#endif