fix: 重构查找对话框;搜索字节支持'?'通配符;

This commit is contained in:
寂静的羽夏 2025-02-24 21:15:15 +08:00
parent 3b4d1a1d4b
commit 90241e89ff
22 changed files with 1278 additions and 718 deletions

View File

@ -65,8 +65,7 @@ add_library(
QHexEdit2/chunks.cpp
QHexEdit2/chunks.h
qhexview.h
qhexview.cpp
)
qhexview.cpp)
set_target_properties(
QHexView
@ -74,6 +73,8 @@ set_target_properties(
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON)
target_compile_definitions(QHexView PUBLIC QHEXVIEW_FIND_LIMIT=1000)
target_link_libraries(
QHexView PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Concurrent)

View File

@ -414,8 +414,8 @@ void QHexDocument::applyBookMarks(const QMap<qsizetype, QString> &books) {
emit documentChanged();
}
void QHexDocument::findAllBytes(qsizetype begin, qsizetype end, QByteArray b,
QList<qsizetype> &results,
void QHexDocument::findAllBytes(qsizetype begin, qsizetype end,
const QByteArray &b, QList<qsizetype> &results,
const std::function<bool()> &pred) {
results.clear();
if (!b.length())
@ -424,20 +424,59 @@ 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;
}
if (results.size() ==
std::numeric_limits<QList<qsizetype>::size_type>::max()) {
if (results.size() > QHEXVIEW_FIND_LIMIT) {
break;
}
results.append(p);
p += offset + 1;
p += offset;
}
}
qsizetype QHexDocument::findAllBytesExt(qsizetype begin, qsizetype end,
const QString &pattern,
QList<qsizetype> &results,
const std::function<bool()> &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<QByteArray>(p)) {
offset += std::get<QByteArray>(p).length();
} else if (std::holds_alternative<size_t>(p)) {
offset += std::get<size_t>(p);
} else if (std::holds_alternative<HexWildItem>(p)) {
offset += 1;
}
}
while (pred()) {
p = findNextExt(p, pattern);
if (p < 0 || (e > 0 && p > e)) {
break;
}
if (results.size() > QHEXVIEW_FIND_LIMIT) {
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 +538,287 @@ bool QHexDocument::_remove(qsizetype offset, qsizetype len) {
return true;
}
qsizetype QHexDocument::findNextExt(qsizetype begin,
const QList<FindStep> &patterns) {
auto op = [this](qsizetype &pos, const FindStep &step,
qsizetype *begin = nullptr) -> bool {
if (pos < 0 || pos >= length()) {
return false;
}
if (std::holds_alternative<QByteArray>(step)) {
auto v = std::get<QByteArray>(step);
auto len = v.length();
auto r = findNext(pos, v);
if (r >= 0) {
if (begin) {
*begin = r;
} else {
if (r != pos) {
pos = -1;
return false;
}
}
pos = r + len;
return true;
} else {
pos = -1;
return false;
}
} else if (std::holds_alternative<HexWildItem>(step)) {
auto v = std::get<HexWildItem>(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<size_t>(step)) {
auto v = std::get<size_t>(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, &begin);
if (!r) {
if (pos < 0) {
return -1;
}
continue;
}
++p;
bool ok = true;
for (; p != patterns.cend(); ++p) {
auto r = op(pos, *p);
if (!r) {
ok = false;
if (pos < 0) {
return -1;
}
begin = pos;
break;
}
}
if (ok) {
return begin;
}
}
return -1;
}
qsizetype QHexDocument::findPreviousExt(qsizetype begin,
const QList<FindStep> &patterns) {
auto op = [this](qsizetype &pos, const FindStep &step,
qsizetype *begin = nullptr) -> bool {
if (pos < 0 || pos >= length()) {
return false;
}
if (std::holds_alternative<QByteArray>(step)) {
auto v = std::get<QByteArray>(step);
auto len = v.length();
auto r = findPrevious(pos, v);
if (r >= 0) {
if (begin) {
*begin = r;
} else {
if (r + len != pos) {
pos = -1;
return false;
}
}
pos = r - len;
return true;
} else {
pos = -1;
return false;
}
} else if (std::holds_alternative<HexWildItem>(step)) {
auto v = std::get<HexWildItem>(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<size_t>(step)) {
auto v = std::get<size_t>(step);
pos -= v;
if (v - pos >= 0) {
return true;
}
}
return false;
};
while (begin >= 0) {
auto pos = begin;
auto p = patterns.crbegin();
auto r = op(pos, *p, &begin);
if (!r) {
if (pos < 0) {
return -1;
}
continue;
}
++p;
bool ok = true;
for (; p != patterns.crend(); ++p) {
auto r = op(pos, *p);
if (!r) {
ok = false;
if (pos < 0) {
return -1;
}
begin = pos;
break;
}
}
if (ok) {
return begin;
}
}
return -1;
}
QList<QHexDocument::FindStep>
QHexDocument::parseConvertPattern(const QString &pattern) {
// process hex pattern
QList<HexWildItem> words;
std::optional<uchar> 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<FindStep> 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 +1048,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) {

View File

@ -103,7 +103,13 @@ public:
bool existBookMark(qsizetype pos);
void findAllBytes(
qsizetype begin, qsizetype end, QByteArray b, QList<qsizetype> &results,
qsizetype begin, qsizetype end, const QByteArray &b,
QList<qsizetype> &results,
const std::function<bool()> &pred = [] { return true; });
qsizetype findAllBytesExt(
qsizetype begin, qsizetype end, const QString &pattern,
QList<qsizetype> &results,
const std::function<bool()> &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<QByteArray, HexWildItem, size_t>;
QList<FindStep> parseConvertPattern(const QString &pattern);
qsizetype findNextExt(qsizetype begin, const QList<FindStep> &patterns);
qsizetype findPreviousExt(qsizetype begin, const QList<FindStep> &patterns);
/*================================*/
/*================================*/

View File

@ -321,6 +321,9 @@ void QHexRenderer::unprintableChars(QByteArray &ascii) const {
}
QByteArray QHexRenderer::toHexSequence(const QByteArray &arr) {
if (arr.isEmpty()) {
return QByteArray(1, '\t');
}
const int length = arr.size() * 4;
QByteArray hex(length, Qt::Uninitialized);
char *hexData = hex.data();

View File

@ -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) {

View File

@ -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();

View File

@ -207,7 +207,8 @@ set(CONTROL_SRC
src/control/qtlonglongspinbox.cpp
src/control/qtlonglongspinbox.h
src/control/dockwidgettab.h
src/control/dockwidgettab.cpp)
src/control/dockwidgettab.cpp
src/control/qhextextedit.h src/control/qhextextedit.cpp)
set(CLASS_SRC
src/class/logger.cpp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -775,15 +775,15 @@ void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) {
registerAPI<qsizetype(qsizetype, const CScriptArray &)>(
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<qsizetype(qsizetype, const CScriptArray &)>(
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<CScriptArray *(qsizetype, qsizetype, const CScriptArray &)>(
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);
}

View File

@ -223,10 +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,
const CScriptArray &ba);
qsizetype _HexReader_findPrevious(qsizetype begin, const CScriptArray &ba);
CScriptArray *_HexReader_findAllBytes(qsizetype begin, qsizetype end,
const CScriptArray &ba);

View File

@ -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));
}
@ -234,8 +237,7 @@ EditorView::FindError EditorView::find(const FindDialog::Result &result) {
m_findResults->endUpdate();
if (m_findResults->size() ==
std::numeric_limits<QList<qsizetype>::size_type>::max()) {
if (m_findResults->size() >= QHEXVIEW_FIND_LIMIT) {
return FindError::MayOutOfRange;
} else {
return FindError::Success;

View File

@ -0,0 +1,111 @@
/*==============================================================================
** 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 <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "qhextextedit.h"
#include <QKeyEvent>
#include <QLineEdit>
QHexTextEdit::QHexTextEdit(QWidget *parent)
: QTextEdit(parent), m_isHexMode(true) {
setLineWrapMode(QTextEdit::NoWrap);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mCurserPositionPre = 0;
}
void QHexTextEdit::keyPressEvent(QKeyEvent *event) {
if (!m_isHexMode) {
QTextEdit::keyPressEvent(event);
return;
}
auto pressedKey = event->key();
QTextCursor cursor = textCursor();
auto cursorPosition = cursor.position();
auto newCursorPosition = cursorPosition;
auto index = cursorPosition - cursorPosition / 3;
if (((pressedKey >= Qt::Key_0) && (pressedKey <= Qt::Key_9)) ||
((pressedKey >= Qt::Key_A) && (pressedKey <= Qt::Key_F)) ||
pressedKey == Qt::Key_Question) {
mText.insert(index, event->text());
newCursorPosition = cursorPosition + (cursorPosition % 3 + 1);
} else if (pressedKey == Qt::Key_Backspace) {
if (index != 0) {
mText.remove(index - 1, 1);
newCursorPosition = cursorPosition - 2 + (cursorPosition) % 3;
}
} else if (pressedKey == Qt::Key_Delete) {
if (index != mText.length()) {
mText.remove(index, 1);
newCursorPosition = cursorPosition;
}
} else if (pressedKey == Qt::Key_Left) {
if (index != 0) {
newCursorPosition = cursorPosition - 2 + (cursorPosition) % 3;
}
} else if (pressedKey == Qt::Key_Right) {
if (index != mText.length()) {
newCursorPosition = cursorPosition + (cursorPosition + 1) % 3;
}
}
// Allow only single-line editing
else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
event->ignore(); // Ignore Enter key press to prevent new lines
}
QString temp;
for (int i = 0; i < mText.length(); i++) {
temp.append(mText.at(i).toUpper());
if (i % 2 == 1)
temp.append(' ');
}
setText(temp);
cursor.setPosition(newCursorPosition);
setTextCursor(cursor);
mCurserPositionPre = newCursorPosition;
}
void QHexTextEdit::mousePressEvent(QMouseEvent *event) {
if (!m_isHexMode) {
QTextEdit::mousePressEvent(event);
return;
}
QTextCursor cursor = cursorForPosition(event->pos());
int cursorPosition = cursor.position();
if (cursorPosition % 3 == 2) {
cursorPosition++;
cursor.setPosition(cursorPosition);
mCurserPositionPre = cursorPosition;
}
QTextEdit::mousePressEvent(event);
setTextCursor(cursor);
}
QSize QHexTextEdit::sizeHint() const {
QFont font = this->font();
QFontMetrics fontMetrics(font);
int lineHeight = fontMetrics.lineSpacing();
return QSize(0, lineHeight);
}
bool QHexTextEdit::isHexMode() const { return m_isHexMode; }
void QHexTextEdit::setIsHexMode(bool newIsHexMode) {
m_isHexMode = newIsHexMode;
}

View File

@ -0,0 +1,43 @@
/*==============================================================================
** 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 <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef QHEXTEXTEDIT_H
#define QHEXTEXTEDIT_H
#include <QTextEdit>
class QHexTextEdit : public QTextEdit {
Q_OBJECT
public:
explicit QHexTextEdit(QWidget *parent = nullptr);
bool isHexMode() const;
void setIsHexMode(bool newIsHexMode);
protected:
void keyPressEvent(QKeyEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
QSize sizeHint() const override;
private:
QString mText;
int mCurserPositionPre;
bool m_isHexMode;
};
#endif // QHEXTEXTEDIT_H

View File

@ -25,60 +25,70 @@
#include <QShortcut>
#include <QVBoxLayout>
#include "control/toast.h"
FindDialog::FindDialog(const FindInfo &info, QWidget *parent)
: FramelessDialogBase(parent) {
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->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);
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->addSpacing(3);
m_lineeditor = new QLineEdit(this);
m_lineeditor->setEnabled(false);
connect(m_string, &QRadioButton::toggled, m_lineeditor,
&QLineEdit::setEnabled);
layout->addWidget(new QLabel(tr("Content:"), this));
m_lineeditor = new QHexTextEdit(this);
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, &QHexTextEdit::textChanged, this, [this]() {
auto text = m_lineeditor->toPlainText();
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, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [this](int index) {
auto oldva = m_lineeditor->isHexMode();
auto newva = index == 0;
m_lineeditor->setIsHexMode(newva);
if (oldva != newva) {
m_lineeditor->clear();
} else {
// force update
emit m_lineeditor->textChanged();
}
});
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 +116,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 +142,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 +185,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 +193,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->toPlainText().trimmed();
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);
}

View File

@ -18,7 +18,7 @@
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
#include "QHexView/qhexview.h"
#include "control/qhextextedit.h"
#include "control/qtlonglongspinbox.h"
#include "framelessdialogbase.h"
@ -26,6 +26,7 @@
#include <QLineEdit>
#include <QObject>
#include <QRadioButton>
#include <QTextEdit>
enum class SearchDirection { None, Region, Foreword, Backword, Selection };
@ -39,7 +40,6 @@ public:
// for searching info
bool isStringFind;
QByteArray buffer;
QString encoding;
QString str;
};
@ -66,11 +66,9 @@ private:
void on_reject();
private:
QHexView *m_hexeditor;
QLineEdit *m_lineeditor;
QRadioButton *m_string;
QRadioButton *m_hex;
QComboBox *m_encodings;
QHexTextEdit *m_lineeditor;
QComboBox *m_findMode;
QTextEdit *m_preview;
QtLongLongSpinBox *m_regionStart;
QtLongLongSpinBox *m_regionStop;

View File

@ -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<EditorView::FindError>(
@ -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);

View File

@ -133,7 +133,7 @@ QList<FindResultModel::FindInfo> &FindResultModel::findData() {
return m_findData;
}
QByteArray &FindResultModel::lastFindData() { return m_lastFindData; }
QString &FindResultModel::lastFindData() { return m_lastFindData; }
void FindResultModel::beginUpdate() { this->beginResetModel(); }
@ -146,6 +146,7 @@ WingHex::FindResult FindResultModel::resultAt(qsizetype index) const {
void FindResultModel::clear() {
m_results.clear();
m_findData.clear();
emit layoutChanged();
}
QList<WingHex::FindResult>::size_type FindResultModel::size() const {

View File

@ -38,7 +38,7 @@ public:
QList<WingHex::FindResult> &results();
QList<FindInfo> &findData();
QByteArray &lastFindData();
QString &lastFindData();
void beginUpdate();
void endUpdate();
@ -63,7 +63,7 @@ public:
private:
QList<WingHex::FindResult> m_results;
QList<FindInfo> m_findData;
QByteArray m_lastFindData;
QString m_lastFindData;
QString m_encoding;
};

View File

@ -142,10 +142,9 @@ signals:
const QString &encoding = QString());
Q_REQUIRED_RESULT QByteArray readBytes(qsizetype offset, qsizetype count);
Q_REQUIRED_RESULT qsizetype searchForward(qsizetype begin,
const QByteArray &ba);
Q_REQUIRED_RESULT qsizetype searchBackward(qsizetype begin,
const QByteArray &ba);
Q_REQUIRED_RESULT qsizetype findNext(qsizetype begin, const QByteArray &ba);
Q_REQUIRED_RESULT qsizetype findPrevious(qsizetype begin,
const QByteArray &ba);
Q_REQUIRED_RESULT QList<qsizetype>
findAllBytes(qsizetype begin, qsizetype end, const QByteArray &b);

View File

@ -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,20 +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,
ba);
return e->hexEditor()->document()->findPrevious(begin, ba);
}
return qsizetype(-1);
});

View File

@ -149,6 +149,7 @@ public:
}
}
#endif
encodings.sort();
}
return encodings;