Coverage Report

Created: 2026-01-25 07:18

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