From: Soeren Apel Date: Fri, 20 Dec 2019 00:43:32 +0000 (+0100) Subject: DecoderOutputView: Implement saving X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=d5645564896bd753551b2ad814cefafd4e29a6d4;p=pulseview.git DecoderOutputView: Implement saving --- diff --git a/pv/views/decoder_output/QHexView.cpp b/pv/views/decoder_output/QHexView.cpp index 0fca4161..d963ae0a 100644 --- a/pv/views/decoder_output/QHexView.cpp +++ b/pv/views/decoder_output/QHexView.cpp @@ -79,7 +79,7 @@ QHexView::QHexView(QWidget *parent): } } -void QHexView::setMode(Mode m) +void QHexView::set_mode(Mode m) { mode_ = m; @@ -87,7 +87,7 @@ void QHexView::setMode(Mode m) // so we don't update the viewport here } -void QHexView::setData(const DecodeBinaryClass* data) +void QHexView::set_data(const DecodeBinaryClass* data) { data_ = data; @@ -100,6 +100,11 @@ void QHexView::setData(const DecodeBinaryClass* data) viewport()->update(); } +unsigned int QHexView::get_bytes_per_line() const +{ + return BYTES_PER_LINE; +} + void QHexView::clear() { verticalScrollBar()->setValue(0); @@ -141,6 +146,47 @@ pair QHexView::get_selection() const return std::make_pair(start, end); } +size_t QHexView::create_hex_line(size_t start, size_t end, QString* dest, + bool with_offset, bool with_ascii) +{ + dest->clear(); + + // Determine start address for the row + uint64_t row = start / BYTES_PER_LINE; + uint64_t offset = row * BYTES_PER_LINE; + end = std::min(end, offset + BYTES_PER_LINE); + + if (with_offset) + dest->append(QString("%1 ").arg(row * BYTES_PER_LINE, 10, 16, QChar('0')).toUpper()); + + initialize_byte_iterator(offset); + for (size_t i = offset; i < offset + BYTES_PER_LINE; i++) { + uint8_t value = 0; + + if (i < end) + value = get_next_byte(); + + if ((i < start) || (i >= end)) + dest->append(" "); + else + dest->append(QString("%1 ").arg(value, 2, 16, QChar('0')).toUpper()); + } + + if (with_ascii) { + initialize_byte_iterator(offset); + for (size_t i = offset; i < end; i++) { + uint8_t value = get_next_byte(); + + if (i < start) + dest->append(' '); + else + dest->append((char)value); + } + } + + return end; +} + void QHexView::initialize_byte_iterator(size_t offset) { current_chunk_id_ = 0; diff --git a/pv/views/decoder_output/QHexView.hpp b/pv/views/decoder_output/QHexView.hpp index c3004c5c..71b06cdd 100644 --- a/pv/views/decoder_output/QHexView.hpp +++ b/pv/views/decoder_output/QHexView.hpp @@ -52,8 +52,9 @@ public: public: QHexView(QWidget *parent = 0); - void setMode(Mode m); - void setData(const DecodeBinaryClass* data); + void set_mode(Mode m); + void set_data(const DecodeBinaryClass* data); + unsigned int get_bytes_per_line() const; void clear(); void showFromOffset(size_t offset); @@ -61,6 +62,9 @@ public: pair get_selection() const; + size_t create_hex_line(size_t start, size_t end, QString* dest, + bool with_offset=false, bool with_ascii=false); + protected: void initialize_byte_iterator(size_t offset); uint8_t get_next_byte(bool* is_next_chunk = nullptr); diff --git a/pv/views/decoder_output/view.cpp b/pv/views/decoder_output/view.cpp index 951bc06e..775f6daf 100644 --- a/pv/views/decoder_output/view.cpp +++ b/pv/views/decoder_output/view.cpp @@ -54,7 +54,9 @@ namespace decoder_output { const char* SaveTypeNames[SaveTypeCount] = { "Binary", - "Hex Dump" + "Hex Dump, plain", + "Hex Dump, with offset", + "Hex Dump, complete" }; @@ -242,7 +244,7 @@ void View::update_data() const DecodeBinaryClass* bin_class = signal_->get_binary_data_class(current_segment_, decoder_, bin_class_id_); - hex_view_->setData(bin_class); + hex_view_->set_data(bin_class); if (!save_button_->isEnabled()) save_button_->setEnabled(true); @@ -286,9 +288,54 @@ void View::save_data() const } } -void View::save_data_as_hex_dump() const +void View::save_data_as_hex_dump(bool with_offset, bool with_ascii) const { + assert(decoder_); + assert(signal_); + + if (!signal_) + return; + + GlobalSettings settings; + const QString dir = settings.value("MainWindow/SaveDirectory").toString(); + + const QString file_name = QFileDialog::getSaveFileName( + parent_, tr("Save Binary Data"), dir, tr("Hex Dumps (*.txt);;All Files (*)")); + + if (file_name.isEmpty()) + return; + + QFile file(file_name); + if (file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + pair selection = hex_view_->get_selection(); + + vector data; + signal_->get_merged_binary_data_chunks_by_offset(current_segment_, decoder_, + bin_class_id_, selection.first, selection.second, &data); + + QTextStream out_stream(&file); + + uint64_t offset = selection.first; + unsigned int n = hex_view_->get_bytes_per_line(); + QString s; + while (offset < selection.second) { + size_t end = std::min(selection.second, offset + n); + offset = hex_view_->create_hex_line(offset, end, &s, with_offset, with_ascii); + out_stream << s << endl; + } + + out_stream << endl; + + if (out_stream.status() != QTextStream::Ok) { + QMessageBox msg(parent_); + msg.setText(tr("Error") + "\n\n" + tr("File %1 could not be written to.").arg(file_name)); + msg.setStandardButtons(QMessageBox::Ok); + msg.setIcon(QMessageBox::Warning); + msg.exec(); + return; + } + } } void View::on_selected_decoder_changed(int index) @@ -412,10 +459,13 @@ void View::on_actionSave_triggered(QAction* action) if (action) save_type = action->data().toInt(); - if (save_type == SaveTypeBinary) - save_data(); - if (save_type == SaveTypeHexDump) - save_data_as_hex_dump(); + switch (save_type) + { + case SaveTypeBinary: save_data(); break; + case SaveTypeHexDumpPlain: save_data_as_hex_dump(false, false); break; + case SaveTypeHexDumpWithOffset: save_data_as_hex_dump(true, false); break; + case SaveTypeHexDumpComplete: save_data_as_hex_dump(true, true); break; + } } void View::perform_delayed_view_update() diff --git a/pv/views/decoder_output/view.hpp b/pv/views/decoder_output/view.hpp index 28c7e906..a6362ede 100644 --- a/pv/views/decoder_output/view.hpp +++ b/pv/views/decoder_output/view.hpp @@ -41,7 +41,9 @@ namespace decoder_output { // When adding an entry here, don't forget to update SaveTypeNames as well enum SaveType { SaveTypeBinary, - SaveTypeHexDump, + SaveTypeHexDumpPlain, + SaveTypeHexDumpWithOffset, + SaveTypeHexDumpComplete, SaveTypeCount // Indicates how many save types there are, must always be last }; @@ -77,7 +79,7 @@ private: void update_data(); void save_data() const; - void save_data_as_hex_dump() const; + void save_data_as_hex_dump(bool with_offset=false, bool with_ascii=false) const; private Q_SLOTS: void on_selected_decoder_changed(int index);