File indexing completed on 2024-05-05 05:50:40

0001 /*
0002     SPDX-FileCopyrightText: 2016 Ragnar Thomsen <rthomsen6@gmail.com>
0003 
0004     SPDX-License-Identifier: BSD-2-Clause
0005 */
0006 
0007 #include "cliproperties.h"
0008 #include "archiveformat.h"
0009 #include "ark_debug.h"
0010 #include "pluginmanager.h"
0011 #include <QRegularExpression>
0012 namespace Kerfuffle
0013 {
0014 CliProperties::CliProperties(QObject *parent, const KPluginMetaData &metaData, const QMimeType &archiveType)
0015     : QObject(parent)
0016     , m_mimeType(archiveType)
0017     , m_metaData(metaData)
0018 {
0019 }
0020 
0021 QStringList CliProperties::addArgs(const QString &archive,
0022                                    const QStringList &files,
0023                                    const QString &password,
0024                                    bool headerEncryption,
0025                                    int compressionLevel,
0026                                    const QString &compressionMethod,
0027                                    const QString &encryptionMethod,
0028                                    ulong volumeSize)
0029 {
0030     if (!encryptionMethod.isEmpty()) {
0031         Q_ASSERT(!password.isEmpty());
0032     }
0033 
0034     QStringList args;
0035     for (const QString &s : std::as_const(m_addSwitch)) {
0036         args << s;
0037     }
0038     if (!password.isEmpty()) {
0039         args << substitutePasswordSwitch(password, headerEncryption);
0040     }
0041     if (compressionLevel > -1) {
0042         args << substituteCompressionLevelSwitch(compressionLevel);
0043     }
0044     if (!compressionMethod.isEmpty()) {
0045         args << substituteCompressionMethodSwitch(compressionMethod);
0046     }
0047     if (!encryptionMethod.isEmpty()) {
0048         args << substituteEncryptionMethodSwitch(encryptionMethod);
0049     }
0050     if (volumeSize > 0) {
0051         args << substituteMultiVolumeSwitch(volumeSize);
0052     }
0053     args << archive;
0054     args << files;
0055 
0056     args.removeAll(QString());
0057     return args;
0058 }
0059 
0060 QStringList CliProperties::commentArgs(const QString &archive, const QString &commentfile)
0061 {
0062     QStringList args;
0063     const QStringList commentSwitches = substituteCommentSwitch(commentfile);
0064     for (const QString &s : commentSwitches) {
0065         args << s;
0066     }
0067     args << archive;
0068 
0069     args.removeAll(QString());
0070     return args;
0071 }
0072 
0073 QStringList CliProperties::deleteArgs(const QString &archive, const QVector<Archive::Entry *> &files, const QString &password)
0074 {
0075     QStringList args;
0076     args << m_deleteSwitch;
0077     if (!password.isEmpty()) {
0078         args << substitutePasswordSwitch(password);
0079     }
0080     args << archive;
0081     for (const Archive::Entry *e : files) {
0082         args << e->fullPath(NoTrailingSlash);
0083     }
0084 
0085     args.removeAll(QString());
0086     return args;
0087 }
0088 
0089 QStringList CliProperties::extractArgs(const QString &archive, const QStringList &files, bool preservePaths, const QString &password)
0090 {
0091     QStringList args;
0092 
0093     if (preservePaths && !m_extractSwitch.isEmpty()) {
0094         args << m_extractSwitch;
0095     } else if (!preservePaths && !m_extractSwitchNoPreserve.isEmpty()) {
0096         args << m_extractSwitchNoPreserve;
0097     }
0098 
0099     if (!password.isEmpty()) {
0100         args << substitutePasswordSwitch(password);
0101     }
0102     args << archive;
0103     args << files;
0104 
0105     args.removeAll(QString());
0106     return args;
0107 }
0108 
0109 QStringList CliProperties::listArgs(const QString &archive, const QString &password)
0110 {
0111     QStringList args;
0112     for (const QString &s : std::as_const(m_listSwitch)) {
0113         args << s;
0114     }
0115 
0116     const auto encryptionType = ArchiveFormat::fromMetadata(m_mimeType, m_metaData).encryptionType();
0117     if (!password.isEmpty() && encryptionType == Archive::EncryptionType::HeaderEncrypted) {
0118         args << substitutePasswordSwitch(password);
0119     }
0120     args << archive;
0121 
0122     args.removeAll(QString());
0123     return args;
0124 }
0125 
0126 QStringList CliProperties::moveArgs(const QString &archive, const QVector<Archive::Entry *> &entries, Archive::Entry *destination, const QString &password)
0127 {
0128     QStringList args;
0129     args << m_moveSwitch;
0130     if (!password.isEmpty()) {
0131         args << substitutePasswordSwitch(password);
0132     }
0133     args << archive;
0134     if (entries.count() > 1) {
0135         for (const Archive::Entry *file : entries) {
0136             args << file->fullPath(NoTrailingSlash);
0137             if (destination) {
0138                 args << destination->fullPath() + file->name();
0139             }
0140         }
0141     } else {
0142         args << entries.at(0)->fullPath(NoTrailingSlash);
0143         if (destination) {
0144             args << destination->fullPath(NoTrailingSlash);
0145         }
0146     }
0147 
0148     args.removeAll(QString());
0149     return args;
0150 }
0151 
0152 QStringList CliProperties::testArgs(const QString &archive, const QString &password)
0153 {
0154     QStringList args;
0155     for (const QString &s : std::as_const(m_testSwitch)) {
0156         args << s;
0157     }
0158     if (!password.isEmpty()) {
0159         args << substitutePasswordSwitch(password);
0160     }
0161     args << archive;
0162 
0163     args.removeAll(QString());
0164     return args;
0165 }
0166 
0167 QStringList CliProperties::substituteCommentSwitch(const QString &commentfile) const
0168 {
0169     Q_ASSERT(!commentfile.isEmpty());
0170 
0171     Q_ASSERT(ArchiveFormat::fromMetadata(m_mimeType, m_metaData).supportsWriteComment());
0172 
0173     QStringList commentSwitches = m_commentSwitch;
0174     Q_ASSERT(!commentSwitches.isEmpty());
0175 
0176     QMutableListIterator<QString> i(commentSwitches);
0177     while (i.hasNext()) {
0178         i.next();
0179         i.value().replace(QLatin1String("$CommentFile"), commentfile);
0180     }
0181 
0182     return commentSwitches;
0183 }
0184 
0185 QStringList CliProperties::substitutePasswordSwitch(const QString &password, bool headerEnc) const
0186 {
0187     if (password.isEmpty()) {
0188         return QStringList();
0189     }
0190 
0191     Archive::EncryptionType encryptionType = ArchiveFormat::fromMetadata(m_mimeType, m_metaData).encryptionType();
0192     Q_ASSERT(encryptionType != Archive::EncryptionType::Unencrypted);
0193 
0194     QStringList passwordSwitch;
0195     if (headerEnc) {
0196         passwordSwitch = m_passwordSwitchHeaderEnc;
0197     } else {
0198         passwordSwitch = m_passwordSwitch;
0199     }
0200     Q_ASSERT(!passwordSwitch.isEmpty());
0201 
0202     QMutableListIterator<QString> i(passwordSwitch);
0203     while (i.hasNext()) {
0204         i.next();
0205         i.value().replace(QLatin1String("$Password"), password);
0206     }
0207 
0208     return passwordSwitch;
0209 }
0210 
0211 QString CliProperties::substituteCompressionLevelSwitch(int level) const
0212 {
0213     if (level < 0 || level > 9) {
0214         return QString();
0215     }
0216 
0217     Q_ASSERT(ArchiveFormat::fromMetadata(m_mimeType, m_metaData).maxCompressionLevel() != -1);
0218 
0219     QString compLevelSwitch = m_compressionLevelSwitch;
0220     Q_ASSERT(!compLevelSwitch.isEmpty());
0221 
0222     compLevelSwitch.replace(QLatin1String("$CompressionLevel"), QString::number(level));
0223 
0224     return compLevelSwitch;
0225 }
0226 
0227 QString CliProperties::substituteCompressionMethodSwitch(const QString &method) const
0228 {
0229     if (method.isEmpty()) {
0230         return QString();
0231     }
0232 
0233     Q_ASSERT(!ArchiveFormat::fromMetadata(m_mimeType, m_metaData).compressionMethods().isEmpty());
0234 
0235     QString compMethodSwitch = m_compressionMethodSwitch[m_mimeType.name()].toString();
0236     Q_ASSERT(!compMethodSwitch.isEmpty());
0237 
0238     QString cliMethod = ArchiveFormat::fromMetadata(m_mimeType, m_metaData).compressionMethods().value(method).toString();
0239 
0240     compMethodSwitch.replace(QLatin1String("$CompressionMethod"), cliMethod);
0241 
0242     return compMethodSwitch;
0243 }
0244 
0245 QString CliProperties::substituteEncryptionMethodSwitch(const QString &method) const
0246 {
0247     if (method.isEmpty()) {
0248         return QString();
0249     }
0250 
0251     const ArchiveFormat format = ArchiveFormat::fromMetadata(m_mimeType, m_metaData);
0252 
0253     Q_ASSERT(!format.encryptionMethods().isEmpty());
0254 
0255     QString encMethodSwitch = m_encryptionMethodSwitch[m_mimeType.name()].toString();
0256     if (encMethodSwitch.isEmpty()) {
0257         return QString();
0258     }
0259 
0260     Q_ASSERT(format.encryptionMethods().contains(method));
0261 
0262     encMethodSwitch.replace(QLatin1String("$EncryptionMethod"), method);
0263 
0264     return encMethodSwitch;
0265 }
0266 
0267 QString CliProperties::substituteMultiVolumeSwitch(ulong volumeSize) const
0268 {
0269     // The maximum value we allow in the QDoubleSpinBox is 1,000,000MB. Converted to
0270     // KB this is 1,024,000,000.
0271     if (volumeSize <= 0 || volumeSize > 1024000000) {
0272         return QString();
0273     }
0274 
0275     Q_ASSERT(ArchiveFormat::fromMetadata(m_mimeType, m_metaData).supportsMultiVolume());
0276 
0277     QString multiVolumeSwitch = m_multiVolumeSwitch;
0278     Q_ASSERT(!multiVolumeSwitch.isEmpty());
0279 
0280     multiVolumeSwitch.replace(QLatin1String("$VolumeSize"), QString::number(volumeSize));
0281 
0282     return multiVolumeSwitch;
0283 }
0284 
0285 bool CliProperties::isTestPassedMsg(const QString &line)
0286 {
0287     for (const QString &rx : std::as_const(m_testPassedPatterns)) {
0288         if (QRegularExpression(rx).match(line).hasMatch()) {
0289             return true;
0290         }
0291     }
0292     return false;
0293 }
0294 
0295 }
0296 
0297 #include "moc_cliproperties.cpp"