RCC: Modernize the compression algorithm selection
Instead of using compression level -2 to indicate no compression, introduce CompressionAlgorithm::None and an equivalent XML attribute. This commit includes some extra error checking for RCC. Change-Id: I343f2beed55440a7ac0bfffd1562d64b024463ba Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
This commit is contained in:
parent
c18c63033e
commit
163b5c0278
@ -1,6 +1,7 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Copyright (C) 2018 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
@ -127,10 +128,21 @@ int runRcc(int argc, char *argv[])
|
||||
QCommandLineOption rootOption(QStringLiteral("root"), QStringLiteral("Prefix resource access path with root path."), QStringLiteral("path"));
|
||||
parser.addOption(rootOption);
|
||||
|
||||
#if !defined(QT_NO_COMPRESS)
|
||||
# define ALGOS "[zlib], none"
|
||||
#else
|
||||
# define ALGOS "[none]"
|
||||
#endif
|
||||
const QString &algoDescription =
|
||||
QStringLiteral("Compress input files using algorithm <algo> (" ALGOS ").");
|
||||
QCommandLineOption compressionAlgoOption(QStringLiteral("compress-algo"), algoDescription, QStringLiteral("algo"));
|
||||
parser.addOption(compressionAlgoOption);
|
||||
#undef ALGOS
|
||||
|
||||
QCommandLineOption compressOption(QStringLiteral("compress"), QStringLiteral("Compress input files by <level>."), QStringLiteral("level"));
|
||||
parser.addOption(compressOption);
|
||||
|
||||
QCommandLineOption nocompressOption(QStringLiteral("no-compress"), QStringLiteral("Disable all compression."));
|
||||
QCommandLineOption nocompressOption(QStringLiteral("no-compress"), QStringLiteral("Disable all compression. Same as --compress-algo=none."));
|
||||
parser.addOption(nocompressOption);
|
||||
|
||||
QCommandLineOption thresholdOption(QStringLiteral("threshold"), QStringLiteral("Threshold to consider compressing files."), QStringLiteral("level"));
|
||||
@ -189,10 +201,15 @@ int runRcc(int argc, char *argv[])
|
||||
|| library.resourceRoot().at(0) != QLatin1Char('/'))
|
||||
errorMsg = QLatin1String("Root must start with a /");
|
||||
}
|
||||
if (parser.isSet(compressOption))
|
||||
library.setCompressLevel(parser.value(compressOption).toInt());
|
||||
|
||||
if (parser.isSet(compressionAlgoOption))
|
||||
library.setCompressionAlgorithm(RCCResourceLibrary::parseCompressionAlgorithm(parser.value(compressionAlgoOption), &errorMsg));
|
||||
if (parser.isSet(nocompressOption))
|
||||
library.setCompressLevel(-2);
|
||||
library.setCompressionAlgorithm(RCCResourceLibrary::CompressionAlgorithm::None);
|
||||
if (parser.isSet(compressOption) && errorMsg.isEmpty()) {
|
||||
int level = library.parseCompressionLevel(library.compressionAlgorithm(), parser.value(compressOption), &errorMsg);
|
||||
library.setCompressLevel(level);
|
||||
}
|
||||
if (parser.isSet(thresholdOption))
|
||||
library.setCompressThreshold(parser.value(thresholdOption).toInt());
|
||||
if (parser.isSet(binaryOption))
|
||||
|
@ -1,6 +1,7 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Copyright (C) 2018 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
@ -51,6 +52,11 @@ enum {
|
||||
CONSTANT_COMPRESSTHRESHOLD_DEFAULT = 70
|
||||
};
|
||||
|
||||
#if !defined(QT_NO_COMPRESS)
|
||||
# define CONSTANT_COMPRESSALGO_DEFAULT RCCResourceLibrary::CompressionAlgorithm::Zlib
|
||||
#else
|
||||
# define CONSTANT_COMPRESSALGO_DEFAULT RCCResourceLibrary::CompressionAlgorithm::None
|
||||
#endif
|
||||
|
||||
#define writeString(s) write(s, sizeof(s))
|
||||
|
||||
@ -97,6 +103,7 @@ public:
|
||||
QLocale::Language language = QLocale::C,
|
||||
QLocale::Country country = QLocale::AnyCountry,
|
||||
uint flags = NoFlags,
|
||||
RCCResourceLibrary::CompressionAlgorithm compressAlgo = CONSTANT_COMPRESSALGO_DEFAULT,
|
||||
int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT,
|
||||
int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT);
|
||||
~RCCFileInfo();
|
||||
@ -115,6 +122,7 @@ public:
|
||||
QFileInfo m_fileInfo;
|
||||
RCCFileInfo *m_parent;
|
||||
QHash<QString, RCCFileInfo*> m_children;
|
||||
RCCResourceLibrary::CompressionAlgorithm m_compressAlgo;
|
||||
int m_compressLevel;
|
||||
int m_compressThreshold;
|
||||
|
||||
@ -125,7 +133,7 @@ public:
|
||||
|
||||
RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo,
|
||||
QLocale::Language language, QLocale::Country country, uint flags,
|
||||
int compressLevel, int compressThreshold)
|
||||
RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel, int compressThreshold)
|
||||
{
|
||||
m_name = name;
|
||||
m_fileInfo = fileInfo;
|
||||
@ -136,6 +144,7 @@ RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo,
|
||||
m_nameOffset = 0;
|
||||
m_dataOffset = 0;
|
||||
m_childOffset = 0;
|
||||
m_compressAlgo = compressAlgo;
|
||||
m_compressLevel = compressLevel;
|
||||
m_compressThreshold = compressThreshold;
|
||||
}
|
||||
@ -236,16 +245,26 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
|
||||
}
|
||||
QByteArray data = file.readAll();
|
||||
|
||||
#ifndef QT_NO_COMPRESS
|
||||
// Check if compression is useful for this file
|
||||
if (m_compressLevel != 0 && data.size() != 0) {
|
||||
if (data.size() != 0) {
|
||||
#ifndef QT_NO_COMPRESS
|
||||
if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Zlib) {
|
||||
QByteArray compressed =
|
||||
qCompress(reinterpret_cast<uchar *>(data.data()), data.size(), m_compressLevel);
|
||||
|
||||
int compressRatio = int(100.0 * (data.size() - compressed.size()) / data.size());
|
||||
if (compressRatio >= m_compressThreshold) {
|
||||
if (lib.verbose()) {
|
||||
QString msg = QString::fromLatin1("%1: note: compressed using zlib (%2 -> %3)\n")
|
||||
.arg(m_name).arg(data.size()).arg(compressed.size());
|
||||
lib.m_errorDevice->write(msg.toUtf8());
|
||||
}
|
||||
data = compressed;
|
||||
m_flags |= Compressed;
|
||||
} else if (lib.verbose()) {
|
||||
QString msg = QString::fromLatin1("%1: note: not compressed\n").arg(m_name);
|
||||
lib.m_errorDevice->write(msg.toUtf8());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // QT_NO_COMPRESS
|
||||
@ -343,7 +362,8 @@ RCCResourceLibrary::Strings::Strings() :
|
||||
ATTRIBUTE_PREFIX(QLatin1String("prefix")),
|
||||
ATTRIBUTE_ALIAS(QLatin1String("alias")),
|
||||
ATTRIBUTE_THRESHOLD(QLatin1String("threshold")),
|
||||
ATTRIBUTE_COMPRESS(QLatin1String("compress"))
|
||||
ATTRIBUTE_COMPRESS(QLatin1String("compress")),
|
||||
ATTRIBUTE_COMPRESSALGO(QStringLiteral("compression-algorithm"))
|
||||
{
|
||||
}
|
||||
|
||||
@ -351,6 +371,7 @@ RCCResourceLibrary::RCCResourceLibrary(quint8 formatVersion)
|
||||
: m_root(0),
|
||||
m_format(C_Code),
|
||||
m_verbose(false),
|
||||
m_compressionAlgo(CONSTANT_COMPRESSALGO_DEFAULT),
|
||||
m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT),
|
||||
m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT),
|
||||
m_treeOffset(0),
|
||||
@ -391,6 +412,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
|
||||
QLocale::Language language = QLocale::c().language();
|
||||
QLocale::Country country = QLocale::c().country();
|
||||
QString alias;
|
||||
auto compressAlgo = m_compressionAlgo;
|
||||
int compressLevel = m_compressLevel;
|
||||
int compressThreshold = m_compressThreshold;
|
||||
|
||||
@ -444,17 +466,27 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
|
||||
if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS))
|
||||
alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString();
|
||||
|
||||
compressAlgo = m_compressionAlgo;
|
||||
compressLevel = m_compressLevel;
|
||||
if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS))
|
||||
compressLevel = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString().toInt();
|
||||
|
||||
compressThreshold = m_compressThreshold;
|
||||
|
||||
QString errorString;
|
||||
if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESSALGO))
|
||||
compressAlgo = parseCompressionAlgorithm(attributes.value(m_strings.ATTRIBUTE_COMPRESSALGO), &errorString);
|
||||
if (errorString.isEmpty() && attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS)) {
|
||||
QString value = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString();
|
||||
compressLevel = parseCompressionLevel(compressAlgo, value, &errorString);
|
||||
}
|
||||
|
||||
// Special case for -no-compress
|
||||
if (m_compressLevel == -2)
|
||||
compressAlgo = CompressionAlgorithm::None;
|
||||
|
||||
if (attributes.hasAttribute(m_strings.ATTRIBUTE_THRESHOLD))
|
||||
compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt();
|
||||
|
||||
// Special case for -no-compress. Overrides all other settings.
|
||||
if (m_compressLevel == -2)
|
||||
compressLevel = 0;
|
||||
if (!errorString.isEmpty())
|
||||
reader.raiseError(errorString);
|
||||
}
|
||||
} else {
|
||||
reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString()));
|
||||
@ -520,6 +552,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
|
||||
language,
|
||||
country,
|
||||
child.isDir() ? RCCFileInfo::Directory : RCCFileInfo::NoFlags,
|
||||
compressAlgo,
|
||||
compressLevel,
|
||||
compressThreshold)
|
||||
);
|
||||
@ -535,6 +568,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
|
||||
language,
|
||||
country,
|
||||
RCCFileInfo::NoFlags,
|
||||
compressAlgo,
|
||||
compressLevel,
|
||||
compressThreshold)
|
||||
);
|
||||
@ -729,6 +763,40 @@ RCCResourceLibrary::ResourceDataFileMap RCCResourceLibrary::resourceDataFileMap(
|
||||
return rc;
|
||||
}
|
||||
|
||||
RCCResourceLibrary::CompressionAlgorithm RCCResourceLibrary::parseCompressionAlgorithm(QStringView value, QString *errorMsg)
|
||||
{
|
||||
if (value == QLatin1String("zlib")) {
|
||||
#ifdef QT_NO_COMPRESS
|
||||
*errorMsg = QLatin1String("zlib support not compiled in");
|
||||
#else
|
||||
return CompressionAlgorithm::Zlib;
|
||||
#endif
|
||||
} else if (value != QLatin1String("none")) {
|
||||
*errorMsg = QString::fromLatin1("Unknown compression algorithm '%1'").arg(value);
|
||||
}
|
||||
|
||||
return CompressionAlgorithm::None;
|
||||
}
|
||||
|
||||
int RCCResourceLibrary::parseCompressionLevel(CompressionAlgorithm algo, const QString &level, QString *errorMsg)
|
||||
{
|
||||
bool ok;
|
||||
int c = level.toInt(&ok);
|
||||
if (ok) {
|
||||
switch (algo) {
|
||||
case CompressionAlgorithm::None:
|
||||
return 0;
|
||||
case CompressionAlgorithm::Zlib:
|
||||
if (c >= 1 && c <= 9)
|
||||
return c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*errorMsg = QString::fromLatin1("invalid compression level '%1'").arg(level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &tempDevice, QIODevice &errorDevice)
|
||||
{
|
||||
m_errorDevice = &errorDevice;
|
||||
|
@ -1,6 +1,7 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Copyright (C) 2018 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
@ -77,6 +78,17 @@ public:
|
||||
void setOutputName(const QString &name) { m_outputName = name; }
|
||||
QString outputName() const { return m_outputName; }
|
||||
|
||||
enum class CompressionAlgorithm {
|
||||
Zlib,
|
||||
|
||||
None = -1
|
||||
};
|
||||
|
||||
static CompressionAlgorithm parseCompressionAlgorithm(QStringView algo, QString *errorMsg);
|
||||
void setCompressionAlgorithm(CompressionAlgorithm algo) { m_compressionAlgo = algo; }
|
||||
CompressionAlgorithm compressionAlgorithm() const { return m_compressionAlgo; }
|
||||
|
||||
static int parseCompressionLevel(CompressionAlgorithm algo, const QString &level, QString *errorMsg);
|
||||
void setCompressLevel(int c) { m_compressLevel = c; }
|
||||
int compressLevel() const { return m_compressLevel; }
|
||||
|
||||
@ -104,6 +116,7 @@ private:
|
||||
const QString ATTRIBUTE_ALIAS;
|
||||
const QString ATTRIBUTE_THRESHOLD;
|
||||
const QString ATTRIBUTE_COMPRESS;
|
||||
const QString ATTRIBUTE_COMPRESSALGO;
|
||||
};
|
||||
friend class RCCFileInfo;
|
||||
void reset();
|
||||
@ -133,6 +146,7 @@ private:
|
||||
QString m_outputName;
|
||||
Format m_format;
|
||||
bool m_verbose;
|
||||
CompressionAlgorithm m_compressionAlgo;
|
||||
int m_compressLevel;
|
||||
int m_compressThreshold;
|
||||
int m_treeOffset;
|
||||
|
Loading…
Reference in New Issue
Block a user