From 46364c2420ba0b23ec93610e134ccf732129de16 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 16 Aug 2022 21:56:07 +0200 Subject: [PATCH] [consider merging] Reader format error with details showing dump or text --- src/db/db/dbReader.cc | 8 +- src/db/db/dbReader.h | 29 ++++ src/lay/lay/ReaderErrorForm.ui | 278 ++++++++++++++++++++++++++++++ src/lay/lay/lay.pro | 3 + src/lay/lay/layApplication.cc | 12 +- src/lay/lay/layReaderErrorForm.cc | 123 +++++++++++++ src/lay/lay/layReaderErrorForm.h | 57 ++++++ 7 files changed, 508 insertions(+), 2 deletions(-) create mode 100644 src/lay/lay/ReaderErrorForm.ui create mode 100644 src/lay/lay/layReaderErrorForm.cc create mode 100644 src/lay/lay/layReaderErrorForm.h diff --git a/src/db/db/dbReader.cc b/src/db/db/dbReader.cc index b48026113..15d2bc6cc 100644 --- a/src/db/db/dbReader.cc +++ b/src/db/db/dbReader.cc @@ -91,7 +91,13 @@ Reader::Reader (tl::InputStream &stream) } if (! mp_actual_reader) { - throw db::ReaderException (tl::to_string (tr ("Stream has unknown format: ")) + stream.source ()); + + m_stream.reset (); + std::string head = m_stream.read_all (4000); + bool has_more (m_stream.get (1) != 0); + + throw db::ReaderUnknownFormatException (tl::to_string (tr ("Stream has unknown format: ")) + stream.source (), head, has_more); + } } diff --git a/src/db/db/dbReader.h b/src/db/db/dbReader.h index d4dd83d9f..c43cffea4 100644 --- a/src/db/db/dbReader.h +++ b/src/db/db/dbReader.h @@ -54,6 +54,35 @@ public: { } }; +/** + * @brief A class representing the "unknown format" reader error + * + * The purpose of this class is supply the header bytes of the + * data stream for analysis. + */ +class DB_PUBLIC ReaderUnknownFormatException + : public ReaderException +{ +public: + ReaderUnknownFormatException (const std::string &msg, const std::string &data, bool has_more) + : ReaderException (msg), m_data (data), m_has_more (has_more) + { } + + const std::string &data () const + { + return m_data; + } + + bool has_more () const + { + return m_has_more; + } + +private: + std::string m_data; + bool m_has_more; +}; + /** * @brief Joins layer names into a single, combined layer * @param s The first layer name and output diff --git a/src/lay/lay/ReaderErrorForm.ui b/src/lay/lay/ReaderErrorForm.ui new file mode 100644 index 000000000..a94902b0c --- /dev/null +++ b/src/lay/lay/ReaderErrorForm.ui @@ -0,0 +1,278 @@ + + + ReaderErrorForm + + + + 0 + 0 + 496 + 297 + + + + Script Error + + + + 6 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 411 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 411 + 20 + + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 71 + + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 0 + + + X + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 71 + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTextEdit::NoWrap + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Liberation Mono';"><br /></p></body></html> + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Details >> + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 341 + 16 + + + + + + + + OK + + + true + + + + + + + + + + + + + ok_button + clicked() + ReaderErrorForm + accept() + + + 457 + 330 + + + 271 + 177 + + + + + diff --git a/src/lay/lay/lay.pro b/src/lay/lay/lay.pro index 3a6001cc0..a30887eb7 100644 --- a/src/lay/lay/lay.pro +++ b/src/lay/lay/lay.pro @@ -31,6 +31,7 @@ HEADERS = \ layProgressWidget.h \ layResourceHelpProvider.h \ layRuntimeErrorForm.h \ + layReaderErrorForm.h \ laySearchReplaceConfigPage.h \ laySearchReplaceDialog.h \ laySearchReplacePropertiesWidgets.h \ @@ -87,6 +88,7 @@ FORMS = \ ReplacePropertiesShape.ui \ ReplacePropertiesText.ui \ RuntimeErrorForm.ui \ + ReaderErrorForm.ui \ SearchPropertiesBox.ui \ SearchPropertiesInstance.ui \ SearchPropertiesPath.ui \ @@ -139,6 +141,7 @@ SOURCES = \ layProgressWidget.cc \ layResourceHelpProvider.cc \ layRuntimeErrorForm.cc \ + layReaderErrorForm.cc \ laySearchReplaceConfigPage.cc \ laySearchReplaceDialog.cc \ laySearchReplacePlugin.cc \ diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 46b7648f4..530ca037f 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -31,6 +31,7 @@ #include "layVersion.h" #include "laySignalHandler.h" #include "layRuntimeErrorForm.h" +#include "layReaderErrorForm.h" #include "layProgress.h" #include "layTextProgress.h" #include "layBackgroundAwareTreeStyle.h" @@ -106,6 +107,7 @@ static void ui_exception_handler_tl (const tl::Exception &ex, QWidget *parent) const tl::ExitException *gsi_exit = dynamic_cast (&ex); const tl::BreakException *gsi_break = dynamic_cast (&ex); const tl::ScriptError *gsi_excpt = dynamic_cast (&ex); + const db::ReaderUnknownFormatException *reader_excpt = dynamic_cast (&ex); if (gsi_exit || gsi_break) { // exit and break exceptions are not shown - they are issued when a script is aborted or @@ -131,11 +133,19 @@ static void ui_exception_handler_tl (const tl::Exception &ex, QWidget *parent) error_dialog.exec (); } else { + tl::error << ex.msg (); if (! parent) { parent = QApplication::activeWindow () ? QApplication::activeWindow () : lay::MainWindow::instance (); } - QMessageBox::critical (parent, QObject::tr ("Error"), tl::to_qstring (ex.msg ())); + + if (reader_excpt) { + lay::ReaderErrorForm error_dialog (parent, "reader_error_form", reader_excpt); + error_dialog.exec (); + } else { + QMessageBox::critical (parent, QObject::tr ("Error"), tl::to_qstring (ex.msg ())); + } + } } diff --git a/src/lay/lay/layReaderErrorForm.cc b/src/lay/lay/layReaderErrorForm.cc new file mode 100644 index 000000000..1ea3f4421 --- /dev/null +++ b/src/lay/lay/layReaderErrorForm.cc @@ -0,0 +1,123 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "layReaderErrorForm.h" +#include "layQtTools.h" +#include "dbReader.h" + +#include + +namespace lay +{ + +// ------------------------------------------------------------ + +static bool is_text (const std::string &s) +{ + for (std::string::const_iterator i = s.begin (); i != s.end (); ++i) { + unsigned char uc = (unsigned char) *i; + if (uc < 32 && uc != '\t' && uc != '\r' && uc != '\n') { + return false; + } + } + return true; +} + +static std::string format_hex_dump (const std::string &s) +{ + const int bytes_per_line = 16; + + std::string hex_dump; + // Some rough estimate of the capacity + hex_dump.reserve ((s.size () / bytes_per_line + 1) * (8 + bytes_per_line * 4) + 100); + + const char *ce = s.c_str () + s.size (); + for (const char *c = s.c_str (); c + bytes_per_line <= ce; c += bytes_per_line) { + + hex_dump += tl::sprintf ("%04x ", c - s.c_str ()); + for (int i = 0; i < bytes_per_line; ++i) { + hex_dump += tl::sprintf ("%02x ", (unsigned char) c [i]); + } + hex_dump += " "; + for (int i = 0; i < bytes_per_line; ++i) { + unsigned char uc = (unsigned char) c[i]; + hex_dump += (uc < 32 || uc >= 128) ? '.' : c[i]; + } + + hex_dump += "\n"; + + } + + return hex_dump; +} + +ReaderErrorForm::ReaderErrorForm (QWidget *parent, const char *name, const db::ReaderUnknownFormatException *error) + : QDialog (parent), Ui::ReaderErrorForm () +{ + setObjectName (QString::fromUtf8 (name)); + + Ui::ReaderErrorForm::setupUi (this); + + msg_label->setText (tl::to_qstring (error->basic_msg ())); + + if (is_text (error->data ())) { + details_text->setText (tl::to_qstring (error->msg () + "\n\n" + error->data () + (error->has_more () ? "..." : ""))); + } else { + details_text->setText (tl::to_qstring (error->msg () + "\n\n" + format_hex_dump (error->data ()) + (error->has_more () ? "..." : ""))); + } + + details_text->setFont (lay::monospace_font ()); + details_frame->hide (); + + // "borrow" the error pixmap from the message box + QMessageBox *mb = new QMessageBox (QMessageBox::Critical, QString (), QString ()); + QPixmap error_icon = mb->iconPixmap (); + delete mb; + icon_label->setPixmap (error_icon); + + connect (details_pb, SIGNAL (clicked ()), this, SLOT (show_details ())); + + resize (size ().width (), 50); +} + +void +ReaderErrorForm::show_details () +{ + QString t (details_pb->text ()); + if (details_frame->isVisible ()) { + details_frame->hide (); + t.replace (QString::fromUtf8 ("<<"), QString::fromUtf8 (">>")); + // It looks like the minimum size is set to a too large value internally. + // Resetting it helps to keep a small-as-possible dialog size. + setMinimumSize (QSize (0, 0)); + resize (size ().width (), 0); + } else { + details_frame->show (); + t.replace (QString::fromUtf8 (">>"), QString::fromUtf8 ("<<")); + resize (size ().width (), sizeHint ().height ()); + } + details_pb->setText (t); +} + +} + diff --git a/src/lay/lay/layReaderErrorForm.h b/src/lay/lay/layReaderErrorForm.h new file mode 100644 index 000000000..81071f7db --- /dev/null +++ b/src/lay/lay/layReaderErrorForm.h @@ -0,0 +1,57 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_rbaReaderErrorForm +#define HDR_rbaReaderErrorForm + +#include +#include + +#include + +#include "ui_ReaderErrorForm.h" + +namespace db +{ + class ReaderUnknownFormatException; +} + +namespace lay +{ + +class ReaderErrorForm + : public QDialog, private Ui::ReaderErrorForm +{ + Q_OBJECT + +public: + ReaderErrorForm (QWidget *parent, const char *name, const db::ReaderUnknownFormatException *error); + +public slots: + void show_details (); +}; + +} + +#endif +