summaryrefslogtreecommitdiff
path: root/ZAPD/Utils
diff options
context:
space:
mode:
authorNicholas Estelami <NEstelami@users.noreply.github.com>2021-08-05 05:11:24 -0400
committerGitHub <noreply@github.com>2021-08-05 05:11:24 -0400
commit82bd27604a4c8f8c1f01f9c2f54c87fab103c39f (patch)
tree282b189bd2d6113bf134a8b34d7ddc518369f3bb /ZAPD/Utils
parent469285b3e1f7885b42905fbfb9b4448f51ea20b3 (diff)
Exporter Support Added (#127)
* Initial exporter implementation * Updated to use static library. * minor cleanup * Cleaned things up a bit * Fixed merge issues * Minor commenting * Added Begin and End functions, and removed HL stuff (to be turned into an exporter at a later date) * Cleaned some stuff up * Additional cleanup * Removed some commented out code * Fixed compilation issues * Cleanup * Fixed merge issues * Got rid of unused windows.h includes * Cleanup * Fixed warning * Removed additional redundancies * Cleanup * Fixed merge issues * Fixed some compiler issues, added makefile for exportertest. * Removed redundancies and clang formatted * Made sure exportertest compiles with C++17 * Moved certain files into new "Utils" folder. * GetExporterMap uses a reference now * Minor fixes and updates. Co-authored-by: Jack Walker <7463599+Jack-Walker@users.noreply.github.com>
Diffstat (limited to 'ZAPD/Utils')
-rw-r--r--ZAPD/Utils/BinaryWriter.cpp95
-rw-r--r--ZAPD/Utils/BinaryWriter.h35
-rw-r--r--ZAPD/Utils/BitConverter.h161
-rw-r--r--ZAPD/Utils/Directory.h39
-rw-r--r--ZAPD/Utils/File.h78
-rw-r--r--ZAPD/Utils/MemoryStream.cpp90
-rw-r--r--ZAPD/Utils/MemoryStream.h32
-rw-r--r--ZAPD/Utils/Path.h53
-rw-r--r--ZAPD/Utils/Stream.h32
-rw-r--r--ZAPD/Utils/StringHelper.h116
10 files changed, 731 insertions, 0 deletions
diff --git a/ZAPD/Utils/BinaryWriter.cpp b/ZAPD/Utils/BinaryWriter.cpp
new file mode 100644
index 0000000..a48d40d
--- /dev/null
+++ b/ZAPD/Utils/BinaryWriter.cpp
@@ -0,0 +1,95 @@
+#include "BinaryWriter.h"
+
+BinaryWriter::BinaryWriter(Stream* nStream)
+{
+ stream.reset(nStream);
+}
+
+BinaryWriter::BinaryWriter(std::shared_ptr<Stream> nStream)
+{
+ stream = nStream;
+}
+
+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)
+{
+ stream->Write((char*)&value, sizeof(int16_t));
+}
+
+void BinaryWriter::Write(uint16_t value)
+{
+ stream->Write((char*)&value, sizeof(uint16_t));
+}
+
+void BinaryWriter::Write(int32_t value)
+{
+ stream->Write((char*)&value, sizeof(int32_t));
+}
+
+void BinaryWriter::Write(uint32_t value)
+{
+ stream->Write((char*)&value, sizeof(uint32_t));
+}
+
+void BinaryWriter::Write(int64_t value)
+{
+ stream->Write((char*)&value, sizeof(int64_t));
+}
+
+void BinaryWriter::Write(uint64_t value)
+{
+ stream->Write((char*)&value, sizeof(uint64_t));
+}
+
+void BinaryWriter::Write(float value)
+{
+ stream->Write((char*)&value, sizeof(float));
+}
+
+void BinaryWriter::Write(double value)
+{
+ stream->Write((char*)&value, sizeof(double));
+}
+
+void BinaryWriter::Write(std::string str)
+{
+ int strLen = str.size();
+ stream->Write((char*)&strLen, sizeof(int));
+
+ for (char c : str)
+ stream->WriteByte(c);
+}
diff --git a/ZAPD/Utils/BinaryWriter.h b/ZAPD/Utils/BinaryWriter.h
new file mode 100644
index 0000000..e187b8c
--- /dev/null
+++ b/ZAPD/Utils/BinaryWriter.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <array>
+#include <memory>
+#include <string>
+#include <vector>
+#include "Stream.h"
+
+class BinaryWriter
+{
+public:
+ BinaryWriter(Stream* nStream);
+ BinaryWriter(std::shared_ptr<Stream> nStream);
+
+ 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(uint32_t value);
+ void Write(int64_t value);
+ void Write(uint64_t value);
+ void Write(float value);
+ void Write(double value);
+ void Write(std::string str);
+
+protected:
+ std::shared_ptr<Stream> stream;
+}; \ No newline at end of file
diff --git a/ZAPD/Utils/BitConverter.h b/ZAPD/Utils/BitConverter.h
new file mode 100644
index 0000000..5cca35b
--- /dev/null
+++ b/ZAPD/Utils/BitConverter.h
@@ -0,0 +1,161 @@
+#pragma once
+
+#include <limits>
+#include <stdint.h>
+#include <vector>
+
+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;
+ }
+};
diff --git a/ZAPD/Utils/Directory.h b/ZAPD/Utils/Directory.h
new file mode 100644
index 0000000..a266487
--- /dev/null
+++ b/ZAPD/Utils/Directory.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#if __has_include(<filesystem>)
+#include <filesystem>
+namespace fs = std::filesystem;
+#else
+#include <experimental/filesystem>
+namespace fs = std::experimental::filesystem;
+#endif
+
+#include "Utils/StringHelper.h"
+
+class Directory
+{
+public:
+ static std::string GetCurrentDirectory() { return fs::current_path().u8string(); }
+
+ static bool Exists(const fs::path& path) { return fs::exists(path); }
+
+ static void CreateDirectory(const std::string& path)
+ {
+ std::string curPath = "";
+ std::vector<std::string> split = StringHelper::Split(path, "/");
+
+ for (std::string s : split)
+ {
+ curPath += s + "/";
+
+ if (!Exists(curPath))
+ fs::create_directory(curPath);
+ }
+
+ // fs::create_directory(path);
+ }
+};
diff --git a/ZAPD/Utils/File.h b/ZAPD/Utils/File.h
new file mode 100644
index 0000000..e3f8880
--- /dev/null
+++ b/ZAPD/Utils/File.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include "Directory.h"
+#include "Utils/StringHelper.h"
+
+class File
+{
+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);
+ 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)
+ {
+ 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)
+ {
+ 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..6c940be
--- /dev/null
+++ b/ZAPD/Utils/MemoryStream.cpp
@@ -0,0 +1,90 @@
+#include "MemoryStream.h"
+#include <string.h>
+
+#ifndef _MSC_VER
+#define memcpy_s(dest, destSize, source, sourceSize) memcpy(dest, source, destSize)
+#endif
+
+MemoryStream::MemoryStream()
+{
+ buffer = std::vector<char>();
+ 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;
+}
+
+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..cc24315
--- /dev/null
+++ b/ZAPD/Utils/MemoryStream.h
@@ -0,0 +1,32 @@
+#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);
+
+ std::unique_ptr<char[]> Read(size_t length);
+ int8_t ReadByte();
+
+ void Write(char* srcBuffer, size_t length);
+ void WriteByte(int8_t value);
+
+ std::vector<char> ToVector();
+
+ void Flush();
+ void Close();
+
+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..fd3c658
--- /dev/null
+++ b/ZAPD/Utils/Path.h
@@ -0,0 +1,53 @@
+#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 std::string& input)
+ {
+ std::vector<std::string> split = StringHelper::Split(input, "/");
+ return split[split.size() - 1];
+ };
+
+ static std::string GetFileNameWithoutExtension(const std::string& input)
+ {
+ std::vector<std::string> split = StringHelper::Split(input, "/");
+ return split[split.size() - 1].substr(0, split[split.size() - 1].find_last_of("."));
+ };
+
+ static std::string GetFileNameExtension(const std::string& input)
+ {
+ return input.substr(input.find_last_of("."), input.length());
+ };
+
+ static std::string GetPath(const std::string& input)
+ {
+ std::vector<std::string> split = StringHelper::Split(input, "/");
+ std::string output = "";
+
+ for (std::string str : split)
+ {
+ if (str.find_last_of(".") == std::string::npos)
+ output += str + "/";
+ }
+
+ return output;
+ };
+
+ static std::string GetDirectoryName(const fs::path& path)
+ {
+ return path.parent_path().u8string();
+ };
+};
diff --git a/ZAPD/Utils/Stream.h b/ZAPD/Utils/Stream.h
new file mode 100644
index 0000000..facb710
--- /dev/null
+++ b/ZAPD/Utils/Stream.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <memory>
+#include <stdint.h>
+
+enum class SeekOffsetType
+{
+ Start,
+ Current,
+ End
+};
+
+class Stream
+{
+public:
+ 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 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.h b/ZAPD/Utils/StringHelper.h
new file mode 100644
index 0000000..26516d0
--- /dev/null
+++ b/ZAPD/Utils/StringHelper.h
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <algorithm>
+#include <cstring>
+#include <numeric>
+#include <stdarg.h>
+#include <string>
+#include <vector>
+
+#ifndef __PRETTY_FUNCTION__
+#ifdef _MSC_VER
+#define __PRETTY_FUNCTION__ __FUNCSIG__
+#else
+#define __PRETTY_FUNCTION__ __func__
+#endif
+#endif
+
+class StringHelper
+{
+public:
+ static std::vector<std::string> Split(std::string s, const std::string& delimiter)
+ {
+ std::vector<std::string> result;
+
+ size_t pos = 0;
+ std::string token;
+
+ while ((pos = s.find(delimiter)) != std::string::npos)
+ {
+ token = s.substr(0, pos);
+ result.push_back(token);
+ s.erase(0, pos + delimiter.length());
+ }
+
+ if (s.length() != 0)
+ result.push_back(s);
+
+ return result;
+ }
+
+ static std::string 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;
+ }
+
+ static std::string Replace(std::string str, const std::string& from, const std::string& to)
+ {
+ size_t start_pos = str.find(from);
+
+ if (start_pos == std::string::npos)
+ return str;
+
+ str.replace(start_pos, from.length(), to);
+ return str;
+ }
+
+ static bool StartsWith(const std::string& s, const std::string& input)
+ {
+ return s.rfind(input, 0) == 0;
+ }
+
+ static bool Contains(const std::string& s, const std::string& input)
+ {
+ return s.find(input) != std::string::npos;
+ }
+
+ static bool EndsWith(const std::string& s, const std::string& input)
+ {
+ size_t inputLen = strlen(input.c_str());
+ return s.rfind(input) == (s.size() - inputLen);
+ }
+
+ static std::string Sprintf(const char* format, ...)
+ {
+ char buffer[32768];
+ // char buffer[2048];
+ std::string output = "";
+ va_list va;
+
+ va_start(va, format);
+ vsprintf(buffer, format, va);
+ va_end(va);
+
+ output = buffer;
+ return output;
+ }
+
+ static std::string Implode(std::vector<std::string>& elements, const char* const separator)
+ {
+ 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;
+ });
+ }
+
+ static int64_t StrToL(const std::string& str, int32_t base = 10)
+ {
+ return std::strtoull(str.c_str(), nullptr, base);
+ }
+
+ static std::string BoolStr(bool b) { return b ? "true" : "false"; }
+
+ static bool HasOnlyDigits(const std::string& str)
+ {
+ return std::all_of(str.begin(), str.end(), ::isdigit);
+ }
+};