diff --git a/src/gui/Src/BasicView/HexDump.cpp b/src/gui/Src/BasicView/HexDump.cpp index 17c4ab97..5266d955 100644 --- a/src/gui/Src/BasicView/HexDump.cpp +++ b/src/gui/Src/BasicView/HexDump.cpp @@ -569,11 +569,12 @@ void HexDump::getColumnRichText(int col, dsint rva, RichTextPainter::List & rich } else if(mDescriptor.at(col - 1).isData == true) { + const ColumnDescriptor_t & desc = mDescriptor.at(col - 1); int wI; QString wStr = ""; - int wByteCount = getSizeOf(mDescriptor.at(col - 1).data.itemSize); - int wBufferByteCount = mDescriptor.at(col - 1).itemCount * wByteCount; + int wByteCount = getSizeOf(desc.data.itemSize); + int wBufferByteCount = desc.itemCount * wByteCount; wBufferByteCount = wBufferByteCount > (dsint)(mMemPage->getSize() - rva) ? mMemPage->getSize() - rva : wBufferByteCount; @@ -582,27 +583,41 @@ void HexDump::getColumnRichText(int col, dsint rva, RichTextPainter::List & rich mMemPage->read(wData, rva, wBufferByteCount); - QColor highlightColor = ConfigColor("HexDumpModifiedBytesColor"); - - for(wI = 0; wI < mDescriptor.at(col - 1).itemCount && (rva + wI) < (dsint)mMemPage->getSize(); wI++) + if(desc.textCodec) //convert the row bytes to unicode { - int maxLen = getStringMaxLength(mDescriptor.at(col - 1).data); - QString append = " "; - if(!maxLen) - append = ""; - if((rva + wI + wByteCount - 1) < (dsint)mMemPage->getSize()) - wStr = toString(mDescriptor.at(col - 1).data, (void*)(wData + wI * wByteCount)).rightJustified(maxLen, ' ') + append; - else - wStr = QString("?").rightJustified(maxLen, ' ') + append; - curData.text = wStr; - dsint start = rvaToVa(rva + wI * wByteCount); - dsint end = start + wByteCount - 1; - if(DbgFunctions()->PatchInRange(start, end)) - curData.textColor = highlightColor; - else - curData.textColor = textColor; + //This might produce invalid characters in variables-width encodings. This is currently ignored. + curData.text = desc.textCodec->toUnicode(QByteArray((const char*)wData, wBufferByteCount)); + curData.text.replace('\t', "\\t"); + curData.text.replace('\f', "\\f"); + curData.text.replace('\v', "\\v"); + curData.text.replace('\n', "\\n"); + curData.text.replace('\r', "\\r"); richText.push_back(curData); } + else + { + QColor highlightColor = ConfigColor("HexDumpModifiedBytesColor"); + + for(wI = 0; wI < desc.itemCount && (rva + wI) < (dsint)mMemPage->getSize(); wI++) + { + int maxLen = getStringMaxLength(mDescriptor.at(col - 1).data); + QString append = " "; + if(!maxLen) + append = ""; + if((rva + wI + wByteCount - 1) < (dsint)mMemPage->getSize()) + wStr = toString(desc.data, (void*)(wData + wI * wByteCount)).rightJustified(maxLen, ' ') + append; + else + wStr = QString("?").rightJustified(maxLen, ' ') + append; + curData.text = wStr; + dsint start = rvaToVa(rva + wI * wByteCount); + dsint end = start + wByteCount - 1; + if(DbgFunctions()->PatchInRange(start, end)) + curData.textColor = highlightColor; + else + curData.textColor = textColor; + richText.push_back(curData); + } + } delete[] wData; } diff --git a/src/gui/Src/BasicView/HexDump.h b/src/gui/Src/BasicView/HexDump.h index d844f1aa..e233ab5f 100644 --- a/src/gui/Src/BasicView/HexDump.h +++ b/src/gui/Src/BasicView/HexDump.h @@ -4,6 +4,7 @@ #include "AbstractTableView.h" #include "RichTextPainter.h" #include "MemoryPage.h" +#include class HexDump : public AbstractTableView { @@ -68,13 +69,19 @@ public: }; } DataDescriptor_t; - typedef struct _ColumnDescriptor_t + struct ColumnDescriptor_t { bool isData; int itemCount; int separator; + QTextCodec* textCodec; //name of the text codec (leave empty if you want to keep your sanity) DataDescriptor_t data; - } ColumnDescriptor_t; + + explicit ColumnDescriptor_t() + : textCodec(nullptr) + { + } + }; explicit HexDump(QWidget* parent = 0); virtual ~HexDump(); diff --git a/src/gui/Src/Gui/CPUDump.cpp b/src/gui/Src/Gui/CPUDump.cpp index f9c6e3c4..44780aab 100644 --- a/src/gui/Src/Gui/CPUDump.cpp +++ b/src/gui/Src/Gui/CPUDump.cpp @@ -11,6 +11,7 @@ #include "EntropyDialog.h" #include "CPUMultiDump.h" #include "WordEditDialog.h" +#include "CodepageSelectionDialog.h" #include CPUDump::CPUDump(CPUDisassembly* disas, CPUMultiDump* multiDump, QWidget* parent) : HexDump(parent) @@ -18,69 +19,7 @@ CPUDump::CPUDump(CPUDisassembly* disas, CPUMultiDump* multiDump, QWidget* parent mDisas = disas; mMultiDump = multiDump; - switch((ViewEnum_t)ConfigUint("HexDump", "DefaultView")) - { - case ViewHexAscii: - hexAsciiSlot(); - break; - case ViewHexUnicode: - hexUnicodeSlot(); - break; - case ViewTextAscii: - textAsciiSlot(); - break; - case ViewTextUnicode: - textUnicodeSlot(); - break; - case ViewIntegerSignedShort: - integerSignedShortSlot(); - break; - case ViewIntegerSignedLong: - integerSignedLongSlot(); - break; -#ifdef _WIN64 - case ViewIntegerSignedLongLong: - integerSignedLongLongSlot(); - break; -#endif //_WIN64 - case ViewIntegerUnsignedShort: - integerUnsignedShortSlot(); - break; - case ViewIntegerUnsignedLong: - integerUnsignedLongSlot(); - break; -#ifdef _WIN64 - case ViewIntegerUnsignedLongLong: - integerUnsignedLongLongSlot(); - break; -#endif //_WIN64 - case ViewIntegerHexShort: - integerHexShortSlot(); - break; - case ViewIntegerHexLong: - integerHexLongSlot(); - break; -#ifdef _WIN64 - case ViewIntegerHexLongLong: - integerHexLongLongSlot(); - break; -#endif //_WIN64 - case ViewFloatFloat: - floatFloatSlot(); - break; - case ViewFloatDouble: - floatDoubleSlot(); - break; - case ViewFloatLongDouble: - floatLongDoubleSlot(); - break; - case ViewAddress: - addressSlot(); - break; - default: - hexAsciiSlot(); - break; - } + setView((ViewEnum_t)ConfigUint("HexDump", "DefaultView")); connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot())); @@ -362,25 +301,33 @@ void CPUDump::setupContextMenu() mHexMenu = new QMenu(tr("&Hex"), this); mHexMenu->setIcon(QIcon(":/icons/images/hex.png")); //Hex->Ascii - mHexAsciiAction = new QAction("&Ascii", this); + mHexAsciiAction = new QAction("&ASCII", this); connect(mHexAsciiAction, SIGNAL(triggered()), this, SLOT(hexAsciiSlot())); mHexMenu->addAction(mHexAsciiAction); //Hex->Unicode - mHexUnicodeAction = new QAction(tr("&Unicode"), this); + mHexUnicodeAction = new QAction(tr("&UTF-16"), this); connect(mHexUnicodeAction, SIGNAL(triggered()), this, SLOT(hexUnicodeSlot())); mHexMenu->addAction(mHexUnicodeAction); + //Hex->Codepage + mHexCodepageAction = new QAction(tr("&Codepage..."), this); + connect(mHexCodepageAction, SIGNAL(triggered()), this, SLOT(hexCodepageSlot())); + mHexMenu->addAction(mHexCodepageAction); //Text menu mTextMenu = new QMenu(tr("&Text"), this); mTextMenu->setIcon(QIcon(":/icons/images/strings.png")); //Text->Ascii - mTextAsciiAction = new QAction(tr("&Ascii"), this); + mTextAsciiAction = new QAction(tr("&ASCII"), this); connect(mTextAsciiAction, SIGNAL(triggered()), this, SLOT(textAsciiSlot())); mTextMenu->addAction(mTextAsciiAction); //Text->Unicode - mTextUnicodeAction = new QAction(tr("&Unicode"), this); + mTextUnicodeAction = new QAction(tr("&UTF-16"), this); connect(mTextUnicodeAction, SIGNAL(triggered()), this, SLOT(textUnicodeSlot())); mTextMenu->addAction(mTextUnicodeAction); + //Hex->Codepage + mTextCodepageAction = new QAction(tr("&Codepage..."), this); + connect(mTextCodepageAction, SIGNAL(triggered()), this, SLOT(textCodepageSlot())); + mTextMenu->addAction(mTextCodepageAction); //Integer menu mIntegerMenu = new QMenu(tr("&Integer"), this); @@ -393,12 +340,10 @@ void CPUDump::setupContextMenu() mIntegerSignedLongAction = new QAction("Signed long (32-bit)", this); connect(mIntegerSignedLongAction, SIGNAL(triggered()), this, SLOT(integerSignedLongSlot())); mIntegerMenu->addAction(mIntegerSignedLongAction); -#ifdef _WIN64 //Integer->Signed long long mIntegerSignedLongLongAction = new QAction("Signed long long (64-bit)", this); connect(mIntegerSignedLongLongAction, SIGNAL(triggered()), this, SLOT(integerSignedLongLongSlot())); mIntegerMenu->addAction(mIntegerSignedLongLongAction); -#endif //_WIN64 //Integer->Unsigned short mIntegerUnsignedShortAction = new QAction("Unsigned short (16-bit)", this); connect(mIntegerUnsignedShortAction, SIGNAL(triggered()), this, SLOT(integerUnsignedShortSlot())); @@ -407,12 +352,10 @@ void CPUDump::setupContextMenu() mIntegerUnsignedLongAction = new QAction("Unsigned long (32-bit)", this); connect(mIntegerUnsignedLongAction, SIGNAL(triggered()), this, SLOT(integerUnsignedLongSlot())); mIntegerMenu->addAction(mIntegerUnsignedLongAction); -#ifdef _WIN64 //Integer->Unsigned long long mIntegerUnsignedLongLongAction = new QAction("Unsigned long long (64-bit)", this); connect(mIntegerUnsignedLongLongAction, SIGNAL(triggered()), this, SLOT(integerUnsignedLongLongSlot())); mIntegerMenu->addAction(mIntegerUnsignedLongLongAction); -#endif //_WIN64 //Integer->Hex short mIntegerHexShortAction = new QAction("Hex short (16-bit)", this); connect(mIntegerHexShortAction, SIGNAL(triggered()), this, SLOT(integerHexShortSlot())); @@ -421,12 +364,10 @@ void CPUDump::setupContextMenu() mIntegerHexLongAction = new QAction("Hex long (32-bit)", this); connect(mIntegerHexLongAction, SIGNAL(triggered()), this, SLOT(integerHexLongSlot())); mIntegerMenu->addAction(mIntegerHexLongAction); -#ifdef _WIN64 //Integer->Hex long long mIntegerHexLongLongAction = new QAction("Hex long long (64-bit)", this); connect(mIntegerHexLongLongAction, SIGNAL(triggered()), this, SLOT(integerHexLongLongSlot())); mIntegerMenu->addAction(mIntegerHexLongLongAction); -#endif //_WIN64 //Float menu mFloatMenu = new QMenu(tr("&Float"), this); @@ -892,6 +833,36 @@ void CPUDump::hexUnicodeSlot() reloadData(); } +void CPUDump::hexCodepageSlot() +{ + CodepageSelectionDialog dialog(this); + if(dialog.exec() != QDialog::Accepted) + return; + + int charwidth = getCharWidth(); + ColumnDescriptor_t wColDesc; + DataDescriptor_t dDesc; + + wColDesc.isData = true; //hex byte + wColDesc.itemCount = 16; + wColDesc.separator = 4; + dDesc.itemSize = Byte; + dDesc.byteMode = HexByte; + wColDesc.data = dDesc; + appendResetDescriptor(8 + charwidth * 47, tr("Hex"), false, wColDesc); + + wColDesc.isData = true; //text (in code page) + wColDesc.itemCount = 16; + wColDesc.separator = 0; + wColDesc.textCodec = QTextCodec::codecForName(dialog.getSelectedCodepage()); + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, dialog.getSelectedCodepage(), false, wColDesc); + + reloadData(); +} + void CPUDump::textAsciiSlot() { Config()->setUint("HexDump", "DefaultView", (duint)ViewTextAscii); @@ -944,6 +915,27 @@ void CPUDump::textUnicodeSlot() reloadData(); } +void CPUDump::textCodepageSlot() +{ + CodepageSelectionDialog dialog(this); + if(dialog.exec() != QDialog::Accepted) + return; + + ColumnDescriptor_t wColDesc; + DataDescriptor_t dDesc; + + wColDesc.isData = true; //text (in code page) + wColDesc.itemCount = 64; + wColDesc.separator = 0; + wColDesc.textCodec = QTextCodec::codecForName(dialog.getSelectedCodepage()); + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendResetDescriptor(0, dialog.getSelectedCodepage(), false, wColDesc); + + reloadData(); +} + void CPUDump::integerSignedShortSlot() { Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerSignedShort); @@ -1656,3 +1648,63 @@ void CPUDump::gotoPrevSlot() historyPrev(); } +void CPUDump::setView(ViewEnum_t view) +{ + switch(view) + { + case ViewHexAscii: + hexAsciiSlot(); + break; + case ViewHexUnicode: + hexUnicodeSlot(); + break; + case ViewTextAscii: + textAsciiSlot(); + break; + case ViewTextUnicode: + textUnicodeSlot(); + break; + case ViewIntegerSignedShort: + integerSignedShortSlot(); + break; + case ViewIntegerSignedLong: + integerSignedLongSlot(); + break; + case ViewIntegerSignedLongLong: + integerSignedLongLongSlot(); + break; + case ViewIntegerUnsignedShort: + integerUnsignedShortSlot(); + break; + case ViewIntegerUnsignedLong: + integerUnsignedLongSlot(); + break; + case ViewIntegerUnsignedLongLong: + integerUnsignedLongLongSlot(); + break; + case ViewIntegerHexShort: + integerHexShortSlot(); + break; + case ViewIntegerHexLong: + integerHexLongSlot(); + break; + case ViewIntegerHexLongLong: + integerHexLongLongSlot(); + break; + case ViewFloatFloat: + floatFloatSlot(); + break; + case ViewFloatDouble: + floatDoubleSlot(); + break; + case ViewFloatLongDouble: + floatLongDoubleSlot(); + break; + case ViewAddress: + addressSlot(); + break; + default: + hexAsciiSlot(); + break; + } +} diff --git a/src/gui/Src/Gui/CPUDump.h b/src/gui/Src/Gui/CPUDump.h index d3d37a07..641554ad 100644 --- a/src/gui/Src/Gui/CPUDump.h +++ b/src/gui/Src/Gui/CPUDump.h @@ -52,9 +52,11 @@ public slots: void hexAsciiSlot(); void hexUnicodeSlot(); + void hexCodepageSlot(); void textAsciiSlot(); void textUnicodeSlot(); + void textCodepageSlot(); void integerSignedShortSlot(); void integerSignedLongSlot(); @@ -145,10 +147,12 @@ private: QMenu* mHexMenu; QAction* mHexAsciiAction; QAction* mHexUnicodeAction; + QAction* mHexCodepageAction; QMenu* mTextMenu; QAction* mTextAsciiAction; QAction* mTextUnicodeAction; + QAction* mTextCodepageAction; QMenu* mIntegerMenu; QAction* mIntegerSignedShortAction; @@ -224,6 +228,8 @@ private: ViewFloatLongDouble, ViewAddress }; + + void setView(ViewEnum_t view); }; #endif // CPUDUMP_H diff --git a/src/gui/Src/Gui/CodepageSelectionDialog.cpp b/src/gui/Src/Gui/CodepageSelectionDialog.cpp new file mode 100644 index 00000000..128a2137 --- /dev/null +++ b/src/gui/Src/Gui/CodepageSelectionDialog.cpp @@ -0,0 +1,33 @@ +#include "CodepageSelectionDialog.h" +#include "ui_CodepageSelectionDialog.h" +#include + +CodepageSelectionDialog::CodepageSelectionDialog(QWidget* parent) : + QDialog(parent), + ui(new Ui::CodepageSelectionDialog) +{ + ui->setupUi(this); + setModal(true); + setFixedSize(this->size()); //fixed size + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::MSWindowsFixedSizeDialogHint); + setWindowIcon(QIcon(":/icons/images/codepage.png")); + for(auto & name : QTextCodec::availableCodecs()) + { + auto codec = QTextCodec::codecForName(name); + if(!codec) + continue; + ui->listCodepages->addItem(name); + mCodepages.append(codec->name()); + } + ui->listCodepages->setCurrentRow(0); +} + +CodepageSelectionDialog::~CodepageSelectionDialog() +{ + delete ui; +} + +QByteArray CodepageSelectionDialog::getSelectedCodepage() +{ + return mCodepages[ui->listCodepages->currentRow()]; +} diff --git a/src/gui/Src/Gui/CodepageSelectionDialog.h b/src/gui/Src/Gui/CodepageSelectionDialog.h new file mode 100644 index 00000000..144d284d --- /dev/null +++ b/src/gui/Src/Gui/CodepageSelectionDialog.h @@ -0,0 +1,25 @@ +#ifndef CODEPAGESELECTIONDIALOG_H +#define CODEPAGESELECTIONDIALOG_H + +#include + +namespace Ui +{ + class CodepageSelectionDialog; +} + +class CodepageSelectionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CodepageSelectionDialog(QWidget* parent = 0); + ~CodepageSelectionDialog(); + QByteArray getSelectedCodepage(); + +private: + Ui::CodepageSelectionDialog* ui; + QList mCodepages; +}; + +#endif // CODEPAGESELECTIONDIALOG_H diff --git a/src/gui/Src/Gui/CodepageSelectionDialog.ui b/src/gui/Src/Gui/CodepageSelectionDialog.ui new file mode 100644 index 00000000..73ce0aa7 --- /dev/null +++ b/src/gui/Src/Gui/CodepageSelectionDialog.ui @@ -0,0 +1,91 @@ + + + CodepageSelectionDialog + + + + 0 + 0 + 396 + 300 + + + + Select Codepage... + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &OK + + + true + + + + + + + &Cancel + + + + + + + + + + + buttonOk + clicked() + CodepageSelectionDialog + accept() + + + 257 + 280 + + + 204 + 273 + + + + + buttonCancel + clicked() + CodepageSelectionDialog + reject() + + + 340 + 283 + + + 93 + 279 + + + + + diff --git a/src/gui/images/codepage.png b/src/gui/images/codepage.png new file mode 100644 index 00000000..eaf23635 Binary files /dev/null and b/src/gui/images/codepage.png differ diff --git a/src/gui/resource.qrc b/src/gui/resource.qrc index 428336f5..893ab014 100644 --- a/src/gui/resource.qrc +++ b/src/gui/resource.qrc @@ -98,5 +98,6 @@ images/dump.png images/analyzesinglefunction.png images/xrefs.png + images/codepage.png diff --git a/src/gui/x64dbg.pro b/src/gui/x64dbg.pro index ae5d04b8..4ef8ab29 100644 --- a/src/gui/x64dbg.pro +++ b/src/gui/x64dbg.pro @@ -152,7 +152,8 @@ SOURCES += \ Src/Utils/HexValidator.cpp \ Src/Utils/LongLongValidator.cpp \ Src/Utils/MiscUtil.cpp \ - Src/Gui/XrefBrowseDialog.cpp + Src/Gui/XrefBrowseDialog.cpp \ + Src/Gui/CodepageSelectionDialog.cpp HEADERS += \ @@ -245,7 +246,8 @@ HEADERS += \ Src/Utils/HexValidator.h \ Src/Utils/LongLongValidator.h \ Src/Utils/MiscUtil.h \ - Src/Gui/XrefBrowseDialog.h + Src/Gui/XrefBrowseDialog.h \ + Src/Gui/CodepageSelectionDialog.h FORMS += \ Src/Gui/MainWindow.ui \ @@ -275,7 +277,8 @@ FORMS += \ Src/Gui/EditBreakpointDialog.ui \ Src/Gui/CPUArgumentWidget.ui \ Src/Gui/EditFloatRegister.ui \ - Src/Gui/XrefBrowseDialog.ui + Src/Gui/XrefBrowseDialog.ui \ + Src/Gui/CodepageSelectionDialog.ui TRANSLATIONS = \ Translations/x64dbg_zh_CN.ts