// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2026 Dany Thinnes #include "xdftool.h" #include #include #include #include #include XdfTool::XdfTool(const QString &program) : m_program(program) {} XdfTool::Result XdfTool::runBatch(const QString &image, const QList &commands) const { Result r; QStringList args; args << image; for (int i = 0; i < commands.size(); ++i) { if (i > 0) args << QStringLiteral("+"); args << commands.at(i); } QStringList shown; for (const QString &a : args) shown << (a.contains(' ') ? QStringLiteral("\"%1\"").arg(a) : a); r.commandLine = m_program + ' ' + shown.join(' '); QProcess p; #ifdef Q_OS_WIN // Python-Ausgabe unter Windows auf UTF-8 zwingen (sonst Umlaute in Dateinamen kaputt) QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(QStringLiteral("PYTHONUTF8"), QStringLiteral("1")); env.insert(QStringLiteral("PYTHONIOENCODING"), QStringLiteral("utf-8")); p.setProcessEnvironment(env); #endif p.start(m_program, args); if (!p.waitForStarted(5000)) { r.err = QStringLiteral("Konnte '%1' nicht starten: %2").arg(m_program, p.errorString()); return r; } p.waitForFinished(-1); r.out = QString::fromUtf8(p.readAllStandardOutput()); r.err = QString::fromUtf8(p.readAllStandardError()); r.ok = (p.exitStatus() == QProcess::NormalExit && p.exitCode() == 0); return r; } XdfTool::Result XdfTool::list(const QString &image, QList &entries) const { Result r = runBatch(image, { { QStringLiteral("list") } }); if (r.ok) entries = parseList(r.out); return r; } // Erwartet das typische Ausgabeformat von "xdftool list": // pro Zeile ein Eintrag, Unterverzeichnisse um je 2 Leerzeichen eingerueckt, // danach eine Spalte mit "DIR" bzw. der Dateigroesse in Bytes. QList XdfTool::parseList(const QString &text) { static const QRegularExpression reWide( QStringLiteral(R"(^( *)(.*?)\s{2,}(DIR|\d+)(?:\s.*)?$)")); static const QRegularExpression reNarrow( QStringLiteral(R"(^( *)(.*?)\s+(DIR|\d+)(?:\s.*)?$)")); QList result; QVector> stack; // (Einrueckung, Pfad) offener Verzeichnisse const QStringList lines = text.split('\n'); for (QString line : lines) { if (line.endsWith('\r')) line.chop(1); if (line.trimmed().isEmpty()) continue; QRegularExpressionMatch m = reWide.match(line); if (!m.hasMatch()) m = reNarrow.match(line); if (!m.hasMatch()) continue; const int indent = m.captured(1).size(); const QString name = m.captured(2).trimmed(); if (name.isEmpty()) continue; while (!stack.isEmpty() && stack.last().first >= indent) stack.removeLast(); const QString parent = stack.isEmpty() ? QString() : stack.last().second; AdfEntry e; e.name = name; e.path = parent.isEmpty() ? name : parent + QLatin1Char('/') + name; e.isDir = (m.captured(3) == QLatin1String("DIR")); e.size = e.isDir ? 0 : m.captured(3).toLongLong(); result << e; if (e.isDir) stack.append({ indent, e.path }); } return result; }