From 1cfacb54db152f97ca1a04d3a2e1912cbbf1bd58 Mon Sep 17 00:00:00 2001 From: Viktor Kopp Date: Thu, 26 Sep 2024 10:58:58 +0200 Subject: [PATCH 01/21] Run unit tests for Linux on CI (#538) * Build unit tests on CI * Run tests upon Linux build on CI * Accelerate linux build Signed-off-by: Viktor Kopp --- .github/workflows/BuildPR.yml | 2 ++ qdlt/CMakeLists.txt | 1 + qdlt/tests/CMakeLists.txt | 5 +++++ scripts/linux/build.sh | 7 +++++-- scripts/linux/install.sh | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/BuildPR.yml b/.github/workflows/BuildPR.yml index c5b1e0de..d399e8ef 100644 --- a/.github/workflows/BuildPR.yml +++ b/.github/workflows/BuildPR.yml @@ -124,6 +124,8 @@ jobs: run: scripts/linux/install.sh - name: Build project run: scripts/linux/build.sh + - name: Run tests + run: ctest --test-dir build/qdlt - name: Make artifact executable run: chmod -R +x build/dist - name: Archive artifact diff --git a/qdlt/CMakeLists.txt b/qdlt/CMakeLists.txt index 4ee1e017..80fa297d 100644 --- a/qdlt/CMakeLists.txt +++ b/qdlt/CMakeLists.txt @@ -123,6 +123,7 @@ endforeach() find_package(GTest) # configure unit tests only if gtest found on the system if (GTest_FOUND) + message(STATUS "Tests enabled") enable_testing() add_subdirectory(tests) endif() diff --git a/qdlt/tests/CMakeLists.txt b/qdlt/tests/CMakeLists.txt index 13b400a4..beccd1f3 100644 --- a/qdlt/tests/CMakeLists.txt +++ b/qdlt/tests/CMakeLists.txt @@ -8,3 +8,8 @@ target_link_libraries( qdlt ) +add_test( + NAME test_tools + COMMAND $ +) + diff --git a/scripts/linux/build.sh b/scripts/linux/build.sh index 42ce0dca..3c36089b 100755 --- a/scripts/linux/build.sh +++ b/scripts/linux/build.sh @@ -9,6 +9,9 @@ BUILD_DIR="${SRC_DIR}/build" INSTALL_DIR="${BUILD_DIR}/install" APP_DIR_NAME="DLTViewer" +NPROC=$(nproc) +echo Nb of cpus: ${NPROC} + rm -rf "${APP_DIR_NAME}" rm -rf "${SRC_DIR}/build" mkdir -p "${BUILD_DIR}" @@ -16,7 +19,7 @@ cd "${BUILD_DIR}" echo Build with QMake qmake ../BuildDltViewer.pro -make +make -j ${NPROC} echo Cleanup rm -rf "${INSTALL_DIR}" @@ -37,7 +40,7 @@ cmake -G Ninja \ -DDLT_RESOURCE_INSTALLATION_PATH="${APP_DIR_NAME}/usr/share" \ -DDLT_PLUGIN_INSTALLATION_PATH="${APP_DIR_NAME}/usr/bin/plugins" \ "${SRC_DIR}" -cmake --build "${BUILD_DIR}" -v +cmake --build "${BUILD_DIR}" -j ${NPROC} -v # External CPack generator calls "cmake --install" and "linuxdeploy" # diff --git a/scripts/linux/install.sh b/scripts/linux/install.sh index dc6c2e1d..6bff11ea 100755 --- a/scripts/linux/install.sh +++ b/scripts/linux/install.sh @@ -23,7 +23,7 @@ sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update sudo apt install -y git cmake build-essential ninja-build \ qt515declarative qt515serialport qt515charts-no-lgpl qt515svg \ - libgtk2.0-dev libgl-dev gcc-11 g++-11 + libgtk2.0-dev libgl-dev gcc-11 g++-11 libgtest-dev sudo update-alternatives --remove-all cpp sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 110 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11 --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-11 --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-11 --slave /usr/bin/cpp cpp /usr/bin/cpp-11 From 9a7797694967f0dac6fc2be2f3e2d0021079cb16 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Thu, 26 Sep 2024 12:56:54 +0200 Subject: [PATCH 02/21] Fix qmake build (#544) Signed-off-by: Alexander Wenzel --- qdlt/qdlt.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qdlt/qdlt.pro b/qdlt/qdlt.pro index e51f5f40..978c5d6f 100644 --- a/qdlt/qdlt.pro +++ b/qdlt/qdlt.pro @@ -32,6 +32,8 @@ CONFIG += warn_on qt QT += network QT += serialport +win32:LIBS += User32.lib + # Put intermediate files in the build directory MOC_DIR = build/moc OBJECTS_DIR = build/obj From 2c27e80f478e9542bb5f3eedf55b7ddb36128e27 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Fri, 27 Sep 2024 12:05:12 +0200 Subject: [PATCH 03/21] Extend regex replace filter operation to all functionalities. (#545) Signed-off-by: Alexander Wenzel --- qdlt/qdltexporter.cpp | 13 +++++++++---- qdlt/qdltfile.cpp | 5 +++++ qdlt/qdltfile.h | 5 +++++ qdlt/qdltfilterlist.cpp | 23 +++++++++++++++++++++++ qdlt/qdltfilterlist.h | 5 +++++ src/mainwindow.cpp | 7 +++++++ src/tablemodel.cpp | 14 +++++++++++++- 7 files changed, 67 insertions(+), 5 deletions(-) diff --git a/qdlt/qdltexporter.cpp b/qdlt/qdltexporter.cpp index 26547ad1..9da4a130 100644 --- a/qdlt/qdltexporter.cpp +++ b/qdlt/qdltexporter.cpp @@ -69,7 +69,9 @@ void QDltExporter::writeCSVLine(int index, QFile *to, QDltMsg msg) text += escapeCSVValue(QString("%1").arg(msg.getSubtypeString())).append(delimiter); text += escapeCSVValue(QString("%1").arg(msg.getModeString())).append(delimiter); text += escapeCSVValue(QString("%1").arg(msg.getNumberOfArguments())).append(delimiter); - text += escapeCSVValue(msg.toStringPayload().simplified().remove(QChar::Null)); + QString payload = msg.toStringPayload().simplified().remove(QChar::Null); + if(from) from->applyRegExString(payload); + text += escapeCSVValue(payload); text += "\n"; to->write(text.toLatin1().constData()); @@ -280,7 +282,9 @@ bool QDltExporter::exportMsg(unsigned long int num, QDltMsg &msg, QByteArray &bu text += " "; } - text += msg.toStringPayload().simplified().remove(QChar::Null); + QString payload = msg.toStringPayload().simplified().remove(QChar::Null); + if(from) from->applyRegExString(payload); + text += payload; text += "\n"; try { @@ -326,11 +330,13 @@ bool QDltExporter::exportMsg(unsigned long int num, QDltMsg &msg, QByteArray &bu text += "|" + QString("%1.%2").arg(msg.getGmTimeWithOffsetString(utcOffset,dst)).arg(msg.getMicroseconds(),6,10,QLatin1Char('0')); else text += "|" + QString("%1.%2").arg(msg.getTimeString()).arg(msg.getMicroseconds(),6,10,QLatin1Char('0')); + QString payload = msg.toStringPayload().simplified().remove(QChar::Null); + if(from) from->applyRegExString(payload); text += "|" + QString("%1.%2").arg(msg.getTimestamp()/10000).arg(msg.getTimestamp()%10000,4,10,QLatin1Char('0')) + "|" + msg.getEcuid() + "|" + msg.getApid() + "|" + msg.getCtid() + - "|" + msg.toStringPayload().simplified().remove(QChar::Null).replace('|', "\\|").replace('#', "\\#").replace('*', "\\*") + + "|" + payload.replace('|', "\\|").replace('#', "\\#").replace('*', "\\*") + "| |\n"; clipboardString += text; } @@ -374,7 +380,6 @@ void QDltExporter::exportMessages(QDltFile *from, QFile *to, QDltPluginManager * return; } - bool silentMode = !QDltOptManager::getInstance()->issilentMode(); if ( this->stoping_index == 0 || this->stoping_index > this->size || this->stoping_index < this->starting_index ) diff --git a/qdlt/qdltfile.cpp b/qdlt/qdltfile.cpp index d2ef5b53..d49733a3 100644 --- a/qdlt/qdltfile.cpp +++ b/qdlt/qdltfile.cpp @@ -754,3 +754,8 @@ void QDltFile::setIndexFilter(QVector _indexFilter) { indexFilter = _indexFilter; } + +bool QDltFile::applyRegExString(QString &text) +{ + return filterList.applyRegExString(text); +} diff --git a/qdlt/qdltfile.h b/qdlt/qdltfile.h index 92a2cd15..06a8df94 100644 --- a/qdlt/qdltfile.h +++ b/qdlt/qdltfile.h @@ -299,6 +299,11 @@ class QDLT_EXPORT QDltFile : public QDlt **/ bool getDLTv2Support() const; + //! Apply RegEx Replace to the string, if any active in the filters + /*! + */ + bool applyRegExString(QString &text); + protected: private: diff --git a/qdlt/qdltfilterlist.cpp b/qdlt/qdltfilterlist.cpp index abe2f747..d53bec82 100644 --- a/qdlt/qdltfilterlist.cpp +++ b/qdlt/qdltfilterlist.cpp @@ -19,6 +19,9 @@ * @licence end@ */ +#include +#include + #include #include @@ -121,6 +124,26 @@ QString QDltFilterList::checkMarker(QDltMsg &msg) #endif +bool QDltFilterList::applyRegExString(QString &text) +{ + QDltFilter *filter; + bool result = false; + + for(int numfilter=0;numfilterenableFilter && filter->enableRegexSearchReplace) + { + std::regex regex(filter->regex_search.toStdString()); + std::string payload_str = std::regex_replace(text.toStdString(), regex, filter->regex_replace.toStdString()); + text = QString::fromStdString(payload_str); + result = true; + } + } + return result; +} + bool QDltFilterList::checkFilter(QDltMsg &msg) { QDltFilter *filter; diff --git a/qdlt/qdltfilterlist.h b/qdlt/qdltfilterlist.h index b2f6a2a7..81efab30 100644 --- a/qdlt/qdltfilterlist.h +++ b/qdlt/qdltfilterlist.h @@ -122,6 +122,11 @@ class QDLT_EXPORT QDltFilterList */ void updateSortedFilter(); + //! Apply RegEx Replace to the string, if any active in the filters. + /*! + */ + bool applyRegExString(QString &text); + protected: private: diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 169ede80..6f589a8d 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -143,6 +143,8 @@ MainWindow::MainWindow(QWidget *parent) : } + filterUpdate(); // update filters of qfile before starting Exporting for RegEx operation + if(!QDltOptManager::getInstance()->getConvertDestFile().isEmpty()) { switch ( QDltOptManager::getInstance()->get_convertionmode() ) @@ -1552,6 +1554,7 @@ void MainWindow::exportSelection(bool ascii = true,bool file = false,QDltExporte QModelIndexList list = ui->tableView->selectionModel()->selection().indexes(); + filterUpdate(); // update filters of qfile before starting Exporting for RegEx operation QDltExporter exporter(project.settings->automaticTimeSettings,project.settings->utcOffset,project.settings->dst,QDltOptManager::getInstance()->getDelimiter()); connect(&exporter,SIGNAL(clipboard(QString)),this,SLOT(clipboard(QString))); @@ -1589,6 +1592,8 @@ void MainWindow::exportSelection_searchTable(QDltExporter::DltExportFormat forma QModelIndexList finallist = ui->tableView->selectionModel()->selection().indexes(); + filterUpdate(); // update filters of qfile before starting Exporting for RegEx operation + QDltExporter exporter(project.settings->automaticTimeSettings,project.settings->utcOffset,project.settings->dst,QDltOptManager::getInstance()->getDelimiter()); connect(&exporter,SIGNAL(clipboard(QString)),this,SLOT(clipboard(QString))); exporter.exportMessages(&qfile,0,&pluginManager,format,QDltExporter::SelectionSelected,&finallist); @@ -1695,6 +1700,8 @@ void MainWindow::on_actionExport_triggered() unsigned long int startix, stopix; exporterDialog.getRange(&startix,&stopix); + filterUpdate(); // update filters of qfile before starting Exporting for RegEx operation + connect(&exporter,SIGNAL(progress(QString,int,int)),this,SLOT(progress(QString,int,int))); if(exportSelection == QDltExporter::SelectionSelected) // marked messages { diff --git a/src/tablemodel.cpp b/src/tablemodel.cpp index 0378ea61..619dc35a 100644 --- a/src/tablemodel.cpp +++ b/src/tablemodel.cpp @@ -369,7 +369,19 @@ TableModel::TableModel(const QString & /*data*/, QObject *parent) msg = last_decoded_msg; } } - return msg.toStringPayload().simplified().remove(QChar::Null); + + QString visu_data = msg.toStringPayload().simplified().remove(QChar::Null); + if((QDltSettingsManager::getInstance()->value("startup/filtersEnabled", true).toBool())) + { + for(int num = 0; num < project->filter->topLevelItemCount (); num++) { + FilterItem *item = (FilterItem*)project->filter->topLevelItem(num); + if(item->checkState(0) == Qt::Checked && item->filter.enableRegexSearchReplace) { + apply_regex_string(visu_data, item->filter.regex_search, item->filter.regex_replace); + } + } + } + + return visu_data; } return QVariant(); From d46c8d9e24e333ace3f673d26ca33b90463c72b0 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Fri, 27 Sep 2024 16:11:38 +0200 Subject: [PATCH 04/21] Change regex replace func from std to qt internal. (#546) CAUTION: Replacement placeholder changes from %1 to \1 . Signed-off-by: Alexander Wenzel --- qdlt/qdltfilterlist.cpp | 4 +--- src/regex_search_replace.h | 18 ------------------ src/searchtablemodel.cpp | 3 +-- src/src.pro | 3 +-- src/tablemodel.cpp | 5 ++--- 5 files changed, 5 insertions(+), 28 deletions(-) delete mode 100644 src/regex_search_replace.h diff --git a/qdlt/qdltfilterlist.cpp b/qdlt/qdltfilterlist.cpp index d53bec82..413add34 100644 --- a/qdlt/qdltfilterlist.cpp +++ b/qdlt/qdltfilterlist.cpp @@ -135,9 +135,7 @@ bool QDltFilterList::applyRegExString(QString &text) if(filter->enableFilter && filter->enableRegexSearchReplace) { - std::regex regex(filter->regex_search.toStdString()); - std::string payload_str = std::regex_replace(text.toStdString(), regex, filter->regex_replace.toStdString()); - text = QString::fromStdString(payload_str); + text.replace(QRegularExpression(filter->regex_search), filter->regex_replace); result = true; } } diff --git a/src/regex_search_replace.h b/src/regex_search_replace.h deleted file mode 100644 index 05c01224..00000000 --- a/src/regex_search_replace.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef REGEX_SEARCH_REPLACE_H -#define REGEX_SEARCH_REPLACE_H - -#include -#include -#include - - -static void apply_regex_string(QString &data, const QString& regex_search, const QString& regex_replace) -{ - std::regex regex(regex_search.toStdString()); - - std::string payload_str = std::regex_replace(data.toStdString(), regex, regex_replace.toStdString()); - - data = QString::fromStdString(payload_str); -} - -#endif // REGEX_SEARCH_REPLACE_H diff --git a/src/searchtablemodel.cpp b/src/searchtablemodel.cpp index cfd5b99b..e0abba56 100644 --- a/src/searchtablemodel.cpp +++ b/src/searchtablemodel.cpp @@ -21,7 +21,6 @@ #include "fieldnames.h" #include "dltuiutils.h" #include "dlt_protocol.h" -#include "regex_search_replace.h" #include "qdltoptmanager.h" @@ -169,7 +168,7 @@ QVariant SearchTableModel::data(const QModelIndex &index, int role) const for(int num = 0; num < project->filter->topLevelItemCount (); num++) { FilterItem *item = (FilterItem*)project->filter->topLevelItem(num); if(item->checkState(0) == Qt::Checked && item->filter.enableRegexSearchReplace) { - apply_regex_string(visu_data, item->filter.regex_search, item->filter.regex_replace); + visu_data.replace(QRegularExpression(item->filter.regex_search), item->filter.regex_replace); } } } diff --git a/src/src.pro b/src/src.pro index 423afb2b..ee4bfd03 100644 --- a/src/src.pro +++ b/src/src.pro @@ -181,8 +181,7 @@ HEADERS += mainwindow.h \ dltmsgqueue.h \ dltfileindexerthread.h \ dltfileindexerdefaultfilterthread.h \ - mcudpsocket.h \ - regex_search_replace.h + mcudpsocket.h # Compile these UI files FORMS += mainwindow.ui \ diff --git a/src/tablemodel.cpp b/src/tablemodel.cpp index 619dc35a..1018ff28 100644 --- a/src/tablemodel.cpp +++ b/src/tablemodel.cpp @@ -26,7 +26,6 @@ #include "dltuiutils.h" #include "dlt_protocol.h" #include "qdltoptmanager.h" -#include "regex_search_replace.h" static long int lastrow = -1; // necessary because object tablemodel can not be changed, so no member variable can be used char buffer[DLT_VIEWER_LIST_BUFFER_SIZE]; @@ -255,7 +254,7 @@ TableModel::TableModel(const QString & /*data*/, QObject *parent) for(int num = 0; num < project->filter->topLevelItemCount (); num++) { FilterItem *item = (FilterItem*)project->filter->topLevelItem(num); if(item->checkState(0) == Qt::Checked && item->filter.enableRegexSearchReplace) { - apply_regex_string(visu_data, item->filter.regex_search, item->filter.regex_replace); + visu_data.replace(QRegularExpression(item->filter.regex_search), item->filter.regex_replace); } } } @@ -376,7 +375,7 @@ TableModel::TableModel(const QString & /*data*/, QObject *parent) for(int num = 0; num < project->filter->topLevelItemCount (); num++) { FilterItem *item = (FilterItem*)project->filter->topLevelItem(num); if(item->checkState(0) == Qt::Checked && item->filter.enableRegexSearchReplace) { - apply_regex_string(visu_data, item->filter.regex_search, item->filter.regex_replace); + visu_data.replace(QRegularExpression(item->filter.regex_search), item->filter.regex_replace); } } } From e73736b4423b0867963b42d614acd119339716be Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Sun, 29 Sep 2024 14:51:09 +0200 Subject: [PATCH 05/21] Fix MAcOS release artifacts --- .github/workflows/Release.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 58383274..3a2468ce 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -35,13 +35,20 @@ jobs: run: scripts/darwin/install.sh - name: Build project run: scripts/darwin/build.sh + - name: Artifact Creation + run: | + cd /Users/runner/work/dlt-viewer/dlt-viewer/build + mkdir -p dist + cp ../scripts/darwin/install.md dist + tar -czvf "dist/DLTViewer.tgz" -C /Users/runner/work/dlt-viewer/dlt-viewer/build/install . - name: Archive artifact run: zip DLT-macOS-${{ matrix.abi }}.zip -r build/dist - - name: Upload DLT artifact + - name: Archive artifact uses: actions/upload-artifact@v4 + if: ${{ success() }} with: name: DLT-Mac-${{ matrix.abi }} - path: DLT-macOS-${{ matrix.abi }}.zip + path: build/dist/DLTViewer*.tgz buildLinux: name: Build ${{ matrix.ubuntu }} From 7b1c7f9981148cead4f74f8dbd4e96a6d2485c40 Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Sun, 29 Sep 2024 16:13:59 +0200 Subject: [PATCH 06/21] MacOS release with codesign and notarization --- .github/workflows/Release.yml | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 3a2468ce..3a3f46e5 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -35,6 +35,61 @@ jobs: run: scripts/darwin/install.sh - name: Build project run: scripts/darwin/build.sh + - name: Codesign app bundle + if: "! github.event.pull_request.head.repo.fork " # not running on a fork + # Extract the secrets we defined earlier as environment variables + env: + MACOS_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + MACOS_CERTIFICATE_PWD: ${{ secrets.P12_PASSWORD }} + MACOS_CERTIFICATE_NAME: ${{ secrets.APPLE_CERTIFICATE_NAME }} + MACOS_CI_KEYCHAIN_PWD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + # Turn our base64-encoded certificate back to a regular .p12 file + + echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12 + # We need to create a new keychain, otherwise using the certificate will prompt + # with a UI dialog asking for the certificate password, which we can't + # use in a headless CI environment + + security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain + security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain + + # We finally codesign our app bundle, specifying the Hardened runtime option + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/Frameworks/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/Resources/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/PlugIns/bearer/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents//PlugIns/iconengines/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/PlugIns/imageformats/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/PlugIns/platforminputcontexts/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/PlugIns/platforms/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/PlugIns/printsupport/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/PlugIns/styles/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/PlugIns/virtualkeyboard/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/MacOS/plugins/* + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/MacOS/dlt-commander + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app/Contents/MacOS/dlt-viewer + /usr/bin/codesign --timestamp --options=runtime -s "$MACOS_CERTIFICATE_NAME" -f -v /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app + - name: Notarize app bundle + if: "! github.event.pull_request.head.repo.fork " # not running on a fork + env: + PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_ID }} + PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.TEAM_ID }} + PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.APP_PASSWORD }} + run: | + echo "Create keychain profile" + xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD" + echo "Creating temp notarization archive" + ditto -c -k --keepParent "/Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app" "/Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.zip" + + echo "Notarize app" + xcrun notarytool submit "/Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.zip" --keychain-profile "notarytool-profile" --wait + + echo "Attach staple" + xcrun stapler staple "/Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.app" + rm -r /Users/runner/work/dlt-viewer/dlt-viewer/build/install/DLTViewer.zip - name: Artifact Creation run: | cd /Users/runner/work/dlt-viewer/dlt-viewer/build From a76999c7d665021c8c774ffa56d786a0d5b35ee5 Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Sun, 29 Sep 2024 16:53:41 +0200 Subject: [PATCH 07/21] Include MacOS artifacts to release action --- .github/workflows/Release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 3a3f46e5..87519599 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -103,7 +103,7 @@ jobs: if: ${{ success() }} with: name: DLT-Mac-${{ matrix.abi }} - path: build/dist/DLTViewer*.tgz + path: DLT-macOS*.zip buildLinux: name: Build ${{ matrix.ubuntu }} From 69ed2dd7bf585783efd64ee59ff5e738fec6bb64 Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Mon, 30 Sep 2024 10:37:55 +0200 Subject: [PATCH 08/21] Reorder label in MacOS release job --- .github/workflows/Release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 87519599..c3292334 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -12,12 +12,12 @@ jobs: runs-on: ${{ matrix.macos }} strategy: matrix: - xcode: [ Xcode_15.2 ] abi: [ x86 ] macos: [ macos-13 ] + xcode: [ Xcode_15.2 ] include: - - macos: macos-14 - abi: arm64 + - abi: arm64 + macos: macos-14 xcode: Xcode steps: - name: Checkout From b44493f0f45898736c0d73cb2f01123c6767ffa6 Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Mon, 30 Sep 2024 10:37:55 +0200 Subject: [PATCH 09/21] Reorder label in MacOS release job --- .github/workflows/Release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index c3292334..e235fa01 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -12,12 +12,12 @@ jobs: runs-on: ${{ matrix.macos }} strategy: matrix: - abi: [ x86 ] macos: [ macos-13 ] + abi: [ x86 ] xcode: [ Xcode_15.2 ] include: - - abi: arm64 - macos: macos-14 + - macos: macos-14 + abi: arm64 xcode: Xcode steps: - name: Checkout From 65e9f2faf210babe23cd14642437caa4fd8dad3f Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Mon, 30 Sep 2024 15:04:45 +0200 Subject: [PATCH 10/21] Additional port 3489 for DLT MF4 Import. (#552) Signed-off-by: Alexander Wenzel --- qdlt/qdltimporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qdlt/qdltimporter.cpp b/qdlt/qdltimporter.cpp index a8a3656d..f40fe1d5 100644 --- a/qdlt/qdltimporter.cpp +++ b/qdlt/qdltimporter.cpp @@ -1052,7 +1052,7 @@ bool QDltImporter::dltFromEthernetFrame(QFile &outputfile,QByteArray &record,int return false; } quint16 destPort = (((quint16)record.at(pos))<<8)|((quint16)(record.at(pos+1)&0xff)); - if(destPort==3490) + if(destPort==3490||destPort==3489) { pos+=6; dltFrame(outputfile,record,pos,sec,usec); @@ -1073,7 +1073,7 @@ bool QDltImporter::dltFromEthernetFrame(QFile &outputfile,QByteArray &record,int return false; } quint16 destPort = (((quint16)segmentBufferUDP.at(pos))<<8)|((quint16)(segmentBufferUDP.at(pos+1)&0xff)); - if(destPort==3490) + if(destPort==3490||destPort==3489) { pos+=6; dltFrame(outputfile,segmentBufferUDP,pos,sec,usec); From 5058ad8ada8f104519b592c6c03c00a49d3e448c Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Wed, 2 Oct 2024 22:30:57 +0200 Subject: [PATCH 11/21] Improve speed of MF4 and PCAP import. (#553) Enable MF4 import of multiple data frames. Signed-off-by: Alexander Wenzel --- qdlt/qdltimporter.cpp | 296 +++++++++++++++++++++++++++--------------- qdlt/qdltimporter.h | 6 + 2 files changed, 194 insertions(+), 108 deletions(-) diff --git a/qdlt/qdltimporter.cpp b/qdlt/qdltimporter.cpp index f40fe1d5..3838f0fc 100644 --- a/qdlt/qdltimporter.cpp +++ b/qdlt/qdltimporter.cpp @@ -52,6 +52,12 @@ void QDltImporter::dltIpcFromPCAP(QFile &outputfile,QString fileName,QWidget *pa if(!inputfile.open(QFile::ReadOnly)) return; + /* open output file */ + if(!outputfile.open(QIODevice::WriteOnly|QIODevice::Append)) + { + qDebug() << "Failed opening WriteOnly" << outputfile.fileName(); + } + int progressCounter = 1; emit progress("PCAP",1,0); @@ -63,6 +69,7 @@ void QDltImporter::dltIpcFromPCAP(QFile &outputfile,QString fileName,QWidget *pa if(inputfile.read((char*)&globalHeader,sizeof(pcap_hdr_t))!=sizeof(pcap_hdr_t)) { inputfile.close(); + outputfile.close(); qDebug() << "fromPCAP:" << "Cannot open file" << fileName; return; } @@ -83,6 +90,7 @@ void QDltImporter::dltIpcFromPCAP(QFile &outputfile,QString fileName,QWidget *pa if(record.length() != recordHeader.incl_len) { inputfile.close(); + outputfile.close(); qDebug() << "fromPCAP: PCAP file not complete!"; qDebug() << "fromPCAP:" << "Size Error: Cannot read Record"; return; @@ -93,6 +101,7 @@ void QDltImporter::dltIpcFromPCAP(QFile &outputfile,QString fileName,QWidget *pa if(record.size()<(qsizetype)(pos+2)) { inputfile.close(); + outputfile.close(); qDebug() << "dltFromPCAP:" << "Size Error: Cannot read Record"; return; } @@ -101,17 +110,20 @@ void QDltImporter::dltIpcFromPCAP(QFile &outputfile,QString fileName,QWidget *pa if(!dltFromEthernetFrame(outputfile,record,pos,etherType,recordHeader.ts_sec,recordHeader.ts_usec)) { inputfile.close(); + outputfile.close(); qDebug() << "fromPCAP:" << "Size Error: Cannot read Ethernet Frame"; return; } if(!ipcFromEthernetFrame(outputfile,record,pos,etherType,recordHeader.ts_sec,recordHeader.ts_usec)) { inputfile.close(); + outputfile.close(); qDebug() << "fromPCAP:" << "Size Error: Cannot read Ethernet Frame"; return; } } inputfile.close(); + outputfile.close(); emit progress("",3,100); @@ -122,7 +134,6 @@ void QDltImporter::dltIpcFromPCAP(QFile &outputfile,QString fileName,QWidget *pa qDebug() << "fromPCAP: Counter IPC Mesages:" << counterIPCMessages; qDebug() << "fromPCAP: Import finished"; - } void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *parent,bool silent) @@ -146,6 +157,12 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par return; } + /* open output file */ + if(!outputfile.open(QIODevice::WriteOnly|QIODevice::Append)) + { + qDebug() << "Failed opening WriteOnly" << outputfile.fileName(); + } + int progressCounter = 1; emit progress("MF4",1,0); @@ -154,140 +171,182 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(inputfile.read((char*)&mdfIdblock,sizeof(mdf_idblock_t))!=sizeof(mdf_idblock_t)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot reard Id Block"; return; } mdf_hdr_t mdfHeader,mdfDgHeader,mdfCgHeader,mdfCnHeader,mdfTxHeader; + mdf_dgblocklinks_t mdfDgBlockLinks; memset((char*)&mdfHeader,0,sizeof(mdf_hdr_t)); quint64 pos=0,hd_pos=0,dt_pos=0; - - while(inputfile.read((char*)&mdfHeader,sizeof(mdf_hdr_t))==sizeof(mdf_hdr_t)) + if(inputfile.read((char*)&mdfHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) + { + inputfile.close(); + outputfile.close(); + qDebug() << "fromMF4:" << "Size Error: Cannot read mdf header"; + return; + } + if(!hd_pos && mdfHeader.id[0]=='#' && mdfHeader.id[1]=='#' && mdfHeader.id[2]=='H' && mdfHeader.id[3]=='D') { - //qDebug() << "pos" << pos; - if(!hd_pos && mdfHeader.id[0]=='#' && mdfHeader.id[1]=='#' && mdfHeader.id[2]=='H' && mdfHeader.id[3]=='D') + pos = inputfile.pos() - sizeof(mdf_hdr_t); + //qDebug() << "HD:"; + hd_pos=pos; + if(inputfile.read((char*)&hdBlockLinks,sizeof(mdf_hdblocklinks_t))!=sizeof(mdf_hdblocklinks_t)) { - pos = inputfile.pos() - sizeof(mdf_hdr_t); - //qDebug() << "HD:"; - hd_pos=pos; - if(inputfile.read((char*)&hdBlockLinks,sizeof(mdf_hdblocklinks_t))!=sizeof(mdf_hdblocklinks_t)) + inputfile.close(); + outputfile.close(); + qDebug() << "fromMF4:" << "Size Error: Cannot read HD Block"; + return; + } + // Iterate through all data groups + quint64 ptrDg = hdBlockLinks.hd_dg_first; + while(ptrDg) + { + inputfile.seek(ptrDg); + if(inputfile.read((char*)&mdfDgHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) { inputfile.close(); - qDebug() << "fromMF4:" << "Size Error: Cannot reard HD Block"; + outputfile.close(); + qDebug() << "fromMF4:" << "Size Error: Cannot reard DG Block"; return; } - // Iterate through all data groups - quint64 ptrDg = hdBlockLinks.hd_dg_first; - while(ptrDg) + if(mdfDgHeader.id[0]=='#' && mdfDgHeader.id[1]=='#' && mdfDgHeader.id[2]=='D' && mdfDgHeader.id[3]=='G') { - inputfile.seek(ptrDg); - if(inputfile.read((char*)&mdfDgHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) + //qDebug() << "\tDG:"; + if(inputfile.read((char*)&mdfDgBlockLinks,sizeof(mdf_dgblocklinks_t))!=sizeof(mdf_dgblocklinks_t)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot reard DG Block"; return; } - if(mdfDgHeader.id[0]=='#' && mdfDgHeader.id[1]=='#' && mdfDgHeader.id[2]=='D' && mdfDgHeader.id[3]=='G') + ptrDg=mdfDgBlockLinks.dg_dg_next; + // Iterate through all channel groups + quint64 ptrCg = mdfDgBlockLinks.dg_cg_first; + while(ptrCg) { - //qDebug() << "\tDG:"; - mdf_dgblocklinks_t mdfDgBlockLinks; - if(inputfile.read((char*)&mdfDgBlockLinks,sizeof(mdf_dgblocklinks_t))!=sizeof(mdf_dgblocklinks_t)) + inputfile.seek(ptrCg); + if(inputfile.read((char*)&mdfCgHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) { inputfile.close(); - qDebug() << "fromMF4:" << "Size Error: Cannot reard DG Block"; + outputfile.close(); + qDebug() << "fromMF4:" << "Size Error: Cannot reard CG Block"; return; } - ptrDg=mdfDgBlockLinks.dg_dg_next; - // Iterate through all channel groups - quint64 ptrCg = mdfDgBlockLinks.dg_cg_first; - while(ptrCg) + if(mdfCgHeader.id[0]=='#' && mdfCgHeader.id[1]=='#' && mdfCgHeader.id[2]=='C' && mdfCgHeader.id[3]=='G') { - inputfile.seek(ptrCg); - if(inputfile.read((char*)&mdfCgHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) + //qDebug() << "\t\tCG:"; + mdf_cgblocklinks_t mdfCgBlockLinks; + if(inputfile.read((char*)&mdfCgBlockLinks,sizeof(mdf_cgblocklinks_t))!=sizeof(mdf_cgblocklinks_t)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot reard CG Block"; return; } - if(mdfCgHeader.id[0]=='#' && mdfCgHeader.id[1]=='#' && mdfCgHeader.id[2]=='C' && mdfCgHeader.id[3]=='G') + //qDebug() << "\t\cg_record_id =" << mdfCgBlockLinks.cg_record_id; + //qDebug() << "\t\cg_data_bytes =" << mdfCgBlockLinks.cg_data_bytes; + ptrCg=mdfCgBlockLinks.cg_cg_next; + if(mdfCgBlockLinks.cg_flags&1) // VLSD + channelGroupLength[mdfCgBlockLinks.cg_record_id]=-1; + else + channelGroupLength[mdfCgBlockLinks.cg_record_id]=mdfCgBlockLinks.cg_data_bytes; + // Iterate through all channels + quint64 ptrCh = mdfCgBlockLinks.cg_cn_first; + while(ptrCh) { - //qDebug() << "\t\tCG:"; - mdf_cgblocklinks_t mdfCgBlockLinks; - if(inputfile.read((char*)&mdfCgBlockLinks,sizeof(mdf_cgblocklinks_t))!=sizeof(mdf_cgblocklinks_t)) + inputfile.seek(ptrCh); + if(inputfile.read((char*)&mdfCnHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) { + qDebug() << "fromMF4:" << "Size Error: Cannot reard CN Block"; inputfile.close(); - qDebug() << "fromMF4:" << "Size Error: Cannot reard CG Block"; + outputfile.close(); return; } - //qDebug() << "\t\cg_record_id =" << mdfCgBlockLinks.cg_record_id; - //qDebug() << "\t\cg_data_bytes =" << mdfCgBlockLinks.cg_data_bytes; - ptrCg=mdfCgBlockLinks.cg_cg_next; - if(mdfCgBlockLinks.cg_flags&1) // VLSD - channelGroupLength[mdfCgBlockLinks.cg_record_id]=-1; - else - channelGroupLength[mdfCgBlockLinks.cg_record_id]=mdfCgBlockLinks.cg_data_bytes; - // Iterate through all channels - quint64 ptrCh = mdfCgBlockLinks.cg_cn_first; - while(ptrCh) + if(mdfCnHeader.id[0]=='#' && mdfCnHeader.id[1]=='#' && mdfCnHeader.id[2]=='C' && mdfCnHeader.id[3]=='N') { - inputfile.seek(ptrCh); - if(inputfile.read((char*)&mdfCnHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) + //qDebug() << "\t\t\tCN:"; + mdf_cnblocklinks_t mdfChBlockLinks; + if(inputfile.read((char*)&mdfChBlockLinks,sizeof(mdf_cnblocklinks_t))!=sizeof(mdf_cnblocklinks_t)) { - qDebug() << "fromMF4:" << "Size Error: Cannot reard CN Block"; inputfile.close(); + outputfile.close(); + qDebug() << "fromMF4:" << "Size Error: Cannot reard CN Block"; return; } - if(mdfCnHeader.id[0]=='#' && mdfCnHeader.id[1]=='#' && mdfCnHeader.id[2]=='C' && mdfCnHeader.id[3]=='N') + ptrCh=mdfChBlockLinks.cn_cn_next; + // Read channel name + inputfile.seek(mdfChBlockLinks.cn_tx_name); + if(inputfile.read((char*)&mdfTxHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) { - //qDebug() << "\t\t\tCN:"; - mdf_cnblocklinks_t mdfChBlockLinks; - if(inputfile.read((char*)&mdfChBlockLinks,sizeof(mdf_cnblocklinks_t))!=sizeof(mdf_cnblocklinks_t)) - { - inputfile.close(); - qDebug() << "fromMF4:" << "Size Error: Cannot reard CN Block"; - return; - } - ptrCh=mdfChBlockLinks.cn_cn_next; - // Read channel name - inputfile.seek(mdfChBlockLinks.cn_tx_name); - if(inputfile.read((char*)&mdfTxHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) + inputfile.close(); + outputfile.close(); + qDebug() << "fromMF4:" << "Size Error: Cannot reard Tx Block"; + return; + } + char cnName[256]; + memset(cnName,0,256); + + const auto cnNameLength = mdfTxHeader.length-sizeof(mdf_hdr_t); + if(cnNameLength < 256) { + const quint64 cnNameReadLength = inputfile.read((char*)cnName, cnNameLength); + if(cnNameReadLength != cnNameLength ) { inputfile.close(); - qDebug() << "fromMF4:" << "Size Error: Cannot reard Tx Block"; + outputfile.close(); + qDebug() << "fromMF4:" << "Size Error: Cannot read cn name"; return; } - char cnName[256]; - memset(cnName,0,256); - - const auto cnNameLength = mdfTxHeader.length-sizeof(mdf_hdr_t); - if(cnNameLength < 256) { - const quint64 cnNameReadLength = inputfile.read((char*)cnName, cnNameLength); - if(cnNameReadLength != cnNameLength ) - { - inputfile.close(); - qDebug() << "fromMF4:" << "Size Error: Cannot read cn name"; - return; - } - } - // FIXME: this is probably a bug if this line is reached because cnNameLength >= 256, since cnName is 0-initialized 256-bytes array - channelGroupName[mdfCgBlockLinks.cg_record_id] = QString(cnName); - //qDebug() << "fromMF4: cnName=" << cnName; - } - else - ptrCh=0; + // FIXME: this is probably a bug if this line is reached because cnNameLength >= 256, since cnName is 0-initialized 256-bytes array + channelGroupName[mdfCgBlockLinks.cg_record_id] = QString(cnName); + //qDebug() << "fromMF4: cnName=" << cnName; + } + else + ptrCh=0; } - else - ptrCg=0; } + else + ptrCg=0; } - else - ptrDg=0; } + else + ptrDg=0; + } + } + // seek to and read data list header + inputfile.seek(mdfDgBlockLinks.dg_data); + if(inputfile.read((char*)&mdfHeader,sizeof(mdf_hdr_t))!=sizeof(mdf_hdr_t)) + { + inputfile.close(); + outputfile.close(); + qDebug() << "fromMF4: Cannot read datalist header"; + return; + } + int numberOfLinks = mdfHeader.link_count; + for(int num=1;num0) && ((percent%10)==0)) + { qDebug() << "Import MF4:" << percent << "%"; // every 10% + } } + //qDebug() << "Record:" << counterRecords << pos << posDt; // TODO: Handle cancel operation @@ -318,6 +380,7 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(inputfile.read((char*)&recordId,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } @@ -332,6 +395,7 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(inputfile.read((char*)&lengthVLSD,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } @@ -346,54 +410,63 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(inputfile.read((char*)ðFrame.timeStamp,sizeof(quint64))!=sizeof(quint64)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.asynchronous,sizeof(quint8))!=sizeof(quint8)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.source,6)!=6) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.destination,6)!=6) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.etherType,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.crc,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.receivedDataByteCount,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.dataLength,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.dataBytes,sizeof(quint64))!=sizeof(quint64)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } @@ -404,6 +477,7 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(!dltFromEthernetFrame(outputfile,recordData,pos,ethFrame.etherType,time/1000000000,time%1000000000/1000)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4: ERROR:" << "Size Error: Cannot read Ethernet Frame"; return; } @@ -411,6 +485,7 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(!ipcFromEthernetFrame(outputfile,recordData,pos,ethFrame.etherType,time/1000000000,time%1000000000/1000)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4: ERROR:" << "Size Error: Cannot read Ethernet Frame"; return; } @@ -424,60 +499,70 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(inputfile.read((char*)ðFrame.timeStamp,sizeof(quint64))!=sizeof(quint64)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.asynchronous,sizeof(quint8))!=sizeof(quint8)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.source,6)!=6) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.destination,6)!=6) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.etherType,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.crc,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.receivedDataByteCount,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.beaconTimeStamp,sizeof(quint64))!=sizeof(quint64)) // TODO: Beacon Time Stamp { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.dataLength,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)ðFrame.dataBytes,sizeof(quint64))!=sizeof(quint64)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } @@ -488,6 +573,7 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(!dltFromEthernetFrame(outputfile,recordData,pos,ethFrame.etherType,time/1000000000,time%1000000000/1000)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4: ERROR:" << "Size Error: Cannot read Ethernet Frame"; return; } @@ -495,6 +581,7 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(!ipcFromEthernetFrame(outputfile,recordData,pos,ethFrame.etherType,time/1000000000,time%1000000000/1000)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4: ERROR:" << "Size Error: Cannot read Ethernet Frame"; return; } @@ -508,42 +595,49 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(inputfile.read((char*)&dltFrameBlock.timeStamp,sizeof(quint64))!=sizeof(quint64)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&dltFrameBlock.asynchronous,sizeof(quint8))!=sizeof(quint8)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&dltFrameBlock.currentFragmentNumber,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&dltFrameBlock.lastFragmentNumber,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&dltFrameBlock.ecuId,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&dltFrameBlock.dataLength,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&dltFrameBlock.dataBytes,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } @@ -554,6 +648,7 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(!dltFrame(outputfile,recordData,pos,time/1000000000,time%1000000000/1000)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4: ERROR:" << "Size Error: Cannot read DLTFrame"; return; } @@ -567,54 +662,63 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(inputfile.read((char*)&plpRaw.timeStamp,sizeof(quint64))!=sizeof(quint64)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&plpRaw.asynchronous,sizeof(quint8))!=sizeof(quint8)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&plpRaw.probeId,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&plpRaw.msgType,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&plpRaw.probeFlags,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&plpRaw.dataFlags,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&plpRaw.dataCounter,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&plpRaw.dataLength,sizeof(quint16))!=sizeof(quint16)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } if(inputfile.read((char*)&plpRaw.dataBytes,sizeof(quint32))!=sizeof(quint32)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4:" << "Size Error: Cannot read Record"; return; } @@ -624,6 +728,7 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par if(!ipcFromPlpRaw(&plpRaw,outputfile,recordData,time/1000000000,time%1000000000/1000)) { inputfile.close(); + outputfile.close(); qDebug() << "fromMF4: ERROR:" << "Size Error: Cannot read Ethernet Frame"; return; } @@ -644,28 +749,11 @@ void QDltImporter::dltIpcFromMF4(QFile &outputfile,QString fileName,QWidget *par break; } } - - } - else if(mdfHeader.id[0]==0 && mdfHeader.id[1]==0 && mdfHeader.id[2]==0 && mdfHeader.id[3]==0) - { - // end reached - break; - } - if(dt_pos && hd_pos) - { - // all blocks found end reading - break; - } - //qDebug() << "pos+mdfHeader.length" << pos+mdfHeader.length; - if(inputfile.size()< (pos+mdfHeader.length)) - { - qDebug() << "fromMF4: ERROR: Header length size error."; - break; } - inputfile.seek(pos+mdfHeader.length); } inputfile.close(); + outputfile.close(); emit progress("",3,100); @@ -1125,12 +1213,6 @@ void QDltImporter::writeDLTMessageToFile(QFile &outputfile,QByteArray &bufferHea } dlt_set_id(str.ecu, ecuId.toLatin1()); - /* check if message is matching the filter */ - if(!outputfile.open(QIODevice::WriteOnly|QIODevice::Append)) - { - qDebug() << "Failed opening WriteOnly" << outputfile.fileName(); - } - // write data into file //if(!ecuitem || !ecuitem->getWriteDLTv2StorageHeader()) { @@ -1154,8 +1236,6 @@ void QDltImporter::writeDLTMessageToFile(QFile &outputfile,QByteArray &bufferHea }*/ outputfile.write(bufferHeader); outputfile.write(bufferPayload,bufferPayloadSize); - outputfile.flush(); - outputfile.close(); } diff --git a/qdlt/qdltimporter.h b/qdlt/qdltimporter.h index b6fff3cc..d21d5117 100644 --- a/qdlt/qdltimporter.h +++ b/qdlt/qdltimporter.h @@ -75,6 +75,12 @@ typedef struct mdf_dgblocklinks { quint64 dg_md_comment; } PACKED mdf_dgblocklinks_t; +typedef struct mdf_dlblocklinks { + quint8 dl_flags; + quint8 reserved[3]; + quint32 dl_count; +} PACKED mdf_dlblocklinks_t; + typedef struct mdf_cgblocklinks { quint64 cg_cg_next; quint64 cg_cn_first; From 5bab5b51af779d4f5a0413d69896cbc9a24dcf06 Mon Sep 17 00:00:00 2001 From: Viktor Kopp Date: Wed, 9 Oct 2024 13:22:45 +0200 Subject: [PATCH 12/21] Use QCommandLineParser instead of custom cmd args parsing (#543) - avoid code duplication by reusing help text in main window - add tests Add QDltOptManager::reset method to have possibility to test the singleton Signed-off-by: Viktor Kopp --- qdlt/qdltoptmanager.cpp | 332 +++++++++++++++--------------- qdlt/qdltoptmanager.h | 12 +- qdlt/tests/CMakeLists.txt | 24 ++- qdlt/tests/test_dltoptmanager.cpp | 171 +++++++++++++++ src/main.cpp | 3 +- src/mainwindow.cpp | 39 +--- 6 files changed, 375 insertions(+), 206 deletions(-) create mode 100644 qdlt/tests/test_dltoptmanager.cpp diff --git a/qdlt/qdltoptmanager.cpp b/qdlt/qdltoptmanager.cpp index c422b762..bf363052 100644 --- a/qdlt/qdltoptmanager.cpp +++ b/qdlt/qdltoptmanager.cpp @@ -23,6 +23,7 @@ #include "qdltoptmanager.h" #include "version.h" + #include #include @@ -37,6 +38,31 @@ QDltOptManager::QDltOptManager() convertionmode = e_ASCI; commandline_mode = false; delimiter=','; + + m_parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + + m_parser.addPositionalArgument("logfile", "Loading one or more logfiles on startup (must end with .dlt)"); + m_parser.addPositionalArgument("projectfile", "Loading project file on startup (must end with .dlp)"); + m_parser.addPositionalArgument("filterfile", "Loading filterfile on startup (must end with .dlf)"); + m_parser.addPositionalArgument("pcapfile", "Importing DLT/IPC from pcap file on startup (must end with .pcap)"); + m_parser.addPositionalArgument("mf4file", "Importing DLT/IPC from mf4 file on startup (must end with .mf4)"); + m_parser.addOptions({ + {"c", "Convert logfile file to ", "textfile"}, + {"u", "Conversion will be done in UTF8 instead of ASCII"}, + {"csv", "Conversion will be done in CSV format"}, + {"d", "Conversion will NOT be done, save in dlt file format again instead"}, + {"dd", "Conversion will NOT be done, save as decoded messages in dlt format"}, + {"b", "Execute a plugin command with parameters before loading log file.", "plugin|command|param1|..|param"}, + {"e", "Execute a plugin command with parameters after loading log file.", "plugin|command|param1|..|param"}, + {QStringList() << "s" << "silent", "Enable silent mode without any GUI. Ideal for commandline usage."}, + {"stream", "Treat the input logfiles as DLT stream instead of DLT files."}, + {QStringList() << "t" << "terminate", "Terminate DLT Viewer after command line execution."}, + {"w", "Set the working directory", "workingdirectory"}, + {"delimiter", "The used delimiter for CSV export (Default: ,).", "character"}, + {QStringList() << "h" << "help", "Print this help message."}, + {QStringList() << "v" << "version", "Print the version."} + }); + } QDltOptManager* QDltOptManager::getInstance() @@ -79,206 +105,157 @@ void QDltOptManager::printVersion(QString appname) qDebug() << "Version:" << PACKAGE_VERSION << PACKAGE_VERSION_STATE; } -void QDltOptManager::printUsage() +void QDltOptManager::printUsage(const QString& helpText) { -#if (WIN32) - qDebug()<<"Usage: dlt-viewer.exe [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]"; -#else - qDebug()<<"Usage: dlt-viewer [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]"; -#endif - - qDebug()<<"\nOptions:"; - qDebug()<<" [logfile]\tLoading one or more logfiles on startup (must end with .dlt)"; - qDebug()<<" [projectfile]\tLoading project file on startup (must end with .dlp)"; - qDebug()<<" [filterfile]\tLoading filterfile on startup (must end with .dlf)"; - qDebug()<<" [pcapfile]\tImporting DLT/IPC from pcap file on startup (must end with .pcap)"; - qDebug()<<" [mf4file]\tImporting DLT/IPC from mf4 file on startup (must end with .mf4)"; - qDebug()<<" -h or --help\tPrint usage"; - qDebug()<<" -c textfile\tConvert logfile file to textfile"; - qDebug()<<" -u\tConversion will be done in UTF8 instead of ASCII"; - qDebug()<<" -csv\tConversion will be done in CSV format"; - qDebug()<<" -d\tConversion will NOT be done, save in dlt file format again instead"; - qDebug()<<" -dd\tConversion will NOT be done, save as decoded messages in dlt format"; - qDebug()<<" -b \"plugin|command|param1|..|param\"\tExecute a plugin command with parameters before loading log file."; - qDebug()<<" -e \"plugin|command|param1|..|param\"\tExecute a plugin command with parameters after loading log file."; - qDebug()<<" -s or --silent\tEnable silent mode without any GUI. Ideal for commandline usage."; - qDebug()<<" -stream\tTreat the input logfiles as DLT stream instead of DLT files."; - qDebug()<<" -t or --terminate\tTerminate DLT Viewer after command line execution."; - qDebug()<<" -v or --version\tOnly show version and buildtime information"; - qDebug()<<" -w workingdirectory\tSet the working directory"; - qDebug()<<" -delimiter \tThe used delimiter for CSV export (Default: ,)."; - qDebug()<<"\nExamples:"; - qDebug()<<" dlt-viewer.exe -t -c output.txt input.dlt"; - qDebug()<<" dlt-viewer.exe -t -s -u -c output.txt input.dlt"; - qDebug()<<" dlt-viewer.exe -t -s -d -c output.dlt input.dlt"; - qDebug()<<" dlt-viewer.exe -t -s decoded.dlp -dd -c output.dlt input.dlt "; - qDebug()<<" dlt-viewer.exe -t -s -csv -c output.csv input.dlt"; - qDebug()<<" dlt-viewer.exe -t -s -d filter.dlf -c output.dlt input.dlt"; - qDebug()<<" dlt-viewer.exe -p export.dlp -e \"Filetransfer Plugin|export|ftransferdir\" input.dlt"; - qDebug()<<" dlt-viewer.exe input1.dlt input2.dlt"; - qDebug()<<" dlt-viewer.exe -t -c output.txt input.pcap"; - qDebug()<<" dlt-viewer.exe -t -c output.txt input1.mf4 input2.mf4"; + qDebug() << helpText.toStdString().c_str(); + qDebug() << "\nExamples:"; + qDebug() << " dlt-viewer.exe -t -c output.txt input.dlt"; + qDebug() << " dlt-viewer.exe -t -s -u -c output.txt input.dlt"; + qDebug() << " dlt-viewer.exe -t -s -d -c output.dlt input.dlt"; + qDebug() << " dlt-viewer.exe -t -s decoded.dlp -dd -c output.dlt input.dlt "; + qDebug() << " dlt-viewer.exe -t -s -csv -c output.csv input.dlt"; + qDebug() << " dlt-viewer.exe -t -s -d filter.dlf -c output.dlt input.dlt"; + qDebug() << " dlt-viewer.exe -p export.dlp -e \"Filetransfer Plugin|export|ftransferdir\" input.dlt"; + qDebug() << " dlt-viewer.exe input1.dlt input2.dlt"; + qDebug() << " dlt-viewer.exe -t -c output.txt input.pcap"; + qDebug() << " dlt-viewer.exe -t -c output.txt input1.mf4 input2.mf4"; } -void QDltOptManager::parse(QStringList *opt) +void QDltOptManager::parse(const QStringList& args) { - QString str; + m_parser.parse(args); qDebug() << "### Starting DLT Viewer"; - printVersion(opt->at(0)); - - qDebug() << "### Parsing Options"; + printVersion(args.at(0)); /* the default parameter - exactly one parameter - should either be * a dlt or a dlp file, so this enables the "doubleclick" feature */ - //str = opt->at(0); && ( str.compare("-h)") != 0 || str.compare("-v") !=0 ) - if(opt->size()==2 ) - { - if(opt->at(1).endsWith(".dlp") || opt->at(1).endsWith(".DLP")) - { - projectFile = QString("%1").arg(opt->at(1)); - project = true; - qDebug()<< "Project filename:" << projectFile; - return; - } - if(opt->at(1).endsWith(".dlt") || opt->at(1).endsWith(".DLT")) - { - const QString logFile = QString("%1").arg(opt->at(1)); - logFiles += logFile; - qDebug()<< "DLT filename:" << logFile; - return; - } - } - - // 0==Binary 1==First Argument - for (int i = 0; i < opt->size(); ++i) - { - str = opt->at(i); - - if(str.compare("-h") == 0 || str.compare("--help") == 0) - { - printUsage(); - exit(0); - } - else if(str.compare("-s") == 0 || str.compare("--silent") == 0) - { - if ( silent_mode == false) - { - silent_mode = true; - qDebug() << "Silent mode enabled"; - } - } - else if(str.compare("-v") == 0 || str.compare("--version") == 0) - { - printVersion(opt->at(0)); - exit(0); - } - else if(str.compare("-t") == 0 || str.compare("--terminate") == 0) - { - terminate = true; - commandline_mode = true; - } - else if(str.compare("-c")==0) - { - QString c1 = opt->value(i+1); - - convertDestFile = QString("%1").arg(c1); - // check here already if the selected file exists - - qDebug() << "Convert filename:" << convertDestFile; - commandline_mode = true; - - i += 1; - } - else if(str.compare("-delimiter")==0) - { - QString c1 = opt->value(i+1); - - delimiter = QString("%1").arg(c1).front().toLatin1(); - - qDebug() << "Delimiter:" << delimiter; - - i += 1; - } - else if(str.compare("-u")==0) - { - convertionmode = e_UTF8; - } - else if(str.compare("-csv")==0) - { - convertionmode = e_CSV; - } - else if(str.compare("-d")==0) - { - convertionmode = e_DLT; - } - else if(str.compare("-dd")==0) - { - convertionmode = e_DDLT; - } - else if(str.compare("-stream")==0) - { - inputmode = e_inputmode::STREAM; - } - else if(str.compare("-e")==0) - { - QString c = opt->value(i+1); - postPluginCommands += c; - commandline_mode = true; - ++i; - } - else if(str.compare("-b")==0) - { - QString c = opt->value(i+1); - prePluginCommands += c; - commandline_mode = true; - ++i; - } - else if (str.compare("-w") == 0) + if (m_parser.optionNames().isEmpty() && m_parser.positionalArguments().size() == 1) + { + const QString& arg = m_parser.positionalArguments().at(0); + if(arg.endsWith(".dlp") || arg.endsWith(".DLP")) { - workingDirectory = opt->value(i+1); - ++i; + projectFile = arg; + project = true; + qDebug()<< "Project filename:" << projectFile; + return; + } + if (arg.endsWith(".dlt") || arg.endsWith(".DLT")) + { + const QString logFile = arg; + logFiles += logFile; + qDebug()<< "DLT filename:" << logFile; + return; } - else if(opt->at(i).endsWith(".dlt") || opt->at(i).endsWith(".DLT")) + } + + if (m_parser.isSet("help")) { + printUsage(m_parser.helpText()); + exit(0); + } + + if (m_parser.isSet("silent")) { + silent_mode = true; + qDebug() << "Silent mode enabled"; + } + + if (m_parser.isSet("version")) { + // version is already printed above + exit(0); + } + + if (m_parser.isSet("terminate")) { + terminate = true; + commandline_mode = true; + } + + if (m_parser.isSet("c")) { + convertDestFile = m_parser.value("c"); + qDebug() << "Convert filename:" << convertDestFile; + commandline_mode = true; + } + + if (m_parser.isSet("delimiter")) { + delimiter = m_parser.value("delimiter").front().toLatin1(); + qDebug() << "Delimiter:" << delimiter; + } + + if (m_parser.isSet("u")) { + convertionmode = e_UTF8; + } + + if (m_parser.isSet("csv")) { + convertionmode = e_CSV; + } + + if (m_parser.isSet("d")) { + convertionmode = e_DLT; + } + + if (m_parser.isSet("dd")) { + convertionmode = e_DDLT; + } + + if (m_parser.isSet("stream")) { + inputmode = e_inputmode::STREAM; + } + + if (m_parser.isSet("e")) { + postPluginCommands += m_parser.value("e"); + commandline_mode = true; + } + + if (m_parser.isSet("b")) { + prePluginCommands += m_parser.value("b"); + commandline_mode = true; + } + + if (m_parser.isSet("w")) { + workingDirectory = m_parser.value("w"); + } + + QStringList positionalArguments = m_parser.positionalArguments(); + for (const QString &arg : positionalArguments) + { + if(arg.endsWith(".dlt") || arg.endsWith(".DLT")) { - const QString logFile = QString("%1").arg(opt->at(i)); + const QString logFile = arg; logFiles += logFile; qDebug()<< "DLT filename:" << logFile; } - else if(opt->at(i).endsWith(".dlp") || opt->at(i).endsWith(".DLP")) + else if(arg.endsWith(".dlp") || arg.endsWith(".DLP")) { if (project == true) { qDebug() << "\nError: Can only load one project file\n"; - printUsage(); + printUsage(m_parser.helpText()); exit(-1); } - projectFile = QString("%1").arg(opt->at(i)); + projectFile = arg; project = true; qDebug()<< "Project filename:" << projectFile; } - else if(opt->at(i).endsWith(".dlf") || opt->at(i).endsWith(".DLF")) + else if(arg.endsWith(".dlf") || arg.endsWith(".DLF")) { - filterFiles += QString("%1").arg(opt->at(i)); - qDebug()<< "Filter filename:" << QString("%1").arg(opt->at(i)); + filterFiles += arg; + qDebug()<< "Filter filename:" << arg; } - else if(opt->at(i).endsWith(".pcap") || opt->at(i).endsWith(".PCAP")) + else if(arg.endsWith(".pcap") || arg.endsWith(".PCAP")) { - const QString pcapFile = QString("%1").arg(opt->at(i)); + const QString pcapFile = arg; pcapFiles += pcapFile; qDebug()<< "Pcap filename:" << pcapFile; } - else if(opt->at(i).endsWith(".mf4") || opt->at(i).endsWith(".MF4")) + else if(arg.endsWith(".mf4") || arg.endsWith(".MF4")) { - const QString mf4File = QString("%1").arg(opt->at(i)); + const QString mf4File = arg; mf4Files += mf4File; qDebug()<< "MF4 filename:" << mf4File; } - - } // end of for loop + } /* On Windows we do not want to open a console in case * we start the application e.g. from file explorer. @@ -315,3 +292,32 @@ QString QDltOptManager::getCommandName(){return commandName;} QStringList QDltOptManager::getCommandParams(){return commandParams;} QString QDltOptManager::getWorkingDirectory() const { return workingDirectory; } char QDltOptManager::getDelimiter(){return delimiter;} + +QString QDltOptManager::getHelpText() const +{ + return m_parser.helpText(); +} + +void QDltOptManager::reset() +{ + project = false; + terminate = false; + silent_mode = false; + commandline_mode = false; + convertionmode = e_ASCI; + inputmode = e_inputmode::DLT; + projectFile.clear(); + logFiles.clear(); + filterFiles.clear(); + convertDestFile.clear(); + pluginName.clear(); + commandName.clear(); + commandParams.clear(); + prePluginCommands.clear(); + postPluginCommands.clear(); + workingDirectory.clear(); + delimiter=','; + pcapFiles.clear(); + mf4Files.clear(); +} + diff --git a/qdlt/qdltoptmanager.h b/qdlt/qdltoptmanager.h index 6cdda7e1..a27deec6 100644 --- a/qdlt/qdltoptmanager.h +++ b/qdlt/qdltoptmanager.h @@ -21,6 +21,7 @@ #define QDLTOPTMANAGER_H #include +#include #include "export_rules.h" @@ -44,9 +45,9 @@ class QDLT_EXPORT QDltOptManager { public: static QDltOptManager* getInstance(); - void printUsage(); + void printUsage(const QString& helpText); void printVersion(QString appname); - void parse(QStringList *opt); + void parse(const QStringList& arguments); bool isProjectFile(); bool isTerminate(); @@ -71,6 +72,11 @@ class QDLT_EXPORT QDltOptManager const QStringList &getMf4Files() const; char getDelimiter(); + QString getHelpText() const; + + // only testing relevant + void reset(); + private: QDltOptManager(); QDltOptManager(QDltOptManager const&); @@ -98,6 +104,8 @@ class QDLT_EXPORT QDltOptManager QString workingDirectory; char delimiter; + + QCommandLineParser m_parser; }; #endif //QDLTOPTMANAGER_H diff --git a/qdlt/tests/CMakeLists.txt b/qdlt/tests/CMakeLists.txt index beccd1f3..7b65fda1 100644 --- a/qdlt/tests/CMakeLists.txt +++ b/qdlt/tests/CMakeLists.txt @@ -1,15 +1,31 @@ -add_executable(test_tools +add_executable(test_dltmessagematcher test_dltmessagematcher.cpp ) target_link_libraries( - test_tools + test_dltmessagematcher PRIVATE GTest::gtest_main qdlt ) add_test( - NAME test_tools - COMMAND $ + NAME test_dltmessagematcher + COMMAND $ ) + +add_executable(test_dltoptmanager + test_dltoptmanager.cpp +) + +target_link_libraries( + test_dltoptmanager + PRIVATE + GTest::gtest_main + qdlt +) + +add_test( + NAME test_dltoptmanager + COMMAND $ +) diff --git a/qdlt/tests/test_dltoptmanager.cpp b/qdlt/tests/test_dltoptmanager.cpp new file mode 100644 index 00000000..df2c4047 --- /dev/null +++ b/qdlt/tests/test_dltoptmanager.cpp @@ -0,0 +1,171 @@ +#include + +#include + +#include + + +QString logMessageSink; + +void messageHandler(QtMsgType type, const QMessageLogContext &, + const QString &msg) { + if (type == QtDebugMsg) { + logMessageSink.append(msg); + } +} + +class OptManagerTest : public ::testing::Test { +protected: + static void SetUpTestSuite() { + m_manager = QDltOptManager::getInstance(); + + qInstallMessageHandler(messageHandler); + } + + void SetUp() override { + m_manager->reset(); + } + + void TearDown() override { + logMessageSink.clear(); + } + + static QDltOptManager* m_manager; +}; + +QDltOptManager* OptManagerTest::m_manager = nullptr; + +TEST_F(OptManagerTest, txtConversion) { + auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input.dlt"; + + m_manager->parse(args); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, txtConversionSilentUtf8Mode) { + auto args = QStringList() << "executable" << "-t" << "-s" << "-u" << "-c" << "output.txt" << "input.dlt"; + + m_manager->parse(args); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_EQ(m_manager->get_convertionmode(), e_UTF8); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, txtConversionSilentAsciiMode) { + auto args = QStringList() << "executable" << "-t" << "-s" << "-d" << "-c" << "output.txt" << "input.dlt"; + + m_manager->parse(args); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_EQ(m_manager->get_convertionmode(), e_DLT); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, csvConversionSilentMode) { + auto args = QStringList() << "executable" << "-t" << "-s" << "-csv" << "-c" << "output.csv" << "input.dlt"; + + m_manager->parse(args); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.csv"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_EQ(m_manager->get_convertionmode(), e_CSV); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, txtConversionSilentDdlMode) { + auto args = QStringList() << "executable" << "-t" << "-s" << "decoded.dlp" << "-dd" << "-c" << "output.dlt" << "input.dlt"; + + m_manager->parse(args); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.dlt"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_EQ(m_manager->get_convertionmode(), e_DDLT); + EXPECT_TRUE(m_manager->isCommandlineMode()); + EXPECT_EQ(m_manager->getProjectFile(), "decoded.dlp"); +} + +TEST_F(OptManagerTest, pluginPostCommands) { + auto args = QStringList() << "executable" + << "-p" + << "export.dlp" + << "-e" + << "\"Filetransfer Plugin|export|ftransferdir\"" + << "input.dlt"; + m_manager->parse(args); + + EXPECT_EQ(m_manager->getProjectFile(), "export.dlp"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_TRUE(m_manager->getPostPluginCommands().contains("\"Filetransfer Plugin|export|ftransferdir\"")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, pluginPreCommands) { + auto args = QStringList() << "executable" + << "-b" + << "\"Filetransfer Plugin|export|ftransferdir\"" + << "input.dlt"; + m_manager->parse(args); + + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_TRUE(m_manager->getPrePluginCommands().contains("\"Filetransfer Plugin|export|ftransferdir\"")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, multipleLogFiles) { + auto args = QStringList() << "executable" << "input1.dlt" << "input2.dlt"; + + m_manager->parse(args); + + EXPECT_TRUE(m_manager->getLogFiles().contains("input1.dlt")); + EXPECT_TRUE(m_manager->getLogFiles().contains("input2.dlt")); +} + +TEST_F(OptManagerTest, pcapFile) { + auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input.pcap"; + + m_manager->parse(args); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getPcapFiles().contains("input.pcap")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, mf4Files) { + auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input1.mf4" << "input2.mf4"; + + m_manager->parse(args); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getMf4Files().contains("input1.mf4")); + EXPECT_TRUE(m_manager->getMf4Files().contains("input2.mf4")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, version) { + // impossible to check just version because there is a call to exit(0) in the qdltoptmanager + // but any output will be enough to check the version call because it is always printed + auto args = QStringList() << "executable" << "some.dlt"; + + m_manager->parse(args); + + EXPECT_TRUE(logMessageSink.contains("Executable Name:")); + EXPECT_TRUE(logMessageSink.contains("Build time:")); + EXPECT_TRUE(logMessageSink.contains("Version:")); +} diff --git a/src/main.cpp b/src/main.cpp index dc8b8db5..b347c743 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,9 +46,8 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); - QStringList arguments = a.arguments(); QDltOptManager *opt = QDltOptManager::getInstance(); - opt->parse(&arguments); + opt->parse(a.arguments()); MainWindow w; w.show(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6f589a8d..6ce4badc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -281,7 +281,6 @@ MainWindow::~MainWindow() delete sortProxyModel; } - void MainWindow::initState() { /* Settings */ @@ -5720,40 +5719,10 @@ void MainWindow::on_action_menuHelp_Info_triggered() QString("(C) 2016,2024 BMW AG\n")); } - -void MainWindow::on_action_menuHelp_Command_Line_triggered() -{ - // Please copy changes to QDltOptManager::getInstance().cpp - printUsage() - - QMessageBox::information(0, QString("DLT Viewer - Command line usage\t\t\t\t\t"), // tabs used to expand mesage box ! - #ifdef WIN32 - QString("Usage: dlt-viewer.exe [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]\n\n")+ - QString("Options:\n")+ - #else - QString("Usage: dlt-viewer [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]\n\n")+ - QString("Options:\n")+ - #endif - QString(" [logfile]\t\t\tLoading one or more logfiles on startup (must end with .dlt)\n")+ - QString(" [projectfile]\t\tLoading project file on startup (must end with .dlp)\n")+ - QString(" [filterfile]\t\tLoading filterfile on startup (must end with .dlf)\n")+ - QString(" [pcapfile]\tImporting DLT/IPC from pcap file on startup (must end with .pcap)\n")+ - QString(" [mf4file]\tImporting DLT/IPC from mf4 file on startup (must end with .mf4)\n")+ - QString(" -h\t\t\tPrint usage\n")+ - QString(" -s\t\t\tEnable silent mode without any GUI. Ideal for commandline usage.\n")+ - QString(" -stream\tTreat the input logfiles as DLT stream instead of DLT files.\n")+ - QString(" -v\t\t\tShow version and buildtime information\n")+ - QString(" -c \tConvert logfile to ASCII textfile\n")+ - QString(" -u\t\t\tExport logfile to UTF8 instead\n")+ - QString(" -csv\t\t\tExport logfile to csv ( Excel ) instead\n")+ - QString(" -d\t\t\tExport logfile to DLT format\n")+ - QString(" -dd\t\t\tExport logfile to decoded DLT format\n")+ - QString(" -b |command|param1|..|param\n\t\t\tExecute a command plugin with parameters before loading log file\n")+ - QString(" -e |command|param1|..|param\n\t\t\tExecute a command plugin with parameters after loading log file\n")+ - QString(" -t\t\t\tTerminate DLT Viewer after command line execution\n")+ - QString(" -v\t\t\tShow version and buildtime information\n")+ - QString(" -w workingdirectory\tSet the working directory\n")+ - QString(" -delimiter \tThe used delimiter for CSV export (Default: ,)\n") - ); +void MainWindow::on_action_menuHelp_Command_Line_triggered() { + QMessageBox::information( + 0, "DLT Viewer - Command line usage\t\t\t\t\t", // tabs used to expand message box ! + QDltOptManager::getInstance()->getHelpText()); } void MainWindow::on_pluginWidget_itemSelectionChanged() From 311336bd5f03d2243df53648ca532c072d2152e5 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Wed, 9 Oct 2024 13:27:45 +0200 Subject: [PATCH 13/21] Enable Filter Regex Replacement also for exporting into DLT format. (#554) Signed-off-by: Alexander Wenzel --- qdlt/qdltexporter.cpp | 8 ++++++++ qdlt/qdltfile.cpp | 5 +++++ qdlt/qdltfile.h | 5 +++++ qdlt/qdltfilterlist.cpp | 31 +++++++++++++++++++++++++++++++ qdlt/qdltfilterlist.h | 5 +++++ 5 files changed, 54 insertions(+) diff --git a/qdlt/qdltexporter.cpp b/qdlt/qdltexporter.cpp index 9da4a130..42934852 100644 --- a/qdlt/qdltexporter.cpp +++ b/qdlt/qdltexporter.cpp @@ -434,6 +434,14 @@ void QDltExporter::exportMessages(QDltFile *from, QFile *to, QDltPluginManager * } } + // apply Regex if needed + if(exportFormat == QDltExporter::FormatDlt || exportFormat == QDltExporter::FormatDltDecoded) + { + msg.setNumberOfArguments(msg.sizeArguments()); + if(from) from->applyRegExStringMsg(msg); + msg.getMsg(buf,true); + } + // export message if(!exportMsg(starting,msg,buf)) { diff --git a/qdlt/qdltfile.cpp b/qdlt/qdltfile.cpp index d49733a3..e0ef1748 100644 --- a/qdlt/qdltfile.cpp +++ b/qdlt/qdltfile.cpp @@ -759,3 +759,8 @@ bool QDltFile::applyRegExString(QString &text) { return filterList.applyRegExString(text); } + +bool QDltFile::applyRegExStringMsg(QDltMsg &msg) +{ + return filterList.applyRegExStringMsg(msg); +} diff --git a/qdlt/qdltfile.h b/qdlt/qdltfile.h index 06a8df94..b6a4e399 100644 --- a/qdlt/qdltfile.h +++ b/qdlt/qdltfile.h @@ -304,6 +304,11 @@ class QDLT_EXPORT QDltFile : public QDlt */ bool applyRegExString(QString &text); + //! Apply RegEx Replace to the arguments of a message, if any active in the filters + /*! + */ + bool applyRegExStringMsg(QDltMsg &msg); + protected: private: diff --git a/qdlt/qdltfilterlist.cpp b/qdlt/qdltfilterlist.cpp index 413add34..c5a976e6 100644 --- a/qdlt/qdltfilterlist.cpp +++ b/qdlt/qdltfilterlist.cpp @@ -142,6 +142,37 @@ bool QDltFilterList::applyRegExString(QString &text) return result; } +bool QDltFilterList::applyRegExStringMsg(QDltMsg &msg) +{ + QDltFilter *filter; + bool result = false; + + for(int numfilter=0;numfilterenableFilter && filter->enableRegexSearchReplace) + { + for(int num=0;numregex_search), filter->regex_replace); + arg.setValue(text); + msg.removeArgument(num); + msg.addArgument(arg,num); + } + } + + result = true; + } + } + return result; +} + bool QDltFilterList::checkFilter(QDltMsg &msg) { QDltFilter *filter; diff --git a/qdlt/qdltfilterlist.h b/qdlt/qdltfilterlist.h index 81efab30..7abb8b3a 100644 --- a/qdlt/qdltfilterlist.h +++ b/qdlt/qdltfilterlist.h @@ -127,6 +127,11 @@ class QDLT_EXPORT QDltFilterList */ bool applyRegExString(QString &text); + //! Apply RegEx Replace to the argumnets of a message, if any active in the filters. + /*! + */ + bool applyRegExStringMsg(QDltMsg &msg); + protected: private: From 3e370ece1537c041253fa4d636adaf226f5a27b3 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Thu, 10 Oct 2024 09:08:17 +0200 Subject: [PATCH 14/21] Revert "Use QCommandLineParser instead of custom cmd args parsing (#543)" This reverts commit 5bab5b51af779d4f5a0413d69896cbc9a24dcf06. --- qdlt/qdltoptmanager.cpp | 332 +++++++++++++++--------------- qdlt/qdltoptmanager.h | 12 +- qdlt/tests/CMakeLists.txt | 24 +-- qdlt/tests/test_dltoptmanager.cpp | 171 --------------- src/main.cpp | 3 +- src/mainwindow.cpp | 39 +++- 6 files changed, 206 insertions(+), 375 deletions(-) delete mode 100644 qdlt/tests/test_dltoptmanager.cpp diff --git a/qdlt/qdltoptmanager.cpp b/qdlt/qdltoptmanager.cpp index bf363052..c422b762 100644 --- a/qdlt/qdltoptmanager.cpp +++ b/qdlt/qdltoptmanager.cpp @@ -23,7 +23,6 @@ #include "qdltoptmanager.h" #include "version.h" - #include #include @@ -38,31 +37,6 @@ QDltOptManager::QDltOptManager() convertionmode = e_ASCI; commandline_mode = false; delimiter=','; - - m_parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); - - m_parser.addPositionalArgument("logfile", "Loading one or more logfiles on startup (must end with .dlt)"); - m_parser.addPositionalArgument("projectfile", "Loading project file on startup (must end with .dlp)"); - m_parser.addPositionalArgument("filterfile", "Loading filterfile on startup (must end with .dlf)"); - m_parser.addPositionalArgument("pcapfile", "Importing DLT/IPC from pcap file on startup (must end with .pcap)"); - m_parser.addPositionalArgument("mf4file", "Importing DLT/IPC from mf4 file on startup (must end with .mf4)"); - m_parser.addOptions({ - {"c", "Convert logfile file to ", "textfile"}, - {"u", "Conversion will be done in UTF8 instead of ASCII"}, - {"csv", "Conversion will be done in CSV format"}, - {"d", "Conversion will NOT be done, save in dlt file format again instead"}, - {"dd", "Conversion will NOT be done, save as decoded messages in dlt format"}, - {"b", "Execute a plugin command with parameters before loading log file.", "plugin|command|param1|..|param"}, - {"e", "Execute a plugin command with parameters after loading log file.", "plugin|command|param1|..|param"}, - {QStringList() << "s" << "silent", "Enable silent mode without any GUI. Ideal for commandline usage."}, - {"stream", "Treat the input logfiles as DLT stream instead of DLT files."}, - {QStringList() << "t" << "terminate", "Terminate DLT Viewer after command line execution."}, - {"w", "Set the working directory", "workingdirectory"}, - {"delimiter", "The used delimiter for CSV export (Default: ,).", "character"}, - {QStringList() << "h" << "help", "Print this help message."}, - {QStringList() << "v" << "version", "Print the version."} - }); - } QDltOptManager* QDltOptManager::getInstance() @@ -105,157 +79,206 @@ void QDltOptManager::printVersion(QString appname) qDebug() << "Version:" << PACKAGE_VERSION << PACKAGE_VERSION_STATE; } -void QDltOptManager::printUsage(const QString& helpText) +void QDltOptManager::printUsage() { - qDebug() << helpText.toStdString().c_str(); - qDebug() << "\nExamples:"; - qDebug() << " dlt-viewer.exe -t -c output.txt input.dlt"; - qDebug() << " dlt-viewer.exe -t -s -u -c output.txt input.dlt"; - qDebug() << " dlt-viewer.exe -t -s -d -c output.dlt input.dlt"; - qDebug() << " dlt-viewer.exe -t -s decoded.dlp -dd -c output.dlt input.dlt "; - qDebug() << " dlt-viewer.exe -t -s -csv -c output.csv input.dlt"; - qDebug() << " dlt-viewer.exe -t -s -d filter.dlf -c output.dlt input.dlt"; - qDebug() << " dlt-viewer.exe -p export.dlp -e \"Filetransfer Plugin|export|ftransferdir\" input.dlt"; - qDebug() << " dlt-viewer.exe input1.dlt input2.dlt"; - qDebug() << " dlt-viewer.exe -t -c output.txt input.pcap"; - qDebug() << " dlt-viewer.exe -t -c output.txt input1.mf4 input2.mf4"; +#if (WIN32) + qDebug()<<"Usage: dlt-viewer.exe [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]"; +#else + qDebug()<<"Usage: dlt-viewer [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]"; +#endif + + qDebug()<<"\nOptions:"; + qDebug()<<" [logfile]\tLoading one or more logfiles on startup (must end with .dlt)"; + qDebug()<<" [projectfile]\tLoading project file on startup (must end with .dlp)"; + qDebug()<<" [filterfile]\tLoading filterfile on startup (must end with .dlf)"; + qDebug()<<" [pcapfile]\tImporting DLT/IPC from pcap file on startup (must end with .pcap)"; + qDebug()<<" [mf4file]\tImporting DLT/IPC from mf4 file on startup (must end with .mf4)"; + qDebug()<<" -h or --help\tPrint usage"; + qDebug()<<" -c textfile\tConvert logfile file to textfile"; + qDebug()<<" -u\tConversion will be done in UTF8 instead of ASCII"; + qDebug()<<" -csv\tConversion will be done in CSV format"; + qDebug()<<" -d\tConversion will NOT be done, save in dlt file format again instead"; + qDebug()<<" -dd\tConversion will NOT be done, save as decoded messages in dlt format"; + qDebug()<<" -b \"plugin|command|param1|..|param\"\tExecute a plugin command with parameters before loading log file."; + qDebug()<<" -e \"plugin|command|param1|..|param\"\tExecute a plugin command with parameters after loading log file."; + qDebug()<<" -s or --silent\tEnable silent mode without any GUI. Ideal for commandline usage."; + qDebug()<<" -stream\tTreat the input logfiles as DLT stream instead of DLT files."; + qDebug()<<" -t or --terminate\tTerminate DLT Viewer after command line execution."; + qDebug()<<" -v or --version\tOnly show version and buildtime information"; + qDebug()<<" -w workingdirectory\tSet the working directory"; + qDebug()<<" -delimiter \tThe used delimiter for CSV export (Default: ,)."; + qDebug()<<"\nExamples:"; + qDebug()<<" dlt-viewer.exe -t -c output.txt input.dlt"; + qDebug()<<" dlt-viewer.exe -t -s -u -c output.txt input.dlt"; + qDebug()<<" dlt-viewer.exe -t -s -d -c output.dlt input.dlt"; + qDebug()<<" dlt-viewer.exe -t -s decoded.dlp -dd -c output.dlt input.dlt "; + qDebug()<<" dlt-viewer.exe -t -s -csv -c output.csv input.dlt"; + qDebug()<<" dlt-viewer.exe -t -s -d filter.dlf -c output.dlt input.dlt"; + qDebug()<<" dlt-viewer.exe -p export.dlp -e \"Filetransfer Plugin|export|ftransferdir\" input.dlt"; + qDebug()<<" dlt-viewer.exe input1.dlt input2.dlt"; + qDebug()<<" dlt-viewer.exe -t -c output.txt input.pcap"; + qDebug()<<" dlt-viewer.exe -t -c output.txt input1.mf4 input2.mf4"; } -void QDltOptManager::parse(const QStringList& args) +void QDltOptManager::parse(QStringList *opt) { - m_parser.parse(args); + QString str; qDebug() << "### Starting DLT Viewer"; - printVersion(args.at(0)); + printVersion(opt->at(0)); + + qDebug() << "### Parsing Options"; /* the default parameter - exactly one parameter - should either be * a dlt or a dlp file, so this enables the "doubleclick" feature */ - if (m_parser.optionNames().isEmpty() && m_parser.positionalArguments().size() == 1) - { - const QString& arg = m_parser.positionalArguments().at(0); - if(arg.endsWith(".dlp") || arg.endsWith(".DLP")) - { - projectFile = arg; - project = true; - qDebug()<< "Project filename:" << projectFile; - return; - } - if (arg.endsWith(".dlt") || arg.endsWith(".DLT")) + //str = opt->at(0); && ( str.compare("-h)") != 0 || str.compare("-v") !=0 ) + if(opt->size()==2 ) + { + if(opt->at(1).endsWith(".dlp") || opt->at(1).endsWith(".DLP")) + { + projectFile = QString("%1").arg(opt->at(1)); + project = true; + qDebug()<< "Project filename:" << projectFile; + return; + } + if(opt->at(1).endsWith(".dlt") || opt->at(1).endsWith(".DLT")) + { + const QString logFile = QString("%1").arg(opt->at(1)); + logFiles += logFile; + qDebug()<< "DLT filename:" << logFile; + return; + } + } + + // 0==Binary 1==First Argument + for (int i = 0; i < opt->size(); ++i) + { + str = opt->at(i); + + if(str.compare("-h") == 0 || str.compare("--help") == 0) + { + printUsage(); + exit(0); + } + else if(str.compare("-s") == 0 || str.compare("--silent") == 0) + { + if ( silent_mode == false) + { + silent_mode = true; + qDebug() << "Silent mode enabled"; + } + } + else if(str.compare("-v") == 0 || str.compare("--version") == 0) + { + printVersion(opt->at(0)); + exit(0); + } + else if(str.compare("-t") == 0 || str.compare("--terminate") == 0) + { + terminate = true; + commandline_mode = true; + } + else if(str.compare("-c")==0) + { + QString c1 = opt->value(i+1); + + convertDestFile = QString("%1").arg(c1); + // check here already if the selected file exists + + qDebug() << "Convert filename:" << convertDestFile; + commandline_mode = true; + + i += 1; + } + else if(str.compare("-delimiter")==0) + { + QString c1 = opt->value(i+1); + + delimiter = QString("%1").arg(c1).front().toLatin1(); + + qDebug() << "Delimiter:" << delimiter; + + i += 1; + } + else if(str.compare("-u")==0) + { + convertionmode = e_UTF8; + } + else if(str.compare("-csv")==0) + { + convertionmode = e_CSV; + } + else if(str.compare("-d")==0) + { + convertionmode = e_DLT; + } + else if(str.compare("-dd")==0) + { + convertionmode = e_DDLT; + } + else if(str.compare("-stream")==0) + { + inputmode = e_inputmode::STREAM; + } + else if(str.compare("-e")==0) + { + QString c = opt->value(i+1); + postPluginCommands += c; + commandline_mode = true; + ++i; + } + else if(str.compare("-b")==0) + { + QString c = opt->value(i+1); + prePluginCommands += c; + commandline_mode = true; + ++i; + } + else if (str.compare("-w") == 0) { - const QString logFile = arg; - logFiles += logFile; - qDebug()<< "DLT filename:" << logFile; - return; + workingDirectory = opt->value(i+1); + ++i; } - } - - if (m_parser.isSet("help")) { - printUsage(m_parser.helpText()); - exit(0); - } - - if (m_parser.isSet("silent")) { - silent_mode = true; - qDebug() << "Silent mode enabled"; - } - - if (m_parser.isSet("version")) { - // version is already printed above - exit(0); - } - - if (m_parser.isSet("terminate")) { - terminate = true; - commandline_mode = true; - } - - if (m_parser.isSet("c")) { - convertDestFile = m_parser.value("c"); - qDebug() << "Convert filename:" << convertDestFile; - commandline_mode = true; - } - - if (m_parser.isSet("delimiter")) { - delimiter = m_parser.value("delimiter").front().toLatin1(); - qDebug() << "Delimiter:" << delimiter; - } - - if (m_parser.isSet("u")) { - convertionmode = e_UTF8; - } - - if (m_parser.isSet("csv")) { - convertionmode = e_CSV; - } - - if (m_parser.isSet("d")) { - convertionmode = e_DLT; - } - - if (m_parser.isSet("dd")) { - convertionmode = e_DDLT; - } - - if (m_parser.isSet("stream")) { - inputmode = e_inputmode::STREAM; - } - - if (m_parser.isSet("e")) { - postPluginCommands += m_parser.value("e"); - commandline_mode = true; - } - - if (m_parser.isSet("b")) { - prePluginCommands += m_parser.value("b"); - commandline_mode = true; - } - - if (m_parser.isSet("w")) { - workingDirectory = m_parser.value("w"); - } - - QStringList positionalArguments = m_parser.positionalArguments(); - for (const QString &arg : positionalArguments) - { - if(arg.endsWith(".dlt") || arg.endsWith(".DLT")) + else if(opt->at(i).endsWith(".dlt") || opt->at(i).endsWith(".DLT")) { - const QString logFile = arg; + const QString logFile = QString("%1").arg(opt->at(i)); logFiles += logFile; qDebug()<< "DLT filename:" << logFile; } - else if(arg.endsWith(".dlp") || arg.endsWith(".DLP")) + else if(opt->at(i).endsWith(".dlp") || opt->at(i).endsWith(".DLP")) { if (project == true) { qDebug() << "\nError: Can only load one project file\n"; - printUsage(m_parser.helpText()); + printUsage(); exit(-1); } - projectFile = arg; + projectFile = QString("%1").arg(opt->at(i)); project = true; qDebug()<< "Project filename:" << projectFile; } - else if(arg.endsWith(".dlf") || arg.endsWith(".DLF")) + else if(opt->at(i).endsWith(".dlf") || opt->at(i).endsWith(".DLF")) { - filterFiles += arg; - qDebug()<< "Filter filename:" << arg; + filterFiles += QString("%1").arg(opt->at(i)); + qDebug()<< "Filter filename:" << QString("%1").arg(opt->at(i)); } - else if(arg.endsWith(".pcap") || arg.endsWith(".PCAP")) + else if(opt->at(i).endsWith(".pcap") || opt->at(i).endsWith(".PCAP")) { - const QString pcapFile = arg; + const QString pcapFile = QString("%1").arg(opt->at(i)); pcapFiles += pcapFile; qDebug()<< "Pcap filename:" << pcapFile; } - else if(arg.endsWith(".mf4") || arg.endsWith(".MF4")) + else if(opt->at(i).endsWith(".mf4") || opt->at(i).endsWith(".MF4")) { - const QString mf4File = arg; + const QString mf4File = QString("%1").arg(opt->at(i)); mf4Files += mf4File; qDebug()<< "MF4 filename:" << mf4File; } - } + + } // end of for loop /* On Windows we do not want to open a console in case * we start the application e.g. from file explorer. @@ -292,32 +315,3 @@ QString QDltOptManager::getCommandName(){return commandName;} QStringList QDltOptManager::getCommandParams(){return commandParams;} QString QDltOptManager::getWorkingDirectory() const { return workingDirectory; } char QDltOptManager::getDelimiter(){return delimiter;} - -QString QDltOptManager::getHelpText() const -{ - return m_parser.helpText(); -} - -void QDltOptManager::reset() -{ - project = false; - terminate = false; - silent_mode = false; - commandline_mode = false; - convertionmode = e_ASCI; - inputmode = e_inputmode::DLT; - projectFile.clear(); - logFiles.clear(); - filterFiles.clear(); - convertDestFile.clear(); - pluginName.clear(); - commandName.clear(); - commandParams.clear(); - prePluginCommands.clear(); - postPluginCommands.clear(); - workingDirectory.clear(); - delimiter=','; - pcapFiles.clear(); - mf4Files.clear(); -} - diff --git a/qdlt/qdltoptmanager.h b/qdlt/qdltoptmanager.h index a27deec6..6cdda7e1 100644 --- a/qdlt/qdltoptmanager.h +++ b/qdlt/qdltoptmanager.h @@ -21,7 +21,6 @@ #define QDLTOPTMANAGER_H #include -#include #include "export_rules.h" @@ -45,9 +44,9 @@ class QDLT_EXPORT QDltOptManager { public: static QDltOptManager* getInstance(); - void printUsage(const QString& helpText); + void printUsage(); void printVersion(QString appname); - void parse(const QStringList& arguments); + void parse(QStringList *opt); bool isProjectFile(); bool isTerminate(); @@ -72,11 +71,6 @@ class QDLT_EXPORT QDltOptManager const QStringList &getMf4Files() const; char getDelimiter(); - QString getHelpText() const; - - // only testing relevant - void reset(); - private: QDltOptManager(); QDltOptManager(QDltOptManager const&); @@ -104,8 +98,6 @@ class QDLT_EXPORT QDltOptManager QString workingDirectory; char delimiter; - - QCommandLineParser m_parser; }; #endif //QDLTOPTMANAGER_H diff --git a/qdlt/tests/CMakeLists.txt b/qdlt/tests/CMakeLists.txt index 7b65fda1..beccd1f3 100644 --- a/qdlt/tests/CMakeLists.txt +++ b/qdlt/tests/CMakeLists.txt @@ -1,31 +1,15 @@ -add_executable(test_dltmessagematcher +add_executable(test_tools test_dltmessagematcher.cpp ) target_link_libraries( - test_dltmessagematcher + test_tools PRIVATE GTest::gtest_main qdlt ) add_test( - NAME test_dltmessagematcher - COMMAND $ + NAME test_tools + COMMAND $ ) - -add_executable(test_dltoptmanager - test_dltoptmanager.cpp -) - -target_link_libraries( - test_dltoptmanager - PRIVATE - GTest::gtest_main - qdlt -) - -add_test( - NAME test_dltoptmanager - COMMAND $ -) diff --git a/qdlt/tests/test_dltoptmanager.cpp b/qdlt/tests/test_dltoptmanager.cpp deleted file mode 100644 index df2c4047..00000000 --- a/qdlt/tests/test_dltoptmanager.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include - -#include - -#include - - -QString logMessageSink; - -void messageHandler(QtMsgType type, const QMessageLogContext &, - const QString &msg) { - if (type == QtDebugMsg) { - logMessageSink.append(msg); - } -} - -class OptManagerTest : public ::testing::Test { -protected: - static void SetUpTestSuite() { - m_manager = QDltOptManager::getInstance(); - - qInstallMessageHandler(messageHandler); - } - - void SetUp() override { - m_manager->reset(); - } - - void TearDown() override { - logMessageSink.clear(); - } - - static QDltOptManager* m_manager; -}; - -QDltOptManager* OptManagerTest::m_manager = nullptr; - -TEST_F(OptManagerTest, txtConversion) { - auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input.dlt"; - - m_manager->parse(args); - - EXPECT_TRUE(m_manager->isTerminate()); - EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); - EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); - EXPECT_TRUE(m_manager->isCommandlineMode()); -} - -TEST_F(OptManagerTest, txtConversionSilentUtf8Mode) { - auto args = QStringList() << "executable" << "-t" << "-s" << "-u" << "-c" << "output.txt" << "input.dlt"; - - m_manager->parse(args); - - EXPECT_TRUE(m_manager->isTerminate()); - EXPECT_TRUE(m_manager->issilentMode()); - EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); - EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); - EXPECT_EQ(m_manager->get_convertionmode(), e_UTF8); - EXPECT_TRUE(m_manager->isCommandlineMode()); -} - -TEST_F(OptManagerTest, txtConversionSilentAsciiMode) { - auto args = QStringList() << "executable" << "-t" << "-s" << "-d" << "-c" << "output.txt" << "input.dlt"; - - m_manager->parse(args); - - EXPECT_TRUE(m_manager->isTerminate()); - EXPECT_TRUE(m_manager->issilentMode()); - EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); - EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); - EXPECT_EQ(m_manager->get_convertionmode(), e_DLT); - EXPECT_TRUE(m_manager->isCommandlineMode()); -} - -TEST_F(OptManagerTest, csvConversionSilentMode) { - auto args = QStringList() << "executable" << "-t" << "-s" << "-csv" << "-c" << "output.csv" << "input.dlt"; - - m_manager->parse(args); - - EXPECT_TRUE(m_manager->isTerminate()); - EXPECT_TRUE(m_manager->issilentMode()); - EXPECT_EQ(m_manager->getConvertDestFile(), "output.csv"); - EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); - EXPECT_EQ(m_manager->get_convertionmode(), e_CSV); - EXPECT_TRUE(m_manager->isCommandlineMode()); -} - -TEST_F(OptManagerTest, txtConversionSilentDdlMode) { - auto args = QStringList() << "executable" << "-t" << "-s" << "decoded.dlp" << "-dd" << "-c" << "output.dlt" << "input.dlt"; - - m_manager->parse(args); - - EXPECT_TRUE(m_manager->isTerminate()); - EXPECT_TRUE(m_manager->issilentMode()); - EXPECT_EQ(m_manager->getConvertDestFile(), "output.dlt"); - EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); - EXPECT_EQ(m_manager->get_convertionmode(), e_DDLT); - EXPECT_TRUE(m_manager->isCommandlineMode()); - EXPECT_EQ(m_manager->getProjectFile(), "decoded.dlp"); -} - -TEST_F(OptManagerTest, pluginPostCommands) { - auto args = QStringList() << "executable" - << "-p" - << "export.dlp" - << "-e" - << "\"Filetransfer Plugin|export|ftransferdir\"" - << "input.dlt"; - m_manager->parse(args); - - EXPECT_EQ(m_manager->getProjectFile(), "export.dlp"); - EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); - EXPECT_TRUE(m_manager->getPostPluginCommands().contains("\"Filetransfer Plugin|export|ftransferdir\"")); - EXPECT_TRUE(m_manager->isCommandlineMode()); -} - -TEST_F(OptManagerTest, pluginPreCommands) { - auto args = QStringList() << "executable" - << "-b" - << "\"Filetransfer Plugin|export|ftransferdir\"" - << "input.dlt"; - m_manager->parse(args); - - EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); - EXPECT_TRUE(m_manager->getPrePluginCommands().contains("\"Filetransfer Plugin|export|ftransferdir\"")); - EXPECT_TRUE(m_manager->isCommandlineMode()); -} - -TEST_F(OptManagerTest, multipleLogFiles) { - auto args = QStringList() << "executable" << "input1.dlt" << "input2.dlt"; - - m_manager->parse(args); - - EXPECT_TRUE(m_manager->getLogFiles().contains("input1.dlt")); - EXPECT_TRUE(m_manager->getLogFiles().contains("input2.dlt")); -} - -TEST_F(OptManagerTest, pcapFile) { - auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input.pcap"; - - m_manager->parse(args); - - EXPECT_TRUE(m_manager->isTerminate()); - EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); - EXPECT_TRUE(m_manager->getPcapFiles().contains("input.pcap")); - EXPECT_TRUE(m_manager->isCommandlineMode()); -} - -TEST_F(OptManagerTest, mf4Files) { - auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input1.mf4" << "input2.mf4"; - - m_manager->parse(args); - - EXPECT_TRUE(m_manager->isTerminate()); - EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); - EXPECT_TRUE(m_manager->getMf4Files().contains("input1.mf4")); - EXPECT_TRUE(m_manager->getMf4Files().contains("input2.mf4")); - EXPECT_TRUE(m_manager->isCommandlineMode()); -} - -TEST_F(OptManagerTest, version) { - // impossible to check just version because there is a call to exit(0) in the qdltoptmanager - // but any output will be enough to check the version call because it is always printed - auto args = QStringList() << "executable" << "some.dlt"; - - m_manager->parse(args); - - EXPECT_TRUE(logMessageSink.contains("Executable Name:")); - EXPECT_TRUE(logMessageSink.contains("Build time:")); - EXPECT_TRUE(logMessageSink.contains("Version:")); -} diff --git a/src/main.cpp b/src/main.cpp index b347c743..dc8b8db5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,8 +46,9 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); + QStringList arguments = a.arguments(); QDltOptManager *opt = QDltOptManager::getInstance(); - opt->parse(a.arguments()); + opt->parse(&arguments); MainWindow w; w.show(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6ce4badc..6f589a8d 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -281,6 +281,7 @@ MainWindow::~MainWindow() delete sortProxyModel; } + void MainWindow::initState() { /* Settings */ @@ -5719,10 +5720,40 @@ void MainWindow::on_action_menuHelp_Info_triggered() QString("(C) 2016,2024 BMW AG\n")); } -void MainWindow::on_action_menuHelp_Command_Line_triggered() { - QMessageBox::information( - 0, "DLT Viewer - Command line usage\t\t\t\t\t", // tabs used to expand message box ! - QDltOptManager::getInstance()->getHelpText()); + +void MainWindow::on_action_menuHelp_Command_Line_triggered() +{ + // Please copy changes to QDltOptManager::getInstance().cpp - printUsage() + + QMessageBox::information(0, QString("DLT Viewer - Command line usage\t\t\t\t\t"), // tabs used to expand mesage box ! + #ifdef WIN32 + QString("Usage: dlt-viewer.exe [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]\n\n")+ + QString("Options:\n")+ + #else + QString("Usage: dlt-viewer [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]\n\n")+ + QString("Options:\n")+ + #endif + QString(" [logfile]\t\t\tLoading one or more logfiles on startup (must end with .dlt)\n")+ + QString(" [projectfile]\t\tLoading project file on startup (must end with .dlp)\n")+ + QString(" [filterfile]\t\tLoading filterfile on startup (must end with .dlf)\n")+ + QString(" [pcapfile]\tImporting DLT/IPC from pcap file on startup (must end with .pcap)\n")+ + QString(" [mf4file]\tImporting DLT/IPC from mf4 file on startup (must end with .mf4)\n")+ + QString(" -h\t\t\tPrint usage\n")+ + QString(" -s\t\t\tEnable silent mode without any GUI. Ideal for commandline usage.\n")+ + QString(" -stream\tTreat the input logfiles as DLT stream instead of DLT files.\n")+ + QString(" -v\t\t\tShow version and buildtime information\n")+ + QString(" -c \tConvert logfile to ASCII textfile\n")+ + QString(" -u\t\t\tExport logfile to UTF8 instead\n")+ + QString(" -csv\t\t\tExport logfile to csv ( Excel ) instead\n")+ + QString(" -d\t\t\tExport logfile to DLT format\n")+ + QString(" -dd\t\t\tExport logfile to decoded DLT format\n")+ + QString(" -b |command|param1|..|param\n\t\t\tExecute a command plugin with parameters before loading log file\n")+ + QString(" -e |command|param1|..|param\n\t\t\tExecute a command plugin with parameters after loading log file\n")+ + QString(" -t\t\t\tTerminate DLT Viewer after command line execution\n")+ + QString(" -v\t\t\tShow version and buildtime information\n")+ + QString(" -w workingdirectory\tSet the working directory\n")+ + QString(" -delimiter \tThe used delimiter for CSV export (Default: ,)\n") + ); } void MainWindow::on_pluginWidget_itemSelectionChanged() From 70fab9e171ca9d2fa5b9dd480f90dbbdf17e9117 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Thu, 10 Oct 2024 09:34:20 +0200 Subject: [PATCH 15/21] Fix setting filter index range start and stop when filter are active. (#555) Signed-off-by: Alexander Wenzel --- src/mainwindow.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6f589a8d..984adb70 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -6693,7 +6693,8 @@ void MainWindow::filterIndexStart() } } - ui->lineEditFilterStart->setText(QString("%1").arg(index.row())); + quint64 pos = qfile.getMsgFilterPos(index.row()); + ui->lineEditFilterStart->setText(QString("%1").arg(pos)); } void MainWindow::filterIndexEnd() @@ -6717,8 +6718,8 @@ void MainWindow::filterIndexEnd() } } - ui->lineEditFilterEnd->setText(QString("%1").arg(index.row())); - + quint64 pos = qfile.getMsgFilterPos(index.row()); + ui->lineEditFilterEnd->setText(QString("%1").arg(pos)); } void MainWindow::filterAddTable() { From f8483534aa98bb9b9c6a2e9c9feac6868e4936c4 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Fri, 11 Oct 2024 07:39:43 +0200 Subject: [PATCH 16/21] Revert/Remove Regex Replace feature for DLT Export. (#556) This causes currently issues with non verbose messages. Signed-off-by: Alexander Wenzel --- qdlt/qdltexporter.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qdlt/qdltexporter.cpp b/qdlt/qdltexporter.cpp index 42934852..ae2aba93 100644 --- a/qdlt/qdltexporter.cpp +++ b/qdlt/qdltexporter.cpp @@ -425,6 +425,7 @@ void QDltExporter::exportMessages(QDltFile *from, QFile *to, QDltPluginManager * // decode message if needed if(exportFormat != QDltExporter::FormatDlt) { + //FIXME: The following does not work for non verbose messages, must be fixed if(pluginManager) pluginManager->decodeMsg(msg,silentMode); if (exportFormat == QDltExporter::FormatDltDecoded) @@ -437,9 +438,10 @@ void QDltExporter::exportMessages(QDltFile *from, QFile *to, QDltPluginManager * // apply Regex if needed if(exportFormat == QDltExporter::FormatDlt || exportFormat == QDltExporter::FormatDltDecoded) { - msg.setNumberOfArguments(msg.sizeArguments()); - if(from) from->applyRegExStringMsg(msg); - msg.getMsg(buf,true); + //FIXME: The following does not work for non verbose messages, must be fixed to enable RegEx for DLT Export again + //msg.setNumberOfArguments(msg.sizeArguments()); + //if(from) from->applyRegExStringMsg(msg); + //msg.getMsg(buf,true); } // export message From df96a31b908460dadb0cba63832ef8090f29073d Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Fri, 11 Oct 2024 08:02:49 +0200 Subject: [PATCH 17/21] Rename build file for Darwin --- .github/workflows/BuildPR.yml | 2 +- .github/workflows/Release.yml | 2 +- scripts/darwin/{build.sh => build_cmake.sh} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename scripts/darwin/{build.sh => build_cmake.sh} (100%) diff --git a/.github/workflows/BuildPR.yml b/.github/workflows/BuildPR.yml index d399e8ef..f0ff44f9 100644 --- a/.github/workflows/BuildPR.yml +++ b/.github/workflows/BuildPR.yml @@ -38,7 +38,7 @@ jobs: - name: Show cmake version run: cmake --version - name: Build project - run: scripts/darwin/build.sh + run: scripts/darwin/build_cmake.sh - name: Codesign app bundle if: "! github.event.pull_request.head.repo.fork " # not running on a fork # Extract the secrets we defined earlier as environment variables diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index e235fa01..36cde841 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -34,7 +34,7 @@ jobs: - name: install build environment run: scripts/darwin/install.sh - name: Build project - run: scripts/darwin/build.sh + run: scripts/darwin/build_cmake.sh - name: Codesign app bundle if: "! github.event.pull_request.head.repo.fork " # not running on a fork # Extract the secrets we defined earlier as environment variables diff --git a/scripts/darwin/build.sh b/scripts/darwin/build_cmake.sh similarity index 100% rename from scripts/darwin/build.sh rename to scripts/darwin/build_cmake.sh From 3f344ddbd074be7aef0ffd43e23074111573675c Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Fri, 11 Oct 2024 08:16:46 +0200 Subject: [PATCH 18/21] Rename qmake build file for Windows --- ...dows_qt5_MSVC.bat => build_parser_windows_qt5_MSVC_qmake.bat | 0 ...tive.bat => build_sdk_windows_qt5_MSVC_interactive_qmake.bat | 2 +- ...windows_qt5_MSVC.bat => build_sdk_windows_qt5_MSVC_qmake.bat | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename build_parser_windows_qt5_MSVC.bat => build_parser_windows_qt5_MSVC_qmake.bat (100%) rename build_sdk_windows_qt5_MSVC_interactive.bat => build_sdk_windows_qt5_MSVC_interactive_qmake.bat (60%) rename build_sdk_windows_qt5_MSVC.bat => build_sdk_windows_qt5_MSVC_qmake.bat (100%) diff --git a/build_parser_windows_qt5_MSVC.bat b/build_parser_windows_qt5_MSVC_qmake.bat similarity index 100% rename from build_parser_windows_qt5_MSVC.bat rename to build_parser_windows_qt5_MSVC_qmake.bat diff --git a/build_sdk_windows_qt5_MSVC_interactive.bat b/build_sdk_windows_qt5_MSVC_interactive_qmake.bat similarity index 60% rename from build_sdk_windows_qt5_MSVC_interactive.bat rename to build_sdk_windows_qt5_MSVC_interactive_qmake.bat index ce3f7cf1..7955d535 100644 --- a/build_sdk_windows_qt5_MSVC_interactive.bat +++ b/build_sdk_windows_qt5_MSVC_interactive_qmake.bat @@ -1,4 +1,4 @@ -call build_sdk_windows_qt5_MSVC.bat +call build_sdk_windows_qt5_MSVC_qmake.bat SET RETCODE=%ERRORLEVEL% set /p name= Continue exit /b %RETCODE% \ No newline at end of file diff --git a/build_sdk_windows_qt5_MSVC.bat b/build_sdk_windows_qt5_MSVC_qmake.bat similarity index 100% rename from build_sdk_windows_qt5_MSVC.bat rename to build_sdk_windows_qt5_MSVC_qmake.bat From ded40327f397b6d8d34e649df4f3b547bd38d961 Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Fri, 11 Oct 2024 08:18:07 +0200 Subject: [PATCH 19/21] Linux build only with cmake in CI --- scripts/linux/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/linux/build.sh b/scripts/linux/build.sh index 3c36089b..f625c5a2 100755 --- a/scripts/linux/build.sh +++ b/scripts/linux/build.sh @@ -17,9 +17,9 @@ rm -rf "${SRC_DIR}/build" mkdir -p "${BUILD_DIR}" cd "${BUILD_DIR}" -echo Build with QMake -qmake ../BuildDltViewer.pro -make -j ${NPROC} +#echo Build with QMake +#qmake ../BuildDltViewer.pro +#make -j ${NPROC} echo Cleanup rm -rf "${INSTALL_DIR}" From ec8082770bb5dd6bdaf3e927c51a974a8f2c86c1 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Mon, 14 Oct 2024 16:10:49 +0200 Subject: [PATCH 20/21] Fix and Improve RegEx Replace feature. (#565) RegEx Replace will only be executed when filter matches. Re enable RegEx Replace for DLT Export, no influence on non verbose messages anymore. Signed-off-by: Alexander Wenzel --- qdlt/qdltexporter.cpp | 11 ++++++----- qdlt/qdltfile.cpp | 7 ++++--- qdlt/qdltfile.h | 2 +- qdlt/qdltfilterlist.cpp | 6 +++--- qdlt/qdltfilterlist.h | 2 +- src/searchtablemodel.cpp | 5 +++-- src/tablemodel.cpp | 6 +++--- 7 files changed, 21 insertions(+), 18 deletions(-) diff --git a/qdlt/qdltexporter.cpp b/qdlt/qdltexporter.cpp index ae2aba93..e58bfc69 100644 --- a/qdlt/qdltexporter.cpp +++ b/qdlt/qdltexporter.cpp @@ -70,7 +70,7 @@ void QDltExporter::writeCSVLine(int index, QFile *to, QDltMsg msg) text += escapeCSVValue(QString("%1").arg(msg.getModeString())).append(delimiter); text += escapeCSVValue(QString("%1").arg(msg.getNumberOfArguments())).append(delimiter); QString payload = msg.toStringPayload().simplified().remove(QChar::Null); - if(from) from->applyRegExString(payload); + if(from) from->applyRegExString(msg,payload); text += escapeCSVValue(payload); text += "\n"; @@ -283,7 +283,7 @@ bool QDltExporter::exportMsg(unsigned long int num, QDltMsg &msg, QByteArray &bu text += " "; } QString payload = msg.toStringPayload().simplified().remove(QChar::Null); - if(from) from->applyRegExString(payload); + if(from) from->applyRegExString(msg,payload); text += payload; text += "\n"; try @@ -331,7 +331,7 @@ bool QDltExporter::exportMsg(unsigned long int num, QDltMsg &msg, QByteArray &bu else text += "|" + QString("%1.%2").arg(msg.getTimeString()).arg(msg.getMicroseconds(),6,10,QLatin1Char('0')); QString payload = msg.toStringPayload().simplified().remove(QChar::Null); - if(from) from->applyRegExString(payload); + if(from) from->applyRegExString(msg,payload); text += "|" + QString("%1.%2").arg(msg.getTimestamp()/10000).arg(msg.getTimestamp()%10000,4,10,QLatin1Char('0')) + "|" + msg.getEcuid() + "|" + msg.getApid() + @@ -440,8 +440,9 @@ void QDltExporter::exportMessages(QDltFile *from, QFile *to, QDltPluginManager * { //FIXME: The following does not work for non verbose messages, must be fixed to enable RegEx for DLT Export again //msg.setNumberOfArguments(msg.sizeArguments()); - //if(from) from->applyRegExStringMsg(msg); - //msg.getMsg(buf,true); + bool isApplied = false; + if(from) isApplied = from->applyRegExStringMsg(msg); + if(isApplied) msg.getMsg(buf,true); } // export message diff --git a/qdlt/qdltfile.cpp b/qdlt/qdltfile.cpp index e0ef1748..1b97144e 100644 --- a/qdlt/qdltfile.cpp +++ b/qdlt/qdltfile.cpp @@ -755,12 +755,13 @@ void QDltFile::setIndexFilter(QVector _indexFilter) indexFilter = _indexFilter; } -bool QDltFile::applyRegExString(QString &text) +bool QDltFile::applyRegExString(QDltMsg &msg,QString &text) { - return filterList.applyRegExString(text); + + return filterList.applyRegExString(msg,text); } bool QDltFile::applyRegExStringMsg(QDltMsg &msg) -{ +{ return filterList.applyRegExStringMsg(msg); } diff --git a/qdlt/qdltfile.h b/qdlt/qdltfile.h index b6a4e399..c07963d8 100644 --- a/qdlt/qdltfile.h +++ b/qdlt/qdltfile.h @@ -302,7 +302,7 @@ class QDLT_EXPORT QDltFile : public QDlt //! Apply RegEx Replace to the string, if any active in the filters /*! */ - bool applyRegExString(QString &text); + bool applyRegExString(QDltMsg &msg,QString &text); //! Apply RegEx Replace to the arguments of a message, if any active in the filters /*! diff --git a/qdlt/qdltfilterlist.cpp b/qdlt/qdltfilterlist.cpp index c5a976e6..0152585c 100644 --- a/qdlt/qdltfilterlist.cpp +++ b/qdlt/qdltfilterlist.cpp @@ -124,7 +124,7 @@ QString QDltFilterList::checkMarker(QDltMsg &msg) #endif -bool QDltFilterList::applyRegExString(QString &text) +bool QDltFilterList::applyRegExString(QDltMsg &msg,QString &text) { QDltFilter *filter; bool result = false; @@ -133,7 +133,7 @@ bool QDltFilterList::applyRegExString(QString &text) { filter = pfilters[numfilter]; - if(filter->enableFilter && filter->enableRegexSearchReplace) + if(filter->enableFilter && filter->enableRegexSearchReplace && filter->match(msg)) { text.replace(QRegularExpression(filter->regex_search), filter->regex_replace); result = true; @@ -151,7 +151,7 @@ bool QDltFilterList::applyRegExStringMsg(QDltMsg &msg) { filter = pfilters[numfilter]; - if(filter->enableFilter && filter->enableRegexSearchReplace) + if(filter->enableFilter && filter->enableRegexSearchReplace && filter->match(msg)) { for(int num=0;numvalue("startup/filtersEnabled", true).toBool())) + if(qfile) qfile->applyRegExString(msg,visu_data); + /*if((QDltSettingsManager::getInstance()->value("startup/filtersEnabled", true).toBool())) { for(int num = 0; num < project->filter->topLevelItemCount (); num++) { FilterItem *item = (FilterItem*)project->filter->topLevelItem(num); @@ -171,7 +172,7 @@ QVariant SearchTableModel::data(const QModelIndex &index, int role) const visu_data.replace(QRegularExpression(item->filter.regex_search), item->filter.regex_replace); } } - } + }*/ return visu_data; case FieldNames::MessageId: return QString::asprintf(project->settings->msgIdFormat.toUtf8(),msg.getMessageId()); diff --git a/src/tablemodel.cpp b/src/tablemodel.cpp index 1018ff28..c4cf1a0d 100644 --- a/src/tablemodel.cpp +++ b/src/tablemodel.cpp @@ -248,8 +248,8 @@ TableModel::TableModel(const QString & /*data*/, QObject *parent) } /* display payload */ visu_data = msg.toStringPayload().simplified().remove(QChar::Null); - - if((QDltSettingsManager::getInstance()->value("startup/filtersEnabled", true).toBool())) + if(qfile) qfile->applyRegExString(msg,visu_data); + /*if((QDltSettingsManager::getInstance()->value("startup/filtersEnabled", true).toBool())) { for(int num = 0; num < project->filter->topLevelItemCount (); num++) { FilterItem *item = (FilterItem*)project->filter->topLevelItem(num); @@ -257,7 +257,7 @@ TableModel::TableModel(const QString & /*data*/, QObject *parent) visu_data.replace(QRegularExpression(item->filter.regex_search), item->filter.regex_replace); } } - } + }*/ /* limit size of string to 1000 characters to speed up scrolling */ if(visu_data.size()>1000) From 7a6700e5dd48eab8f552ed0542c6782f5b734976 Mon Sep 17 00:00:00 2001 From: Viktor Kopp Date: Mon, 14 Oct 2024 16:17:48 +0200 Subject: [PATCH 21/21] Add QDltOptmanager unit tests and minor cleanup (#564) * Add unit tests for qdltoptmanager * Avoid double work when adding cmd argument Reuse help text in main window * Avoid duplicate text on --version call * Remove redundant code in QDltOptmanager singleton * Avoid -Wempty-body compiler warnings Signed-off-by: Viktor Kopp --- qdlt/qdltexporter.cpp | 36 +++--- qdlt/qdltoptmanager.cpp | 180 ++++++++++++++-------------- qdlt/qdltoptmanager.h | 23 ++-- qdlt/tests/CMakeLists.txt | 24 +++- qdlt/tests/test_dltoptmanager.cpp | 191 ++++++++++++++++++++++++++++++ src/main.cpp | 5 +- src/mainwindow.cpp | 38 +----- 7 files changed, 339 insertions(+), 158 deletions(-) create mode 100644 qdlt/tests/test_dltoptmanager.cpp diff --git a/qdlt/qdltexporter.cpp b/qdlt/qdltexporter.cpp index e58bfc69..8fc52382 100644 --- a/qdlt/qdltexporter.cpp +++ b/qdlt/qdltexporter.cpp @@ -99,12 +99,12 @@ bool QDltExporter::start() { if(!to->open(QIODevice::WriteOnly | QIODevice::Text)) { - if ( true == QDltOptManager::getInstance()->issilentMode() ) - { - qDebug() << QString("ERROR - cannot open the export file %1").arg(to->fileName()); - } - else - ;//QMessageBox::critical(qobject_cast(parent()), QString("DLT Viewer"), + if (QDltOptManager::getInstance()->issilentMode()) + { + qDebug() << QString("ERROR - cannot open the export file %1").arg(to->fileName()); + } + //else + //QMessageBox::critical(qobject_cast(parent()), QString("DLT Viewer"), // QString("Cannot open the export file %1").arg(to->fileName())); return false; } @@ -113,12 +113,12 @@ bool QDltExporter::start() { if(!to->open(QIODevice::WriteOnly)) { - if ( true == QDltOptManager::getInstance()->issilentMode() ) - { - qDebug() << QString("ERROR - cannot open the export file %1").arg(to->fileName()); - } - else - ;//QMessageBox::critical(qobject_cast(parent()), QString("DLT Viewer"), + if (QDltOptManager::getInstance()->issilentMode() ) + { + qDebug() << QString("ERROR - cannot open the export file %1").arg(to->fileName()); + } + //else + //QMessageBox::critical(qobject_cast(parent()), QString("DLT Viewer"), // QString("Cannot open the export file %1").arg(to->fileName())); return false; } @@ -130,12 +130,12 @@ bool QDltExporter::start() /* Write the first line of CSV file */ if(!writeCSVHeader(to)) { - if ( true == QDltOptManager::getInstance()->issilentMode() ) - { - qDebug() << QString("ERROR - cannot open the export file %1").arg(to->fileName()); - } - else - ;//QMessageBox::critical(qobject_cast(parent()), QString("DLT Viewer"), + if(QDltOptManager::getInstance()->issilentMode()) + { + qDebug() << QString("ERROR - cannot open the export file %1").arg(to->fileName()); + } + //else + //QMessageBox::critical(qobject_cast(parent()), QString("DLT Viewer"), // QString("Cannot open the export file %1").arg(to->fileName())); return false; } diff --git a/qdlt/qdltoptmanager.cpp b/qdlt/qdltoptmanager.cpp index c422b762..3c9eb874 100644 --- a/qdlt/qdltoptmanager.cpp +++ b/qdlt/qdltoptmanager.cpp @@ -26,30 +26,11 @@ #include #include -// Global static pointer used to ensure a single instance of the class. -QDltOptManager* QDltOptManager::instance; - -QDltOptManager::QDltOptManager() -{ - project = false; - silent_mode = false; - terminate=false; - convertionmode = e_ASCI; - commandline_mode = false; - delimiter=','; -} - QDltOptManager* QDltOptManager::getInstance() { - if (!instance) - instance = new QDltOptManager; - - return instance; -} - -QDltOptManager::QDltOptManager(QDltOptManager const&) -{ + static QDltOptManager instance; + return &instance; } const QStringList &QDltOptManager::getMf4Files() const @@ -81,32 +62,8 @@ void QDltOptManager::printVersion(QString appname) void QDltOptManager::printUsage() { -#if (WIN32) - qDebug()<<"Usage: dlt-viewer.exe [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]"; -#else - qDebug()<<"Usage: dlt-viewer [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]"; -#endif + qDebug().noquote() << getHelpText(); - qDebug()<<"\nOptions:"; - qDebug()<<" [logfile]\tLoading one or more logfiles on startup (must end with .dlt)"; - qDebug()<<" [projectfile]\tLoading project file on startup (must end with .dlp)"; - qDebug()<<" [filterfile]\tLoading filterfile on startup (must end with .dlf)"; - qDebug()<<" [pcapfile]\tImporting DLT/IPC from pcap file on startup (must end with .pcap)"; - qDebug()<<" [mf4file]\tImporting DLT/IPC from mf4 file on startup (must end with .mf4)"; - qDebug()<<" -h or --help\tPrint usage"; - qDebug()<<" -c textfile\tConvert logfile file to textfile"; - qDebug()<<" -u\tConversion will be done in UTF8 instead of ASCII"; - qDebug()<<" -csv\tConversion will be done in CSV format"; - qDebug()<<" -d\tConversion will NOT be done, save in dlt file format again instead"; - qDebug()<<" -dd\tConversion will NOT be done, save as decoded messages in dlt format"; - qDebug()<<" -b \"plugin|command|param1|..|param\"\tExecute a plugin command with parameters before loading log file."; - qDebug()<<" -e \"plugin|command|param1|..|param\"\tExecute a plugin command with parameters after loading log file."; - qDebug()<<" -s or --silent\tEnable silent mode without any GUI. Ideal for commandline usage."; - qDebug()<<" -stream\tTreat the input logfiles as DLT stream instead of DLT files."; - qDebug()<<" -t or --terminate\tTerminate DLT Viewer after command line execution."; - qDebug()<<" -v or --version\tOnly show version and buildtime information"; - qDebug()<<" -w workingdirectory\tSet the working directory"; - qDebug()<<" -delimiter \tThe used delimiter for CSV export (Default: ,)."; qDebug()<<"\nExamples:"; qDebug()<<" dlt-viewer.exe -t -c output.txt input.dlt"; qDebug()<<" dlt-viewer.exe -t -s -u -c output.txt input.dlt"; @@ -120,42 +77,37 @@ void QDltOptManager::printUsage() qDebug()<<" dlt-viewer.exe -t -c output.txt input1.mf4 input2.mf4"; } -void QDltOptManager::parse(QStringList *opt) +void QDltOptManager::parse(QStringList&& opt) { - QString str; - qDebug() << "### Starting DLT Viewer"; - printVersion(opt->at(0)); + printVersion(opt.at(0)); qDebug() << "### Parsing Options"; /* the default parameter - exactly one parameter - should either be * a dlt or a dlp file, so this enables the "doubleclick" feature */ - //str = opt->at(0); && ( str.compare("-h)") != 0 || str.compare("-v") !=0 ) - if(opt->size()==2 ) - { - if(opt->at(1).endsWith(".dlp") || opt->at(1).endsWith(".DLP")) - { - projectFile = QString("%1").arg(opt->at(1)); - project = true; - qDebug()<< "Project filename:" << projectFile; - return; - } - if(opt->at(1).endsWith(".dlt") || opt->at(1).endsWith(".DLT")) - { - const QString logFile = QString("%1").arg(opt->at(1)); - logFiles += logFile; - qDebug()<< "DLT filename:" << logFile; - return; - } - } + //str = opt.at(0); && ( str.compare("-h)") != 0 || str.compare("-v") !=0 ) + if (opt.size() == 2) { + if (opt.at(1).endsWith(".dlp") || opt.at(1).endsWith(".DLP")) { + projectFile = QString("%1").arg(opt.at(1)); + project = true; + qDebug() << "Project filename:" << projectFile; + return; + } + if (opt.at(1).endsWith(".dlt") || opt.at(1).endsWith(".DLT")) { + const QString logFile = QString("%1").arg(opt.at(1)); + logFiles += logFile; + qDebug() << "DLT filename:" << logFile; + return; + } + } // 0==Binary 1==First Argument - for (int i = 0; i < opt->size(); ++i) + for (int i = 0; i < opt.size(); ++i) { - str = opt->at(i); + QString str = opt.at(i); if(str.compare("-h") == 0 || str.compare("--help") == 0) { @@ -172,7 +124,7 @@ void QDltOptManager::parse(QStringList *opt) } else if(str.compare("-v") == 0 || str.compare("--version") == 0) { - printVersion(opt->at(0)); + // version has already been printed above, just exit exit(0); } else if(str.compare("-t") == 0 || str.compare("--terminate") == 0) @@ -182,7 +134,7 @@ void QDltOptManager::parse(QStringList *opt) } else if(str.compare("-c")==0) { - QString c1 = opt->value(i+1); + QString c1 = opt.value(i+1); convertDestFile = QString("%1").arg(c1); // check here already if the selected file exists @@ -194,7 +146,7 @@ void QDltOptManager::parse(QStringList *opt) } else if(str.compare("-delimiter")==0) { - QString c1 = opt->value(i+1); + QString c1 = opt.value(i+1); delimiter = QString("%1").arg(c1).front().toLatin1(); @@ -224,30 +176,30 @@ void QDltOptManager::parse(QStringList *opt) } else if(str.compare("-e")==0) { - QString c = opt->value(i+1); + QString c = opt.value(i+1); postPluginCommands += c; commandline_mode = true; ++i; } else if(str.compare("-b")==0) { - QString c = opt->value(i+1); + QString c = opt.value(i+1); prePluginCommands += c; commandline_mode = true; ++i; } else if (str.compare("-w") == 0) { - workingDirectory = opt->value(i+1); + workingDirectory = opt.value(i+1); ++i; } - else if(opt->at(i).endsWith(".dlt") || opt->at(i).endsWith(".DLT")) + else if(opt.at(i).endsWith(".dlt") || opt.at(i).endsWith(".DLT")) { - const QString logFile = QString("%1").arg(opt->at(i)); + const QString logFile = QString("%1").arg(opt.at(i)); logFiles += logFile; qDebug()<< "DLT filename:" << logFile; } - else if(opt->at(i).endsWith(".dlp") || opt->at(i).endsWith(".DLP")) + else if(opt.at(i).endsWith(".dlp") || opt.at(i).endsWith(".DLP")) { if (project == true) { @@ -256,24 +208,24 @@ void QDltOptManager::parse(QStringList *opt) exit(-1); } - projectFile = QString("%1").arg(opt->at(i)); + projectFile = QString("%1").arg(opt.at(i)); project = true; qDebug()<< "Project filename:" << projectFile; } - else if(opt->at(i).endsWith(".dlf") || opt->at(i).endsWith(".DLF")) + else if(opt.at(i).endsWith(".dlf") || opt.at(i).endsWith(".DLF")) { - filterFiles += QString("%1").arg(opt->at(i)); - qDebug()<< "Filter filename:" << QString("%1").arg(opt->at(i)); + filterFiles += QString("%1").arg(opt.at(i)); + qDebug()<< "Filter filename:" << QString("%1").arg(opt.at(i)); } - else if(opt->at(i).endsWith(".pcap") || opt->at(i).endsWith(".PCAP")) + else if(opt.at(i).endsWith(".pcap") || opt.at(i).endsWith(".PCAP")) { - const QString pcapFile = QString("%1").arg(opt->at(i)); + const QString pcapFile = QString("%1").arg(opt.at(i)); pcapFiles += pcapFile; qDebug()<< "Pcap filename:" << pcapFile; } - else if(opt->at(i).endsWith(".mf4") || opt->at(i).endsWith(".MF4")) + else if(opt.at(i).endsWith(".mf4") || opt.at(i).endsWith(".MF4")) { - const QString mf4File = QString("%1").arg(opt->at(i)); + const QString mf4File = QString("%1").arg(opt.at(i)); mf4Files += mf4File; qDebug()<< "MF4 filename:" << mf4File; } @@ -315,3 +267,57 @@ QString QDltOptManager::getCommandName(){return commandName;} QStringList QDltOptManager::getCommandParams(){return commandParams;} QString QDltOptManager::getWorkingDirectory() const { return workingDirectory; } char QDltOptManager::getDelimiter(){return delimiter;} + +QString QDltOptManager::getHelpText() const { + QStringList helpText; +#if (WIN32) + helpText << "Usage: dlt-viewer.exe [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]"; +#else + helpText << "Usage: dlt-viewer [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]"; +#endif + + helpText << "\nOptions:"; + helpText << " [logfile]\tLoading one or more logfiles on startup (must end with .dlt)"; + helpText << " [projectfile]\tLoading project file on startup (must end with .dlp)"; + helpText << " [filterfile]\tLoading filterfile on startup (must end with .dlf)"; + helpText << " [pcapfile]\tImporting DLT/IPC from pcap file on startup (must end with .pcap)"; + helpText << " [mf4file]\tImporting DLT/IPC from mf4 file on startup (must end with .mf4)"; + helpText << " -h or --help\tPrint usage"; + helpText << " -c textfile\tConvert logfile file to textfile"; + helpText << " -u\tConversion will be done in UTF8 instead of ASCII"; + helpText << " -csv\tConversion will be done in CSV format"; + helpText << " -d\tConversion will NOT be done, save in dlt file format again instead"; + helpText << " -dd\tConversion will NOT be done, save as decoded messages in dlt format"; + helpText << " -b \"plugin|command|param1|..|param\"\tExecute a plugin command with parameters before loading log file."; + helpText << " -e \"plugin|command|param1|..|param\"\tExecute a plugin command with parameters after loading log file."; + helpText << " -s or --silent\tEnable silent mode without any GUI. Ideal for commandline usage."; + helpText << " -stream\tTreat the input logfiles as DLT stream instead of DLT files."; + helpText << " -t or --terminate\tTerminate DLT Viewer after command line execution."; + helpText << " -v or --version\tOnly show version and buildtime information"; + helpText << " -w workingdirectory\tSet the working directory"; + helpText << " -delimiter \tThe used delimiter for CSV export (Default: ,)."; + + return helpText.join('\n'); +} + +void QDltOptManager::reset() { + project = false; + terminate = false; + silent_mode = false; + commandline_mode = false; + convertionmode = e_ASCI; + inputmode = e_inputmode::DLT; + projectFile.clear(); + logFiles.clear(); + filterFiles.clear(); + convertDestFile.clear(); + pluginName.clear(); + commandName.clear(); + commandParams.clear(); + prePluginCommands.clear(); + postPluginCommands.clear(); + workingDirectory.clear(); + delimiter = ','; + pcapFiles.clear(); + mf4Files.clear(); +} diff --git a/qdlt/qdltoptmanager.h b/qdlt/qdltoptmanager.h index 6cdda7e1..f1fccd71 100644 --- a/qdlt/qdltoptmanager.h +++ b/qdlt/qdltoptmanager.h @@ -46,7 +46,7 @@ class QDLT_EXPORT QDltOptManager static QDltOptManager* getInstance(); void printUsage(); void printVersion(QString appname); - void parse(QStringList *opt); + void parse(QStringList&& opt); bool isProjectFile(); bool isTerminate(); @@ -71,16 +71,17 @@ class QDLT_EXPORT QDltOptManager const QStringList &getMf4Files() const; char getDelimiter(); + QString getHelpText() const; + + // only testing relevant + void reset(); + private: - QDltOptManager(); - QDltOptManager(QDltOptManager const&); - static QDltOptManager *instance; - - bool project; - bool terminate; - bool silent_mode; - bool commandline_mode; - e_convertionmode convertionmode; + bool project{false}; + bool terminate{false}; + bool silent_mode{false}; + bool commandline_mode{false}; + e_convertionmode convertionmode{e_ASCI}; e_inputmode inputmode{e_inputmode::DLT}; QString projectFile; @@ -97,7 +98,7 @@ class QDLT_EXPORT QDltOptManager QStringList postPluginCommands; // command after loading log file QString workingDirectory; - char delimiter; + char delimiter{','}; }; #endif //QDLTOPTMANAGER_H diff --git a/qdlt/tests/CMakeLists.txt b/qdlt/tests/CMakeLists.txt index beccd1f3..7b65fda1 100644 --- a/qdlt/tests/CMakeLists.txt +++ b/qdlt/tests/CMakeLists.txt @@ -1,15 +1,31 @@ -add_executable(test_tools +add_executable(test_dltmessagematcher test_dltmessagematcher.cpp ) target_link_libraries( - test_tools + test_dltmessagematcher PRIVATE GTest::gtest_main qdlt ) add_test( - NAME test_tools - COMMAND $ + NAME test_dltmessagematcher + COMMAND $ ) + +add_executable(test_dltoptmanager + test_dltoptmanager.cpp +) + +target_link_libraries( + test_dltoptmanager + PRIVATE + GTest::gtest_main + qdlt +) + +add_test( + NAME test_dltoptmanager + COMMAND $ +) diff --git a/qdlt/tests/test_dltoptmanager.cpp b/qdlt/tests/test_dltoptmanager.cpp new file mode 100644 index 00000000..116d19c9 --- /dev/null +++ b/qdlt/tests/test_dltoptmanager.cpp @@ -0,0 +1,191 @@ +#include + +#include + +#include + + +QString logMessageSink; + +void messageHandler(QtMsgType type, const QMessageLogContext &, + const QString &msg) { + if (type == QtDebugMsg) { + logMessageSink.append(msg); + } +} + +class OptManagerTest : public ::testing::Test { +protected: + static void SetUpTestSuite() { + m_manager = QDltOptManager::getInstance(); + + qInstallMessageHandler(messageHandler); + } + + void SetUp() override { + m_manager->reset(); + } + + void TearDown() override { + logMessageSink.clear(); + } + + static QDltOptManager* m_manager; +}; + +QDltOptManager* OptManagerTest::m_manager = nullptr; + +TEST_F(OptManagerTest, txtConversion) { + auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input.dlt"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, txtConversionSilentUtf8Mode) { + auto args = QStringList() << "executable" << "-t" << "-s" << "-u" << "-c" << "output.txt" << "input.dlt"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_EQ(m_manager->get_convertionmode(), e_UTF8); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, txtConversionSilentAsciiMode) { + auto args = QStringList() << "executable" << "-t" << "-s" << "-d" << "-c" << "output.txt" << "input.dlt"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_EQ(m_manager->get_convertionmode(), e_DLT); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, csvConversionSilentMode) { + auto args = QStringList() << "executable" << "-t" << "-s" << "-csv" << "-c" << "output.csv" << "input.dlt"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.csv"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_EQ(m_manager->get_convertionmode(), e_CSV); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, txtConversionSilentDdlMode) { + auto args = QStringList() << "executable" << "-t" << "-s" << "decoded.dlp" << "-dd" << "-c" << "output.dlt" << "input.dlt"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.dlt"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_EQ(m_manager->get_convertionmode(), e_DDLT); + EXPECT_TRUE(m_manager->isCommandlineMode()); + EXPECT_EQ(m_manager->getProjectFile(), "decoded.dlp"); +} + +TEST_F(OptManagerTest, pluginPostCommands) { + auto args = QStringList() << "executable" + << "-p" + << "export.dlp" + << "-e" + << "\"Filetransfer Plugin|export|ftransferdir\"" + << "input.dlt"; + m_manager->parse(std::move(args)); + + EXPECT_EQ(m_manager->getProjectFile(), "export.dlp"); + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_TRUE(m_manager->getPostPluginCommands().contains("\"Filetransfer Plugin|export|ftransferdir\"")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, pluginPreCommands) { + auto args = QStringList() << "executable" + << "-b" + << "\"Filetransfer Plugin|export|ftransferdir\"" + << "input.dlt"; + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_TRUE(m_manager->getPrePluginCommands().contains("\"Filetransfer Plugin|export|ftransferdir\"")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, multipleLogFiles) { + auto args = QStringList() << "executable" << "input1.dlt" << "input2.dlt"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->getLogFiles().contains("input1.dlt")); + EXPECT_TRUE(m_manager->getLogFiles().contains("input2.dlt")); +} + +TEST_F(OptManagerTest, pcapFile) { + auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input.pcap"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getPcapFiles().contains("input.pcap")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, mf4Files) { + auto args = QStringList() << "executable" << "-t" << "-c" << "output.txt" << "input1.mf4" << "input2.mf4"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_EQ(m_manager->getConvertDestFile(), "output.txt"); + EXPECT_TRUE(m_manager->getMf4Files().contains("input1.mf4")); + EXPECT_TRUE(m_manager->getMf4Files().contains("input2.mf4")); + EXPECT_TRUE(m_manager->isCommandlineMode()); +} + +TEST_F(OptManagerTest, filterFile) { + auto args = QStringList() << "executable" + << "input.dlt" + << "filter.dlf" + << "-c" + << "out.dlt" + << "-d" + << "-s" + << "-t"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(m_manager->getLogFiles().contains("input.dlt")); + EXPECT_TRUE(m_manager->getFilterFiles().contains("filter.dlf")); + EXPECT_EQ(m_manager->getConvertDestFile(), "out.dlt"); + EXPECT_TRUE(m_manager->isCommandlineMode()); + EXPECT_TRUE(m_manager->isTerminate()); + EXPECT_TRUE(m_manager->issilentMode()); +} + +TEST_F(OptManagerTest, version) { + // impossible to check just version because there is a call to exit(0) in the qdltoptmanager + // but any output will be enough to check the version call because it is always printed + auto args = QStringList() << "executable" << "some.dlt"; + + m_manager->parse(std::move(args)); + + EXPECT_TRUE(logMessageSink.contains("Executable Name:")); + EXPECT_TRUE(logMessageSink.contains("Build time:")); + EXPECT_TRUE(logMessageSink.contains("Version:")); +} diff --git a/src/main.cpp b/src/main.cpp index dc8b8db5..e3ac3cac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,10 +45,7 @@ int main(int argc, char *argv[]) } QApplication a(argc, argv); - - QStringList arguments = a.arguments(); - QDltOptManager *opt = QDltOptManager::getInstance(); - opt->parse(&arguments); + QDltOptManager::getInstance()->parse(a.arguments()); MainWindow w; w.show(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 984adb70..83702fcf 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -17,7 +17,6 @@ * @licence end@ */ -#include #include #include #include @@ -5721,39 +5720,10 @@ void MainWindow::on_action_menuHelp_Info_triggered() } -void MainWindow::on_action_menuHelp_Command_Line_triggered() -{ - // Please copy changes to QDltOptManager::getInstance().cpp - printUsage() - - QMessageBox::information(0, QString("DLT Viewer - Command line usage\t\t\t\t\t"), // tabs used to expand mesage box ! - #ifdef WIN32 - QString("Usage: dlt-viewer.exe [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]\n\n")+ - QString("Options:\n")+ - #else - QString("Usage: dlt-viewer [OPTIONS] [logfile] [projectfile] [filterfile] [mf4file] [pcapfile]\n\n")+ - QString("Options:\n")+ - #endif - QString(" [logfile]\t\t\tLoading one or more logfiles on startup (must end with .dlt)\n")+ - QString(" [projectfile]\t\tLoading project file on startup (must end with .dlp)\n")+ - QString(" [filterfile]\t\tLoading filterfile on startup (must end with .dlf)\n")+ - QString(" [pcapfile]\tImporting DLT/IPC from pcap file on startup (must end with .pcap)\n")+ - QString(" [mf4file]\tImporting DLT/IPC from mf4 file on startup (must end with .mf4)\n")+ - QString(" -h\t\t\tPrint usage\n")+ - QString(" -s\t\t\tEnable silent mode without any GUI. Ideal for commandline usage.\n")+ - QString(" -stream\tTreat the input logfiles as DLT stream instead of DLT files.\n")+ - QString(" -v\t\t\tShow version and buildtime information\n")+ - QString(" -c \tConvert logfile to ASCII textfile\n")+ - QString(" -u\t\t\tExport logfile to UTF8 instead\n")+ - QString(" -csv\t\t\tExport logfile to csv ( Excel ) instead\n")+ - QString(" -d\t\t\tExport logfile to DLT format\n")+ - QString(" -dd\t\t\tExport logfile to decoded DLT format\n")+ - QString(" -b |command|param1|..|param\n\t\t\tExecute a command plugin with parameters before loading log file\n")+ - QString(" -e |command|param1|..|param\n\t\t\tExecute a command plugin with parameters after loading log file\n")+ - QString(" -t\t\t\tTerminate DLT Viewer after command line execution\n")+ - QString(" -v\t\t\tShow version and buildtime information\n")+ - QString(" -w workingdirectory\tSet the working directory\n")+ - QString(" -delimiter \tThe used delimiter for CSV export (Default: ,)\n") - ); +void MainWindow::on_action_menuHelp_Command_Line_triggered() { + QMessageBox::information( + 0, "DLT Viewer - Command line usage\t\t\t\t\t", // tabs used to expand message box ! + QDltOptManager::getInstance()->getHelpText()); } void MainWindow::on_pluginWidget_itemSelectionChanged()