]> sigrok.org Git - pulseview.git/commitdiff
DecoderOutputView: Implement saving
authorSoeren Apel <redacted>
Fri, 20 Dec 2019 00:43:32 +0000 (01:43 +0100)
committerSoeren Apel <redacted>
Fri, 20 Dec 2019 00:44:21 +0000 (01:44 +0100)
pv/views/decoder_output/QHexView.cpp
pv/views/decoder_output/QHexView.hpp
pv/views/decoder_output/view.cpp
pv/views/decoder_output/view.hpp

index 0fca4161fe02f6467799619a56862cb09db8b8c1..d963ae0aa03af632d963233f6bca7fb33f0dcfe2 100644 (file)
@@ -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<size_t, size_t> 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;
index c3004c5c59d07aa7040589b688f9e36b4e26616e..71b06cdd71ff3a84d8b6f72e485b152fe9d9a839 100644 (file)
@@ -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<size_t, size_t> 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);
index 951bc06ef296712c65c467548736a1eb62e421eb..775f6daf92a8d1ebe9b10f56eed98da1b7a25770 100644 (file)
@@ -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<size_t, size_t> selection = hex_view_->get_selection();
+
+               vector<uint8_t> 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()
index 28c7e9066ae27960d8b321919c8f2ec472ac2d13..a6362ede7ac59646e1b08e43124c741abaab96d9 100644 (file)
@@ -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);