mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-23 16:38:23 +08:00
Replace QHexEdit2 with QHexView5
New widget adds better look-and-feel and comes with free proper dark mode support.
This commit is contained in:
parent
cbf26d125d
commit
cba31d826a
@ -23,6 +23,7 @@ SET(PROJECT_HEADERS
|
|||||||
hexviewdialog.h
|
hexviewdialog.h
|
||||||
gotobasedialog.h
|
gotobasedialog.h
|
||||||
gotoaddressdialog.h
|
gotoaddressdialog.h
|
||||||
|
qhexview5/qhexview.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(PROJECT_SOURCES
|
SET(PROJECT_SOURCES
|
||||||
@ -35,63 +36,73 @@ SET(PROJECT_SOURCES
|
|||||||
hexlineedit.cpp
|
hexlineedit.cpp
|
||||||
ffsfinder.cpp
|
ffsfinder.cpp
|
||||||
hexspinbox.cpp
|
hexspinbox.cpp
|
||||||
qhexedit2/qhexedit.cpp
|
qhexview5/model/buffer/qhexbuffer.cpp
|
||||||
qhexedit2/chunks.cpp
|
qhexview5/model/buffer/qdevicebuffer.cpp
|
||||||
qhexedit2/commands.cpp
|
qhexview5/model/buffer/qmemorybuffer.cpp
|
||||||
../common/fitparser.cpp
|
qhexview5/model/commands/hexcommand.cpp
|
||||||
../common/guiddatabase.cpp
|
qhexview5/model/commands/insertcommand.cpp
|
||||||
../common/nvram.cpp
|
qhexview5/model/commands/removecommand.cpp
|
||||||
../common/nvramparser.cpp
|
qhexview5/model/commands/replacecommand.cpp
|
||||||
../common/meparser.cpp
|
qhexview5/model/qhexcursor.cpp
|
||||||
../common/ffsops.cpp
|
qhexview5/model/qhexdelegate.cpp
|
||||||
../common/types.cpp
|
qhexview5/model/qhexdocument.cpp
|
||||||
../common/descriptor.cpp
|
qhexview5/model/qhexmetadata.cpp
|
||||||
../common/ffs.cpp
|
qhexview5/model/qhexutils.cpp
|
||||||
../common/peimage.cpp
|
qhexview5/qhexview.cpp
|
||||||
../common/utility.cpp
|
../common/fitparser.cpp
|
||||||
../common/ffsbuilder.cpp
|
../common/guiddatabase.cpp
|
||||||
../common/ffsparser.cpp
|
../common/nvram.cpp
|
||||||
../common/ffsreport.cpp
|
../common/nvramparser.cpp
|
||||||
../common/treeitem.cpp
|
../common/meparser.cpp
|
||||||
../common/treemodel.cpp
|
../common/ffsops.cpp
|
||||||
../common/LZMA/LzmaCompress.c
|
../common/types.cpp
|
||||||
../common/LZMA/LzmaDecompress.c
|
../common/descriptor.cpp
|
||||||
../common/LZMA/SDK/C/CpuArch.c
|
../common/ffs.cpp
|
||||||
../common/LZMA/SDK/C/Bra.c
|
../common/peimage.cpp
|
||||||
../common/LZMA/SDK/C/Bra86.c
|
../common/utility.cpp
|
||||||
../common/LZMA/SDK/C/LzFind.c
|
../common/ffsbuilder.cpp
|
||||||
../common/LZMA/SDK/C/LzmaDec.c
|
../common/ffsparser.cpp
|
||||||
../common/LZMA/SDK/C/LzmaEnc.c
|
../common/ffsreport.cpp
|
||||||
../common/Tiano/EfiTianoDecompress.c
|
../common/treeitem.cpp
|
||||||
../common/Tiano/EfiTianoCompress.c
|
../common/treemodel.cpp
|
||||||
../common/Tiano/EfiTianoCompressLegacy.c
|
../common/LZMA/LzmaCompress.c
|
||||||
../common/ustring.cpp
|
../common/LZMA/LzmaDecompress.c
|
||||||
../common/digest/sha1.c
|
../common/LZMA/SDK/C/CpuArch.c
|
||||||
../common/digest/sha256.c
|
../common/LZMA/SDK/C/Bra.c
|
||||||
../common/digest/sha512.c
|
../common/LZMA/SDK/C/Bra86.c
|
||||||
../common/digest/sm3.c
|
../common/LZMA/SDK/C/LzFind.c
|
||||||
|
../common/LZMA/SDK/C/LzmaDec.c
|
||||||
|
../common/LZMA/SDK/C/LzmaEnc.c
|
||||||
|
../common/Tiano/EfiTianoDecompress.c
|
||||||
|
../common/Tiano/EfiTianoCompress.c
|
||||||
|
../common/Tiano/EfiTianoCompressLegacy.c
|
||||||
|
../common/ustring.cpp
|
||||||
|
../common/digest/sha1.c
|
||||||
|
../common/digest/sha256.c
|
||||||
|
../common/digest/sha512.c
|
||||||
|
../common/digest/sm3.c
|
||||||
../common/generated/ami_nvar.cpp
|
../common/generated/ami_nvar.cpp
|
||||||
../common/generated/intel_acbp_v1.cpp
|
../common/generated/intel_acbp_v1.cpp
|
||||||
../common/generated/intel_acbp_v2.cpp
|
../common/generated/intel_acbp_v2.cpp
|
||||||
../common/generated/intel_keym_v1.cpp
|
../common/generated/intel_keym_v1.cpp
|
||||||
../common/generated/intel_keym_v2.cpp
|
../common/generated/intel_keym_v2.cpp
|
||||||
../common/generated/intel_acm.cpp
|
../common/generated/intel_acm.cpp
|
||||||
../common/kaitai/kaitaistream.cpp
|
../common/kaitai/kaitaistream.cpp
|
||||||
../common/zlib/adler32.c
|
../common/zlib/adler32.c
|
||||||
../common/zlib/compress.c
|
../common/zlib/compress.c
|
||||||
../common/zlib/crc32.c
|
../common/zlib/crc32.c
|
||||||
../common/zlib/deflate.c
|
../common/zlib/deflate.c
|
||||||
../common/zlib/gzclose.c
|
../common/zlib/gzclose.c
|
||||||
../common/zlib/gzlib.c
|
../common/zlib/gzlib.c
|
||||||
../common/zlib/gzread.c
|
../common/zlib/gzread.c
|
||||||
../common/zlib/gzwrite.c
|
../common/zlib/gzwrite.c
|
||||||
../common/zlib/inflate.c
|
../common/zlib/inflate.c
|
||||||
../common/zlib/infback.c
|
../common/zlib/infback.c
|
||||||
../common/zlib/inftrees.c
|
../common/zlib/inftrees.c
|
||||||
../common/zlib/inffast.c
|
../common/zlib/inffast.c
|
||||||
../common/zlib/trees.c
|
../common/zlib/trees.c
|
||||||
../common/zlib/uncompr.c
|
../common/zlib/uncompr.c
|
||||||
../common/zlib/zutil.c
|
../common/zlib/zutil.c
|
||||||
)
|
)
|
||||||
|
|
||||||
QT_ADD_RESOURCES(PROJECT_SOURCES
|
QT_ADD_RESOURCES(PROJECT_SOURCES
|
||||||
|
@ -20,9 +20,8 @@ hexView(NULL)
|
|||||||
{
|
{
|
||||||
// Create UI
|
// Create UI
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
hexView = new QHexEdit(this);
|
hexView = new QHexView(this);
|
||||||
hexView->setReadOnly(true);
|
hexView->setReadOnly(true);
|
||||||
hexView->setUpperCase(true);
|
|
||||||
ui->layout->addWidget(hexView);
|
ui->layout->addWidget(hexView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include "../common/treemodel.h"
|
#include "../common/treemodel.h"
|
||||||
#include "qhexedit2/qhexedit.h"
|
#include "qhexview5/qhexview.h"
|
||||||
#include "ui_hexviewdialog.h"
|
#include "ui_hexviewdialog.h"
|
||||||
|
|
||||||
class HexViewDialog : public QDialog
|
class HexViewDialog : public QDialog
|
||||||
@ -38,7 +38,7 @@ public:
|
|||||||
void setFont(const QFont &font);
|
void setFont(const QFont &font);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHexEdit * hexView;
|
QHexView * hexView;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HEXVIEWDIALOG_H
|
#endif // HEXVIEWDIALOG_H
|
||||||
|
@ -1,323 +0,0 @@
|
|||||||
#include "chunks.h"
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#define NORMAL 0
|
|
||||||
#define HIGHLIGHTED 1
|
|
||||||
|
|
||||||
#define BUFFER_SIZE 0x10000
|
|
||||||
#define CHUNK_SIZE 0x1000
|
|
||||||
#define READ_CHUNK_MASK Q_INT64_C(0xfffffffffffff000)
|
|
||||||
|
|
||||||
// ***************************************** Constructors and file settings
|
|
||||||
|
|
||||||
Chunks::Chunks(QObject *parent): QObject(parent)
|
|
||||||
{
|
|
||||||
QBuffer *buf = new QBuffer(this);
|
|
||||||
setIODevice(*buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
Chunks::Chunks(QIODevice &ioDevice, QObject *parent): QObject(parent)
|
|
||||||
{
|
|
||||||
setIODevice(ioDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Chunks::setIODevice(QIODevice &ioDevice)
|
|
||||||
{
|
|
||||||
_ioDevice = &ioDevice;
|
|
||||||
bool ok = _ioDevice->open(QIODevice::ReadOnly);
|
|
||||||
if (ok) // Try to open IODevice
|
|
||||||
{
|
|
||||||
_size = _ioDevice->size();
|
|
||||||
_ioDevice->close();
|
|
||||||
}
|
|
||||||
else // Fallback is an empty buffer
|
|
||||||
{
|
|
||||||
QBuffer *buf = new QBuffer(this);
|
|
||||||
_ioDevice = buf;
|
|
||||||
_size = 0;
|
|
||||||
}
|
|
||||||
_chunks.clear();
|
|
||||||
_pos = 0;
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ***************************************** Getting data out of Chunks
|
|
||||||
|
|
||||||
QByteArray Chunks::data(qint64 pos, qint64 maxSize, QByteArray *highlighted)
|
|
||||||
{
|
|
||||||
qint64 ioDelta = 0;
|
|
||||||
int chunkIdx = 0;
|
|
||||||
|
|
||||||
Chunk chunk;
|
|
||||||
QByteArray buffer;
|
|
||||||
|
|
||||||
// Do some checks and some arrangements
|
|
||||||
if (highlighted)
|
|
||||||
highlighted->clear();
|
|
||||||
|
|
||||||
if (pos >= _size)
|
|
||||||
return buffer;
|
|
||||||
|
|
||||||
if (maxSize < 0)
|
|
||||||
maxSize = _size;
|
|
||||||
else
|
|
||||||
if ((pos + maxSize) > _size)
|
|
||||||
maxSize = _size - pos;
|
|
||||||
|
|
||||||
_ioDevice->open(QIODevice::ReadOnly);
|
|
||||||
|
|
||||||
while (maxSize > 0)
|
|
||||||
{
|
|
||||||
chunk.absPos = LLONG_MAX;
|
|
||||||
bool chunksLoopOngoing = true;
|
|
||||||
while ((chunkIdx < _chunks.count()) && chunksLoopOngoing)
|
|
||||||
{
|
|
||||||
// In this section, we track changes before our required data and
|
|
||||||
// we take the editdet data, if availible. ioDelta is a difference
|
|
||||||
// counter to justify the read pointer to the original data, if
|
|
||||||
// data in between was deleted or inserted.
|
|
||||||
|
|
||||||
chunk = _chunks[chunkIdx];
|
|
||||||
if (chunk.absPos > pos)
|
|
||||||
chunksLoopOngoing = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
chunkIdx += 1;
|
|
||||||
qint64 count;
|
|
||||||
qint64 chunkOfs = pos - chunk.absPos;
|
|
||||||
if (maxSize > ((qint64)chunk.data.size() - chunkOfs))
|
|
||||||
{
|
|
||||||
count = (qint64)chunk.data.size() - chunkOfs;
|
|
||||||
ioDelta += CHUNK_SIZE - chunk.data.size();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
count = maxSize;
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
buffer += chunk.data.mid((int)chunkOfs, (int)count);
|
|
||||||
maxSize -= count;
|
|
||||||
pos += count;
|
|
||||||
if (highlighted)
|
|
||||||
*highlighted += chunk.dataChanged.mid((int)chunkOfs, (int)count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((maxSize > 0) && (pos < chunk.absPos))
|
|
||||||
{
|
|
||||||
// In this section, we read data from the original source. This only will
|
|
||||||
// happen, whe no copied data is available
|
|
||||||
|
|
||||||
qint64 byteCount;
|
|
||||||
QByteArray readBuffer;
|
|
||||||
if ((chunk.absPos - pos) > maxSize)
|
|
||||||
byteCount = maxSize;
|
|
||||||
else
|
|
||||||
byteCount = chunk.absPos - pos;
|
|
||||||
|
|
||||||
maxSize -= byteCount;
|
|
||||||
_ioDevice->seek(pos + ioDelta);
|
|
||||||
readBuffer = _ioDevice->read(byteCount);
|
|
||||||
buffer += readBuffer;
|
|
||||||
if (highlighted)
|
|
||||||
*highlighted += QByteArray(readBuffer.size(), NORMAL);
|
|
||||||
pos += readBuffer.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ioDevice->close();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Chunks::write(QIODevice &iODevice, qint64 pos, qint64 count)
|
|
||||||
{
|
|
||||||
if (count == -1)
|
|
||||||
count = _size;
|
|
||||||
bool ok = iODevice.open(QIODevice::WriteOnly);
|
|
||||||
if (ok)
|
|
||||||
{
|
|
||||||
for (qint64 idx=pos; idx < count; idx += BUFFER_SIZE)
|
|
||||||
{
|
|
||||||
QByteArray ba = data(idx, BUFFER_SIZE);
|
|
||||||
iODevice.write(ba);
|
|
||||||
}
|
|
||||||
iODevice.close();
|
|
||||||
}
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ***************************************** Set and get highlighting infos
|
|
||||||
|
|
||||||
void Chunks::setDataChanged(qint64 pos, bool dataChanged)
|
|
||||||
{
|
|
||||||
if ((pos < 0) || (pos >= _size))
|
|
||||||
return;
|
|
||||||
int chunkIdx = getChunkIndex(pos);
|
|
||||||
qint64 posInBa = pos - _chunks[chunkIdx].absPos;
|
|
||||||
_chunks[chunkIdx].dataChanged[(int)posInBa] = char(dataChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Chunks::dataChanged(qint64 pos)
|
|
||||||
{
|
|
||||||
QByteArray highlighted;
|
|
||||||
data(pos, 1, &highlighted);
|
|
||||||
return bool(highlighted.at(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ***************************************** Search API
|
|
||||||
|
|
||||||
qint64 Chunks::indexOf(const QByteArray &ba, qint64 from)
|
|
||||||
{
|
|
||||||
qint64 result = -1;
|
|
||||||
QByteArray buffer;
|
|
||||||
|
|
||||||
for (qint64 pos=from; (pos < _size) && (result < 0); pos += BUFFER_SIZE)
|
|
||||||
{
|
|
||||||
buffer = data(pos, BUFFER_SIZE + ba.size() - 1);
|
|
||||||
int findPos = (int)buffer.indexOf(ba);
|
|
||||||
if (findPos >= 0)
|
|
||||||
result = pos + (qint64)findPos;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 Chunks::lastIndexOf(const QByteArray &ba, qint64 from)
|
|
||||||
{
|
|
||||||
qint64 result = -1;
|
|
||||||
QByteArray buffer;
|
|
||||||
|
|
||||||
for (qint64 pos=from; (pos > 0) && (result < 0); pos -= BUFFER_SIZE)
|
|
||||||
{
|
|
||||||
qint64 sPos = pos - BUFFER_SIZE - (qint64)ba.size() + 1;
|
|
||||||
if (sPos < 0)
|
|
||||||
sPos = 0;
|
|
||||||
buffer = data(sPos, pos - sPos);
|
|
||||||
int findPos = (int)buffer.lastIndexOf(ba);
|
|
||||||
if (findPos >= 0)
|
|
||||||
result = sPos + (qint64)findPos;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ***************************************** Char manipulations
|
|
||||||
|
|
||||||
bool Chunks::insert(qint64 pos, char b)
|
|
||||||
{
|
|
||||||
if ((pos < 0) || (pos > _size))
|
|
||||||
return false;
|
|
||||||
int chunkIdx;
|
|
||||||
if (pos == _size)
|
|
||||||
chunkIdx = getChunkIndex(pos-1);
|
|
||||||
else
|
|
||||||
chunkIdx = getChunkIndex(pos);
|
|
||||||
qint64 posInBa = pos - _chunks[chunkIdx].absPos;
|
|
||||||
_chunks[chunkIdx].data.insert((int)posInBa, b);
|
|
||||||
_chunks[chunkIdx].dataChanged.insert((int)posInBa, char(1));
|
|
||||||
for (int idx=chunkIdx+1; idx < _chunks.size(); idx++)
|
|
||||||
_chunks[idx].absPos += 1;
|
|
||||||
_size += 1;
|
|
||||||
_pos = pos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Chunks::overwrite(qint64 pos, char b)
|
|
||||||
{
|
|
||||||
if ((pos < 0) || (pos >= _size))
|
|
||||||
return false;
|
|
||||||
int chunkIdx = getChunkIndex(pos);
|
|
||||||
qint64 posInBa = pos - _chunks[chunkIdx].absPos;
|
|
||||||
_chunks[chunkIdx].data[(int)posInBa] = b;
|
|
||||||
_chunks[chunkIdx].dataChanged[(int)posInBa] = char(1);
|
|
||||||
_pos = pos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Chunks::removeAt(qint64 pos)
|
|
||||||
{
|
|
||||||
if ((pos < 0) || (pos >= _size))
|
|
||||||
return false;
|
|
||||||
int chunkIdx = getChunkIndex(pos);
|
|
||||||
qint64 posInBa = pos - _chunks[chunkIdx].absPos;
|
|
||||||
_chunks[chunkIdx].data.remove((int)posInBa, 1);
|
|
||||||
_chunks[chunkIdx].dataChanged.remove((int)posInBa, 1);
|
|
||||||
for (int idx=chunkIdx+1; idx < _chunks.size(); idx++)
|
|
||||||
_chunks[idx].absPos -= 1;
|
|
||||||
_size -= 1;
|
|
||||||
_pos = pos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ***************************************** Utility functions
|
|
||||||
|
|
||||||
char Chunks::operator[](qint64 pos)
|
|
||||||
{
|
|
||||||
return data(pos, 1)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 Chunks::pos()
|
|
||||||
{
|
|
||||||
return _pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 Chunks::size()
|
|
||||||
{
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Chunks::getChunkIndex(qint64 absPos)
|
|
||||||
{
|
|
||||||
// This routine checks, if there is already a copied chunk available. If os, it
|
|
||||||
// returns a reference to it. If there is no copied chunk available, original
|
|
||||||
// data will be copied into a new chunk.
|
|
||||||
|
|
||||||
int foundIdx = -1;
|
|
||||||
int insertIdx = 0;
|
|
||||||
qint64 ioDelta = 0;
|
|
||||||
|
|
||||||
|
|
||||||
for (int idx=0; idx < _chunks.size(); idx++)
|
|
||||||
{
|
|
||||||
Chunk chunk = _chunks[idx];
|
|
||||||
if ((absPos >= chunk.absPos) && (absPos < (chunk.absPos + chunk.data.size())))
|
|
||||||
{
|
|
||||||
foundIdx = idx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (absPos < chunk.absPos)
|
|
||||||
{
|
|
||||||
insertIdx = idx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ioDelta += chunk.data.size() - CHUNK_SIZE;
|
|
||||||
insertIdx = idx + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundIdx == -1)
|
|
||||||
{
|
|
||||||
Chunk newChunk;
|
|
||||||
qint64 readAbsPos = absPos - ioDelta;
|
|
||||||
qint64 readPos = (readAbsPos & READ_CHUNK_MASK);
|
|
||||||
_ioDevice->open(QIODevice::ReadOnly);
|
|
||||||
_ioDevice->seek(readPos);
|
|
||||||
newChunk.data = _ioDevice->read(CHUNK_SIZE);
|
|
||||||
_ioDevice->close();
|
|
||||||
newChunk.absPos = absPos - (readAbsPos - readPos);
|
|
||||||
newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0));
|
|
||||||
_chunks.insert(insertIdx, newChunk);
|
|
||||||
foundIdx = insertIdx;
|
|
||||||
}
|
|
||||||
return foundIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef MODUL_TEST
|
|
||||||
int Chunks::chunkSize()
|
|
||||||
{
|
|
||||||
return _chunks.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,77 +0,0 @@
|
|||||||
#ifndef CHUNKS_H
|
|
||||||
#define CHUNKS_H
|
|
||||||
|
|
||||||
/** \cond docNever */
|
|
||||||
|
|
||||||
/*! The Chunks class is the storage backend for QHexEdit.
|
|
||||||
*
|
|
||||||
* When QHexEdit loads data, Chunks access them using a QIODevice interface. When the app uses
|
|
||||||
* a QByteArray interface, QBuffer is used to provide again a QIODevice like interface. No data
|
|
||||||
* will be changed, therefore Chunks opens the QIODevice in QIODevice::ReadOnly mode. After every
|
|
||||||
* access Chunks closes the QIODevice, that's why external applications can overwrite files while
|
|
||||||
* QHexEdit shows them.
|
|
||||||
*
|
|
||||||
* When the the user starts to edit the data, Chunks creates a local copy of a chunk of data (4
|
|
||||||
* kilobytes) and notes all changes there. Parallel to that chunk, there is a second chunk,
|
|
||||||
* which keep track of which bytes are changed and which not.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <QtCore>
|
|
||||||
|
|
||||||
struct Chunk
|
|
||||||
{
|
|
||||||
QByteArray data;
|
|
||||||
QByteArray dataChanged;
|
|
||||||
qint64 absPos;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Chunks: public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
// Constructors and file settings
|
|
||||||
Chunks(QObject *parent);
|
|
||||||
Chunks(QIODevice &ioDevice, QObject *parent);
|
|
||||||
bool setIODevice(QIODevice &ioDevice);
|
|
||||||
|
|
||||||
// Getting data out of Chunks
|
|
||||||
QByteArray data(qint64 pos=0, qint64 count=-1, QByteArray *highlighted=0);
|
|
||||||
bool write(QIODevice &iODevice, qint64 pos=0, qint64 count=-1);
|
|
||||||
|
|
||||||
// Set and get highlighting infos
|
|
||||||
void setDataChanged(qint64 pos, bool dataChanged);
|
|
||||||
bool dataChanged(qint64 pos);
|
|
||||||
|
|
||||||
// Search API
|
|
||||||
qint64 indexOf(const QByteArray &ba, qint64 from);
|
|
||||||
qint64 lastIndexOf(const QByteArray &ba, qint64 from);
|
|
||||||
|
|
||||||
// Char manipulations
|
|
||||||
bool insert(qint64 pos, char b);
|
|
||||||
bool overwrite(qint64 pos, char b);
|
|
||||||
bool removeAt(qint64 pos);
|
|
||||||
|
|
||||||
// Utility functions
|
|
||||||
char operator[](qint64 pos);
|
|
||||||
qint64 pos();
|
|
||||||
qint64 size();
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
int getChunkIndex(qint64 absPos);
|
|
||||||
|
|
||||||
QIODevice * _ioDevice;
|
|
||||||
qint64 _pos;
|
|
||||||
qint64 _size;
|
|
||||||
QList<Chunk> _chunks;
|
|
||||||
|
|
||||||
#ifdef MODUL_TEST
|
|
||||||
public:
|
|
||||||
int chunkSize();
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \endcond docNever */
|
|
||||||
|
|
||||||
#endif // CHUNKS_H
|
|
@ -1,167 +0,0 @@
|
|||||||
#include "commands.h"
|
|
||||||
#include <QUndoCommand>
|
|
||||||
|
|
||||||
|
|
||||||
// Helper class to store single byte commands
|
|
||||||
class CharCommand : public QUndoCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum CCmd {insert, removeAt, overwrite};
|
|
||||||
|
|
||||||
CharCommand(Chunks * chunks, CCmd cmd, qint64 charPos, char newChar,
|
|
||||||
QUndoCommand *parent=0);
|
|
||||||
|
|
||||||
void undo();
|
|
||||||
void redo();
|
|
||||||
bool mergeWith(const QUndoCommand *command);
|
|
||||||
int id() const { return 1234; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Chunks * _chunks;
|
|
||||||
qint64 _charPos;
|
|
||||||
bool _wasChanged;
|
|
||||||
char _newChar;
|
|
||||||
char _oldChar;
|
|
||||||
CCmd _cmd;
|
|
||||||
};
|
|
||||||
|
|
||||||
CharCommand::CharCommand(Chunks * chunks, CCmd cmd, qint64 charPos, char newChar, QUndoCommand *parent)
|
|
||||||
: QUndoCommand(parent)
|
|
||||||
{
|
|
||||||
_chunks = chunks;
|
|
||||||
_charPos = charPos;
|
|
||||||
_newChar = newChar;
|
|
||||||
_cmd = cmd;
|
|
||||||
_wasChanged = false;
|
|
||||||
_oldChar = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CharCommand::mergeWith(const QUndoCommand *command)
|
|
||||||
{
|
|
||||||
const CharCommand *nextCommand = static_cast<const CharCommand *>(command);
|
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
if (_cmd != CharCommand::removeAt)
|
|
||||||
{
|
|
||||||
if (nextCommand->_cmd == overwrite)
|
|
||||||
if (nextCommand->_charPos == _charPos)
|
|
||||||
{
|
|
||||||
_newChar = nextCommand->_newChar;
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CharCommand::undo()
|
|
||||||
{
|
|
||||||
switch (_cmd)
|
|
||||||
{
|
|
||||||
case insert:
|
|
||||||
_chunks->removeAt(_charPos);
|
|
||||||
break;
|
|
||||||
case overwrite:
|
|
||||||
_chunks->overwrite(_charPos, _oldChar);
|
|
||||||
_chunks->setDataChanged(_charPos, _wasChanged);
|
|
||||||
break;
|
|
||||||
case removeAt:
|
|
||||||
_chunks->insert(_charPos, _oldChar);
|
|
||||||
_chunks->setDataChanged(_charPos, _wasChanged);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CharCommand::redo()
|
|
||||||
{
|
|
||||||
switch (_cmd)
|
|
||||||
{
|
|
||||||
case insert:
|
|
||||||
_chunks->insert(_charPos, _newChar);
|
|
||||||
break;
|
|
||||||
case overwrite:
|
|
||||||
_oldChar = (*_chunks)[_charPos];
|
|
||||||
_wasChanged = _chunks->dataChanged(_charPos);
|
|
||||||
_chunks->overwrite(_charPos, _newChar);
|
|
||||||
break;
|
|
||||||
case removeAt:
|
|
||||||
_oldChar = (*_chunks)[_charPos];
|
|
||||||
_wasChanged = _chunks->dataChanged(_charPos);
|
|
||||||
_chunks->removeAt(_charPos);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UndoStack::UndoStack(Chunks * chunks, QObject * parent)
|
|
||||||
: QUndoStack(parent)
|
|
||||||
{
|
|
||||||
_chunks = chunks;
|
|
||||||
_parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UndoStack::insert(qint64 pos, char c)
|
|
||||||
{
|
|
||||||
if ((pos >= 0) && (pos <= _chunks->size()))
|
|
||||||
{
|
|
||||||
QUndoCommand *cc = new CharCommand(_chunks, CharCommand::insert, pos, c);
|
|
||||||
this->push(cc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UndoStack::insert(qint64 pos, const QByteArray &ba)
|
|
||||||
{
|
|
||||||
if ((pos >= 0) && (pos <= _chunks->size()))
|
|
||||||
{
|
|
||||||
QString txt = QString(tr("Inserting %1 bytes")).arg(ba.size());
|
|
||||||
beginMacro(txt);
|
|
||||||
for (int idx=0; idx < ba.size(); idx++)
|
|
||||||
{
|
|
||||||
QUndoCommand *cc = new CharCommand(_chunks, CharCommand::insert, pos + idx, ba.at(idx));
|
|
||||||
this->push(cc);
|
|
||||||
}
|
|
||||||
endMacro();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UndoStack::removeAt(qint64 pos, qint64 len)
|
|
||||||
{
|
|
||||||
if ((pos >= 0) && (pos < _chunks->size()))
|
|
||||||
{
|
|
||||||
if (len==1)
|
|
||||||
{
|
|
||||||
QUndoCommand *cc = new CharCommand(_chunks, CharCommand::removeAt, pos, char(0));
|
|
||||||
this->push(cc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QString txt = QString(tr("Delete %1 chars")).arg(len);
|
|
||||||
beginMacro(txt);
|
|
||||||
for (qint64 cnt=0; cnt<len; cnt++)
|
|
||||||
{
|
|
||||||
QUndoCommand *cc = new CharCommand(_chunks, CharCommand::removeAt, pos, char(0));
|
|
||||||
push(cc);
|
|
||||||
}
|
|
||||||
endMacro();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UndoStack::overwrite(qint64 pos, char c)
|
|
||||||
{
|
|
||||||
if ((pos >= 0) && (pos < _chunks->size()))
|
|
||||||
{
|
|
||||||
QUndoCommand *cc = new CharCommand(_chunks, CharCommand::overwrite, pos, c);
|
|
||||||
this->push(cc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UndoStack::overwrite(qint64 pos, int len, const QByteArray &ba)
|
|
||||||
{
|
|
||||||
if ((pos >= 0) && (pos < _chunks->size()))
|
|
||||||
{
|
|
||||||
QString txt = QString(tr("Overwrite %1 chars")).arg(len);
|
|
||||||
beginMacro(txt);
|
|
||||||
removeAt(pos, len);
|
|
||||||
insert(pos, ba);
|
|
||||||
endMacro();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
#ifndef COMMANDS_H
|
|
||||||
#define COMMANDS_H
|
|
||||||
|
|
||||||
/** \cond docNever */
|
|
||||||
|
|
||||||
#include <QUndoStack>
|
|
||||||
|
|
||||||
#include "chunks.h"
|
|
||||||
|
|
||||||
/*! CharCommand is a class to provid undo/redo functionality in QHexEdit.
|
|
||||||
A QUndoCommand represents a single editing action on a document. CharCommand
|
|
||||||
is responsable for manipulations on single chars. It can insert. overwrite and
|
|
||||||
remove characters. A manipulation stores allways two actions
|
|
||||||
1. redo (or do) action
|
|
||||||
2. undo action.
|
|
||||||
|
|
||||||
CharCommand also supports command compression via mergeWidht(). This allows
|
|
||||||
the user to execute a undo command contation e.g. 3 steps in a single command.
|
|
||||||
If you for example insert a new byt "34" this means for the editor doing 3
|
|
||||||
steps: insert a "00", overwrite it with "03" and the overwrite it with "34". These
|
|
||||||
3 steps are combined into a single step, insert a "34".
|
|
||||||
|
|
||||||
The byte array oriented commands are just put into a set of single byte commands,
|
|
||||||
which are pooled together with the macroBegin() and macroEnd() functionality of
|
|
||||||
Qt's QUndoStack.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class UndoStack : public QUndoStack
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
UndoStack(Chunks *chunks, QObject * parent=0);
|
|
||||||
void insert(qint64 pos, char c);
|
|
||||||
void insert(qint64 pos, const QByteArray &ba);
|
|
||||||
void removeAt(qint64 pos, qint64 len=1);
|
|
||||||
void overwrite(qint64 pos, char c);
|
|
||||||
void overwrite(qint64 pos, int len, const QByteArray &ba);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Chunks * _chunks;
|
|
||||||
QObject * _parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \endcond docNever */
|
|
||||||
|
|
||||||
#endif // COMMANDS_H
|
|
@ -1,502 +0,0 @@
|
|||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 2.1, February 1999
|
|
||||||
|
|
||||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
[This is the first released version of the Lesser GPL. It also counts
|
|
||||||
as the successor of the GNU Library Public License, version 2, hence
|
|
||||||
the version number 2.1.]
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
Licenses are intended to guarantee your freedom to share and change
|
|
||||||
free software--to make sure the software is free for all its users.
|
|
||||||
|
|
||||||
This license, the Lesser General Public License, applies to some
|
|
||||||
specially designated software packages--typically libraries--of the
|
|
||||||
Free Software Foundation and other authors who decide to use it. You
|
|
||||||
can use it too, but we suggest you first think carefully about whether
|
|
||||||
this license or the ordinary General Public License is the better
|
|
||||||
strategy to use in any particular case, based on the explanations below.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom of use,
|
|
||||||
not price. Our General Public Licenses are designed to make sure that
|
|
||||||
you have the freedom to distribute copies of free software (and charge
|
|
||||||
for this service if you wish); that you receive source code or can get
|
|
||||||
it if you want it; that you can change the software and use pieces of
|
|
||||||
it in new free programs; and that you are informed that you can do
|
|
||||||
these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
distributors to deny you these rights or to ask you to surrender these
|
|
||||||
rights. These restrictions translate to certain responsibilities for
|
|
||||||
you if you distribute copies of the library or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of the library, whether gratis
|
|
||||||
or for a fee, you must give the recipients all the rights that we gave
|
|
||||||
you. You must make sure that they, too, receive or can get the source
|
|
||||||
code. If you link other code with the library, you must provide
|
|
||||||
complete object files to the recipients, so that they can relink them
|
|
||||||
with the library after making changes to the library and recompiling
|
|
||||||
it. And you must show them these terms so they know their rights.
|
|
||||||
|
|
||||||
We protect your rights with a two-step method: (1) we copyright the
|
|
||||||
library, and (2) we offer you this license, which gives you legal
|
|
||||||
permission to copy, distribute and/or modify the library.
|
|
||||||
|
|
||||||
To protect each distributor, we want to make it very clear that
|
|
||||||
there is no warranty for the free library. Also, if the library is
|
|
||||||
modified by someone else and passed on, the recipients should know
|
|
||||||
that what they have is not the original version, so that the original
|
|
||||||
author's reputation will not be affected by problems that might be
|
|
||||||
introduced by others.
|
|
||||||
|
|
||||||
Finally, software patents pose a constant threat to the existence of
|
|
||||||
any free program. We wish to make sure that a company cannot
|
|
||||||
effectively restrict the users of a free program by obtaining a
|
|
||||||
restrictive license from a patent holder. Therefore, we insist that
|
|
||||||
any patent license obtained for a version of the library must be
|
|
||||||
consistent with the full freedom of use specified in this license.
|
|
||||||
|
|
||||||
Most GNU software, including some libraries, is covered by the
|
|
||||||
ordinary GNU General Public License. This license, the GNU Lesser
|
|
||||||
General Public License, applies to certain designated libraries, and
|
|
||||||
is quite different from the ordinary General Public License. We use
|
|
||||||
this license for certain libraries in order to permit linking those
|
|
||||||
libraries into non-free programs.
|
|
||||||
|
|
||||||
When a program is linked with a library, whether statically or using
|
|
||||||
a shared library, the combination of the two is legally speaking a
|
|
||||||
combined work, a derivative of the original library. The ordinary
|
|
||||||
General Public License therefore permits such linking only if the
|
|
||||||
entire combination fits its criteria of freedom. The Lesser General
|
|
||||||
Public License permits more lax criteria for linking other code with
|
|
||||||
the library.
|
|
||||||
|
|
||||||
We call this license the "Lesser" General Public License because it
|
|
||||||
does Less to protect the user's freedom than the ordinary General
|
|
||||||
Public License. It also provides other free software developers Less
|
|
||||||
of an advantage over competing non-free programs. These disadvantages
|
|
||||||
are the reason we use the ordinary General Public License for many
|
|
||||||
libraries. However, the Lesser license provides advantages in certain
|
|
||||||
special circumstances.
|
|
||||||
|
|
||||||
For example, on rare occasions, there may be a special need to
|
|
||||||
encourage the widest possible use of a certain library, so that it becomes
|
|
||||||
a de-facto standard. To achieve this, non-free programs must be
|
|
||||||
allowed to use the library. A more frequent case is that a free
|
|
||||||
library does the same job as widely used non-free libraries. In this
|
|
||||||
case, there is little to gain by limiting the free library to free
|
|
||||||
software only, so we use the Lesser General Public License.
|
|
||||||
|
|
||||||
In other cases, permission to use a particular library in non-free
|
|
||||||
programs enables a greater number of people to use a large body of
|
|
||||||
free software. For example, permission to use the GNU C Library in
|
|
||||||
non-free programs enables many more people to use the whole GNU
|
|
||||||
operating system, as well as its variant, the GNU/Linux operating
|
|
||||||
system.
|
|
||||||
|
|
||||||
Although the Lesser General Public License is Less protective of the
|
|
||||||
users' freedom, it does ensure that the user of a program that is
|
|
||||||
linked with the Library has the freedom and the wherewithal to run
|
|
||||||
that program using a modified version of the Library.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow. Pay close attention to the difference between a
|
|
||||||
"work based on the library" and a "work that uses the library". The
|
|
||||||
former contains code derived from the library, whereas the latter must
|
|
||||||
be combined with the library in order to run.
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License Agreement applies to any software library or other
|
|
||||||
program which contains a notice placed by the copyright holder or
|
|
||||||
other authorized party saying it may be distributed under the terms of
|
|
||||||
this Lesser General Public License (also called "this License").
|
|
||||||
Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
A "library" means a collection of software functions and/or data
|
|
||||||
prepared so as to be conveniently linked with application programs
|
|
||||||
(which use some of those functions and data) to form executables.
|
|
||||||
|
|
||||||
The "Library", below, refers to any such software library or work
|
|
||||||
which has been distributed under these terms. A "work based on the
|
|
||||||
Library" means either the Library or any derivative work under
|
|
||||||
copyright law: that is to say, a work containing the Library or a
|
|
||||||
portion of it, either verbatim or with modifications and/or translated
|
|
||||||
straightforwardly into another language. (Hereinafter, translation is
|
|
||||||
included without limitation in the term "modification".)
|
|
||||||
|
|
||||||
"Source code" for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For a library, complete source code means
|
|
||||||
all the source code for all modules it contains, plus any associated
|
|
||||||
interface definition files, plus the scripts used to control compilation
|
|
||||||
and installation of the library.
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running a program using the Library is not restricted, and output from
|
|
||||||
such a program is covered only if its contents constitute a work based
|
|
||||||
on the Library (independent of the use of the Library in a tool for
|
|
||||||
writing it). Whether that is true depends on what the Library does
|
|
||||||
and what the program that uses the Library does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Library's
|
|
||||||
complete source code as you receive it, in any medium, provided that
|
|
||||||
you conspicuously and appropriately publish on each copy an
|
|
||||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
|
||||||
all the notices that refer to this License and to the absence of any
|
|
||||||
warranty; and distribute a copy of this License along with the
|
|
||||||
Library.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy,
|
|
||||||
and you may at your option offer warranty protection in exchange for a
|
|
||||||
fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Library or any portion
|
|
||||||
of it, thus forming a work based on the Library, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The modified work must itself be a software library.
|
|
||||||
|
|
||||||
b) You must cause the files modified to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
c) You must cause the whole of the work to be licensed at no
|
|
||||||
charge to all third parties under the terms of this License.
|
|
||||||
|
|
||||||
d) If a facility in the modified Library refers to a function or a
|
|
||||||
table of data to be supplied by an application program that uses
|
|
||||||
the facility, other than as an argument passed when the facility
|
|
||||||
is invoked, then you must make a good faith effort to ensure that,
|
|
||||||
in the event an application does not supply such function or
|
|
||||||
table, the facility still operates, and performs whatever part of
|
|
||||||
its purpose remains meaningful.
|
|
||||||
|
|
||||||
(For example, a function in a library to compute square roots has
|
|
||||||
a purpose that is entirely well-defined independent of the
|
|
||||||
application. Therefore, Subsection 2d requires that any
|
|
||||||
application-supplied function or table used by this function must
|
|
||||||
be optional: if the application does not supply it, the square
|
|
||||||
root function must still compute square roots.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Library,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Library, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote
|
|
||||||
it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Library.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Library
|
|
||||||
with the Library (or with a work based on the Library) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
|
||||||
License instead of this License to a given copy of the Library. To do
|
|
||||||
this, you must alter all the notices that refer to this License, so
|
|
||||||
that they refer to the ordinary GNU General Public License, version 2,
|
|
||||||
instead of to this License. (If a newer version than version 2 of the
|
|
||||||
ordinary GNU General Public License has appeared, then you can specify
|
|
||||||
that version instead if you wish.) Do not make any other change in
|
|
||||||
these notices.
|
|
||||||
|
|
||||||
Once this change is made in a given copy, it is irreversible for
|
|
||||||
that copy, so the ordinary GNU General Public License applies to all
|
|
||||||
subsequent copies and derivative works made from that copy.
|
|
||||||
|
|
||||||
This option is useful when you wish to copy part of the code of
|
|
||||||
the Library into a program that is not a library.
|
|
||||||
|
|
||||||
4. You may copy and distribute the Library (or a portion or
|
|
||||||
derivative of it, under Section 2) in object code or executable form
|
|
||||||
under the terms of Sections 1 and 2 above provided that you accompany
|
|
||||||
it with the complete corresponding machine-readable source code, which
|
|
||||||
must be distributed under the terms of Sections 1 and 2 above on a
|
|
||||||
medium customarily used for software interchange.
|
|
||||||
|
|
||||||
If distribution of object code is made by offering access to copy
|
|
||||||
from a designated place, then offering equivalent access to copy the
|
|
||||||
source code from the same place satisfies the requirement to
|
|
||||||
distribute the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
5. A program that contains no derivative of any portion of the
|
|
||||||
Library, but is designed to work with the Library by being compiled or
|
|
||||||
linked with it, is called a "work that uses the Library". Such a
|
|
||||||
work, in isolation, is not a derivative work of the Library, and
|
|
||||||
therefore falls outside the scope of this License.
|
|
||||||
|
|
||||||
However, linking a "work that uses the Library" with the Library
|
|
||||||
creates an executable that is a derivative of the Library (because it
|
|
||||||
contains portions of the Library), rather than a "work that uses the
|
|
||||||
library". The executable is therefore covered by this License.
|
|
||||||
Section 6 states terms for distribution of such executables.
|
|
||||||
|
|
||||||
When a "work that uses the Library" uses material from a header file
|
|
||||||
that is part of the Library, the object code for the work may be a
|
|
||||||
derivative work of the Library even though the source code is not.
|
|
||||||
Whether this is true is especially significant if the work can be
|
|
||||||
linked without the Library, or if the work is itself a library. The
|
|
||||||
threshold for this to be true is not precisely defined by law.
|
|
||||||
|
|
||||||
If such an object file uses only numerical parameters, data
|
|
||||||
structure layouts and accessors, and small macros and small inline
|
|
||||||
functions (ten lines or less in length), then the use of the object
|
|
||||||
file is unrestricted, regardless of whether it is legally a derivative
|
|
||||||
work. (Executables containing this object code plus portions of the
|
|
||||||
Library will still fall under Section 6.)
|
|
||||||
|
|
||||||
Otherwise, if the work is a derivative of the Library, you may
|
|
||||||
distribute the object code for the work under the terms of Section 6.
|
|
||||||
Any executables containing that work also fall under Section 6,
|
|
||||||
whether or not they are linked directly with the Library itself.
|
|
||||||
|
|
||||||
6. As an exception to the Sections above, you may also combine or
|
|
||||||
link a "work that uses the Library" with the Library to produce a
|
|
||||||
work containing portions of the Library, and distribute that work
|
|
||||||
under terms of your choice, provided that the terms permit
|
|
||||||
modification of the work for the customer's own use and reverse
|
|
||||||
engineering for debugging such modifications.
|
|
||||||
|
|
||||||
You must give prominent notice with each copy of the work that the
|
|
||||||
Library is used in it and that the Library and its use are covered by
|
|
||||||
this License. You must supply a copy of this License. If the work
|
|
||||||
during execution displays copyright notices, you must include the
|
|
||||||
copyright notice for the Library among them, as well as a reference
|
|
||||||
directing the user to the copy of this License. Also, you must do one
|
|
||||||
of these things:
|
|
||||||
|
|
||||||
a) Accompany the work with the complete corresponding
|
|
||||||
machine-readable source code for the Library including whatever
|
|
||||||
changes were used in the work (which must be distributed under
|
|
||||||
Sections 1 and 2 above); and, if the work is an executable linked
|
|
||||||
with the Library, with the complete machine-readable "work that
|
|
||||||
uses the Library", as object code and/or source code, so that the
|
|
||||||
user can modify the Library and then relink to produce a modified
|
|
||||||
executable containing the modified Library. (It is understood
|
|
||||||
that the user who changes the contents of definitions files in the
|
|
||||||
Library will not necessarily be able to recompile the application
|
|
||||||
to use the modified definitions.)
|
|
||||||
|
|
||||||
b) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (1) uses at run time a
|
|
||||||
copy of the library already present on the user's computer system,
|
|
||||||
rather than copying library functions into the executable, and (2)
|
|
||||||
will operate properly with a modified version of the library, if
|
|
||||||
the user installs one, as long as the modified version is
|
|
||||||
interface-compatible with the version that the work was made with.
|
|
||||||
|
|
||||||
c) Accompany the work with a written offer, valid for at
|
|
||||||
least three years, to give the same user the materials
|
|
||||||
specified in Subsection 6a, above, for a charge no more
|
|
||||||
than the cost of performing this distribution.
|
|
||||||
|
|
||||||
d) If distribution of the work is made by offering access to copy
|
|
||||||
from a designated place, offer equivalent access to copy the above
|
|
||||||
specified materials from the same place.
|
|
||||||
|
|
||||||
e) Verify that the user has already received a copy of these
|
|
||||||
materials or that you have already sent this user a copy.
|
|
||||||
|
|
||||||
For an executable, the required form of the "work that uses the
|
|
||||||
Library" must include any data and utility programs needed for
|
|
||||||
reproducing the executable from it. However, as a special exception,
|
|
||||||
the materials to be distributed need not include anything that is
|
|
||||||
normally distributed (in either source or binary form) with the major
|
|
||||||
components (compiler, kernel, and so on) of the operating system on
|
|
||||||
which the executable runs, unless that component itself accompanies
|
|
||||||
the executable.
|
|
||||||
|
|
||||||
It may happen that this requirement contradicts the license
|
|
||||||
restrictions of other proprietary libraries that do not normally
|
|
||||||
accompany the operating system. Such a contradiction means you cannot
|
|
||||||
use both them and the Library together in an executable that you
|
|
||||||
distribute.
|
|
||||||
|
|
||||||
7. You may place library facilities that are a work based on the
|
|
||||||
Library side-by-side in a single library together with other library
|
|
||||||
facilities not covered by this License, and distribute such a combined
|
|
||||||
library, provided that the separate distribution of the work based on
|
|
||||||
the Library and of the other library facilities is otherwise
|
|
||||||
permitted, and provided that you do these two things:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work
|
|
||||||
based on the Library, uncombined with any other library
|
|
||||||
facilities. This must be distributed under the terms of the
|
|
||||||
Sections above.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library of the fact
|
|
||||||
that part of it is a work based on the Library, and explaining
|
|
||||||
where to find the accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
8. You may not copy, modify, sublicense, link with, or distribute
|
|
||||||
the Library except as expressly provided under this License. Any
|
|
||||||
attempt otherwise to copy, modify, sublicense, link with, or
|
|
||||||
distribute the Library is void, and will automatically terminate your
|
|
||||||
rights under this License. However, parties who have received copies,
|
|
||||||
or rights, from you under this License will not have their licenses
|
|
||||||
terminated so long as such parties remain in full compliance.
|
|
||||||
|
|
||||||
9. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Library or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Library (or any work based on the
|
|
||||||
Library), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Library or works based on it.
|
|
||||||
|
|
||||||
10. Each time you redistribute the Library (or any work based on the
|
|
||||||
Library), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute, link with or modify the Library
|
|
||||||
subject to these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties with
|
|
||||||
this License.
|
|
||||||
|
|
||||||
11. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Library at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Library by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Library.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under any
|
|
||||||
particular circumstance, the balance of the section is intended to apply,
|
|
||||||
and the section as a whole is intended to apply in other circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
12. If the distribution and/or use of the Library is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Library under this License may add
|
|
||||||
an explicit geographical distribution limitation excluding those countries,
|
|
||||||
so that distribution is permitted only in or among countries not thus
|
|
||||||
excluded. In such case, this License incorporates the limitation as if
|
|
||||||
written in the body of this License.
|
|
||||||
|
|
||||||
13. The Free Software Foundation may publish revised and/or new
|
|
||||||
versions of the Lesser General Public License from time to time.
|
|
||||||
Such new versions will be similar in spirit to the present version,
|
|
||||||
but may differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Library
|
|
||||||
specifies a version number of this License which applies to it and
|
|
||||||
"any later version", you have the option of following the terms and
|
|
||||||
conditions either of that version or of any later version published by
|
|
||||||
the Free Software Foundation. If the Library does not specify a
|
|
||||||
license version number, you may choose any version ever published by
|
|
||||||
the Free Software Foundation.
|
|
||||||
|
|
||||||
14. If you wish to incorporate parts of the Library into other free
|
|
||||||
programs whose distribution conditions are incompatible with these,
|
|
||||||
write to the author to ask for permission. For software which is
|
|
||||||
copyrighted by the Free Software Foundation, write to the Free
|
|
||||||
Software Foundation; we sometimes make exceptions for this. Our
|
|
||||||
decision will be guided by the two goals of preserving the free status
|
|
||||||
of all derivatives of our free software and of promoting the sharing
|
|
||||||
and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
|
||||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
|
||||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
|
||||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
|
||||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
|
||||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
|
||||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
|
||||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
|
||||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
|
||||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
|
||||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
|
||||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
|
||||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
|
||||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|
||||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Libraries
|
|
||||||
|
|
||||||
If you develop a new library, and you want it to be of the greatest
|
|
||||||
possible use to the public, we recommend making it free software that
|
|
||||||
everyone can redistribute and change. You can do so by permitting
|
|
||||||
redistribution under these terms (or, alternatively, under the terms of the
|
|
||||||
ordinary General Public License).
|
|
||||||
|
|
||||||
To apply these terms, attach the following notices to the library. It is
|
|
||||||
safest to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least the
|
|
||||||
"copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the library's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
|
||||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1990
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
That's all there is to it!
|
|
File diff suppressed because it is too large
Load Diff
@ -1,411 +0,0 @@
|
|||||||
#ifndef QHEXEDIT_H
|
|
||||||
#define QHEXEDIT_H
|
|
||||||
|
|
||||||
#include <QAbstractScrollArea>
|
|
||||||
#include <QPen>
|
|
||||||
#include <QBrush>
|
|
||||||
|
|
||||||
#include "chunks.h"
|
|
||||||
#include "commands.h"
|
|
||||||
|
|
||||||
#ifdef QHEXEDIT_EXPORTS
|
|
||||||
#define QHEXEDIT_API Q_DECL_EXPORT
|
|
||||||
#elif QHEXEDIT_IMPORTS
|
|
||||||
#define QHEXEDIT_API Q_DECL_IMPORT
|
|
||||||
#else
|
|
||||||
#define QHEXEDIT_API
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \mainpage
|
|
||||||
QHexEdit is a binary editor widget for Qt.
|
|
||||||
|
|
||||||
\version Version 0.8.2
|
|
||||||
\image html qhexedit.png
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** QHexEdit is a hex editor widget written in C++ for the Qt (Qt4, Qt5) framework.
|
|
||||||
It is a simple editor for binary data, just like QPlainTextEdit is for text
|
|
||||||
data. There are sip configuration files included, so it is easy to create
|
|
||||||
bindings for PyQt and you can use this widget also in python 2 and 3.
|
|
||||||
|
|
||||||
QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use
|
|
||||||
the mouse or the keyboard to navigate inside the widget. If you hit the keys
|
|
||||||
(0..9, a..f) you will change the data. Changed data is highlighted and can be
|
|
||||||
accessed via data().
|
|
||||||
|
|
||||||
Normaly QHexEdit works in the overwrite Mode. You can set overwriteMode(false)
|
|
||||||
and insert data. In this case the size of data() increases. It is also possible
|
|
||||||
to delete bytes (del or backspace), here the size of data decreases.
|
|
||||||
|
|
||||||
You can select data with keyboard hits or mouse movements. The copy-key will
|
|
||||||
copy the selected data into the clipboard. The cut-key copies also but delets
|
|
||||||
it afterwards. In overwrite mode, the paste function overwrites the content of
|
|
||||||
the (does not change the length) data. In insert mode, clipboard data will be
|
|
||||||
inserted. The clipboard content is expected in ASCII Hex notation. Unknown
|
|
||||||
characters will be ignored.
|
|
||||||
|
|
||||||
QHexEdit comes with undo/redo functionality. All changes can be undone, by
|
|
||||||
pressing the undo-key (usually ctr-z). They can also be redone afterwards.
|
|
||||||
The undo/redo framework is cleared, when setData() sets up a new
|
|
||||||
content for the editor. You can search data inside the content with indexOf()
|
|
||||||
and lastIndexOf(). The replace() function is to change located subdata. This
|
|
||||||
'replaced' data can also be undone by the undo/redo framework.
|
|
||||||
|
|
||||||
QHexEdit is based on QIODevice, that's why QHexEdit can handle big amounts of
|
|
||||||
data. The size of edited data can be more then two gigabytes without any
|
|
||||||
restrictions.
|
|
||||||
*/
|
|
||||||
class QHEXEDIT_API QHexEdit : public QAbstractScrollArea
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
/*! Property address area switch the address area on or off. Set addressArea true
|
|
||||||
(show it), false (hide it).
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(bool addressArea READ addressArea WRITE setAddressArea)
|
|
||||||
|
|
||||||
/*! Property address area color sets (setAddressAreaColor()) the backgorund
|
|
||||||
color of address areas. You can also read the color (addressaAreaColor()).
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor)
|
|
||||||
|
|
||||||
/*! Property addressOffset is added to the Numbers of the Address Area.
|
|
||||||
A offset in the address area (left side) is sometimes usefull, whe you show
|
|
||||||
only a segment of a complete memory picture. With setAddressOffset() you set
|
|
||||||
this property - with addressOffset() you get the current value.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(qint64 addressOffset READ addressOffset WRITE setAddressOffset)
|
|
||||||
|
|
||||||
/*! Set and get the minimum width of the address area, width in characters.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(int addressWidth READ addressWidth WRITE setAddressWidth)
|
|
||||||
|
|
||||||
/*! Switch the ascii area on (true, show it) or off (false, hide it).
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(bool asciiArea READ asciiArea WRITE setAsciiArea)
|
|
||||||
|
|
||||||
/*! Set and get bytes number per line.*/
|
|
||||||
Q_PROPERTY(int bytesPerLine READ bytesPerLine WRITE setBytesPerLine)
|
|
||||||
|
|
||||||
/*! Porperty cursorPosition sets or gets the position of the editor cursor
|
|
||||||
in QHexEdit. Every byte in data has to cursor positions: the lower and upper
|
|
||||||
Nibble. Maximum cursor position is factor two of data.size().
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(qint64 cursorPosition READ cursorPosition WRITE setCursorPosition)
|
|
||||||
|
|
||||||
/*! Property data holds the content of QHexEdit. Call setData() to set the
|
|
||||||
content of QHexEdit, data() returns the actual content. When calling setData()
|
|
||||||
with a QByteArray as argument, QHexEdit creates a internal copy of the data
|
|
||||||
If you want to edit big files please use setData(), based on QIODevice.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(QByteArray data READ data WRITE setData NOTIFY dataChanged)
|
|
||||||
|
|
||||||
/*! Switch the highlighting feature on or of: true (show it), false (hide it).
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(bool highlighting READ highlighting WRITE setHighlighting)
|
|
||||||
|
|
||||||
/*! Property highlighting color sets (setHighlightingColor()) the backgorund
|
|
||||||
color of highlighted text areas. You can also read the color
|
|
||||||
(highlightingColor()).
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor)
|
|
||||||
|
|
||||||
/*! Porperty overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode
|
|
||||||
in which the editor works. In overwrite mode the user will overwrite existing data. The
|
|
||||||
size of data will be constant. In insert mode the size will grow, when inserting
|
|
||||||
new data.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode)
|
|
||||||
|
|
||||||
/*! Property selection color sets (setSelectionColor()) the backgorund
|
|
||||||
color of selected text areas. You can also read the color
|
|
||||||
(selectionColor()).
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor)
|
|
||||||
|
|
||||||
/*! Property readOnly sets (setReadOnly()) or gets (isReadOnly) the mode
|
|
||||||
in which the editor works. In readonly mode the the user can only navigate
|
|
||||||
through the data and select data; modifying is not possible. This
|
|
||||||
property's default is false.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
|
|
||||||
|
|
||||||
/*! Property upperCase sets (setUpperCase()) or gets (isUpperCase) the case of hex
|
|
||||||
data. Default is lowercase.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(bool upperCase READ isUpperCase WRITE setUpperCase)
|
|
||||||
|
|
||||||
/*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/
|
|
||||||
Q_PROPERTY(QFont font READ font WRITE setFont)
|
|
||||||
|
|
||||||
public:
|
|
||||||
/*! Creates an instance of QHexEdit.
|
|
||||||
\param parent Parent widget of QHexEdit.
|
|
||||||
*/
|
|
||||||
QHexEdit(QWidget *parent=0);
|
|
||||||
|
|
||||||
// Access to data of qhexedit
|
|
||||||
|
|
||||||
/*! Sets the data of QHexEdit. The QIODevice will be opend just before reading
|
|
||||||
and closed immediately afterwards. This is to allow other programs to rewrite
|
|
||||||
the file while editing it.
|
|
||||||
*/
|
|
||||||
bool setData(QIODevice &iODevice);
|
|
||||||
|
|
||||||
/*! Gives back the data as a QByteArray starting at position \param pos and
|
|
||||||
delivering \param count bytes.
|
|
||||||
*/
|
|
||||||
QByteArray dataAt(qint64 pos, qint64 count=-1);
|
|
||||||
|
|
||||||
/*! Gives back the data into a \param iODevice starting at position \param pos
|
|
||||||
and delivering \param count bytes.
|
|
||||||
*/
|
|
||||||
bool write(QIODevice &iODevice, qint64 pos=0, qint64 count=-1);
|
|
||||||
|
|
||||||
|
|
||||||
// Char handling
|
|
||||||
|
|
||||||
/*! Inserts a char.
|
|
||||||
\param pos Index position, where to insert
|
|
||||||
\param ch Char, which is to insert
|
|
||||||
The char will be inserted and size of data grows.
|
|
||||||
*/
|
|
||||||
void insert(qint64 pos, char ch);
|
|
||||||
|
|
||||||
/*! Removes len bytes from the content.
|
|
||||||
\param pos Index position, where to remove
|
|
||||||
\param len Amount of bytes to remove
|
|
||||||
*/
|
|
||||||
void remove(qint64 pos, qint64 len=1);
|
|
||||||
|
|
||||||
/*! Replaces a char.
|
|
||||||
\param pos Index position, where to overwrite
|
|
||||||
\param ch Char, which is to insert
|
|
||||||
The char will be overwritten and size remains constant.
|
|
||||||
*/
|
|
||||||
void replace(qint64 pos, char ch);
|
|
||||||
|
|
||||||
|
|
||||||
// ByteArray handling
|
|
||||||
|
|
||||||
/*! Inserts a byte array.
|
|
||||||
\param pos Index position, where to insert
|
|
||||||
\param ba QByteArray, which is to insert
|
|
||||||
The QByteArray will be inserted and size of data grows.
|
|
||||||
*/
|
|
||||||
void insert(qint64 pos, const QByteArray &ba);
|
|
||||||
|
|
||||||
/*! Replaces \param len bytes with a byte array \param ba
|
|
||||||
\param pos Index position, where to overwrite
|
|
||||||
\param ba QByteArray, which is inserted
|
|
||||||
\param len count of bytes to overwrite
|
|
||||||
The data is overwritten and size of data may change.
|
|
||||||
*/
|
|
||||||
void replace(qint64 pos, qint64 len, const QByteArray &ba);
|
|
||||||
|
|
||||||
|
|
||||||
// Utility functioins
|
|
||||||
/*! Calc cursor position from graphics position
|
|
||||||
* \param point from where the cursor position should be calculated
|
|
||||||
* \return Cursor postioin
|
|
||||||
*/
|
|
||||||
qint64 cursorPosition(QPoint point);
|
|
||||||
|
|
||||||
/*! Ensure the cursor to be visble
|
|
||||||
*/
|
|
||||||
void ensureVisible();
|
|
||||||
|
|
||||||
/*! Find first occurence of ba in QHexEdit data
|
|
||||||
* \param ba Data to find
|
|
||||||
* \param from Point where the search starts
|
|
||||||
* \return pos if fond, else -1
|
|
||||||
*/
|
|
||||||
qint64 indexOf(const QByteArray &ba, qint64 from);
|
|
||||||
|
|
||||||
/*! Returns if any changes where done on document
|
|
||||||
* \return true when document is modified else false
|
|
||||||
*/
|
|
||||||
bool isModified();
|
|
||||||
|
|
||||||
/*! Find last occurence of ba in QHexEdit data
|
|
||||||
* \param ba Data to find
|
|
||||||
* \param from Point where the search starts
|
|
||||||
* \return pos if fond, else -1
|
|
||||||
*/
|
|
||||||
qint64 lastIndexOf(const QByteArray &ba, qint64 from);
|
|
||||||
|
|
||||||
/*! Gives back a formatted image of the selected content of QHexEdit
|
|
||||||
*/
|
|
||||||
QString selectionToReadableString();
|
|
||||||
|
|
||||||
/*! Set Font of QHexEdit
|
|
||||||
* \param font
|
|
||||||
*/
|
|
||||||
void setFont(const QFont &font);
|
|
||||||
|
|
||||||
/*! Gives back a formatted image of the content of QHexEdit
|
|
||||||
*/
|
|
||||||
QString toReadableString();
|
|
||||||
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
/*! Redoes the last operation. If there is no operation to redo, i.e.
|
|
||||||
there is no redo step in the undo/redo history, nothing happens.
|
|
||||||
*/
|
|
||||||
void redo();
|
|
||||||
|
|
||||||
/*! Undoes the last operation. If there is no operation to undo, i.e.
|
|
||||||
there is no undo step in the undo/redo history, nothing happens.
|
|
||||||
*/
|
|
||||||
void undo();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
|
|
||||||
/*! Contains the address, where the cursor is located. */
|
|
||||||
void currentAddressChanged(qint64 address);
|
|
||||||
|
|
||||||
/*! Contains the size of the data to edit. */
|
|
||||||
void currentSizeChanged(qint64 size);
|
|
||||||
|
|
||||||
/*! The signal is emitted every time, the data is changed. */
|
|
||||||
void dataChanged();
|
|
||||||
|
|
||||||
/*! The signal is emitted every time, the overwrite mode is changed. */
|
|
||||||
void overwriteModeChanged(bool state);
|
|
||||||
|
|
||||||
|
|
||||||
/*! \cond docNever */
|
|
||||||
public:
|
|
||||||
~QHexEdit();
|
|
||||||
|
|
||||||
// Properties
|
|
||||||
bool addressArea();
|
|
||||||
void setAddressArea(bool addressArea);
|
|
||||||
|
|
||||||
QColor addressAreaColor();
|
|
||||||
void setAddressAreaColor(const QColor &color);
|
|
||||||
|
|
||||||
qint64 addressOffset();
|
|
||||||
void setAddressOffset(qint64 addressArea);
|
|
||||||
|
|
||||||
int addressWidth();
|
|
||||||
void setAddressWidth(int addressWidth);
|
|
||||||
|
|
||||||
bool asciiArea();
|
|
||||||
void setAsciiArea(bool asciiArea);
|
|
||||||
|
|
||||||
int bytesPerLine();
|
|
||||||
void setBytesPerLine(int count);
|
|
||||||
|
|
||||||
qint64 cursorPosition();
|
|
||||||
void setCursorPosition(qint64 position);
|
|
||||||
|
|
||||||
QByteArray data();
|
|
||||||
void setData(const QByteArray &ba);
|
|
||||||
|
|
||||||
bool highlighting();
|
|
||||||
void setHighlighting(bool mode);
|
|
||||||
|
|
||||||
QColor highlightingColor();
|
|
||||||
void setHighlightingColor(const QColor &color);
|
|
||||||
|
|
||||||
bool overwriteMode();
|
|
||||||
void setOverwriteMode(bool overwriteMode);
|
|
||||||
|
|
||||||
bool isReadOnly();
|
|
||||||
void setReadOnly(bool readOnly);
|
|
||||||
|
|
||||||
bool isUpperCase();
|
|
||||||
void setUpperCase(bool upperCase);
|
|
||||||
|
|
||||||
QColor selectionColor();
|
|
||||||
void setSelectionColor(const QColor &color);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Handle events
|
|
||||||
void keyPressEvent(QKeyEvent *event);
|
|
||||||
void mouseMoveEvent(QMouseEvent * event);
|
|
||||||
void mousePressEvent(QMouseEvent * event);
|
|
||||||
void paintEvent(QPaintEvent *event);
|
|
||||||
void resizeEvent(QResizeEvent *);
|
|
||||||
virtual bool focusNextPrevChild(bool next);
|
|
||||||
private:
|
|
||||||
// Handle selections
|
|
||||||
void resetSelection(qint64 pos); // set selectionStart and selectionEnd to pos
|
|
||||||
void resetSelection(); // set selectionEnd to selectionStart
|
|
||||||
void setSelection(qint64 pos); // set min (if below init) or max (if greater init)
|
|
||||||
int getSelectionBegin();
|
|
||||||
int getSelectionEnd();
|
|
||||||
|
|
||||||
// Private utility functions
|
|
||||||
void init();
|
|
||||||
void readBuffers();
|
|
||||||
QString toReadable(const QByteArray &ba);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void adjust(); // recalc pixel positions
|
|
||||||
void dataChangedPrivate(int idx=0); // emit dataChanged() signal
|
|
||||||
void refresh(); // ensureVisible() and readBuffers()
|
|
||||||
void updateCursor(); // update blinking cursor
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Name convention: pixel positions start with _px
|
|
||||||
int _pxCharWidth, _pxCharHeight; // char dimensions (dpendend on font)
|
|
||||||
int _pxPosHexX; // X-Pos of HeaxArea
|
|
||||||
int _pxPosAdrX; // X-Pos of Address Area
|
|
||||||
int _pxPosAsciiX; // X-Pos of Ascii Area
|
|
||||||
int _pxGapAdr; // gap left from AddressArea
|
|
||||||
int _pxGapAdrHex; // gap between AddressArea and HexAerea
|
|
||||||
int _pxGapHexAscii; // gap between HexArea and AsciiArea
|
|
||||||
int _pxCursorWidth; // cursor width
|
|
||||||
int _pxSelectionSub; // offset selection rect
|
|
||||||
int _pxCursorX; // current cursor pos
|
|
||||||
int _pxCursorY; // current cursor pos
|
|
||||||
|
|
||||||
// Name convention: absolute byte positions in chunks start with _b
|
|
||||||
qint64 _bSelectionBegin; // first position of Selection
|
|
||||||
qint64 _bSelectionEnd; // end of Selection
|
|
||||||
qint64 _bSelectionInit; // memory position of Selection
|
|
||||||
qint64 _bPosFirst; // position of first byte shown
|
|
||||||
qint64 _bPosLast; // position of last byte shown
|
|
||||||
qint64 _bPosCurrent; // current position
|
|
||||||
|
|
||||||
// variables to store the property values
|
|
||||||
bool _addressArea; // left area of QHexEdit
|
|
||||||
QColor _addressAreaColor;
|
|
||||||
int _addressWidth;
|
|
||||||
bool _asciiArea;
|
|
||||||
qint64 _addressOffset;
|
|
||||||
int _bytesPerLine;
|
|
||||||
int _hexCharsInLine;
|
|
||||||
bool _highlighting;
|
|
||||||
bool _overwriteMode;
|
|
||||||
QBrush _brushSelection;
|
|
||||||
QPen _penSelection;
|
|
||||||
QBrush _brushHighlighted;
|
|
||||||
QPen _penHighlighted;
|
|
||||||
bool _readOnly;
|
|
||||||
bool _upperCase;
|
|
||||||
|
|
||||||
// other variables
|
|
||||||
bool _editAreaIsAscii; // flag about the ascii mode edited
|
|
||||||
int _addrDigits; // real no of addressdigits, may be > addressWidth
|
|
||||||
bool _blink; // help get cursor blinking
|
|
||||||
QBuffer _bData; // buffer, when setup with QByteArray
|
|
||||||
Chunks *_chunks; // IODevice based access to data
|
|
||||||
QTimer _cursorTimer; // for blinking cursor
|
|
||||||
qint64 _cursorPosition; // absolute position of cursor, 1 Byte == 2 tics
|
|
||||||
QRect _cursorRect; // physical dimensions of cursor
|
|
||||||
QByteArray _data; // QHexEdit's data, when setup with QByteArray
|
|
||||||
QByteArray _dataShown; // data in the current View
|
|
||||||
QByteArray _hexDataShown; // data in view, transformed to hex
|
|
||||||
qint64 _lastEventSize; // size, which was emitted last time
|
|
||||||
QByteArray _markedShown; // marked data in view
|
|
||||||
bool _modified; // Is any data in editor modified?
|
|
||||||
int _rowsShown; // lines of text shown
|
|
||||||
UndoStack * _undoStack; // Stack to store edit actions for undo/redo
|
|
||||||
/*! \endcond docNever */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QHEXEDIT_H
|
|
20
UEFITool/qhexview5/LICENSE
Normal file
20
UEFITool/qhexview5/LICENSE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Dax89
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
130
UEFITool/qhexview5/model/buffer/qdevicebuffer.cpp
Normal file
130
UEFITool/qhexview5/model/buffer/qdevicebuffer.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include "qdevicebuffer.h"
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
QDeviceBuffer::QDeviceBuffer(QObject *parent) : QHexBuffer{parent} { }
|
||||||
|
|
||||||
|
QDeviceBuffer::~QDeviceBuffer()
|
||||||
|
{
|
||||||
|
if(!m_device) return;
|
||||||
|
|
||||||
|
if(m_device->parent() == this)
|
||||||
|
{
|
||||||
|
if(m_device->isOpen()) m_device->close();
|
||||||
|
m_device->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar QDeviceBuffer::at(qint64 idx)
|
||||||
|
{
|
||||||
|
m_device->seek(idx);
|
||||||
|
|
||||||
|
char c = '\0';
|
||||||
|
m_device->getChar(&c);
|
||||||
|
return static_cast<uchar>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 QDeviceBuffer::length() const { return m_device->size(); }
|
||||||
|
|
||||||
|
void QDeviceBuffer::insert(qint64 offset, const QByteArray &data)
|
||||||
|
{
|
||||||
|
Q_UNUSED(offset)
|
||||||
|
Q_UNUSED(data)
|
||||||
|
// Not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
void QDeviceBuffer::replace(qint64 offset, const QByteArray& data)
|
||||||
|
{
|
||||||
|
m_device->seek(offset);
|
||||||
|
m_device->write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QDeviceBuffer::remove(qint64 offset, int length)
|
||||||
|
{
|
||||||
|
Q_UNUSED(offset)
|
||||||
|
Q_UNUSED(length)
|
||||||
|
// Not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray QDeviceBuffer::read(qint64 offset, int length)
|
||||||
|
{
|
||||||
|
m_device->seek(offset);
|
||||||
|
return m_device->read(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QDeviceBuffer::read(QIODevice *device)
|
||||||
|
{
|
||||||
|
m_device = device;
|
||||||
|
if(!m_device) return false;
|
||||||
|
if(!m_device->isOpen()) m_device->open(QIODevice::ReadWrite);
|
||||||
|
return m_device->isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QDeviceBuffer::write(QIODevice *device)
|
||||||
|
{
|
||||||
|
Q_UNUSED(device)
|
||||||
|
// Not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 QDeviceBuffer::indexOf(const QByteArray& ba, qint64 from)
|
||||||
|
{
|
||||||
|
const auto MAX = std::numeric_limits<int>::max();
|
||||||
|
qint64 idx = -1;
|
||||||
|
|
||||||
|
if(from < m_device->size())
|
||||||
|
{
|
||||||
|
idx = from;
|
||||||
|
m_device->seek(from);
|
||||||
|
|
||||||
|
while(idx < m_device->size())
|
||||||
|
{
|
||||||
|
QByteArray data = m_device->read(MAX);
|
||||||
|
int sidx = data.indexOf(ba);
|
||||||
|
|
||||||
|
if(sidx >= 0)
|
||||||
|
{
|
||||||
|
idx += sidx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(idx + data.size() >= m_device->size()) return -1;
|
||||||
|
m_device->seek(m_device->pos() + data.size() - ba.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 QDeviceBuffer::lastIndexOf(const QByteArray& ba, qint64 from)
|
||||||
|
{
|
||||||
|
const auto MAX = std::numeric_limits<int>::max();
|
||||||
|
qint64 idx = -1;
|
||||||
|
|
||||||
|
if(from >= 0 && ba.size() < MAX)
|
||||||
|
{
|
||||||
|
qint64 currpos = from;
|
||||||
|
|
||||||
|
while(currpos >= 0)
|
||||||
|
{
|
||||||
|
qint64 readpos = (currpos < MAX) ? 0 : currpos - MAX;
|
||||||
|
m_device->seek(readpos);
|
||||||
|
|
||||||
|
QByteArray data = m_device->read(currpos - readpos);
|
||||||
|
int lidx = data.lastIndexOf(ba, from);
|
||||||
|
|
||||||
|
if(lidx >= 0)
|
||||||
|
{
|
||||||
|
idx = readpos + lidx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(readpos <= 0) break;
|
||||||
|
currpos = readpos + ba.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
25
UEFITool/qhexview5/model/buffer/qdevicebuffer.h
Normal file
25
UEFITool/qhexview5/model/buffer/qdevicebuffer.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qhexbuffer.h"
|
||||||
|
|
||||||
|
class QDeviceBuffer : public QHexBuffer
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QDeviceBuffer(QObject *parent = nullptr);
|
||||||
|
virtual ~QDeviceBuffer();
|
||||||
|
uchar at(qint64 idx) override;
|
||||||
|
qint64 length() const override;
|
||||||
|
void insert(qint64 offset, const QByteArray& data) override;
|
||||||
|
void replace(qint64 offset, const QByteArray& data) override;
|
||||||
|
void remove(qint64 offset, int length) override;
|
||||||
|
QByteArray read(qint64 offset, int length) override;
|
||||||
|
bool read(QIODevice* device) override;
|
||||||
|
void write(QIODevice* device) override;
|
||||||
|
qint64 indexOf(const QByteArray& ba, qint64 from) override;
|
||||||
|
qint64 lastIndexOf(const QByteArray& ba, qint64 from) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QIODevice* m_device{nullptr};
|
||||||
|
};
|
35
UEFITool/qhexview5/model/buffer/qhexbuffer.cpp
Normal file
35
UEFITool/qhexview5/model/buffer/qhexbuffer.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "qhexbuffer.h"
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
|
QHexBuffer::QHexBuffer(QObject *parent) : QObject{parent} { }
|
||||||
|
uchar QHexBuffer::at(qint64 idx) { return this->read(idx, 1).at(0); }
|
||||||
|
bool QHexBuffer::isEmpty() const { return this->length() <= 0; }
|
||||||
|
|
||||||
|
void QHexBuffer::replace(qint64 offset, const QByteArray &data)
|
||||||
|
{
|
||||||
|
this->remove(offset, data.length());
|
||||||
|
this->insert(offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexBuffer::read(char *data, int size)
|
||||||
|
{
|
||||||
|
QBuffer* buffer = new QBuffer(this);
|
||||||
|
buffer->setData(data, size);
|
||||||
|
|
||||||
|
if(!buffer->isOpen())
|
||||||
|
buffer->open(QBuffer::ReadWrite);
|
||||||
|
|
||||||
|
this->read(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexBuffer::read(const QByteArray &ba)
|
||||||
|
{
|
||||||
|
QBuffer* buffer = new QBuffer(this);
|
||||||
|
|
||||||
|
buffer->setData(ba);
|
||||||
|
if(!buffer->isOpen())
|
||||||
|
buffer->open(QBuffer::ReadWrite);
|
||||||
|
|
||||||
|
this->read(buffer);
|
||||||
|
}
|
||||||
|
|
30
UEFITool/qhexview5/model/buffer/qhexbuffer.h
Normal file
30
UEFITool/qhexview5/model/buffer/qhexbuffer.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QIODevice>
|
||||||
|
|
||||||
|
class QHexBuffer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QHexBuffer(QObject *parent = nullptr);
|
||||||
|
bool isEmpty() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual uchar at(qint64 idx);
|
||||||
|
virtual void replace(qint64 offset, const QByteArray& data);
|
||||||
|
virtual void read(char* data, int size);
|
||||||
|
virtual void read(const QByteArray& ba);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual qint64 length() const = 0;
|
||||||
|
virtual void insert(qint64 offset, const QByteArray& data) = 0;
|
||||||
|
virtual void remove(qint64 offset, int length) = 0;
|
||||||
|
virtual QByteArray read(qint64 offset, int length) = 0;
|
||||||
|
virtual bool read(QIODevice* iodevice) = 0;
|
||||||
|
virtual void write(QIODevice* iodevice) = 0;
|
||||||
|
virtual qint64 indexOf(const QByteArray& ba, qint64 from) = 0;
|
||||||
|
virtual qint64 lastIndexOf(const QByteArray& ba, qint64 from) = 0;
|
||||||
|
|
||||||
|
};
|
19
UEFITool/qhexview5/model/buffer/qmemorybuffer.cpp
Normal file
19
UEFITool/qhexview5/model/buffer/qmemorybuffer.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "qmemorybuffer.h"
|
||||||
|
#include <QIODevice>
|
||||||
|
|
||||||
|
QMemoryBuffer::QMemoryBuffer(QObject *parent) : QHexBuffer{parent} { }
|
||||||
|
uchar QMemoryBuffer::at(qint64 idx) { return static_cast<uchar>(m_buffer.at(idx)); }
|
||||||
|
qint64 QMemoryBuffer::length() const { return static_cast<qint64>(m_buffer.length()); }
|
||||||
|
void QMemoryBuffer::insert(qint64 offset, const QByteArray &data) { m_buffer.insert(static_cast<int>(offset), data); }
|
||||||
|
void QMemoryBuffer::remove(qint64 offset, int length) { m_buffer.remove(static_cast<int>(offset), length); }
|
||||||
|
QByteArray QMemoryBuffer::read(qint64 offset, int length) { return m_buffer.mid(static_cast<int>(offset), length); }
|
||||||
|
|
||||||
|
bool QMemoryBuffer::read(QIODevice *device)
|
||||||
|
{
|
||||||
|
m_buffer = device->readAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QMemoryBuffer::write(QIODevice *device) { device->write(m_buffer); }
|
||||||
|
qint64 QMemoryBuffer::indexOf(const QByteArray& ba, qint64 from) { return m_buffer.indexOf(ba, static_cast<int>(from)); }
|
||||||
|
qint64 QMemoryBuffer::lastIndexOf(const QByteArray& ba, qint64 from) { return m_buffer.lastIndexOf(ba, static_cast<int>(from)); }
|
23
UEFITool/qhexview5/model/buffer/qmemorybuffer.h
Normal file
23
UEFITool/qhexview5/model/buffer/qmemorybuffer.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qhexbuffer.h"
|
||||||
|
|
||||||
|
class QMemoryBuffer : public QHexBuffer
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QMemoryBuffer(QObject *parent = nullptr);
|
||||||
|
uchar at(qint64 idx) override;
|
||||||
|
qint64 length() const override;
|
||||||
|
void insert(qint64 offset, const QByteArray& data) override;
|
||||||
|
void remove(qint64 offset, int length) override;
|
||||||
|
QByteArray read(qint64 offset, int length) override;
|
||||||
|
bool read(QIODevice* device) override;
|
||||||
|
void write(QIODevice* device) override;
|
||||||
|
qint64 indexOf(const QByteArray& ba, qint64 from) override;
|
||||||
|
qint64 lastIndexOf(const QByteArray& ba, qint64 from) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray m_buffer;
|
||||||
|
};
|
3
UEFITool/qhexview5/model/commands/hexcommand.cpp
Normal file
3
UEFITool/qhexview5/model/commands/hexcommand.cpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "hexcommand.h"
|
||||||
|
|
||||||
|
HexCommand::HexCommand(QHexBuffer *buffer, QHexDocument* document, QUndoCommand *parent): QUndoCommand(parent), m_hexdocument(document), m_buffer(buffer), m_offset(0), m_length(0) { }
|
19
UEFITool/qhexview5/model/commands/hexcommand.h
Normal file
19
UEFITool/qhexview5/model/commands/hexcommand.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QUndoCommand>
|
||||||
|
#include "../buffer/qhexbuffer.h"
|
||||||
|
|
||||||
|
class QHexDocument;
|
||||||
|
|
||||||
|
class HexCommand: public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HexCommand(QHexBuffer* buffer, QHexDocument* document, QUndoCommand* parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QHexDocument* m_hexdocument;
|
||||||
|
QHexBuffer* m_buffer;
|
||||||
|
qint64 m_offset;
|
||||||
|
int m_length;
|
||||||
|
QByteArray m_data;
|
||||||
|
};
|
16
UEFITool/qhexview5/model/commands/insertcommand.cpp
Normal file
16
UEFITool/qhexview5/model/commands/insertcommand.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include "insertcommand.h"
|
||||||
|
#include "../qhexdocument.h"
|
||||||
|
|
||||||
|
InsertCommand::InsertCommand(QHexBuffer *buffer, QHexDocument* document, qint64 offset, const QByteArray &data, QUndoCommand *parent): HexCommand(buffer, document, parent)
|
||||||
|
{
|
||||||
|
m_offset = offset;
|
||||||
|
m_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertCommand::undo()
|
||||||
|
{
|
||||||
|
m_buffer->remove(m_offset, m_data.length());
|
||||||
|
Q_EMIT m_hexdocument->dataChanged(m_data, m_offset, QHexDocument::ChangeReason::Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertCommand::redo() { m_buffer->insert(m_offset, m_data); }
|
11
UEFITool/qhexview5/model/commands/insertcommand.h
Normal file
11
UEFITool/qhexview5/model/commands/insertcommand.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hexcommand.h"
|
||||||
|
|
||||||
|
class InsertCommand: public HexCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InsertCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, const QByteArray& data, QUndoCommand* parent = nullptr);
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
};
|
20
UEFITool/qhexview5/model/commands/removecommand.cpp
Normal file
20
UEFITool/qhexview5/model/commands/removecommand.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "removecommand.h"
|
||||||
|
#include "../qhexdocument.h"
|
||||||
|
|
||||||
|
RemoveCommand::RemoveCommand(QHexBuffer *buffer, QHexDocument* document, qint64 offset, int length, QUndoCommand *parent): HexCommand(buffer, document, parent)
|
||||||
|
{
|
||||||
|
m_offset = offset;
|
||||||
|
m_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveCommand::undo()
|
||||||
|
{
|
||||||
|
m_buffer->insert(m_offset, m_data);
|
||||||
|
Q_EMIT m_hexdocument->dataChanged(m_data, m_offset, QHexDocument::ChangeReason::Insert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveCommand::redo()
|
||||||
|
{
|
||||||
|
m_data = m_buffer->read(m_offset, m_length); // Backup data
|
||||||
|
m_buffer->remove(m_offset, m_length);
|
||||||
|
}
|
11
UEFITool/qhexview5/model/commands/removecommand.h
Normal file
11
UEFITool/qhexview5/model/commands/removecommand.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hexcommand.h"
|
||||||
|
|
||||||
|
class RemoveCommand: public HexCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RemoveCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, int length, QUndoCommand* parent = nullptr);
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
};
|
20
UEFITool/qhexview5/model/commands/replacecommand.cpp
Normal file
20
UEFITool/qhexview5/model/commands/replacecommand.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "replacecommand.h"
|
||||||
|
#include "../qhexdocument.h"
|
||||||
|
|
||||||
|
ReplaceCommand::ReplaceCommand(QHexBuffer *buffer, QHexDocument* document, qint64 offset, const QByteArray &data, QUndoCommand *parent): HexCommand(buffer, document, parent)
|
||||||
|
{
|
||||||
|
m_offset = offset;
|
||||||
|
m_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplaceCommand::undo()
|
||||||
|
{
|
||||||
|
m_buffer->replace(m_offset, m_olddata);
|
||||||
|
Q_EMIT m_hexdocument->dataChanged(m_olddata, m_offset, QHexDocument::ChangeReason::Replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplaceCommand::redo()
|
||||||
|
{
|
||||||
|
m_olddata = m_buffer->read(m_offset, m_data.length());
|
||||||
|
m_buffer->replace(m_offset, m_data);
|
||||||
|
}
|
14
UEFITool/qhexview5/model/commands/replacecommand.h
Normal file
14
UEFITool/qhexview5/model/commands/replacecommand.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hexcommand.h"
|
||||||
|
|
||||||
|
class ReplaceCommand: public HexCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReplaceCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, const QByteArray& data, QUndoCommand* parent = nullptr);
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray m_olddata;
|
||||||
|
};
|
129
UEFITool/qhexview5/model/qhexcursor.cpp
Normal file
129
UEFITool/qhexview5/model/qhexcursor.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include "../qhexview.h"
|
||||||
|
#include "qhexcursor.h"
|
||||||
|
#include "qhexdocument.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://stackoverflow.com/questions/10803043/inverse-column-row-major-order-transformation
|
||||||
|
*
|
||||||
|
* If the index is calculated as:
|
||||||
|
* offset = row + column*NUMROWS
|
||||||
|
* then the inverse would be:
|
||||||
|
* row = offset % NUMROWS
|
||||||
|
* column = offset / NUMROWS
|
||||||
|
* where % is modulus, and / is integer division.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QHexCursor::QHexCursor(const QHexOptions* options, QHexView* parent) : QObject(parent), m_options(options) { }
|
||||||
|
QHexView* QHexCursor::hexView() const { return qobject_cast<QHexView*>(this->parent()); }
|
||||||
|
QHexCursor::Mode QHexCursor::mode() const { return m_mode; }
|
||||||
|
qint64 QHexCursor::offset() const { return this->positionToOffset(m_position); }
|
||||||
|
qint64 QHexCursor::address() const { return m_options->baseaddress + this->offset(); }
|
||||||
|
quint64 QHexCursor::lineAddress() const { return m_options->baseaddress + (m_position.line * m_options->linelength); }
|
||||||
|
qint64 QHexCursor::selectionStartOffset() const { return this->positionToOffset(this->selectionStart()); }
|
||||||
|
qint64 QHexCursor::selectionEndOffset() const { return this->positionToOffset(this->selectionEnd()); }
|
||||||
|
qint64 QHexCursor::line() const { return m_position.line; }
|
||||||
|
qint64 QHexCursor::column() const { return m_position.column; }
|
||||||
|
|
||||||
|
QHexPosition QHexCursor::selectionStart() const
|
||||||
|
{
|
||||||
|
if(m_position.line < m_selection.line)
|
||||||
|
return m_position;
|
||||||
|
|
||||||
|
if(m_position.line == m_selection.line)
|
||||||
|
{
|
||||||
|
if(m_position.column < m_selection.column)
|
||||||
|
return m_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHexPosition QHexCursor::selectionEnd() const
|
||||||
|
{
|
||||||
|
if(m_position.line > m_selection.line)
|
||||||
|
return m_position;
|
||||||
|
|
||||||
|
if(m_position.line == m_selection.line)
|
||||||
|
{
|
||||||
|
if(m_position.column > m_selection.column)
|
||||||
|
return m_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 QHexCursor::selectionLength() const
|
||||||
|
{
|
||||||
|
auto selstart = this->selectionStartOffset(), selend = this->selectionEndOffset();
|
||||||
|
return selstart == selend ? 0 : selend - selstart + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHexPosition QHexCursor::position() const { return m_position; }
|
||||||
|
QByteArray QHexCursor::selectedBytes() const { return this->hexView()->selectedBytes(); }
|
||||||
|
bool QHexCursor::hasSelection() const { return m_position != m_selection; }
|
||||||
|
|
||||||
|
bool QHexCursor::isSelected(qint64 line, qint64 column) const
|
||||||
|
{
|
||||||
|
if(!this->hasSelection()) return false;
|
||||||
|
|
||||||
|
auto selstart = this->selectionStart(), selend = this->selectionEnd();
|
||||||
|
if(line > selstart.line && line < selend.line) return true;
|
||||||
|
if(line == selstart.line && line == selend.line) return column >= selstart.column && column <= selend.column;
|
||||||
|
if(line == selstart.line) return column >= selstart.column;
|
||||||
|
if(line == selend.line) return column <= selend.column;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexCursor::setMode(Mode m)
|
||||||
|
{
|
||||||
|
if(m_mode == m) return;
|
||||||
|
m_mode = m;
|
||||||
|
Q_EMIT modeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexCursor::switchMode()
|
||||||
|
{
|
||||||
|
switch(m_mode)
|
||||||
|
{
|
||||||
|
case Mode::Insert: this->setMode(Mode::Overwrite); break;
|
||||||
|
case Mode::Overwrite: this->setMode(Mode::Insert); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexCursor::move(qint64 offset) { this->move(this->offsetToPosition(offset)); }
|
||||||
|
void QHexCursor::move(qint64 line, qint64 column) { return this->move({line, column}); }
|
||||||
|
|
||||||
|
void QHexCursor::move(QHexPosition pos)
|
||||||
|
{
|
||||||
|
if(pos.line >= 0) m_selection.line = pos.line;
|
||||||
|
if(pos.column >= 0) m_selection.column = pos.column;
|
||||||
|
this->select(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexCursor::select(qint64 offset) { this->select(this->offsetToPosition(offset)); }
|
||||||
|
void QHexCursor::select(qint64 line, qint64 column) { this->select({line, column}); }
|
||||||
|
|
||||||
|
void QHexCursor::select(QHexPosition pos)
|
||||||
|
{
|
||||||
|
if(pos.line >= 0) m_position.line = pos.line;
|
||||||
|
if(pos.column >= 0) m_position.column = pos.column;
|
||||||
|
Q_EMIT positionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexCursor::selectSize(qint64 length)
|
||||||
|
{
|
||||||
|
if(length > 0) length--;
|
||||||
|
else if(length < 0) length++;
|
||||||
|
if(length) this->select(this->offset() + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 QHexCursor::replace(const QVariant& oldvalue, const QVariant& newvalue, qint64 offset, QHexFindMode mode, unsigned int options, QHexFindDirection fd) const { return this->hexView()->replace(oldvalue, newvalue, offset, mode, options, fd); }
|
||||||
|
qint64 QHexCursor::find(const QVariant& value, qint64 offset, QHexFindMode mode, unsigned int options, QHexFindDirection fd) const { return this->hexView()->find(value, offset, mode, options, fd); }
|
||||||
|
void QHexCursor::cut(bool hex) { this->hexView()->cut(hex); }
|
||||||
|
void QHexCursor::copy(bool hex) const { this->hexView()->copy(hex); }
|
||||||
|
void QHexCursor::paste(bool hex) { this->hexView()->paste(hex); }
|
||||||
|
void QHexCursor::selectAll() { this->hexView()->selectAll(); }
|
||||||
|
void QHexCursor::removeSelection() { this->hexView()->removeSelection(); }
|
||||||
|
void QHexCursor::clearSelection() { m_position = m_selection; Q_EMIT positionChanged(); }
|
||||||
|
qint64 QHexCursor::positionToOffset(QHexPosition pos) const { return QHexUtils::positionToOffset(m_options, pos); }
|
||||||
|
QHexPosition QHexCursor::offsetToPosition(qint64 offset) const { return QHexUtils::offsetToPosition(m_options, offset); }
|
69
UEFITool/qhexview5/model/qhexcursor.h
Normal file
69
UEFITool/qhexview5/model/qhexcursor.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "qhexoptions.h"
|
||||||
|
#include "qhexutils.h"
|
||||||
|
|
||||||
|
class QHexView;
|
||||||
|
|
||||||
|
class QHexCursor : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class Mode { Overwrite, Insert };
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit QHexCursor(const QHexOptions* options, QHexView *parent = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
QHexView* hexView() const;
|
||||||
|
Mode mode() const;
|
||||||
|
qint64 line() const;
|
||||||
|
qint64 column() const;
|
||||||
|
qint64 offset() const;
|
||||||
|
qint64 address() const;
|
||||||
|
quint64 lineAddress() const;
|
||||||
|
qint64 selectionStartOffset() const;
|
||||||
|
qint64 selectionEndOffset() const;
|
||||||
|
qint64 selectionLength() const;
|
||||||
|
QHexPosition position() const;
|
||||||
|
QHexPosition selectionStart() const;
|
||||||
|
QHexPosition selectionEnd() const;
|
||||||
|
QByteArray selectedBytes() const;
|
||||||
|
bool hasSelection() const;
|
||||||
|
bool isSelected(qint64 line, qint64 column) const;
|
||||||
|
void setMode(Mode m);
|
||||||
|
void move(qint64 offset);
|
||||||
|
void move(qint64 line, qint64 column);
|
||||||
|
void move(QHexPosition pos);
|
||||||
|
void select(qint64 offset);
|
||||||
|
void select(qint64 line, qint64 column);
|
||||||
|
void select(QHexPosition pos);
|
||||||
|
void selectSize(qint64 length);
|
||||||
|
qint64 replace(const QVariant& oldvalue, const QVariant& newvalue, qint64 offset, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward) const;
|
||||||
|
qint64 find(const QVariant& value, qint64 offset, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward) const;
|
||||||
|
qint64 positionToOffset(QHexPosition pos) const;
|
||||||
|
QHexPosition offsetToPosition(qint64 offset) const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void cut(bool hex = false);
|
||||||
|
void copy(bool hex = false) const;
|
||||||
|
void paste(bool hex = false);
|
||||||
|
void selectAll();
|
||||||
|
void removeSelection();
|
||||||
|
void clearSelection();
|
||||||
|
void switchMode();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void positionChanged();
|
||||||
|
void modeChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QHexOptions* m_options;
|
||||||
|
Mode m_mode{Mode::Overwrite};
|
||||||
|
QHexPosition m_position{}, m_selection{};
|
||||||
|
|
||||||
|
friend class QHexView;
|
||||||
|
};
|
||||||
|
|
68
UEFITool/qhexview5/model/qhexdelegate.cpp
Normal file
68
UEFITool/qhexview5/model/qhexdelegate.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "../qhexview.h"
|
||||||
|
#include "qhexdelegate.h"
|
||||||
|
|
||||||
|
QHexDelegate::QHexDelegate(QObject* parent): QObject{parent} { }
|
||||||
|
|
||||||
|
QString QHexDelegate::addressHeader(const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QHexDelegate::hexHeader(const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QHexDelegate::asciiHeader(const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexDelegate::renderAddress(quint64 address, QTextCharFormat& cf, const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(address);
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
Q_UNUSED(cf);
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexDelegate::renderHeader(QTextBlockFormat& bf, const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(bf);
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexDelegate::renderHeaderPart(const QString& s, QHexArea area, QTextCharFormat& cf, const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(s);
|
||||||
|
Q_UNUSED(area);
|
||||||
|
Q_UNUSED(cf);
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QHexDelegate::render(quint64 offset, quint8 b, QTextCharFormat& outcf, const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(offset);
|
||||||
|
Q_UNUSED(b);
|
||||||
|
Q_UNUSED(outcf);
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QHexDelegate::paintSeparator(QPainter* painter, QLineF line, const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(painter);
|
||||||
|
Q_UNUSED(line);
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexDelegate::paint(QPainter* painter, const QHexView* hexview) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(hexview);
|
||||||
|
hexview->paint(painter);
|
||||||
|
}
|
25
UEFITool/qhexview5/model/qhexdelegate.h
Normal file
25
UEFITool/qhexview5/model/qhexdelegate.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QTextCharFormat>
|
||||||
|
#include <QObject>
|
||||||
|
#include "qhexutils.h"
|
||||||
|
|
||||||
|
class QHexView;
|
||||||
|
|
||||||
|
class QHexDelegate: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QHexDelegate(QObject* parent = nullptr);
|
||||||
|
virtual ~QHexDelegate() = default;
|
||||||
|
virtual QString addressHeader(const QHexView* hexview) const;
|
||||||
|
virtual QString hexHeader(const QHexView* hexview) const;
|
||||||
|
virtual QString asciiHeader(const QHexView* hexview) const;
|
||||||
|
virtual void renderAddress(quint64 address, QTextCharFormat& cf, const QHexView* hexview) const;
|
||||||
|
virtual void renderHeader(QTextBlockFormat& bf, const QHexView* hexview) const;
|
||||||
|
virtual void renderHeaderPart(const QString& s, QHexArea area, QTextCharFormat& cf, const QHexView* hexview) const;
|
||||||
|
virtual bool render(quint64 offset, quint8 b, QTextCharFormat& outcf, const QHexView* hexview) const;
|
||||||
|
virtual bool paintSeparator(QPainter* painter, QLineF line, const QHexView* hexview) const;
|
||||||
|
virtual void paint(QPainter* painter, const QHexView* hexview) const;
|
||||||
|
};
|
99
UEFITool/qhexview5/model/qhexdocument.cpp
Normal file
99
UEFITool/qhexview5/model/qhexdocument.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include "qhexdocument.h"
|
||||||
|
#include "buffer/qmemorybuffer.h"
|
||||||
|
#include "commands/insertcommand.h"
|
||||||
|
#include "commands/replacecommand.h"
|
||||||
|
#include "commands/removecommand.h"
|
||||||
|
#include "qhexutils.h"
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QFile>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
QHexDocument::QHexDocument(QHexBuffer *buffer, QObject* parent): QObject(parent)
|
||||||
|
{
|
||||||
|
m_buffer = buffer;
|
||||||
|
m_buffer->setParent(this); // Take Ownership
|
||||||
|
|
||||||
|
connect(&m_undostack, &QUndoStack::canUndoChanged, this, &QHexDocument::canUndoChanged);
|
||||||
|
connect(&m_undostack, &QUndoStack::canRedoChanged, this, &QHexDocument::canRedoChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 QHexDocument::indexOf(const QByteArray& ba, qint64 from) { return m_buffer->indexOf(ba, from); }
|
||||||
|
qint64 QHexDocument::lastIndexOf(const QByteArray& ba, qint64 from) { return m_buffer->lastIndexOf(ba, from); }
|
||||||
|
bool QHexDocument::isEmpty() const { return m_buffer->isEmpty(); }
|
||||||
|
bool QHexDocument::canUndo() const { return m_undostack.canUndo(); }
|
||||||
|
bool QHexDocument::canRedo() const { return m_undostack.canRedo(); }
|
||||||
|
|
||||||
|
void QHexDocument::setData(const QByteArray& ba)
|
||||||
|
{
|
||||||
|
QHexBuffer* mb = new QMemoryBuffer();
|
||||||
|
mb->read(ba);
|
||||||
|
this->setData(mb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexDocument::setData(QHexBuffer* buffer)
|
||||||
|
{
|
||||||
|
if(!buffer) return;
|
||||||
|
|
||||||
|
m_undostack.clear();
|
||||||
|
buffer->setParent(this);
|
||||||
|
|
||||||
|
auto* oldbuffer = m_buffer;
|
||||||
|
m_buffer = buffer;
|
||||||
|
if(oldbuffer) oldbuffer->deleteLater();
|
||||||
|
|
||||||
|
Q_EMIT canUndoChanged(false);
|
||||||
|
Q_EMIT canRedoChanged(false);
|
||||||
|
Q_EMIT changed();
|
||||||
|
Q_EMIT reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 QHexDocument::length() const { return m_buffer ? m_buffer->length() : 0; }
|
||||||
|
uchar QHexDocument::at(int offset) const { return m_buffer->at(offset); }
|
||||||
|
|
||||||
|
QHexDocument* QHexDocument::fromFile(QString filename, QObject* parent)
|
||||||
|
{
|
||||||
|
QFile f(filename);
|
||||||
|
f.open(QFile::ReadOnly);
|
||||||
|
return QHexDocument::fromMemory<QMemoryBuffer>(f.readAll(), parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexDocument::undo() { m_undostack.undo(); Q_EMIT changed(); }
|
||||||
|
void QHexDocument::redo() { m_undostack.redo(); Q_EMIT changed(); }
|
||||||
|
void QHexDocument::insert(qint64 offset, uchar b) { this->insert(offset, QByteArray(1, b)); }
|
||||||
|
void QHexDocument::replace(qint64 offset, uchar b) { this->replace(offset, QByteArray(1, b)); }
|
||||||
|
|
||||||
|
void QHexDocument::insert(qint64 offset, const QByteArray &data)
|
||||||
|
{
|
||||||
|
m_undostack.push(new InsertCommand(m_buffer, this, offset, data));
|
||||||
|
|
||||||
|
Q_EMIT changed();
|
||||||
|
Q_EMIT dataChanged(data, offset, ChangeReason::Insert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexDocument::replace(qint64 offset, const QByteArray &data)
|
||||||
|
{
|
||||||
|
m_undostack.push(new ReplaceCommand(m_buffer, this, offset, data));
|
||||||
|
Q_EMIT changed();
|
||||||
|
Q_EMIT dataChanged(data, offset, ChangeReason::Replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexDocument::remove(qint64 offset, int len)
|
||||||
|
{
|
||||||
|
QByteArray data = m_buffer->read(offset, len);
|
||||||
|
|
||||||
|
m_undostack.push(new RemoveCommand(m_buffer, this, offset, len));
|
||||||
|
Q_EMIT changed();
|
||||||
|
Q_EMIT dataChanged(data, offset, ChangeReason::Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray QHexDocument::read(qint64 offset, int len) const { return m_buffer->read(offset, len); }
|
||||||
|
|
||||||
|
bool QHexDocument::saveTo(QIODevice *device)
|
||||||
|
{
|
||||||
|
if(!device->isWritable()) return false;
|
||||||
|
m_buffer->write(device);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHexDocument* QHexDocument::fromBuffer(QHexBuffer* buffer, QObject* parent) { return new QHexDocument(buffer, parent); }
|
||||||
|
QHexDocument* QHexDocument::create(QObject* parent) { return QHexDocument::fromMemory<QMemoryBuffer>({}, parent); }
|
89
UEFITool/qhexview5/model/qhexdocument.h
Normal file
89
UEFITool/qhexview5/model/qhexdocument.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QUndoStack>
|
||||||
|
#include "buffer/qhexbuffer.h"
|
||||||
|
#include "qhexmetadata.h"
|
||||||
|
#include "qhexoptions.h"
|
||||||
|
|
||||||
|
class QHexCursor;
|
||||||
|
|
||||||
|
class QHexDocument: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class ChangeReason { Insert, Remove, Replace };
|
||||||
|
enum class FindDirection { Forward, Backward };
|
||||||
|
Q_ENUM(ChangeReason);
|
||||||
|
Q_ENUM(FindDirection);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit QHexDocument(QHexBuffer* buffer, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isEmpty() const;
|
||||||
|
bool canUndo() const;
|
||||||
|
bool canRedo() const;
|
||||||
|
void setData(const QByteArray& ba);
|
||||||
|
void setData(QHexBuffer* buffer);
|
||||||
|
qint64 length() const;
|
||||||
|
qint64 indexOf(const QByteArray& ba, qint64 from = 0);
|
||||||
|
qint64 lastIndexOf(const QByteArray& ba, qint64 from = 0);
|
||||||
|
QByteArray read(qint64 offset, int len = 0) const;
|
||||||
|
uchar at(int offset) const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
void insert(qint64 offset, uchar b);
|
||||||
|
void replace(qint64 offset, uchar b);
|
||||||
|
void insert(qint64 offset, const QByteArray& data);
|
||||||
|
void replace(qint64 offset, const QByteArray& data);
|
||||||
|
void remove(qint64 offset, int len);
|
||||||
|
bool saveTo(QIODevice* device);
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename T, bool Owned = true> static QHexDocument* fromDevice(QIODevice* iodevice, QObject* parent = nullptr);
|
||||||
|
template<typename T> static QHexDocument* fromMemory(char *data, int size, QObject* parent = nullptr);
|
||||||
|
template<typename T> static QHexDocument* fromMemory(const QByteArray& ba, QObject* parent = nullptr);
|
||||||
|
static QHexDocument* fromBuffer(QHexBuffer* buffer, QObject* parent = nullptr);
|
||||||
|
static QHexDocument* fromFile(QString filename, QObject* parent = nullptr);
|
||||||
|
static QHexDocument* create(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void canUndoChanged(bool canundo);
|
||||||
|
void canRedoChanged(bool canredo);
|
||||||
|
void dataChanged(const QByteArray& data, quint64 offset, QHexDocument::ChangeReason reason);
|
||||||
|
void changed();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHexBuffer* m_buffer;
|
||||||
|
QUndoStack m_undostack;
|
||||||
|
|
||||||
|
friend class QHexView;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, bool Owned>
|
||||||
|
QHexDocument* QHexDocument::fromDevice(QIODevice* iodevice, QObject *parent)
|
||||||
|
{
|
||||||
|
QHexBuffer* hexbuffer = new T(parent);
|
||||||
|
if(Owned) iodevice->setParent(hexbuffer);
|
||||||
|
return hexbuffer->read(iodevice) ? new QHexDocument(hexbuffer, parent) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
QHexDocument* QHexDocument::fromMemory(char *data, int size, QObject *parent)
|
||||||
|
{
|
||||||
|
QHexBuffer* hexbuffer = new T();
|
||||||
|
hexbuffer->read(data, size);
|
||||||
|
return new QHexDocument(hexbuffer, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
QHexDocument* QHexDocument::fromMemory(const QByteArray& ba, QObject *parent)
|
||||||
|
{
|
||||||
|
QHexBuffer* hexbuffer = new T();
|
||||||
|
hexbuffer->read(ba);
|
||||||
|
return new QHexDocument(hexbuffer, parent);
|
||||||
|
}
|
149
UEFITool/qhexview5/model/qhexmetadata.cpp
Normal file
149
UEFITool/qhexview5/model/qhexmetadata.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include "qhexmetadata.h"
|
||||||
|
#include "qhexcursor.h"
|
||||||
|
|
||||||
|
QHexMetadata::QHexMetadata(const QHexOptions* options, QObject *parent) : QObject(parent), m_options(options) { }
|
||||||
|
|
||||||
|
const QHexMetadataLine* QHexMetadata::find(qint64 line) const
|
||||||
|
{
|
||||||
|
auto it = m_metadata.find(line);
|
||||||
|
return it != m_metadata.end() ? std::addressof(it.value()) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QHexMetadata::getComment(qint64 line, qint64 column) const
|
||||||
|
{
|
||||||
|
auto* metadataline = this->find(line);
|
||||||
|
if(!metadataline) return QString();
|
||||||
|
|
||||||
|
auto offset = QHexUtils::positionToOffset(m_options, {line, column});
|
||||||
|
QStringList comments;
|
||||||
|
|
||||||
|
for(auto& mi : *metadataline)
|
||||||
|
{
|
||||||
|
if((offset < mi.begin || offset > mi.end) || mi.comment.isEmpty()) continue;
|
||||||
|
comments.push_back(mi.comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return comments.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexMetadata::removeMetadata(qint64 line)
|
||||||
|
{
|
||||||
|
auto it = m_metadata.find(line);
|
||||||
|
if(it == m_metadata.end()) return;
|
||||||
|
|
||||||
|
m_metadata.erase(it);
|
||||||
|
Q_EMIT changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexMetadata::removeBackground(qint64 line)
|
||||||
|
{
|
||||||
|
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
||||||
|
if(!mi.background.isValid()) return false;
|
||||||
|
|
||||||
|
if(mi.foreground.isValid() || !mi.comment.isEmpty()) {
|
||||||
|
mi.background = QColor();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexMetadata::removeForeground(qint64 line)
|
||||||
|
{
|
||||||
|
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
||||||
|
if(!mi.foreground.isValid()) return false;
|
||||||
|
|
||||||
|
if(mi.background.isValid() || !mi.comment.isEmpty()) {
|
||||||
|
mi.foreground = QColor();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexMetadata::removeComments(qint64 line)
|
||||||
|
{
|
||||||
|
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
||||||
|
if(mi.comment.isEmpty()) return false;
|
||||||
|
|
||||||
|
if(mi.foreground.isValid() || mi.background.isValid()) {
|
||||||
|
mi.comment.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexMetadata::unhighlight(qint64 line)
|
||||||
|
{
|
||||||
|
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
||||||
|
if(!mi.foreground.isValid() && !mi.background.isValid()) return false;
|
||||||
|
|
||||||
|
if(!mi.comment.isEmpty()) {
|
||||||
|
mi.foreground = QColor();
|
||||||
|
mi.background = QColor();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexMetadata::clear() { m_metadata.clear(); Q_EMIT changed(); }
|
||||||
|
void QHexMetadata::copy(const QHexMetadata* metadata) { m_metadata = metadata->m_metadata; }
|
||||||
|
|
||||||
|
void QHexMetadata::clearMetadata(qint64 line, ClearMetadataCallback&& cb)
|
||||||
|
{
|
||||||
|
auto iit = m_metadata.find(line);
|
||||||
|
if(iit == m_metadata.end()) return;
|
||||||
|
|
||||||
|
auto oldsize = iit->size();
|
||||||
|
|
||||||
|
for(auto it = iit->begin(); it != iit->end(); )
|
||||||
|
{
|
||||||
|
if(cb(*it)) it = iit->erase(it);
|
||||||
|
else it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iit->empty())
|
||||||
|
{
|
||||||
|
this->removeMetadata(line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oldsize != iit->size()) Q_EMIT changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexMetadata::setMetadata(const QHexMetadataItem& mi)
|
||||||
|
{
|
||||||
|
if(!m_options->linelength) return;
|
||||||
|
|
||||||
|
const qint64 firstline = mi.begin / m_options->linelength;
|
||||||
|
const qint64 lastline = mi.end / m_options->linelength;
|
||||||
|
bool notify = false;
|
||||||
|
|
||||||
|
for(auto line = firstline; line <= lastline; line++)
|
||||||
|
{
|
||||||
|
auto start = line == firstline ? mi.begin % m_options->linelength : 0;
|
||||||
|
auto length = line == lastline ? (mi.end % m_options->linelength) - start : m_options->linelength;
|
||||||
|
if(length <= 0) continue;
|
||||||
|
|
||||||
|
notify = true;
|
||||||
|
m_metadata[line].push_back(mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(notify) Q_EMIT changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHexMetadata::invalidate()
|
||||||
|
{
|
||||||
|
auto oldmetadata = m_metadata;
|
||||||
|
m_metadata.clear();
|
||||||
|
|
||||||
|
for(const QHexMetadataLine& line : oldmetadata)
|
||||||
|
for(const QHexMetadataItem& mi : line)
|
||||||
|
this->setMetadata(mi);
|
||||||
|
}
|
64
UEFITool/qhexview5/model/qhexmetadata.h
Normal file
64
UEFITool/qhexview5/model/qhexmetadata.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QList>
|
||||||
|
#include <QColor>
|
||||||
|
#include "qhexoptions.h"
|
||||||
|
|
||||||
|
struct QHexMetadataItem
|
||||||
|
{
|
||||||
|
qint64 begin, end;
|
||||||
|
QColor foreground, background;
|
||||||
|
QString comment;
|
||||||
|
};
|
||||||
|
|
||||||
|
using QHexMetadataLine = QList<QHexMetadataItem>;
|
||||||
|
|
||||||
|
class QHexMetadata : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using ClearMetadataCallback = std::function<bool(QHexMetadataItem&)>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit QHexMetadata(const QHexOptions* options, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const QHexMetadataLine* find(qint64 line) const;
|
||||||
|
QString getComment(qint64 line, qint64 column) const;
|
||||||
|
void removeMetadata(qint64 line);
|
||||||
|
void removeBackground(qint64 line);
|
||||||
|
void removeForeground(qint64 line);
|
||||||
|
void removeComments(qint64 line);
|
||||||
|
void unhighlight(qint64 line);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline void setMetadata(qint64 begin, qint64 end, const QColor &fgcolor, const QColor &bgcolor, const QString &comment) { this->setMetadata({begin, end, fgcolor, bgcolor, comment}); }
|
||||||
|
inline void setForeground(qint64 begin, qint64 end, const QColor &fgcolor) { this->setMetadata(begin, end, fgcolor, QColor(), QString()); }
|
||||||
|
inline void setBackground(qint64 begin, qint64 end, const QColor &bgcolor) { this->setMetadata(begin, end, QColor(), bgcolor, QString()); }
|
||||||
|
inline void setComment(qint64 begin, qint64 end, const QString& comment) { this->setMetadata(begin, end, QColor(), QColor(), comment); };
|
||||||
|
inline void setMetadataSize(qint64 begin, qint64 length, const QColor &fgcolor, const QColor &bgcolor, const QString &comment) { this->setMetadata({begin, begin + length, fgcolor, bgcolor, comment}); }
|
||||||
|
inline void setForegroundSize(qint64 begin, qint64 length, const QColor &fgcolor) { this->setForeground(begin, begin + length, fgcolor); }
|
||||||
|
inline void setBackgroundSize(qint64 begin, qint64 length, const QColor &bgcolor) { this->setBackground(begin, begin + length, bgcolor); }
|
||||||
|
inline void setCommentSize(qint64 begin, qint64 length, const QString& comment) { this->setComment(begin, begin + length, comment); };
|
||||||
|
|
||||||
|
private:
|
||||||
|
void copy(const QHexMetadata* metadata);
|
||||||
|
void clearMetadata(qint64 line, ClearMetadataCallback&& cb);
|
||||||
|
void setMetadata(const QHexMetadataItem& mi);
|
||||||
|
void invalidate();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void changed();
|
||||||
|
void cleared();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<qint64, QHexMetadataLine> m_metadata;
|
||||||
|
const QHexOptions* m_options;
|
||||||
|
|
||||||
|
friend class QHexView;
|
||||||
|
};
|
55
UEFITool/qhexview5/model/qhexoptions.h
Normal file
55
UEFITool/qhexview5/model/qhexoptions.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QChar>
|
||||||
|
|
||||||
|
namespace QHexFlags {
|
||||||
|
enum: unsigned int {
|
||||||
|
None = (1 << 0),
|
||||||
|
HSeparator = (1 << 1),
|
||||||
|
VSeparator = (1 << 2),
|
||||||
|
StyledHeader = (1 << 3),
|
||||||
|
StyledAddress = (1 << 4),
|
||||||
|
NoHeader = (1 << 5),
|
||||||
|
HighlightAddress = (1 << 6),
|
||||||
|
HighlightColumn = (1 << 7),
|
||||||
|
|
||||||
|
Separators = HSeparator | VSeparator,
|
||||||
|
Styled = StyledHeader | StyledAddress,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct QHexColor
|
||||||
|
{
|
||||||
|
QColor foreground;
|
||||||
|
QColor background;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QHexOptions
|
||||||
|
{
|
||||||
|
// Appearance
|
||||||
|
QChar unprintablechar{'.'};
|
||||||
|
QString addresslabel{""};
|
||||||
|
QString hexlabel;
|
||||||
|
QString asciilabel;
|
||||||
|
quint64 baseaddress{0};
|
||||||
|
unsigned int flags{QHexFlags::None};
|
||||||
|
unsigned int linelength{0x10};
|
||||||
|
unsigned int addresswidth{0};
|
||||||
|
unsigned int grouplength{1};
|
||||||
|
unsigned int scrollsteps{1};
|
||||||
|
|
||||||
|
// Colors & Styles
|
||||||
|
QHash<quint8, QHexColor> bytecolors;
|
||||||
|
QColor linealternatebackground;
|
||||||
|
QColor linebackground;
|
||||||
|
QColor headercolor;
|
||||||
|
QColor commentcolor;
|
||||||
|
QColor separatorcolor;
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
bool copybreak{true};
|
||||||
|
|
||||||
|
inline bool hasFlag(unsigned int flag) const { return flags & flag; }
|
||||||
|
};
|
314
UEFITool/qhexview5/model/qhexutils.cpp
Normal file
314
UEFITool/qhexview5/model/qhexutils.cpp
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
#include "qhexutils.h"
|
||||||
|
#include "qhexoptions.h"
|
||||||
|
#include "../qhexview.h"
|
||||||
|
#include <QGlobalStatic>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QtEndian>
|
||||||
|
#include <QList>
|
||||||
|
#include <QHash>
|
||||||
|
#include <limits>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
#define QHEXVIEW_VARIANT_EQ(x, t) ((x).metaType().id() == QMetaType::Q##t)
|
||||||
|
#else
|
||||||
|
#define QHEXVIEW_VARIANT_EQ(x, t) ((x).type() == QVariant::t)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace QHexUtils {
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC_WITH_ARGS(QList<char>, HEXMAP, ({
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||||
|
}));
|
||||||
|
|
||||||
|
namespace PatternUtils {
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC_WITH_ARGS(QString, WILDCARD_BYTE, ("??"))
|
||||||
|
|
||||||
|
bool check(QString& p, qint64& len)
|
||||||
|
{
|
||||||
|
static QHash<QString, QPair<QString, size_t>> processed; // Cache processed patterns
|
||||||
|
|
||||||
|
auto it = processed.find(p);
|
||||||
|
|
||||||
|
if(it != processed.end())
|
||||||
|
{
|
||||||
|
p = it.value().first;
|
||||||
|
len = it.value().second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString op = p; // Store unprocessed pattern
|
||||||
|
p = p.simplified().replace(" ", "");
|
||||||
|
if(p.isEmpty() || (p.size() % 2)) return false;
|
||||||
|
|
||||||
|
int wccount = 0;
|
||||||
|
|
||||||
|
for(auto i = 0; i < p.size() - 2; i += 2)
|
||||||
|
{
|
||||||
|
const auto& hexb = p.mid(i, 2);
|
||||||
|
|
||||||
|
if(hexb == *WILDCARD_BYTE)
|
||||||
|
{
|
||||||
|
wccount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isxdigit(hexb.at(0).toLatin1()) || !isxdigit(hexb.at(1).toLatin1()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wccount >= p.size()) return false;
|
||||||
|
len = p.size() / 2;
|
||||||
|
processed[op] = qMakePair(p, len); // Cache processed pattern
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match(const QByteArray& data, const QString& pattern)
|
||||||
|
{
|
||||||
|
for(qint64 i = 0, idx = 0; (i <= (pattern.size() - 2)); i += 2, idx++)
|
||||||
|
{
|
||||||
|
if(idx >= data.size()) return false;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
QStringView hexb = QStringView{pattern}.mid(i, 2);
|
||||||
|
#else
|
||||||
|
const QStringRef& hexb = pattern.midRef(i, 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(hexb == *WILDCARD_BYTE) continue;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
auto b = static_cast<char>(hexb.toUInt(&ok, 16));
|
||||||
|
if(!ok || (b != data.at(idx))) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
unsigned int countBits(uint val)
|
||||||
|
{
|
||||||
|
if(val <= std::numeric_limits<quint8>::max()) return QHexFindOptions::Int8;
|
||||||
|
if(val <= std::numeric_limits<quint16>::max()) return QHexFindOptions::Int16;
|
||||||
|
if(val <= std::numeric_limits<quint32>::max()) return QHexFindOptions::Int32;
|
||||||
|
|
||||||
|
return QHexFindOptions::Int64;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Function>
|
||||||
|
qint64 findIter(qint64 startoffset, QHexFindDirection fd, const QHexView* hexview, Function&& f)
|
||||||
|
{
|
||||||
|
QHexDocument* hexdocument = hexview->hexDocument();
|
||||||
|
qint64 offset = -1;
|
||||||
|
|
||||||
|
QHexFindDirection cfd = fd;
|
||||||
|
if(cfd == QHexFindDirection::All) cfd = QHexFindDirection::Forward;
|
||||||
|
|
||||||
|
qint64 i = startoffset;
|
||||||
|
|
||||||
|
while(offset == -1 && (cfd == QHexFindDirection::Backward ? (i >= 0) : (i < hexdocument->length())))
|
||||||
|
{
|
||||||
|
if(!f(i, offset)) break;
|
||||||
|
|
||||||
|
if(cfd == QHexFindDirection::Backward) i--;
|
||||||
|
else i++;
|
||||||
|
|
||||||
|
if(fd == QHexFindDirection::All && i >= hexdocument->length()) i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 findDefault(const QByteArray& value, qint64 startoffset, const QHexView* hexview, unsigned int options, QHexFindDirection fd)
|
||||||
|
{
|
||||||
|
QHexDocument* hexdocument = hexview->hexDocument();
|
||||||
|
if(value.size() > hexdocument->length()) return -1;
|
||||||
|
|
||||||
|
return findIter(startoffset, fd, hexview, [options, value, hexdocument](qint64 idx, qint64& offset) -> bool {
|
||||||
|
for(auto i = 0; i < value.size(); i++) {
|
||||||
|
qint64 curroffset = idx + i;
|
||||||
|
|
||||||
|
if(curroffset >= hexdocument->length()) {
|
||||||
|
offset = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar ch1 = hexdocument->at(curroffset);
|
||||||
|
uchar ch2 = value.at(i);
|
||||||
|
|
||||||
|
if(!(options & QHexFindOptions::CaseSensitive)) {
|
||||||
|
ch1 = std::tolower(ch1);
|
||||||
|
ch2 = std::tolower(ch2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ch1 != ch2) break;
|
||||||
|
if(i == value.size() - 1) offset = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 findWildcard(QString pattern, qint64 startoffset, const QHexView* hexview, QHexFindDirection fd, qint64& patternlen)
|
||||||
|
{
|
||||||
|
QHexDocument* hexdocument = hexview->hexDocument();
|
||||||
|
if(!PatternUtils::check(pattern, patternlen) || (patternlen >= hexdocument->length())) return -1;
|
||||||
|
|
||||||
|
return findIter(startoffset, fd, hexview, [hexdocument, pattern, patternlen](qint64 idx, qint64& offset) -> bool {
|
||||||
|
if(PatternUtils::match(hexdocument->read(idx, patternlen), pattern)) offset = idx;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray variantToByteArray(QVariant value, QHexFindMode mode, unsigned int options)
|
||||||
|
{
|
||||||
|
QByteArray v;
|
||||||
|
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
case QHexFindMode::Text:
|
||||||
|
if(QHEXVIEW_VARIANT_EQ(value, String)) v = value.toString().toUtf8();
|
||||||
|
else if(QHEXVIEW_VARIANT_EQ(value, ByteArray)) v = value.toByteArray();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QHexFindMode::Hex: {
|
||||||
|
if(QHEXVIEW_VARIANT_EQ(value, String)) {
|
||||||
|
qint64 len = 0;
|
||||||
|
auto s = value.toString();
|
||||||
|
if(!PatternUtils::check(s, len)) return { };
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
for(auto i = 0; ok && i < s.size(); i += 2) v.push_back(static_cast<char>(QStringView{s}.mid(i, 2).toUInt(&ok, 16)));
|
||||||
|
#else
|
||||||
|
for(auto i = 0; ok && i < s.size(); i += 2) v.push_back(static_cast<char>(s.midRef(i, 2).toUInt(&ok, 16)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!ok) return { };
|
||||||
|
}
|
||||||
|
else if(QHEXVIEW_VARIANT_EQ(value, ByteArray)) v = value.toByteArray();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QHexFindMode::Int: {
|
||||||
|
bool ok = false;
|
||||||
|
uint val = value.toUInt(&ok);
|
||||||
|
if(!ok) return QByteArray{ };
|
||||||
|
|
||||||
|
QDataStream ds(&v, QIODevice::WriteOnly);
|
||||||
|
|
||||||
|
if(options & QHexFindOptions::BigEndian) {
|
||||||
|
if(options & QHexFindOptions::Int8) ds << qToBigEndian<quint8>(val);
|
||||||
|
else if(options & QHexFindOptions::Int16) ds << qToBigEndian<quint16>(val);
|
||||||
|
else if(options & QHexFindOptions::Int32) ds << qToBigEndian<quint32>(val);
|
||||||
|
else if(options & QHexFindOptions::Int64) ds << qToBigEndian<quint64>(val);
|
||||||
|
else return variantToByteArray(value, mode, options | countBits(val));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(options & QHexFindOptions::Int8) ds << static_cast<quint8>(val);
|
||||||
|
else if(options & QHexFindOptions::Int16) ds << static_cast<quint16>(val);
|
||||||
|
else if(options & QHexFindOptions::Int32) ds << static_cast<quint32>(val);
|
||||||
|
else if(options & QHexFindOptions::Int64) ds << static_cast<quint64>(val);
|
||||||
|
else return variantToByteArray(value, mode, options | countBits(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QHexFindMode::Float: {
|
||||||
|
bool ok = false;
|
||||||
|
QDataStream ds(&v, QIODevice::WriteOnly);
|
||||||
|
if(options & QHexFindOptions::Float) ds << value.toFloat(&ok);
|
||||||
|
else if(options & QHexFindOptions::Double) ds << value.toDouble(&ok);
|
||||||
|
if(!ok) return { };
|
||||||
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
QByteArray toHex(const QByteArray& ba, char sep)
|
||||||
|
{
|
||||||
|
QByteArray hex(sep ? (ba.size() * 3 - 1) : (ba.size() * 2), Qt::Uninitialized);
|
||||||
|
|
||||||
|
for(auto i = 0, o = 0; i < ba.size(); i++)
|
||||||
|
{
|
||||||
|
if(sep && i) hex[o++] = static_cast<uchar>(sep);
|
||||||
|
hex[o++] = HEXMAP->at((ba.at(i) & 0xf0) >> 4);
|
||||||
|
hex[o++] = HEXMAP->at(ba.at(i) & 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray toHex(const QByteArray& ba) { return QHexUtils::toHex(ba, '\0'); }
|
||||||
|
qint64 positionToOffset(const QHexOptions* options, QHexPosition pos) { return options->linelength * pos.line + pos.column; }
|
||||||
|
QHexPosition offsetToPosition(const QHexOptions* options, qint64 offset) { return { offset / options->linelength, offset % options->linelength }; }
|
||||||
|
|
||||||
|
QPair<qint64, qint64> find(const QHexView* hexview, QVariant value, qint64 startoffset, QHexFindMode mode, unsigned int options, QHexFindDirection fd)
|
||||||
|
{
|
||||||
|
qint64 offset = -1, size = 0;
|
||||||
|
if(startoffset == -1) startoffset = static_cast<qint64>(hexview->offset());
|
||||||
|
|
||||||
|
if(mode == QHexFindMode::Hex && QHEXVIEW_VARIANT_EQ(value, String))
|
||||||
|
{
|
||||||
|
offset = QHexUtils::findWildcard(value.toString(), startoffset, hexview, fd, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto ba = variantToByteArray(value, mode, options);
|
||||||
|
|
||||||
|
if(!ba.isEmpty())
|
||||||
|
{
|
||||||
|
offset = QHexUtils::findDefault(ba, startoffset, hexview, options, fd);
|
||||||
|
size = ba.size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
offset = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {offset, offset > -1 ? size : 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkPattern(QString pattern)
|
||||||
|
{
|
||||||
|
qint64 len = 0;
|
||||||
|
return PatternUtils::check(pattern, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<qint64, qint64> replace(const QHexView* hexview, QVariant oldvalue, QVariant newvalue, qint64 startoffset, QHexFindMode mode, unsigned int options, QHexFindDirection fd)
|
||||||
|
{
|
||||||
|
auto res = QHexUtils::find(hexview, oldvalue, startoffset, mode, options, fd);
|
||||||
|
|
||||||
|
if(res.first != -1 && res.second > 0)
|
||||||
|
{
|
||||||
|
QHexDocument* hexdocument = hexview->hexDocument();
|
||||||
|
auto ba = variantToByteArray(newvalue, mode, options);
|
||||||
|
|
||||||
|
if(!ba.isEmpty())
|
||||||
|
{
|
||||||
|
hexdocument->remove(res.first, res.second);
|
||||||
|
hexdocument->insert(res.first, ba);
|
||||||
|
res.second = ba.size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.first = -1;
|
||||||
|
res.second = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
UEFITool/qhexview5/model/qhexutils.h
Normal file
48
UEFITool/qhexview5/model/qhexutils.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
#include <QPair>
|
||||||
|
|
||||||
|
struct QHexOptions;
|
||||||
|
class QHexView;
|
||||||
|
|
||||||
|
namespace QHexFindOptions {
|
||||||
|
enum: unsigned int {
|
||||||
|
None = (1 << 0),
|
||||||
|
CaseSensitive = (1 << 1),
|
||||||
|
Int8 = (1 << 2),
|
||||||
|
Int16 = (1 << 3),
|
||||||
|
Int32 = (1 << 4),
|
||||||
|
Int64 = (1 << 5),
|
||||||
|
Float = (1 << 6),
|
||||||
|
Double = (1 << 7),
|
||||||
|
|
||||||
|
BigEndian = (1 << 11),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class QHexFindMode { Text, Hex, Int, Float };
|
||||||
|
enum class QHexFindDirection { All, Forward, Backward };
|
||||||
|
enum class QHexArea { Header, Address, Hex, Ascii, Extra };
|
||||||
|
|
||||||
|
struct QHexPosition {
|
||||||
|
qint64 line; qint64 column;
|
||||||
|
static inline QHexPosition invalid() { return {-1, -1}; }
|
||||||
|
inline bool isValid() const { return line >= 0 && column >= 0; }
|
||||||
|
inline bool operator==(const QHexPosition& rhs) const { return (line == rhs.line) && (column == rhs.column); }
|
||||||
|
inline bool operator!=(const QHexPosition& rhs) const { return (line != rhs.line) || (column != rhs.column); }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace QHexUtils {
|
||||||
|
|
||||||
|
QByteArray toHex(const QByteArray& ba, char sep);
|
||||||
|
QByteArray toHex(const QByteArray& ba);
|
||||||
|
qint64 positionToOffset(const QHexOptions* options, QHexPosition pos);
|
||||||
|
QPair<qint64, qint64> find(const QHexView* hexview, QVariant value, qint64 startoffset = 0, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward);
|
||||||
|
QPair<qint64, qint64> replace(const QHexView* hexview, QVariant oldvalue, QVariant newvalue, qint64 startoffset = 0, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward);
|
||||||
|
QHexPosition offsetToPosition(const QHexOptions* options, qint64 offset);
|
||||||
|
bool checkPattern(QString pattern);
|
||||||
|
|
||||||
|
}
|
1261
UEFITool/qhexview5/qhexview.cpp
Normal file
1261
UEFITool/qhexview5/qhexview.cpp
Normal file
File diff suppressed because it is too large
Load Diff
169
UEFITool/qhexview5/qhexview.h
Normal file
169
UEFITool/qhexview5/qhexview.h
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define QHEXVIEW_VERSION 5.0
|
||||||
|
|
||||||
|
#include <QAbstractScrollArea>
|
||||||
|
#include <QTextCharFormat>
|
||||||
|
#include <QFontMetricsF>
|
||||||
|
#include <QRectF>
|
||||||
|
#include <QList>
|
||||||
|
#include "model/qhexdelegate.h"
|
||||||
|
#include "model/qhexdocument.h"
|
||||||
|
#include "model/qhexcursor.h"
|
||||||
|
|
||||||
|
#if defined(QHEXVIEW_ENABLE_DIALOGS)
|
||||||
|
class HexFindDialog;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class QHexView : public QAbstractScrollArea
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class CopyMode { Visual, HexArraySquare, HexArrayCurly, HexArrayChar };
|
||||||
|
Q_ENUM(CopyMode);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QHexView(QWidget *parent = nullptr);
|
||||||
|
QRectF headerRect() const;
|
||||||
|
QRectF addressRect() const;
|
||||||
|
QRectF hexRect() const;
|
||||||
|
QRectF asciiRect() const;
|
||||||
|
QHexDocument* hexDocument() const;
|
||||||
|
QHexCursor* hexCursor() const;
|
||||||
|
const QHexMetadata* hexMetadata() const;
|
||||||
|
QHexOptions options() const;
|
||||||
|
QColor getReadableColor(QColor c) const;
|
||||||
|
QByteArray selectedBytes() const;
|
||||||
|
QByteArray getLine(qint64 line) const;
|
||||||
|
unsigned int addressWidth() const;
|
||||||
|
unsigned int lineLength() const;
|
||||||
|
bool canUndo() const;
|
||||||
|
bool canRedo() const;
|
||||||
|
quint64 offset() const;
|
||||||
|
quint64 address() const;
|
||||||
|
QHexPosition position() const;
|
||||||
|
QHexPosition selectionStart() const;
|
||||||
|
QHexPosition selectionEnd() const;
|
||||||
|
quint64 selectionStartOffset() const;
|
||||||
|
quint64 selectionEndOffset() const;
|
||||||
|
quint64 baseAddress() const;
|
||||||
|
quint64 lines() const;
|
||||||
|
qint64 replace(const QVariant& oldvalue, const QVariant& newvalue, qint64 offset, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward) const;
|
||||||
|
qint64 find(const QVariant& value, qint64 offset, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward) const;
|
||||||
|
void setOptions(const QHexOptions& options);
|
||||||
|
void setBaseAddress(quint64 baseaddress);
|
||||||
|
void setDelegate(QHexDelegate* rd);
|
||||||
|
void setDocument(QHexDocument* doc);
|
||||||
|
void setData(const QByteArray& ba);
|
||||||
|
void setData(QHexBuffer* buffer);
|
||||||
|
void setCursorMode(QHexCursor::Mode mode);
|
||||||
|
void setByteColor(quint8 b, QHexColor c);
|
||||||
|
void setByteForeground(quint8 b, QColor c);
|
||||||
|
void setByteBackground(quint8 b, QColor c);
|
||||||
|
void setMetadata(qint64 begin, qint64 end, const QColor &fgcolor, const QColor &bgcolor, const QString &comment);
|
||||||
|
void setForeground(qint64 begin, qint64 end, const QColor &fgcolor);
|
||||||
|
void setBackground(qint64 begin, qint64 end, const QColor &bgcolor);
|
||||||
|
void setComment(qint64 begin, qint64 end, const QString& comment);
|
||||||
|
void setMetadataSize(qint64 begin, qint64 length, const QColor &fgcolor, const QColor &bgcolor, const QString &comment);
|
||||||
|
void setForegroundSize(qint64 begin, qint64 length, const QColor &fgcolor);
|
||||||
|
void setBackgroundSize(qint64 begin, qint64 length, const QColor &bgcolor);
|
||||||
|
void setCommentSize(qint64 begin, qint64 length, const QString& comment);
|
||||||
|
void removeMetadata(qint64 line);
|
||||||
|
void removeBackground(qint64 line);
|
||||||
|
void removeForeground(qint64 line);
|
||||||
|
void removeComments(qint64 line);
|
||||||
|
void unhighlight(qint64 line);
|
||||||
|
void clearMetadata();
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
#if defined(QHEXVIEW_ENABLE_DIALOGS)
|
||||||
|
void showFind();
|
||||||
|
void showReplace();
|
||||||
|
#endif
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
void cut(bool hex = false);
|
||||||
|
void copyAs(CopyMode mode = CopyMode::Visual) const;
|
||||||
|
void copy(bool hex = false) const;
|
||||||
|
void paste(bool hex = false);
|
||||||
|
void selectAll();
|
||||||
|
void removeSelection();
|
||||||
|
void switchMode();
|
||||||
|
void setAddressWidth(unsigned int w);
|
||||||
|
void setLineLength(unsigned int l);
|
||||||
|
void setGroupLength(unsigned int l);
|
||||||
|
void setScrollSteps(unsigned int l);
|
||||||
|
void setReadOnly(bool r);
|
||||||
|
void setAutoWidth(bool r);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paint(QPainter* painter) const;
|
||||||
|
void checkOptions();
|
||||||
|
void checkState();
|
||||||
|
void checkAndUpdate(bool calccolumns = false);
|
||||||
|
void calcColumns();
|
||||||
|
void ensureVisible();
|
||||||
|
void drawSeparators(QPainter* p) const;
|
||||||
|
void drawHeader(QTextCursor& c) const;
|
||||||
|
void drawDocument(QTextCursor& c) const;
|
||||||
|
QTextCharFormat drawFormat(QTextCursor& c, quint8 b, const QString& s, QHexArea area, qint64 line, qint64 column, bool applyformat) const;
|
||||||
|
unsigned int calcAddressWidth() const;
|
||||||
|
int visibleLines(bool absolute = false) const;
|
||||||
|
qint64 getLastColumn(qint64 line) const;
|
||||||
|
qint64 lastLine() const;
|
||||||
|
qreal getNCellsWidth(int n) const;
|
||||||
|
qreal hexColumnWidth() const;
|
||||||
|
qreal hexColumnX() const;
|
||||||
|
qreal asciiColumnX() const;
|
||||||
|
qreal endColumnX() const;
|
||||||
|
qreal cellWidth() const;
|
||||||
|
qreal lineHeight() const;
|
||||||
|
QHexPosition positionFromPoint(QPoint pt) const;
|
||||||
|
QPoint absolutePoint(QPoint pt) const;
|
||||||
|
QHexArea areaFromPoint(QPoint pt) const;
|
||||||
|
void moveNext(bool select = false);
|
||||||
|
void movePrevious(bool select = false);
|
||||||
|
bool keyPressMove(QKeyEvent* e);
|
||||||
|
bool keyPressTextInput(QKeyEvent* e);
|
||||||
|
bool keyPressAction(QKeyEvent* e);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool event(QEvent* e) override;
|
||||||
|
void showEvent(QShowEvent* e) override;
|
||||||
|
void paintEvent(QPaintEvent*) override;
|
||||||
|
void resizeEvent(QResizeEvent* e) override;
|
||||||
|
void focusInEvent(QFocusEvent* e) override;
|
||||||
|
void focusOutEvent(QFocusEvent* e) override;
|
||||||
|
void mousePressEvent(QMouseEvent* e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent* e) override;
|
||||||
|
void wheelEvent(QWheelEvent* e) override;
|
||||||
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QString reduced(const QString& s, int maxlen);
|
||||||
|
static bool isColorLight(QColor c);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void dataChanged(const QByteArray& data, quint64 offset, QHexDocument::ChangeReason reason);
|
||||||
|
void positionChanged();
|
||||||
|
void modeChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_readonly{false}, m_writing{false}, m_autowidth{false};
|
||||||
|
QHexArea m_currentarea{QHexArea::Ascii};
|
||||||
|
QList<QRectF> m_hexcolumns;
|
||||||
|
QFontMetricsF m_fontmetrics;
|
||||||
|
QHexOptions m_options;
|
||||||
|
QHexCursor* m_hexcursor{nullptr};
|
||||||
|
QHexDocument* m_hexdocument{nullptr};
|
||||||
|
QHexMetadata* m_hexmetadata{nullptr};
|
||||||
|
QHexDelegate* m_hexdelegate{nullptr};
|
||||||
|
#if defined(QHEXVIEW_ENABLE_DIALOGS)
|
||||||
|
HexFindDialog *m_hexdlgfind{nullptr}, *m_hexdlgreplace{nullptr};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
friend class QHexDelegate;
|
||||||
|
friend class QHexCursor;
|
||||||
|
};
|
||||||
|
|
@ -585,7 +585,7 @@ void UEFITool::about()
|
|||||||
tr("<b>UEFITool %1.</b><br><br>"
|
tr("<b>UEFITool %1.</b><br><br>"
|
||||||
"Copyright (c) 2013-2023, Nikolaj Schlej.<br><br>"
|
"Copyright (c) 2013-2023, Nikolaj Schlej.<br><br>"
|
||||||
"Program icon made by <a href=https://www.behance.net/alzhidkov>Alexander Zhidkov</a>.<br><br>"
|
"Program icon made by <a href=https://www.behance.net/alzhidkov>Alexander Zhidkov</a>.<br><br>"
|
||||||
"GUI uses QHexEdit2 library made by <a href=https://github.com/Simsys>Simsys</a>.<br>"
|
"GUI uses QHexView made by <a href=https://github.com/Dax89>Antonio Davide</a>.<br>"
|
||||||
"Qt-less engine uses Bstrlib made by <a href=https://github.com/websnarf>Paul Hsieh</a>.<br>"
|
"Qt-less engine uses Bstrlib made by <a href=https://github.com/websnarf>Paul Hsieh</a>.<br>"
|
||||||
"Engine uses Tiano compression code made by <a href=https://github.com/tianocore>TianoCore developers</a>.<br>"
|
"Engine uses Tiano compression code made by <a href=https://github.com/tianocore>TianoCore developers</a>.<br>"
|
||||||
"Engine uses LZMA compression code made by <a href=https://www.7-zip.org/sdk.html>Igor Pavlov</a>.<br>"
|
"Engine uses LZMA compression code made by <a href=https://www.7-zip.org/sdk.html>Igor Pavlov</a>.<br>"
|
||||||
|
@ -62,9 +62,20 @@ HEADERS += uefitool.h \
|
|||||||
../common/zlib/zlib.h \
|
../common/zlib/zlib.h \
|
||||||
../common/zlib/crc32.h \
|
../common/zlib/crc32.h \
|
||||||
../version.h \
|
../version.h \
|
||||||
qhexedit2/qhexedit.h \
|
qhexview5/model/buffer/qhexbuffer.h \
|
||||||
qhexedit2/chunks.h \
|
qhexview5/model/buffer/qdevicebuffer.h \
|
||||||
qhexedit2/commands.h
|
qhexview5/model/buffer/qmemorybuffer.h \
|
||||||
|
qhexview5/model/commands/hexcommand.h \
|
||||||
|
qhexview5/model/commands/insertcommand.h \
|
||||||
|
qhexview5/model/commands/removecommand.h \
|
||||||
|
qhexview5/model/commands/replacecommand.h \
|
||||||
|
qhexview5/model/qhexcursor.h \
|
||||||
|
qhexview5/model/qhexdelegate.h \
|
||||||
|
qhexview5/model/qhexdocument.h \
|
||||||
|
qhexview5/model/qhexmetadata.h \
|
||||||
|
qhexview5/model/qhexoptions.h \
|
||||||
|
qhexview5/model/qhexutils.h \
|
||||||
|
qhexview5/qhexview.h
|
||||||
|
|
||||||
SOURCES += uefitool_main.cpp \
|
SOURCES += uefitool_main.cpp \
|
||||||
uefitool.cpp \
|
uefitool.cpp \
|
||||||
@ -127,9 +138,19 @@ SOURCES += uefitool_main.cpp \
|
|||||||
../common/zlib/trees.c \
|
../common/zlib/trees.c \
|
||||||
../common/zlib/uncompr.c \
|
../common/zlib/uncompr.c \
|
||||||
../common/zlib/zutil.c \
|
../common/zlib/zutil.c \
|
||||||
qhexedit2/qhexedit.cpp \
|
qhexview5/model/buffer/qhexbuffer.cpp \
|
||||||
qhexedit2/chunks.cpp \
|
qhexview5/model/buffer/qdevicebuffer.cpp \
|
||||||
qhexedit2/commands.cpp
|
qhexview5/model/buffer/qmemorybuffer.cpp \
|
||||||
|
qhexview5/model/commands/hexcommand.cpp \
|
||||||
|
qhexview5/model/commands/insertcommand.cpp \
|
||||||
|
qhexview5/model/commands/removecommand.cpp \
|
||||||
|
qhexview5/model/commands/replacecommand.cpp \
|
||||||
|
qhexview5/model/qhexcursor.cpp \
|
||||||
|
qhexview5/model/qhexdelegate.cpp \
|
||||||
|
qhexview5/model/qhexdocument.cpp \
|
||||||
|
qhexview5/model/qhexmetadata.cpp \
|
||||||
|
qhexview5/model/qhexutils.cpp \
|
||||||
|
qhexview5/qhexview.cpp
|
||||||
|
|
||||||
FORMS += uefitool.ui \
|
FORMS += uefitool.ui \
|
||||||
searchdialog.ui \
|
searchdialog.ui \
|
||||||
|
Loading…
Reference in New Issue
Block a user