From 52968d60fc01597cf7bf12a10eb0750e3c80c3e4 Mon Sep 17 00:00:00 2001 From: Peter Rybicki Date: Thu, 23 Nov 2017 17:15:13 +0100 Subject: [PATCH 1/5] Add more representations of unprintable bytes *) Convert byte to pretty unicode representation *) Create gui options of default unprintable characters rendering *) Save unprintable mode default settings *) Add icon to view toolbar *) Add instant unprintable mode changing --- include/ui/hexedit.h | 9 ++- include/ui/hexeditwidget.h | 2 + include/util/settings/hexedit.h | 4 ++ src/ui/hexedit.cc | 67 ++++++++++++++++++----- src/ui/hexeditwidget.cc | 24 ++++++++ src/ui/optionsdialog.cc | 9 +++ src/ui/optionsdialog.ui | 97 ++++++++++++++++++++++----------- src/util/settings/hexedit.cc | 10 ++++ 8 files changed, 174 insertions(+), 48 deletions(-) diff --git a/include/ui/hexedit.h b/include/ui/hexedit.h index 4845568e..2022cdf0 100644 --- a/include/ui/hexedit.h +++ b/include/ui/hexedit.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "ui/createchunkdialog.h" #include "ui/fileblobmodel.h" @@ -71,6 +72,7 @@ class HexEdit : public QAbstractScrollArea { void applyChanges(); void undo(); void discardChanges(); + void setUnprintablesMode(QAction* action); protected: void paintEvent(QPaintEvent* event) override; @@ -177,6 +179,8 @@ class HexEdit : public QAbstractScrollArea { QScopedPointer textEncoder_; util::EditEngine edit_engine_; + QString unprintablesModeString; + void recalculateValues(); void initParseMenu(); void adjustBytesPerRowToWindowSize(); @@ -188,7 +192,10 @@ class HexEdit : public QAbstractScrollArea { WindowArea pointToWindowArea(QPoint pos); QString addressAsText(qint64 pos); QString hexRepresentationFromByte(uint64_t byte_val); - static QString asciiRepresentationFromByte(uint64_t byte_val); + + QString asciiRepresentationFromByte(uint64_t byte_val); + void updateAsciiCache(); + void updateHexCache(); static QColor byteTextColorFromByteValue(uint64_t byte_val); QColor byteBackroundColorFromPos(qint64 pos, bool modified); diff --git a/include/ui/hexeditwidget.h b/include/ui/hexeditwidget.h index fc7a1b08..82602420 100644 --- a/include/ui/hexeditwidget.h +++ b/include/ui/hexeditwidget.h @@ -92,6 +92,7 @@ class HexEditWidget : public View { void createActions(); void createToolBars(); void initParsersMenu(); + void initUnprintablesMenu(); void createSelectionInfo(); MainWindowWithDetachableDockWidgets* main_window_; @@ -127,6 +128,7 @@ class HexEditWidget : public View { QStringList parsers_ids_; QMenu parsers_menu_; + QMenu unprintables_menu_; QLabel* selection_label_; }; diff --git a/include/util/settings/hexedit.h b/include/util/settings/hexedit.h index 54f48c81..ca4e1223 100644 --- a/include/util/settings/hexedit.h +++ b/include/util/settings/hexedit.h @@ -16,6 +16,8 @@ */ #pragma once +#include + namespace veles { namespace util { namespace settings { @@ -25,6 +27,8 @@ int columnsNumber(); void setColumnsNumber(int number); bool resizeColumnsToWindowWidth(); void setResizeColumnsToWindowWidth(bool on); +QString unprintablesModes(); +void setUnprintablesMode(QString mode); } // namespace hexedit } // namespace settings diff --git a/src/ui/hexedit.cc b/src/ui/hexedit.cc index a9e3a5ca..023157fb 100644 --- a/src/ui/hexedit.cc +++ b/src/ui/hexedit.cc @@ -29,8 +29,11 @@ #include "util/encoders/factory.h" #include "util/misc.h" #include "util/random.h" +#include "util/settings/hexedit.h" #include "util/settings/theme.h" +#include + using veles::util::misc::array_size; namespace veles { @@ -142,16 +145,9 @@ HexEdit::HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel, recalculateValues(); // Initialize hex & ASCII text cache. - for (size_t i = 0; i < array_size(hex_text_cache_); i++) { - hex_text_cache_[i].setPerformanceHint(QStaticText::ModerateCaching); - hex_text_cache_[i].setText(hexRepresentationFromByte(i)); - hex_text_cache_[i].setTextFormat(Qt::PlainText); - } - for (size_t i = 0; i < array_size(ascii_text_cache_); i++) { - ascii_text_cache_[i].setPerformanceHint(QStaticText::ModerateCaching); - ascii_text_cache_[i].setText(asciiRepresentationFromByte(i)); - ascii_text_cache_[i].setTextFormat(Qt::PlainText); - } + unprintablesModeString = util::settings::hexedit::unprintablesModes(); + updateAsciiCache(); + updateHexCache(); connect(verticalScrollBar(), &QAbstractSlider::valueChanged, this, &HexEdit::recalculateValues); @@ -475,6 +471,21 @@ HexEdit::HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel, }); } +void HexEdit::updateAsciiCache() { + for (size_t i = 0; i < array_size(ascii_text_cache_); i++) { + ascii_text_cache_[i].setPerformanceHint(QStaticText::ModerateCaching); + ascii_text_cache_[i].setText(asciiRepresentationFromByte(i)); + ascii_text_cache_[i].setTextFormat(Qt::PlainText); + } +} + +void HexEdit::updateHexCache() { + for (size_t i = 0; i < array_size(hex_text_cache_); i++) { + hex_text_cache_[i].setPerformanceHint(QStaticText::ModerateCaching); + hex_text_cache_[i].setText(hexRepresentationFromByte(i)); + hex_text_cache_[i].setTextFormat(Qt::PlainText); + } +} QModelIndex HexEdit::selectedChunk() { if (chunkSelectionModel_ == nullptr) { return {}; @@ -609,6 +620,12 @@ void HexEdit::discardChanges() { viewport()->update(); } +void HexEdit::setUnprintablesMode(QAction* action) { + unprintablesModeString = action->text(); + updateAsciiCache(); + viewport()->update(); +} + qint64 HexEdit::selectionStart() { if (selection_size_ < 0) { return current_position_ + selection_size_ + 1; @@ -643,10 +660,32 @@ QString HexEdit::addressAsText(qint64 pos) { } QString HexEdit::asciiRepresentationFromByte(uint64_t byte_val) { - if (byte_val >= 0x20 && byte_val < 0x7f) { - return QChar::fromLatin1(byte_val); + static QTextCodec* windows1250 = QTextCodec::codecForName("windows-1250"); + + if (unprintablesModeString.compare("windows-1250") == 0) { + // 0x85 is NEL, 0xa0 is nbsp in unicode, but we want to display them + // 0x83, ..., 0x98 are undefined in used codeing + if (byte_val != 0x85 && byte_val != 0xa0 && + (QChar(static_cast(byte_val)).isSpace() || + QChar(static_cast(byte_val)).isNull() || byte_val == 0x83 || + byte_val == 0x88 || byte_val == 0x90 || byte_val == 0x98)) { + return QChar(static_cast(' ')); + } + + // printable ascii chars + if (byte_val >= 0x20 && byte_val < 0x7f) { + return QChar::fromLatin1(byte_val); + } + + // ascii-unprintable chars + char a = (static_cast(byte_val)); + return byte_val >= 0x7f + ? windows1250->toUnicode(&a, 1) + : QChar(static_cast(byte_val) + 0x180); // greek } - return "."; + // dots fallback + return (byte_val >= 0x20 && byte_val < 0x7f) ? QChar::fromLatin1(byte_val) + : QString("."); } QColor HexEdit::byteTextColorFromByteValue(uint64_t byte_val) { @@ -814,7 +853,7 @@ void HexEdit::paintEvent(QPaintEvent* event) { auto bgc = byteBackroundColorFromPos( byte_idx, modified_positions[byte_idx - start_byte]); bool redraw_hex = invalidated_rect.intersects(hex_rect); - bool redraw_ascii = invalidated_rect.intersects(ascii_rect); + bool redraw_ascii = true; // invalidated_rect.intersects(ascii_rect); if (redraw_hex && bgc.isValid()) { painter.fillRect(hex_rect, bgc); } diff --git a/src/ui/hexeditwidget.cc b/src/ui/hexeditwidget.cc index c6b1f001..82eac094 100644 --- a/src/ui/hexeditwidget.cc +++ b/src/ui/hexeditwidget.cc @@ -84,6 +84,11 @@ HexEditWidget::HexEditWidget( setParserIds(dynamic_cast( MainWindowWithDetachableDockWidgets::getFirstMainWindow()) ->parsersList()); + + initUnprintablesMenu(); + connect(&unprintables_menu_, &QMenu::triggered, hex_edit_, + &HexEdit::setUnprintablesMode); + selectionChanged(0, 0); } @@ -282,6 +287,18 @@ void HexEditWidget::createToolBars() { addToolBar(edit_tool_bar_); view_tool_bar_ = new QToolBar(tr("View")); + + auto unprintables_tool_button = new QToolButton(); + unprintables_tool_button->setMenu(&unprintables_menu_); + unprintables_tool_button->setPopupMode(QToolButton::InstantPopup); + unprintables_tool_button->setIcon(QIcon(":/images/brightness.png")); + unprintables_tool_button->setText(tr("&Unprintables")); + unprintables_tool_button->setToolTip(tr("Appearance of unprintable bytes")); + unprintables_tool_button->setAutoRaise(true); + auto unprintables_widget_action = new QWidgetAction(view_tool_bar_); + unprintables_widget_action->setDefaultWidget(unprintables_tool_button); + + view_tool_bar_->addAction(unprintables_widget_action); view_tool_bar_->addAction(remove_column_act_); view_tool_bar_->addAction(add_column_act_); view_tool_bar_->addSeparator(); @@ -302,6 +319,13 @@ void HexEditWidget::initParsersMenu() { } } +void HexEditWidget::initUnprintablesMenu() { + unprintables_menu_.clear(); + unprintables_menu_.addAction("dots"); + unprintables_menu_.addSeparator(); + unprintables_menu_.addAction("windows-1250"); +} + void HexEditWidget::createSelectionInfo() { auto* widget_action = new QWidgetAction(this); auto* selection_panel = new QWidget; diff --git a/src/ui/optionsdialog.cc b/src/ui/optionsdialog.cc index 4a8f6b73..5160effd 100644 --- a/src/ui/optionsdialog.cc +++ b/src/ui/optionsdialog.cc @@ -47,6 +47,10 @@ void OptionsDialog::show() { ui->hexColumnsAutoCheckBox->setCheckState(checkState); ui->hexColumnsSpinBox->setValue(util::settings::hexedit::columnsNumber()); ui->hexColumnsSpinBox->setEnabled(checkState != Qt::Checked); + ui->unprintablesModeDots->setChecked( + util::settings::hexedit::unprintablesModes() == "dots"); + ui->unprintablesModeWindows1250->setChecked( + util::settings::hexedit::unprintablesModes() == "windows-1250"); QWidget::show(); } @@ -63,6 +67,11 @@ void OptionsDialog::accept() { ui->hexColumnsAutoCheckBox->checkState() == Qt::Checked); util::settings::hexedit::setColumnsNumber(ui->hexColumnsSpinBox->value()); + if (ui->unprintablesModeDots->isChecked()) + util::settings::hexedit::setUnprintablesMode("dots"); + if (ui->unprintablesModeWindows1250->isChecked()) + util::settings::hexedit::setUnprintablesMode("windows-1250"); + if (restart_needed) { QMessageBox::about( this, tr("Options change"), diff --git a/src/ui/optionsdialog.ui b/src/ui/optionsdialog.ui index c4d38321..a7106986 100644 --- a/src/ui/optionsdialog.ui +++ b/src/ui/optionsdialog.ui @@ -6,8 +6,8 @@ 0 0 - 259 - 229 + 337 + 296 @@ -49,42 +49,73 @@ HexEdit defaults - - - + + + - + - Columns + Windows-1250 + + + + - - - - - 1 - - - 1024 - - - 16 - - - - - - - Resize to window width - - - - + + + 1 + + + 1024 + + + 16 + + + + + + + Resize to window width + + + + + + Columns + + + + + + + Qt::Horizontal + + + + + + + Dots + + + + + + + Unprintable characters + + + true + + + @@ -112,8 +143,8 @@ reject() - 290 - 160 + 299 + 286 286 @@ -128,8 +159,8 @@ accept() - 222 - 154 + 231 + 286 157 diff --git a/src/util/settings/hexedit.cc b/src/util/settings/hexedit.cc index 2d7a95fc..a2d9c1ca 100644 --- a/src/util/settings/hexedit.cc +++ b/src/util/settings/hexedit.cc @@ -43,6 +43,16 @@ void setResizeColumnsToWindowWidth(bool on) { settings.setValue("hexedit.resizeColumnsToWindowWidth", on); } +QString unprintablesModes() { + QSettings settings; + return settings.value("hexedit.unprintablesMode", "dots").toString(); +} + +void setUnprintablesMode(QString mode) { + QSettings settings; + settings.setValue("hexedit.unprintablesMode", mode); +} + } // namespace hexedit } // namespace settings } // namespace util From 51561bb85a77fee3d19dba9e568b7ac5e9e0e597 Mon Sep 17 00:00:00 2001 From: Peter Rybicki Date: Wed, 6 Dec 2017 16:46:06 +0100 Subject: [PATCH 2/5] Review fixup: minor issues (wip) --- include/ui/hexedit.h | 4 +- include/util/misc.h | 2 + include/util/settings/hexedit.h | 4 +- src/ui/hexedit.cc | 91 +++++++++++++++++++-------------- src/ui/hexeditwidget.cc | 6 +-- src/ui/optionsdialog.cc | 11 ++-- src/util/misc.cc | 19 ++++++- src/util/settings/hexedit.cc | 6 +-- 8 files changed, 91 insertions(+), 52 deletions(-) diff --git a/include/ui/hexedit.h b/include/ui/hexedit.h index 2022cdf0..a91789d1 100644 --- a/include/ui/hexedit.h +++ b/include/ui/hexedit.h @@ -64,6 +64,7 @@ class HexEdit : public QAbstractScrollArea { in_insert_mode_ = in_insert_mode; } void saveToFile(const QString& file_name); + std::vector getListOfUnprintablesModes(); public slots: void newBinData(); @@ -179,7 +180,8 @@ class HexEdit : public QAbstractScrollArea { QScopedPointer textEncoder_; util::EditEngine edit_engine_; - QString unprintablesModeString; + QString unprintables_mode_string_; + QTextCodec* windows1250_codec_; void recalculateValues(); void initParseMenu(); diff --git a/include/util/misc.h b/include/util/misc.h index 72455d62..60c84a26 100644 --- a/include/util/misc.h +++ b/include/util/misc.h @@ -26,6 +26,8 @@ inline size_t array_size(T (&/*arr*/)[SIZE]) { return SIZE; } +char ucharToChar(unsigned char value); + } // namespace misc } // namespace util } // namespace veles diff --git a/include/util/settings/hexedit.h b/include/util/settings/hexedit.h index ca4e1223..68984983 100644 --- a/include/util/settings/hexedit.h +++ b/include/util/settings/hexedit.h @@ -27,8 +27,8 @@ int columnsNumber(); void setColumnsNumber(int number); bool resizeColumnsToWindowWidth(); void setResizeColumnsToWindowWidth(bool on); -QString unprintablesModes(); -void setUnprintablesMode(QString mode); +QString unprintablesMode(); +void setUnprintablesMode(const QString& mode); } // namespace hexedit } // namespace settings diff --git a/src/ui/hexedit.cc b/src/ui/hexedit.cc index 023157fb..9745e4d9 100644 --- a/src/ui/hexedit.cc +++ b/src/ui/hexedit.cc @@ -32,8 +32,6 @@ #include "util/settings/hexedit.h" #include "util/settings/theme.h" -#include - using veles::util::misc::array_size; namespace veles { @@ -130,7 +128,9 @@ HexEdit::HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel, cursor_pos_in_byte_(0), cursor_visible_(false), in_insert_mode_(false), - edit_engine_(dataModel_) { + edit_engine_(dataModel_), + windows1250_codec_(QTextCodec::codecForName("windows-1250")) { + // TODO Add log warning if codec is unavailable (== nullptr) auto font = util::settings::theme::font(); setFont(font); @@ -145,7 +145,7 @@ HexEdit::HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel, recalculateValues(); // Initialize hex & ASCII text cache. - unprintablesModeString = util::settings::hexedit::unprintablesModes(); + unprintables_mode_string_ = util::settings::hexedit::unprintablesMode(); updateAsciiCache(); updateHexCache(); @@ -471,21 +471,6 @@ HexEdit::HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel, }); } -void HexEdit::updateAsciiCache() { - for (size_t i = 0; i < array_size(ascii_text_cache_); i++) { - ascii_text_cache_[i].setPerformanceHint(QStaticText::ModerateCaching); - ascii_text_cache_[i].setText(asciiRepresentationFromByte(i)); - ascii_text_cache_[i].setTextFormat(Qt::PlainText); - } -} - -void HexEdit::updateHexCache() { - for (size_t i = 0; i < array_size(hex_text_cache_); i++) { - hex_text_cache_[i].setPerformanceHint(QStaticText::ModerateCaching); - hex_text_cache_[i].setText(hexRepresentationFromByte(i)); - hex_text_cache_[i].setTextFormat(Qt::PlainText); - } -} QModelIndex HexEdit::selectedChunk() { if (chunkSelectionModel_ == nullptr) { return {}; @@ -613,6 +598,15 @@ void HexEdit::saveToFile(const QString& file_name) { saveDataToFile(0, edit_engine_.dataSize(), file_name); } +std::vector HexEdit::getListOfUnprintablesModes() { + std::vector modes; + modes.push_back("Dots"); + if (windows1250_codec_ != nullptr) { + modes.push_back("Windows-1250"); + } + return modes; +} + void HexEdit::discardChanges() { edit_engine_.clear(); recalculateValues(); @@ -621,7 +615,7 @@ void HexEdit::discardChanges() { } void HexEdit::setUnprintablesMode(QAction* action) { - unprintablesModeString = action->text(); + unprintables_mode_string_ = action->text(); updateAsciiCache(); viewport()->update(); } @@ -660,34 +654,55 @@ QString HexEdit::addressAsText(qint64 pos) { } QString HexEdit::asciiRepresentationFromByte(uint64_t byte_val) { - static QTextCodec* windows1250 = QTextCodec::codecForName("windows-1250"); - - if (unprintablesModeString.compare("windows-1250") == 0) { - // 0x85 is NEL, 0xa0 is nbsp in unicode, but we want to display them - // 0x83, ..., 0x98 are undefined in used codeing - if (byte_val != 0x85 && byte_val != 0xa0 && - (QChar(static_cast(byte_val)).isSpace() || - QChar(static_cast(byte_val)).isNull() || byte_val == 0x83 || - byte_val == 0x88 || byte_val == 0x90 || byte_val == 0x98)) { - return QChar(static_cast(' ')); + if (byte_val > 0xff) { + return "."; + } + if (windows1250_codec_ != nullptr && + unprintables_mode_string_.compare("Windows-1250") == 0) { + char a = veles::util::misc::ucharToChar(byte_val); + QChar unicode_repr = windows1250_codec_->toUnicode(&a, 1).at(0); + + bool is_undefined_windows1250 = byte_val == 0x81 || byte_val == 0x83 || + byte_val == 0x88 || byte_val == 0x90 || + byte_val == 0x98; + + bool is_whitespace = unicode_repr.isSpace() || unicode_repr.isNull(); + + if (is_whitespace || is_undefined_windows1250) { + return " "; } - // printable ascii chars + // printable ASCII chars if (byte_val >= 0x20 && byte_val < 0x7f) { return QChar::fromLatin1(byte_val); } - // ascii-unprintable chars - char a = (static_cast(byte_val)); - return byte_val >= 0x7f - ? windows1250->toUnicode(&a, 1) - : QChar(static_cast(byte_val) + 0x180); // greek + // unprintable ASCII chars + return byte_val >= 0x7f ? windows1250_codec_->toUnicode(&a, 1) + : QChar(static_cast(byte_val) + + 0x180); // greek for < 0x20 } - // dots fallback + // dots mode return (byte_val >= 0x20 && byte_val < 0x7f) ? QChar::fromLatin1(byte_val) : QString("."); } +void HexEdit::updateAsciiCache() { + for (size_t i = 0; i < array_size(ascii_text_cache_); i++) { + ascii_text_cache_[i].setPerformanceHint(QStaticText::ModerateCaching); + ascii_text_cache_[i].setText(asciiRepresentationFromByte(i)); + ascii_text_cache_[i].setTextFormat(Qt::PlainText); + } +} + +void HexEdit::updateHexCache() { + for (size_t i = 0; i < array_size(hex_text_cache_); i++) { + hex_text_cache_[i].setPerformanceHint(QStaticText::ModerateCaching); + hex_text_cache_[i].setText(hexRepresentationFromByte(i)); + hex_text_cache_[i].setTextFormat(Qt::PlainText); + } +} + QColor HexEdit::byteTextColorFromByteValue(uint64_t byte_val) { // TODO(mkow): better support for non 8 bit bytes. return util::settings::theme::byteColor(byte_val & 0xff); @@ -853,7 +868,7 @@ void HexEdit::paintEvent(QPaintEvent* event) { auto bgc = byteBackroundColorFromPos( byte_idx, modified_positions[byte_idx - start_byte]); bool redraw_hex = invalidated_rect.intersects(hex_rect); - bool redraw_ascii = true; // invalidated_rect.intersects(ascii_rect); + bool redraw_ascii = invalidated_rect.intersects(ascii_rect); if (redraw_hex && bgc.isValid()) { painter.fillRect(hex_rect, bgc); } diff --git a/src/ui/hexeditwidget.cc b/src/ui/hexeditwidget.cc index 82eac094..f5c3d3f4 100644 --- a/src/ui/hexeditwidget.cc +++ b/src/ui/hexeditwidget.cc @@ -321,9 +321,9 @@ void HexEditWidget::initParsersMenu() { void HexEditWidget::initUnprintablesMenu() { unprintables_menu_.clear(); - unprintables_menu_.addAction("dots"); - unprintables_menu_.addSeparator(); - unprintables_menu_.addAction("windows-1250"); + for (auto& mode : hex_edit_->getListOfUnprintablesModes()) { + unprintables_menu_.addAction(mode); + } } void HexEditWidget::createSelectionInfo() { diff --git a/src/ui/optionsdialog.cc b/src/ui/optionsdialog.cc index 5160effd..73d339cd 100644 --- a/src/ui/optionsdialog.cc +++ b/src/ui/optionsdialog.cc @@ -47,10 +47,11 @@ void OptionsDialog::show() { ui->hexColumnsAutoCheckBox->setCheckState(checkState); ui->hexColumnsSpinBox->setValue(util::settings::hexedit::columnsNumber()); ui->hexColumnsSpinBox->setEnabled(checkState != Qt::Checked); + ui->unprintablesModeDots->setChecked( - util::settings::hexedit::unprintablesModes() == "dots"); + util::settings::hexedit::unprintablesMode() == "Dots"); ui->unprintablesModeWindows1250->setChecked( - util::settings::hexedit::unprintablesModes() == "windows-1250"); + util::settings::hexedit::unprintablesMode() == "Windows-1250"); QWidget::show(); } @@ -68,9 +69,11 @@ void OptionsDialog::accept() { util::settings::hexedit::setColumnsNumber(ui->hexColumnsSpinBox->value()); if (ui->unprintablesModeDots->isChecked()) - util::settings::hexedit::setUnprintablesMode("dots"); + util::settings::hexedit::setUnprintablesMode( + ui->unprintablesModeDots->text()); if (ui->unprintablesModeWindows1250->isChecked()) - util::settings::hexedit::setUnprintablesMode("windows-1250"); + util::settings::hexedit::setUnprintablesMode( + ui->unprintablesModeWindows1250->text()); if (restart_needed) { QMessageBox::about( diff --git a/src/util/misc.cc b/src/util/misc.cc index b72795e2..fe7105ea 100644 --- a/src/util/misc.cc +++ b/src/util/misc.cc @@ -15,9 +15,26 @@ * */ #include "util/misc.h" +#include namespace veles { namespace util { -namespace misc {} // namespace misc +namespace misc { + +/** + * This magic performs the only safe method + * of casting uchar to char according to the C++ standard. +*/ +char ucharToChar(unsigned char value) { + if (value < 0x80) { + return static_cast(value); + } else { + int64_t int_value = static_cast(value); + int_value -= 0x100; + return static_cast(int_value); + } +} + +} // namespace misc } // namespace util } // namespace veles diff --git a/src/util/settings/hexedit.cc b/src/util/settings/hexedit.cc index a2d9c1ca..2c243f5a 100644 --- a/src/util/settings/hexedit.cc +++ b/src/util/settings/hexedit.cc @@ -43,12 +43,12 @@ void setResizeColumnsToWindowWidth(bool on) { settings.setValue("hexedit.resizeColumnsToWindowWidth", on); } -QString unprintablesModes() { +QString unprintablesMode() { QSettings settings; - return settings.value("hexedit.unprintablesMode", "dots").toString(); + return settings.value("hexedit.unprintablesMode", "Dots").toString(); } -void setUnprintablesMode(QString mode) { +void setUnprintablesMode(const QString& mode) { QSettings settings; settings.setValue("hexedit.unprintablesMode", mode); } From 6a98497cb8528c636a13f2ec21de27becaff37cd Mon Sep 17 00:00:00 2001 From: Peter Rybicki Date: Wed, 6 Dec 2017 18:18:58 +0100 Subject: [PATCH 3/5] Review fixup: enumized unprintablesMode --- include/ui/hexedit.h | 11 ++++++++--- include/util/settings/hexedit.h | 5 +++-- src/ui/hexedit.cc | 34 +++++++++++++++++++-------------- src/ui/hexeditwidget.cc | 14 ++++++++++---- src/ui/optionsdialog.cc | 11 +++++++---- src/util/settings/hexedit.cc | 12 ++++++++---- 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/include/ui/hexedit.h b/include/ui/hexedit.h index a91789d1..73e4a029 100644 --- a/include/ui/hexedit.h +++ b/include/ui/hexedit.h @@ -40,6 +40,11 @@ namespace ui { class HexEdit : public QAbstractScrollArea { Q_OBJECT public: + enum class UnprintablesMode { + Dots, + Windows_1250, + }; // do not change the order as settings may invalidate. + explicit HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel = nullptr, QWidget* parent = nullptr); @@ -64,7 +69,8 @@ class HexEdit : public QAbstractScrollArea { in_insert_mode_ = in_insert_mode; } void saveToFile(const QString& file_name); - std::vector getListOfUnprintablesModes(); + QString unprintablesModeToString(UnprintablesMode mode); + void setUnprintablesMode(UnprintablesMode mode); public slots: void newBinData(); @@ -73,7 +79,6 @@ class HexEdit : public QAbstractScrollArea { void applyChanges(); void undo(); void discardChanges(); - void setUnprintablesMode(QAction* action); protected: void paintEvent(QPaintEvent* event) override; @@ -180,7 +185,7 @@ class HexEdit : public QAbstractScrollArea { QScopedPointer textEncoder_; util::EditEngine edit_engine_; - QString unprintables_mode_string_; + UnprintablesMode unprintables_mode_; QTextCodec* windows1250_codec_; void recalculateValues(); diff --git a/include/util/settings/hexedit.h b/include/util/settings/hexedit.h index 68984983..d7e53b81 100644 --- a/include/util/settings/hexedit.h +++ b/include/util/settings/hexedit.h @@ -16,6 +16,7 @@ */ #pragma once +#include #include namespace veles { @@ -27,8 +28,8 @@ int columnsNumber(); void setColumnsNumber(int number); bool resizeColumnsToWindowWidth(); void setResizeColumnsToWindowWidth(bool on); -QString unprintablesMode(); -void setUnprintablesMode(const QString& mode); +veles::ui::HexEdit::UnprintablesMode unprintablesMode(); +void setUnprintablesMode(veles::ui::HexEdit::UnprintablesMode); } // namespace hexedit } // namespace settings diff --git a/src/ui/hexedit.cc b/src/ui/hexedit.cc index 9745e4d9..18186bfd 100644 --- a/src/ui/hexedit.cc +++ b/src/ui/hexedit.cc @@ -145,7 +145,7 @@ HexEdit::HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel, recalculateValues(); // Initialize hex & ASCII text cache. - unprintables_mode_string_ = util::settings::hexedit::unprintablesMode(); + unprintables_mode_ = util::settings::hexedit::unprintablesMode(); updateAsciiCache(); updateHexCache(); @@ -598,13 +598,25 @@ void HexEdit::saveToFile(const QString& file_name) { saveDataToFile(0, edit_engine_.dataSize(), file_name); } -std::vector HexEdit::getListOfUnprintablesModes() { - std::vector modes; - modes.push_back("Dots"); - if (windows1250_codec_ != nullptr) { - modes.push_back("Windows-1250"); +QString HexEdit::unprintablesModeToString(UnprintablesMode mode) { + switch (mode) { + case UnprintablesMode::Windows_1250: + return "Windows-1250"; + case UnprintablesMode::Dots: + default: + return "Dots"; } - return modes; +} + +void HexEdit::setUnprintablesMode(UnprintablesMode mode) { + unprintables_mode_ = mode; + if (mode == UnprintablesMode::Windows_1250 && windows1250_codec_ == nullptr) { + QMessageBox::warning(this, "Error", "Windows-1250 is unavailable.", + QMessageBox::Ok); + return; + } + updateAsciiCache(); + viewport()->update(); } void HexEdit::discardChanges() { @@ -614,12 +626,6 @@ void HexEdit::discardChanges() { viewport()->update(); } -void HexEdit::setUnprintablesMode(QAction* action) { - unprintables_mode_string_ = action->text(); - updateAsciiCache(); - viewport()->update(); -} - qint64 HexEdit::selectionStart() { if (selection_size_ < 0) { return current_position_ + selection_size_ + 1; @@ -658,7 +664,7 @@ QString HexEdit::asciiRepresentationFromByte(uint64_t byte_val) { return "."; } if (windows1250_codec_ != nullptr && - unprintables_mode_string_.compare("Windows-1250") == 0) { + unprintables_mode_ == UnprintablesMode::Windows_1250) { char a = veles::util::misc::ucharToChar(byte_val); QChar unicode_repr = windows1250_codec_->toUnicode(&a, 1).at(0); diff --git a/src/ui/hexeditwidget.cc b/src/ui/hexeditwidget.cc index f5c3d3f4..c012578d 100644 --- a/src/ui/hexeditwidget.cc +++ b/src/ui/hexeditwidget.cc @@ -86,8 +86,6 @@ HexEditWidget::HexEditWidget( ->parsersList()); initUnprintablesMenu(); - connect(&unprintables_menu_, &QMenu::triggered, hex_edit_, - &HexEdit::setUnprintablesMode); selectionChanged(0, 0); } @@ -321,8 +319,16 @@ void HexEditWidget::initParsersMenu() { void HexEditWidget::initUnprintablesMenu() { unprintables_menu_.clear(); - for (auto& mode : hex_edit_->getListOfUnprintablesModes()) { - unprintables_menu_.addAction(mode); + + HexEdit::UnprintablesMode modes[] = {HexEdit::UnprintablesMode::Dots, + HexEdit::UnprintablesMode::Windows_1250}; + + for (auto mode : modes) { + QAction* action = new QAction(hex_edit_->unprintablesModeToString(mode), + &unprintables_menu_); + connect(action, &QAction::triggered, + [=]() { this->hex_edit_->setUnprintablesMode(mode); }); + unprintables_menu_.addAction(action); } } diff --git a/src/ui/optionsdialog.cc b/src/ui/optionsdialog.cc index 73d339cd..830fe304 100644 --- a/src/ui/optionsdialog.cc +++ b/src/ui/optionsdialog.cc @@ -18,6 +18,7 @@ #include +#include #include "ui_optionsdialog.h" #include "util/settings/hexedit.h" #include "util/settings/theme.h" @@ -49,9 +50,11 @@ void OptionsDialog::show() { ui->hexColumnsSpinBox->setEnabled(checkState != Qt::Checked); ui->unprintablesModeDots->setChecked( - util::settings::hexedit::unprintablesMode() == "Dots"); + util::settings::hexedit::unprintablesMode() == + veles::ui::HexEdit::UnprintablesMode::Dots); ui->unprintablesModeWindows1250->setChecked( - util::settings::hexedit::unprintablesMode() == "Windows-1250"); + util::settings::hexedit::unprintablesMode() == + veles::ui::HexEdit::UnprintablesMode::Windows_1250); QWidget::show(); } @@ -70,10 +73,10 @@ void OptionsDialog::accept() { if (ui->unprintablesModeDots->isChecked()) util::settings::hexedit::setUnprintablesMode( - ui->unprintablesModeDots->text()); + veles::ui::HexEdit::UnprintablesMode::Dots); if (ui->unprintablesModeWindows1250->isChecked()) util::settings::hexedit::setUnprintablesMode( - ui->unprintablesModeWindows1250->text()); + veles::ui::HexEdit::UnprintablesMode::Windows_1250); if (restart_needed) { QMessageBox::about( diff --git a/src/util/settings/hexedit.cc b/src/util/settings/hexedit.cc index 2c243f5a..d0c41ea4 100644 --- a/src/util/settings/hexedit.cc +++ b/src/util/settings/hexedit.cc @@ -43,14 +43,18 @@ void setResizeColumnsToWindowWidth(bool on) { settings.setValue("hexedit.resizeColumnsToWindowWidth", on); } -QString unprintablesMode() { +veles::ui::HexEdit::UnprintablesMode unprintablesMode() { QSettings settings; - return settings.value("hexedit.unprintablesMode", "Dots").toString(); + + int default_value = + static_cast(veles::ui::HexEdit::UnprintablesMode::Dots); + return static_cast( + settings.value("hexedit.unprintablesMode", default_value).toInt()); } -void setUnprintablesMode(const QString& mode) { +void setUnprintablesMode(veles::ui::HexEdit::UnprintablesMode mode) { QSettings settings; - settings.setValue("hexedit.unprintablesMode", mode); + settings.setValue("hexedit.unprintablesMode", static_cast(mode)); } } // namespace hexedit From 57a8a2f7210d36d7a93b1ca4cf757e575e718b84 Mon Sep 17 00:00:00 2001 From: Peter Rybicki Date: Wed, 13 Dec 2017 14:09:48 +0100 Subject: [PATCH 4/5] Review fixup 3 --- include/ui/hexedit.h | 7 ++++--- include/util/settings/hexedit.h | 3 ++- src/ui/hexedit.cc | 31 +++++++++++++++++-------------- src/ui/hexeditwidget.cc | 4 ++-- src/ui/optionsdialog.cc | 8 ++++---- src/util/misc.cc | 4 +++- 6 files changed, 32 insertions(+), 25 deletions(-) diff --git a/include/ui/hexedit.h b/include/ui/hexedit.h index 73e4a029..57a24dde 100644 --- a/include/ui/hexedit.h +++ b/include/ui/hexedit.h @@ -41,9 +41,10 @@ class HexEdit : public QAbstractScrollArea { Q_OBJECT public: enum class UnprintablesMode { + // do not change the order as settings may invalidate. Dots, - Windows_1250, - }; // do not change the order as settings may invalidate. + Windows1250, + }; explicit HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel = nullptr, @@ -69,7 +70,7 @@ class HexEdit : public QAbstractScrollArea { in_insert_mode_ = in_insert_mode; } void saveToFile(const QString& file_name); - QString unprintablesModeToString(UnprintablesMode mode); + static QString unprintablesModeToString(UnprintablesMode mode); void setUnprintablesMode(UnprintablesMode mode); public slots: diff --git a/include/util/settings/hexedit.h b/include/util/settings/hexedit.h index d7e53b81..1857aae0 100644 --- a/include/util/settings/hexedit.h +++ b/include/util/settings/hexedit.h @@ -16,9 +16,10 @@ */ #pragma once -#include #include +#include "ui/hexedit.h" + namespace veles { namespace util { namespace settings { diff --git a/src/ui/hexedit.cc b/src/ui/hexedit.cc index 18186bfd..8c2187b0 100644 --- a/src/ui/hexedit.cc +++ b/src/ui/hexedit.cc @@ -130,7 +130,7 @@ HexEdit::HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel, in_insert_mode_(false), edit_engine_(dataModel_), windows1250_codec_(QTextCodec::codecForName("windows-1250")) { - // TODO Add log warning if codec is unavailable (== nullptr) + // TODO Log warning if codec is unavailable (== nullptr) auto font = util::settings::theme::font(); setFont(font); @@ -600,7 +600,7 @@ void HexEdit::saveToFile(const QString& file_name) { QString HexEdit::unprintablesModeToString(UnprintablesMode mode) { switch (mode) { - case UnprintablesMode::Windows_1250: + case UnprintablesMode::Windows1250: return "Windows-1250"; case UnprintablesMode::Dots: default: @@ -609,12 +609,12 @@ QString HexEdit::unprintablesModeToString(UnprintablesMode mode) { } void HexEdit::setUnprintablesMode(UnprintablesMode mode) { - unprintables_mode_ = mode; - if (mode == UnprintablesMode::Windows_1250 && windows1250_codec_ == nullptr) { - QMessageBox::warning(this, "Error", "Windows-1250 is unavailable.", + if (mode == UnprintablesMode::Windows1250 && windows1250_codec_ == nullptr) { + QMessageBox::warning(this, "Error", "Windows-1250 encoding is unavailable.", QMessageBox::Ok); return; } + unprintables_mode_ = mode; updateAsciiCache(); viewport()->update(); } @@ -664,17 +664,20 @@ QString HexEdit::asciiRepresentationFromByte(uint64_t byte_val) { return "."; } if (windows1250_codec_ != nullptr && - unprintables_mode_ == UnprintablesMode::Windows_1250) { - char a = veles::util::misc::ucharToChar(byte_val); - QChar unicode_repr = windows1250_codec_->toUnicode(&a, 1).at(0); - + unprintables_mode_ == UnprintablesMode::Windows1250) { bool is_undefined_windows1250 = byte_val == 0x81 || byte_val == 0x83 || byte_val == 0x88 || byte_val == 0x90 || byte_val == 0x98; - bool is_whitespace = unicode_repr.isSpace() || unicode_repr.isNull(); + if (is_undefined_windows1250) { + return " "; + } + + char a = veles::util::misc::ucharToChar(byte_val); + QChar unicode_repr = windows1250_codec_->toUnicode(&a, 1).at(0); - if (is_whitespace || is_undefined_windows1250) { + // 0x7f decodes to DEL in CP1250 which is unprintable + if (unicode_repr.isSpace() || unicode_repr.isNull() || byte_val == 0x7f) { return " "; } @@ -684,9 +687,9 @@ QString HexEdit::asciiRepresentationFromByte(uint64_t byte_val) { } // unprintable ASCII chars - return byte_val >= 0x7f ? windows1250_codec_->toUnicode(&a, 1) - : QChar(static_cast(byte_val) + - 0x180); // greek for < 0x20 + return byte_val > 0x7f ? windows1250_codec_->toUnicode(&a, 1) + : QChar(static_cast(byte_val) + + 0x180); // greek for < 0x20 } // dots mode return (byte_val >= 0x20 && byte_val < 0x7f) ? QChar::fromLatin1(byte_val) diff --git a/src/ui/hexeditwidget.cc b/src/ui/hexeditwidget.cc index c012578d..ad281ef5 100644 --- a/src/ui/hexeditwidget.cc +++ b/src/ui/hexeditwidget.cc @@ -321,13 +321,13 @@ void HexEditWidget::initUnprintablesMenu() { unprintables_menu_.clear(); HexEdit::UnprintablesMode modes[] = {HexEdit::UnprintablesMode::Dots, - HexEdit::UnprintablesMode::Windows_1250}; + HexEdit::UnprintablesMode::Windows1250}; for (auto mode : modes) { QAction* action = new QAction(hex_edit_->unprintablesModeToString(mode), &unprintables_menu_); connect(action, &QAction::triggered, - [=]() { this->hex_edit_->setUnprintablesMode(mode); }); + [this, mode]() { this->hex_edit_->setUnprintablesMode(mode); }); unprintables_menu_.addAction(action); } } diff --git a/src/ui/optionsdialog.cc b/src/ui/optionsdialog.cc index 830fe304..f46fe34f 100644 --- a/src/ui/optionsdialog.cc +++ b/src/ui/optionsdialog.cc @@ -14,11 +14,11 @@ * limitations under the License. * */ -#include "ui/optionsdialog.h" #include -#include +#include "ui/hexedit.h" +#include "ui/optionsdialog.h" #include "ui_optionsdialog.h" #include "util/settings/hexedit.h" #include "util/settings/theme.h" @@ -54,7 +54,7 @@ void OptionsDialog::show() { veles::ui::HexEdit::UnprintablesMode::Dots); ui->unprintablesModeWindows1250->setChecked( util::settings::hexedit::unprintablesMode() == - veles::ui::HexEdit::UnprintablesMode::Windows_1250); + veles::ui::HexEdit::UnprintablesMode::Windows1250); QWidget::show(); } @@ -76,7 +76,7 @@ void OptionsDialog::accept() { veles::ui::HexEdit::UnprintablesMode::Dots); if (ui->unprintablesModeWindows1250->isChecked()) util::settings::hexedit::setUnprintablesMode( - veles::ui::HexEdit::UnprintablesMode::Windows_1250); + veles::ui::HexEdit::UnprintablesMode::Windows1250); if (restart_needed) { QMessageBox::about( diff --git a/src/util/misc.cc b/src/util/misc.cc index fe7105ea..74b7bb54 100644 --- a/src/util/misc.cc +++ b/src/util/misc.cc @@ -14,9 +14,11 @@ * limitations under the License. * */ -#include "util/misc.h" + #include +#include "util/misc.h" + namespace veles { namespace util { namespace misc { From f8944268100ded01010b769e66ad6e713e572835 Mon Sep 17 00:00:00 2001 From: Peter Rybicki Date: Wed, 13 Dec 2017 16:07:55 +0100 Subject: [PATCH 5/5] Jenkins fixup --- include/util/settings/hexedit.h | 2 +- src/ui/hexedit.cc | 2 +- src/ui/optionsdialog.cc | 6 ++++-- src/util/misc.cc | 8 ++++---- src/util/settings/hexedit.cc | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/util/settings/hexedit.h b/include/util/settings/hexedit.h index 1857aae0..1c7181e0 100644 --- a/include/util/settings/hexedit.h +++ b/include/util/settings/hexedit.h @@ -30,7 +30,7 @@ void setColumnsNumber(int number); bool resizeColumnsToWindowWidth(); void setResizeColumnsToWindowWidth(bool on); veles::ui::HexEdit::UnprintablesMode unprintablesMode(); -void setUnprintablesMode(veles::ui::HexEdit::UnprintablesMode); +void setUnprintablesMode(veles::ui::HexEdit::UnprintablesMode mode); } // namespace hexedit } // namespace settings diff --git a/src/ui/hexedit.cc b/src/ui/hexedit.cc index 8c2187b0..4b0ca3fb 100644 --- a/src/ui/hexedit.cc +++ b/src/ui/hexedit.cc @@ -130,7 +130,7 @@ HexEdit::HexEdit(FileBlobModel* dataModel, QItemSelectionModel* selectionModel, in_insert_mode_(false), edit_engine_(dataModel_), windows1250_codec_(QTextCodec::codecForName("windows-1250")) { - // TODO Log warning if codec is unavailable (== nullptr) + // TODO(mkow) Log warning if codec is unavailable (== nullptr) auto font = util::settings::theme::font(); setFont(font); diff --git a/src/ui/optionsdialog.cc b/src/ui/optionsdialog.cc index f46fe34f..1c736334 100644 --- a/src/ui/optionsdialog.cc +++ b/src/ui/optionsdialog.cc @@ -71,12 +71,14 @@ void OptionsDialog::accept() { ui->hexColumnsAutoCheckBox->checkState() == Qt::Checked); util::settings::hexedit::setColumnsNumber(ui->hexColumnsSpinBox->value()); - if (ui->unprintablesModeDots->isChecked()) + if (ui->unprintablesModeDots->isChecked()) { util::settings::hexedit::setUnprintablesMode( veles::ui::HexEdit::UnprintablesMode::Dots); - if (ui->unprintablesModeWindows1250->isChecked()) + } + if (ui->unprintablesModeWindows1250->isChecked()) { util::settings::hexedit::setUnprintablesMode( veles::ui::HexEdit::UnprintablesMode::Windows1250); + } if (restart_needed) { QMessageBox::about( diff --git a/src/util/misc.cc b/src/util/misc.cc index 74b7bb54..fd4d3288 100644 --- a/src/util/misc.cc +++ b/src/util/misc.cc @@ -30,11 +30,11 @@ namespace misc { char ucharToChar(unsigned char value) { if (value < 0x80) { return static_cast(value); - } else { - int64_t int_value = static_cast(value); - int_value -= 0x100; - return static_cast(int_value); } + + auto int_value = static_cast(value); + int_value -= 0x100; + return static_cast(int_value); } } // namespace misc diff --git a/src/util/settings/hexedit.cc b/src/util/settings/hexedit.cc index d0c41ea4..36826074 100644 --- a/src/util/settings/hexedit.cc +++ b/src/util/settings/hexedit.cc @@ -46,7 +46,7 @@ void setResizeColumnsToWindowWidth(bool on) { veles::ui::HexEdit::UnprintablesMode unprintablesMode() { QSettings settings; - int default_value = + auto default_value = static_cast(veles::ui::HexEdit::UnprintablesMode::Dots); return static_cast( settings.value("hexedit.unprintablesMode", default_value).toInt());