Skip to content
This repository has been archived by the owner on Sep 30, 2020. It is now read-only.

Add more representations of unprintable bytes #380

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion include/ui/hexedit.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <QMouseEvent>
#include <QStaticText>
#include <QStringList>
#include <QTextCodec>

#include "ui/createchunkdialog.h"
#include "ui/fileblobmodel.h"
Expand All @@ -39,6 +40,12 @@ namespace ui {
class HexEdit : public QAbstractScrollArea {
Q_OBJECT
public:
enum class UnprintablesMode {
// do not change the order as settings may invalidate.
Dots,
Windows1250,
};

explicit HexEdit(FileBlobModel* dataModel,
QItemSelectionModel* selectionModel = nullptr,
QWidget* parent = nullptr);
Expand All @@ -63,6 +70,8 @@ class HexEdit : public QAbstractScrollArea {
in_insert_mode_ = in_insert_mode;
}
void saveToFile(const QString& file_name);
static QString unprintablesModeToString(UnprintablesMode mode);
void setUnprintablesMode(UnprintablesMode mode);

public slots:
void newBinData();
Expand Down Expand Up @@ -177,6 +186,9 @@ class HexEdit : public QAbstractScrollArea {
QScopedPointer<util::encoders::TextEncoder> textEncoder_;
util::EditEngine edit_engine_;

UnprintablesMode unprintables_mode_;
QTextCodec* windows1250_codec_;

void recalculateValues();
void initParseMenu();
void adjustBytesPerRowToWindowSize();
Expand All @@ -188,7 +200,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);
Expand Down
2 changes: 2 additions & 0 deletions include/ui/hexeditwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class HexEditWidget : public View {
void createActions();
void createToolBars();
void initParsersMenu();
void initUnprintablesMenu();
void createSelectionInfo();

MainWindowWithDetachableDockWidgets* main_window_;
Expand Down Expand Up @@ -127,6 +128,7 @@ class HexEditWidget : public View {

QStringList parsers_ids_;
QMenu parsers_menu_;
QMenu unprintables_menu_;
QLabel* selection_label_;
};

Expand Down
2 changes: 2 additions & 0 deletions include/util/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions include/util/settings/hexedit.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
*/
#pragma once

#include <QString>

#include "ui/hexedit.h"

namespace veles {
namespace util {
namespace settings {
Expand All @@ -25,6 +29,8 @@ int columnsNumber();
void setColumnsNumber(int number);
bool resizeColumnsToWindowWidth();
void setResizeColumnsToWindowWidth(bool on);
veles::ui::HexEdit::UnprintablesMode unprintablesMode();
void setUnprintablesMode(veles::ui::HexEdit::UnprintablesMode mode);

} // namespace hexedit
} // namespace settings
Expand Down
91 changes: 77 additions & 14 deletions src/ui/hexedit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "util/encoders/factory.h"
#include "util/misc.h"
#include "util/random.h"
#include "util/settings/hexedit.h"
#include "util/settings/theme.h"

using veles::util::misc::array_size;
Expand Down Expand Up @@ -127,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(mkow) Log warning if codec is unavailable (== nullptr)
auto font = util::settings::theme::font();
setFont(font);

Expand All @@ -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);
}
unprintables_mode_ = util::settings::hexedit::unprintablesMode();
updateAsciiCache();
updateHexCache();

connect(verticalScrollBar(), &QAbstractSlider::valueChanged, this,
&HexEdit::recalculateValues);
Expand Down Expand Up @@ -602,6 +598,27 @@ void HexEdit::saveToFile(const QString& file_name) {
saveDataToFile(0, edit_engine_.dataSize(), file_name);
}

QString HexEdit::unprintablesModeToString(UnprintablesMode mode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method can be static.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

switch (mode) {
case UnprintablesMode::Windows1250:
return "Windows-1250";
case UnprintablesMode::Dots:
default:
return "Dots";
}
}

void HexEdit::setUnprintablesMode(UnprintablesMode mode) {
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();
}

void HexEdit::discardChanges() {
edit_engine_.clear();
recalculateValues();
Expand Down Expand Up @@ -643,10 +660,56 @@ QString HexEdit::addressAsText(qint64 pos) {
}

QString HexEdit::asciiRepresentationFromByte(uint64_t byte_val) {
if (byte_val >= 0x20 && byte_val < 0x7f) {
return QChar::fromLatin1(byte_val);
if (byte_val > 0xff) {
return ".";
}
if (windows1250_codec_ != nullptr &&
unprintables_mode_ == UnprintablesMode::Windows1250) {
bool is_undefined_windows1250 = byte_val == 0x81 || byte_val == 0x83 ||
byte_val == 0x88 || byte_val == 0x90 ||
byte_val == 0x98;

if (is_undefined_windows1250) {
return " ";
}

char a = veles::util::misc::ucharToChar(byte_val);
QChar unicode_repr = windows1250_codec_->toUnicode(&a, 1).at(0);

// 0x7f decodes to DEL in CP1250 which is unprintable
if (unicode_repr.isSpace() || unicode_repr.isNull() || byte_val == 0x7f) {
return " ";
}

// printable ASCII chars
if (byte_val >= 0x20 && byte_val < 0x7f) {
return QChar::fromLatin1(byte_val);
}

// unprintable ASCII chars
return byte_val > 0x7f ? windows1250_codec_->toUnicode(&a, 1)
: QChar(static_cast<uint>(byte_val) +
0x180); // greek for < 0x20
}
// 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);
}
return ".";
}

QColor HexEdit::byteTextColorFromByteValue(uint64_t byte_val) {
Expand Down
30 changes: 30 additions & 0 deletions src/ui/hexeditwidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ HexEditWidget::HexEditWidget(
setParserIds(dynamic_cast<VelesMainWindow*>(
MainWindowWithDetachableDockWidgets::getFirstMainWindow())
->parsersList());

initUnprintablesMenu();

selectionChanged(0, 0);
}

Expand Down Expand Up @@ -282,6 +285,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();
Expand All @@ -302,6 +317,21 @@ void HexEditWidget::initParsersMenu() {
}
}

void HexEditWidget::initUnprintablesMenu() {
unprintables_menu_.clear();

HexEdit::UnprintablesMode modes[] = {HexEdit::UnprintablesMode::Dots,
HexEdit::UnprintablesMode::Windows1250};

for (auto mode : modes) {
QAction* action = new QAction(hex_edit_->unprintablesModeToString(mode),
&unprintables_menu_);
connect(action, &QAction::triggered,
[this, mode]() { this->hex_edit_->setUnprintablesMode(mode); });
unprintables_menu_.addAction(action);
}
}

void HexEditWidget::createSelectionInfo() {
auto* widget_action = new QWidgetAction(this);
auto* selection_panel = new QWidget;
Expand Down
19 changes: 18 additions & 1 deletion src/ui/optionsdialog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
* limitations under the License.
*
*/
#include "ui/optionsdialog.h"

#include <QMessageBox>

#include "ui/hexedit.h"
#include "ui/optionsdialog.h"
#include "ui_optionsdialog.h"
#include "util/settings/hexedit.h"
#include "util/settings/theme.h"
Expand Down Expand Up @@ -48,6 +49,13 @@ void OptionsDialog::show() {
ui->hexColumnsSpinBox->setValue(util::settings::hexedit::columnsNumber());
ui->hexColumnsSpinBox->setEnabled(checkState != Qt::Checked);

ui->unprintablesModeDots->setChecked(
util::settings::hexedit::unprintablesMode() ==
veles::ui::HexEdit::UnprintablesMode::Dots);
ui->unprintablesModeWindows1250->setChecked(
util::settings::hexedit::unprintablesMode() ==
veles::ui::HexEdit::UnprintablesMode::Windows1250);

QWidget::show();
}

Expand All @@ -63,6 +71,15 @@ void OptionsDialog::accept() {
ui->hexColumnsAutoCheckBox->checkState() == Qt::Checked);
util::settings::hexedit::setColumnsNumber(ui->hexColumnsSpinBox->value());

if (ui->unprintablesModeDots->isChecked()) {
util::settings::hexedit::setUnprintablesMode(
veles::ui::HexEdit::UnprintablesMode::Dots);
}
if (ui->unprintablesModeWindows1250->isChecked()) {
util::settings::hexedit::setUnprintablesMode(
veles::ui::HexEdit::UnprintablesMode::Windows1250);
}

if (restart_needed) {
QMessageBox::about(
this, tr("Options change"),
Expand Down
Loading