/src/exiv2/include/exiv2/xmp_exiv2.hpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | |
3 | | #ifndef EXIV2_XMP_EXIV2_HPP |
4 | | #define EXIV2_XMP_EXIV2_HPP |
5 | | |
6 | | // ***************************************************************************** |
7 | | #include "exiv2lib_export.h" |
8 | | |
9 | | // included header files |
10 | | #include "datasets.hpp" |
11 | | #include "metadatum.hpp" |
12 | | #include "properties.hpp" |
13 | | |
14 | | #include <atomic> |
15 | | |
16 | | // ***************************************************************************** |
17 | | // namespace extensions |
18 | | namespace Exiv2 { |
19 | | // ***************************************************************************** |
20 | | // class declarations |
21 | | class ExifData; |
22 | | class XmpKey; |
23 | | |
24 | | // ***************************************************************************** |
25 | | // class definitions |
26 | | |
27 | | /*! |
28 | | @brief Information related to an XMP property. An XMP metadatum consists |
29 | | of an XmpKey and a Value and provides methods to manipulate these. |
30 | | */ |
31 | | class EXIV2API Xmpdatum : public Metadatum { |
32 | | public: |
33 | | //! @name Creators |
34 | | //@{ |
35 | | /*! |
36 | | @brief Constructor for new tags created by an application. The |
37 | | %Xmpdatum is created from a key / value pair. %Xmpdatum |
38 | | copies (clones) the value if one is provided. Alternatively, a |
39 | | program can create an 'empty' %Xmpdatum with only a key and |
40 | | set the value using setValue(). |
41 | | |
42 | | @param key The key of the %Xmpdatum. |
43 | | @param pValue Pointer to a %Xmpdatum value. |
44 | | @throw Error if the key cannot be parsed and converted |
45 | | to a known schema namespace prefix and property name. |
46 | | */ |
47 | | explicit Xmpdatum(const XmpKey& key, const Value* pValue = nullptr); |
48 | | //! Copy constructor |
49 | | Xmpdatum(const Xmpdatum& rhs); |
50 | | //! Destructor |
51 | | ~Xmpdatum() override; |
52 | | //@} |
53 | | |
54 | | //! @name Manipulators |
55 | | //@{ |
56 | | //! Assignment operator |
57 | | Xmpdatum& operator=(const Xmpdatum& rhs); |
58 | | /*! |
59 | | @brief Assign std::string \em value to the %Xmpdatum. |
60 | | Calls setValue(const std::string&). |
61 | | */ |
62 | | template <typename T> |
63 | | Xmpdatum& operator=(const T& value); |
64 | | /*! |
65 | | @brief Assign Value \em value to the %Xmpdatum. |
66 | | Calls setValue(const Value*). |
67 | | */ |
68 | | void setValue(const Value* pValue) override; |
69 | | /*! |
70 | | @brief Set the value to the string \em value. Uses Value::read(const |
71 | | std::string&). If the %Xmpdatum does not have a Value yet, |
72 | | then a %Value of the correct type for this %Xmpdatum is |
73 | | created. If the key is unknown, a XmpTextValue is used as |
74 | | default. Return 0 if the value was read successfully. |
75 | | */ |
76 | | int setValue(const std::string& value) override; |
77 | | //@} |
78 | | |
79 | | //! @name Accessors |
80 | | //@{ |
81 | | //! Not implemented. Calling this method will raise an exception. |
82 | | size_t copy(byte* buf, ByteOrder byteOrder) const override; |
83 | | std::ostream& write(std::ostream& os, const ExifData* pMetadata = nullptr) const override; |
84 | | /*! |
85 | | @brief Return the key of the Xmpdatum. The key is of the form |
86 | | '<b>Xmp</b>.prefix.property'. Note however that the |
87 | | key is not necessarily unique, i.e., an XmpData object may |
88 | | contain multiple metadata with the same key. |
89 | | */ |
90 | | [[nodiscard]] std::string key() const override; |
91 | | [[nodiscard]] const char* familyName() const override; |
92 | | //! Return the (preferred) schema namespace prefix. |
93 | | [[nodiscard]] std::string groupName() const override; |
94 | | //! Return the property name. |
95 | | [[nodiscard]] std::string tagName() const override; |
96 | | [[nodiscard]] std::string tagLabel() const override; |
97 | | [[nodiscard]] std::string tagDesc() const override; |
98 | | //! Properties don't have a tag number. Return 0. |
99 | | [[nodiscard]] uint16_t tag() const override; |
100 | | [[nodiscard]] TypeId typeId() const override; |
101 | | [[nodiscard]] const char* typeName() const override; |
102 | | // Todo: Remove this method from the baseclass |
103 | | //! The Exif typeSize doesn't make sense here. Return 0. |
104 | | [[nodiscard]] size_t typeSize() const override; |
105 | | [[nodiscard]] size_t count() const override; |
106 | | [[nodiscard]] size_t size() const override; |
107 | | [[nodiscard]] std::string toString() const override; |
108 | | [[nodiscard]] std::string toString(size_t n) const override; |
109 | | [[nodiscard]] int64_t toInt64(size_t n = 0) const override; |
110 | | [[nodiscard]] float toFloat(size_t n = 0) const override; |
111 | | [[nodiscard]] Rational toRational(size_t n = 0) const override; |
112 | | [[nodiscard]] std::unique_ptr<Value> getValue() const override; |
113 | | [[nodiscard]] const Value& value() const override; |
114 | | //@} |
115 | | |
116 | | private: |
117 | | // Pimpl idiom |
118 | | struct Impl; |
119 | | std::unique_ptr<Impl> p_; |
120 | | |
121 | | }; // class Xmpdatum |
122 | | |
123 | | //! Container type to hold all metadata |
124 | | using XmpMetadata = std::vector<Xmpdatum>; |
125 | | |
126 | | /*! |
127 | | @brief A container for XMP data. This is a top-level class of |
128 | | the %Exiv2 library. |
129 | | |
130 | | Provide high-level access to the XMP data of an image: |
131 | | - read XMP information from an XML block |
132 | | - access metadata through keys and standard C++ iterators |
133 | | - add, modify and delete metadata |
134 | | - serialize XMP data to an XML block |
135 | | */ |
136 | | class EXIV2API XmpData { |
137 | | public: |
138 | | //! Default constructor |
139 | 44.2k | XmpData() = default; |
140 | | |
141 | | //! XmpMetadata iterator type |
142 | | using iterator = XmpMetadata::iterator; |
143 | | //! XmpMetadata const iterator type |
144 | | using const_iterator = XmpMetadata::const_iterator; |
145 | | |
146 | | //! @name Manipulators |
147 | | //@{ |
148 | | /*! |
149 | | @brief Returns a reference to the %Xmpdatum that is associated with a |
150 | | particular \em key. If %XmpData does not already contain such |
151 | | an %Xmpdatum, operator[] adds object \em Xmpdatum(key). |
152 | | |
153 | | @note Since operator[] might insert a new element, it can't be a const |
154 | | member function. |
155 | | */ |
156 | | Xmpdatum& operator[](const std::string& key); |
157 | | /*! |
158 | | @brief Add an %Xmpdatum from the supplied key and value pair. This |
159 | | method copies (clones) the value. |
160 | | @return 0 if successful. |
161 | | */ |
162 | | int add(const XmpKey& key, const Value* value); |
163 | | /*! |
164 | | @brief Add a copy of the Xmpdatum to the XMP metadata. |
165 | | @return 0 if successful. |
166 | | */ |
167 | | int add(const Xmpdatum& xmpDatum); |
168 | | /* |
169 | | @brief Delete the Xmpdatum at iterator position pos, return the |
170 | | position of the next Xmpdatum. |
171 | | |
172 | | @note Iterators into the metadata, including pos, are potentially |
173 | | invalidated by this call. |
174 | | @brief Delete the Xmpdatum at iterator position pos and update pos |
175 | | */ |
176 | | iterator erase(XmpData::iterator pos); |
177 | | /*! |
178 | | @brief Delete the Xmpdatum at iterator position pos and update pos |
179 | | erases all following keys from the same family |
180 | | See: https://github.com/Exiv2/exiv2/issues/521 |
181 | | */ |
182 | | void eraseFamily(XmpData::iterator& pos); |
183 | | //! Delete all Xmpdatum instances resulting in an empty container. |
184 | | void clear(); |
185 | | //! Sort metadata by key |
186 | | void sortByKey(); |
187 | | //! Begin of the metadata |
188 | | iterator begin(); |
189 | | //! End of the metadata |
190 | | iterator end(); |
191 | | /*! |
192 | | @brief Find the first Xmpdatum with the given key, return an iterator |
193 | | to it. |
194 | | */ |
195 | | iterator findKey(const XmpKey& key); |
196 | | //@} |
197 | | |
198 | | //! @name Accessors |
199 | | //@{ |
200 | | //! Begin of the metadata |
201 | | [[nodiscard]] const_iterator begin() const; |
202 | | //! End of the metadata |
203 | | [[nodiscard]] const_iterator end() const; |
204 | | /*! |
205 | | @brief Find the first Xmpdatum with the given key, return a const |
206 | | iterator to it. |
207 | | */ |
208 | | [[nodiscard]] const_iterator findKey(const XmpKey& key) const; |
209 | | //! Return true if there is no XMP metadata |
210 | | [[nodiscard]] bool empty() const; |
211 | | //! Get the number of metadata entries |
212 | | [[nodiscard]] long count() const; |
213 | | |
214 | | //! are we to use the packet? |
215 | 2.73k | [[nodiscard]] bool usePacket() const { |
216 | 2.73k | return usePacket_; |
217 | 2.73k | } |
218 | | |
219 | | //! set usePacket_ |
220 | 10.8k | bool usePacket(bool b) { |
221 | 10.8k | bool r = usePacket_; |
222 | 10.8k | usePacket_ = b; |
223 | 10.8k | return r; |
224 | 10.8k | } |
225 | | //! setPacket |
226 | 10.8k | void setPacket(std::string xmpPacket) { |
227 | 10.8k | xmpPacket_ = std::move(xmpPacket); |
228 | 10.8k | usePacket(false); |
229 | 10.8k | } |
230 | | // ! getPacket |
231 | 0 | [[nodiscard]] const std::string& xmpPacket() const { |
232 | 0 | return xmpPacket_; |
233 | 0 | } |
234 | | |
235 | | //@} |
236 | | |
237 | | private: |
238 | | // DATA |
239 | | XmpMetadata xmpMetadata_; |
240 | | std::string xmpPacket_; |
241 | | bool usePacket_{}; |
242 | | |
243 | | int addUnlocked(const XmpKey& key, const Value* value, const XmpProperties::XmpLock&); |
244 | | int addUnlocked(const Xmpdatum& xmpDatum, const XmpProperties::XmpLock&); |
245 | | bool emptyUnlocked(const XmpProperties::XmpLock&) const; |
246 | | long countUnlocked(const XmpProperties::XmpLock&) const; |
247 | | void sortByKeyUnlocked(const XmpProperties::XmpLock&); |
248 | | void clearUnlocked(const XmpProperties::XmpLock&); |
249 | | friend class XmpParser; |
250 | | }; // class XmpData |
251 | | |
252 | | /*! |
253 | | @brief Stateless parser class for XMP packets. Images use this |
254 | | class to parse and serialize XMP packets. The parser uses |
255 | | the XMP toolkit to do the job. |
256 | | */ |
257 | | class EXIV2API XmpParser { |
258 | | public: |
259 | | //! Options to control the format of the serialized XMP packet. |
260 | | enum XmpFormatFlags { |
261 | | omitPacketWrapper = 0x0010UL, //!< Omit the XML packet wrapper. |
262 | | readOnlyPacket = 0x0020UL, //!< Default is a writeable packet. |
263 | | useCompactFormat = 0x0040UL, //!< Use a compact form of RDF. |
264 | | includeThumbnailPad = 0x0100UL, //!< Include a padding allowance for a thumbnail image. |
265 | | exactPacketLength = 0x0200UL, //!< The padding parameter is the overall packet length. |
266 | | writeAliasComments = 0x0400UL, //!< Show aliases as XML comments. |
267 | | omitAllFormatting = 0x0800UL //!< Omit all formatting whitespace. |
268 | | }; |
269 | | /*! |
270 | | @brief Decode XMP metadata from an XMP packet \em xmpPacket into |
271 | | \em xmpData. The format of the XMP packet must follow the |
272 | | XMP specification. This method clears any previous contents |
273 | | of \em xmpData. |
274 | | |
275 | | @param xmpData Container for the decoded XMP properties |
276 | | @param xmpPacket The raw XMP packet to decode |
277 | | @return 0 if successful;<BR> |
278 | | 1 if XMP support has not been compiled-in;<BR> |
279 | | 2 if the XMP toolkit failed to initialize;<BR> |
280 | | 3 if the XMP toolkit failed and raised an XMP_Error |
281 | | */ |
282 | | static int decode(XmpData& xmpData, const std::string& xmpPacket); |
283 | | /*! |
284 | | @brief Encode (serialize) XMP metadata from \em xmpData into a |
285 | | string xmpPacket. The XMP packet returned in the string |
286 | | follows the XMP specification. This method only modifies |
287 | | \em xmpPacket if the operations succeeds (return code 0). |
288 | | |
289 | | @param xmpPacket Reference to a string to hold the encoded XMP |
290 | | packet. |
291 | | @param xmpData XMP properties to encode. |
292 | | @param formatFlags Flags that control the format of the XMP packet, |
293 | | see enum XmpFormatFlags. |
294 | | @param padding Padding length. |
295 | | @return 0 if successful;<BR> |
296 | | 1 if XMP support has not been compiled-in;<BR> |
297 | | 2 if the XMP toolkit failed to initialize;<BR> |
298 | | 3 if the XMP toolkit failed and raised an XMP_Error |
299 | | */ |
300 | | static int encode(std::string& xmpPacket, const XmpData& xmpData, uint16_t formatFlags = useCompactFormat, |
301 | | uint32_t padding = 0); |
302 | | |
303 | | /*! |
304 | | @deprecated This function is no longer needed and does absolutely nothing. |
305 | | XMP Toolkit initialization is handled automatically. |
306 | | Arguments are ignored. |
307 | | |
308 | | @return Always returns true. |
309 | | */ |
310 | | [[deprecated( |
311 | | "XmpParser::initialize is deprecated and does nothing. The XMP Toolkit is initialized " |
312 | | "automatically.")]] static bool |
313 | | initialize(void (*)(void*, bool) = nullptr, void* = nullptr); |
314 | | |
315 | | /*! |
316 | | @deprecated This function is no longer needed and does absolutely nothing. |
317 | | XMP Toolkit termination is handled automatically. |
318 | | */ |
319 | | [[deprecated( |
320 | | "XmpParser::terminate is deprecated and does nothing. The XMP Toolkit termination is handled " |
321 | | "automatically.")]] static void |
322 | | terminate(); |
323 | | /*! |
324 | | @brief Clear all custom namespaces registered with the XMP Toolkit. |
325 | | This is useful for resetting the registry state in tests. |
326 | | */ |
327 | | static void clearCustomNamespaces(); |
328 | | |
329 | | private: |
330 | | /*! |
331 | | @brief Register a namespace with the XMP Toolkit. |
332 | | */ |
333 | | static void registerNs(const std::string& ns, const std::string& prefix); |
334 | | /*! |
335 | | @brief Delete a namespace from the XMP Toolkit. |
336 | | |
337 | | XmpProperties::unregisterNs calls this to synchronize namespaces. |
338 | | */ |
339 | | static void unregisterNs(const std::string& ns); |
340 | | |
341 | | /*! |
342 | | @brief Register a namespace with the XMP Toolkit without locking. |
343 | | Assumes the lock obtained via XmpProperties::XmpLock is already held by caller. |
344 | | */ |
345 | | static void registerNsImpl(const std::string& ns, const std::string& prefix); |
346 | | |
347 | | static void registeredNamespacesUnlocked(Exiv2::Dictionary&, const XmpProperties::XmpLock&); |
348 | | |
349 | | /*! |
350 | | @brief Get namespaces registered with XMPsdk |
351 | | */ |
352 | | static void registeredNamespaces(Exiv2::Dictionary&); |
353 | | |
354 | | friend class XmpProperties; // permit XmpProperties -> registerNs() and registeredNamespaces() |
355 | | |
356 | | static std::unique_ptr<XmpKey> makeXmpKey(const std::string& schemaNs, const std::string& propPath, |
357 | | const XmpProperties::XmpLock&); |
358 | | |
359 | | }; // class XmpParser |
360 | | |
361 | | // ***************************************************************************** |
362 | | // free functions, template and inline definitions |
363 | | |
364 | | #if __cpp_if_constexpr |
365 | | template <typename T> |
366 | 18.2k | Xmpdatum& Xmpdatum::operator=(const T& value) { |
367 | | if constexpr (std::is_same_v<T, bool>) |
368 | 0 | setValue(value ? "True" : "False"); |
369 | | else if constexpr (std::is_convertible_v<T, std::string>) |
370 | 7.72k | setValue(value); |
371 | | else if constexpr (std::is_base_of_v<Value, T>) |
372 | 0 | setValue(&value); |
373 | | else |
374 | 10.5k | setValue(Exiv2::toString(value)); |
375 | 18.2k | return *this; |
376 | 18.2k | } Unexecuted instantiation: Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<Exiv2::Value>(Exiv2::Value const&) Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) Line | Count | Source | 366 | 7.13k | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | 7.13k | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | | setValue(Exiv2::toString(value)); | 375 | 7.13k | return *this; | 376 | 7.13k | } |
Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<double>(double const&) Line | Count | Source | 366 | 2.89k | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | 2.89k | setValue(Exiv2::toString(value)); | 375 | 2.89k | return *this; | 376 | 2.89k | } |
Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<unsigned long>(unsigned long const&) Line | Count | Source | 366 | 4.11k | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | 4.11k | setValue(Exiv2::toString(value)); | 375 | 4.11k | return *this; | 376 | 4.11k | } |
Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<unsigned int>(unsigned int const&) Line | Count | Source | 366 | 1.96k | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | 1.96k | setValue(Exiv2::toString(value)); | 375 | 1.96k | return *this; | 376 | 1.96k | } |
Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<unsigned char const*>(unsigned char const* const&) Line | Count | Source | 366 | 55 | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | 55 | setValue(Exiv2::toString(value)); | 375 | 55 | return *this; | 376 | 55 | } |
Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<char [4]>(char const (&) [4]) Line | Count | Source | 366 | 28 | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | 28 | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | | setValue(Exiv2::toString(value)); | 375 | 28 | return *this; | 376 | 28 | } |
Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<long>(long const&) Line | Count | Source | 366 | 22 | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | 22 | setValue(Exiv2::toString(value)); | 375 | 22 | return *this; | 376 | 22 | } |
Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<float>(float const&) Line | Count | Source | 366 | 1.43k | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | 1.43k | setValue(Exiv2::toString(value)); | 375 | 1.43k | return *this; | 376 | 1.43k | } |
Unexecuted instantiation: Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<char [18]>(char const (&) [18]) Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<unsigned short>(unsigned short const&) Line | Count | Source | 366 | 48 | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | 48 | setValue(Exiv2::toString(value)); | 375 | 48 | return *this; | 376 | 48 | } |
Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<short>(short const&) Line | Count | Source | 366 | 18 | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | 18 | setValue(Exiv2::toString(value)); | 375 | 18 | return *this; | 376 | 18 | } |
Unexecuted instantiation: Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<unsigned char*>(unsigned char* const&) Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<char const*>(char const* const&) Line | Count | Source | 366 | 563 | Xmpdatum& Xmpdatum::operator=(const T& value) { | 367 | | if constexpr (std::is_same_v<T, bool>) | 368 | | setValue(value ? "True" : "False"); | 369 | | else if constexpr (std::is_convertible_v<T, std::string>) | 370 | 563 | setValue(value); | 371 | | else if constexpr (std::is_base_of_v<Value, T>) | 372 | | setValue(&value); | 373 | | else | 374 | | setValue(Exiv2::toString(value)); | 375 | 563 | return *this; | 376 | 563 | } |
Unexecuted instantiation: Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<int>(int const&) Unexecuted instantiation: Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<char [12]>(char const (&) [12]) Unexecuted instantiation: Exiv2::Xmpdatum& Exiv2::Xmpdatum::operator=<bool>(bool const&) |
377 | | #else |
378 | | template <typename T> |
379 | | std::enable_if_t<std::is_convertible<T, std::string>::value> operatorHelper(Xmpdatum* xmp, const T& value) { |
380 | | xmp->setValue(value); |
381 | | } |
382 | | |
383 | | template <typename T> |
384 | | std::enable_if_t<std::is_base_of<Value, T>::value> operatorHelper(Xmpdatum* xmp, const T& value) { |
385 | | xmp->setValue(&value); |
386 | | } |
387 | | |
388 | | template <typename T> |
389 | | std::enable_if_t<std::is_same<T, bool>::value> operatorHelper(Xmpdatum* xmp, const T& value) { |
390 | | xmp->setValue(value ? "True" : "False"); |
391 | | } |
392 | | |
393 | | template <typename T> |
394 | | std::enable_if_t<!(std::is_convertible<T, std::string>::value || std::is_base_of<Value, T>::value || |
395 | | std::is_same<T, bool>::value)> |
396 | | operatorHelper(Xmpdatum* xmp, const T& value) { |
397 | | xmp->setValue(Exiv2::toString(value)); |
398 | | } |
399 | | |
400 | | template <typename T> |
401 | | Xmpdatum& Xmpdatum::operator=(const T& value) { |
402 | | operatorHelper(this, value); |
403 | | return *this; |
404 | | } |
405 | | #endif |
406 | | } // namespace Exiv2 |
407 | | |
408 | | #endif // EXIV2_XMP_EXIV2_HPP |