diff --git a/ZAPD/CMakeLists.txt b/ZAPD/CMakeLists.txt index f570243..26e0ea0 100644 --- a/ZAPD/CMakeLists.txt +++ b/ZAPD/CMakeLists.txt @@ -242,6 +242,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} @@ -250,6 +256,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} @@ -257,6 +264,7 @@ set(ALL_FILES ${Source_Files__Z64} ${Source_Files__Z64__ZRoom} ${Source_Files__Z64__ZRoom__Commands} + ${Source_Files__Utils} ${any__any} ) @@ -347,10 +355,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}/ . @@ -446,7 +452,6 @@ endif() ################################################################################ add_dependencies(${PROJECT_NAME} OTRExporter - ZAPDUtils libultraship ) @@ -454,7 +459,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:$/$" "libultraship;" storm @@ -465,7 +469,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 $/$ "libultraship;" PNG::PNG @@ -476,7 +479,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 $/$ -Wl,--no-whole-archive "libultraship;" PNG::PNG @@ -484,7 +486,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch") ) elseif(CMAKE_SYSTEM_NAME STREQUAL "CafeOS") set(ADDITIONAL_LIBRARY_DEPENDENCIES - "ZAPDUtils;" "libultraship;" PNG::PNG ) @@ -492,7 +493,6 @@ else() set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) set(ADDITIONAL_LIBRARY_DEPENDENCIES - "ZAPDUtils;" -Wl,--whole-archive $/$ -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 +#include +#include "Stream.h" + +BinaryReader::BinaryReader(Stream* nStream) +{ + stream.reset(nStream); +} + +BinaryReader::BinaryReader(std::shared_ptr 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 +#include +#include +#include +#include "BitConverter.h" +#include "Stream.h" + +class BinaryReader +{ +public: + BinaryReader(Stream* nStream); + BinaryReader(std::shared_ptr 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; + 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 nStream) +{ + stream = nStream; +} + +void BinaryWriter::SetEndianness(Endianness endianness) +{ + this->endianness = endianness; +} + +void BinaryWriter::Close() +{ + stream->Close(); +} + +std::shared_ptr 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 +#include +#include +#include +#include "BitConverter.h" +#include "Stream.h" + +class BinaryWriter +{ +public: + BinaryWriter(Stream* nStream); + BinaryWriter(std::shared_ptr nStream); + + void SetEndianness(Endianness endianness); + + std::shared_ptr 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; + 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 +#include +#include +#include + +#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& 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& 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& 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& 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& 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& 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& 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& 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& 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::is_iec559, + "expected IEC559 floats on host machine"); + std::memcpy(&value, &floatData, sizeof(value)); + return value; + } + + static inline double ToDoubleBE(const std::vector& 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::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 +#include +#include "StringHelper.h" +#include + +#if __has_include() +#include +namespace fs = std::filesystem; +#else +#include +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 ListFiles(const std::string& dir) + { + std::vector 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 +#include +#include +#include +#include +#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 ReadAllBytes(const fs::path& filePath) + { + std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate); + + if (!file) + return std::vector(); + + int32_t fileSize = (int32_t)file.tellg(); + file.seekg(0); + char* data = new char[fileSize]; + file.read(data, fileSize); + std::vector result = std::vector(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 ReadAllLines(const fs::path& filePath) + { + std::string text = ReadAllText(filePath); + std::vector lines = StringHelper::Split(text, "\n"); + + return lines; + }; + + static void WriteAllBytes(const fs::path& filePath, const std::vector& 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& 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 + +#ifndef _MSC_VER +#define memcpy_s(dest, destSize, source, sourceSize) memcpy(dest, source, destSize) +#endif + +MemoryStream::MemoryStream() +{ + buffer = std::vector(); + //buffer.reserve(1024 * 16); + bufferSize = 0; + baseAddress = 0; +} + +MemoryStream::MemoryStream(char* nBuffer, size_t nBufferSize) : MemoryStream() +{ + buffer = std::vector(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 MemoryStream::Read(size_t length) +{ + std::unique_ptr result = std::make_unique(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 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 +#include +#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 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 ToVector(); + + void Flush() override; + void Close() override; + +protected: + std::vector 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 +#include +#include "Utils/StringHelper.h" + +#if __has_include() +#include +namespace fs = std::filesystem; +#else +#include +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 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 +#include + +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 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 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 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 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 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& 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 +#include +#include +#include +#include +#include +#include +#include + +class StringHelper +{ +public: + static std::vector Split(std::string s, const std::string& delimiter); + static std::vector 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& 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