├── README.md ├── LICENSE ├── qhexview.pri ├── dialoghex.h ├── dialoghex.cpp ├── dialoghex.ui ├── qhexviewwidget.h ├── qhexviewwidget.ui ├── qhexview.h ├── qhexviewwidget.cpp └── qhexview.cpp /README.md: -------------------------------------------------------------------------------- 1 | # QHexView 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2025 hors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /qhexview.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD 2 | DEPENDPATH += $$PWD 3 | 4 | HEADERS += \ 5 | $$PWD/dialoghex.h \ 6 | $$PWD/qhexview.h \ 7 | $$PWD/qhexviewwidget.h 8 | 9 | SOURCES += \ 10 | $$PWD/dialoghex.cpp \ 11 | $$PWD/qhexview.cpp \ 12 | $$PWD/qhexviewwidget.cpp 13 | 14 | FORMS += \ 15 | $$PWD/dialoghex.ui \ 16 | $$PWD/qhexviewwidget.ui 17 | 18 | !contains(XCONFIG, xlineedithex) { 19 | XCONFIG += xlineedithex 20 | include($$PWD/../Controls/xlineedithex.pri) 21 | } 22 | 23 | !contains(XCONFIG, dialogdump) { 24 | XCONFIG += dialogdump 25 | include($$PWD/../FormatDialogs/dialogdump.pri) 26 | } 27 | 28 | !contains(XCONFIG, dialogsearch) { 29 | XCONFIG += dialogsearch 30 | include($$PWD/../FormatDialogs/dialogsearch.pri) 31 | } 32 | 33 | !contains(XCONFIG, dialoggotoaddress) { 34 | XCONFIG += dialoggotoaddress 35 | include($$PWD/../FormatDialogs/dialoggotoaddress.pri) 36 | } 37 | 38 | !contains(XCONFIG, dialoghexsignature) { 39 | XCONFIG += dialoghexsignature 40 | include($$PWD/../FormatDialogs/dialoghexsignature.pri) 41 | } 42 | 43 | !contains(XCONFIG, xbinary) { 44 | XCONFIG += xbinary 45 | include($$PWD/../Formats/xbinary.pri) 46 | } 47 | -------------------------------------------------------------------------------- /dialoghex.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef DIALOGHEX_H 22 | #define DIALOGHEX_H 23 | 24 | #include 25 | 26 | #include "qhexview.h" 27 | 28 | namespace Ui { 29 | class DialogHex; 30 | } 31 | 32 | class DialogHex : public QDialog { 33 | Q_OBJECT 34 | 35 | public: 36 | explicit DialogHex(QWidget *pParent, QIODevice *pDevice, QHexView::OPTIONS *pOptions = nullptr); 37 | ~DialogHex(); 38 | 39 | signals: 40 | void editState(bool bState); 41 | 42 | private slots: 43 | void on_pushButtonClose_clicked(); 44 | 45 | private: 46 | Ui::DialogHex *ui; 47 | }; 48 | 49 | #endif // DIALOGHEX_H 50 | -------------------------------------------------------------------------------- /dialoghex.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2017-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "dialoghex.h" 22 | 23 | #include "ui_dialoghex.h" 24 | 25 | DialogHex::DialogHex(QWidget *pParent, QIODevice *pDevice, QHexView::OPTIONS *pOptions) : QDialog(pParent), ui(new Ui::DialogHex) 26 | { 27 | ui->setupUi(this); 28 | 29 | setWindowFlags(Qt::Window); 30 | 31 | connect(ui->widgetHex, SIGNAL(editState(bool)), this, SIGNAL(editState(bool))); 32 | 33 | ui->widgetHex->enableHeader(true); 34 | ui->widgetHex->enableReadOnly(true); 35 | 36 | ui->widgetHex->setData(pDevice, pOptions); 37 | } 38 | 39 | DialogHex::~DialogHex() 40 | { 41 | delete ui; 42 | } 43 | 44 | void DialogHex::on_pushButtonClose_clicked() 45 | { 46 | this->close(); 47 | } 48 | -------------------------------------------------------------------------------- /dialoghex.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DialogHex 4 | 5 | 6 | Qt::ApplicationModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 792 13 | 348 14 | 15 | 16 | 17 | Hex 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 0 28 | 0 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Qt::Horizontal 39 | 40 | 41 | 42 | 40 43 | 20 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Close 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | QHexViewWidget 62 | QWidget 63 |
qhexviewwidget.h
64 | 1 65 |
66 |
67 | 68 | 69 |
70 | -------------------------------------------------------------------------------- /qhexviewwidget.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef QHEXVIEWWIDGET_H 22 | #define QHEXVIEWWIDGET_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "dialogdumpprocess.h" 31 | #include "dialoggotoaddress.h" 32 | #include "dialoghexsignature.h" 33 | #include "dialogsearch.h" 34 | #include "dialogsearchprocess.h" 35 | #include "qhexview.h" 36 | #include "xshortcuts.h" 37 | 38 | namespace Ui { 39 | class QHexViewWidget; 40 | } 41 | 42 | class QHexViewWidget : public QWidget { 43 | Q_OBJECT 44 | 45 | public: 46 | explicit QHexViewWidget(QWidget *pParent = nullptr); 47 | ~QHexViewWidget(); 48 | void setData(QIODevice *pDevice, QHexView::OPTIONS *pOptions = nullptr); 49 | void setBackupFileName(QString sBackupFileName); 50 | void setSaveDirectory(QString sSaveDirectory); 51 | void enableHeader(bool bState); 52 | void enableReadOnly(bool bState); 53 | bool setReadonly(bool bState); 54 | void reload(); 55 | bool isEdited(); 56 | void setEdited(bool bState); 57 | qint64 getBaseAddress(); 58 | void setSelection(qint64 nAddress, qint64 nSize); 59 | void goToAddress(qint64 nAddress); 60 | void goToOffset(qint64 nOffset); 61 | 62 | protected: 63 | bool eventFilter(QObject *pObj, QEvent *pEvent) override; 64 | 65 | signals: 66 | void editState(bool bState); 67 | 68 | private slots: 69 | void on_pushButtonGoTo_clicked(); 70 | void on_checkBoxReadonly_toggled(bool bChecked); 71 | void _getState(); 72 | void _goToAddress(); 73 | void _dumpToFile(); 74 | void _find(); 75 | void _findNext(); 76 | void _selectAll(); 77 | void _copyAsHex(); 78 | void _signature(); 79 | void _customContextMenu(const QPoint &pos); 80 | void _errorMessage(QString sText); 81 | QString getDumpName(); 82 | void registerShortcuts(bool bState); 83 | 84 | private: 85 | Ui::QHexViewWidget *ui; 86 | XBinary::SEARCHDATA g_searchData; 87 | QShortcut *g_scGoToAddress; 88 | QShortcut *g_scDumpToFile; 89 | QShortcut *g_scSelectAll; 90 | QShortcut *g_scCopyAsHex; 91 | QShortcut *g_scFind; 92 | QShortcut *g_scFindNext; 93 | QShortcut *g_scSignature; 94 | 95 | QString g_sSaveDirectory; 96 | }; 97 | 98 | #endif // QHEXVIEWWIDGET_H 99 | -------------------------------------------------------------------------------- /qhexviewwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | QHexViewWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 842 10 | 571 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | 36 | 0 37 | 38 | 39 | 0 40 | 41 | 42 | 0 43 | 44 | 45 | 0 46 | 47 | 48 | 49 | 50 | Go to address 51 | 52 | 53 | 54 | 55 | 56 | 57 | Cursor 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 140 66 | 16777215 67 | 68 | 69 | 70 | false 71 | 72 | 73 | 74 | 75 | 76 | 77 | Selection 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 140 86 | 16777215 87 | 88 | 89 | 90 | false 91 | 92 | 93 | 94 | 95 | 96 | 97 | Size 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 140 106 | 16777215 107 | 108 | 109 | 110 | false 111 | 112 | 113 | false 114 | 115 | 116 | false 117 | 118 | 119 | 120 | 121 | 122 | 123 | Qt::Horizontal 124 | 125 | 126 | 127 | 40 128 | 20 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | Readonly 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 0 148 | 0 149 | 150 | 151 | 152 | true 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | QHexView 161 | QWidget 162 |
qhexview.h
163 | 1 164 |
165 | 166 | XLineEditHEX 167 | QLineEdit 168 |
xlineedithex.h
169 |
170 |
171 | 172 | 173 |
174 | -------------------------------------------------------------------------------- /qhexview.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef QHEXVIEW_H 22 | #define QHEXVIEW_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "xbinary.h" 36 | 37 | class QHexView : public QAbstractScrollArea { 38 | Q_OBJECT 39 | 40 | public: 41 | struct OPTIONS { 42 | qint64 nStartAddress; 43 | qint64 nStartSelectionAddress; 44 | qint64 nSizeOfSelection; 45 | QString sBackupFileName; 46 | XBinary::_MEMORY_MAP memoryMap; 47 | }; 48 | 49 | enum CURSOR_TYPE { 50 | CT_NONE = 0, 51 | CT_HIWORD, 52 | CT_LOWORD, 53 | CT_ANSI 54 | }; 55 | 56 | struct CURSOR_POSITION { 57 | qint64 nOffset; 58 | CURSOR_TYPE type; 59 | }; 60 | 61 | struct STATE { 62 | qint64 nCursorAddress; 63 | qint64 nCursorOffset; 64 | qint64 nSelectionAddress; 65 | qint64 nSelectionOffset; 66 | qint64 nSelectionSize; 67 | }; 68 | 69 | struct POS_INFO { 70 | qint64 nSelectionInitOffset; 71 | qint64 nSelectionStartOffset; 72 | qint64 nSelectionEndOffset; 73 | CURSOR_POSITION cursorPosition; 74 | }; 75 | 76 | QHexView(QWidget *pParent = nullptr); 77 | // ~QHexView(); 78 | QIODevice *getDevice() const; 79 | void setData(QIODevice *pDevice, OPTIONS *pOptions = nullptr); 80 | void setBackupFileName(QString sBackupFileName); 81 | quint32 getBytesProLine() const; 82 | void setBytesProLine(const quint32 nBytesProLine); 83 | // qint64 getBaseAddress() const; 84 | void setFont(const QFont &font); 85 | bool isAddressValid(qint64 nAddress); 86 | bool isRelAddressValid(qint64 nRelAddress); 87 | bool isOffsetValid(qint64 nOffset); 88 | void reload(); 89 | STATE getState(); 90 | bool setReadonly(bool bState); 91 | QByteArray readArray(qint64 nOffset, qint64 nSize); 92 | bool isEdited(); 93 | void setEdited(bool bState); 94 | qint64 getBaseAddress(); 95 | 96 | private: 97 | enum ST { 98 | ST_NOTSELECTED = 0, 99 | ST_ONEBYTE, 100 | ST_BEGIN, 101 | ST_MID, 102 | ST_END 103 | }; 104 | 105 | static char convertANSI(char cByte); 106 | static QString getFontName(); 107 | 108 | public slots: 109 | void goToAddress(qint64 nAddress); 110 | void goToRelAddress(qint64 nRelAddress); 111 | void goToOffset(qint64 nOffset); 112 | void _goToOffset(qint64 nOffset); 113 | void setSelection(qint64 nAddress, qint64 nSize); 114 | void selectAll(); 115 | void setWidgetResizable(bool resizable) 116 | { 117 | Q_UNUSED(resizable) 118 | } // hack TODO Check 119 | void setWidget(QWidget *widget) 120 | { 121 | Q_UNUSED(widget) 122 | } // hack TODO Check 123 | XBinary::_MEMORY_MAP *getMemoryMap(); 124 | 125 | private slots: 126 | void verticalScroll(); 127 | void horisontalScroll(); 128 | void adjust(); 129 | void init(); 130 | CURSOR_POSITION getCursorPosition(QPoint pos); 131 | void updateBlink(); 132 | void _initSelection(qint64 nOffset); 133 | void _setSelection(qint64 nOffset); 134 | ST getSelectType(qint64 nOffset); 135 | qint64 addressToOffset(qint64 nAddress); 136 | qint64 relAddressToOffset(qint64 nRelAddress); 137 | qint64 offsetToAddress(qint64 nOffset); 138 | QPoint cursorToPoint(CURSOR_POSITION cp); 139 | bool readByte(qint64 nOffset, quint8 *pByte); 140 | bool writeByte(qint64 nOffset, quint8 *pByte); 141 | void _customContextMenu(const QPoint &pos); 142 | 143 | signals: 144 | void cursorPositionChanged(); 145 | void errorMessage(QString sText); 146 | void customContextMenu(const QPoint &pos); 147 | void editState(bool bState); 148 | 149 | protected: 150 | virtual void paintEvent(QPaintEvent *pEvent); 151 | virtual void mouseMoveEvent(QMouseEvent *pEvent); 152 | virtual void mousePressEvent(QMouseEvent *pEvent); 153 | virtual void resizeEvent(QResizeEvent *pEvent); 154 | virtual void keyPressEvent(QKeyEvent *pEvent); 155 | virtual void wheelEvent(QWheelEvent *pEvent); 156 | 157 | private: 158 | QIODevice *g_pDevice; 159 | qint32 g_nXOffset; 160 | qint32 g_nBytesProLine; 161 | qint32 g_nCharWidth; 162 | qint32 g_nCharHeight; 163 | qint32 g_nLinesProPage; 164 | qint32 g_nDataBlockSize; 165 | qint64 g_nStartOffset; 166 | qint64 g_nStartOffsetDelta; 167 | qint32 g_nLineHeight; 168 | qint32 g_nAddressPosition; 169 | qint32 g_nAddressWidth; 170 | qint32 g_nAddressWidthCount; 171 | qint32 g_nHexPosition; 172 | qint32 g_nHexWidth; 173 | qint32 g_nAnsiPosition; 174 | qint32 g_nAnsiWidth; 175 | qint32 g_nTotalLineCount; 176 | qint64 g_nDataSize; 177 | QByteArray g_baDataBuffer; 178 | QByteArray g_baDataHexBuffer; 179 | qint32 g_nLineDelta; 180 | bool g_bBlink; 181 | QTimer g_timerCursor; 182 | QRect g_rectCursor; 183 | POS_INFO g_posInfo; 184 | bool g_bMouseSelection; 185 | bool g_bReadonly; 186 | bool g_bIsEdited; 187 | QString g_sBackupFileName; 188 | XBinary::_MEMORY_MAP g_memoryMap; 189 | }; 190 | 191 | #endif // QHEXVIEW_H 192 | -------------------------------------------------------------------------------- /qhexviewwidget.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "qhexviewwidget.h" 22 | 23 | #include "ui_qhexviewwidget.h" 24 | 25 | QHexViewWidget::QHexViewWidget(QWidget *pParent) : QWidget(pParent), ui(new Ui::QHexViewWidget) 26 | { 27 | ui->setupUi(this); 28 | 29 | ui->scrollAreaHex->installEventFilter(this); 30 | 31 | ui->lineEditCursorAddress->setReadOnly(true); 32 | ui->lineEditSelectionAddress->setReadOnly(true); 33 | ui->lineEditSelectionSize->setReadOnly(true); 34 | 35 | connect(ui->scrollAreaHex, SIGNAL(cursorPositionChanged()), this, SLOT(_getState())); 36 | connect(ui->scrollAreaHex, SIGNAL(errorMessage(QString)), this, SLOT(_errorMessage(QString))); 37 | connect(ui->scrollAreaHex, SIGNAL(customContextMenu(const QPoint &)), this, SLOT(_customContextMenu(const QPoint &))); 38 | connect(ui->scrollAreaHex, SIGNAL(editState(bool)), this, SIGNAL(editState(bool))); 39 | 40 | g_scGoToAddress = nullptr; 41 | g_scDumpToFile = nullptr; 42 | g_scSelectAll = nullptr; 43 | g_scCopyAsHex = nullptr; 44 | g_scFind = nullptr; 45 | g_scFindNext = nullptr; 46 | g_scSignature = nullptr; 47 | 48 | ui->scrollAreaHex->setFocus(); 49 | 50 | g_searchData = {}; 51 | g_searchData.nResultOffset = -1; 52 | } 53 | 54 | QHexViewWidget::~QHexViewWidget() 55 | { 56 | delete ui; 57 | } 58 | 59 | void QHexViewWidget::setData(QIODevice *pDevice, QHexView::OPTIONS *pOptions) 60 | { 61 | ui->scrollAreaHex->setData(pDevice, pOptions); 62 | ui->checkBoxReadonly->setChecked(true); 63 | ui->checkBoxReadonly->setEnabled(pDevice->isWritable()); 64 | } 65 | 66 | void QHexViewWidget::setBackupFileName(QString sBackupFileName) 67 | { 68 | ui->scrollAreaHex->setBackupFileName(sBackupFileName); 69 | } 70 | 71 | void QHexViewWidget::setSaveDirectory(QString sSaveDirectory) 72 | { 73 | this->g_sSaveDirectory = sSaveDirectory; 74 | } 75 | 76 | void QHexViewWidget::enableHeader(bool bState) 77 | { 78 | if (bState) { 79 | ui->widgetHeader->show(); 80 | } else { 81 | ui->widgetHeader->hide(); 82 | } 83 | } 84 | 85 | void QHexViewWidget::enableReadOnly(bool bState) 86 | { 87 | if (bState) { 88 | ui->checkBoxReadonly->show(); 89 | } else { 90 | ui->checkBoxReadonly->hide(); 91 | } 92 | } 93 | 94 | bool QHexViewWidget::setReadonly(bool bState) 95 | { 96 | return ui->scrollAreaHex->setReadonly(bState); 97 | } 98 | 99 | void QHexViewWidget::reload() 100 | { 101 | ui->scrollAreaHex->reload(); 102 | } 103 | 104 | bool QHexViewWidget::isEdited() 105 | { 106 | return ui->scrollAreaHex->isEdited(); 107 | } 108 | 109 | void QHexViewWidget::setEdited(bool bState) 110 | { 111 | ui->scrollAreaHex->setEdited(bState); 112 | } 113 | 114 | qint64 QHexViewWidget::getBaseAddress() 115 | { 116 | return ui->scrollAreaHex->getBaseAddress(); 117 | } 118 | 119 | void QHexViewWidget::setSelection(qint64 nAddress, qint64 nSize) 120 | { 121 | ui->scrollAreaHex->setSelection(nAddress, nSize); 122 | } 123 | 124 | void QHexViewWidget::goToAddress(qint64 nAddress) 125 | { 126 | ui->scrollAreaHex->goToAddress(nAddress); 127 | ui->scrollAreaHex->reload(); 128 | } 129 | 130 | void QHexViewWidget::goToOffset(qint64 nOffset) 131 | { 132 | ui->scrollAreaHex->goToOffset(nOffset); 133 | ui->scrollAreaHex->reload(); 134 | } 135 | 136 | bool QHexViewWidget::eventFilter(QObject *pObj, QEvent *pEvent) 137 | { 138 | Q_UNUSED(pObj) 139 | 140 | if (pEvent->type() == QEvent::FocusIn) { 141 | registerShortcuts(true); 142 | } else if (pEvent->type() == QEvent::FocusOut) { 143 | registerShortcuts(false); 144 | } 145 | 146 | return false; 147 | } 148 | 149 | void QHexViewWidget::_getState() 150 | { 151 | QHexView::STATE state = ui->scrollAreaHex->getState(); 152 | 153 | ui->lineEditCursorAddress->setValue32_64((quint64)state.nCursorAddress); 154 | ui->lineEditSelectionAddress->setValue32_64((quint64)state.nSelectionAddress); 155 | ui->lineEditSelectionSize->setValue32_64((quint64)state.nSelectionSize); 156 | } 157 | 158 | void QHexViewWidget::on_pushButtonGoTo_clicked() 159 | { 160 | _goToAddress(); 161 | } 162 | 163 | void QHexViewWidget::on_checkBoxReadonly_toggled(bool bChecked) 164 | { 165 | ui->scrollAreaHex->setReadonly(bChecked); 166 | } 167 | 168 | void QHexViewWidget::_goToAddress() 169 | { 170 | DialogGoToAddress da(this, ui->scrollAreaHex->getMemoryMap(), DialogGoToAddress::TYPE_ADDRESS); 171 | if (da.exec() == QDialog::Accepted) { 172 | ui->scrollAreaHex->goToAddress(da.getValue()); 173 | ui->scrollAreaHex->setFocus(); 174 | ui->scrollAreaHex->reload(); 175 | } 176 | } 177 | 178 | void QHexViewWidget::_dumpToFile() 179 | { 180 | QString sFilter; 181 | sFilter += QString("%1 (*.bin)").arg(tr("Raw data")); 182 | QString sSaveFileName = getDumpName(); 183 | QString sFileName = QFileDialog::getSaveFileName(this, tr("Save dump"), sSaveFileName, sFilter); 184 | 185 | if (!sFileName.isEmpty()) { 186 | QHexView::STATE state = ui->scrollAreaHex->getState(); 187 | 188 | DialogDumpProcess dd(this, ui->scrollAreaHex->getDevice(), state.nSelectionOffset, state.nSelectionSize, sFileName, DumpProcess::DT_OFFSET); 189 | 190 | dd.exec(); 191 | } 192 | } 193 | 194 | void QHexViewWidget::_find() 195 | { 196 | QHexView::STATE state = ui->scrollAreaHex->getState(); 197 | 198 | g_searchData = {}; 199 | g_searchData.nResultOffset = -1; 200 | g_searchData.nCurrentOffset = state.nCursorOffset; 201 | 202 | DialogSearch::OPTIONS options = {}; 203 | 204 | DialogSearch dialogSearch(this, ui->scrollAreaHex->getDevice(), &g_searchData, DialogSearch::SEARCHMODE_SIGNATURE, options); 205 | 206 | if (dialogSearch.exec() == QDialog::Accepted) { 207 | ui->scrollAreaHex->goToOffset(g_searchData.nResultOffset); 208 | ui->scrollAreaHex->setFocus(); 209 | ui->scrollAreaHex->reload(); 210 | } 211 | } 212 | 213 | void QHexViewWidget::_findNext() 214 | { 215 | if (g_searchData.bInit) { 216 | g_searchData.nCurrentOffset = g_searchData.nResultOffset + 1; 217 | g_searchData.startFrom = XBinary::SF_CURRENTOFFSET; 218 | 219 | DialogSearchProcess dialogSearch(this, ui->scrollAreaHex->getDevice(), &g_searchData); 220 | 221 | if (dialogSearch.exec() == QDialog::Accepted) { 222 | ui->scrollAreaHex->goToOffset(g_searchData.nResultOffset); 223 | ui->scrollAreaHex->setFocus(); 224 | ui->scrollAreaHex->reload(); 225 | } 226 | } 227 | } 228 | 229 | void QHexViewWidget::_selectAll() 230 | { 231 | ui->scrollAreaHex->selectAll(); 232 | _getState(); 233 | } 234 | 235 | void QHexViewWidget::_copyAsHex() 236 | { 237 | QHexView::STATE state = ui->scrollAreaHex->getState(); 238 | 239 | qint64 nSize = qMin(state.nSelectionSize, (qint64)0x10000); 240 | 241 | QByteArray baData = ui->scrollAreaHex->readArray(state.nSelectionOffset, nSize); 242 | 243 | QApplication::clipboard()->setText(baData.toHex()); 244 | } 245 | 246 | void QHexViewWidget::_signature() 247 | { 248 | QHexView::STATE state = ui->scrollAreaHex->getState(); 249 | 250 | DialogHexSignature dsh(this, ui->scrollAreaHex->getDevice(), state.nSelectionOffset, state.nSelectionSize); 251 | 252 | dsh.exec(); 253 | } 254 | 255 | void QHexViewWidget::_customContextMenu(const QPoint &pos) 256 | { 257 | // QHexView::STATE state=ui->scrollAreaHex->getState(); 258 | 259 | // QMenu contextMenu(this); 260 | 261 | // QAction actionGoToAddress(tr("Go to address"),this); 262 | // actionGoToAddress.setShortcut(QKeySequence(XShortcuts::GOTOADDRESS)); 263 | // connect(&actionGoToAddress,SIGNAL(triggered()),this,SLOT(_goToAddress())); 264 | // contextMenu.addAction(&actionGoToAddress); 265 | 266 | // QAction actionDumpToFile(tr("Dump to file"),this); 267 | // actionDumpToFile.setShortcut(QKeySequence(XShortcuts::DUMPTOFILE)); 268 | // connect(&actionDumpToFile,SIGNAL(triggered()),this,SLOT(_dumpToFile())); 269 | 270 | // QAction actionSignature(tr("Signature"),this); 271 | // actionSignature.setShortcut(QKeySequence(XShortcuts::HEXSIGNATURE)); 272 | // connect(&actionSignature,SIGNAL(triggered()),this,SLOT(_signature())); 273 | 274 | // if(state.nSelectionSize) 275 | // { 276 | // contextMenu.addAction(&actionDumpToFile); 277 | // contextMenu.addAction(&actionSignature); 278 | // } 279 | 280 | // QAction actionFind(tr("Find"),this); 281 | // actionFind.setShortcut(QKeySequence(XShortcuts::FIND)); 282 | // connect(&actionFind,SIGNAL(triggered()),this,SLOT(_find())); 283 | // contextMenu.addAction(&actionFind); 284 | 285 | // QAction actionFindNext(tr("Find next"),this); 286 | // actionFindNext.setShortcut(QKeySequence(XShortcuts::FINDNEXT)); 287 | // connect(&actionFindNext,SIGNAL(triggered()),this,SLOT(_findNext())); 288 | // contextMenu.addAction(&actionFindNext); 289 | 290 | // QMenu menuSelect(tr("Select"),this); 291 | 292 | // QAction actionSelectAll(tr("Select all"),this); 293 | // actionSelectAll.setShortcut(QKeySequence(XShortcuts::SELECTALL)); 294 | // connect(&actionSelectAll,SIGNAL(triggered()),this,SLOT(_selectAll())); 295 | 296 | // menuSelect.addAction(&actionSelectAll); 297 | // contextMenu.addMenu(&menuSelect); 298 | 299 | // QMenu menuCopy(tr("Copy"),this); 300 | 301 | // QAction actionCopyAsHex(tr("Copy as hex"),this); 302 | // actionCopyAsHex.setShortcut(QKeySequence(XShortcuts::COPYASHEX)); 303 | // connect(&actionCopyAsHex,SIGNAL(triggered()),this,SLOT(_copyAsHex())); 304 | 305 | // menuCopy.addAction(&actionCopyAsHex); 306 | // contextMenu.addMenu(&menuCopy); 307 | 308 | // // TODO reset select 309 | 310 | // contextMenu.exec(pos); 311 | } 312 | 313 | void QHexViewWidget::_errorMessage(QString sText) 314 | { 315 | QMessageBox::critical(this, tr("Error"), sText); 316 | } 317 | 318 | QString QHexViewWidget::getDumpName() 319 | { 320 | QString sResult; 321 | 322 | if (g_sSaveDirectory != "") { 323 | sResult += g_sSaveDirectory; 324 | sResult += QDir::separator(); 325 | } 326 | 327 | sResult += "dump.bin"; 328 | 329 | return sResult; 330 | } 331 | 332 | void QHexViewWidget::registerShortcuts(bool bState) 333 | { 334 | // if(bState) 335 | // { 336 | // if(!g_scGoToAddress) g_scGoToAddress =new QShortcut(QKeySequence(XShortcuts::GOTOADDRESS), this,SLOT(_goToAddress())); 337 | // if(!g_scDumpToFile) g_scDumpToFile =new QShortcut(QKeySequence(XShortcuts::DUMPTOFILE), this,SLOT(_dumpToFile())); 338 | // if(!g_scSelectAll) g_scSelectAll =new QShortcut(QKeySequence(XShortcuts::SELECTALL), this,SLOT(_selectAll())); 339 | // if(!g_scCopyAsHex) g_scCopyAsHex =new QShortcut(QKeySequence(XShortcuts::COPYASHEX), this,SLOT(_copyAsHex())); 340 | // if(!g_scFind) g_scFind =new QShortcut(QKeySequence(XShortcuts::FIND), this,SLOT(_find())); 341 | // if(!g_scFindNext) g_scFindNext =new QShortcut(QKeySequence(XShortcuts::FINDNEXT), this,SLOT(_findNext())); 342 | // if(!g_scSignature) g_scSignature =new QShortcut(QKeySequence(XShortcuts::HEXSIGNATURE), this,SLOT(_signature())); 343 | // } 344 | // else 345 | // { 346 | // if(g_scGoToAddress) {delete g_scGoToAddress; g_scGoToAddress=nullptr;} 347 | // if(g_scDumpToFile) {delete g_scDumpToFile; g_scDumpToFile=nullptr;} 348 | // if(g_scSelectAll) {delete g_scSelectAll; g_scSelectAll=nullptr;} 349 | // if(g_scCopyAsHex) {delete g_scCopyAsHex; g_scCopyAsHex=nullptr;} 350 | // if(g_scFind) {delete g_scFind; g_scFind=nullptr;} 351 | // if(g_scFindNext) {delete g_scFindNext; g_scFindNext=nullptr;} 352 | // if(g_scSignature) {delete g_scSignature; g_scSignature=nullptr;} 353 | // } 354 | } 355 | -------------------------------------------------------------------------------- /qhexview.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "qhexview.h" 22 | 23 | QHexView::QHexView(QWidget *pParent) : QAbstractScrollArea(pParent) 24 | { 25 | g_pDevice = nullptr; 26 | 27 | g_bReadonly = true; 28 | g_bIsEdited = false; 29 | 30 | g_bMouseSelection = false; 31 | g_nDataSize = 0; 32 | g_bBlink = false; 33 | g_nBytesProLine = 0; 34 | 35 | g_nStartOffset = 0; 36 | g_nStartOffsetDelta = 0; 37 | 38 | setBytesProLine(16); 39 | _initSelection(-1); 40 | g_nLineDelta = 4; // mb 3 41 | g_posInfo.cursorPosition.nOffset = 0; 42 | g_posInfo.cursorPosition.type = CT_HIWORD; 43 | 44 | #ifdef Q_OS_WIN 45 | setFont(QFont("Courier", 10)); 46 | #endif 47 | #ifdef Q_OS_LINUX 48 | setFont(QFont("Monospace", 10)); 49 | #endif 50 | #ifdef Q_OS_OSX 51 | setFont(QFont("Courier", 10)); // TODO Check "Menlo" 52 | #endif 53 | 54 | setContextMenuPolicy(Qt::CustomContextMenu); 55 | 56 | connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(verticalScroll())); 57 | connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(horisontalScroll())); 58 | 59 | connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(_customContextMenu(QPoint))); 60 | 61 | connect(&g_timerCursor, SIGNAL(timeout()), this, SLOT(updateBlink())); 62 | 63 | g_timerCursor.setInterval(500); 64 | g_timerCursor.start(); 65 | } 66 | 67 | // QHexView::~QHexView() 68 | //{ 69 | 70 | //} 71 | 72 | QIODevice *QHexView::getDevice() const 73 | { 74 | return g_pDevice; 75 | } 76 | 77 | void QHexView::setData(QIODevice *pDevice, OPTIONS *pOptions) 78 | { 79 | this->g_pDevice = pDevice; 80 | 81 | if (pOptions) { 82 | this->g_sBackupFileName = pOptions->sBackupFileName; 83 | this->g_memoryMap = pOptions->memoryMap; 84 | } 85 | 86 | if (this->g_memoryMap.listRecords.count() == 0) { 87 | XBinary binary(pDevice); 88 | this->g_memoryMap = binary.getMemoryMap(); 89 | } 90 | 91 | init(); 92 | 93 | adjust(); 94 | viewport()->update(); 95 | 96 | if (pOptions) { 97 | goToAddress(pOptions->nStartAddress); 98 | 99 | if (pOptions->nSizeOfSelection) { 100 | if (isAddressValid(pOptions->nStartSelectionAddress)) { 101 | _initSelection(addressToOffset(pOptions->nStartSelectionAddress)); 102 | _setSelection(addressToOffset(pOptions->nStartSelectionAddress) + pOptions->nSizeOfSelection - 1); 103 | } 104 | } 105 | } 106 | 107 | emit cursorPositionChanged(); 108 | } 109 | 110 | void QHexView::setBackupFileName(QString sBackupFileName) 111 | { 112 | this->g_sBackupFileName = sBackupFileName; 113 | } 114 | 115 | void QHexView::paintEvent(QPaintEvent *pEvent) 116 | { 117 | // QElapsedTimer timer; 118 | // timer.start(); 119 | 120 | QPainter painter(viewport()); 121 | QFont fontNormal = painter.font(); 122 | QFont fontBold = fontNormal; 123 | fontBold.setBold(true); 124 | 125 | painter.setPen(viewport()->palette().color(QPalette::WindowText)); 126 | 127 | if (g_rectCursor != pEvent->rect()) { 128 | // qDebug("void QHexView::paintEvent(QPaintEvent *event)"); 129 | qint32 topLeftY = pEvent->rect().topLeft().y(); 130 | qint32 topLeftX = pEvent->rect().topLeft().x() - g_nXOffset; 131 | 132 | painter.setPen(QPen(Qt::gray)); 133 | 134 | for (qint32 i = 0; i < g_nLinesProPage; i++) { 135 | qint64 nLineAddress = XBinary::offsetToAddress(&g_memoryMap, g_nStartOffset + i * g_nBytesProLine); 136 | 137 | if (nLineAddress != -1) { 138 | qint32 nLinePosition = topLeftY + (i + 1) * g_nLineHeight; 139 | QString sLineAddress = QString("%1").arg(nLineAddress, g_nAddressWidthCount, 16, QChar('0')); 140 | painter.drawText(topLeftX + g_nAddressPosition, nLinePosition, sLineAddress); 141 | } 142 | } 143 | 144 | painter.setPen(viewport()->palette().color(QPalette::WindowText)); 145 | painter.setBackgroundMode(Qt::TransparentMode); 146 | 147 | // HEX 148 | bool bIsSelected = false; 149 | QColor color = viewport()->palette().color(QPalette::Base); 150 | 151 | qint32 nDataBufferSize = g_baDataBuffer.size(); 152 | 153 | for (qint32 i = 0; i < g_nLinesProPage; i++) { 154 | qint32 nLinePosition = topLeftY + (i + 1) * g_nLineHeight; 155 | 156 | for (qint32 j = 0; j < g_nBytesProLine; j++) { 157 | bool _bIsSelected = false; 158 | 159 | qint32 nBytePositionHEX = topLeftX + g_nHexPosition + j * g_nCharWidth * 3; 160 | qint32 nBytePositionANSI = topLeftX + g_nAnsiPosition + j * g_nCharWidth; 161 | qint32 nIndex = (j + i * g_nBytesProLine); 162 | QString sHex = g_baDataHexBuffer.mid(nIndex * 2, 2); 163 | char ch = ' '; 164 | 165 | if (nIndex < nDataBufferSize) { 166 | ch = g_baDataBuffer.at(nIndex); 167 | ch = convertANSI(ch); 168 | } 169 | 170 | ST st = getSelectType(g_nStartOffset + nIndex); 171 | 172 | _bIsSelected = !(st == ST_NOTSELECTED); 173 | 174 | if (bIsSelected != _bIsSelected) { 175 | bIsSelected = _bIsSelected; 176 | 177 | if (st == ST_NOTSELECTED) { 178 | color = viewport()->palette().color(QPalette::Base); 179 | // painter.setPen(viewport()->palette().color(QPalette::WindowText)); 180 | } else { 181 | color = viewport()->palette().color(QPalette::Highlight); 182 | // painter.setPen(viewport()->palette().color(QPalette::WindowText)); 183 | } 184 | } 185 | 186 | int nCount = 3; 187 | 188 | if ((st == ST_END) || (st == ST_ONEBYTE) || ((st != ST_NOTSELECTED) && (j == g_nBytesProLine - 1))) { 189 | nCount = 2; 190 | } 191 | 192 | // TODO flag changed if selected 193 | QRect rect; 194 | rect.setRect(nBytePositionHEX, nLinePosition - g_nLineHeight + g_nLineDelta, g_nCharWidth * nCount, g_nLineHeight); // mb TODO fix 3 195 | painter.fillRect(rect, color); 196 | rect.setRect(nBytePositionANSI, nLinePosition - g_nLineHeight + g_nLineDelta, g_nCharWidth, g_nLineHeight); 197 | painter.fillRect(rect, color); 198 | 199 | bool bBold = (sHex != "00"); 200 | 201 | if (bBold) { 202 | painter.setFont(fontBold); 203 | } 204 | 205 | painter.drawText(nBytePositionHEX, nLinePosition, sHex); 206 | painter.drawText(nBytePositionANSI, nLinePosition, QChar(ch)); 207 | 208 | if (bBold) { 209 | // Restore 210 | painter.setFont(fontNormal); 211 | } 212 | } 213 | } 214 | 215 | painter.setBackgroundMode(Qt::TransparentMode); 216 | painter.setPen(viewport()->palette().color(QPalette::WindowText)); 217 | } 218 | 219 | if (g_posInfo.cursorPosition.nOffset != -1) { 220 | if (g_bBlink && hasFocus()) { 221 | painter.setPen(viewport()->palette().color(QPalette::Highlight)); 222 | painter.fillRect(g_rectCursor, this->palette().color(QPalette::WindowText)); 223 | } else { 224 | painter.setPen(viewport()->palette().color(QPalette::WindowText)); 225 | painter.fillRect(g_rectCursor, this->palette().color(QPalette::Base)); 226 | } 227 | 228 | qint32 nRelOffset = g_posInfo.cursorPosition.nOffset - g_nStartOffset; 229 | 230 | if (g_posInfo.cursorPosition.type == CT_ANSI) { 231 | char ch = ' '; 232 | 233 | if (nRelOffset < g_baDataBuffer.size()) { 234 | ch = g_baDataBuffer.at(nRelOffset); 235 | ch = convertANSI(ch); 236 | } 237 | 238 | painter.drawText(g_rectCursor.x(), g_rectCursor.y() + g_nLineHeight - g_nLineDelta, QChar(ch)); 239 | } else if (g_posInfo.cursorPosition.type == CT_HIWORD) { 240 | painter.drawText(g_rectCursor.x(), g_rectCursor.y() + g_nLineHeight - g_nLineDelta, g_baDataHexBuffer.mid(nRelOffset * 2, 1)); 241 | } else if (g_posInfo.cursorPosition.type == CT_LOWORD) { 242 | painter.drawText(g_rectCursor.x(), g_rectCursor.y() + g_nLineHeight - g_nLineDelta, g_baDataHexBuffer.mid(nRelOffset * 2 + 1, 1)); 243 | } 244 | } 245 | 246 | // qDebug("QHexView::paintEvent: %d msec",timer.elapsed()); 247 | } 248 | 249 | void QHexView::mouseMoveEvent(QMouseEvent *pEvent) 250 | { 251 | if (g_bMouseSelection) { 252 | viewport()->update(); 253 | 254 | int nPos = getCursorPosition(pEvent->pos()).nOffset; 255 | 256 | if (nPos >= 0) { 257 | _setSelection(nPos); 258 | emit cursorPositionChanged(); 259 | // _rectCursor=QRect(0,0,100,100); 260 | } 261 | } 262 | } 263 | 264 | void QHexView::mousePressEvent(QMouseEvent *pEvent) 265 | { 266 | g_bMouseSelection = false; 267 | 268 | if (pEvent->button() == Qt::LeftButton) { 269 | // viewport()->update(); 270 | CURSOR_POSITION cp = getCursorPosition(pEvent->pos()); 271 | 272 | if (cp.nOffset >= 0) { 273 | g_posInfo.cursorPosition = cp; 274 | _initSelection(cp.nOffset); 275 | // _rectCursor=QRect(0,0,100,100); 276 | g_bMouseSelection = true; 277 | } 278 | 279 | adjust(); 280 | g_bBlink = true; 281 | viewport()->update(); // mb TODO 282 | } 283 | } 284 | 285 | quint32 QHexView::getBytesProLine() const 286 | { 287 | return g_nBytesProLine; 288 | } 289 | 290 | void QHexView::setBytesProLine(const quint32 nBytesProLine) 291 | { 292 | g_nBytesProLine = nBytesProLine; 293 | } 294 | 295 | // qint64 QHexView::getBaseAddress() const 296 | //{ 297 | // return _nBaseAddress; 298 | // } 299 | 300 | void QHexView::setFont(const QFont &font) 301 | { 302 | const QFontMetricsF fm(font); 303 | g_nCharWidth = fm.boundingRect('2').width(); 304 | g_nCharWidth = qMax(fm.boundingRect('W').width(), (qreal)g_nCharWidth); 305 | g_nCharHeight = fm.height(); 306 | 307 | QAbstractScrollArea::setFont(font); 308 | 309 | adjust(); 310 | viewport()->update(); 311 | } 312 | 313 | bool QHexView::isAddressValid(qint64 nAddress) 314 | { 315 | // return ((_nBaseAddress<=nAddress)&&(nAddress<_nDataSize+_nBaseAddress)); 316 | return XBinary::isAddressValid(&g_memoryMap, nAddress); 317 | } 318 | 319 | bool QHexView::isRelAddressValid(qint64 nRelAddress) 320 | { 321 | return XBinary::isRelAddressValid(&g_memoryMap, nRelAddress); 322 | } 323 | 324 | bool QHexView::isOffsetValid(qint64 nOffset) 325 | { 326 | // return ((0<=nOffset)&&(nOffset<_nDataSize)); 327 | return XBinary::isOffsetValid(&g_memoryMap, nOffset); 328 | } 329 | 330 | void QHexView::reload() 331 | { 332 | adjust(); 333 | viewport()->update(); 334 | } 335 | 336 | QHexView::STATE QHexView::getState() 337 | { 338 | STATE state = STATE(); 339 | 340 | state.nCursorOffset = g_posInfo.cursorPosition.nOffset; 341 | state.nCursorAddress = offsetToAddress(g_posInfo.cursorPosition.nOffset); 342 | 343 | if (state.nCursorAddress == -1) { 344 | state.nCursorAddress = 0; 345 | } 346 | 347 | if (g_posInfo.nSelectionStartOffset != -1) { 348 | state.nSelectionOffset = g_posInfo.nSelectionStartOffset; 349 | state.nSelectionAddress = offsetToAddress(g_posInfo.nSelectionStartOffset); 350 | state.nSelectionSize = g_posInfo.nSelectionEndOffset - g_posInfo.nSelectionStartOffset + 1; 351 | } else { 352 | // state.nCursorAddress=0; 353 | state.nSelectionOffset = 0; 354 | state.nSelectionAddress = 0; 355 | state.nSelectionSize = 0; 356 | } 357 | 358 | return state; 359 | } 360 | 361 | bool QHexView::setReadonly(bool bState) 362 | { 363 | bool bResult = false; 364 | 365 | if (g_pDevice) { 366 | if ((bState) || ((!bState) && (g_pDevice->isWritable()))) { 367 | g_bReadonly = bState; 368 | bResult = true; 369 | } 370 | } 371 | 372 | return bResult; 373 | } 374 | 375 | QByteArray QHexView::readArray(qint64 nOffset, qint64 nSize) 376 | { 377 | QByteArray baResult; 378 | 379 | if (g_pDevice->seek(nOffset) && (nOffset + nSize <= g_pDevice->size())) { 380 | baResult.resize((qint32)nSize); 381 | qint64 _nSize = g_pDevice->read(baResult.data(), nSize); 382 | 383 | if (_nSize != nSize) { 384 | baResult.resize((qint32)_nSize); 385 | } 386 | } 387 | 388 | return baResult; 389 | } 390 | 391 | bool QHexView::isEdited() 392 | { 393 | return g_bIsEdited; 394 | } 395 | 396 | void QHexView::setEdited(bool bState) 397 | { 398 | this->g_bIsEdited = bState; 399 | } 400 | 401 | qint64 QHexView::getBaseAddress() 402 | { 403 | return this->getMemoryMap()->nModuleAddress; 404 | } 405 | 406 | char QHexView::convertANSI(char cByte) 407 | { 408 | if ((cByte < 0x20) || (cByte > 0x7e)) { 409 | cByte = '.'; 410 | } 411 | 412 | return cByte; 413 | } 414 | 415 | QString QHexView::getFontName() 416 | { 417 | QString sResult; 418 | #ifdef Q_OS_WIN 419 | sResult = "Courier"; 420 | #endif 421 | #ifdef Q_OS_LINUX 422 | sResult = "Monospace"; 423 | #endif 424 | #ifdef Q_OS_OSX 425 | sResult = "Courier"; // TODO Check "Menlo" 426 | #endif 427 | return sResult; 428 | } 429 | 430 | void QHexView::goToAddress(qint64 nAddress) 431 | { 432 | if ((isAddressValid(nAddress)) && (g_nBytesProLine)) { 433 | qint64 nOffset = addressToOffset(nAddress); 434 | 435 | goToOffset(nOffset); 436 | } 437 | } 438 | 439 | void QHexView::goToRelAddress(qint64 nRelAddress) 440 | { 441 | if ((isRelAddressValid(nRelAddress)) && (g_nBytesProLine)) { 442 | qint64 nOffset = relAddressToOffset(nRelAddress); 443 | 444 | goToOffset(nOffset); 445 | } 446 | } 447 | 448 | void QHexView::goToOffset(qint64 nOffset) 449 | { 450 | if ((isOffsetValid(nOffset)) && (g_nBytesProLine)) { 451 | verticalScrollBar()->setValue((nOffset) / g_nBytesProLine); // TODO check for large files 452 | g_nStartOffsetDelta = (nOffset) % g_nBytesProLine; 453 | 454 | // posInfo.cursorPosition.nOffset+=(addressToOffset(nAddress))%_nBytesProLine; 455 | // posInfo.cursorPosition.nOffset=addressToOffset(nAddress); 456 | // qDebug(QString::number(posInfo.cursorPosition.nOffset,16).toLatin1().data()); 457 | g_posInfo.cursorPosition.nOffset = nOffset; 458 | g_posInfo.cursorPosition.type = CT_HIWORD; 459 | // qDebug(QString::number(posInfo.cursorPosition.nOffset,16).toLatin1().data()); 460 | } 461 | } 462 | 463 | void QHexView::_goToOffset(qint64 nOffset) 464 | { 465 | if ((isOffsetValid(nOffset)) && (g_nBytesProLine)) { 466 | verticalScrollBar()->setValue((nOffset) / g_nBytesProLine); 467 | g_nStartOffsetDelta = (nOffset) % g_nBytesProLine; 468 | } 469 | } 470 | 471 | void QHexView::setSelection(qint64 nAddress, qint64 nSize) 472 | { 473 | if (nSize) { 474 | if (isAddressValid(nAddress)) { 475 | qint64 nOffset = addressToOffset(nAddress); 476 | _initSelection(nOffset); 477 | _setSelection(nOffset + nSize - 1); 478 | 479 | viewport()->update(); 480 | } 481 | } 482 | } 483 | 484 | void QHexView::selectAll() 485 | { 486 | setSelection(g_memoryMap.nModuleAddress, g_nDataSize); 487 | } 488 | 489 | XBinary::_MEMORY_MAP *QHexView::getMemoryMap() 490 | { 491 | return &g_memoryMap; 492 | } 493 | 494 | void QHexView::verticalScroll() 495 | { 496 | // _nStartOffsetDelta=0; 497 | adjust(); 498 | } 499 | 500 | void QHexView::horisontalScroll() 501 | { 502 | adjust(); 503 | } 504 | 505 | QHexView::ST QHexView::getSelectType(qint64 nOffset) 506 | { 507 | ST result = ST_NOTSELECTED; 508 | 509 | if (nOffset == g_posInfo.nSelectionStartOffset) { 510 | if (nOffset == g_posInfo.nSelectionEndOffset) { 511 | result = ST_ONEBYTE; 512 | } else { 513 | result = ST_BEGIN; 514 | } 515 | } else if (nOffset == g_posInfo.nSelectionEndOffset) { 516 | result = ST_END; 517 | } else if ((nOffset > g_posInfo.nSelectionStartOffset) && (nOffset < g_posInfo.nSelectionEndOffset)) { 518 | result = ST_MID; 519 | } 520 | 521 | return result; 522 | } 523 | 524 | qint64 QHexView::addressToOffset(qint64 nAddress) 525 | { 526 | return XBinary::addressToOffset(&g_memoryMap, nAddress); 527 | } 528 | 529 | qint64 QHexView::relAddressToOffset(qint64 nRelAddress) 530 | { 531 | return XBinary::relAddressToOffset(&g_memoryMap, nRelAddress); 532 | } 533 | 534 | qint64 QHexView::offsetToAddress(qint64 nOffset) 535 | { 536 | // qint64 nResult=-1; 537 | 538 | // if(nOffset!=-1) 539 | // { 540 | // nResult=nOffset+_nBaseAddress; 541 | // } 542 | 543 | // return nResult; 544 | return XBinary::offsetToAddress(&g_memoryMap, nOffset); 545 | } 546 | 547 | QPoint QHexView::cursorToPoint(QHexView::CURSOR_POSITION cp) 548 | { 549 | QPoint result; 550 | 551 | qint64 nRelOffset = cp.nOffset - g_nStartOffset; 552 | 553 | if (cp.type != CT_NONE) { 554 | result.setY((nRelOffset / g_nBytesProLine) * g_nLineHeight); 555 | } 556 | 557 | if (cp.type == CT_ANSI) { 558 | result.setX(g_nAnsiPosition + (nRelOffset % g_nBytesProLine) * g_nCharWidth); 559 | } else if (cp.type == CT_HIWORD) { 560 | result.setX(g_nHexPosition + (nRelOffset % g_nBytesProLine) * g_nCharWidth * 3); 561 | } else if (cp.type == CT_LOWORD) { 562 | result.setX(g_nHexPosition + (nRelOffset % g_nBytesProLine) * g_nCharWidth * 3 + g_nCharWidth); 563 | } 564 | 565 | return result; 566 | } 567 | 568 | bool QHexView::readByte(qint64 nOffset, quint8 *pByte) 569 | { 570 | int nCount = 0; 571 | 572 | if (g_pDevice->seek(nOffset)) { 573 | nCount = (int)g_pDevice->read((char *)pByte, 1); 574 | } 575 | 576 | return (nCount == 1); 577 | } 578 | 579 | bool QHexView::writeByte(qint64 nOffset, quint8 *pByte) 580 | { 581 | int nCount = 0; 582 | 583 | if (g_pDevice->seek(nOffset)) { 584 | nCount = (int)g_pDevice->write((char *)pByte, 1); 585 | } 586 | 587 | return (nCount == 1); 588 | } 589 | 590 | void QHexView::_customContextMenu(const QPoint &pos) 591 | { 592 | // TODO 593 | emit customContextMenu(mapToGlobal(pos)); 594 | } 595 | 596 | void QHexView::adjust() 597 | { 598 | int nHeight = viewport()->height(); 599 | g_nLineHeight = g_nCharHeight + 5; 600 | g_nLinesProPage = (nHeight) / g_nLineHeight; // mb nHeight-4 601 | g_nDataBlockSize = g_nLinesProPage * g_nBytesProLine; 602 | 603 | g_nAddressPosition = g_nCharWidth; 604 | g_nAddressWidthCount = 8; 605 | 606 | if (g_pDevice) { 607 | if ((g_pDevice->size() + g_memoryMap.nModuleAddress) >= 0xFFFFFFFF) { 608 | g_nAddressWidthCount = 16; 609 | } 610 | } 611 | 612 | g_nAddressWidth = (g_nAddressWidthCount + 3) * g_nCharWidth; // TODO set addresswidth 613 | g_nHexPosition = g_nAddressPosition + g_nAddressWidth; 614 | g_nHexWidth = (g_nBytesProLine + 1) * g_nCharWidth * 3; 615 | g_nAnsiPosition = g_nHexPosition + g_nHexWidth; 616 | g_nAnsiWidth = (g_nBytesProLine + 1) * g_nCharWidth; 617 | 618 | horizontalScrollBar()->setRange(0, g_nAnsiPosition + g_nAnsiWidth - viewport()->width()); 619 | horizontalScrollBar()->setPageStep(viewport()->width()); 620 | 621 | verticalScrollBar()->setRange(0, g_nTotalLineCount - g_nLinesProPage); 622 | verticalScrollBar()->setPageStep(g_nLinesProPage); 623 | 624 | g_nStartOffset = verticalScrollBar()->value() * g_nBytesProLine + g_nStartOffsetDelta; 625 | g_nXOffset = horizontalScrollBar()->value(); 626 | 627 | // TODO update 628 | if (g_pDevice) { 629 | if (g_pDevice->seek(g_nStartOffset)) { 630 | g_baDataBuffer.resize(g_nDataBlockSize); 631 | int nCount = (int)g_pDevice->read(g_baDataBuffer.data(), g_nDataBlockSize); 632 | g_baDataBuffer.resize(nCount); 633 | g_baDataHexBuffer = QByteArray(g_baDataBuffer.toHex()); 634 | } else { 635 | g_baDataBuffer.clear(); 636 | g_baDataHexBuffer.clear(); 637 | } 638 | } 639 | 640 | qint64 nRelOffset = g_posInfo.cursorPosition.nOffset - g_nStartOffset; 641 | 642 | if (nRelOffset < 0) { 643 | nRelOffset = g_posInfo.cursorPosition.nOffset % g_nBytesProLine; 644 | g_posInfo.cursorPosition.nOffset = g_nStartOffset + nRelOffset; 645 | } else if (nRelOffset >= g_nBytesProLine * g_nLinesProPage) { 646 | nRelOffset = g_posInfo.cursorPosition.nOffset % g_nBytesProLine; 647 | g_posInfo.cursorPosition.nOffset = g_nStartOffset + g_nBytesProLine * (g_nLinesProPage - 1) + nRelOffset; 648 | } 649 | 650 | if (g_posInfo.cursorPosition.nOffset > g_nDataSize - 1) { 651 | g_posInfo.cursorPosition.nOffset = g_nDataSize - 1; 652 | } 653 | 654 | if ((g_posInfo.cursorPosition.nOffset != -1) && (g_posInfo.cursorPosition.type != CT_NONE)) { 655 | QPoint point = cursorToPoint(g_posInfo.cursorPosition); 656 | g_rectCursor.setRect(point.x() - horizontalScrollBar()->value(), point.y() + g_nLineDelta, g_nCharWidth, g_nLineHeight); 657 | } 658 | 659 | emit cursorPositionChanged(); 660 | } 661 | 662 | void QHexView::init() 663 | { 664 | g_nStartOffset = 0; 665 | g_nStartOffsetDelta = 0; 666 | g_nDataSize = 0; 667 | 668 | if (g_pDevice) { 669 | g_nDataSize = g_pDevice->size(); 670 | } 671 | 672 | g_nTotalLineCount = g_nDataSize / g_nBytesProLine + 1; 673 | verticalScrollBar()->setValue(0); 674 | } 675 | 676 | QHexView::CURSOR_POSITION QHexView::getCursorPosition(QPoint pos) 677 | { 678 | CURSOR_POSITION result = CURSOR_POSITION(); 679 | result.nOffset = -1; 680 | 681 | result.type = CT_NONE; 682 | quint64 nRelOffset = -1; 683 | 684 | int nX = pos.x() + horizontalScrollBar()->value(); 685 | int nY = pos.y(); 686 | int nDeltaX = 0; 687 | int nDeltaY = 0; 688 | 689 | if ((nX > g_nAddressPosition) && (nX < g_nAddressPosition + g_nAddressWidth)) { 690 | nDeltaX = 0; 691 | nDeltaY = (nY - g_nLineDelta) / g_nLineHeight; 692 | 693 | result.type = CT_HIWORD; 694 | 695 | nRelOffset = nDeltaY * g_nBytesProLine + nDeltaX; 696 | } else if ((nX > g_nHexPosition) && (nX < g_nHexPosition + g_nHexWidth)) { 697 | nDeltaX = (nX - g_nHexPosition) / (g_nCharWidth * 3); 698 | nDeltaY = (nY - g_nLineDelta) / g_nLineHeight; 699 | 700 | if ((nX - g_nHexPosition) % (g_nCharWidth * 3) <= g_nCharWidth) { 701 | result.type = CT_HIWORD; 702 | } else { 703 | result.type = CT_LOWORD; 704 | } 705 | 706 | nRelOffset = nDeltaY * g_nBytesProLine + nDeltaX; 707 | // TODO !!! 708 | } else if ((nX > g_nAnsiPosition) && (nX < g_nAnsiPosition + g_nAnsiWidth)) { 709 | nDeltaX = (nX - g_nAnsiPosition) / g_nCharWidth; 710 | nDeltaY = (nY - g_nLineDelta) / g_nLineHeight; // mb TODO LindeDelta 711 | 712 | result.type = CT_ANSI; 713 | nRelOffset = nDeltaY * g_nBytesProLine + nDeltaX; 714 | } 715 | 716 | if (nRelOffset != (quint64)-1) { 717 | result.nOffset = g_nStartOffset + nRelOffset; 718 | 719 | if (!isOffsetValid(result.nOffset)) { 720 | result.nOffset = -1; 721 | } 722 | } 723 | 724 | return result; 725 | } 726 | 727 | void QHexView::updateBlink() 728 | { 729 | g_bBlink = (bool)(!g_bBlink); 730 | viewport()->update(g_rectCursor); 731 | } 732 | 733 | void QHexView::_initSelection(qint64 nOffset) 734 | { 735 | if (!isOffsetValid(nOffset)) { 736 | nOffset = -1; 737 | } 738 | 739 | g_posInfo.nSelectionInitOffset = nOffset; 740 | g_posInfo.nSelectionStartOffset = -1; 741 | g_posInfo.nSelectionEndOffset = -1; 742 | } 743 | 744 | void QHexView::_setSelection(qint64 nOffset) 745 | { 746 | if (isOffsetValid(nOffset)) { 747 | if (nOffset > g_posInfo.nSelectionInitOffset) { 748 | g_posInfo.nSelectionStartOffset = g_posInfo.nSelectionInitOffset; 749 | g_posInfo.nSelectionEndOffset = nOffset; 750 | } else { 751 | g_posInfo.nSelectionStartOffset = nOffset; 752 | g_posInfo.nSelectionEndOffset = g_posInfo.nSelectionInitOffset; 753 | } 754 | } 755 | } 756 | 757 | void QHexView::resizeEvent(QResizeEvent *pEvent) 758 | { 759 | Q_UNUSED(pEvent) 760 | 761 | adjust(); 762 | } 763 | 764 | void QHexView::keyPressEvent(QKeyEvent *pEvent) 765 | { 766 | // Move commands 767 | if (pEvent->matches(QKeySequence::MoveToNextChar) || pEvent->matches(QKeySequence::MoveToPreviousChar) || pEvent->matches(QKeySequence::MoveToNextLine) || 768 | pEvent->matches(QKeySequence::MoveToPreviousLine) || pEvent->matches(QKeySequence::MoveToStartOfLine) || pEvent->matches(QKeySequence::MoveToEndOfLine) || 769 | pEvent->matches(QKeySequence::MoveToNextPage) || pEvent->matches(QKeySequence::MoveToPreviousPage) || pEvent->matches(QKeySequence::MoveToStartOfDocument) || 770 | pEvent->matches(QKeySequence::MoveToEndOfDocument)) { 771 | if (pEvent->matches(QKeySequence::MoveToNextChar) || pEvent->matches(QKeySequence::MoveToPreviousChar)) { 772 | if (g_posInfo.cursorPosition.type == CT_ANSI) { 773 | if (pEvent->matches(QKeySequence::MoveToNextChar)) { 774 | g_posInfo.cursorPosition.nOffset++; 775 | } else if (pEvent->matches(QKeySequence::MoveToPreviousChar)) { 776 | g_posInfo.cursorPosition.nOffset--; 777 | } 778 | } else if (g_posInfo.cursorPosition.type == CT_HIWORD) { 779 | if (pEvent->matches(QKeySequence::MoveToNextChar)) { 780 | g_posInfo.cursorPosition.type = CT_LOWORD; 781 | } else if (pEvent->matches(QKeySequence::MoveToPreviousChar)) { 782 | g_posInfo.cursorPosition.nOffset--; 783 | g_posInfo.cursorPosition.type = CT_LOWORD; 784 | } 785 | } else if (g_posInfo.cursorPosition.type == CT_LOWORD) { 786 | if (pEvent->matches(QKeySequence::MoveToNextChar)) { 787 | g_posInfo.cursorPosition.nOffset++; 788 | g_posInfo.cursorPosition.type = CT_HIWORD; 789 | } else if (pEvent->matches(QKeySequence::MoveToPreviousChar)) { 790 | g_posInfo.cursorPosition.type = CT_HIWORD; 791 | } 792 | } 793 | } else if (pEvent->matches(QKeySequence::MoveToNextLine) || pEvent->matches(QKeySequence::MoveToPreviousLine)) { 794 | if (pEvent->matches(QKeySequence::MoveToNextLine)) { 795 | g_posInfo.cursorPosition.nOffset += g_nBytesProLine; 796 | } else if (pEvent->matches(QKeySequence::MoveToPreviousLine)) { 797 | g_posInfo.cursorPosition.nOffset -= g_nBytesProLine; 798 | } 799 | } else if (pEvent->matches(QKeySequence::MoveToNextPage) || pEvent->matches(QKeySequence::MoveToPreviousPage)) { 800 | if (pEvent->matches(QKeySequence::MoveToNextPage)) { 801 | g_posInfo.cursorPosition.nOffset += g_nBytesProLine * g_nLinesProPage; 802 | } else if (pEvent->matches(QKeySequence::MoveToPreviousPage)) { 803 | g_posInfo.cursorPosition.nOffset -= g_nBytesProLine * g_nLinesProPage; 804 | } 805 | } else if (pEvent->matches(QKeySequence::MoveToStartOfLine) || pEvent->matches(QKeySequence::MoveToEndOfLine) || 806 | pEvent->matches(QKeySequence::MoveToStartOfDocument) || pEvent->matches(QKeySequence::MoveToEndOfDocument)) { 807 | if ((g_posInfo.cursorPosition.type == CT_HIWORD) || (g_posInfo.cursorPosition.type == CT_LOWORD)) { 808 | g_posInfo.cursorPosition.type = CT_HIWORD; 809 | } 810 | 811 | if (pEvent->matches(QKeySequence::MoveToStartOfLine)) { 812 | g_posInfo.cursorPosition.nOffset = (g_posInfo.cursorPosition.nOffset / g_nBytesProLine) * g_nBytesProLine; 813 | } else if (pEvent->matches(QKeySequence::MoveToEndOfLine)) { 814 | g_posInfo.cursorPosition.nOffset = ((g_posInfo.cursorPosition.nOffset / g_nBytesProLine) + 1) * g_nBytesProLine - 1; 815 | } else if (pEvent->matches(QKeySequence::MoveToStartOfDocument)) { 816 | g_posInfo.cursorPosition.nOffset = 0; 817 | } else if (pEvent->matches(QKeySequence::MoveToEndOfDocument)) { 818 | g_posInfo.cursorPosition.nOffset = g_nDataSize - 1; 819 | } 820 | } 821 | 822 | if (g_posInfo.cursorPosition.type != CT_NONE) { 823 | if (pEvent->matches(QKeySequence::MoveToNextChar) || pEvent->matches(QKeySequence::MoveToPreviousChar) || pEvent->matches(QKeySequence::MoveToNextLine) || 824 | pEvent->matches(QKeySequence::MoveToPreviousLine) || pEvent->matches(QKeySequence::MoveToStartOfLine) || pEvent->matches(QKeySequence::MoveToEndOfLine)) { 825 | if (g_posInfo.cursorPosition.nOffset < 0) { 826 | g_posInfo.cursorPosition.nOffset = 0; 827 | g_nStartOffsetDelta = 0; 828 | 829 | if (g_posInfo.cursorPosition.type != CT_ANSI) { 830 | g_posInfo.cursorPosition.type = CT_HIWORD; 831 | } 832 | } else if (g_posInfo.cursorPosition.nOffset > g_nDataSize - 1) { 833 | g_posInfo.cursorPosition.nOffset = g_nDataSize - 1; 834 | g_nStartOffsetDelta = 0; 835 | 836 | if (g_posInfo.cursorPosition.type != CT_ANSI) { 837 | g_posInfo.cursorPosition.type = CT_LOWORD; 838 | } 839 | } 840 | 841 | qint64 nRelOffset = g_posInfo.cursorPosition.nOffset - g_nStartOffset; 842 | 843 | if (nRelOffset >= g_nBytesProLine * g_nLinesProPage) { 844 | _goToOffset(g_nStartOffset + g_nBytesProLine); 845 | } else if (nRelOffset < 0) { 846 | _goToOffset(g_nStartOffset - g_nBytesProLine); 847 | } 848 | } else if (pEvent->matches(QKeySequence::MoveToNextPage) || pEvent->matches(QKeySequence::MoveToPreviousPage)) { 849 | if (g_posInfo.cursorPosition.nOffset < 0) { 850 | g_posInfo.cursorPosition.nOffset += g_nBytesProLine * g_nLinesProPage; 851 | } else if (g_posInfo.cursorPosition.nOffset > g_nDataSize - 1) { 852 | g_posInfo.cursorPosition.nOffset -= g_nBytesProLine * g_nLinesProPage; 853 | } else { 854 | if (pEvent->matches(QKeySequence::MoveToNextPage)) { 855 | _goToOffset(g_nStartOffset + g_nBytesProLine * g_nLinesProPage); 856 | } else if (pEvent->matches(QKeySequence::MoveToPreviousPage)) { 857 | _goToOffset(g_nStartOffset - g_nBytesProLine * g_nLinesProPage); 858 | } 859 | } 860 | } else if (pEvent->matches(QKeySequence::MoveToStartOfDocument)) { 861 | _goToOffset(0); 862 | } else if (pEvent->matches(QKeySequence::MoveToEndOfDocument)) { 863 | qint64 nEndPageOffset = 0; 864 | nEndPageOffset = (g_nDataSize - (g_nDataSize) % g_nBytesProLine - g_nBytesProLine * (g_nLinesProPage - 1)); 865 | 866 | if (nEndPageOffset < 0) { 867 | nEndPageOffset = 0; 868 | } 869 | 870 | _goToOffset(nEndPageOffset); 871 | } 872 | 873 | adjust(); 874 | viewport()->update(); 875 | } 876 | } else if (pEvent->matches(QKeySequence::SelectAll)) // TODO select chars 877 | { 878 | _initSelection(0); 879 | _setSelection(g_nDataSize - 1); 880 | 881 | adjust(); 882 | viewport()->update(); 883 | } else { 884 | if (!g_bReadonly) { 885 | if ((!(pEvent->modifiers() & Qt::AltModifier)) && (!(pEvent->modifiers() & Qt::ControlModifier)) && (!(pEvent->modifiers() & Qt::MetaModifier))) { 886 | quint8 nByte = 0; 887 | quint8 nChar = 0; 888 | int nKey = pEvent->key(); 889 | bool bSuccess = false; 890 | 891 | if (readByte(g_posInfo.cursorPosition.nOffset, &nByte)) { 892 | if (g_posInfo.cursorPosition.type == CT_ANSI) { 893 | if ((nKey >= Qt::Key_Space) && (nKey <= Qt::Key_AsciiTilde)) { 894 | nChar = (quint8)((unsigned char *)(pEvent->text().toLatin1().data()))[0]; 895 | bSuccess = true; 896 | } 897 | } else if ((g_posInfo.cursorPosition.type == CT_HIWORD) || (g_posInfo.cursorPosition.type == CT_LOWORD)) { 898 | if ((nKey >= Qt::Key_0) && (nKey <= Qt::Key_9)) { 899 | nChar = (quint8)(nKey - Qt::Key_0); 900 | bSuccess = true; 901 | } else if ((nKey >= Qt::Key_A) && (nKey <= Qt::Key_F)) { 902 | nChar = (quint8)(nKey - Qt::Key_A + 10); 903 | bSuccess = true; 904 | } 905 | } 906 | 907 | if (bSuccess) { 908 | if (g_posInfo.cursorPosition.type == CT_HIWORD) { 909 | nChar = (nByte & 0x0F) + (nChar << 4); 910 | } else if (g_posInfo.cursorPosition.type == CT_LOWORD) { 911 | nChar = (nByte & 0xF0) + nChar; 912 | } 913 | 914 | bool bSave = true; 915 | 916 | if (!g_bIsEdited) { 917 | // TODO Check 918 | // Save backup 919 | if (g_sBackupFileName != "") { 920 | if (!QFile::exists(g_sBackupFileName)) { 921 | if (g_pDevice->metaObject()->className() == QString("QFile")) { 922 | QString sFileName = ((QFile *)g_pDevice)->fileName(); 923 | 924 | if (!QFile::copy(sFileName, g_sBackupFileName)) { 925 | bSave = false; 926 | emit errorMessage(tr("Cannot save file") + QString(": %1").arg(g_sBackupFileName)); 927 | } 928 | } 929 | // TODO if not file/ Create file/ Write data 930 | } 931 | } 932 | } 933 | 934 | if (bSave) { 935 | if (writeByte(g_posInfo.cursorPosition.nOffset, &nChar)) { 936 | g_bIsEdited = true; 937 | 938 | emit editState(g_bIsEdited); 939 | 940 | if (g_posInfo.cursorPosition.type == CT_ANSI) { 941 | g_posInfo.cursorPosition.nOffset++; 942 | } else if (g_posInfo.cursorPosition.type == CT_HIWORD) { 943 | g_posInfo.cursorPosition.type = CT_LOWORD; 944 | } else if (g_posInfo.cursorPosition.type == CT_LOWORD) { 945 | g_posInfo.cursorPosition.nOffset++; 946 | g_posInfo.cursorPosition.type = CT_HIWORD; 947 | } 948 | 949 | if (g_posInfo.cursorPosition.nOffset > g_nDataSize - 1) { 950 | g_posInfo.cursorPosition.nOffset = g_nDataSize - 1; 951 | 952 | if (g_posInfo.cursorPosition.type != CT_ANSI) { 953 | g_posInfo.cursorPosition.type = CT_LOWORD; 954 | } 955 | } 956 | 957 | adjust(); 958 | viewport()->update(); 959 | } 960 | } 961 | } 962 | } 963 | } 964 | } 965 | 966 | QAbstractScrollArea::keyPressEvent(pEvent); 967 | } 968 | } 969 | 970 | void QHexView::wheelEvent(QWheelEvent *pEvent) 971 | { 972 | if ((g_nStartOffsetDelta) && (pEvent->angleDelta().y() > 0)) { 973 | if (verticalScrollBar()->value() == 0) { 974 | g_nStartOffsetDelta = 0; 975 | adjust(); 976 | viewport()->update(); 977 | } 978 | } 979 | 980 | QAbstractScrollArea::wheelEvent(pEvent); 981 | } 982 | --------------------------------------------------------------------------------