r5sdk/r5dev/public/utility.cpp
IcePixelx c81aca28de Fixed a few asserts regarding the gui. RPak things. Check description.
* Fixed assert on ImGui on IBrowser because ImGui::Begin wasn't followed up by ImGui::End
* FileExists got modernized. Using std library instead of Windows native functions now.
* RTech::DecompressedSize is actually readable now thanks to steyk.
* Same goes for RTech::Decompress
* rtech_decompress prints the decompressed file CRC32 now and writes the file all at once.
* Fixed ImGui assert on spamming SetupImGui();
2021-12-26 02:30:20 +01:00

282 lines
8.8 KiB
C++

/*-----------------------------------------------------------------------------
* _utility
*-----------------------------------------------------------------------------*/
#include "core/stdafx.h"
#include "core/logdef.h"
#include "public/include/utility.h"
///////////////////////////////////////////////////////////////////////////////
// For checking if a specific file exists.
BOOL FileExists(const char* szPath)
{
return std::filesystem::exists(szPath);
}
///////////////////////////////////////////////////////////////////////////////
// For getting information about the executing module.
MODULEINFO GetModuleInfo(const char* szModule)
{
MODULEINFO modinfo = { 0 };
HMODULE hModule = GetModuleHandle(szModule);
if (hModule == INVALID_HANDLE_VALUE)
{
return modinfo;
}
GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof(MODULEINFO));
return modinfo;
}
///////////////////////////////////////////////////////////////////////////////
// For finding a byte pattern in memory of the process.
BOOL Compare(const unsigned char* pData, const unsigned char* szPattern, const char* szMask)
{
for (; *szMask; ++szMask, ++pData, ++szPattern)
{
if (*szMask == 'x' && *pData != *szPattern)
{
return false;
}
}
return (*szMask) == NULL;
}
///////////////////////////////////////////////////////////////////////////////
// For finding a pattern in memory of the process with SIMD.
DWORD64 FindPatternSIMD(const char* szModule, const unsigned char* szPattern, const char* szMask)
{
MODULEINFO mInfo = GetModuleInfo(szModule);
DWORD64 dwBase = (DWORD64)mInfo.lpBaseOfDll;
DWORD64 dwSize = (DWORD64)mInfo.SizeOfImage;
unsigned char* pData = (unsigned char*)dwBase;
unsigned int length = (unsigned int)dwSize;
const unsigned char* end = pData + length - strlen(szMask);
int num_masks = (int)ceil((float)strlen(szMask) / (float)16);
int masks[32]; // 32*16 = enough masks for 512 bytes.
memset(masks, 0, num_masks * sizeof(int));
for (int64_t i = 0; i < num_masks; ++i)
{
for (int64_t j = strnlen(szMask + i * 16, 16) - 1; j >= 0; --j)
{
if (szMask[i * 16 + j] == 'x')
{
masks[i] |= 1 << j;
}
}
}
__m128i xmm1 = _mm_loadu_si128((const __m128i*) szPattern);
__m128i xmm2, xmm3, msks;
for (; pData != end; _mm_prefetch((const char*)(++pData + 64), _MM_HINT_NTA))
{
if (szPattern[0] == pData[0])
{
xmm2 = _mm_loadu_si128((const __m128i*) pData);
msks = _mm_cmpeq_epi8(xmm1, xmm2);
if ((_mm_movemask_epi8(msks) & masks[0]) == masks[0])
{
for (DWORD64 i = 1; i < num_masks; ++i)
{
xmm2 = _mm_loadu_si128((const __m128i*) (pData + i * 16));
xmm3 = _mm_loadu_si128((const __m128i*) (szPattern + i * 16));
msks = _mm_cmpeq_epi8(xmm2, xmm3);
if ((_mm_movemask_epi8(msks) & masks[i]) == masks[i])
{
if ((i + 1) == num_masks)
{
return (DWORD64)pData;
}
}
else goto cont;
}
return (DWORD64)pData;
}
}cont:;
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
// For printing output to the debugger.
void DbgPrint(LPCSTR sFormat, ...)
{
CHAR sBuffer[512] = { 0 };
va_list sArgs = {};
// Get the variable arg pointer.
va_start(sArgs, sFormat);
// Format print the string.
int length = vsnprintf(sBuffer, sizeof(sBuffer), sFormat, sArgs);
va_end(sArgs);
// Output the string to the debugger.
OutputDebugString(sBuffer);
}
///////////////////////////////////////////////////////////////////////////////
// For dumping data from a buffer to a file on the disk
void HexDump(const char* szHeader, int nFunc, const void* pData, int nSize)
{
static unsigned char szAscii[17] = {};
static std::atomic<int> i = {}, j = {}, k = {};
static std::shared_ptr<spdlog::logger> logger = spdlog::get("default_logger");
// Loop until the function returned to the first caller.
while (k == 1) { /*Sleep(75);*/ }
k = 1;
szAscii[16] = '\0';
// Add new loggers here to replace the placeholder.
if (nFunc == 0) { logger = g_spd_netchan_logger; }
// Add timestamp.
logger->set_level(spdlog::level::trace);
logger->set_pattern("%v [%H:%M:%S.%f]\n");
logger->trace("---------------------------------------------------------");
// Disable EOL and create block header.
logger->set_pattern("%v");
logger->trace("{:s} ---- LEN BYTES: {}\n:\n", szHeader, nSize);
logger->trace("-------- 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF\n");
// Output the buffer to the file.
for (i = 0; i < nSize; i++)
{
if (i % nSize == 0) { logger->trace(" 0x{:04X} ", i); }
logger->trace("{:02x} ", ((unsigned char*)pData)[i]);
if (((unsigned char*)pData)[i] >= ' ' && ((unsigned char*)pData)[i] <= '~') { szAscii[i % 16] = ((unsigned char*)pData)[i]; }
else { szAscii[i % 16] = '.'; }
if ((i + 1) % 8 == 0 || i + 1 == nSize)
{
logger->trace(" ");
if ((i + 1) % 16 == 0)
{
if (i + 1 == nSize)
{
logger->trace("{:s}\n", szAscii);
logger->trace("---------------------------------------------------------------------------\n");
logger->trace("\n");
}
else
{
i++;
logger->trace("{:s}\n ", szAscii);
logger->trace("0x{:04X} ", i--);
}
}
else if (i + 1 == nSize)
{
szAscii[(i + 1) % 16] = '\0';
if ((i + 1) % 16 <= 8)
{
logger->trace(" ");
}
for (j = (i + 1) % 16; j < 16; j++)
{
logger->trace(" ");
}
logger->trace("{:s}\n", szAscii);
logger->trace("---------------------------------------------------------------------------\n");
logger->trace("\n");
}
}
}
k = 0;
///////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////
// For encoding data in base64.
std::string Base64Encode(const std::string& in)
{
std::string results;
int val = 0, valb = -6;
for (unsigned char c : in)
{
val = (val << 8) + c;
valb += 8;
while (valb >= 0)
{
results.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb > -6)
{
results.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
}
while (results.size() % 4)
{
results.push_back('=');
}
return results;
}
///////////////////////////////////////////////////////////////////////////////
// For decoding data in base64.
std::string Base64Decode(const std::string& in)
{
std::string results;
int val = 0, valb = -8;
std::vector<int> T(256, -1);
for (int i = 0; i < 64; i++)
{
T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
}
for (unsigned char c : in)
{
if (T[c] == -1)
{
break;
}
val = (val << 6) + T[c];
valb += 6;
if (valb >= 0)
{
results.push_back(char((val >> valb) & 0xFF));
valb -= 8;
}
}
return results;
}
///////////////////////////////////////////////////////////////////////////////
// For replacing parts of a given string.
bool StringReplace(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 false;
}
str.replace(start_pos, from.length(), to);
return true;
}
///////////////////////////////////////////////////////////////////////////////
// For creating directories for output streams.
std::string CreateDirectories(std::string svFilePath)
{
std::filesystem::path fspPathOut(svFilePath);
std::string results = fspPathOut.u8string();
StringReplace(svFilePath, "\\ \\", "\\");
fspPathOut = fspPathOut.parent_path();
std::filesystem::create_directories(fspPathOut);
return results;
}