Coverage Report

Created: 2026-10-14 08:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/image/qimagereaderwriterhelpers.cpp
Line
Count
Source
1
// Copyright (C) 2018 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#include "private/qimagereaderwriterhelpers_p.h"
6
7
#include <qcborarray.h>
8
#include <qmutex.h>
9
#include <private/qfactoryloader_p.h>
10
11
QT_BEGIN_NAMESPACE
12
13
using namespace Qt::StringLiterals;
14
15
namespace QImageReaderWriterHelpers {
16
17
#ifndef QT_NO_IMAGEFORMATPLUGIN
18
19
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, irhLoader,
20
                          (QImageIOHandlerFactoryInterface_iid, "/imageformats"_L1))
21
Q_GLOBAL_STATIC(QMutex, irhLoaderMutex)
22
23
static void appendImagePluginFormats(QFactoryLoader *loader,
24
                                     QImageIOPlugin::Capability cap,
25
                                     QList<QByteArray> *result)
26
0
{
27
0
    typedef QMultiMap<int, QString> PluginKeyMap;
28
0
    typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator;
29
30
0
    const PluginKeyMap keyMap = loader->keyMap();
31
0
    const PluginKeyMapConstIterator cend = keyMap.constEnd();
32
0
    int i = -1;
33
0
    QImageIOPlugin *plugin = nullptr;
34
0
    result->reserve(result->size() + keyMap.size());
35
0
    for (PluginKeyMapConstIterator it = keyMap.constBegin(); it != cend; ++it) {
36
0
        if (it.key() != i) {
37
0
            i = it.key();
38
0
            plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i));
39
0
        }
40
0
        const QByteArray key = it.value().toLatin1();
41
0
        if (plugin && (plugin->capabilities(nullptr, key) & cap) != 0)
42
0
            result->append(key);
43
0
    }
44
0
}
45
46
static void appendImagePluginMimeTypes(QFactoryLoader *loader,
47
                                       QImageIOPlugin::Capability cap,
48
                                       QList<QByteArray> *result,
49
                                       QList<QByteArray> *resultKeys = nullptr)
50
0
{
51
0
    QList<QPluginParsedMetaData> metaDataList = loader->metaData();
52
0
    const int pluginCount = metaDataList.size();
53
0
    for (int i = 0; i < pluginCount; ++i) {
54
0
        const QCborMap metaData = metaDataList.at(i).value(QtPluginMetaDataKeys::MetaData).toMap();
55
0
        const QCborArray keys = metaData.value("Keys"_L1).toArray();
56
0
        const QCborArray mimeTypes = metaData.value("MimeTypes"_L1).toArray();
57
0
        QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i));
58
0
        const int keyCount = keys.size();
59
0
        for (int k = 0; k < keyCount; ++k) {
60
0
            const QByteArray key = keys.at(k).toString().toLatin1();
61
0
            if (plugin && (plugin->capabilities(nullptr, key) & cap) != 0) {
62
0
                result->append(mimeTypes.at(k).toString().toLatin1());
63
0
                if (resultKeys)
64
0
                    resultKeys->append(key);
65
0
            }
66
0
        }
67
0
    }
68
0
}
69
70
QSharedPointer<QFactoryLoader> pluginLoader()
71
0
{
72
0
    irhLoaderMutex()->lock();
73
0
    return QSharedPointer<QFactoryLoader>(irhLoader(), [](QFactoryLoader *) {
74
0
        irhLoaderMutex()->unlock();
75
0
    });
76
0
}
77
78
static inline QImageIOPlugin::Capability pluginCapability(Capability cap)
79
0
{
80
0
    return cap == CanRead ? QImageIOPlugin::CanRead : QImageIOPlugin::CanWrite;
81
0
}
82
83
#endif // QT_NO_IMAGEFORMATPLUGIN
84
85
QList<QByteArray> supportedImageFormats(Capability cap)
86
0
{
87
0
    QList<QByteArray> formats;
88
0
    formats.reserve(_qt_NumFormats);
89
0
    for (int i = 0; i < _qt_NumFormats; ++i)
90
0
        formats << _qt_BuiltInFormats[i].extension;
91
92
0
#ifndef QT_NO_IMAGEFORMATPLUGIN
93
0
    appendImagePluginFormats(irhLoader(), pluginCapability(cap), &formats);
94
0
#endif // QT_NO_IMAGEFORMATPLUGIN
95
96
0
    std::sort(formats.begin(), formats.end());
97
0
    formats.erase(std::unique(formats.begin(), formats.end()), formats.end());
98
0
    return formats;
99
0
}
100
101
0
static constexpr QByteArrayView imagePrefix() noexcept { return "image/"; }
102
103
QList<QByteArray> supportedMimeTypes(Capability cap)
104
0
{
105
0
    QList<QByteArray> mimeTypes;
106
0
    mimeTypes.reserve(_qt_NumFormats);
107
0
    for (const auto &fmt : _qt_BuiltInFormats)
108
0
        mimeTypes.emplace_back(imagePrefix() + fmt.mimeType);
109
110
0
#ifndef QT_NO_IMAGEFORMATPLUGIN
111
0
    appendImagePluginMimeTypes(irhLoader(), pluginCapability(cap), &mimeTypes);
112
0
#endif // QT_NO_IMAGEFORMATPLUGIN
113
114
0
    std::sort(mimeTypes.begin(), mimeTypes.end());
115
0
    mimeTypes.erase(std::unique(mimeTypes.begin(), mimeTypes.end()), mimeTypes.end());
116
0
    return mimeTypes;
117
0
}
118
119
QList<QByteArray> imageFormatsForMimeType(QByteArrayView mimeType, Capability cap)
120
0
{
121
0
    QList<QByteArray> formats;
122
0
    if (mimeType.startsWith(imagePrefix())) {
123
0
        const QByteArrayView type = mimeType.mid(imagePrefix().size());
124
0
        for (const auto &fmt : _qt_BuiltInFormats) {
125
0
            if (fmt.mimeType == type && !formats.contains(fmt.extension))
126
0
                formats << fmt.extension;
127
0
        }
128
0
    }
129
130
0
#ifndef QT_NO_IMAGEFORMATPLUGIN
131
0
    QList<QByteArray> mimeTypes;
132
0
    QList<QByteArray> keys;
133
0
    appendImagePluginMimeTypes(irhLoader(), pluginCapability(cap), &mimeTypes, &keys);
134
0
    for (int i = 0; i < mimeTypes.size(); ++i) {
135
0
        if (mimeTypes.at(i) == mimeType) {
136
0
            const auto &key = keys.at(i);
137
0
            if (!formats.contains(key))
138
0
                formats << key;
139
0
        }
140
0
    }
141
0
#endif // QT_NO_IMAGEFORMATPLUGIN
142
143
0
    return formats;
144
0
}
145
146
} // QImageReaderWriterHelpers
147
148
QT_END_NAMESPACE