Coverage Report

Created: 2026-04-29 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libkexiv2/src/kexiv2_p.h
Line
Count
Source
1
/*
2
    SPDX-FileCopyrightText: 2006-2015 Gilles Caulier <caulier dot gilles at gmail dot com>
3
    SPDX-FileCopyrightText: 2006-2012 Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
4
5
    SPDX-License-Identifier: GPL-2.0-or-later
6
*/
7
8
#ifndef KEXIV2PRIVATE_H
9
#define KEXIV2PRIVATE_H
10
11
#include "kexiv2.h"
12
13
 // C++ includes
14
15
#include <cstdlib>
16
#include <cstdio>
17
#include <cassert>
18
#include <cmath>
19
#include <cfloat>
20
#include <iostream>
21
#include <iomanip>
22
#include <string>
23
24
// Qt includes
25
26
#include <QFile>
27
#include <QSize>
28
#include <QLatin1String>
29
#include <QFileInfo>
30
#include <QSharedData>
31
32
// Exiv2 includes -------------------------------------------------------
33
34
// NOTE: All Exiv2 header must be stay there to not expose external source code to Exiv2 API
35
//       and reduce Exiv2 dependency to client code.
36
37
// The pragmas are required to be able to catch exceptions thrown by libexiv2:
38
// See https://gcc.gnu.org/wiki/Visibility, the section about c++ exceptions.
39
// They are needed for all libexiv2 versions that do not care about visibility.
40
#ifdef __GNUC__
41
#pragma GCC visibility push(default)
42
#endif
43
44
#include <exiv2/exiv2.hpp>
45
46
// Check if Exiv2 support XMP
47
48
#ifdef EXV_HAVE_XMP_TOOLKIT
49
#   define _XMP_SUPPORT_ 1
50
#endif
51
52
// With exiv2 > 0.20.0, all makernote header files have been removed to increase binary compatibility.
53
// See Exiv2 bugzilla entry https://dev.exiv2.org/issues/719
54
// and wiki topic           https://dev.exiv2.org/boards/3/topics/583
55
56
#ifdef __GNUC__
57
#pragma GCC visibility pop
58
#endif
59
60
// End of Exiv2 headers ------------------------------------------------------
61
62
namespace KExiv2Iface
63
{
64
65
class KExiv2DataPrivate : public QSharedData
66
{
67
public:
68
69
    void clear();
70
71
public:
72
73
    std::string     imageComments;
74
75
    Exiv2::ExifData exifMetadata;
76
77
    Exiv2::IptcData iptcMetadata;
78
79
#ifdef _XMP_SUPPORT_
80
    Exiv2::XmpData  xmpMetadata;
81
#endif
82
};
83
84
// --------------------------------------------------------------------------
85
86
class KExiv2Private
87
{
88
public:
89
90
    KExiv2Private();
91
    ~KExiv2Private();
92
93
    void copyPrivateData(const KExiv2Private* const other);
94
95
    bool saveToXMPSidecar(const QFileInfo& finfo)                            const;
96
    bool saveToFile(const QFileInfo& finfo)                                  const;
97
#if EXIV2_TEST_VERSION(0,28,0)
98
    bool saveOperations(const QFileInfo& finfo, Exiv2::Image::UniquePtr image) const;
99
#else
100
    bool saveOperations(const QFileInfo& finfo, Exiv2::Image::AutoPtr image) const;
101
#endif
102
103
    /** Wrapper method to convert a Comments content to a QString.
104
     */
105
    QString convertCommentValue(const Exiv2::Exifdatum& exifDatum) const;
106
107
    /** Charset autodetection to convert a string to a QString.
108
     */
109
    QString detectEncodingAndDecode(const std::string& value)      const;
110
111
    /** UTF8 autodetection from a string.
112
     */
113
    bool isUtf8(const char* const buffer)                          const;
114
115
    int getXMPTagsListFromPrefix(const QString& pf, KExiv2::TagsMap& tagsMap) const;
116
117
0
    const Exiv2::ExifData& exifMetadata()  const { return data.constData()->exifMetadata;  }
118
0
    const Exiv2::IptcData& iptcMetadata()  const { return data.constData()->iptcMetadata;  }
119
0
    const std::string&     imageComments() const { return data.constData()->imageComments; }
120
121
#ifdef _XMP_SUPPORT_
122
0
    const Exiv2::XmpData&  xmpMetadata()   const { return data.constData()->xmpMetadata;   }
123
#endif
124
125
50.7k
    Exiv2::ExifData&       exifMetadata()        { return data.data()->exifMetadata;       }
126
17.0k
    Exiv2::IptcData&       iptcMetadata()        { return data.data()->iptcMetadata;       }
127
17.0k
    std::string&           imageComments()       { return data.data()->imageComments;      }
128
129
#ifdef _XMP_SUPPORT_
130
17.0k
    Exiv2::XmpData&        xmpMetadata()         { return data.data()->xmpMetadata;        }
131
132
#if EXIV2_TEST_VERSION(0,28,0)
133
    void loadSidecarData(Exiv2::Image::UniquePtr xmpsidecar);
134
#else
135
    void loadSidecarData(Exiv2::Image::AutoPtr xmpsidecar);
136
#endif
137
#endif
138
139
public:
140
141
    /** Generic method to print the Exiv2 C++ Exception error message from 'e'.
142
     *  'msg' string is printed using kDebug rules..
143
     */
144
    static void printExiv2ExceptionError(const QString& msg, Exiv2::Error& e);
145
146
    /** Generic method to print debug message from Exiv2.
147
     *  'msg' string is printed using kDebug rules. 'lvl' is the debug level of Exiv2 message.
148
     */
149
    static void printExiv2MessageHandler(int lvl, const char* msg);
150
151
public:
152
153
    bool                                           writeRawFiles;
154
    bool                                           updateFileTimeStamp;
155
156
    bool                                           useXMPSidecar4Reading;
157
158
    /// A mode from #MetadataWritingMode enum.
159
    int                                            metadataWritingMode;
160
161
    /// XMP, and parts of EXIF/IPTC, were loaded from an XMP sidecar file
162
    bool                                           loadedFromSidecar;
163
164
    QString                                        filePath;
165
    QSize                                          pixelSize;
166
    QString                                        mimeType;
167
168
    QSharedDataPointer<KExiv2DataPrivate> data;
169
};
170
171
// --------------------------------------------------------------------------------------------
172
173
template <class Data, class Key, class KeyString, class KeyStringList = QList<KeyString> >
174
175
class MergeHelper
176
{
177
public:
178
179
    KeyStringList keys;
180
181
    MergeHelper& operator<<(const KeyString& key)
182
0
    {
183
0
        keys << key;
184
0
        return *this;
185
0
    }
Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::ExifData, Exiv2::ExifKey, QLatin1String, QList<QLatin1String> >::operator<<(QLatin1String const&)
Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::IptcData, Exiv2::IptcKey, QLatin1String, QList<QLatin1String> >::operator<<(QLatin1String const&)
186
187
    /**
188
      * Merge two (Exif,IPTC,Xmp)Data packages, where the result is stored in dest
189
      * and fields from src take precedence over existing data from dest.
190
      */
191
    void mergeAll(const Data& src, Data& dest)
192
    {
193
        for (typename Data::const_iterator it = src.begin(); it != src.end(); ++it)
194
        {
195
            typename Data::iterator destIt = dest.findKey(Key(it->key()));
196
197
            if (destIt == dest.end())
198
            {
199
                dest.add(*it);
200
            }
201
            else
202
            {
203
                *destIt = *it;
204
            }
205
        }
206
    }
207
208
    /**
209
     * Merge two (Exif,IPTC,Xmp)Data packages, the result is stored in dest.
210
     * Only keys in keys are considered for merging.
211
     * Fields from src take precedence over existing data from dest.
212
     */
213
    void mergeFields(const Data& src, Data& dest) const
214
0
    {
215
0
        for (const KeyString& keyString : keys)
216
0
        {
217
0
            Key key(keyString.latin1());
218
0
            typename Data::const_iterator it = src.findKey(key);
219
220
0
            if (it == src.end())
221
0
            {
222
0
                continue;
223
0
            }
224
225
0
            typename Data::iterator destIt = dest.findKey(key);
226
227
0
            if (destIt == dest.end())
228
0
            {
229
0
                dest.add(*it);
230
0
            }
231
0
            else
232
0
            {
233
0
                *destIt = *it;
234
0
            }
235
0
        }
236
0
    }
Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::ExifData, Exiv2::ExifKey, QLatin1String, QList<QLatin1String> >::mergeFields(Exiv2::ExifData const&, Exiv2::ExifData&) const
Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::IptcData, Exiv2::IptcKey, QLatin1String, QList<QLatin1String> >::mergeFields(Exiv2::IptcData const&, Exiv2::IptcData&) const
237
238
    /**
239
     * Merge two (Exif,IPTC,Xmp)Data packages, the result is stored in dest.
240
     * The following steps apply only to keys in "keys":
241
     * The result is determined by src.
242
     * Keys must exist in src to kept in dest.
243
     * Fields from src take precedence over existing data from dest.
244
     */
245
    void exclusiveMerge(const Data& src, Data& dest) const
246
0
    {
247
0
        for (const KeyString& keyString : keys)
248
0
        {
249
0
            Key key(keyString.latin1());
250
0
            typename Data::const_iterator it = src.findKey(key);
251
0
            typename Data::iterator destIt = dest.findKey(key);
252
253
0
            if (destIt == dest.end())
254
0
            {
255
0
                if (it != src.end())
256
0
                {
257
0
                    dest.add(*it);
258
0
                }
259
0
            }
260
0
            else
261
0
            {
262
0
                if (it == src.end())
263
0
                {
264
0
                    dest.erase(destIt);
265
0
                }
266
0
                else
267
0
                {
268
0
                    *destIt = *it;
269
0
                }
270
0
            }
271
0
        }
272
0
    }
Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::ExifData, Exiv2::ExifKey, QLatin1String, QList<QLatin1String> >::exclusiveMerge(Exiv2::ExifData const&, Exiv2::ExifData&) const
Unexecuted instantiation: KExiv2Iface::MergeHelper<Exiv2::IptcData, Exiv2::IptcKey, QLatin1String, QList<QLatin1String> >::exclusiveMerge(Exiv2::IptcData const&, Exiv2::IptcData&) const
273
};
274
275
class ExifMergeHelper : public MergeHelper<Exiv2::ExifData, Exiv2::ExifKey, QLatin1String>
276
{
277
};
278
279
class IptcMergeHelper : public MergeHelper<Exiv2::IptcData, Exiv2::IptcKey, QLatin1String>
280
{
281
};
282
283
#ifdef _XMP_SUPPORT_
284
class XmpMergeHelper : public MergeHelper<Exiv2::XmpData, Exiv2::XmpKey, QLatin1String>
285
{
286
};
287
#endif
288
289
}  // NameSpace KExiv2Iface
290
291
#endif // KEXIV2PRIVATE_H