feat: 优化选区功能;完成插件系统升级;修复查找编码应用无效问题;

This commit is contained in:
寂静的羽夏 2024-12-31 21:00:49 +08:00
parent bd5ddfba9a
commit 3e21be134c
28 changed files with 1390 additions and 816 deletions

View File

@ -93,6 +93,7 @@ bool QHexCursor::hasInternalSelection() const { return !m_sels.isEmpty(); }
void QHexCursor::clearPreviewSelection() {
m_selection = m_position;
m_preMode = SelectionNormal;
emit selectionChanged();
}
void QHexCursor::clearSelection() { m_sels.clear(); }
@ -156,7 +157,6 @@ void QHexCursor::select(qsizetype line, int column, int nibbleindex,
}
}
emit positionChanged();
emit selectionChanged();
}
@ -306,4 +306,6 @@ void QHexCursor::mergePreviewSelection() {
break;
}
clearPreviewSelection();
emit selectionChanged();
}

View File

@ -57,6 +57,7 @@ struct QHexPosition {
return this->offset() >= rhs.offset();
}
};
Q_DECLARE_METATYPE(QHexPosition)
struct QHexSelection {
QHexPosition start;

View File

@ -96,12 +96,17 @@ bool QHexDocument::metaCommentVisible() { return m_metacomment; }
void QHexDocument::insertBookMarkAdjust(qsizetype offset, qsizetype length) {
QMap<qsizetype, QString> bms;
if (_bookmarks.isEmpty()) {
return;
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto rmbegin = _bookmarks.lowerBound(offset);
#else
auto rmbegin = std::as_const(_bookmarks).lowerBound(offset);
#endif
auto addbegin = _bookmarks.upperBound(offset);
for (auto p = addbegin; p != _bookmarks.end(); ++p) {
bms.insert(p.key() + length, p.value());
}
@ -120,6 +125,10 @@ void QHexDocument::insertBookMarkAdjust(qsizetype offset, qsizetype length) {
void QHexDocument::removeBookMarkAdjust(qsizetype offset, qsizetype length) {
QMap<qsizetype, QString> bms;
if (_bookmarks.isEmpty()) {
return;
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto rmbegin = _bookmarks.lowerBound(offset);
#else

View File

@ -113,8 +113,10 @@ void QHexView::establishSignal(QHexDocument *doc) {
connect(m_cursor, &QHexCursor::positionChanged, this,
&QHexView::moveToSelection);
connect(m_cursor, &QHexCursor::selectionChanged, this,
[this]() { this->viewport()->update(); });
connect(m_cursor, &QHexCursor::selectionChanged, this, [this]() {
this->viewport()->update();
emit cursorSelectionChanged();
});
connect(m_cursor, &QHexCursor::insertionModeChanged, this,
&QHexView::renderCurrentLine);
connect(doc, &QHexDocument::canUndoChanged, this,

View File

@ -128,6 +128,7 @@ private:
signals:
void documentChanged(QHexDocument *doc);
void cursorLocationChanged();
void cursorSelectionChanged(); // TODO
void canUndoChanged(bool canUndo);
void canRedoChanged(bool canRedo);
void documentSaved(bool saved);

View File

@ -188,7 +188,9 @@ set(CONTROL_SRC
src/control/codeedit.h
src/control/codeedit.cpp
src/control/asobjtreewidget.h
src/control/asobjtreewidget.cpp)
src/control/asobjtreewidget.cpp
src/control/qtlonglongspinbox.cpp
src/control/qtlonglongspinbox.h)
set(CLASS_SRC
src/class/logger.cpp
@ -252,7 +254,9 @@ set(CLASS_SRC
src/class/layoutmanager.h
src/class/layoutmanager.cpp
src/class/wingupdater.h
src/class/wingupdater.cpp)
src/class/wingupdater.cpp
src/class/richtextitemdelegate.h
src/class/richtextitemdelegate.cpp)
if(WINGHEX_USE_FRAMELESS)
set(WIDGET_FRAME_SRC

View File

@ -316,30 +316,30 @@
<context>
<name>TestPlugin</name>
<message>
<location filename="../testplugin.cpp" line="83"/>
<location filename="../testplugin.cpp" line="84"/>
<source>Test</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="95"/>
<location filename="../testplugin.cpp" line="104"/>
<location filename="../testplugin.cpp" line="109"/>
<location filename="../testplugin.cpp" line="190"/>
<location filename="../testplugin.cpp" line="96"/>
<location filename="../testplugin.cpp" line="105"/>
<location filename="../testplugin.cpp" line="110"/>
<location filename="../testplugin.cpp" line="191"/>
<source>TestPlugin</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="113"/>
<location filename="../testplugin.cpp" line="114"/>
<source>Button - </source>
<translation> - </translation>
</message>
<message>
<location filename="../testplugin.cpp" line="117"/>
<location filename="../testplugin.cpp" line="118"/>
<source>Click</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="197"/>
<location filename="../testplugin.cpp" line="198"/>
<source>A Test Plugin for WingHexExplorer2.</source>
<translation>2</translation>
</message>

View File

@ -245,6 +245,18 @@ void TestPlugin::test_b(const QString &a) {
}
QHash<QString, WingHex::IWingPlugin::ScriptFnInfo>
TestPlugin::registeredScriptFn() {
TestPlugin::registeredScriptFns() const {
return _scriptInfo;
}
WingHex::IWingPlugin::RegisteredEvents TestPlugin::registeredEvents() const {
return RegisteredEvent::AppReady;
}
void TestPlugin::eventReady() {
bool ret;
emit invokeService(
QStringLiteral("WingAngelAPI"), "execCode", Qt::AutoConnection,
WINGAPI_RETURN_ARG(bool, ret),
WINGAPI_ARG(QString, R"(print("Hello, this is TestPlugin!");)"));
}

View File

@ -66,7 +66,10 @@ public:
virtual QList<WingHex::PluginPage *> registeredPages() const override;
virtual QList<WingHex::WingEditorViewWidget *>
registeredEditorViewWidgets() const override;
virtual QHash<QString, ScriptFnInfo> registeredScriptFn() override;
virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const override;
virtual RegisteredEvents registeredEvents() const override;
virtual void eventReady() override;
private:
QString getPuid() const;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
#include "richtextitemdelegate.h"
#include <QAbstractTextDocumentLayout>
#include <QApplication>
#include <QPainter>
#include <QTextDocument>
RichTextItemDelegate::RichTextItemDelegate(QObject *parent)
: QStyledItemDelegate(parent) {}
void RichTextItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
auto options = option;
initStyleOption(&options, index);
painter->save();
QTextDocument doc;
doc.setHtml(options.text);
options.text.clear();
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options,
painter);
// shift text right to make icon visible
QSize iconSize = options.icon.actualSize(options.rect.size());
painter->translate(options.rect.left() + iconSize.width(),
options.rect.top());
QRect clip(0, 0, options.rect.width() + iconSize.width(),
options.rect.height());
painter->setClipRect(clip);
QAbstractTextDocumentLayout::PaintContext ctx;
// set text color to red for selected item
if (option.state & QStyle::State_Selected)
ctx.palette.setColor(QPalette::Text, Qt::red);
ctx.clip = clip;
doc.documentLayout()->draw(painter, ctx);
painter->restore();
}
QSize RichTextItemDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const {
auto options = option;
initStyleOption(&options, index);
QTextDocument doc;
doc.setHtml(options.text);
doc.setTextWidth(options.rect.width());
return QSize(doc.idealWidth(), doc.size().height());
}

View File

@ -0,0 +1,19 @@
#ifndef RICHTEXTITEMDELEGATE_H
#define RICHTEXTITEMDELEGATE_H
#include <QStyledItemDelegate>
class RichTextItemDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
explicit RichTextItemDelegate(QObject *parent = nullptr);
// QAbstractItemDelegate interface
public:
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
virtual QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
};
#endif // RICHTEXTITEMDELEGATE_H

View File

@ -23,6 +23,7 @@
#include "class/scriptmachine.h"
#include "class/wingfiledialog.h"
#include "class/winginputdialog.h"
#include "control/scriptingconsole.h"
#include "define.h"
#include "scriptaddon/scriptqdictionary.h"
@ -96,6 +97,8 @@ void WingAngelAPI::registerScriptFns(const QString &ns,
}
void WingAngelAPI::installAPI(ScriptMachine *machine) {
Q_ASSERT(machine);
auto engine = machine->engine();
auto stringTypeID = machine->typeInfo(ScriptMachine::tString)->GetTypeId();
@ -566,12 +569,6 @@ void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) {
engine, std::bind(&WingHex::WingPlugin::Reader::addressBase, reader),
QPTR_WRAP("addressBase()"));
registerAPI<bool(qsizetype, void *, int)>(
engine,
std::bind(&WingAngelAPI::_HexReader_read, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3),
"bool read(" QSIZETYPE " offset, ? &out obj)");
registerAPI<CScriptArray *(qsizetype, qsizetype)>(
engine,
std::bind(&WingAngelAPI::_HexReader_readBytes, this,
@ -738,24 +735,6 @@ void WingAngelAPI::installHexControllerAPI(asIScriptEngine *engine) {
std::placeholders::_1),
"bool setAddressBase(" QPTR " base)");
registerAPI<bool(qsizetype, void *, int)>(
engine,
std::bind(&WingAngelAPI::_HexReader_write, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3),
"bool write(" QSIZETYPE " offset, ? &in obj)");
registerAPI<bool(qsizetype, void *, int)>(
engine,
std::bind(&WingAngelAPI::_HexReader_insert, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3),
"bool insert(" QSIZETYPE " offset, ? &in obj)");
registerAPI<bool(void *, int)>(engine,
std::bind(&WingAngelAPI::_HexReader_append,
this, std::placeholders::_1,
std::placeholders::_2),
"bool append(? &in obj)");
registerAPI<bool(qsizetype, qint8)>(
engine,
std::bind(&WingHex::WingPlugin::Controller::writeInt8, ctl,
@ -1232,329 +1211,6 @@ QByteArray WingAngelAPI::cArray2ByteArray(const CScriptArray &array, int byteID,
return buffer;
}
bool WingAngelAPI::read2Ref(qsizetype offset, void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
*reinterpret_cast<bool *>(ref) =
(emit reader.readInt8(offset) != 0);
else if (typeId == asTYPEID_INT8)
*reinterpret_cast<qint8 *>(ref) = emit reader.readInt8(offset);
else if (typeId == asTYPEID_INT16)
*reinterpret_cast<qint16 *>(ref) = emit reader.readInt16(offset);
else if (typeId == asTYPEID_INT32)
*reinterpret_cast<qint32 *>(ref) = emit reader.readInt32(offset);
else if (typeId == asTYPEID_INT64)
*reinterpret_cast<qint64 *>(ref) = emit reader.readInt64(offset);
else if (typeId == asTYPEID_UINT8)
*reinterpret_cast<quint8 *>(ref) =
quint8(emit reader.readInt8(offset));
else if (typeId == asTYPEID_UINT16)
*reinterpret_cast<quint16 *>(ref) =
quint16(emit reader.readInt16(offset));
else if (typeId == asTYPEID_UINT32)
*reinterpret_cast<quint32 *>(ref) =
quint32(emit reader.readInt32(offset));
else if (typeId == asTYPEID_UINT64)
*reinterpret_cast<quint64 *>(ref) =
quint64(emit reader.readInt64(offset));
else if (typeId == asTYPEID_FLOAT)
*reinterpret_cast<float *>(ref) = emit reader.readFloat(offset);
else if (typeId == asTYPEID_DOUBLE)
*reinterpret_cast<double *>(ref) = emit reader.readDouble(offset);
else if ((typeId & asTYPEID_MASK_OBJECT) == 0) {
bool ok = false;
// Check if the value matches one of the defined enums
if (engine) {
asITypeInfo *t = engine->GetTypeInfoById(typeId);
for (int n = t->GetEnumValueCount(); n-- > 0;) {
int enumVal;
t->GetEnumValueByIndex(n, &enumVal);
if (enumVal == *(int *)ref) {
*reinterpret_cast<int *>(ref) = enumVal;
ok = true;
break;
}
}
}
if (!ok) {
return false;
}
} else if (typeId & asTYPEID_SCRIPTOBJECT) {
void *value = ref;
// Dereference handles, so we can see what it points to
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
asIScriptObject *obj = (asIScriptObject *)value;
if (obj) {
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
auto id = obj->GetPropertyTypeId(n);
auto data = obj->GetAddressOfProperty(n);
auto size = getAsTypeSize(id, data);
auto ret = read2Ref(offset, data, id);
if (!ret) {
return false;
}
if (size > 0) {
offset += size;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoByName("string");
if (value) {
// only string supported
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
*reinterpret_cast<QString *>(value) =
emit reader.readString(offset);
}
}
}
}
return true;
} else {
return false;
}
}
bool WingAngelAPI::write2Ref(qsizetype offset, void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
return emit controller.writeInt8(
offset, *reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
return emit controller.writeInt8(offset,
*reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
return emit controller.writeInt16(offset,
*reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
return emit controller.writeInt32(offset,
*reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
return emit controller.writeInt64(offset,
*reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
return emit controller.writeFloat(offset,
*reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
return emit controller.writeDouble(
offset, *reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
return emit controller.writeInt32(offset,
*reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
asIScriptObject *obj = (asIScriptObject *)value;
if (obj) {
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
auto id = obj->GetPropertyTypeId(n);
auto data = obj->GetAddressOfProperty(n);
auto size = getAsTypeSize(id, data);
auto ret = write2Ref(offset, data, id);
if (!ret) {
return false;
}
if (size > 0) {
offset += size;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// only string supported
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
return emit controller.writeString(
offset, *reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
}
bool WingAngelAPI::insert2Ref(qsizetype offset, void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
return emit controller.insertInt8(
offset, *reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
return emit controller.insertInt8(offset,
*reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
return emit controller.insertInt16(
offset, *reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
return emit controller.insertInt32(
offset, *reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
return emit controller.insertInt64(
offset, *reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
return emit controller.insertFloat(offset,
*reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
return emit controller.insertDouble(
offset, *reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
return emit controller.insertInt32(offset,
*reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
asIScriptObject *obj = (asIScriptObject *)value;
if (obj) {
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
auto id = obj->GetPropertyTypeId(n);
auto data = obj->GetAddressOfProperty(n);
auto size = getAsTypeSize(id, data);
auto ret = insert2Ref(offset, data, id);
if (!ret) {
return false;
}
if (size > 0) {
offset += size;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// TODO support other type, now only string
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
return emit controller.insertString(
offset, *reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
}
bool WingAngelAPI::append2Ref(void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
return emit controller.appendInt8(
*reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
return emit controller.appendInt8(*reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
return emit controller.appendInt16(
*reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
return emit controller.appendInt32(
*reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
return emit controller.appendInt64(
*reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
return emit controller.appendFloat(*reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
return emit controller.appendDouble(
*reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
return emit controller.appendInt32(*reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
asIScriptObject *obj = (asIScriptObject *)value;
if (obj) {
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
auto id = obj->GetPropertyTypeId(n);
auto data = obj->GetAddressOfProperty(n);
auto ret = append2Ref(data, id);
if (!ret) {
return false;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// only string supported
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
return emit controller.appendString(
*reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
}
qsizetype WingAngelAPI::getAsTypeSize(int typeId, void *data) {
if (typeId == asTYPEID_VOID)
return false;
@ -1904,7 +1560,7 @@ int WingAngelAPI::qvariantCastASID(asIScriptEngine *engine,
bool WingAngelAPI::isTempBuffered(QMetaType::Type type) {
switch (type) {
case QMetaType::Type::Bool:
case QMetaType::Bool:
case QMetaType::Short:
case QMetaType::UShort:
case QMetaType::Int:
@ -1997,6 +1653,52 @@ void WingAngelAPI::script_call(asIScriptGeneric *gen) {
std::bind(op, gen, std::placeholders::_1, std::placeholders::_2));
}
bool WingAngelAPI::execScriptCode(const QString &code) {
if (code.isEmpty()) {
return true;
}
if (_console) {
QTemporaryFile f;
if (f.open()) {
f.write(code.toUtf8());
f.close();
}
_console->setMode(ScriptingConsole::Output);
_console->write(QStringLiteral("(") %
property("__LAST_CALLER__").toString() %
QStringLiteral(") "));
_console->machine()->executeScript(f.fileName());
_console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input);
}
return false;
}
bool WingAngelAPI::execScript(const QString &fileName) {
_console->setMode(ScriptingConsole::Output);
_console->write(QStringLiteral("(") %
property("__LAST_CALLER__").toString() %
QStringLiteral(") "));
auto ret = _console->machine()->executeScript(fileName);
_console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input);
return ret;
}
bool WingAngelAPI::execCode(const QString &code) {
_console->setMode(ScriptingConsole::Output);
_console->write(QStringLiteral("(") %
property("__LAST_CALLER__").toString() %
QStringLiteral(") "));
auto ret = _console->machine()->executeCode(code);
_console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input);
return ret;
}
QString WingAngelAPI::_InputBox_getItem(int stringID, const QString &title,
const QString &label,
const CScriptArray &items, int current,
@ -2068,22 +1770,6 @@ CScriptArray *WingAngelAPI::_HexReader_readBytes(qsizetype offset,
});
}
bool WingAngelAPI::_HexReader_read(qsizetype offset, void *ref, int typeId) {
return read2Ref(offset, ref, typeId);
}
bool WingAngelAPI::_HexReader_write(qsizetype offset, void *ref, int typeId) {
return write2Ref(offset, ref, typeId);
}
bool WingAngelAPI::_HexReader_insert(qsizetype offset, void *ref, int typeId) {
return insert2Ref(offset, ref, typeId);
}
bool WingAngelAPI::_HexReader_append(void *ref, int typeId) {
return append2Ref(ref, typeId);
}
qsizetype WingAngelAPI::_HexReader_searchForward(qsizetype begin,
const CScriptArray &ba) {
// If called from the script, there will always be an active
@ -2263,3 +1949,9 @@ bool WingAngelAPI::_DataVisual_updateTextTable(
return false;
}
}
ScriptingConsole *WingAngelAPI::bindingConsole() const { return _console; }
void WingAngelAPI::setBindingConsole(ScriptingConsole *console) {
_console = console;
}

View File

@ -27,6 +27,7 @@
class asIScriptEngine;
class ScriptMachine;
class ScriptingConsole;
class WingAngelAPI : public WingHex::IWingPlugin {
Q_OBJECT
@ -46,12 +47,16 @@ public:
virtual uint pluginVersion() const override;
virtual const QString pluginComment() const override;
public:
void
registerScriptFns(const QString &ns,
const QHash<QString, IWingPlugin::ScriptFnInfo> &rfns);
void installAPI(ScriptMachine *machine);
ScriptingConsole *bindingConsole() const;
void setBindingConsole(ScriptingConsole *console);
private:
void installLogAPI(asIScriptEngine *engine);
void installExtAPI(asIScriptEngine *engine);
@ -86,14 +91,6 @@ private:
QByteArray cArray2ByteArray(const CScriptArray &array, int byteID,
bool *ok = nullptr);
bool read2Ref(qsizetype offset, void *ref, int typeId);
bool write2Ref(qsizetype offset, void *ref, int typeId);
bool insert2Ref(qsizetype offset, void *ref, int typeId);
bool append2Ref(void *ref, int typeId);
qsizetype getAsTypeSize(int typeId, void *data);
template <typename T>
@ -124,6 +121,11 @@ private:
static void script_call(asIScriptGeneric *gen);
private:
WING_SERVICE bool execScriptCode(const QString &code);
WING_SERVICE bool execScript(const QString &fileName);
WING_SERVICE bool execCode(const QString &code);
private:
QString _InputBox_getItem(int stringID, const QString &title,
const QString &label, const CScriptArray &items,
@ -142,14 +144,6 @@ private:
CScriptArray *_HexReader_readBytes(qsizetype offset, qsizetype len);
bool _HexReader_read(qsizetype offset, void *ref, int typeId);
bool _HexReader_write(qsizetype offset, void *ref, int typeId);
bool _HexReader_insert(qsizetype offset, void *ref, int typeId);
bool _HexReader_append(void *ref, int typeId);
qsizetype _HexReader_searchForward(qsizetype begin, const CScriptArray &ba);
qsizetype _HexReader_searchBackward(qsizetype begin,
@ -180,6 +174,8 @@ private:
std::vector<std::any> _fnbuffer;
QVector<IWingPlugin::ScriptFnInfo> _sfns;
ScriptingConsole *_console = nullptr;
QHash<QString, QHash<QString, qsizetype>> _rfns;
};

View File

@ -170,8 +170,7 @@ void EditorView::registerQMenu(QMenu *menu) {
m_menu->addMenu(menu);
}
EditorView::FindError EditorView::find(const QByteArray &data,
const FindDialog::Result &result) {
EditorView::FindError EditorView::find(const FindDialog::Result &result) {
if (m_findMutex.tryLock(3000)) {
std::unique_lock<QMutex> locker(m_findMutex, std::adopt_lock_t());
auto d = m_hex->document();
@ -196,19 +195,41 @@ EditorView::FindError EditorView::find(const QByteArray &data,
end = -1;
} break;
}
QByteArray data;
if (result.isStringFind) {
data = Utilities::encodingString(result.str, result.encoding);
} else {
data = result.buffer;
}
d->findAllBytes(begin, end, data, results);
m_findResults->beginUpdate();
m_findResults->clear();
for (auto &result : results) {
auto lineWidth = m_hex->renderer()->hexLineWidth();
for (auto &ritem : results) {
FindResult r;
r.offset = result;
r.line = r.offset / m_hex->renderer()->hexLineWidth();
r.col = r.offset % m_hex->renderer()->hexLineWidth();
r.offset = ritem;
r.line = r.offset / lineWidth;
r.col = r.offset % lineWidth;
m_findResults->results().append(r);
QString content;
QByteArray buffer;
// TODO
FindResultModel::FindInfo info;
// default show lineWidth count
if (data.size() > lineWidth - 4) {
}
info.decoding = Utilities::decodingString(buffer, result.encoding);
m_findResults->lastFindData().append(info);
}
m_findResults->lastFindData() = data.toHex(' ').toUpper();
m_findResults->endUpdate();
if (m_findResults->size() ==

View File

@ -92,7 +92,7 @@ public slots:
void switchView(WingEditorViewWidget *w);
void registerQMenu(QMenu *menu);
FindError find(const QByteArray &data, const FindDialog::Result &result);
FindError find(const FindDialog::Result &result);
void clearFindResult();

View File

@ -0,0 +1,257 @@
/*==============================================================================
** 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 "qtlonglongspinbox.h"
#include <QEvent>
#include <QKeyEvent>
#include <QLineEdit>
#include <limits>
QtLongLongSpinBox::QtLongLongSpinBox(QWidget *parent)
: QAbstractSpinBox(parent) {
m_minimum = std::numeric_limits<qlonglong>::min();
m_maximum = std::numeric_limits<qlonglong>::max();
m_value = 0;
m_singleStep = 1;
m_base = 10;
setValue(m_value);
}
qlonglong QtLongLongSpinBox::value() const { return m_value; }
void QtLongLongSpinBox::setValue(qlonglong expectedNewValue) {
const qlonglong newValue = qBound(m_minimum, expectedNewValue, m_maximum);
const QString newValueString = QString::number(newValue, m_base);
lineEdit()->setText(m_prefix + newValueString + m_suffix);
if (m_value != newValue) {
m_value = newValue;
emit valueChanged(newValue);
}
}
QString QtLongLongSpinBox::prefix() const { return m_prefix; }
void QtLongLongSpinBox::setPrefix(const QString &prefix) {
m_prefix = prefix;
setValue(m_value);
}
QString QtLongLongSpinBox::suffix() const { return m_suffix; }
void QtLongLongSpinBox::setSuffix(const QString &suffix) {
m_suffix = suffix;
setValue(m_value);
}
QString QtLongLongSpinBox::cleanText() const {
return QString::number(m_value);
}
qlonglong QtLongLongSpinBox::singleStep() const { return m_singleStep; }
void QtLongLongSpinBox::setSingleStep(qlonglong step) { m_singleStep = step; }
qlonglong QtLongLongSpinBox::minimum() const { return m_minimum; }
void QtLongLongSpinBox::setMinimum(qlonglong min) {
m_minimum = min;
if (m_maximum < m_minimum) {
m_maximum = m_minimum;
}
setValue(m_value);
}
qlonglong QtLongLongSpinBox::maximum() const { return m_maximum; }
void QtLongLongSpinBox::setMaximum(qlonglong max) {
m_maximum = max;
if (m_maximum < m_minimum) {
m_maximum = m_minimum;
}
setValue(m_value);
}
void QtLongLongSpinBox::setRange(qlonglong min, qlonglong max) {
if (min < max) {
m_minimum = min;
m_maximum = max;
} else {
m_minimum = max;
m_maximum = min;
}
setValue(m_value);
}
void QtLongLongSpinBox::setDisplayIntegerBase(int base) {
if (m_base != base) {
m_base = base;
setValue(m_value);
}
}
int QtLongLongSpinBox::displayIntegerBase() const { return m_base; }
void QtLongLongSpinBox::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_Enter:
case Qt::Key_Return:
selectCleanText();
lineEditEditingFinalize();
}
QAbstractSpinBox::keyPressEvent(event);
}
void QtLongLongSpinBox::focusOutEvent(QFocusEvent *event) {
lineEditEditingFinalize();
QAbstractSpinBox::focusOutEvent(event);
}
QAbstractSpinBox::StepEnabled QtLongLongSpinBox::stepEnabled() const {
if (isReadOnly()) {
return StepNone;
}
StepEnabled se = StepNone;
if (wrapping() || m_value < m_maximum) {
se |= StepUpEnabled;
}
if (wrapping() || m_value > m_minimum) {
se |= StepDownEnabled;
}
return se;
}
void QtLongLongSpinBox::stepBy(int steps) {
if (isReadOnly()) {
return;
}
if (m_prefix + QString::number(m_value) + m_suffix != lineEdit()->text()) {
lineEditEditingFinalize();
}
qlonglong newValue = m_value + (steps * m_singleStep);
if (wrapping()) {
// emulating the behavior of QSpinBox
if (newValue > m_maximum) {
if (m_value == m_maximum) {
newValue = m_minimum;
} else {
newValue = m_maximum;
}
} else if (newValue < m_minimum) {
if (m_value == m_minimum) {
newValue = m_maximum;
} else {
newValue = m_minimum;
}
}
} else {
newValue = qBound(m_minimum, newValue, m_maximum);
}
setValue(newValue);
selectCleanText();
}
QValidator::State QtLongLongSpinBox::validate(QString &input, int &pos) const {
// first, we try to interpret as a number without prefixes
bool ok;
const qlonglong value = input.toLongLong(&ok);
if (input.isEmpty() || (ok && value <= m_maximum)) {
input = m_prefix + input + m_suffix;
pos += m_prefix.length();
return QValidator::Acceptable;
}
// if string of text editor aren't simple number, try to interpret it
// as a number with prefix and suffix
bool valid = true;
if (!m_prefix.isEmpty() && !input.startsWith(m_prefix)) {
valid = false;
}
if (!m_suffix.isEmpty() && !input.endsWith(m_suffix)) {
valid = false;
}
if (valid) {
const int start = m_prefix.length();
const int length = input.length() - start - m_suffix.length();
bool ok;
const QString number = input.mid(start, length);
const qlonglong value = number.toLongLong(&ok);
if (number.isEmpty() || (ok && value <= m_maximum)) {
return QValidator::Acceptable;
}
}
// otherwise not acceptable
return QValidator::Invalid;
}
void QtLongLongSpinBox::lineEditEditingFinalize() {
const QString text = lineEdit()->text();
// first, we try to read as a number without prefixes
bool ok;
qlonglong value = text.toLongLong(&ok);
if (ok) {
setValue(value);
return;
}
// if string of text editor aren't simple number, try to interpret it
// as a number with prefix and suffix
bool valid = true;
if (!m_prefix.isEmpty() && !text.startsWith(m_prefix)) {
valid = false;
} else if (!m_suffix.isEmpty() && !text.endsWith(m_suffix)) {
valid = false;
}
if (valid) {
const int start = m_prefix.length();
const int length = text.length() - start - m_suffix.length();
bool ok;
const qlonglong value = text.mid(start, length).toLongLong(&ok);
if (ok) {
setValue(value);
return;
}
}
// otherwise set old value
setValue(m_value);
}
void QtLongLongSpinBox::selectCleanText() {
lineEdit()->setSelection(m_prefix.length(), lineEdit()->text().length() -
m_prefix.length() -
m_suffix.length());
}

View File

@ -0,0 +1,85 @@
/*==============================================================================
** 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 QTLONGLONGSPINBOX_H
#define QTLONGLONGSPINBOX_H
#include <QAbstractSpinBox>
#include <QtGlobal>
class QtLongLongSpinBox : public QAbstractSpinBox {
Q_OBJECT
public:
explicit QtLongLongSpinBox(QWidget *parent = 0);
qlonglong value() const;
QString prefix() const;
void setPrefix(const QString &prefix);
QString suffix() const;
void setSuffix(const QString &suffix);
QString cleanText() const;
qlonglong singleStep() const;
void setSingleStep(qlonglong val);
qlonglong minimum() const;
void setMinimum(qlonglong min);
qlonglong maximum() const;
void setMaximum(qlonglong max);
void setRange(qlonglong min, qlonglong max);
void setDisplayIntegerBase(int base);
int displayIntegerBase() const;
public slots:
void setValue(qlonglong value);
signals:
void valueChanged(qlonglong i);
protected:
virtual void keyPressEvent(QKeyEvent *event);
virtual void focusOutEvent(QFocusEvent *event);
virtual void stepBy(int steps);
virtual StepEnabled stepEnabled() const;
virtual QValidator::State validate(QString &input, int &pos) const;
private:
void lineEditEditingFinalize();
void selectCleanText();
private:
QString m_prefix;
QString m_suffix;
qlonglong m_singleStep;
qlonglong m_minimum;
qlonglong m_maximum;
qlonglong m_value;
int m_base;
private:
Q_DISABLE_COPY(QtLongLongSpinBox)
};
#endif // QTLONGLONGSPINBOX_H

View File

@ -25,14 +25,7 @@
#include <QShortcut>
#include <QVBoxLayout>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QStringDecoder>
#else
#include <QTextCodec>
#endif
FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
QWidget *parent)
FindDialog::FindDialog(const FindInfo &info, QWidget *parent)
: FramelessDialogBase(parent) {
auto widget = new QWidget(this);
auto layout = new QVBoxLayout(widget);
@ -71,30 +64,44 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
layout->addWidget(m_hexeditor);
layout->addSpacing(10);
m_hex->setChecked(true);
if (info.isStringFind) {
m_string->setChecked(true);
m_lineeditor->setEnabled(true);
m_hex->setEnabled(false);
if (!info.encoding.isEmpty()) {
m_encodings->setCurrentText(info.encoding);
}
} else {
m_hex->setChecked(true);
m_lineeditor->setEnabled(false);
m_hex->setEnabled(true);
}
m_lineeditor->setText(info.str);
m_hexeditor->document()->_insert(0, info.buffer);
auto regionw = new QWidget(this);
auto regionLayout = new QHBoxLayout(regionw);
regionLayout->addWidget(new QLabel(tr("Region:"), regionw));
m_regionStart = new QSpinBox(regionw);
Q_ASSERT(stop >= start);
m_regionStart->setRange(start, stop);
m_regionStart = new QtLongLongSpinBox(regionw);
Q_ASSERT(info.stop >= info.start);
m_regionStart->setRange(info.start, info.stop);
m_regionStart->setEnabled(false);
m_regionStart->setValue(start);
m_regionStart->setValue(info.start);
m_regionStart->setDisplayIntegerBase(16);
m_regionStart->setPrefix(QStringLiteral("0x"));
regionLayout->addWidget(m_regionStart, 1);
regionLayout->addWidget(new QLabel(QStringLiteral(" - "), regionw));
m_regionStop = new QSpinBox(regionw);
m_regionStop->setRange(start, stop);
connect(m_regionStart, QOverload<int>::of(&QSpinBox::valueChanged),
m_regionStop, &QSpinBox::setMinimum);
m_regionStop = new QtLongLongSpinBox(regionw);
m_regionStop->setRange(info.start, info.stop);
connect(m_regionStart, &QtLongLongSpinBox::valueChanged, m_regionStop,
&QtLongLongSpinBox::setMinimum);
m_regionStop->setEnabled(false);
m_regionStop->setValue(qMin(start + 1024 * 1024, stop));
m_regionStop->setValue(qMin(info.start + 1024 * 1024, info.stop));
m_regionStop->setDisplayIntegerBase(16);
m_regionStop->setPrefix(QStringLiteral("0x"));
regionLayout->addWidget(m_regionStop, 1);
@ -118,7 +125,7 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
}
});
group->addButton(b, id++);
b->setEnabled(!isBigFile);
b->setEnabled(!info.isBigFile);
buttonLayout->addWidget(b);
b = new QPushButton(tr("Region"), this);
@ -155,7 +162,7 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
b = new QPushButton(tr("Selection"), this);
b->setCheckable(true);
if (sel) {
if (info.isSel) {
connect(b, &QPushButton::toggled, this, [=](bool b) {
if (b) {
_result.dir = SearchDirection::Selection;
@ -167,7 +174,7 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
group->addButton(b, id++);
buttonLayout->addWidget(b);
group->button(isBigFile ? 1 : 0)->setChecked(true);
group->button(info.isBigFile ? 1 : 0)->setChecked(true);
layout->addWidget(btnBox);
layout->addSpacing(20);
@ -184,38 +191,20 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
this->setWindowTitle(tr("find"));
}
QByteArray FindDialog::getResult(Result &result) {
FindDialog::Result FindDialog::getResult() const { return _result; }
void FindDialog::on_accept() {
_result.start = 0;
_result.stop = 0;
if (m_regionStart->isEnabled()) {
_result.start = m_regionStart->value();
_result.stop = m_regionStop->value();
}
result = _result;
return _findarr;
}
void FindDialog::on_accept() {
if (m_string->isChecked()) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto en = QStringConverter::encodingForName(
m_encodings->currentText().toUtf8());
Q_ASSERT(en.has_value());
QStringEncoder e(en.value());
_findarr = e.encode(m_lineeditor->text());
#else
auto en = QTextCodec::codecForName(m_encodings->currentText().toUtf8());
auto e = en->makeEncoder();
_findarr = e->fromUnicode(m_lineeditor->text());
#endif
} else {
_findarr =
m_hexeditor->document()->read(0, int(m_hexeditor->documentBytes()));
}
_result.encoding = m_encodings->currentText();
_result.isStringFind = m_string->isChecked();
_result.buffer = m_hexeditor->document()->read(0);
_result.str = m_lineeditor->text();
done(1);
}
void FindDialog::on_reject() {
_findarr.clear();
done(0);
}
void FindDialog::on_reject() { done(0); }

View File

@ -19,13 +19,13 @@
#define FINDDIALOG_H
#include "QHexView/qhexview.h"
#include "control/qtlonglongspinbox.h"
#include "framelessdialogbase.h"
#include <QComboBox>
#include <QLineEdit>
#include <QObject>
#include <QRadioButton>
#include <QSpinBox>
enum class SearchDirection { None, Region, Foreword, Backword, Selection };
@ -36,12 +36,30 @@ public:
SearchDirection dir = SearchDirection::None;
qsizetype start = 0;
qsizetype stop = 0;
// for searching info
bool isStringFind;
QByteArray buffer;
QString encoding;
QString str;
};
struct FindInfo {
bool isBigFile;
bool isStringFind;
qlonglong start;
qlonglong stop;
bool isSel;
// for searching info
QByteArray buffer;
QString encoding;
QString str;
};
public:
FindDialog(bool isBigFile, int start, int stop, bool sel = true,
QWidget *parent = nullptr);
QByteArray getResult(Result &result);
explicit FindDialog(const FindInfo &info, QWidget *parent = nullptr);
Result getResult() const;
private:
void on_accept();
@ -53,10 +71,9 @@ private:
QRadioButton *m_string;
QRadioButton *m_hex;
QComboBox *m_encodings;
QByteArray _findarr;
QSpinBox *m_regionStart;
QSpinBox *m_regionStop;
QtLongLongSpinBox *m_regionStart;
QtLongLongSpinBox *m_regionStop;
Result _result;
};

View File

@ -29,6 +29,7 @@
#include "class/layoutmanager.h"
#include "class/logger.h"
#include "class/qkeysequences.h"
#include "class/richtextitemdelegate.h"
#include "class/scriptconsolemachine.h"
#include "class/settingmanager.h"
#include "class/wingfiledialog.h"
@ -185,6 +186,8 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
// load the model
Q_ASSERT(m_scriptConsole && m_scriptConsole->machine());
m_varshowtable->setModel(m_scriptConsole->consoleMachine()->model());
plg.angelApi()->setBindingConsole(m_scriptConsole);
}
// connect settings signals
@ -238,6 +241,8 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
this->setUpdatesEnabled(true);
plg.dispatchEvent(IWingPlugin::RegisteredEvent::AppReady, {});
if (splash)
splash->setInfoText(tr("SetupFinished"));
}
@ -484,6 +489,9 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
m_findresult->addAction(newAction(QStringLiteral("del"),
tr("ClearFindResult"),
&MainWindow::on_clearfindresult));
m_findresult->setItemDelegate(new RichTextItemDelegate(m_findresult));
m_findresult->setModel(_findEmptyResult);
connect(m_findresult, &QTableView::doubleClicked, this,
@ -1826,14 +1834,24 @@ void MainWindow::on_findfile() {
return;
}
auto hexeditor = editor->hexEditor();
FindDialog fd(editor->isBigFile(), 0, int(hexeditor->documentBytes()),
hexeditor->selectionCount() == 1, this);
static FindDialog::FindInfo info;
info.isBigFile = editor->isBigFile();
info.start = 0;
info.stop = hexeditor->documentBytes();
info.isSel = hexeditor->selectionCount() == 1;
FindDialog fd(info, this);
if (fd.exec()) {
FindDialog::Result r;
auto res = fd.getResult(r);
auto r = fd.getResult();
info.isStringFind = r.isStringFind;
info.encoding = r.encoding;
info.buffer = r.buffer;
info.str = r.str;
ExecAsync<EditorView::FindError>(
[this, r, res]() -> EditorView::FindError {
return currentEditor()->find(res, r);
[this, r]() -> EditorView::FindError {
return currentEditor()->find(r);
},
[this](EditorView::FindError err) {
switch (err) {
@ -2262,7 +2280,10 @@ void MainWindow::on_exportfindresult() {
if (f.open(QFile::WriteOnly)) {
QJsonObject fobj;
fobj.insert(QStringLiteral("file"), editor->fileName());
fobj.insert(QStringLiteral("data"), findresitem->lastFindData());
// auto d= findresitem->lastFindData();
// fobj.insert(QStringLiteral("data"), findresitem->lastFindData());
QJsonArray arr;
for (int i = 0; i < c; i++) {
auto data = findresitem->resultAt(i);
@ -2371,6 +2392,19 @@ void MainWindow::on_locChanged() {
_numsitem->setNumData(NumShowModel::NumTableIndex::Char, QString());
}
auto cursor = hexeditor->cursor();
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::CursorPositionChanged,
{QVariant::fromValue(cursor->position())});
}
void MainWindow::on_selectionChanged() {
auto hexeditor = currentHexView();
if (hexeditor == nullptr) {
return;
}
// 解码字符串
auto cursor = hexeditor->cursor();
QByteArrayList buffer;
@ -2402,22 +2436,8 @@ void MainWindow::on_locChanged() {
// 如果不超过 10KB (默认)那么解码,防止太多卡死
if (buffer.length() <= 1024 * _decstrlim) {
auto encname = hexeditor->renderer()->encoding();
if (encname == QStringLiteral("ASCII")) {
encname = QStringLiteral("ISO-8859-1");
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto enc = QStringConverter::encodingForName(encname.toUtf8());
Q_ASSERT(enc.has_value());
QStringDecoder dec(enc.value());
m_txtDecode->insertPlainText(dec.decode(b));
#else
auto enc = QTextCodec::codecForName(encname.toUtf8());
auto dec = enc->makeDecoder();
m_txtDecode->setText(dec->toUnicode(b));
#endif
m_txtDecode->insertPlainText(Utilities::decodingString(
b, hexeditor->renderer()->encoding()));
m_txtDecode->insertPlainText(QStringLiteral("\n"));
} else {
m_txtDecode->insertHtml(
@ -2425,6 +2445,10 @@ void MainWindow::on_locChanged() {
.arg(tr("TooManyBytesDecode")));
}
}
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::SelectionChanged,
{QVariant::fromValue(buffer), isPreview});
}
void MainWindow::on_viewtxt() {
@ -2621,6 +2645,9 @@ void MainWindow::registerEditorView(EditorView *editor) {
auto ta = editor->toggleViewAction();
menu->addAction(ta);
ev->setEnabled(true);
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::FileOpened, {editor->fileName()});
}
void MainWindow::connectEditorView(EditorView *editor) {
@ -2717,6 +2744,7 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
if (old != nullptr) {
auto hexeditor = old->hexEditor();
hexeditor->disconnect(SIGNAL(cursorLocationChanged()));
hexeditor->disconnect(SIGNAL(cursorSelectionChanged()));
hexeditor->disconnect(SIGNAL(canUndoChanged(bool)));
hexeditor->disconnect(SIGNAL(canRedoChanged(bool)));
hexeditor->disconnect(SIGNAL(documentSaved(bool)));
@ -2731,6 +2759,8 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
auto hexeditor = cur->hexEditor();
connect(hexeditor, &QHexView::cursorLocationChanged, this,
&MainWindow::on_locChanged);
connect(hexeditor, &QHexView::cursorSelectionChanged, this,
&MainWindow::on_selectionChanged);
connect(hexeditor, &QHexView::canUndoChanged, this, [this](bool b) {
m_toolBtneditors[ToolButtonIndex::UNDO_ACTION]->setEnabled(b);
});
@ -2793,6 +2823,10 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
m_curEditor = cur;
hexeditor->getStatus();
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::FileSwitched,
{cur->fileName(), (old ? old->fileName() : QString())});
}
void MainWindow::loadFindResult(EditorView *view) {
@ -2971,6 +3005,8 @@ ErrFile MainWindow::saveEditor(EditorView *editor, const QString &filename,
return ErrFile::Permission;
}
auto oldName = editor->fileName();
QString workspace = m_views.value(editor);
if (editor->change2WorkSpace()) {
workspace = editor->fileName() + PROEXT;
@ -2979,6 +3015,10 @@ ErrFile MainWindow::saveEditor(EditorView *editor, const QString &filename,
auto ret = editor->save(workspace, filename, ignoreMd5, isExport);
if (ret == ErrFile::Success) {
m_views[editor] = workspace;
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::FileSaved,
{filename.isEmpty() ? oldName : filename, oldName});
}
return ret;
}
@ -3002,8 +3042,13 @@ ErrFile MainWindow::closeEditor(EditorView *editor, bool force) {
m_curEditor = nullptr;
_editorLock.unlock();
}
auto fileName = editor->fileName();
PluginSystem::instance().cleanUpEditorViewHandle(editor);
editor->deleteDockWidget();
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::FileClosed, {fileName});
m_toolBtneditors.value(ToolButtonIndex::EDITOR_VIEWS)
->setEnabled(m_views.size() != 0);

View File

@ -188,6 +188,7 @@ private slots:
void on_clearfindresult();
void on_exportfindresult();
void on_locChanged();
void on_selectionChanged();
void on_viewtxt();
void on_fullScreen();

View File

@ -21,15 +21,20 @@ FindResultModel::FindResultModel(QObject *parent)
: QAbstractTableModel(parent) {}
int FindResultModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return m_results.size();
}
int FindResultModel::columnCount(const QModelIndex &parent) const { return 4; }
int FindResultModel::columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return 5;
}
QVariant FindResultModel::data(const QModelIndex &index, int role) const {
switch (role) {
case Qt::DisplayRole: {
auto r = m_results.at(index.row());
auto row = index.row();
auto r = m_results.at(row);
switch (index.column()) {
case 0: // line
return r.line;
@ -38,8 +43,10 @@ QVariant FindResultModel::data(const QModelIndex &index, int role) const {
case 2: // offset
return QStringLiteral("0x") +
QString::number(r.offset, 16).toUpper();
case 3: // value
return m_lastFindData;
case 3: // range
return m_lastFindData.at(row).findRange;
case 4: // decoding
return m_lastFindData.at(row).decoding;
}
return QVariant();
}
@ -62,6 +69,8 @@ QVariant FindResultModel::headerData(int section, Qt::Orientation orientation,
return tr("offset");
case 3:
return tr("value");
case 4:
return tr("encoding");
}
} else {
return section + 1;
@ -72,7 +81,9 @@ QVariant FindResultModel::headerData(int section, Qt::Orientation orientation,
QList<WingHex::FindResult> &FindResultModel::results() { return m_results; }
QString &FindResultModel::lastFindData() { return m_lastFindData; }
QList<FindResultModel::FindInfo> &FindResultModel::lastFindData() {
return m_lastFindData;
}
void FindResultModel::beginUpdate() { this->beginResetModel(); }

View File

@ -19,15 +19,22 @@
#define FINDRESULTMODEL_H
#include "plugin/iwingplugin.h"
#include <QAbstractTableModel>
class FindResultModel : public QAbstractTableModel {
Q_OBJECT
public:
struct FindInfo {
QString findRange;
QString decoding;
};
public:
explicit FindResultModel(QObject *parent = nullptr);
QList<WingHex::FindResult> &results();
QString &lastFindData();
QList<FindInfo> &lastFindData();
void beginUpdate();
void endUpdate();
@ -46,7 +53,7 @@ public:
private:
QList<WingHex::FindResult> m_results;
QString m_lastFindData;
QList<FindInfo> m_lastFindData;
};
#endif // FINDRESULTMODEL_H

View File

@ -40,6 +40,7 @@
#include <QFileDialog>
#include <QInputDialog>
#include <QMessageBox>
#include <QMetaObject>
/**
* Don't try to modify this file, unless you are the dev
@ -50,7 +51,7 @@ namespace WingHex {
using qusizetype = QIntegerForSizeof<std::size_t>::Unsigned;
Q_DECL_UNUSED constexpr auto SDKVERSION = 14;
Q_DECL_UNUSED constexpr auto SDKVERSION = 15;
Q_DECL_UNUSED static QString PLUGINDIR() {
return QCoreApplication::applicationDirPath() + QStringLiteral("/plugin");
@ -490,6 +491,22 @@ signals:
void raiseView();
};
struct WingDependency {
QString puid;
uint version;
QString md5; // optional, but recommend
};
#ifdef WING_SERVICE
#undef WING_SERVICE
#endif
#define WING_SERVICE Q_INVOKABLE
// for bad broken Qt API
#define WINGAPI_ARG(type, data) QArgument<type>(#type, data)
#define WINGAPI_RETURN_ARG(type, data) QReturnArgument<type>(#type, data)
class IWingPlugin : public QObject {
Q_OBJECT
public:
@ -519,6 +536,7 @@ public:
MetaTypeMask = 0xFFFFF,
Ref = 0x10000000,
Array = 0x100000,
Map = 0x200000
};
static_assert(MetaType::MetaMax < MetaType::Array);
@ -531,11 +549,18 @@ public:
enum class RegisteredEvent : uint {
None,
SelectionChanged = 1u,
CursorPositionChanged = 1u << 1
AppReady = 1u,
SelectionChanged = 1u << 1,
CursorPositionChanged = 1u << 2,
FileOpened = 1u << 3,
FileSaved = 1u << 4,
FileSwitched = 1u << 5,
FileClosed = 1u << 6
};
Q_DECLARE_FLAGS(RegisteredEvents, RegisteredEvent)
enum class PluginFileEvent { Opened, Saved, Switched, Closed };
public:
virtual int sdkVersion() const = 0;
virtual const QString signature() const = 0;
@ -548,6 +573,13 @@ public:
virtual uint pluginVersion() const = 0;
virtual const QString pluginComment() const = 0;
virtual QList<WingDependency> dependencies() const { return {}; }
virtual RegisteredEvents registeredEvents() const {
return RegisteredEvent::None;
}
public:
virtual QList<WingDockWidgetInfo> registeredDockWidgets() const {
return {};
}
@ -564,22 +596,41 @@ public:
return {};
}
// QHash<function-name, fn>
virtual QHash<QString, ScriptFnInfo> registeredScriptFn() { return {}; }
virtual RegisteredEvents registeredEvents() const {
return RegisteredEvent::None;
public:
// QHash< function-name, fn >
virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const {
return {};
}
// QHash< obj-names, decl-members >
virtual QHash<QString, QStringList> registeredScriptObjs() const {
return {};
}
signals:
// QHash< obj-names, decl-members >
bool registerScriptObj(const QString &obj, const QStringList &members);
public:
virtual void eventSelectionChanged(const QByteArrayList &selections) {
virtual void eventSelectionChanged(const QByteArrayList &selections,
bool isPreview) {
Q_UNUSED(selections);
Q_UNUSED(isPreview);
}
virtual void eventCursorPositionChanged(const WingHex::HexPosition &pos) {
Q_UNUSED(pos);
}
virtual void eventPluginFile(PluginFileEvent e, const QString &newfileName,
const QString &oldfileName) {
Q_UNUSED(e);
Q_UNUSED(newfileName);
Q_UNUSED(oldfileName);
}
virtual void eventReady() {}
signals:
// extension and exposed to WingHexAngelScript
void toast(const QPixmap &icon, const QString &message);
@ -591,8 +642,72 @@ signals:
// not available for AngelScript
// only for plugin UI extenstion
QDialog *createDialog(QWidget *content);
bool invokeService(const QString &puid, const char *method,
Qt::ConnectionType type, QGenericReturnArgument ret,
QGenericArgument val0 = QGenericArgument(nullptr),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument());
public:
inline bool invokeService(const QString &puid, const char *member,
QGenericReturnArgument ret,
QGenericArgument val0 = QGenericArgument(nullptr),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) {
return emit invokeService(puid, member, Qt::AutoConnection, ret, val0,
val1, val2, val3, val4, val5, val6, val7,
val8, val9);
}
inline bool invokeService(const QString &puid, const char *member,
Qt::ConnectionType type, QGenericArgument val0,
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) {
return emit invokeService(puid, member, type, QGenericReturnArgument(),
val0, val1, val2, val3, val4, val5, val6,
val7, val8, val9);
}
inline bool invokeService(const QString &puid, const char *member,
QGenericArgument val0,
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) {
return emit invokeService(puid, member, Qt::AutoConnection,
QGenericReturnArgument(), val0, val1, val2,
val3, val4, val5, val6, val7, val8, val9);
}
public:
WingPlugin::Reader reader;
WingPlugin::Controller controller;

View File

@ -47,7 +47,7 @@ PluginSystem::~PluginSystem() {
qApp->exit(int(CrashCode::PluginSetting));
}
for (auto &item : loadedplgs) {
for (auto &item : _loadedplgs) {
auto set = std::make_unique<QSettings>(
udir.absoluteFilePath(item->metaObject()->className()),
QSettings::Format::IniFormat);
@ -56,10 +56,12 @@ PluginSystem::~PluginSystem() {
}
}
const QList<IWingPlugin *> &PluginSystem::plugins() const { return loadedplgs; }
const QList<IWingPlugin *> &PluginSystem::plugins() const {
return _loadedplgs;
}
const IWingPlugin *PluginSystem::plugin(qsizetype index) const {
return loadedplgs.at(index);
return _loadedplgs.at(index);
}
void PluginSystem::loadPlugin(const QFileInfo &fileinfo, const QDir &setdir) {
@ -201,9 +203,82 @@ bool PluginSystem::closeEditor(IWingPlugin *plg, int handle, bool force) {
return true;
}
void PluginSystem::dispatchEvent(IWingPlugin::RegisteredEvent event,
const QVariantList &params) {
switch (event) {
case WingHex::IWingPlugin::RegisteredEvent::SelectionChanged: {
Q_ASSERT(params.size() == 2 &&
params.at(0).canConvert<QByteArrayList>() &&
params.at(1).canConvert<bool>());
auto buffers = params.first().value<QByteArrayList>();
auto isPreview = params.at(1).toBool();
for (auto &plg : _evplgs[event]) {
plg->eventSelectionChanged(buffers, isPreview);
}
} break;
case WingHex::IWingPlugin::RegisteredEvent::CursorPositionChanged: {
Q_ASSERT(params.size() == 1 && params.at(0).canConvert<QHexPosition>());
auto cursor = params.at(0).value<QHexPosition>();
HexPosition pos;
pos.line = cursor.line;
pos.column = cursor.column;
pos.nibbleindex = cursor.nibbleindex;
pos.lineWidth = cursor.lineWidth;
for (auto &plg : _evplgs[event]) {
plg->eventCursorPositionChanged(pos);
}
} break;
case WingHex::IWingPlugin::RegisteredEvent::FileOpened: {
Q_ASSERT(params.size() == 1);
auto fileName = params.first().toString();
Q_ASSERT(!fileName.isEmpty());
for (auto &plg : _evplgs[event]) {
plg->eventPluginFile(IWingPlugin::PluginFileEvent::Opened, fileName,
{});
}
} break;
case WingHex::IWingPlugin::RegisteredEvent::FileSaved: {
Q_ASSERT(params.size() == 2);
auto newFileName = params.at(0).toString();
auto oldFileName = params.at(1).toString();
Q_ASSERT(!newFileName.isEmpty() && !oldFileName.isEmpty());
for (auto &plg : _evplgs[event]) {
plg->eventPluginFile(IWingPlugin::PluginFileEvent::Saved,
oldFileName, newFileName);
}
} break;
case WingHex::IWingPlugin::RegisteredEvent::FileSwitched: {
Q_ASSERT(params.size() == 2);
auto newFileName = params.at(0).toString();
auto oldFileName = params.at(1).toString();
for (auto &plg : _evplgs[event]) {
plg->eventPluginFile(IWingPlugin::PluginFileEvent::Switched,
oldFileName, newFileName);
}
} break;
case WingHex::IWingPlugin::RegisteredEvent::AppReady: {
Q_ASSERT(params.isEmpty());
for (auto &plg : _evplgs[event]) {
plg->eventReady();
}
} break;
case WingHex::IWingPlugin::RegisteredEvent::FileClosed: {
Q_ASSERT(params.size() == 1);
auto fileName = params.first().toString();
Q_ASSERT(!fileName.isEmpty());
for (auto &plg : _evplgs[event]) {
plg->eventPluginFile(IWingPlugin::PluginFileEvent::Closed, fileName,
{});
}
} break;
default:
break;
}
}
void PluginSystem::registerFns(IWingPlugin *plg) {
Q_ASSERT(plg);
auto fns = plg->registeredScriptFn();
auto fns = plg->registeredScriptFns();
if (fns.isEmpty()) {
return;
}
@ -224,9 +299,48 @@ void PluginSystem::registerFns(IWingPlugin *plg) {
_angelplg->registerScriptFns(plg->metaObject()->className(), rfns);
}
void PluginSystem::registerEvents(IWingPlugin *plg) {
Q_ASSERT(plg);
auto evs = plg->registeredEvents();
using FlagInt = decltype(evs)::Int;
if (FlagInt(evs) == FlagInt(IWingPlugin::RegisteredEvent::None)) {
return;
}
if (evs.testFlag(IWingPlugin::RegisteredEvent::SelectionChanged)) {
_evplgs[IWingPlugin::RegisteredEvent::SelectionChanged].append(plg);
}
if (evs.testFlag(IWingPlugin::RegisteredEvent::CursorPositionChanged)) {
_evplgs[IWingPlugin::RegisteredEvent::CursorPositionChanged].append(
plg);
}
if (evs.testFlag(IWingPlugin::RegisteredEvent::FileOpened)) {
_evplgs[IWingPlugin::RegisteredEvent::FileOpened].append(plg);
}
if (evs.testFlag(IWingPlugin::RegisteredEvent::FileSaved)) {
_evplgs[IWingPlugin::RegisteredEvent::FileSaved].append(plg);
}
if (evs.testFlag(IWingPlugin::RegisteredEvent::FileSwitched)) {
_evplgs[IWingPlugin::RegisteredEvent::FileSwitched].append(plg);
}
if (evs.testFlag(IWingPlugin::RegisteredEvent::AppReady)) {
_evplgs[IWingPlugin::RegisteredEvent::AppReady].append(plg);
}
if (evs.testFlag(IWingPlugin::RegisteredEvent::FileClosed)) {
_evplgs[IWingPlugin::RegisteredEvent::FileClosed].append(plg);
}
}
QString PluginSystem::type2AngelScriptString(IWingPlugin::MetaType type,
bool isArg) {
bool isArray = type & WingHex::IWingPlugin::Array;
bool isMap = type & WingHex::IWingPlugin::Map;
bool isRef = type & WingHex::IWingPlugin::Ref;
QString retype;
@ -282,10 +396,18 @@ QString PluginSystem::type2AngelScriptString(IWingPlugin::MetaType type,
return {};
}
if (isMap && isArray) {
return {};
}
if (isArray) {
retype = QStringLiteral("array<") + retype + QStringLiteral(">");
}
if (isMap) {
retype = QStringLiteral("dictionary<") + retype + QStringLiteral(">");
}
if (isRef) {
if (isArg) {
retype += QStringLiteral(" @out");
@ -349,7 +471,7 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
}
auto puid = getPUID(p);
if (loadedpuid.contains(puid)) {
if (_loadedpuid.contains(puid)) {
throw tr("ErrLoadLoadedPlugin");
}
@ -374,8 +496,8 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
}
}
loadedplgs.push_back(p);
loadedpuid << puid;
_loadedplgs.push_back(p);
_loadedpuid << puid;
Logger::warning(tr("PluginName :") + p->pluginName());
Logger::warning(tr("PluginAuthor :") + p->pluginAuthor());
@ -543,6 +665,7 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
}
registerFns(p);
registerEvents(p);
connectInterface(p);
m_plgviewMap.insert(p, nullptr);
@ -609,6 +732,82 @@ void PluginSystem::connectBaseInterface(IWingPlugin *plg) {
return nullptr;
}
});
connect(
plg,
QOverload<const QString &, const char *, Qt::ConnectionType,
QGenericReturnArgument, QGenericArgument, QGenericArgument,
QGenericArgument, QGenericArgument, QGenericArgument,
QGenericArgument, QGenericArgument, QGenericArgument,
QGenericArgument,
QGenericArgument>::of(&IWingPlugin::invokeService),
this,
[=](const QString &puid, const char *method, Qt::ConnectionType type,
QGenericReturnArgument ret, QGenericArgument val0,
QGenericArgument val1, QGenericArgument val2, QGenericArgument val3,
QGenericArgument val4, QGenericArgument val5, QGenericArgument val6,
QGenericArgument val7, QGenericArgument val8,
QGenericArgument val9) -> bool {
auto r = std::find_if(
_loadedplgs.begin(), _loadedplgs.end(),
[=](IWingPlugin *plg) { return getPUID(plg) == puid; });
if (r == _loadedplgs.end()) {
return false;
}
auto meta = (*r)->metaObject();
// filter the evil call and report to log
QVarLengthArray<char, 512> sig;
int len = qstrlen(method);
if (len <= 0)
return false;
sig.append(method, len);
sig.append('(');
const char *typeNames[] = {ret.name(), val0.name(), val1.name(),
val2.name(), val3.name(), val4.name(),
val5.name(), val6.name(), val7.name(),
val8.name(), val9.name()};
size_t paramCount;
constexpr auto maxParamCount =
sizeof(typeNames) / sizeof(const char *);
for (paramCount = 1; paramCount < maxParamCount; ++paramCount) {
len = qstrlen(typeNames[paramCount]);
if (len <= 0)
break;
sig.append(typeNames[paramCount], len);
sig.append(',');
}
if (paramCount == 1)
sig.append(')'); // no parameters
else
sig[sig.size() - 1] = ')';
sig.append('\0');
// checking
auto midx = meta->indexOfMethod(sig.constData());
if (midx < 0) {
auto norm = QMetaObject::normalizedSignature(sig.constData());
midx = meta->indexOfMethod(norm.constData());
if (midx < 0) {
return false;
}
}
auto m = meta->method(midx);
if (m.methodType() == QMetaMethod::Signal) {
// report
Logger::warning(packLogMessage(
plg->metaObject()->className(),
tr("[EvilCall]") %
QString::fromLatin1(sig.data(), sig.length())));
return false;
}
auto obj = *r;
obj->setProperty("__LAST_CALLER__", plg->metaObject()->className());
return m.invoke(obj, type, ret, val0, val1, val2, val3, val4, val5,
val6, val7, val8, val9);
});
}
void PluginSystem::connectReaderInterface(IWingPlugin *plg) {
@ -873,7 +1072,7 @@ void PluginSystem::connectReaderInterface(IWingPlugin *plg) {
}
_rwlock.unlock();
return toByteArray(buffer, enco);
return Utilities::decodingString(buffer, enco);
}
return QString();
});
@ -1155,7 +1354,7 @@ void PluginSystem::connectControllerInterface(IWingPlugin *plg) {
enco = render->encoding();
}
auto unicode = toByteArray(value, enco);
auto unicode = Utilities::encodingString(value, enco);
_rwlock.lockForWrite();
auto ret = doc->insert(offset, unicode);
@ -1204,7 +1403,7 @@ void PluginSystem::connectControllerInterface(IWingPlugin *plg) {
enco = render->encoding();
}
auto unicode = toByteArray(value, enco);
auto unicode = Utilities::encodingString(value, enco);
_rwlock.lockForWrite();
auto ret = doc->replace(offset, unicode);
_rwlock.unlock();
@ -1251,7 +1450,7 @@ void PluginSystem::connectControllerInterface(IWingPlugin *plg) {
enco = render->encoding();
}
auto unicode = toByteArray(value, enco);
auto unicode = Utilities::encodingString(value, enco);
_rwlock.lockForWrite();
auto ret = doc->insert(offset, unicode);
_rwlock.unlock();
@ -2185,26 +2384,3 @@ EditorView *PluginSystem::pluginCurrentEditor(IWingPlugin *sender) const {
}
return nullptr;
}
QByteArray PluginSystem::toByteArray(const QString &buffer,
const QString &encoding) {
auto enn = encoding;
if (enn.isEmpty() || enn == QStringLiteral("ASCII")) {
enn = QStringLiteral("ISO-8859-1");
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto en = QStringConverter::encodingForName(enn.toUtf8());
QByteArray unicode;
if (en.has_value()) {
QStringEncoder e(en.value());
unicode = e.encode(buffer);
}
#else
auto enc = QTextCodec::codecForName(enn.toUtf8());
auto e = enc->makeEncoder();
auto unicode = e->fromUnicode(buffer);
#endif
return unicode;
}

View File

@ -121,8 +121,12 @@ public:
bool closeEditor(IWingPlugin *plg, int handle, bool force);
void dispatchEvent(IWingPlugin::RegisteredEvent event,
const QVariantList &params);
private:
void registerFns(IWingPlugin *plg);
void registerEvents(IWingPlugin *plg);
QString type2AngelScriptString(IWingPlugin::MetaType type, bool isArg);
@ -146,8 +150,6 @@ private:
EditorView *pluginCurrentEditor(IWingPlugin *sender) const;
QByteArray toByteArray(const QString &buffer, const QString &encoding);
private:
template <typename T>
T readBasicTypeContent(IWingPlugin *plg, qsizetype offset) {
@ -228,8 +230,10 @@ private:
private:
MainWindow *_win = nullptr;
QStringList loadedpuid;
QList<IWingPlugin *> loadedplgs;
QStringList _loadedpuid;
QList<IWingPlugin *> _loadedplgs;
QMap<IWingPlugin::RegisteredEvent, QList<IWingPlugin *>> _evplgs;
QHash<IWingPlugin *, EditorView *> m_plgviewMap;
QHash<IWingPlugin *, QList<QPair<SharedUniqueId, EditorView *>>>

View File

@ -250,6 +250,47 @@ public:
}
}
}
static QByteArray encodingString(const QString &str,
const QString &enc = {}) {
auto encoding = enc;
if (encoding.isEmpty() || encoding.compare(QStringLiteral("ASCII"),
Qt::CaseInsensitive) == 0) {
encoding = QStringLiteral("ISO-8859-1");
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto en = QStringConverter::encodingForName(encoding.toUtf8());
Q_ASSERT(en.has_value());
QStringEncoder e(en.value());
return e.encode(str);
#else
auto en = QTextCodec::codecForName(encoding.toUtf8());
auto e = en->makeEncoder();
return e->fromUnicode(str);
#endif
}
static QString decodingString(const QByteArray &buffer,
const QString &enc = {}) {
auto encoding = enc;
if (encoding.isEmpty() || encoding.compare(QStringLiteral("ASCII"),
Qt::CaseInsensitive) == 0) {
encoding = QStringLiteral("ISO-8859-1");
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto en = QStringConverter::encodingForName(encoding.toUtf8());
Q_ASSERT(en.has_value());
QStringDecoder dec(en.value());
return dec.decode(buffer);
#else
auto en = QTextCodec::codecForName(encoding.toUtf8());
auto dec = en->makeDecoder();
return dec->toUnicode(buffer);
#endif
}
};
#endif // UTILITIES_H