1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2006-09-15
7  * Description : Exiv2 library interface.
8  *               Internal private container.
9  *
10  * Copyright (C) 2006-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  * Copyright (C) 2006-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
12  *
13  * This program is free software; you can redistribute it
14  * and/or modify it under the terms of the GNU General
15  * Public License as published by the Free Software Foundation;
16  * either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #ifndef DIGIKAM_META_ENGINE_PRIVATE_H
27 #define DIGIKAM_META_ENGINE_PRIVATE_H
28 
29 #include "metaengine.h"
30 
31  // C++ includes
32 
33 #include <cstdlib>
34 #include <cstdio>
35 #include <cmath>
36 #include <cfloat>
37 #include <iostream>
38 #include <iomanip>
39 #include <string>
40 
41 // Qt includes
42 
43 #include <QFile>
44 #include <QSize>
45 #include <QLatin1String>
46 #include <QFileInfo>
47 #include <QSharedData>
48 #include <QMutexLocker>
49 #include <QMimeDatabase>
50 
51 // Exiv2 includes -------------------------------------------------------
52 
53 // NOTE: All Exiv2 headers must be stay there to not expose external source code to Exiv2 API
54 //       and reduce Exiv2 dependency to client code.
55 
56 #if defined(Q_CC_CLANG)
57 #   pragma clang diagnostic push
58 #   pragma clang diagnostic ignored "-Wdeprecated-declarations"
59 #endif
60 
61 // The pragmas are required to be able to catch exceptions thrown by libexiv2:
62 // See gcc.gnu.org/wiki/Visibility, the section about c++ exceptions.
63 // They are needed for all libexiv2 versions that do not care about visibility.
64 
65 #ifdef Q_CC_GNU
66 #   pragma GCC visibility push(default)
67 #endif
68 
69 #include <exiv2/exv_conf.h>
70 #include <exiv2/error.hpp>
71 #include <exiv2/image.hpp>
72 #include <exiv2/jpgimage.hpp>
73 #include <exiv2/datasets.hpp>
74 #include <exiv2/tags.hpp>
75 #include <exiv2/preview.hpp>
76 #include <exiv2/properties.hpp>
77 #include <exiv2/types.hpp>
78 #include <exiv2/exif.hpp>
79 #include <exiv2/xmpsidecar.hpp>
80 #include <exiv2/version.hpp>
81 
82 // Check if Exiv2 support XMP
83 
84 #ifdef EXV_HAVE_XMP_TOOLKIT
85 #   define _XMP_SUPPORT_ 1
86 #endif
87 
88 #ifndef EXIV2_TEST_VERSION
89 #    define EXIV2_TEST_VERSION(major,minor,patch) \
90          ( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) )
91 #endif
92 
93 #if EXIV2_TEST_VERSION(0,27,99)
94 #   define AutoPtr UniquePtr
95 #endif
96 
97 #if EXIV2_TEST_VERSION(0,27,4)
98 #   include <exiv2/bmffimage.hpp>
99 #endif
100 
101 // With exiv2 > 0.20.0, all makernote header files have been removed to increase binary compatibility.
102 // See Exiv2 bugzilla entry dev.exiv2.org/issues/719
103 // and wiki topic           dev.exiv2.org/boards/3/topics/583
104 
105 #ifdef Q_CC_GNU
106 #   pragma GCC visibility pop
107 #endif
108 
109 // End of Exiv2 headers ------------------------------------------------------
110 
111 // Local includes
112 
113 #include "metaengine_mergehelper.h"
114 
115 namespace Digikam
116 {
117 
118 extern QMutex s_metaEngineMutex;            ///< Mutex to fix no re-entrancy from Exiv2.
119 extern bool   s_metaEngineSupportBmff;      ///< Flag for Exiv2 Base Media File Format support.
120 
121 // --------------------------------------------------------------------------
122 
123 class Q_DECL_HIDDEN MetaEngine::Private
124 {
125 public:
126 
127     explicit Private();
128     ~Private();
129 
130     void copyPrivateData(const Private* const other);
131 
132     bool saveToXMPSidecar(const QFileInfo& finfo)                                 const;
133     bool saveToFile(const QFileInfo& finfo)                                       const;
134     bool saveOperations(const QFileInfo& finfo, Exiv2::Image::AutoPtr image)      const;
135 
136     /**
137      * Wrapper method to convert a Comments content to a QString.
138      */
139     QString convertCommentValue(const Exiv2::Exifdatum& exifDatum)                const;
140 
141     /**
142      * Charset autodetection to convert a string to a QString.
143      */
144     QString detectEncodingAndDecode(const std::string& value)                     const;
145 
146     /**
147      * UTF8 autodetection from a string.
148      */
149     bool isUtf8(const char* const buffer)                                         const;
150 
151     int getXMPTagsListFromPrefix(const QString& pf, MetaEngine::TagsMap& tagsMap) const;
152 
153     const Exiv2::ExifData& exifMetadata()                                         const;
154     const Exiv2::IptcData& iptcMetadata()                                         const;
155     const std::string&     itemComments()                                         const;
156 
157     Exiv2::ExifData&       exifMetadata();
158     Exiv2::IptcData&       iptcMetadata();
159     std::string&           itemComments();
160 
161 public:
162 
163 #ifdef _XMP_SUPPORT_
164 
165     const Exiv2::XmpData&  xmpMetadata()                                          const;
166     Exiv2::XmpData&        xmpMetadata();
167 
168     void loadSidecarData(Exiv2::Image::AutoPtr xmpsidecar);
169 
170 #endif
171 
172 public:
173 
174     /**
175      * Helper method to decode IPTC tag string contents following characters encoding preset.
176      */
177     QString extractIptcTagString(const Exiv2::IptcData& iptcData, const Exiv2::Iptcdatum& iptcTag) const;
178 
179 public:
180 
181     /**
182      * Generic method to print the Exiv2 C++ Exception error message from 'e'.
183      * 'msg' string is printed using qDebug rules.
184      */
185     static void printExiv2ExceptionError(const QString& msg, Exiv2::AnyError& e);
186 
187     /**
188      * Generic method to print debug message from Exiv2.
189      * 'msg' string is printed using qDebug rules. 'lvl' is the debug level of Exiv2 message.
190      */
191     static void printExiv2MessageHandler(int lvl, const char* msg);
192 
193 public:
194 
195     bool                                                  writeRawFiles;
196     bool                                                  writeDngFiles;
197     bool                                                  updateFileTimeStamp;
198 
199     bool                                                  useXMPSidecar4Reading;
200     bool                                                  useCompatibleFileName;
201 
202     /// A mode from #MetadataWritingMode enum.
203     int                                                   metadataWritingMode;
204 
205     /// XMP, and parts of EXIF/IPTC, were loaded from an XMP sidecar file
206     bool                                                  loadedFromSidecar;
207 
208     QString                                               filePath;
209     QSize                                                 pixelSize;
210     QString                                               mimeType;
211 
212     QExplicitlySharedDataPointer<MetaEngineData::Private> data;
213 };
214 
215 } // namespace Digikam
216 
217 #if defined(Q_CC_CLANG)
218 #   pragma clang diagnostic pop
219 #endif
220 
221 #endif // DIGIKAM_META_ENGINE_PRIVATE_H
222