[multimedia/k3b] /: Consider word boundaries during feature parsing
Albert Astals Cid <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit ba63705a21502406b53743264982eb287783ead7 by Albert Astals Cid, on behalf of Ole Osterhagen.
Committed on 06/08/2026 at 19:09.
Pushed by aacid into branch 'master'.
Consider word boundaries during feature parsing
A simple substring search without taking word boundaries into account
can lead to wrong results. E.g. for xorrisofs, which can be used as a
replacement for mkisofs, the feature "xa" should not be listed, as this
command has no option -xa (only --xattr and --xattr-any).
In a few cases the search string has been adjusted:
cdda2wav
* dev= -> dev=device
cdrecord
* gracetime -> gracetime=#
* cuefile= -> cuefile=name
cdrskin
* gracetime -> gracetime=#
M +48 -26 libk3b/core/k3bdefaultexternalprograms.cpp
M +2 -0 libk3b/core/k3bdefaultexternalprograms.h
M +6 -0 tests/CMakeLists.txt
A +34 -0 tests/k3bdefaultexternalprogramstest.cpp *
A +15 -0 tests/k3bdefaultexternalprogramstest.h *
The files marked with a * at the end have a non valid license. Please read: https://community.kde.org/Policies/Licensing_Policy and use the headers which are listed at that page.
https://invent.kde.org/multimedia/k3b/-/commit/ba63705a21502406b53743264982eb287783ead7
diff --git a/libk3b/core/k3bdefaultexternalprograms.cpp b/libk3b/core/k3bdefaultexternalprograms.cpp
index f06491414..6334f9e54 100644
--- a/libk3b/core/k3bdefaultexternalprograms.cpp
+++ b/libk3b/core/k3bdefaultexternalprograms.cpp
@@ -20,6 +20,8 @@
#include <QStringList>
#include <QTextStream>
+using namespace Qt::StringLiterals;
+
void K3b::addDefaultPrograms( K3b::ExternalBinManager* m )
{
@@ -67,6 +69,26 @@ void K3b::addVcdimagerPrograms( K3b::ExternalBinManager* m )
}
+bool K3b::containsWord( const QString& haystack, QStringView needle )
+{
+ if( needle.length() == 0 )
+ return true;
+
+ for( qsizetype index = 0;; ) {
+ index = haystack.indexOf( needle, index );
+ if( index == -1 )
+ return false;
+ if( index > 0 && !haystack[index - 1].isSpace() ) {
+ index += needle.length();
+ continue;
+ }
+ index += needle.length();
+ if( index >= haystack.length() || haystack[index].isSpace() )
+ return true;
+ }
+}
+
+
class K3b::AbstractCdrtoolsProgram::Private
{
public:
@@ -188,17 +210,17 @@ void K3b::CdrecordProgram::parseFeatures( const QString& output, ExternalBin& bi
bin.setVersion( QString(bin.version().versionString()).remove("-dvd") );
}
- if( output.contains( "gracetime" ) )
+ if( containsWord( output, u"gracetime=#"_s ) )
bin.addFeature( "gracetime" );
- if( output.contains( "-overburn" ) )
+ if( containsWord( output, u"-overburn"_s ) )
bin.addFeature( "overburn" );
- if( output.contains( "-text" ) )
+ if( containsWord( output, u"-text"_s ) )
bin.addFeature( "cdtext" );
- if( output.contains( "-clone" ) )
+ if( containsWord( output, u"-clone"_s ) )
bin.addFeature( "clone" );
- if( output.contains( "-tao" ) )
+ if( containsWord( output, u"-tao"_s ) )
bin.addFeature( "tao" );
- if( output.contains( "cuefile=" ) &&
+ if( containsWord( output, u"cuefile=name"_s ) &&
( usingCdrkit( bin ) || bin.version() > K3b::Version( 2, 1, -1, "a14") ) ) // cuefile handling was still buggy in a14
bin.addFeature( "cuefile" );
@@ -207,7 +229,7 @@ void K3b::CdrecordProgram::parseFeatures( const QString& output, ExternalBin& bi
// just double-checked and the help page is proper but there is no harm in having
// two checks)
// and the version check does not handle versions like 2.01-dvd properly
- if( output.contains( "-xamix" ) ||
+ if( containsWord( output, u"-xamix"_s ) ||
bin.version() >= K3b::Version( 2, 1, -1, "a12" ) ||
usingCdrkit( bin ) )
bin.addFeature( "xamix" );
@@ -252,15 +274,15 @@ void K3b::MkisofsProgram::parseFeatures( const QString& output, ExternalBin& bin
if( usingCdrkit( bin ) )
bin.addFeature( "genisoimage" );
- if( output.contains( "-udf" ) )
+ if( containsWord( output, u"-udf"_s ) )
bin.addFeature( "udf" );
- if( output.contains( "-dvd-video" ) )
+ if( containsWord( output, u"-dvd-video"_s ) )
bin.addFeature( "dvd-video" );
- if( output.contains( "-joliet-long" ) )
+ if( containsWord( output, u"-joliet-long"_s ) )
bin.addFeature( "joliet-long" );
- if( output.contains( "-xa" ) )
+ if( containsWord( output, u"-xa"_s ) )
bin.addFeature( "xa" );
- if( output.contains( "-sectype" ) )
+ if( containsWord( output, u"-sectype"_s ) )
bin.addFeature( "sectype" );
if( bin.version() < K3b::Version( 1, 14) && !usingCdrkit( bin ) )
@@ -288,7 +310,7 @@ void K3b::ReadcdProgram::parseFeatures( const QString& output, ExternalBin& bin
if( usingCdrkit( bin ) )
bin.addFeature( "readom" );
- if( output.contains( "-clone" ) )
+ if( containsWord( output, u"-clone"_s ) )
bin.addFeature( "clone" );
// FIXME: are these version correct?
@@ -309,15 +331,15 @@ void K3b::Cdda2wavProgram::parseFeatures( const QString& output, ExternalBin& bi
{
// features (we do this since the cdda2wav help says that the short
// options will disappear soon)
- if( output.indexOf( "-info-only" ) )
+ if( containsWord( output, u"-info-only"_s ) )
bin.addFeature( "info-only" ); // otherwise use the -J option
- if( output.indexOf( "-no-infofile" ) )
+ if( containsWord( output, u"-no-infofile"_s ) )
bin.addFeature( "no-infofile" ); // otherwise use the -H option
- if( output.indexOf( "-gui" ) )
+ if( containsWord( output, u"-gui"_s ) )
bin.addFeature( "gui" ); // otherwise use the -g option
- if( output.indexOf( "-bulk" ) )
+ if( containsWord( output, u"-bulk"_s ) )
bin.addFeature( "bulk" ); // otherwise use the -B option
- if( output.indexOf( "dev=" ) )
+ if( containsWord( output, u"dev=device"_s ) )
bin.addFeature( "dev" ); // otherwise use the -B option
}
@@ -343,12 +365,12 @@ bool K3b::CdrdaoProgram::scanFeatures( ExternalBin& bin ) const
if( fp.execute() >= 0 ) {
QByteArray out = fp.readAll();
- if( out.contains( "--overburn" ) )
+ if( containsWord( out, u"--overburn"_s ) )
bin.addFeature( "overburn" );
- if( out.contains( "--multi" ) )
+ if( containsWord( out, u"--multi"_s ) )
bin.addFeature( "multisession" );
- if( out.contains( "--buffer-under-run-protection" ) )
+ if( containsWord( out, u"--buffer-under-run-protection"_s ) )
bin.addFeature( "disable-burnproof" );
// SuSE 9.0 ships with a patched cdrdao 1.1.7 which contains an updated libschily
@@ -546,15 +568,15 @@ bool K3b::CdrskinProgram::scanFeatures(ExternalBin& bin) const
if (fp.execute() >= 0) {
QByteArray output = fp.readAll();
- if (output.contains("gracetime"))
+ if (containsWord(output, u"gracetime=#"_s))
bin.addFeature("gracetime");
- if (output.contains("-overburn"))
+ if (containsWord(output, u"-overburn"_s))
bin.addFeature("overburn");
- if (output.contains("-text"))
+ if (containsWord(output, u"-text"_s))
bin.addFeature("cdtext");
- if (output.contains("-clone"))
+ if (containsWord(output, u"-clone"_s))
bin.addFeature("clone");
- if (output.contains("-tao"))
+ if (containsWord(output, u"-tao"_s))
bin.addFeature("tao");
}
diff --git a/libk3b/core/k3bdefaultexternalprograms.h b/libk3b/core/k3bdefaultexternalprograms.h
index 47cf06e78..c29c6c303 100644
--- a/libk3b/core/k3bdefaultexternalprograms.h
+++ b/libk3b/core/k3bdefaultexternalprograms.h
@@ -20,6 +20,8 @@ namespace K3b {
LIBK3B_EXPORT void addTranscodePrograms( ExternalBinManager* );
LIBK3B_EXPORT void addVcdimagerPrograms( ExternalBinManager* );
+ LIBK3B_EXPORT bool containsWord( const QString& haystack, QStringView needle );
+
class LIBK3B_EXPORT AbstractCdrtoolsProgram : public SimpleExternalProgram
{
public:
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b88f93aa4..793eacecb 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -56,6 +56,12 @@ target_link_libraries(k3bdeviceglobalstest
k3bdevice)
add_test(NAME k3bdeviceglobalstest COMMAND k3bdeviceglobalstest)
+add_executable(k3bdefaultexternalprogramstest k3bdefaultexternalprogramstest.cpp)
+target_link_libraries(k3bdefaultexternalprogramstest
+ Qt6::Test
+ k3blib)
+add_test(NAME k3bdefaultexternalprogramstest COMMAND k3bdefaultexternalprogramstest)
+
qt_generate_dbus_interface(${CMAKE_SOURCE_DIR}/src/k3bjobinterface.h org.k3b.Job.xml)
qt_add_dbus_adaptor(dbus_sources ${CMAKE_CURRENT_BINARY_DIR}/org.k3b.Job.xml ${CMAKE_SOURCE_DIR}/src/k3bjobinterface.h K3b::JobInterface k3bjobinterfaceadaptor K3bJobInterfaceAdaptor)
diff --git a/tests/k3bdefaultexternalprogramstest.cpp b/tests/k3bdefaultexternalprogramstest.cpp
new file mode 100644
index 000000000..830412e1b
--- /dev/null
+++ b/tests/k3bdefaultexternalprogramstest.cpp
@@ -0,0 +1,34 @@
+#include "k3bdefaultexternalprogramstest.h"
+#include "k3bdefaultexternalprograms.h"
+
+#include <QTest>
+
+QTEST_APPLESS_MAIN( DefaultExternalProgramsTest )
+
+void DefaultExternalProgramsTest::testContainsWord_data()
+{
+ QTest::addColumn<QString>( "haystack" );
+ QTest::addColumn<QString>( "needle" );
+ QTest::addColumn<bool>( "isContained" );
+
+ QTest::newRow("empty") << "abc" << "" << true;
+ QTest::newRow("left") << "abc def" << "abc" << true;
+ QTest::newRow("right") << "ghi\tjkl" << "jkl" << true;
+ QTest::newRow("middle") << "x\ny\rz" << "y" << true;
+ QTest::newRow("match") << "ab a c" << "a" << true;
+ QTest::newRow("no match 1") << "x" << "a" << false;
+ QTest::newRow("no match 2") << "" << "a" << false;
+ QTest::newRow("partial 1") << "appletree" << "apple" << false;
+ QTest::newRow("partial 2") << "appletree" << "tree" << false;
+}
+
+void DefaultExternalProgramsTest::testContainsWord()
+{
+ QFETCH( QString, haystack );
+ QFETCH( QString, needle );
+ QFETCH( bool, isContained );
+
+ QCOMPARE( K3b::containsWord( haystack, needle ), isContained );
+}
+
+#include "moc_k3bdefaultexternalprogramstest.cpp"
diff --git a/tests/k3bdefaultexternalprogramstest.h b/tests/k3bdefaultexternalprogramstest.h
new file mode 100644
index 000000000..44b29bd19
--- /dev/null
+++ b/tests/k3bdefaultexternalprogramstest.h
@@ -0,0 +1,15 @@
+#ifndef K3B_DEFAULT_EXTERNAL_PROGRAMS_TEST_H
+#define K3B_DEFAULT_EXTERNAL_PROGRAMS_TEST_H
+
+#include <QObject>
+
+class DefaultExternalProgramsTest : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testContainsWord_data();
+ void testContainsWord();
+};
+
+#endif // K3B_DEFAULT_EXTERNAL_PROGRAMS_TEST_H