Files
2026-11-01 15:38:43 +01:00

108 lines
3.4 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026 Dany Thinnes
#include "xdftool.h"
#include <QPair>
#include <QProcess>
#include <QProcessEnvironment>
#include <QRegularExpression>
#include <QVector>
XdfTool::XdfTool(const QString &program) : m_program(program) {}
XdfTool::Result XdfTool::runBatch(const QString &image, const QList<QStringList> &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<AdfEntry> &entries) const
{
Result r = runBatch(image, { { QStringLiteral("list") } });
if (r.ok)
entries = parseList(r.out);
return r;
}
// Erwartet das typische Ausgabeformat von "xdftool <img> list":
// pro Zeile ein Eintrag, Unterverzeichnisse um je 2 Leerzeichen eingerueckt,
// danach eine Spalte mit "DIR" bzw. der Dateigroesse in Bytes.
QList<AdfEntry> 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<AdfEntry> result;
QVector<QPair<int, QString>> 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;
}