forked from Public-Mirror/Textractor
sanitize surrogate characters which cause qt to crash if unpaired
This commit is contained in:
parent
81d5b745aa
commit
0ace753199
@ -60,7 +60,7 @@ namespace
|
|||||||
std::scoped_lock writeLock(extenMutex);
|
std::scoped_lock writeLock(extenMutex);
|
||||||
std::vector<Extension> extensions;
|
std::vector<Extension> extensions;
|
||||||
for (auto extenName : extenNames)
|
for (auto extenName : extenNames)
|
||||||
extensions.push_back(*std::find_if(::extensions.begin(), ::extensions.end(), [&](auto extension) { return extension.name == S(extenName); }));
|
extensions.push_back(*std::find_if(::extensions.begin(), ::extensions.end(), [&](Extension extension) { return extension.name == S(extenName); }));
|
||||||
::extensions = extensions;
|
::extensions = extensions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ void TextThread::Push(BYTE* data, int length)
|
|||||||
|
|
||||||
if (filterRepetition)
|
if (filterRepetition)
|
||||||
{
|
{
|
||||||
if (std::all_of(buffer.begin(), buffer.end(), [&](auto ch) { return repeatingChars.find(ch) != repeatingChars.end(); })) buffer.clear();
|
if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t ch) { return repeatingChars.find(ch) != repeatingChars.end(); })) buffer.clear();
|
||||||
if (RemoveRepetition(buffer)) // sentence repetition detected, which means the entire sentence has already been received
|
if (RemoveRepetition(buffer)) // sentence repetition detected, which means the entire sentence has already been received
|
||||||
{
|
{
|
||||||
if (hp.type & BLOCK_FLOOD) Host::RemoveHook(tp.processId, tp.addr);
|
if (hp.type & BLOCK_FLOOD) Host::RemoveHook(tp.processId, tp.addr);
|
||||||
|
@ -66,7 +66,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
extenWindow(new ExtenWindow(this))
|
extenWindow(new ExtenWindow(this))
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
for (auto [text, slot] : Array<std::tuple<const char*, void(MainWindow::*)()>>{
|
for (auto [text, slot] : Array<const char*, void(MainWindow::*)()>{
|
||||||
{ ATTACH, &MainWindow::AttachProcess },
|
{ ATTACH, &MainWindow::AttachProcess },
|
||||||
{ LAUNCH, &MainWindow::LaunchProcess },
|
{ LAUNCH, &MainWindow::LaunchProcess },
|
||||||
{ DETACH, &MainWindow::DetachProcess },
|
{ DETACH, &MainWindow::DetachProcess },
|
||||||
@ -211,8 +211,9 @@ bool MainWindow::SentenceReceived(TextThread& thread, std::wstring& sentence)
|
|||||||
{
|
{
|
||||||
if (!DispatchSentenceToExtensions(sentence, GetSentenceInfo(thread).data())) return false;
|
if (!DispatchSentenceToExtensions(sentence, GetSentenceInfo(thread).data())) return false;
|
||||||
sentence += L'\n';
|
sentence += L'\n';
|
||||||
if (current == &thread) QMetaObject::invokeMethod(this, [this, sentence = S(sentence)]
|
if (current == &thread) QMetaObject::invokeMethod(this, [this, sentence = S(sentence)]() mutable
|
||||||
{
|
{
|
||||||
|
sanitize(sentence);
|
||||||
auto scrollbar = ui->textOutput->verticalScrollBar();
|
auto scrollbar = ui->textOutput->verticalScrollBar();
|
||||||
bool atBottom = scrollbar->value() + 3 > scrollbar->maximum() || (double)scrollbar->value() / scrollbar->maximum() > 0.975; // arbitrary
|
bool atBottom = scrollbar->value() + 3 > scrollbar->maximum() || (double)scrollbar->value() / scrollbar->maximum() > 0.975; // arbitrary
|
||||||
QTextCursor cursor(ui->textOutput->document());
|
QTextCursor cursor(ui->textOutput->document());
|
||||||
@ -354,7 +355,7 @@ void MainWindow::ForgetProcess()
|
|||||||
for (auto file : { GAME_SAVE_FILE, HOOK_SAVE_FILE })
|
for (auto file : { GAME_SAVE_FILE, HOOK_SAVE_FILE })
|
||||||
{
|
{
|
||||||
QStringList lines = QString::fromUtf8(QTextFile(file, QIODevice::ReadOnly).readAll()).split("\n", QString::SkipEmptyParts);
|
QStringList lines = QString::fromUtf8(QTextFile(file, QIODevice::ReadOnly).readAll()).split("\n", QString::SkipEmptyParts);
|
||||||
lines.erase(std::remove_if(lines.begin(), lines.end(), [&](auto line) { return line.contains(S(processName.value())); }), lines.end());
|
lines.erase(std::remove_if(lines.begin(), lines.end(), [&](const QString& line) { return line.contains(S(processName.value())); }), lines.end());
|
||||||
QTextFile(file, QIODevice::WriteOnly | QIODevice::Truncate).write(lines.join("\n").append("\n").toUtf8());
|
QTextFile(file, QIODevice::WriteOnly | QIODevice::Truncate).write(lines.join("\n").append("\n").toUtf8());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,7 +476,7 @@ void MainWindow::FindHooks()
|
|||||||
QLineEdit patternInput(x64 ? "CC CC 48 89" : "55 8B EC", &dialog);
|
QLineEdit patternInput(x64 ? "CC CC 48 89" : "55 8B EC", &dialog);
|
||||||
assert(QByteArray::fromHex(patternInput.text().toUtf8()) == QByteArray((const char*)sp.pattern, sp.length));
|
assert(QByteArray::fromHex(patternInput.text().toUtf8()) == QByteArray((const char*)sp.pattern, sp.length));
|
||||||
layout.addRow(SEARCH_PATTERN, &patternInput);
|
layout.addRow(SEARCH_PATTERN, &patternInput);
|
||||||
for (auto [value, label] : Array<std::tuple<int&, const char*>>{
|
for (auto [value, label] : Array<int&, const char*>{
|
||||||
{ sp.searchTime, SEARCH_DURATION },
|
{ sp.searchTime, SEARCH_DURATION },
|
||||||
{ sp.offset, PATTERN_OFFSET },
|
{ sp.offset, PATTERN_OFFSET },
|
||||||
{ sp.maxRecords, MAX_HOOK_SEARCH_RECORDS },
|
{ sp.maxRecords, MAX_HOOK_SEARCH_RECORDS },
|
||||||
@ -490,7 +491,7 @@ void MainWindow::FindHooks()
|
|||||||
}
|
}
|
||||||
QLineEdit boundInput(QFileInfo(S(Util::GetModuleFilename(GetSelectedProcessId()).value_or(L""))).fileName(), &dialog);
|
QLineEdit boundInput(QFileInfo(S(Util::GetModuleFilename(GetSelectedProcessId()).value_or(L""))).fileName(), &dialog);
|
||||||
layout.addRow(SEARCH_MODULE, &boundInput);
|
layout.addRow(SEARCH_MODULE, &boundInput);
|
||||||
for (auto [value, label] : Array<std::tuple<uintptr_t&, const char*>>{
|
for (auto [value, label] : Array<uintptr_t&, const char*>{
|
||||||
{ sp.minAddress, MIN_ADDRESS },
|
{ sp.minAddress, MIN_ADDRESS },
|
||||||
{ sp.maxAddress, MAX_ADDRESS },
|
{ sp.maxAddress, MAX_ADDRESS },
|
||||||
{ sp.padding, STRING_OFFSET },
|
{ sp.padding, STRING_OFFSET },
|
||||||
@ -528,7 +529,8 @@ void MainWindow::FindHooks()
|
|||||||
auto hooks = std::make_shared<QStringList>();
|
auto hooks = std::make_shared<QStringList>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Host::FindHooks(processId, sp, [=](HookParam hp, std::wstring text) { if (std::regex_search(text, filter)) *hooks << S(Util::GenerateCode(hp) + L" => " + text); });
|
Host::FindHooks(processId, sp,
|
||||||
|
[=](HookParam hp, std::wstring text) { if (std::regex_search(text, filter)) *hooks << sanitize(S(Util::GenerateCode(hp) + L" => " + text)); });
|
||||||
}
|
}
|
||||||
catch (std::out_of_range) { return; }
|
catch (std::out_of_range) { return; }
|
||||||
std::thread([this, hooks]
|
std::thread([this, hooks]
|
||||||
@ -572,7 +574,7 @@ void MainWindow::Settings()
|
|||||||
QSettings settings(CONFIG_FILE, QSettings::IniFormat, &dialog);
|
QSettings settings(CONFIG_FILE, QSettings::IniFormat, &dialog);
|
||||||
QFormLayout layout(&dialog);
|
QFormLayout layout(&dialog);
|
||||||
QPushButton saveButton(SAVE_SETTINGS, &dialog);
|
QPushButton saveButton(SAVE_SETTINGS, &dialog);
|
||||||
for (auto [value, label] : Array<std::tuple<bool&, const char*>>{
|
for (auto [value, label] : Array<bool&, const char*>{
|
||||||
{ TextThread::filterRepetition, FILTER_REPETITION },
|
{ TextThread::filterRepetition, FILTER_REPETITION },
|
||||||
{ autoAttach, AUTO_ATTACH },
|
{ autoAttach, AUTO_ATTACH },
|
||||||
{ autoAttachSavedOnly, ATTACH_SAVED_ONLY },
|
{ autoAttachSavedOnly, ATTACH_SAVED_ONLY },
|
||||||
@ -584,7 +586,7 @@ void MainWindow::Settings()
|
|||||||
layout.addRow(label, checkBox);
|
layout.addRow(label, checkBox);
|
||||||
connect(&saveButton, &QPushButton::clicked, [checkBox, label, &settings, &value] { settings.setValue(label, value = checkBox->isChecked()); });
|
connect(&saveButton, &QPushButton::clicked, [checkBox, label, &settings, &value] { settings.setValue(label, value = checkBox->isChecked()); });
|
||||||
}
|
}
|
||||||
for (auto [value, label] : Array<std::tuple<int&, const char*>>{
|
for (auto [value, label] : Array<int&, const char*>{
|
||||||
{ TextThread::maxBufferSize, MAX_BUFFER_SIZE },
|
{ TextThread::maxBufferSize, MAX_BUFFER_SIZE },
|
||||||
{ TextThread::flushDelay, FLUSH_DELAY },
|
{ TextThread::flushDelay, FLUSH_DELAY },
|
||||||
{ TextThread::maxHistorySize, MAX_HISTORY_SIZE },
|
{ TextThread::maxHistorySize, MAX_HISTORY_SIZE },
|
||||||
@ -612,7 +614,7 @@ void MainWindow::Extensions()
|
|||||||
void MainWindow::ViewThread(int index)
|
void MainWindow::ViewThread(int index)
|
||||||
{
|
{
|
||||||
ui->ttCombo->setCurrentIndex(index);
|
ui->ttCombo->setCurrentIndex(index);
|
||||||
ui->textOutput->setPlainText(S((current = &Host::GetThread(ParseTextThreadString(ui->ttCombo->itemText(index))))->storage->c_str()));
|
ui->textOutput->setPlainText(sanitize(S((current = &Host::GetThread(ParseTextThreadString(ui->ttCombo->itemText(index))))->storage->c_str())));
|
||||||
ui->textOutput->moveCursor(QTextCursor::End);
|
ui->textOutput->moveCursor(QTextCursor::End);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ public:
|
|||||||
ui.display->setTextFormat(Qt::PlainText);
|
ui.display->setTextFormat(Qt::PlainText);
|
||||||
setGeometry(settings.value(WINDOW, geometry()).toRect());
|
setGeometry(settings.value(WINDOW, geometry()).toRect());
|
||||||
|
|
||||||
for (auto [name, default, slot] : Array<std::tuple<const char*, bool, void(ExtraWindow::*)(bool)>>{
|
for (auto [name, default, slot] : Array<const char*, bool, void(ExtraWindow::*)(bool)>{
|
||||||
{ TOPMOST, false, &ExtraWindow::setTopmost },
|
{ TOPMOST, false, &ExtraWindow::setTopmost },
|
||||||
{ SIZE_LOCK, false, &ExtraWindow::setLock },
|
{ SIZE_LOCK, false, &ExtraWindow::setLock },
|
||||||
{ SHOW_ORIGINAL, true, &ExtraWindow::setShowOriginal },
|
{ SHOW_ORIGINAL, true, &ExtraWindow::setShowOriginal },
|
||||||
@ -187,6 +187,7 @@ public:
|
|||||||
void AddSentence(QString sentence)
|
void AddSentence(QString sentence)
|
||||||
{
|
{
|
||||||
if (!showOriginal) sentence = sentence.section('\n', sentence.count('\n') / 2 + 1);
|
if (!showOriginal) sentence = sentence.section('\n', sentence.count('\n') / 2 + 1);
|
||||||
|
sanitize(sentence);
|
||||||
sentenceHistory.push_back(sentence);
|
sentenceHistory.push_back(sentence);
|
||||||
historyIndex = sentenceHistory.size() - 1;
|
historyIndex = sentenceHistory.size() - 1;
|
||||||
ui.display->setText(sentence);
|
ui.display->setText(sentence);
|
||||||
|
@ -101,7 +101,7 @@ std::wstring GetTranslationUri(const std::wstring& text)
|
|||||||
|
|
||||||
bool IsHash(const std::wstring& result)
|
bool IsHash(const std::wstring& result)
|
||||||
{
|
{
|
||||||
return result.size() == 32 && std::all_of(result.begin(), result.end(), [](auto ch) { return (ch >= L'0' && ch <= L'9') || (ch >= L'a' && ch <= L'z'); });
|
return result.size() == 32 && std::all_of(result.begin(), result.end(), [](char ch) { return (ch >= L'0' && ch <= L'9') || (ch >= L'a' && ch <= L'z'); });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
||||||
|
@ -26,7 +26,12 @@ constexpr bool x64 = true;
|
|||||||
constexpr bool x64 = false;
|
constexpr bool x64 = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T, typename... X> using Array = std::conditional_t<sizeof...(X), std::tuple<T, X...>[], T[]>;
|
template <typename T, typename... Xs>
|
||||||
|
struct ArrayImpl { using type = std::tuple<T, Xs...>[]; };
|
||||||
|
template <typename T>
|
||||||
|
struct ArrayImpl<T> { using type = T[]; };
|
||||||
|
template <typename... Ts>
|
||||||
|
using Array = typename ArrayImpl<Ts...>::type;
|
||||||
|
|
||||||
template <auto F> using Functor = std::integral_constant<std::decay_t<decltype(F)>, F>;
|
template <auto F> using Functor = std::integral_constant<std::decay_t<decltype(F)>, F>;
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
static thread_local bool ok;
|
static thread_local bool ok;
|
||||||
|
|
||||||
struct QTextFile : QFile { QTextFile(QString name, QIODevice::OpenMode mode) : QFile(name) { open(mode | QIODevice::Text); } };
|
struct QTextFile : QFile { QTextFile(QString name, QIODevice::OpenMode mode) : QFile(name) { open(mode | QIODevice::Text); } };
|
||||||
inline std::wstring S(const QString& S) { return { S.toStdWString() }; }
|
inline std::wstring S(const QString& s) { return { s.toStdWString() }; }
|
||||||
inline QString S(const std::string& S) { return QString::fromStdString(S); }
|
inline QString S(const std::string& s) { return QString::fromStdString(s); }
|
||||||
inline QString S(const std::wstring& S) { return QString::fromStdWString(S); }
|
inline QString S(const std::wstring& s) { return QString::fromStdWString(s); }
|
||||||
|
// TODO: allow paired surrogates
|
||||||
|
inline void sanitize(QString& s) { s.chop(std::distance(std::remove_if(s.begin(), s.end(), [](QChar ch) { return ch.isSurrogate(); }), s.end())); }
|
||||||
|
inline QString sanitize(QString&& s) { QString result; for (auto ch : s) if (!ch.isSurrogate()) result.push_back(ch); return result; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user