LunaHook-mirror/LunaHook/embed_util.cc

293 lines
7.7 KiB
C++
Raw Permalink Normal View History

2024-10-22 00:44:15 +08:00
#include "MinHook.h"
2024-07-21 21:04:12 +08:00
DynamicShiftJISCodec *dynamiccodec = new DynamicShiftJISCodec(932);
2024-02-07 20:59:24 +08:00
2024-07-21 21:04:12 +08:00
void cast_back(const HookParam &hp, void *data, size_t *len, const std::wstring &trans, bool normal)
{
2024-02-07 20:59:24 +08:00
2024-07-21 21:04:12 +08:00
if ((hp.type & EMBED_CODEC_UTF16) || (hp.type & CODEC_UTF16))
{ // renpy
write_string_overwrite(data, len, trans);
}
else
{
2024-02-07 20:59:24 +08:00
std::string astr;
2024-07-21 21:04:12 +08:00
if (hp.type & EMBED_DYNA_SJIS && !normal)
{
astr = dynamiccodec->encodeSTD(trans, 0);
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
else
{
astr = WideStringToString(trans, hp.codepage ? hp.codepage : ((hp.type & CODEC_UTF8) ? CP_UTF8 : embedsharedmem->codepage));
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
write_string_overwrite(data, len, astr);
}
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
struct FunctionInfo
{
const char *name; // for debugging purpose
uintptr_t *oldFunction,
newFunction;
bool attached;
uintptr_t addr;
explicit FunctionInfo(const uintptr_t _addr = 0, const char *name = "", uintptr_t *oldFunction = nullptr, uintptr_t newFunction = 0,
bool attached = false)
: name(name), oldFunction(oldFunction), newFunction(newFunction), attached(attached), addr(_addr)
{
}
};
2024-02-07 20:59:24 +08:00
std::unordered_map<uintptr_t, FunctionInfo> funcs; // attached functions
2024-07-21 21:04:12 +08:00
std::vector<uintptr_t> replacedfuns; // attached functions
2024-02-07 20:59:24 +08:00
bool _1f()
{
2024-07-21 21:04:12 +08:00
#define ADD_FUN(_f) funcs[F_##_f] = FunctionInfo((uintptr_t)_f, #_f, (uintptr_t *)&Hijack::old##_f, (uintptr_t)Hijack::new##_f);
2024-02-07 20:59:24 +08:00
ADD_FUN(CreateFontA)
ADD_FUN(CreateFontW)
ADD_FUN(CreateFontIndirectA)
ADD_FUN(CreateFontIndirectW)
ADD_FUN(GetGlyphOutlineA)
ADD_FUN(GetGlyphOutlineW)
ADD_FUN(GetTextExtentPoint32A)
ADD_FUN(GetTextExtentPoint32W)
ADD_FUN(GetTextExtentExPointA)
ADD_FUN(GetTextExtentExPointW)
2024-07-21 21:04:12 +08:00
// ADD_FUN(GetCharABCWidthsA)
// ADD_FUN(GetCharABCWidthsW)
2024-02-07 20:59:24 +08:00
ADD_FUN(TextOutA)
ADD_FUN(TextOutW)
ADD_FUN(ExtTextOutA)
ADD_FUN(ExtTextOutW)
ADD_FUN(DrawTextA)
ADD_FUN(DrawTextW)
ADD_FUN(DrawTextExA)
ADD_FUN(DrawTextExW)
ADD_FUN(CharNextA)
2024-07-21 21:04:12 +08:00
// ADD_FUN(CharNextW)
// ADD_FUN(CharNextExA)
// ADD_FUN(CharNextExW)
2024-02-07 20:59:24 +08:00
ADD_FUN(CharPrevA)
2024-07-21 21:04:12 +08:00
// ADD_FUN(CharPrevW)
2024-02-07 20:59:24 +08:00
ADD_FUN(MultiByteToWideChar)
ADD_FUN(WideCharToMultiByte)
#undef ADD_FUN
2024-07-21 21:04:12 +08:00
return 0;
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
bool _1 = _1f();
2024-10-22 00:44:15 +08:00
bool ReplaceFunction(PVOID oldf, PVOID newf, PVOID *pOrigin)
2024-07-21 21:04:12 +08:00
{
2024-10-22 00:44:15 +08:00
PVOID oldx;
if (!pOrigin)
pOrigin = &oldx;
RemoveHook((uintptr_t)oldf);
if (MH_OK == MH_CreateHook(oldf, newf, pOrigin))
return MH_OK == MH_EnableHook(oldf);
else
{
MH_RemoveHook(oldf);
return false;
}
2024-02-07 20:59:24 +08:00
}
void attachFunction(uintptr_t _hook_font_flag)
{
2024-07-21 21:04:12 +08:00
for (auto &_func : funcs)
{
if (_func.first & _hook_font_flag)
{
if (_func.second.attached)
continue;
2024-10-22 00:44:15 +08:00
if (ReplaceFunction((PVOID)_func.second.addr, (PVOID)_func.second.newFunction, (PVOID *)_func.second.oldFunction))
{
_func.second.attached = true;
replacedfuns.push_back(_func.first);
}
2024-02-07 20:59:24 +08:00
}
}
}
2024-07-21 21:04:12 +08:00
void detachall()
{
for (auto _flag : replacedfuns)
{
auto info = funcs.at(_flag);
2024-10-22 00:44:15 +08:00
if (MH_OK == MH_DisableHook((LPVOID)info.addr))
MH_RemoveHook((LPVOID)info.addr);
2024-07-21 21:04:12 +08:00
}
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
void solvefont(HookParam hp)
{
if (hp.hook_font)
{
attachFunction(hp.hook_font);
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
if (hp.hook_font & F_MultiByteToWideChar)
disable_mbwc = true;
if (hp.hook_font & F_WideCharToMultiByte)
disable_wcmb = true;
if (auto current_patch_fun = patch_fun.exchange(nullptr))
{
2024-02-07 20:59:24 +08:00
current_patch_fun();
2024-07-21 21:04:12 +08:00
dont_detach = true;
2024-02-07 20:59:24 +08:00
}
}
2024-07-21 21:04:12 +08:00
static std::wstring alwaysInsertSpacesSTD(const std::wstring &text)
{
std::wstring ret;
for (auto c : text)
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
ret.push_back(c);
if (c >= 32) // ignore non-printable characters
ret.push_back(L' '); // or insert \u3000 if needed
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
return ret;
}
bool charEncodableSTD(const wchar_t &ch, UINT codepage)
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
if (ch <= 127) // ignore ascii characters
return true;
std::wstring s;
s.push_back(ch);
return StringToWideString(WideStringToString(s, codepage), codepage).value() == s;
}
static std::wstring insertSpacesAfterUnencodableSTD(const std::wstring &text, HookParam hp)
{
std::wstring ret;
for (const wchar_t &c : text)
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
ret.push_back(c);
if (!charEncodableSTD(c, hp.codepage ? hp.codepage : embedsharedmem->codepage))
ret.push_back(L' ');
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
return ret;
}
std::wstring adjustSpacesSTD(const std::wstring &text, HookParam hp)
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
2024-02-07 20:59:24 +08:00
switch (embedsharedmem->spaceadjustpolicy)
{
2024-07-21 21:04:12 +08:00
case 0:
return text;
case 1:
return alwaysInsertSpacesSTD(text);
case 2:
return insertSpacesAfterUnencodableSTD(text, hp);
default:
return text;
}
}
2024-02-07 20:59:24 +08:00
bool isPauseKeyPressed()
{
2024-07-21 21:04:12 +08:00
return WinKey::isKeyControlPressed() || WinKey::isKeyShiftPressed() && !WinKey::isKeyReturnPressed();
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
inline UINT64 djb2_n2(const unsigned char *str, size_t len, UINT64 hash = 5381)
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
int i = 0;
while (len--)
{
hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c
}
return hash;
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
std::unordered_map<UINT64, std::wstring> translatecache;
bool check_is_thread_selected(const ThreadParam &tp)
{
for (int i = 0; i < 10; i++)
if (embedsharedmem->use[i])
if ((embedsharedmem->addr[i] == tp.addr) && (embedsharedmem->ctx1[i] == tp.ctx) && (embedsharedmem->ctx2[i] == tp.ctx2))
2024-02-07 20:59:24 +08:00
return true;
return false;
}
2024-07-21 21:04:12 +08:00
bool check_embed_able(const ThreadParam &tp)
{
return host_connected && check_is_thread_selected(tp) && ((isPauseKeyPressed() == false) ? true : !embedsharedmem->fastskipignore);
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
bool waitforevent(UINT32 timems, const ThreadParam &tp, const std::wstring &origin)
{
char eventname[1000];
sprintf(eventname, LUNA_EMBED_notify_event, GetCurrentProcessId(), djb2_n2((const unsigned char *)(origin.c_str()), origin.size() * 2));
auto event = win_event(eventname);
while (timems)
{
if (check_embed_able(tp) == false)
return false;
auto sleepstep = min(100, timems);
if (event.wait(sleepstep))
return true;
timems -= sleepstep;
}
return false;
2024-02-07 20:59:24 +08:00
}
2024-02-28 23:33:52 +08:00
2024-07-21 21:04:12 +08:00
void TextHook::parsenewlineseperator(void *data, size_t *len)
2024-02-28 23:33:52 +08:00
{
2024-07-21 21:04:12 +08:00
if (!(hp.newlineseperator))
return;
2024-02-28 23:33:52 +08:00
if (hp.type & CODEC_UTF16)
{
2024-09-27 15:28:18 +08:00
StringCharReplacer((wchar_t *)data, len, hp.newlineseperator, wcslen(hp.newlineseperator), L'\n');
2024-02-28 23:33:52 +08:00
}
2024-07-21 21:04:12 +08:00
else if (hp.type & CODEC_UTF32)
return;
2024-02-28 23:33:52 +08:00
else
{
2024-07-21 21:04:12 +08:00
// ansi/utf8newlineseperator都是简单字符
2024-02-28 23:33:52 +08:00
std::string newlineseperatorA;
2024-07-21 21:04:12 +08:00
for (int i = 0; i < wcslen(hp.newlineseperator); i++)
newlineseperatorA += (char)hp.newlineseperator[i];
2024-09-27 15:28:18 +08:00
StringCharReplacer((char *)data, len, newlineseperatorA.c_str(), newlineseperatorA.size(), '\n');
2024-02-28 23:33:52 +08:00
}
}
2024-07-21 21:04:12 +08:00
UINT64 texthash(void *data, size_t len)
2024-03-08 22:22:26 +08:00
{
2024-07-21 21:04:12 +08:00
UINT64 sum = 0;
auto u8data = (UINT8 *)data;
for (int i = 0; i < len; i++)
{
sum += u8data[i];
sum = sum << 1;
2024-03-08 22:22:26 +08:00
}
return sum;
}
2024-07-21 21:04:12 +08:00
bool checktranslatedok(void *data, size_t len)
2024-03-08 22:22:26 +08:00
{
2024-07-21 21:04:12 +08:00
ZeroMemory(embedsharedmem->text, sizeof(embedsharedmem->text)); // clear trans before call
if (len > 1000)
return true;
return (translatecache.find(texthash(data, len)) != translatecache.end());
2024-03-08 22:22:26 +08:00
}
2024-07-21 21:04:12 +08:00
bool TextHook::waitfornotify(TextOutput_T *buffer, void *data, size_t *len, ThreadParam tp)
{
2024-02-08 21:48:24 +08:00
std::wstring origin;
2024-07-21 21:04:12 +08:00
if (auto t = commonparsestring(data, *len, &hp, embedsharedmem->codepage))
origin = t.value();
else
return false;
2024-02-07 20:59:24 +08:00
std::wstring translate;
2024-07-21 21:04:12 +08:00
auto hash = texthash(data, *len);
if (translatecache.find(hash) != translatecache.end())
{
translate = translatecache.at(hash);
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
else
{
if (waitforevent(embedsharedmem->waittime, tp, origin) == false)
return false;
translate = embedsharedmem->text;
if ((translate.size() == 0))
return false;
translatecache.insert(std::make_pair(hash, translate));
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
if (hp.newlineseperator)
strReplace(translate, L"\n", hp.newlineseperator);
translate = adjustSpacesSTD(translate, hp);
if (embedsharedmem->keeprawtext)
translate = origin + L" " + translate;
2024-02-07 20:59:24 +08:00
solvefont(hp);
2024-07-21 21:04:12 +08:00
cast_back(hp, data, len, translate, false);
return true;
2024-02-07 20:59:24 +08:00
}