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/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the tools applications of the Qt Toolkit.
|
** 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"));
|
QCommandLineOption rootOption(QStringLiteral("root"), QStringLiteral("Prefix resource access path with root path."), QStringLiteral("path"));
|
||||||
parser.addOption(rootOption);
|
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"));
|
QCommandLineOption compressOption(QStringLiteral("compress"), QStringLiteral("Compress input files by <level>."), QStringLiteral("level"));
|
||||||
parser.addOption(compressOption);
|
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);
|
parser.addOption(nocompressOption);
|
||||||
|
|
||||||
QCommandLineOption thresholdOption(QStringLiteral("threshold"), QStringLiteral("Threshold to consider compressing files."), QStringLiteral("level"));
|
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('/'))
|
|| library.resourceRoot().at(0) != QLatin1Char('/'))
|
||||||
errorMsg = QLatin1String("Root must start with a /");
|
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))
|
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))
|
if (parser.isSet(thresholdOption))
|
||||||
library.setCompressThreshold(parser.value(thresholdOption).toInt());
|
library.setCompressThreshold(parser.value(thresholdOption).toInt());
|
||||||
if (parser.isSet(binaryOption))
|
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/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the tools applications of the Qt Toolkit.
|
** This file is part of the tools applications of the Qt Toolkit.
|
||||||
@ -51,6 +52,11 @@ enum {
|
|||||||
CONSTANT_COMPRESSTHRESHOLD_DEFAULT = 70
|
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))
|
#define writeString(s) write(s, sizeof(s))
|
||||||
|
|
||||||
@ -97,6 +103,7 @@ public:
|
|||||||
QLocale::Language language = QLocale::C,
|
QLocale::Language language = QLocale::C,
|
||||||
QLocale::Country country = QLocale::AnyCountry,
|
QLocale::Country country = QLocale::AnyCountry,
|
||||||
uint flags = NoFlags,
|
uint flags = NoFlags,
|
||||||
|
RCCResourceLibrary::CompressionAlgorithm compressAlgo = CONSTANT_COMPRESSALGO_DEFAULT,
|
||||||
int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT,
|
int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT,
|
||||||
int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT);
|
int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT);
|
||||||
~RCCFileInfo();
|
~RCCFileInfo();
|
||||||
@ -115,6 +122,7 @@ public:
|
|||||||
QFileInfo m_fileInfo;
|
QFileInfo m_fileInfo;
|
||||||
RCCFileInfo *m_parent;
|
RCCFileInfo *m_parent;
|
||||||
QHash<QString, RCCFileInfo*> m_children;
|
QHash<QString, RCCFileInfo*> m_children;
|
||||||
|
RCCResourceLibrary::CompressionAlgorithm m_compressAlgo;
|
||||||
int m_compressLevel;
|
int m_compressLevel;
|
||||||
int m_compressThreshold;
|
int m_compressThreshold;
|
||||||
|
|
||||||
@ -125,7 +133,7 @@ public:
|
|||||||
|
|
||||||
RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo,
|
RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo,
|
||||||
QLocale::Language language, QLocale::Country country, uint flags,
|
QLocale::Language language, QLocale::Country country, uint flags,
|
||||||
int compressLevel, int compressThreshold)
|
RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel, int compressThreshold)
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_fileInfo = fileInfo;
|
m_fileInfo = fileInfo;
|
||||||
@ -136,6 +144,7 @@ RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo,
|
|||||||
m_nameOffset = 0;
|
m_nameOffset = 0;
|
||||||
m_dataOffset = 0;
|
m_dataOffset = 0;
|
||||||
m_childOffset = 0;
|
m_childOffset = 0;
|
||||||
|
m_compressAlgo = compressAlgo;
|
||||||
m_compressLevel = compressLevel;
|
m_compressLevel = compressLevel;
|
||||||
m_compressThreshold = compressThreshold;
|
m_compressThreshold = compressThreshold;
|
||||||
}
|
}
|
||||||
@ -236,16 +245,26 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
|
|||||||
}
|
}
|
||||||
QByteArray data = file.readAll();
|
QByteArray data = file.readAll();
|
||||||
|
|
||||||
#ifndef QT_NO_COMPRESS
|
|
||||||
// Check if compression is useful for this file
|
// Check if compression is useful for this file
|
||||||
if (m_compressLevel != 0 && data.size() != 0) {
|
if (data.size() != 0) {
|
||||||
QByteArray compressed =
|
#ifndef QT_NO_COMPRESS
|
||||||
qCompress(reinterpret_cast<uchar *>(data.data()), data.size(), m_compressLevel);
|
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());
|
int compressRatio = int(100.0 * (data.size() - compressed.size()) / data.size());
|
||||||
if (compressRatio >= m_compressThreshold) {
|
if (compressRatio >= m_compressThreshold) {
|
||||||
data = compressed;
|
if (lib.verbose()) {
|
||||||
m_flags |= Compressed;
|
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
|
#endif // QT_NO_COMPRESS
|
||||||
@ -343,7 +362,8 @@ RCCResourceLibrary::Strings::Strings() :
|
|||||||
ATTRIBUTE_PREFIX(QLatin1String("prefix")),
|
ATTRIBUTE_PREFIX(QLatin1String("prefix")),
|
||||||
ATTRIBUTE_ALIAS(QLatin1String("alias")),
|
ATTRIBUTE_ALIAS(QLatin1String("alias")),
|
||||||
ATTRIBUTE_THRESHOLD(QLatin1String("threshold")),
|
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_root(0),
|
||||||
m_format(C_Code),
|
m_format(C_Code),
|
||||||
m_verbose(false),
|
m_verbose(false),
|
||||||
|
m_compressionAlgo(CONSTANT_COMPRESSALGO_DEFAULT),
|
||||||
m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT),
|
m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT),
|
||||||
m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT),
|
m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT),
|
||||||
m_treeOffset(0),
|
m_treeOffset(0),
|
||||||
@ -391,6 +412,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
|
|||||||
QLocale::Language language = QLocale::c().language();
|
QLocale::Language language = QLocale::c().language();
|
||||||
QLocale::Country country = QLocale::c().country();
|
QLocale::Country country = QLocale::c().country();
|
||||||
QString alias;
|
QString alias;
|
||||||
|
auto compressAlgo = m_compressionAlgo;
|
||||||
int compressLevel = m_compressLevel;
|
int compressLevel = m_compressLevel;
|
||||||
int compressThreshold = m_compressThreshold;
|
int compressThreshold = m_compressThreshold;
|
||||||
|
|
||||||
@ -444,17 +466,27 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
|
|||||||
if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS))
|
if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS))
|
||||||
alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString();
|
alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString();
|
||||||
|
|
||||||
|
compressAlgo = m_compressionAlgo;
|
||||||
compressLevel = m_compressLevel;
|
compressLevel = m_compressLevel;
|
||||||
if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS))
|
|
||||||
compressLevel = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString().toInt();
|
|
||||||
|
|
||||||
compressThreshold = m_compressThreshold;
|
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))
|
if (attributes.hasAttribute(m_strings.ATTRIBUTE_THRESHOLD))
|
||||||
compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt();
|
compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt();
|
||||||
|
|
||||||
// Special case for -no-compress. Overrides all other settings.
|
if (!errorString.isEmpty())
|
||||||
if (m_compressLevel == -2)
|
reader.raiseError(errorString);
|
||||||
compressLevel = 0;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString()));
|
reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString()));
|
||||||
@ -520,6 +552,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
|
|||||||
language,
|
language,
|
||||||
country,
|
country,
|
||||||
child.isDir() ? RCCFileInfo::Directory : RCCFileInfo::NoFlags,
|
child.isDir() ? RCCFileInfo::Directory : RCCFileInfo::NoFlags,
|
||||||
|
compressAlgo,
|
||||||
compressLevel,
|
compressLevel,
|
||||||
compressThreshold)
|
compressThreshold)
|
||||||
);
|
);
|
||||||
@ -535,6 +568,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
|
|||||||
language,
|
language,
|
||||||
country,
|
country,
|
||||||
RCCFileInfo::NoFlags,
|
RCCFileInfo::NoFlags,
|
||||||
|
compressAlgo,
|
||||||
compressLevel,
|
compressLevel,
|
||||||
compressThreshold)
|
compressThreshold)
|
||||||
);
|
);
|
||||||
@ -729,6 +763,40 @@ RCCResourceLibrary::ResourceDataFileMap RCCResourceLibrary::resourceDataFileMap(
|
|||||||
return rc;
|
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)
|
bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &tempDevice, QIODevice &errorDevice)
|
||||||
{
|
{
|
||||||
m_errorDevice = &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/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the tools applications of the Qt Toolkit.
|
** 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; }
|
void setOutputName(const QString &name) { m_outputName = name; }
|
||||||
QString outputName() const { return m_outputName; }
|
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; }
|
void setCompressLevel(int c) { m_compressLevel = c; }
|
||||||
int compressLevel() const { return m_compressLevel; }
|
int compressLevel() const { return m_compressLevel; }
|
||||||
|
|
||||||
@ -104,6 +116,7 @@ private:
|
|||||||
const QString ATTRIBUTE_ALIAS;
|
const QString ATTRIBUTE_ALIAS;
|
||||||
const QString ATTRIBUTE_THRESHOLD;
|
const QString ATTRIBUTE_THRESHOLD;
|
||||||
const QString ATTRIBUTE_COMPRESS;
|
const QString ATTRIBUTE_COMPRESS;
|
||||||
|
const QString ATTRIBUTE_COMPRESSALGO;
|
||||||
};
|
};
|
||||||
friend class RCCFileInfo;
|
friend class RCCFileInfo;
|
||||||
void reset();
|
void reset();
|
||||||
@ -133,6 +146,7 @@ private:
|
|||||||
QString m_outputName;
|
QString m_outputName;
|
||||||
Format m_format;
|
Format m_format;
|
||||||
bool m_verbose;
|
bool m_verbose;
|
||||||
|
CompressionAlgorithm m_compressionAlgo;
|
||||||
int m_compressLevel;
|
int m_compressLevel;
|
||||||
int m_compressThreshold;
|
int m_compressThreshold;
|
||||||
int m_treeOffset;
|
int m_treeOffset;
|
||||||
|
Loading…
Reference in New Issue
Block a user