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