Commit 50a9f590 authored by Ragnar Thomsen's avatar Ragnar Thomsen
Browse files

Detect compression method

A new property was added to Archive to store detected compression
method(s). Currently, it's only displayed in PropertiesDialog, but the
plan is to also use it to select a sane default compression method when
adding files to an existing archive. Code was added to all plugins for
detecting the compression method(s) when opening an archive and a signal
added to ReadOnlyArchiveInterface to set the property.

Many archive types support multiple compression methods in same archive,
so the property is a QStringList.

Differential Revision: D2987
parent a3921c6c
......@@ -172,8 +172,19 @@ Archive::Archive(ReadOnlyArchiveInterface *archiveInterface, bool isReadOnly, QO
m_iface->setParent(this);
connect(m_iface, &ReadOnlyArchiveInterface::entry, this, &Archive::onNewEntry);
connect(m_iface, &ReadOnlyArchiveInterface::compressionMethodFound, this, &Archive::onCompressionMethodFound);
}
void Archive::onCompressionMethodFound(const QStringList &methods)
{
// If other methods are found, we dont report "Store" method.
QStringList processedMethods = methods;
if (processedMethods.size() > 1 &&
processedMethods.contains(QStringLiteral("Store"))) {
processedMethods.removeOne(QStringLiteral("Store"));
}
setProperty("compressionMethods", processedMethods);
}
Archive::~Archive()
{
......
......@@ -93,6 +93,7 @@ class KERFUFFLE_EXPORT Archive : public QObject
Q_PROPERTY(qulonglong packedSize READ packedSize)
Q_PROPERTY(QString subfolderName MEMBER m_subfolderName READ subfolderName)
Q_PROPERTY(QString password READ password)
Q_PROPERTY(QStringList compressionMethods MEMBER m_compressionMethods)
public:
......@@ -221,6 +222,7 @@ private slots:
void onAddFinished(KJob*);
void onUserQuery(Kerfuffle::Query*);
void onNewEntry(const Archive::Entry *entry);
void onCompressionMethodFound(const QStringList &methods);
private:
Archive(ReadOnlyArchiveInterface *archiveInterface, bool isReadOnly, QObject *parent = 0);
......@@ -235,7 +237,6 @@ private:
* @return A valid archive if the plugin could be loaded, an invalid one otherwise (with the FailedPlugin error set).
*/
static Archive *create(const QString &fileName, Plugin *plugin, QObject *parent = Q_NULLPTR);
ReadOnlyArchiveInterface *m_iface;
bool m_isReadOnly;
bool m_isSingleFolder;
......@@ -249,6 +250,7 @@ private:
qulonglong m_numberOfFolders;
CompressionOptions m_compOptions;
QMimeType m_mimeType;
QStringList m_compressionMethods;
};
} // namespace Kerfuffle
......
......@@ -167,6 +167,7 @@ signals:
void finished(bool result);
void userQuery(Query *query);
void testSuccess();
void compressionMethodFound(const QStringList);
protected:
......
......@@ -63,6 +63,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent, Archive *archive, qulonglong
m_ui->lblArchiveName->setText(archive->fileName());
m_ui->lblArchiveType->setText(archive->mimeType().comment());
m_ui->lblMimetype->setText(archive->mimeType().name());
m_ui->lblCompressionMethods->setText(archive->property("compressionMethods").toStringList().join(QStringLiteral(", ")));
m_ui->lblReadOnly->setText(archive->isReadOnly() ? i18n("yes") : i18n("no"));
m_ui->lblMultiVolume->setText(archive->isMultiVolume() ? i18n("yes (%1 volumes)", archive->numberOfVolumes()) : i18n("no"));
m_ui->lblHasComment->setText(archive->hasComment() ? i18n("yes") : i18n("no"));
......
......@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>730</width>
<height>412</height>
<height>436</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
......@@ -73,126 +73,126 @@
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Opened read-only:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QLabel" name="lblReadOnly">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Password-protected:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QLabel" name="lblPasswordProtected">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Has comment:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="7" column="1">
<widget class="QLabel" name="lblHasComment">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Number of entries:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="8" column="1">
<widget class="QLabel" name="lblNumberOfEntries">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="8" column="0">
<item row="9" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Unpacked size:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="9" column="1">
<widget class="QLabel" name="lblUnpackedSize">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="9" column="0">
<item row="10" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Packed size:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="10" column="1">
<widget class="QLabel" name="lblPackedSize">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="10" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Compression ratio:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<item row="11" column="1">
<widget class="QLabel" name="lblCompressionRatio">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Last modified:</string>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="12" column="1">
<widget class="QLabel" name="lblLastModified">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="12" column="0">
<item row="13" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>MD5 hash:</string>
</property>
</widget>
</item>
<item row="12" column="1">
<item row="13" column="1">
<widget class="QLabel" name="lblMD5">
<property name="text">
<string/>
......@@ -205,14 +205,14 @@
</property>
</widget>
</item>
<item row="13" column="0">
<item row="14" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>SHA-1 hash:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<item row="14" column="1">
<widget class="QLabel" name="lblSHA1">
<property name="text">
<string/>
......@@ -222,14 +222,14 @@
</property>
</widget>
</item>
<item row="14" column="0">
<item row="15" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>SHA-256 hash:</string>
</property>
</widget>
</item>
<item row="14" column="1">
<item row="15" column="1">
<widget class="QLabel" name="lblSHA256">
<property name="text">
<string notr="true">nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn</string>
......@@ -239,20 +239,34 @@
</property>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Multi-volume:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QLabel" name="lblMultiVolume">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Compression method(s):</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="lblCompressionMethods">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
......
......@@ -180,6 +180,23 @@ bool CliPlugin::readListLine(const QString& line)
}
} else if (line.startsWith(QStringLiteral("Volumes = "))) {
m_numberOfVolumes = line.section(QLatin1Char('='), 1).trimmed().toInt();
} else if (line.startsWith(QStringLiteral("Method = "))) {
QStringList methods = line.section(QLatin1Char('='), 1).trimmed().split(QLatin1Char(' '), QString::SkipEmptyParts);
// LZMA methods are output with some trailing numbers by 7z representing dictionary/block sizes.
// We are not interested in these, so remove them.
QMutableListIterator<QString> i(methods);
while (i.hasNext()) {
QString m = i.next();
if (m.startsWith(QLatin1String("LZMA2"))) {
m = m.left(5);
} else if (m.startsWith(QLatin1String("LZMA"))) {
m = m.left(4);
}
i.setValue(m);
}
emit compressionMethodFound(methods);
} else if (rxComment.match(line).hasMatch()) {
m_parseState = ParseStateComment;
m_comment.append(line.section(QLatin1Char('='), 1) + QLatin1Char('\n'));
......@@ -241,6 +258,19 @@ bool CliPlugin::readListLine(const QString& line)
m_currentArchiveEntry->setProperty("CRC", line.mid(6).trimmed());
} else if (line.startsWith(QStringLiteral("Method = "))) {
m_currentArchiveEntry->setProperty("method", line.mid(9).trimmed());
// For zip archives we need to check method for each entry.
if (m_archiveType == ArchiveTypeZip) {
QString method = line.mid(9).trimmed();
if (method == QLatin1String("xz")) {
method = QStringLiteral("XZ");
}
if (!m_compressionMethods.contains(method)) {
m_compressionMethods.append(method);
emit compressionMethodFound(m_compressionMethods);
}
}
} else if (line.startsWith(QStringLiteral("Encrypted = ")) &&
line.size() >= 13) {
m_currentArchiveEntry->setProperty("isPasswordProtected", line.at(12) == QLatin1Char('+'));
......
......@@ -67,6 +67,7 @@ private:
int m_linesComment;
Kerfuffle::Archive::Entry *m_currentArchiveEntry;
bool m_isFirstInformationEntry;
QStringList m_compressionMethods;
};
#endif // CLIPLUGIN_H
......@@ -217,6 +217,11 @@ bool CliPlugin::handleUnrar5Line(const QString &line)
m_isSolid = true;
qCDebug(ARK) << "Solid archive detected";
}
if (line.contains(QLatin1String("RAR 4"))) {
emit compressionMethodFound(QStringList{QStringLiteral("RAR4")});
} else if (line.contains(QLatin1String("RAR 5"))) {
emit compressionMethodFound(QStringList{QStringLiteral("RAR5")});
}
}
return true;
}
......
......@@ -240,6 +240,12 @@ void CliPlugin::readJsonOutput()
setMultiVolume(true);
}
QString formatName = json.value(QStringLiteral("lsarFormatName")).toString();
if (formatName == QLatin1String("RAR")) {
emit compressionMethodFound(QStringList{QStringLiteral("RAR4")});
} else if (formatName == QLatin1String("RAR 5")) {
emit compressionMethodFound(QStringList{QStringLiteral("RAR5")});
}
const QJsonArray entries = json.value(QStringLiteral("lsarContents")).toArray();
foreach (const QJsonValue& value, entries) {
......
......@@ -179,6 +179,12 @@ bool CliPlugin::readListLine(const QString &line)
e->setProperty("compressedSize", rxMatch.captured(6).toInt());
e->setProperty("method", rxMatch.captured(7));
QString method = convertCompressionMethod(rxMatch.captured(7));
if (!m_compressionMethods.contains(method)) {
m_compressionMethods.append(method);
emit compressionMethodFound(m_compressionMethods);
}
const QDateTime ts(QDate::fromString(rxMatch.captured(8), QStringLiteral("yyyyMMdd")),
QTime::fromString(rxMatch.captured(9), QStringLiteral("hhmmss")));
e->setProperty("timestamp", ts);
......@@ -284,4 +290,16 @@ void CliPlugin::finishMoving(bool result)
cleanUp();
}
QString CliPlugin::convertCompressionMethod(const QString &method)
{
if (method == QLatin1String("stor")) {
return QStringLiteral("Store");
} else if (method.startsWith(QLatin1String("def"))) {
return QStringLiteral("Deflate");
} else if (method == QLatin1String("bzp2")) {
return QStringLiteral("BZip2");
}
return method;
}
#include "cliplugin.moc"
......@@ -50,6 +50,7 @@ private slots:
private:
bool setMovingAddedFiles();
void finishMoving(bool result);
QString convertCompressionMethod(const QString &method);
enum ParseState {
ParseStateHeader = 0,
......@@ -59,6 +60,7 @@ private:
int m_linesComment;
QString m_tempComment;
QStringList m_compressionMethods;
};
#endif // CLIPLUGIN_H
......@@ -58,6 +58,10 @@ bool LibarchivePlugin::list()
}
qDebug(ARK) << "Detected compression filter:" << archive_filter_name(m_archiveReader.data(), 0);
QString compMethod = convertCompressionName(QString::fromUtf8(archive_filter_name(m_archiveReader.data(), 0)));
if (!compMethod.isEmpty()) {
emit compressionMethodFound(QStringList{compMethod});
}
m_cachedArchiveEntryCount = 0;
m_extractedFilesSize = 0;
......@@ -531,4 +535,28 @@ void LibarchivePlugin::copyData(const QString& filename, struct archive *source,
}
}
QString LibarchivePlugin::convertCompressionName(const QString &method)
{
if (method == QLatin1String("gzip")) {
return QStringLiteral("GZip");
} else if (method == QLatin1String("bzip2")) {
return QStringLiteral("BZip2");
} else if (method == QLatin1String("xz")) {
return QStringLiteral("XZ");
} else if (method == QLatin1String("compress (.Z)")) {
return QStringLiteral("Compress");
} else if (method == QLatin1String("lrzip")) {
return QStringLiteral("LRZip");
} else if (method == QLatin1String("lzip")) {
return QStringLiteral("LZip");
} else if (method == QLatin1String("lz4")) {
return QStringLiteral("LZ4");
} else if (method == QLatin1String("lzop")) {
return QStringLiteral("lzop");
} else if (method == QLatin1String("lzma")) {
return QStringLiteral("LZMA");
}
return QString();
}
#include "libarchiveplugin.moc"
......@@ -90,6 +90,7 @@ protected:
private:
int extractionFlags() const;
QString convertCompressionName(const QString &method);
int m_cachedArchiveEntryCount;
qlonglong m_currentExtractedFilesSize;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment