From 82c8466335e9e6f107bcfffdd576cae6f66023ee Mon Sep 17 00:00:00 2001 From: wingsummer <1326224942@qq.com> Date: Sun, 23 Feb 2025 23:36:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=87=8D=E6=9E=84=E6=9F=A5=E6=89=BE?= =?UTF-8?q?=E5=AF=B9=E8=AF=9D=E6=A1=86=EF=BC=9B=E6=90=9C=E7=B4=A2=E5=AD=97?= =?UTF-8?q?=E8=8A=82=E6=94=AF=E6=8C=81'=3F'=E9=80=9A=E9=85=8D=E7=AC=A6(WIP?= =?UTF-8?q?)=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdparty/QHexView/document/qhexdocument.cpp | 325 ++++++++++- 3rdparty/QHexView/document/qhexdocument.h | 29 +- 3rdparty/QHexView/qhexview.cpp | 8 +- 3rdparty/QHexView/qhexview.h | 4 +- CMakeLists.txt | 3 +- lang/zh_CN/winghex_zh_CN.ts | 614 ++++++++++---------- lang/zh_TW/winghex_zh_TW.ts | 614 ++++++++++---------- src/class/hexstringvalidator.cpp | 55 ++ src/class/hexstringvalidator.h | 32 + src/class/wingangelapi.cpp | 20 +- src/class/wingangelapi.h | 4 +- src/control/editorview.cpp | 15 +- src/dialog/finddialog.cpp | 116 ++-- src/dialog/finddialog.h | 13 +- src/dialog/mainwindow.cpp | 7 +- src/model/findresultmodel.cpp | 2 +- src/model/findresultmodel.h | 4 +- src/plugin/iwingplugin.h | 4 +- src/plugin/pluginsystem.cpp | 12 +- src/utilities.h | 1 + 20 files changed, 1176 insertions(+), 706 deletions(-) create mode 100644 src/class/hexstringvalidator.cpp create mode 100644 src/class/hexstringvalidator.h diff --git a/3rdparty/QHexView/document/qhexdocument.cpp b/3rdparty/QHexView/document/qhexdocument.cpp index f108bd2..c2b132f 100644 --- a/3rdparty/QHexView/document/qhexdocument.cpp +++ b/3rdparty/QHexView/document/qhexdocument.cpp @@ -414,8 +414,8 @@ void QHexDocument::applyBookMarks(const QMap &books) { emit documentChanged(); } -void QHexDocument::findAllBytes(qsizetype begin, qsizetype end, QByteArray b, - QList &results, +void QHexDocument::findAllBytes(qsizetype begin, qsizetype end, + const QByteArray &b, QList &results, const std::function &pred) { results.clear(); if (!b.length()) @@ -424,7 +424,7 @@ void QHexDocument::findAllBytes(qsizetype begin, qsizetype end, QByteArray b, qsizetype e = end > begin ? end : -1; auto offset = b.size(); while (pred()) { - p = m_buffer->indexOf(b, p); + p = findNext(p, b); if (p < 0 || (e > 0 && p > e)) { break; } @@ -434,10 +434,51 @@ void QHexDocument::findAllBytes(qsizetype begin, qsizetype end, QByteArray b, break; } results.append(p); - p += offset + 1; + p += offset; } } +qsizetype QHexDocument::findAllBytesExt(qsizetype begin, qsizetype end, + const QString &pattern, + QList &results, + const std::function &pred) { + results.clear(); + auto patterns = parseConvertPattern(pattern); + if (patterns.isEmpty()) { + return 0; + } + + qsizetype p = begin > 0 ? begin : 0; + qsizetype e = end > begin ? end : -1; + + qsizetype offset = 0; + for (auto &p : patterns) { + if (std::holds_alternative(p)) { + offset += std::get(p).length(); + } else if (std::holds_alternative(p)) { + offset += std::get(p); + } else if (std::holds_alternative(p)) { + offset += 1; + } + } + + while (pred()) { + p = findNextExt(p, pattern); + if (p < 0 || (e > 0 && p > e)) { + break; + } + + if (results.size() == + std::numeric_limits::size_type>::max()) { + break; + } + results.append(p); + p += offset; + } + + return offset; +} + bool QHexDocument::insert(qsizetype offset, uchar b) { if (m_keepsize || m_readonly || m_islocked || (offset < m_buffer->length() && m_metadata->hasMetadata())) @@ -499,6 +540,259 @@ bool QHexDocument::_remove(qsizetype offset, qsizetype len) { return true; } +qsizetype QHexDocument::findNextExt(qsizetype begin, + const QList &patterns) { + auto op = [this](qsizetype &pos, const FindStep &step) -> bool { + if (pos < 0 || pos >= length()) { + return false; + } + if (std::holds_alternative(step)) { + auto v = std::get(step); + auto len = v.length(); + auto r = findNext(pos, v); + if (r >= 0) { + pos = r + len; + return true; + } else { + pos += len; + } + } else if (std::holds_alternative(step)) { + auto v = std::get(step); + auto wc = uchar(at(pos)); + pos += 1; + + if (v.higher == '?') { + if ((wc & 0xf) == v.lower) { + return true; + } + } else { + if ((wc >> 4) == v.higher) { + return true; + } + } + } else if (std::holds_alternative(step)) { + auto v = std::get(step); + pos += v; + if (v + pos < length()) { + return true; + } + } + return false; + }; + + while (begin < length()) { + auto pos = begin; + + auto p = patterns.cbegin(); + auto r = op(pos, *p); + if (!r) { + continue; + } + ++p; + + bool ok = true; + for (; p != patterns.cend(); ++p) { + auto r = op(pos, *p); + if (!r) { + ok = false; + begin = pos; + break; + } + } + + if (ok) { + return begin; + } + } + + return -1; +} + +qsizetype QHexDocument::findPreviousExt(qsizetype begin, + const QList &patterns) { + auto op = [this](qsizetype pos, const FindStep &step, + qsizetype &len) -> bool { + len = 0; + if (pos < 0 || pos >= length()) { + return false; + } + if (std::holds_alternative(step)) { + auto v = std::get(step); + len = v.length(); + if (findPrevious(pos, v) >= 0) { + return true; + } + } else if (std::holds_alternative(step)) { + auto v = std::get(step); + auto wc = uchar(at(pos)); + len = 1; + + if (v.higher == '?') { + if ((wc & 0xf) == v.lower) { + return true; + } + } else { + if ((wc >> 4) == v.higher) { + return true; + } + } + } else if (std::holds_alternative(step)) { + auto v = std::get(step); + len = v; + if (pos - v >= 0) { + return true; + } + } + return false; + }; + + while (begin >= 0) { + auto pos = begin; + + qsizetype len; + auto p = patterns.crbegin(); + auto r = op(pos, *p, len); + if (r) { + pos -= len; + } else { + begin = pos - len; + continue; + } + ++p; + + bool ok = true; + for (; p != patterns.crend(); ++p) { + auto r = op(pos, *p, len); + if (r) { + pos -= len; + } else { + ok = false; + begin = pos; + break; + } + } + + if (ok) { + return begin; + } + } + + return -1; +} + +QList +QHexDocument::parseConvertPattern(const QString &pattern) { + // process hex pattern + QList words; + std::optional higher; + for (auto pchar = pattern.cbegin(); pchar != pattern.cend(); ++pchar) { + if (pchar->isSpace()) { + if (higher) { + return {}; + } else { + continue; + } + } + + auto c = pchar->unicode(); + if (c >= '0' && c <= '9') { + if (higher) { + HexWildItem item; + item.higher = higher.value(); + item.lower = uchar(c) - '0'; + words.append(item); + higher.reset(); + } else { + higher = uchar(c) - '0'; + } + } else if (c >= 'A' && c <= 'F') { + if (higher) { + HexWildItem item; + item.higher = higher.value(); + item.lower = uchar(c) - 'A' + 10; + words.append(item); + higher.reset(); + } else { + higher = uchar(c) - 'A' + 10; + } + } else if (c >= 'a' && c <= 'f') { + if (higher) { + HexWildItem item; + item.higher = higher.value(); + item.lower = uchar(c) - 'a' + 10; + words.append(item); + higher.reset(); + } else { + higher = uchar(c) - 'a' + 10; + } + } else if (c == '?') { + if (higher) { + HexWildItem item; + item.higher = higher.value(); + item.lower = '?'; + words.append(item); + higher.reset(); + } else { + higher = '?'; + } + } + } + + if (higher) { + return {}; + } + + if (!words.isEmpty()) { + QList steps; + + // parsing... + QByteArray buffer; + size_t len = 0; + for (auto pw = words.cbegin(); pw != words.cend(); ++pw) { + auto higher = pw->higher; + auto lower = pw->lower; + if (higher == '?' || lower == '?') { + if (higher == '?' && lower == '?') { + if (!buffer.isEmpty()) { + steps.append(buffer); + buffer.clear(); + } + len++; + } else { + if (len != 0) { + steps.append(len); + len = 0; + } + if (!buffer.isEmpty()) { + steps.append(buffer); + buffer.clear(); + } + HexWildItem item; + item.higher = higher; + item.lower = lower; + steps.append(item); + } + } else { + if (len != 0) { + steps.append(len); + len = 0; + } + buffer.append(char(pw->higher << 4 | pw->lower)); + } + } + + // clean up + if (len != 0) { + steps.append(len); + } + if (!buffer.isEmpty()) { + steps.append(buffer); + } + return steps; + } + return {}; +} + /*======================*/ // modified by wingsummer @@ -728,20 +1022,39 @@ bool QHexDocument::saveTo(QIODevice *device, bool cleanUndo) { return true; } -qsizetype QHexDocument::searchForward(qsizetype begin, const QByteArray &ba) { +qsizetype QHexDocument::findNext(qsizetype begin, const QByteArray &ba) { if (begin < 0) { return -1; } return m_buffer->indexOf(ba, begin); } -qsizetype QHexDocument::searchBackward(qsizetype begin, const QByteArray &ba) { +qsizetype QHexDocument::findPrevious(qsizetype begin, const QByteArray &ba) { if (begin < 0) { return -1; } return m_buffer->lastIndexOf(ba, begin); } +qsizetype QHexDocument::findNextExt(qsizetype begin, const QString &pattern) { + auto patterns = parseConvertPattern(pattern); + if (patterns.isEmpty()) { + return -1; + } + + return findNextExt(begin, patterns); +} + +qsizetype QHexDocument::findPreviousExt(qsizetype begin, + const QString &pattern) { + auto patterns = parseConvertPattern(pattern); + if (patterns.isEmpty()) { + return -1; + } + + return findPreviousExt(begin, patterns); +} + QHexDocument *QHexDocument::fromLargeFile(const QString &filename, bool readonly) { diff --git a/3rdparty/QHexView/document/qhexdocument.h b/3rdparty/QHexView/document/qhexdocument.h index c192b6a..3a509f6 100644 --- a/3rdparty/QHexView/document/qhexdocument.h +++ b/3rdparty/QHexView/document/qhexdocument.h @@ -103,7 +103,13 @@ public: bool existBookMark(qsizetype pos); void findAllBytes( - qsizetype begin, qsizetype end, QByteArray b, QList &results, + qsizetype begin, qsizetype end, const QByteArray &b, + QList &results, + const std::function &pred = [] { return true; }); + + qsizetype findAllBytesExt( + qsizetype begin, qsizetype end, const QString &pattern, + QList &results, const std::function &pred = [] { return true; }); bool isDocSaved(); @@ -179,8 +185,11 @@ public slots: /*================================*/ // added by wingsummer - qsizetype searchForward(qsizetype begin, const QByteArray &ba); - qsizetype searchBackward(qsizetype begin, const QByteArray &ba); + qsizetype findNext(qsizetype begin, const QByteArray &ba); + qsizetype findPrevious(qsizetype begin, const QByteArray &ba); + + qsizetype findNextExt(qsizetype begin, const QString &pattern); + qsizetype findPreviousExt(qsizetype begin, const QString &pattern); bool insert(qsizetype offset, uchar b); bool insert(qsizetype offset, const QByteArray &data); @@ -194,6 +203,20 @@ public slots: bool _replace(qsizetype offset, const QByteArray &data); bool _remove(qsizetype offset, qsizetype len); +private: + // AB + struct HexWildItem { + uchar higher; // A + uchar lower; // B + }; + + // std::variant< find-content, hex with wildcard, all-wildcards > + using FindStep = std::variant; + + QList parseConvertPattern(const QString &pattern); + qsizetype findNextExt(qsizetype begin, const QList &patterns); + qsizetype findPreviousExt(qsizetype begin, const QList &patterns); + /*================================*/ /*================================*/ diff --git a/3rdparty/QHexView/qhexview.cpp b/3rdparty/QHexView/qhexview.cpp index baa1174..e8e95e1 100644 --- a/3rdparty/QHexView/qhexview.cpp +++ b/3rdparty/QHexView/qhexview.cpp @@ -336,21 +336,21 @@ void QHexView::setCopyLimit(qsizetype newCopylimit) { qreal QHexView::scaleRate() const { return m_scaleRate; } -qsizetype QHexView::searchForward(qsizetype begin, const QByteArray &ba) { +qsizetype QHexView::findNext(qsizetype begin, const QByteArray &ba) { if (begin < 0) { begin = m_cursor->position().offset(); } - return m_document->searchForward(begin, ba); + return m_document->findNext(begin, ba); } -qsizetype QHexView::searchBackward(qsizetype begin, const QByteArray &ba) { +qsizetype QHexView::findPrevious(qsizetype begin, const QByteArray &ba) { qsizetype startPos; if (begin < 0) { startPos = m_cursor->position().offset() - 1; } else { startPos = begin; } - return m_document->searchBackward(startPos, ba); + return m_document->findPrevious(startPos, ba); } bool QHexView::RemoveSelection(int nibbleindex) { diff --git a/3rdparty/QHexView/qhexview.h b/3rdparty/QHexView/qhexview.h index 25fc188..9df6973 100644 --- a/3rdparty/QHexView/qhexview.h +++ b/3rdparty/QHexView/qhexview.h @@ -122,8 +122,8 @@ public: void setScaleRate(qreal rate); qreal scaleRate() const; - qsizetype searchForward(qsizetype begin, const QByteArray &ba); - qsizetype searchBackward(qsizetype begin, const QByteArray &ba); + qsizetype findNext(qsizetype begin, const QByteArray &ba); + qsizetype findPrevious(qsizetype begin, const QByteArray &ba); bool RemoveSelection(int nibbleindex = 1); bool removeSelection(); diff --git a/CMakeLists.txt b/CMakeLists.txt index 82a7603..6949bb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,7 +282,8 @@ set(CLASS_SRC src/class/diffutil.cpp src/class/clickcallback.h src/class/crashhandler.h - src/class/crashhandler.cpp) + src/class/crashhandler.cpp + src/class/hexstringvalidator.h src/class/hexstringvalidator.cpp) set(INTERNAL_PLG_SRC src/class/wingangelapi.h src/class/wingangelapi.cpp diff --git a/lang/zh_CN/winghex_zh_CN.ts b/lang/zh_CN/winghex_zh_CN.ts index 88055e4..cc07f70 100644 --- a/lang/zh_CN/winghex_zh_CN.ts +++ b/lang/zh_CN/winghex_zh_CN.ts @@ -392,7 +392,7 @@ 书签 - + Untitled 未命名 @@ -476,50 +476,60 @@ FindDialog - - findstring - 字符串 + + Mode: + 模式: - - findhex - 十六进制 + + Content: + 内容: - + + EncBytes: + 解码: + + + Region: 搜索区域: - + None 全局搜索 - + Region 区域 - + BeforeCursor 光标前搜索 - + AfterCursor 光标后搜索 - + Selection 选区搜索 - + find 查找 + + + InvalidHexSeq + + FindResultModel @@ -810,7 +820,7 @@ - + View 视图 @@ -847,8 +857,8 @@ - - + + Plugin 插件 @@ -859,7 +869,7 @@ - + Log 日志 @@ -875,308 +885,308 @@ - + FindResult 搜索结果 - - - - - - + + + + + + Copy 复制 - - - - - - - + + + + + + + CopyToClipBoard 数据已拷贝到粘贴板 - + LittleEndian 小端 - + BigEndian 大端 - + Number 数值 - - + + CheckSum 校验和 - - + + DeleteBookMark 删除书签 - - + + ClearBookMark 清空书签 - - - - + + + + BookMark 书签 - - + + DecodeText 解码字符串 - + ScriptConsole 脚本控制台 - - + + DVList 可视化列表 - - + + DVTree 可视化树数据 - - + + DVTable 可视化表格 - - + + DVText 可视化文本 - - + + Basic 基础 - + New 新建 - + OpenF 打开文件 - + OpenWorkSpace 打开工作区 - + RecentFiles 最近打开 - + Reload 重新加载 - - + + Save 保存 - + SaveAs 另存为 - + ConvertWS 转为工作区 - + Export 导出 - + SaveSel 保存选区字节 - - - - + + + + General 基本 - + Undo 撤销 - + Redo 恢复 - + Cut 剪切 - + Paste 粘贴 - + Delete 删除 - + Clone 克隆 - + Lookup 查询 - + Find 查找 - + Goto 跳转 - + Encoding 编码 - + FileInfo 文件信息 - - + + Hex 十六进制 - + CutHex 剪切(十六进制) - + CopyHex 复制(十六进制) - + PasteHex 粘贴(十六进制) - - + + Fill 填充 - + FillZero 填充零 - - - - - + + + + + MetaData 标注 - + DeleteMetadata 删除标注 - + ClearMetadata 清空标注 - + MetaDataEdit 编辑标注 - + DeleteMetaData 删除标注 - + ClearMetaData 清空标注 - + Display 显示 - + ViewText 文本预览 - + Scale 缩放 @@ -1261,731 +1271,731 @@ 无扩展 - - - - - - + + + + + + ExportResult 导出结果 - - - + + + NothingToSave 没有保存的数据 - - - - + + + + ClearResult 清空结果 - + OpenExt 打开 - 拓展 - + ResetScale 重置缩放 - + ShowMetafg 标注前景色 - + ShowMetabg 标注背景色 - + ShowMetaComment 批注 - + MetaShowAll 显示所有标注 - + MetaHideAll 隐藏所有标注 - + FileStatus 文件状态 - + InfoSave 是否保存 - + ReadOnly 可读写 - + SetLocked 启用/禁用锁定编辑 - + ErrUnLock 锁定编辑失败 - + SetOver 启用/禁用改变大小 - + ErrUnOver 锁定文件大小失败 - + Window 窗体 - + Editor 编辑器 - + Tools 工具 - + HexEditorLayout 编辑器布局 - + SetBaseAddr 设置基址 - + addressBase 基址 - + inputAddressBase 请输入基址 - + WarnBigBaseAddress 基址过大,你得到的地址将会不正确! - + ErrBaseAddress 非法基址输入 - + SetColInfo 显示/隐藏地址栏 - + SetHeaderInfo 显示/隐藏表头 - + SetAsciiString 显示/隐藏解码字符串 - + Layout 布局 - + Fullscreen 全屏 - + Default 默认 - - - + + + LayoutRestoring... 恢复布局中... - + RestoreLayout 恢复布局 - - + + SaveLayout 保存布局 - + ExportLog 导出日志 - + ClearLog 清空日志 - + ScriptEditor 脚本编辑器 - + Scripts 脚本仓库 - + PluginFunctions 插件功能 - + ScriptSetting 脚本设置 - + PluginSettings 插件设置 - + Info 信息 - + Software 软件 - + Sponsor 赞助 - + CheckUpdate 检查更新 - + Wiki 网页 Wiki - + AboutQT 关于 QT - + SetPageIDEmptyTryUseName 设置页 ID 为空,尝试使用名称作为 ID - + SetPageDupNameIgnored 设置页重复的 ID 名称,已忽略加载 - + Plugin %1 contains a duplicate ID (%2) that is already registered by plugin %3 插件 %1 包含重复 ID (%2),该 ID 已被插件 %3 注册 - - + + ChooseFile 选择文件 - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + Error 错误 - - + + FileNotExist 文件不存在! - - - - - - - - + + + + + + + + FilePermission 因文件权限无法继续! - + ProjectFile (*.wingpro) 项目文件 (*.wingpro) - + ReloadSuccessfully 文件重新加载成功! - + ReloadUnSuccessfully 文件重新加载失败! - - - - - - - + + + + + + + ChooseSaveFile 请选择保存文件路径: - + NoMoreClone 克隆已到上限,无法继续操作! - + FindFininishBusy 查找任务繁忙,请勿重复查找! - + MayTooMuchFindResult 搜索数量已到达上限,结果可能不全,建议请按区段搜索。 - + SaveLayoutSuccess 保存布局成功 - + SaveLayoutError 保存布局失败 - + HasClonedView 该编辑页已被克隆编辑,如果关闭,相关联的页也会被关闭,你确认继续吗? - + SaveWorkSpace 保存工作区 - + WingHexWorkSpace (*.wingpro) 羽云十六进制工作区 (*.wingpro) - + ConfirmSave 正在关闭未保存的文件或工作区,你确定保存吗? - + Column %1 列 %1 - + ConfirmAPPSave 你尝试关闭程序,但仍存在未保存的文件或工作区,你确定保存这些更改吗? - - - - - - + + + + + + SaveSuccessfully 保存成功! - - + + SaveWSError 保存工作区错误! - + Warn 警告 - + ScriptObjShow 脚本对象 - + Opening... 打开文件中... - + WorkSpaceOpening... 打开工作区中... - + Reloading... 重载文件中... - + Saving... 保存中... - + SaveNewFirst 请首先保存新建的文件 - + AlreadyWorkSpace 已经是工作区,无需转化 - + ConvWorkSpaceFailed 转化为工作区失败 - + ConvWorkSpaceSuccess 转化为工作区成功 - + SavingAs... 另存为中... - + SaveUnSuccessfully 保存失败! - + Exporting... 导出中... - + ChooseExportFile 请选择导出文件路径: - + ExportSuccessfully 导出成功! - + ExportUnSuccessfully 导出失败! - + SavingSel... 保存选中字节中... - + SaveSelSuccess 保存选区字节成功! - + SaveSelError 保存选区字节失败,因文件不具有可写权限! - - + + CutToClipBoard 数据已剪切到粘贴板! - - + + UnCutToClipBoard 由于保持大小限制,数据剪切到粘贴板失败! - - + + UnCopyToClipBoard 由于保持大小限制,数据剪切到复制板失败! - - + + Finding... 查找中... - + DeleteSuccess 删除成功 - + DeleteFailed 删除失败 - + FindFininish 查找结果完毕! - + PleaseInputFill 请输入填充字节值 - + FillInputTruncWarn 填充输入数值过大,将会被截断填充 - + FillInputError 填充字节输入错误 - - + + InputComment 请输入批注: - - + + BookmarkDelSuccess 删除书签成功 - + BookmarkDelNoItem 无书签可删除 - + BookmarkClearSuccess 书签清空完毕 - - - + + + NoSelection 没有选区,无法继续的操作! - + NoMetaData 无可编辑标记 - + PleaseClearSel 请清空选择 - + MetaDelSuccess 元数据删除成功 - + MetaDelNoItem 无元数据可删除 - + MetaClearSuccess 元数据清空完毕 - + FindResultExporting... 查找结果导出中... - - + + EmptyFindResult 没有可导出的搜索结果! - + SaveFindResult 导出搜索结果成功! - + SaveFindResultError 导出结果失败! - + TooManyBytesDecode 超出解码字节限制…… - + LayoutSaving... 布局保存中... - + PleaseInput 请输入 - + LogExporting... 日志导出中... - + ExportLogError 导出日志失败! - + ExportLogSuccess 导出日志成功,路径: - + ClearLogSuccess 清空日志成功! - + BadNetwork 无法与远程服务器的更新检查建立连接,请检查网络。 - + NewestVersion 当前软件为最新版本 - + OlderVersion 你使用的软件为老版本,建议到 Github 和 Gitee 的仓库发行版下载更新。 - + CheckingUpdate 检查更新中…… - + Too much opened files 打开的文件过多,无法继续操作! - + FilePermissionSure2Quit 因文件权限无法保存,你确认要退出吗? - + UnknownErrorSure2Quit 因未知错误无法保存,你确认要退出吗? - + WorkSpaceUnSavedSure2Quit 工作区文件无法保存,你确认要退出吗? - + CopyLimit 拷贝字节超出限制 - + ErrOpenFileBelow 打开文件出现错误(由于权限不足),如下为打开错误的文件: @@ -2427,7 +2437,7 @@ QApplication - + OptionNeedRestart 该设置需要程序重启后生效 diff --git a/lang/zh_TW/winghex_zh_TW.ts b/lang/zh_TW/winghex_zh_TW.ts index 6a7d6f7..013b35e 100644 --- a/lang/zh_TW/winghex_zh_TW.ts +++ b/lang/zh_TW/winghex_zh_TW.ts @@ -392,7 +392,7 @@ 書簽 - + Untitled 未命名 @@ -476,50 +476,60 @@ FindDialog - - findstring - 字串 + + Mode: + 模式: - - findhex - 十六進制 + + Content: + 內容: - + + EncBytes: + 解碼: + + + Region: 搜索區域: - + None 全局搜索 - + Region 區域 - + BeforeCursor 游標前搜索 - + AfterCursor 游標後搜索 - + Selection 選區搜索 - + find 查找 + + + InvalidHexSeq + + FindResultModel @@ -810,7 +820,7 @@ - + View 視圖 @@ -847,8 +857,8 @@ - - + + Plugin 插件 @@ -859,7 +869,7 @@ - + Log 日誌 @@ -875,308 +885,308 @@ - + FindResult 搜索結果 - - - - - - + + + + + + Copy 複製 - - - - - - - + + + + + + + CopyToClipBoard 數據已拷貝到粘貼板 - + LittleEndian 小端 - + BigEndian 大端 - + Number 數值 - - + + CheckSum 校驗和 - - + + DeleteBookMark 刪除書簽 - - + + ClearBookMark 清空書簽 - - - - + + + + BookMark 書簽 - - + + DecodeText 解碼字串 - + ScriptConsole 腳本控制臺 - - + + DVList 可視化列表 - - + + DVTree 可視化樹數據 - - + + DVTable 可視化表格 - - + + DVText 可視化文本 - - + + Basic 基礎 - + New 新建 - + OpenF 打開檔 - + OpenWorkSpace 打開工作區 - + RecentFiles 最近打開 - + Reload 重新加載 - - + + Save 保存 - + SaveAs 另存為 - + ConvertWS 轉為工作區 - + Export 導出 - + SaveSel 保存選區位元組 - - - - + + + + General 基本 - + Undo 撤銷 - + Redo 恢復 - + Cut 剪切 - + Paste 粘貼 - + Delete 刪除 - + Clone 克隆 - + Lookup 查詢 - + Find 查找 - + Goto 跳轉 - + Encoding 編碼 - + FileInfo 檔資訊 - - + + Hex 十六進制 - + CutHex 剪切(十六進制) - + CopyHex 複製(十六進制) - + PasteHex 粘貼(十六進制) - - + + Fill 填充 - + FillZero 填充零 - - - - - + + + + + MetaData 標注 - + DeleteMetadata 刪除標注 - + ClearMetadata 清空標注 - + MetaDataEdit 編輯標注 - + DeleteMetaData 刪除標注 - + ClearMetaData 清空標注 - + Display 顯示 - + ViewText 文本預覽 - + Scale 縮放 @@ -1261,731 +1271,731 @@ 無擴展 - - - - - - + + + + + + ExportResult 導出結果 - - - + + + NothingToSave 沒有保存的數據 - - - - + + + + ClearResult 清空結果 - + OpenExt 打開 - 拓展 - + ResetScale 重置縮放 - + ShowMetafg 標注前景色 - + ShowMetabg 標注背景色 - + ShowMetaComment 批註 - + MetaShowAll 顯示所有標注 - + MetaHideAll 隱藏所有標注 - + FileStatus 檔狀態 - + InfoSave 是否保存 - + ReadOnly 可讀寫 - + SetLocked 啟用/禁用鎖定編輯 - + ErrUnLock 鎖定編輯失敗 - + SetOver 啟用/禁用改變大小 - + ErrUnOver 鎖定檔大小失敗 - + Window 窗體 - + Editor 編輯器 - + Tools 工具 - + HexEditorLayout 編輯器佈局 - + SetBaseAddr 設置基址 - + addressBase 基址 - + inputAddressBase 請輸入基址 - + WarnBigBaseAddress 基址過大,你得到的地址將會不正確! - + ErrBaseAddress 非法基址輸入 - + SetColInfo 顯示/隱藏地址欄 - + SetHeaderInfo 顯示/隱藏表頭 - + SetAsciiString 顯示/隱藏解碼字串 - + Layout 佈局 - + Fullscreen 全屏 - + Default 默認 - - - + + + LayoutRestoring... 恢復佈局中... - + RestoreLayout 恢復佈局 - - + + SaveLayout 保存佈局 - + ExportLog 導出日誌 - + ClearLog 清空日誌 - + ScriptEditor 腳本編輯器 - + Scripts 腳本倉庫 - + PluginFunctions 插件功能 - + ScriptSetting 腳本設置 - + PluginSettings 插件設置 - + Info 資訊 - + Software 軟體 - + Sponsor 贊助 - + CheckUpdate 檢查更新 - + Wiki 網頁 Wiki - + AboutQT 關於 QT - + SetPageIDEmptyTryUseName 設置頁 ID 為空,嘗試使用名稱作為 ID - + SetPageDupNameIgnored 設置頁重複的 ID 名稱,已忽略加載 - + Plugin %1 contains a duplicate ID (%2) that is already registered by plugin %3 插件 %1 包含重複 ID (%2),該 ID 已被插件 %3 註冊 - - + + ChooseFile 選擇檔 - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + Error 錯誤 - - + + FileNotExist 檔不存在! - - - - - - - - + + + + + + + + FilePermission 因檔許可權無法繼續! - + ProjectFile (*.wingpro) 專案檔 (*.wingpro) - + ReloadSuccessfully 檔重新加載成功! - + ReloadUnSuccessfully 檔重新加載失敗! - - - - - - - + + + + + + + ChooseSaveFile 請選擇保存檔路徑: - + NoMoreClone 克隆已到上限,無法繼續操作! - + FindFininishBusy 查找任務繁忙,請勿重複查找! - + MayTooMuchFindResult 搜索數量已到達上限,結果可能不全,建議請按區段搜索。 - + SaveLayoutSuccess 保存佈局成功 - + SaveLayoutError 保存佈局失敗 - + HasClonedView 該編輯頁已被克隆編輯,如果關閉,相關聯的頁也會被關閉,你確認繼續嗎? - + SaveWorkSpace 保存工作區 - + WingHexWorkSpace (*.wingpro) 羽雲十六進制工作區 (*.wingpro) - + ConfirmSave 正在關閉未保存的檔或工作區,你確定保存嗎? - + Column %1 列 %1 - + ConfirmAPPSave 你嘗試關閉程式,但仍存在未保存的檔或工作區,你確定保存這些更改嗎? - - - - - - + + + + + + SaveSuccessfully 保存成功! - - + + SaveWSError 保存工作區錯誤! - + Warn 警告 - + ScriptObjShow 腳本對象 - + Opening... 打開檔中... - + WorkSpaceOpening... 打開工作區中... - + Reloading... 重載檔中... - + Saving... 保存中... - + SaveNewFirst 請首先保存新建的檔 - + AlreadyWorkSpace 已經是工作區,無需轉化 - + ConvWorkSpaceFailed 轉化為工作區失敗 - + ConvWorkSpaceSuccess 轉化為工作區成功 - + SavingAs... 另存為中... - + SaveUnSuccessfully 保存失敗! - + Exporting... 導出中... - + ChooseExportFile 請選擇導出檔路徑: - + ExportSuccessfully 導出成功! - + ExportUnSuccessfully 導出失敗! - + SavingSel... 保存選中位元組中... - + SaveSelSuccess 保存選區位元組成功! - + SaveSelError 保存選區位元組失敗,因檔不具有可寫許可權! - - + + CutToClipBoard 數據已剪切到粘貼板! - - + + UnCutToClipBoard 由於保持大小限制,數據剪切到粘貼板失敗! - - + + UnCopyToClipBoard 由於保持大小限制,數據剪切到複製板失敗! - - + + Finding... 查找中... - + DeleteSuccess 刪除成功 - + DeleteFailed 刪除失敗 - + FindFininish 查找結果完畢! - + PleaseInputFill 請輸入填充位元組值 - + FillInputTruncWarn 填充輸入數值過大,將會被截斷填充 - + FillInputError 填充位元組輸入錯誤 - - + + InputComment 請輸入批註: - - + + BookmarkDelSuccess 刪除書簽成功 - + BookmarkDelNoItem 無書簽可刪除 - + BookmarkClearSuccess 書簽清空完畢 - - - + + + NoSelection 沒有選區,無法繼續的操作! - + NoMetaData 無可編輯標記 - + PleaseClearSel 請清空選擇 - + MetaDelSuccess 元數據刪除成功 - + MetaDelNoItem 無元數據可刪除 - + MetaClearSuccess 元數據清空完畢 - + FindResultExporting... 查找結果導出中... - - + + EmptyFindResult 沒有可導出的搜索結果! - + SaveFindResult 導出搜索結果成功! - + SaveFindResultError 導出結果失敗! - + TooManyBytesDecode 超出解碼位元組限制…… - + LayoutSaving... 佈局保存中... - + PleaseInput 請輸入 - + LogExporting... 日誌導出中... - + ExportLogError 導出日誌失敗! - + ExportLogSuccess 導出日誌成功,路徑: - + ClearLogSuccess 清空日誌成功! - + BadNetwork 無法與遠程伺服器的更新檢查建立連接,請檢查網路。 - + NewestVersion 當前軟體為最新版本 - + OlderVersion 你使用的軟體為老版本,建議到 Github 和 Gitee 的倉庫發行版下載更新。 - + CheckingUpdate 檢查更新中…… - + Too much opened files 打開的檔過多,無法繼續操作! - + FilePermissionSure2Quit 因檔許可權無法保存,你確認要退出嗎? - + UnknownErrorSure2Quit 因未知錯誤無法保存,你確認要退出嗎? - + WorkSpaceUnSavedSure2Quit 工作區檔無法保存,你確認要退出嗎? - + CopyLimit 拷貝位元組超出限制 - + ErrOpenFileBelow 打開檔出現錯誤(由於許可權不足),如下為打開錯誤的檔: @@ -2427,7 +2437,7 @@ QApplication - + OptionNeedRestart 該設置需要程式重啟後生效 diff --git a/src/class/hexstringvalidator.cpp b/src/class/hexstringvalidator.cpp new file mode 100644 index 0000000..715f2c4 --- /dev/null +++ b/src/class/hexstringvalidator.cpp @@ -0,0 +1,55 @@ +/*============================================================================== +** Copyright (C) 2024-2027 WingSummer +** +** This program is free software: you can redistribute it and/or modify it under +** the terms of the GNU Affero General Public License as published by the Free +** Software Foundation, version 3. +** +** This program is distributed in the hope that it will be useful, but WITHOUT +** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +** details. +** +** You should have received a copy of the GNU Affero General Public License +** along with this program. If not, see . +** ============================================================================= +*/ + +#include "hexstringvalidator.h" + +#include + +HexStringValidator::HexStringValidator(QObject *parent) : QValidator(parent) {} + +QValidator::State HexStringValidator::validate(QString &input, int &pos) const { + const QChar space = QLatin1Char(' '); + QString data = input; + data.remove(space); + + if (data.isEmpty()) + return Intermediate; + + // limit maximum size and forbid trailing spaces + if (input.endsWith(space)) + return Invalid; + + // check if all input is valid + static const QRegularExpression re(QStringLiteral("^[[:xdigit:]?]*$")); + auto m = re.match(data); + if (!m.hasMatch()) + return Invalid; + + // insert a space after every two hex nibbles + static const QRegularExpression insertSpace( + QStringLiteral("(?:[[:xdigit:]?]{2} )*[[:xdigit:]?]{3}")); + + m = insertSpace.match(input); + if (m.hasMatch()) { + input.insert(input.size() - 1, space); + pos = input.size(); + } + + input = input.toUpper(); + + return Acceptable; +} diff --git a/src/class/hexstringvalidator.h b/src/class/hexstringvalidator.h new file mode 100644 index 0000000..4a86661 --- /dev/null +++ b/src/class/hexstringvalidator.h @@ -0,0 +1,32 @@ +/*============================================================================== +** Copyright (C) 2024-2027 WingSummer +** +** This program is free software: you can redistribute it and/or modify it under +** the terms of the GNU Affero General Public License as published by the Free +** Software Foundation, version 3. +** +** This program is distributed in the hope that it will be useful, but WITHOUT +** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +** details. +** +** You should have received a copy of the GNU Affero General Public License +** along with this program. If not, see . +** ============================================================================= +*/ + +#ifndef HEXSTRINGVALIDATOR_H +#define HEXSTRINGVALIDATOR_H + +#include +#include + +class HexStringValidator : public QValidator { + Q_OBJECT +public: + explicit HexStringValidator(QObject *parent = nullptr); + + QValidator::State validate(QString &input, int &pos) const override; +}; + +#endif // HEXSTRINGVALIDATOR_H diff --git a/src/class/wingangelapi.cpp b/src/class/wingangelapi.cpp index 18d3523..fe765da 100644 --- a/src/class/wingangelapi.cpp +++ b/src/class/wingangelapi.cpp @@ -775,15 +775,15 @@ void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) { registerAPI( engine, - std::bind(&WingAngelAPI::_HexReader_searchForward, this, + std::bind(&WingAngelAPI::_HexReader_findNext, this, std::placeholders::_1, std::placeholders::_2), - QSIZETYPE_WRAP("searchForward(" QSIZETYPE " begin, byte[] &in ba)")); + QSIZETYPE_WRAP("findNext(" QSIZETYPE " begin, byte[] &in ba)")); registerAPI( engine, - std::bind(&WingAngelAPI::_HexReader_searchBackward, this, + std::bind(&WingAngelAPI::_HexReader_findPrevious, this, std::placeholders::_1, std::placeholders::_2), - QSIZETYPE_WRAP("searchBackward(" QSIZETYPE " begin, byte[] &in ba)")); + QSIZETYPE_WRAP("findPrevious(" QSIZETYPE " begin, byte[] &in ba)")); registerAPI( engine, @@ -2374,8 +2374,8 @@ CScriptArray *WingAngelAPI::_HexReader_readBytes(qsizetype offset, }); } -qsizetype WingAngelAPI::_HexReader_searchForward(qsizetype begin, - const CScriptArray &ba) { +qsizetype WingAngelAPI::_HexReader_findNext(qsizetype begin, + const CScriptArray &ba) { // If called from the script, there will always be an active // context, which can be used to obtain a pointer to the engine. asIScriptContext *ctx = asGetActiveContext(); @@ -2386,14 +2386,14 @@ qsizetype WingAngelAPI::_HexReader_searchForward(qsizetype begin, auto byteID = engine->GetTypeIdByDecl("byte"); Q_ASSERT(byteID); auto bab = cArray2ByteArray(ba, byteID, &ok); - return emit reader.searchForward(begin, bab); + return emit reader.findNext(begin, bab); } else { return qsizetype(-1); } } -qsizetype WingAngelAPI::_HexReader_searchBackward(qsizetype begin, - const CScriptArray &ba) { +qsizetype WingAngelAPI::_HexReader_findPrevious(qsizetype begin, + const CScriptArray &ba) { // If called from the script, there will always be an active // context, which can be used to obtain a pointer to the engine. asIScriptContext *ctx = asGetActiveContext(); @@ -2404,7 +2404,7 @@ qsizetype WingAngelAPI::_HexReader_searchBackward(qsizetype begin, auto byteID = engine->GetTypeIdByDecl("byte"); auto bab = cArray2ByteArray(ba, byteID, &ok); if (ok) { - return emit reader.searchBackward(begin, bab); + return emit reader.findPrevious(begin, bab); } else { return qsizetype(-1); } diff --git a/src/class/wingangelapi.h b/src/class/wingangelapi.h index 1e82866..733bd60 100644 --- a/src/class/wingangelapi.h +++ b/src/class/wingangelapi.h @@ -223,9 +223,9 @@ private: CScriptArray *_HexReader_readBytes(qsizetype offset, qsizetype len); - qsizetype _HexReader_searchForward(qsizetype begin, const CScriptArray &ba); + qsizetype _HexReader_findNext(qsizetype begin, const CScriptArray &ba); - qsizetype _HexReader_searchBackward(qsizetype begin, + qsizetype _HexReader_findPrevious(qsizetype begin, const CScriptArray &ba); CScriptArray *_HexReader_findAllBytes(qsizetype begin, qsizetype end, diff --git a/src/control/editorview.cpp b/src/control/editorview.cpp index ba12df7..6dfcc3d 100644 --- a/src/control/editorview.cpp +++ b/src/control/editorview.cpp @@ -204,17 +204,20 @@ EditorView::FindError EditorView::find(const FindDialog::Result &result) { } break; } - QByteArray data; + QString data; + data = result.str; + + qsizetype contextLen = 0; if (result.isStringFind) { - data = Utilities::encodingString(result.str, result.encoding); + auto raw = Utilities::encodingString(data, result.encoding); + contextLen = raw.length(); m_findResults->setEncoding(result.encoding); + d->findAllBytes(begin, end, raw, results); } else { - data = result.buffer; + contextLen = d->findAllBytesExt(begin, end, result.str, results); } - d->findAllBytes(begin, end, data, results); - m_findResults->beginUpdate(); m_findResults->clear(); @@ -226,7 +229,7 @@ EditorView::FindError EditorView::find(const FindDialog::Result &result) { r.col = r.offset % lineWidth; m_findResults->results().append(r); m_findResults->findData().append( - readContextFinding(ritem, data.size(), FIND_CONTEXT_SIZE, + readContextFinding(ritem, contextLen, FIND_CONTEXT_SIZE, FIND_MAX_DISPLAY_FIND_CHARS)); } diff --git a/src/dialog/finddialog.cpp b/src/dialog/finddialog.cpp index f529cf9..8ac059d 100644 --- a/src/dialog/finddialog.cpp +++ b/src/dialog/finddialog.cpp @@ -25,60 +25,71 @@ #include #include +#include "control/toast.h" + FindDialog::FindDialog(const FindInfo &info, QWidget *parent) : FramelessDialogBase(parent) { + _hexvalidator = new HexStringValidator(this); + auto widget = new QWidget(this); auto layout = new QVBoxLayout(widget); - m_string = new QRadioButton(this); - m_string->setText(tr("findstring")); - layout->addWidget(m_string); - layout->addSpacing(3); - - m_encodings = new QComboBox(this); - m_encodings->addItems(Utilities::getEncodings()); - m_encodings->setCurrentIndex(0); - m_encodings->setEnabled(false); - connect(m_string, &QRadioButton::toggled, m_encodings, - &QComboBox::setEnabled); - layout->addWidget(m_encodings); + layout->addWidget(new QLabel(tr("Mode:"), this)); + m_findMode = new QComboBox(this); + m_findMode->addItem(QStringLiteral("HEX")); + m_findMode->addItems(Utilities::getEncodings()); + m_findMode->setCurrentIndex(1); + + layout->addWidget(m_findMode); layout->addSpacing(3); + layout->addWidget(new QLabel(tr("Content:"), this)); m_lineeditor = new QLineEdit(this); - m_lineeditor->setEnabled(false); - connect(m_string, &QRadioButton::toggled, m_lineeditor, - &QLineEdit::setEnabled); layout->addWidget(m_lineeditor); layout->addSpacing(3); - m_hex = new QRadioButton(this); - m_hex->setText(tr("findhex")); - layout->addWidget(m_hex); - layout->addSpacing(3); + layout->addWidget(new QLabel(tr("EncBytes:"), this)); + m_preview = new QTextEdit(this); + m_preview->setFocusPolicy(Qt::NoFocus); + m_preview->setReadOnly(true); + m_preview->setUndoRedoEnabled(false); + m_preview->setWordWrapMode(QTextOption::WordWrap); + m_preview->setAcceptRichText(false); + m_preview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + layout->addWidget(m_preview); - m_hexeditor = new QHexView(this); - m_hexeditor->setAsciiVisible(false); - m_hexeditor->setAddressVisible(false); - m_hexeditor->setEnabled(true); - connect(m_hex, &QRadioButton::toggled, m_hexeditor, &QHexView::setEnabled); - layout->addWidget(m_hexeditor); - layout->addSpacing(10); + connect(m_lineeditor, &QLineEdit::textChanged, this, + [this](const QString &text) { + if (m_findMode->currentIndex()) { + auto encoding = m_findMode->currentText(); + auto dbytes = Utilities::encodingString(text, encoding); + m_preview->setText(dbytes.toHex(' ')); + } else { + m_preview->setText(text); + } + }); + connect(m_findMode, &QComboBox::currentIndexChanged, this, + [this](int index) { + auto oldva = m_lineeditor->validator(); + auto newva = index > 0 ? nullptr : _hexvalidator; + m_lineeditor->setValidator(newva); + if (oldva != newva) { + m_lineeditor->clear(); + } else { + // force update + emit m_lineeditor->textChanged(m_lineeditor->text()); + } + }); if (info.isStringFind) { - m_string->setChecked(true); - m_lineeditor->setEnabled(true); - m_hexeditor->setEnabled(false); if (!info.encoding.isEmpty()) { - m_encodings->setCurrentText(info.encoding); + m_findMode->setCurrentText(info.encoding); } } else { - m_hex->setChecked(true); - m_lineeditor->setEnabled(false); - m_hexeditor->setEnabled(true); + m_findMode->setCurrentIndex(0); } m_lineeditor->setText(info.str); - m_hexeditor->document()->_insert(0, info.buffer); auto regionw = new QWidget(this); auto regionLayout = new QHBoxLayout(regionw); @@ -106,8 +117,6 @@ FindDialog::FindDialog(const FindInfo &info, QWidget *parent) m_regionStop->setPrefix(QStringLiteral("0x")); regionLayout->addWidget(m_regionStop, 1); - layout->addWidget(regionw); - auto group = new QButtonGroup(this); group->setExclusive(true); @@ -134,8 +143,8 @@ FindDialog::FindDialog(const FindInfo &info, QWidget *parent) if (b) { _result.dir = SearchDirection::Region; } - m_regionStart->setEnabled(b); - m_regionStop->setEnabled(b); + regionw->setVisible(b); + regionw->setEnabled(b); }); group->addButton(b, id++); buttonLayout->addWidget(b); @@ -177,7 +186,7 @@ FindDialog::FindDialog(const FindInfo &info, QWidget *parent) group->button(info.isBigFile ? 1 : 0)->setChecked(true); layout->addWidget(btnBox); - layout->addSpacing(20); + auto dbbox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(dbbox, &QDialogButtonBox::accepted, this, &FindDialog::on_accept); @@ -185,25 +194,42 @@ FindDialog::FindDialog(const FindInfo &info, QWidget *parent) auto key = QKeySequence(Qt::Key_Return); auto s = new QShortcut(key, this); connect(s, &QShortcut::activated, this, &FindDialog::on_accept); + + layout->addWidget(regionw); + regionw->hide(); + + layout->addSpacing(20); layout->addWidget(dbbox); buildUpContent(widget); this->setWindowTitle(tr("find")); + + m_lineeditor->setFocus(); } FindDialog::Result FindDialog::getResult() const { return _result; } void FindDialog::on_accept() { - _result.start = 0; - _result.stop = 0; + _result.isStringFind = m_findMode->currentIndex() > 0; + _result.str = m_lineeditor->text(); + + if (!_result.isStringFind) { + // check the last byte nibbles + if (std::next(_result.str.rbegin())->isSpace()) { + Toast::toast(this, NAMEICONRES("find"), tr("InvalidHexSeq")); + return; + } + } + if (m_regionStart->isEnabled()) { _result.start = m_regionStart->value(); _result.stop = m_regionStop->value(); + } else { + _result.start = 0; + _result.stop = 0; } - _result.encoding = m_encodings->currentText(); - _result.isStringFind = m_string->isChecked(); - _result.buffer = m_hexeditor->document()->read(0); - _result.str = m_lineeditor->text(); + + _result.encoding = m_findMode->currentText(); done(1); } diff --git a/src/dialog/finddialog.h b/src/dialog/finddialog.h index 7170547..0b656fd 100644 --- a/src/dialog/finddialog.h +++ b/src/dialog/finddialog.h @@ -18,14 +18,16 @@ #ifndef FINDDIALOG_H #define FINDDIALOG_H -#include "QHexView/qhexview.h" #include "control/qtlonglongspinbox.h" #include "framelessdialogbase.h" +#include "class/hexstringvalidator.h" + #include #include #include #include +#include enum class SearchDirection { None, Region, Foreword, Backword, Selection }; @@ -39,7 +41,6 @@ public: // for searching info bool isStringFind; - QByteArray buffer; QString encoding; QString str; }; @@ -66,11 +67,11 @@ private: void on_reject(); private: - QHexView *m_hexeditor; QLineEdit *m_lineeditor; - QRadioButton *m_string; - QRadioButton *m_hex; - QComboBox *m_encodings; + QComboBox *m_findMode; + QTextEdit *m_preview; + + HexStringValidator *_hexvalidator; QtLongLongSpinBox *m_regionStart; QtLongLongSpinBox *m_regionStop; diff --git a/src/dialog/mainwindow.cpp b/src/dialog/mainwindow.cpp index 23c61b7..d209644 100644 --- a/src/dialog/mainwindow.cpp +++ b/src/dialog/mainwindow.cpp @@ -661,9 +661,6 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock, m_findresult->setModel(_findEmptyResult); m_findEncoding.value(_findEmptyResult->encoding())->setChecked(true); - header->setSectionResizeMode(3, QHeaderView::Stretch); - header->setSectionResizeMode(4, QHeaderView::Stretch); - connect(m_findresult, &QTableView::doubleClicked, this, [=](const QModelIndex &index) { auto editor = @@ -2301,7 +2298,6 @@ void MainWindow::on_findfile() { auto r = fd.getResult(); info.isStringFind = r.isStringFind; info.encoding = r.encoding; - info.buffer = r.buffer; info.str = r.str; ExecAsync( @@ -2775,8 +2771,7 @@ void MainWindow::on_exportfindresult() { auto d = findresitem->lastFindData(); - fobj.insert(QStringLiteral("find"), - QString::fromLatin1(d.toHex(' ').toUpper())); + fobj.insert(QStringLiteral("find"), d); QJsonArray arr; for (int i = 0; i < c; i++) { auto data = findresitem->resultAt(i); diff --git a/src/model/findresultmodel.cpp b/src/model/findresultmodel.cpp index d52758d..a10afef 100644 --- a/src/model/findresultmodel.cpp +++ b/src/model/findresultmodel.cpp @@ -133,7 +133,7 @@ QList &FindResultModel::findData() { return m_findData; } -QByteArray &FindResultModel::lastFindData() { return m_lastFindData; } +QString &FindResultModel::lastFindData() { return m_lastFindData; } void FindResultModel::beginUpdate() { this->beginResetModel(); } diff --git a/src/model/findresultmodel.h b/src/model/findresultmodel.h index 57f7ebb..3b35d94 100644 --- a/src/model/findresultmodel.h +++ b/src/model/findresultmodel.h @@ -38,7 +38,7 @@ public: QList &results(); QList &findData(); - QByteArray &lastFindData(); + QString &lastFindData(); void beginUpdate(); void endUpdate(); @@ -63,7 +63,7 @@ public: private: QList m_results; QList m_findData; - QByteArray m_lastFindData; + QString m_lastFindData; QString m_encoding; }; diff --git a/src/plugin/iwingplugin.h b/src/plugin/iwingplugin.h index 84d0327..9fb2d8b 100644 --- a/src/plugin/iwingplugin.h +++ b/src/plugin/iwingplugin.h @@ -142,9 +142,9 @@ signals: const QString &encoding = QString()); Q_REQUIRED_RESULT QByteArray readBytes(qsizetype offset, qsizetype count); - Q_REQUIRED_RESULT qsizetype searchForward(qsizetype begin, + Q_REQUIRED_RESULT qsizetype findNext(qsizetype begin, const QByteArray &ba); - Q_REQUIRED_RESULT qsizetype searchBackward(qsizetype begin, + Q_REQUIRED_RESULT qsizetype findPrevious(qsizetype begin, const QByteArray &ba); Q_REQUIRED_RESULT QList findAllBytes(qsizetype begin, qsizetype end, const QByteArray &b); diff --git a/src/plugin/pluginsystem.cpp b/src/plugin/pluginsystem.cpp index 6544b59..0c3bf01 100644 --- a/src/plugin/pluginsystem.cpp +++ b/src/plugin/pluginsystem.cpp @@ -1875,9 +1875,9 @@ void PluginSystem::connectReaderInterface(IWingPlugin *plg) { _rwlock.lockForRead(); auto hexeditor = e->hexEditor(); auto doc = hexeditor->document(); - auto pos = doc->searchForward(offset, QByteArray(1, 0)); + auto pos = doc->findNext(offset, QByteArray(1, 0)); if (pos < 0) { - pos = doc->searchForward(offset, QByteArray(1, '\n')); + pos = doc->findNext(offset, QByteArray(1, '\n')); if (pos < 0) { return QString(); } @@ -1900,19 +1900,19 @@ void PluginSystem::connectReaderInterface(IWingPlugin *plg) { } return results; }); - connect(preader, &WingPlugin::Reader::searchForward, _win, + connect(preader, &WingPlugin::Reader::findNext, _win, [=](qsizetype begin, const QByteArray &ba) -> qsizetype { auto e = pluginCurrentEditor(plg); if (e) { - return e->hexEditor()->document()->searchForward(begin, ba); + return e->hexEditor()->document()->findNext(begin, ba); } return qsizetype(-1); }); - connect(preader, &WingPlugin::Reader::searchBackward, _win, + connect(preader, &WingPlugin::Reader::findPrevious, _win, [=](qsizetype begin, const QByteArray &ba) -> qsizetype { auto e = pluginCurrentEditor(plg); if (e) { - return e->hexEditor()->document()->searchBackward(begin, + return e->hexEditor()->document()->findPrevious(begin, ba); } return qsizetype(-1); diff --git a/src/utilities.h b/src/utilities.h index b6c747a..209a6cd 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -149,6 +149,7 @@ public: } } #endif + encodings.sort(); } return encodings;