|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
#include <optional>
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include "iconv.h"
|
|
|
|
|
|
#include "uemf.h"
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
#define SAFEPRINTF_SUCCESS 0
|
|
|
|
|
|
#define SAFEPRINTF_ERROR -1
|
|
|
|
|
|
|
|
|
|
|
|
static const char * HexStringToByteArray(string hexString)
|
|
|
|
|
|
{
|
|
|
|
|
|
size_t length = hexString.length();
|
|
|
|
|
|
char * byteArray = new char[length / 2];
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < length; i += 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
//byteArray[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
|
|
|
|
|
|
// <20><>ÿһ<C3BF><D2BB>ʮ<EFBFBD><CAAE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ֽ<EFBFBD>
|
|
|
|
|
|
byteArray[i / 2] = std::stoi(hexString.substr(i, 2), nullptr, 16);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return byteArray;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>ȡ<EFBFBD><C8A1><EFBFBD>ļ<EFBFBD><C4BC>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
static std::vector<BYTE> ReadFullFileData(CFile &fr)
|
|
|
|
|
|
{
|
|
|
|
|
|
ULONGLONG fileSize = fr.GetLength();
|
|
|
|
|
|
std::vector<BYTE> buffer(fileSize);
|
|
|
|
|
|
|
|
|
|
|
|
ULONGLONG left = fileSize;
|
|
|
|
|
|
ULONGLONG nread = 0;
|
|
|
|
|
|
BYTE* ptr = buffer.data();
|
|
|
|
|
|
|
|
|
|
|
|
while (left > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
UINT n = static_cast<UINT>(min(UINT_MAX, left));
|
|
|
|
|
|
|
|
|
|
|
|
if (fr.Read(ptr, n) != n)
|
|
|
|
|
|
{
|
|
|
|
|
|
return {};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
left -= n;
|
|
|
|
|
|
ptr += n;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//string->wstring
|
|
|
|
|
|
static std::wstring UTF8ToWide(const char* utf8Str) {
|
|
|
|
|
|
if (!utf8Str) return L"";
|
|
|
|
|
|
int wideLen = MultiByteToWideChar(CP_ACP, 0, utf8Str, -1, nullptr, 0);
|
|
|
|
|
|
if (wideLen <= 0) return L"";
|
|
|
|
|
|
std::wstring wideStr(wideLen, 0);
|
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, utf8Str, -1, &wideStr[0], wideLen);
|
|
|
|
|
|
wideStr.resize(wideLen - 1); // ȥ<><C8A5>ĩβ<C4A9><CEB2> null <20>ַ<EFBFBD>
|
|
|
|
|
|
return wideStr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline char *utf8_to_gbk(const char *utf8_str)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!utf8_str) return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>ij<EFBFBD><C4B3><EFBFBD>
|
|
|
|
|
|
size_t utf8_len = strlen(utf8_str) + 1; // +1 Ϊ null <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
size_t gbk_len = utf8_len * 2; // GBK <20><><EFBFBD>ȹ<F3B3A4B6><C8B9><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
char *gbk_str = (char *)malloc(gbk_len);
|
|
|
|
|
|
if (!gbk_str) return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
char *in_buf = (char *)utf8_str;
|
|
|
|
|
|
char *out_buf = gbk_str;
|
|
|
|
|
|
|
|
|
|
|
|
// iconv <20><>ʼ<EFBFBD><CABC>
|
|
|
|
|
|
iconv_t conv = iconv_open("GBK", "UTF-8");
|
|
|
|
|
|
if (conv == (iconv_t)-1)
|
|
|
|
|
|
{
|
|
|
|
|
|
free(gbk_str);
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size_t in_bytes_left = utf8_len;
|
|
|
|
|
|
size_t out_bytes_left = gbk_len;
|
|
|
|
|
|
|
|
|
|
|
|
// ת<><D7AA>
|
|
|
|
|
|
size_t result = iconv(conv, &in_buf, &in_bytes_left, &out_buf, &out_bytes_left);
|
|
|
|
|
|
iconv_close(conv);
|
|
|
|
|
|
|
|
|
|
|
|
if (result == (size_t)-1)
|
|
|
|
|
|
{
|
|
|
|
|
|
free(gbk_str);
|
|
|
|
|
|
return NULL; // ת<><D7AA>ʧ<EFBFBD><CAA7>
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ʵ<EFBFBD>ʳ<EFBFBD><CAB3>Ȳ<EFBFBD><C8B2><EFBFBD><EFBFBD><EFBFBD> null <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
size_t out_len = gbk_len - out_bytes_left;
|
|
|
|
|
|
gbk_str[out_len] = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
return gbk_str;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline char *gbk_to_utf8(const char *gbk_str)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!gbk_str) return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>ij<EFBFBD><C4B3><EFBFBD>
|
|
|
|
|
|
size_t gbk_len = strlen(gbk_str) + 1; // +1 Ϊ null <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
size_t utf8_len = gbk_len * 3; // UTF-8 <20><><EFBFBD>ȹ<F3B3A4B6><C8B9>㣬ÿ<E3A3AC><C3BF>GBK<42>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>ܱ<EFBFBD><DCB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3<EFBFBD><33>UTF-8<>ַ<EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
char *utf8_str = (char *)malloc(utf8_len);
|
|
|
|
|
|
if (!utf8_str) return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
char *in_buf = (char *)gbk_str;
|
|
|
|
|
|
char *out_buf = utf8_str;
|
|
|
|
|
|
|
|
|
|
|
|
// iconv <20><>ʼ<EFBFBD><CABC>
|
|
|
|
|
|
iconv_t conv = iconv_open("UTF-8", "GBK");
|
|
|
|
|
|
if (conv == (iconv_t)-1)
|
|
|
|
|
|
{
|
|
|
|
|
|
free(utf8_str);
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size_t in_bytes_left = gbk_len;
|
|
|
|
|
|
size_t out_bytes_left = utf8_len;
|
|
|
|
|
|
|
|
|
|
|
|
// ת<><D7AA>
|
|
|
|
|
|
size_t result = iconv(conv, &in_buf, &in_bytes_left, &out_buf, &out_bytes_left);
|
|
|
|
|
|
iconv_close(conv);
|
|
|
|
|
|
|
|
|
|
|
|
if (result == (size_t)-1)
|
|
|
|
|
|
{
|
|
|
|
|
|
free(utf8_str);
|
|
|
|
|
|
return NULL; // ת<><D7AA>ʧ<EFBFBD><CAA7>
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ʵ<EFBFBD>ʳ<EFBFBD><CAB3>Ȳ<EFBFBD><C8B2><EFBFBD><EFBFBD><EFBFBD> null <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
size_t out_len = utf8_len - out_bytes_left;
|
|
|
|
|
|
utf8_str[out_len] = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
return utf8_str;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
\brief Find a (sub)string in a caseinvariant manner, used for locating "Narrow" in font name
|
|
|
|
|
|
\return Returns -1 if no match, else returns the position (numbered from 0) of the first character of the match.
|
|
|
|
|
|
\param string Text to search
|
|
|
|
|
|
\param sub Text to find
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline int TR_findcasesub(const char *string, const char *sub)
|
|
|
|
|
|
{
|
|
|
|
|
|
int i, j;
|
|
|
|
|
|
int match = 0;
|
|
|
|
|
|
for (i = 0; string[i]; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (match = 1, j = 0; sub[j] && string[i + j]; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (toupper(sub[j]) != toupper(string[i + j]))
|
|
|
|
|
|
{
|
|
|
|
|
|
match = 0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (match && !sub[j])
|
|
|
|
|
|
{
|
|
|
|
|
|
break; /* matched over the entire substring */
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return((match ? i : -1));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline void U_swap4(void *ul, unsigned int count)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t ctmp;
|
|
|
|
|
|
uint8_t *cl = (uint8_t *)ul;
|
|
|
|
|
|
for (; count; count--, cl += 4)
|
|
|
|
|
|
{
|
|
|
|
|
|
ctmp = *(cl + 0);
|
|
|
|
|
|
*(cl + 0) = *(cl + 3);
|
|
|
|
|
|
*(cl + 3) = ctmp;
|
|
|
|
|
|
ctmp = *(cl + 1);
|
|
|
|
|
|
*(cl + 1) = *(cl + 2);
|
|
|
|
|
|
*(cl + 2) = ctmp;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Useful composition macros */
|
|
|
|
|
|
|
|
|
|
|
|
constexpr double SP_COLOR_U_TO_F(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return v / 255.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t SP_COLOR_F_TO_U(double v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (unsigned int)(v * 255. + .5);
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t SP_RGBA32_R_U(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (v >> 24) & 0xff;
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t SP_RGBA32_G_U(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (v >> 16) & 0xff;
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t SP_RGBA32_B_U(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (v >> 8) & 0xff;
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t SP_RGBA32_A_U(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return v & 0xff;
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr double SP_RGBA32_R_F(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SP_COLOR_U_TO_F(SP_RGBA32_R_U(v));
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr double SP_RGBA32_G_F(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SP_COLOR_U_TO_F(SP_RGBA32_G_U(v));
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr double SP_RGBA32_B_F(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SP_COLOR_U_TO_F(SP_RGBA32_B_U(v));
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr double SP_RGBA32_A_F(uint32_t v)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SP_COLOR_U_TO_F(SP_RGBA32_A_U(v));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
constexpr uint32_t SP_RGBA32_U_COMPOSE(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ((b & 0xff) << 24) | ((g & 0xff) << 16) | ((r & 0xff) << 8) | (a & 0xff);
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t SP_RGBA32_F_COMPOSE(double r, double g, double b, double a)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SP_RGBA32_U_COMPOSE(SP_COLOR_F_TO_U(r), SP_COLOR_F_TO_U(g), SP_COLOR_F_TO_U(b), SP_COLOR_F_TO_U(a));
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t SP_RGBA32_C_COMPOSE(uint32_t c, double o)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SP_RGBA32_U_COMPOSE(SP_RGBA32_R_U(c), SP_RGBA32_G_U(c), SP_RGBA32_B_U(c), SP_COLOR_F_TO_U(o));
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t U_RGB_COMPOSE(U_COLORREF c)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SP_RGBA32_U_COMPOSE(U_RGBAGetR(c), U_RGBAGetG(c), U_RGBAGetB(c), 0xff);
|
|
|
|
|
|
}
|
|
|
|
|
|
constexpr uint32_t U_RGBA_COMPOSE(U_COLORREF c)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SP_RGBA32_U_COMPOSE(U_RGBAGetR(c), U_RGBAGetG(c), U_RGBAGetB(c), U_RGBAGetA(c));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<size_t N>
|
|
|
|
|
|
int safeprintf(char(&buf)[N], const char* fmt, ...) {
|
|
|
|
|
|
va_list args;
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
|
|
auto len = vsnprintf(buf, N, fmt, args);
|
|
|
|
|
|
va_end(args);
|
|
|
|
|
|
return len;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|