summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex <prevedtest@gmail.com>2014-01-15 19:36:44 +0400
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-26 09:18:49 +0100
commitd47d38d7d718673e2c3673bb13fa158446ae8fba (patch)
treedb3666b86d6f4bfd92b567f405889957f1456aff
parent10f883c2dc8264cec87e0e07a0968142216740be (diff)
Add support for reading icon variants in ICNS plugin
Change-Id: I68395ac4e9604d852405643710aa79585974b3e3 Reviewed-by: Ivan Komissarov <ABBAPOH@gmail.com> Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com> Reviewed-by: Jake Petroules <jake.petroules@petroules.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
-rw-r--r--src/plugins/imageformats/icns/qicnshandler.cpp39
-rw-r--r--src/plugins/imageformats/icns/qicnshandler_p.h10
-rw-r--r--tests/auto/icns/tst_qicns.cpp1
-rw-r--r--tests/shared/images/icns.qrc1
-rw-r--r--tests/shared/images/icns/test-variants.icnsbin0 -> 16360 bytes
5 files changed, 47 insertions, 4 deletions
diff --git a/src/plugins/imageformats/icns/qicnshandler.cpp b/src/plugins/imageformats/icns/qicnshandler.cpp
index b99c667..c6bff58 100644
--- a/src/plugins/imageformats/icns/qicnshandler.cpp
+++ b/src/plugins/imageformats/icns/qicnshandler.cpp
@@ -372,7 +372,8 @@ static inline bool isIconCompressed(const ICNSEntry &icon)
static inline bool isMaskSuitable(const ICNSEntry &mask, const ICNSEntry &icon, ICNSEntry::Depth target)
{
- return mask.depth == target && mask.height == icon.height && mask.width == icon.width;
+ return mask.variant == icon.variant && mask.depth == target
+ && mask.height == icon.height && mask.width == icon.width;
}
static inline QByteArray nameFromOSType(quint32 ostype)
@@ -813,6 +814,8 @@ QVariant QICNSHandler::option(ImageOption option) const
if (option == SubType) {
if (imageCount() > 0 && m_currentIconIndex <= imageCount()) {
const ICNSEntry &icon = m_icons.at(m_currentIconIndex);
+ if (icon.variant != 0)
+ return nameFromOSType(icon.variant) + '-' + nameFromOSType(icon.ostype);
return nameFromOSType(icon.ostype);
}
}
@@ -852,11 +855,12 @@ bool QICNSHandler::ensureScanned() const
return m_state == ScanSuccess;
}
-bool QICNSHandler::addEntry(const ICNSBlockHeader &header, qint64 imgDataOffset)
+bool QICNSHandler::addEntry(const ICNSBlockHeader &header, qint64 imgDataOffset, quint32 variant)
{
// Note: This function returns false only when a device positioning error occurred
ICNSEntry entry;
entry.ostype = header.ostype;
+ entry.variant = variant;
entry.dataOffset = imgDataOffset;
entry.dataLength = header.length - ICNSBlockHeaderSize;
// Check for known magic numbers:
@@ -920,6 +924,37 @@ bool QICNSHandler::scanDevice()
// We don't have a good use for these blocks... yet.
stream.skipRawData(blockDataLength);
break;
+ case ICNSBlockHeader::TypeTile:
+ case ICNSBlockHeader::TypeOver:
+ case ICNSBlockHeader::TypeOpen:
+ case ICNSBlockHeader::TypeDrop:
+ case ICNSBlockHeader::TypeOdrp:
+ // Icns container seems to have an embedded icon variant container
+ // Let's start a scan for entries
+ while (device()->pos() < nextBlockOffset) {
+ ICNSBlockHeader icon;
+ stream >> icon;
+ // Check for incorrect variant entry header and stop scan
+ if (!isBlockHeaderValid(icon, blockDataLength))
+ break;
+ if (!addEntry(icon, device()->pos(), blockHeader.ostype))
+ return false;
+ if (stream.skipRawData(icon.length - ICNSBlockHeaderSize) < 0)
+ return false;
+ }
+ if (device()->pos() != nextBlockOffset) {
+ // Scan of this container didn't end where we expected.
+ // Let's generate some output about this incident:
+ qWarning("Scan of the icon variant container (\"%s\") failed at pos %s.\n" \
+ "Reason: Scan didn't reach the end of this container's block, " \
+ "delta: %s bytes. This file may be corrupted.",
+ nameFromOSType(blockHeader.ostype).constData(),
+ QByteArray::number(device()->pos()).constData(),
+ QByteArray::number(nextBlockOffset - device()->pos()).constData());
+ if (!device()->seek(nextBlockOffset))
+ return false;
+ }
+ break;
case ICNSBlockHeader::TypeToc: {
// Quick scan, table of contents
if (blockDataOffset != ICNSBlockHeaderSize * 2) {
diff --git a/src/plugins/imageformats/icns/qicnshandler_p.h b/src/plugins/imageformats/icns/qicnshandler_p.h
index 12c165b..747cb3e 100644
--- a/src/plugins/imageformats/icns/qicnshandler_p.h
+++ b/src/plugins/imageformats/icns/qicnshandler_p.h
@@ -60,6 +60,11 @@ struct ICNSBlockHeader
TypeIcnv = MAKEOSTYPE('i', 'c', 'n', 'V'), // Icon Composer version
// Legacy:
TypeClut = MAKEOSTYPE('c', 'l', 'u', 't'), // Color look-up table (pre-OS X resources)
+ TypeTile = MAKEOSTYPE('t', 'i', 'l', 'e'), // Container (icon variants)
+ TypeOver = MAKEOSTYPE('o', 'v', 'e', 'r'), // Container (icon variants)
+ TypeOpen = MAKEOSTYPE('o', 'p', 'e', 'n'), // Container (icon variants)
+ TypeDrop = MAKEOSTYPE('d', 'r', 'o', 'p'), // Container (icon variants)
+ TypeOdrp = MAKEOSTYPE('o', 'd', 'r', 'p'), // Container (icon variants)
};
quint32 ostype;
@@ -102,6 +107,7 @@ struct ICNSEntry
};
quint32 ostype; // Real OSType
+ quint32 variant; // Virtual OSType: a parent container, zero if parent is icns root
Group group; // ASCII character number
quint32 width; // For uncompressed icons only, zero for compressed ones for now
quint32 height; // For uncompressed icons only, zero for compressed ones fow now
@@ -112,7 +118,7 @@ struct ICNSEntry
qint64 dataOffset; // Offset from the initial position of the file/device
ICNSEntry() :
- ostype(0), group(GroupUnknown), width(0), height(0), depth(DepthUnknown),
+ ostype(0), variant(0), group(GroupUnknown), width(0), height(0), depth(DepthUnknown),
flags(Unknown), dataFormat(FormatUnknown), dataLength(0), dataOffset(0)
{
}
@@ -142,7 +148,7 @@ public:
private:
bool ensureScanned() const;
bool scanDevice();
- bool addEntry(const ICNSBlockHeader &header, qint64 imgDataOffset);
+ bool addEntry(const ICNSBlockHeader &header, qint64 imgDataOffset, quint32 variant = 0);
const ICNSEntry &getIconMask(const ICNSEntry &icon) const;
private:
diff --git a/tests/auto/icns/tst_qicns.cpp b/tests/auto/icns/tst_qicns.cpp
index 261590e..29ca3ee 100644
--- a/tests/auto/icns/tst_qicns.cpp
+++ b/tests/auto/icns/tst_qicns.cpp
@@ -65,6 +65,7 @@ void tst_qicns::readIcons_data()
QTest::newRow("2") << QStringLiteral("test-jp2") << QSize(128, 128) << 7 << QByteArrayLiteral("jp2");
QTest::newRow("3") << QStringLiteral("test-32bit") << QSize(128, 128) << 4 << QByteArray();
QTest::newRow("4") << QStringLiteral("test-legacy") << QSize(48, 48) << 12 << QByteArray();
+ QTest::newRow("5") << QStringLiteral("test-variants") << QSize(128, 128) << 5 << QByteArrayLiteral("png");
}
void tst_qicns::readIcons()
diff --git a/tests/shared/images/icns.qrc b/tests/shared/images/icns.qrc
index 072b78c..f87830d 100644
--- a/tests/shared/images/icns.qrc
+++ b/tests/shared/images/icns.qrc
@@ -4,6 +4,7 @@
<file>icns/test-jp2.icns</file>
<file>icns/test-32bit.icns</file>
<file>icns/test-legacy.icns</file>
+ <file>icns/test-variants.icns</file>
<file>icns/test-write-16.png</file>
<file>icns/test-write-32.png</file>
<file>icns/test-write-64.png</file>
diff --git a/tests/shared/images/icns/test-variants.icns b/tests/shared/images/icns/test-variants.icns
new file mode 100644
index 0000000..e623279
--- /dev/null
+++ b/tests/shared/images/icns/test-variants.icns
Binary files differ