Coverage Report

Created: 2026-05-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/exiv2/include/exiv2/properties.hpp
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
3
#ifndef EXIV2_PROPERTIES_HPP
4
#define EXIV2_PROPERTIES_HPP
5
6
// *****************************************************************************
7
#include "exiv2lib_export.h"
8
9
// included header files
10
#include "datasets.hpp"
11
12
#include <mutex>
13
14
// *****************************************************************************
15
// namespace extensions
16
namespace Exiv2 {
17
// *****************************************************************************
18
// class declarations
19
class XmpKey;
20
21
// *****************************************************************************
22
// class definitions
23
24
//! Category of an XMP property
25
enum XmpCategory { xmpInternal, xmpExternal };
26
27
//! Information about one XMP property.
28
struct EXIV2API XmpPropertyInfo {
29
  //! Comparison operator for name
30
  bool operator==(const std::string& name) const;
31
32
  const char* name_;          //!< Property name
33
  const char* title_;         //!< Property title or label
34
  const char* xmpValueType_;  //!< XMP value type (for info only)
35
  TypeId typeId_;             //!< Exiv2 default type for the property
36
  XmpCategory xmpCategory_;   //!< Category (internal or external)
37
  const char* desc_;          //!< Property description
38
};
39
40
//! Structure mapping XMP namespaces and (preferred) prefixes.
41
struct EXIV2API XmpNsInfo {
42
  //! For comparison with prefix
43
  struct Prefix {
44
    //! The prefix string.
45
    std::string prefix_;
46
  };
47
  //! For comparison with namespace
48
  struct Ns {
49
    //! The namespace string
50
    std::string ns_;
51
  };
52
  //! Comparison operator for namespace
53
  bool operator==(const Ns& ns) const;
54
  //! Comparison operator for prefix
55
  bool operator==(const Prefix& prefix) const;
56
57
  const char* ns_;                          //!< Namespace
58
  const char* prefix_;                      //!< (Preferred) prefix
59
  const XmpPropertyInfo* xmpPropertyInfo_;  //!< List of known properties
60
  const char* desc_;                        //!< Brief description of the namespace
61
};
62
63
//! XMP property reference, implemented as a static class.
64
class EXIV2API XmpProperties {
65
  /*!
66
    @brief Lock to be used interacting with xmp toolkit.
67
   */
68
  struct EXIV2API XmpLock {
69
   private:
70
    friend class XmpProperties;
71
    friend class XmpData;
72
    friend class XmpKey;
73
    friend class XmpParser;
74
    friend class Xmpdatum;
75
76
2.29M
    XmpLock() : lock_(getMutex()) {
77
2.29M
    }
78
    std::scoped_lock<std::mutex> lock_;
79
  };
80
81
 private:
82
  /*!
83
    @brief Key used to authorize access to no-lock methods during static destruction.
84
           Only XmpToolkitLifetimeManager can create this key.
85
   */
86
  struct LifetimeKey {
87
   private:
88
    friend class XmpProperties;
89
    friend class XmpToolkitLifetimeManager;
90
    LifetimeKey() = default;
91
  };
92
93
  friend class XmpToolkitLifetimeManager;
94
  static const XmpNsInfo* lookupNsRegistryUnlocked(const XmpNsInfo::Prefix& prefix, const XmpLock&);
95
  static void unregisterNsUnlocked(const std::string& ns, const XmpLock&);
96
  // Internal versions that do NOT check for lock (only for use by XmpToolkitLifetimeManager or internal helpers)
97
  static void unregisterNsNoLock(const std::string& ns, LifetimeKey);
98
  static void unregisterAllNsNoLock(LifetimeKey);
99
100
  // Unlocked versions of public methods (Caller MUST hold the lock obtained via XmpProperties::XmpLock)
101
  static std::string nsUnlocked(const std::string& prefix, const XmpLock&);
102
  static std::string prefixUnlocked(const std::string& ns, const XmpLock&);
103
  static void registerNsUnlocked(const std::string& ns, const std::string& prefix, const XmpLock&);
104
  static void unregisterNsUnlocked(const XmpLock&);
105
  static void registeredNamespacesUnlocked(Exiv2::Dictionary& nsDict, const XmpLock&);
106
107
  static const char* propertyTitleUnlocked(const XmpKey& key, const XmpLock&);
108
  static const char* propertyDescUnlocked(const XmpKey& key, const XmpLock&);
109
  static TypeId propertyTypeUnlocked(const XmpKey& key, const XmpLock&);
110
  static const XmpPropertyInfo* propertyInfoUnlocked(const XmpKey& key, const XmpLock&);
111
  static const char* nsDescUnlocked(const std::string& prefix, const XmpLock&);
112
  static const XmpPropertyInfo* propertyListUnlocked(const std::string& prefix, const XmpLock&);
113
  static const XmpNsInfo* nsInfoUnlocked(const std::string& prefix, const XmpLock&);
114
  static void printPropertiesUnlocked(std::ostream& os, const std::string& prefix, const XmpLock&);
115
  static std::ostream& printPropertyUnlocked(std::ostream& os, const std::string& key, const Value& value,
116
                                             const XmpLock&);
117
118
  friend class XmpParser;  // Allow XmpParser to call Unlocked methods while holding the lock
119
  friend class XmpKey;     // Allow XmpKey to call Unlocked methods for tagging
120
  friend class XmpData;
121
  friend class Xmpdatum;
122
  friend class XmpToolkitLifetimeManager;  // Allow access to unregisterNsUnlocked() during cleanup
123
124
 public:
125
  /*!
126
    @brief Return the title (label) of the property.
127
    @param key The property key
128
    @return The title (label) of the property, 0 if the
129
           key is of an unknown property.
130
   */
131
  static const char* propertyTitle(const XmpKey& key);
132
  /*!
133
    @brief Return the description of the property.
134
    @param key The property key
135
    @return The description of the property, 0 if the
136
           key is of an unknown property.
137
   */
138
  static const char* propertyDesc(const XmpKey& key);
139
  /*!
140
    @brief Return the type for property \em key. The default
141
           for unknown keys is xmpText.
142
    @param key The property key
143
    @return The type of the property
144
   */
145
  static TypeId propertyType(const XmpKey& key);
146
  /*!
147
    @brief Return information for the property for key.
148
149
    If the key is a path to a nested property (one which contains a slash,
150
    like \c Xmp.MP.RegionInfo/MPRI:Regions), determines the innermost element
151
    (\c Xmp.MPRI.Regions) and returns its property information.
152
153
    @param key The property key
154
    @return A pointer to the property information, 0 if the
155
           key is of an unknown property.
156
   */
157
  static const XmpPropertyInfo* propertyInfo(const XmpKey& key);
158
  /*!
159
     @brief Return the namespace name for the schema associated
160
            with \em prefix.
161
     @param prefix Prefix
162
     @return The namespace name
163
     @throw Error if no namespace is registered with \em prefix.
164
   */
165
  static std::string ns(const std::string& prefix);
166
  /*!
167
     @brief Return the namespace description for the schema associated
168
            with \em prefix.
169
     @param prefix Prefix
170
     @return The namespace description
171
     @throw Error if no namespace is registered with \em prefix.
172
   */
173
  static const char* nsDesc(const std::string& prefix);
174
  /*!
175
    @brief Return read-only list of built-in properties for \em prefix.
176
    @param prefix Prefix
177
    @return Pointer to the built-in properties for prefix, may be 0 if
178
            none is configured in the namespace info.
179
    @throw Error if no namespace is registered with \em prefix.
180
   */
181
  static const XmpPropertyInfo* propertyList(const std::string& prefix);
182
  /*!
183
    @brief Return information about a schema namespace for \em prefix.
184
           Always returns a valid pointer.
185
    @param prefix The prefix
186
    @return A pointer to the related information
187
    @throw Error if no namespace is registered with \em prefix.
188
   */
189
  static const XmpNsInfo* nsInfo(const std::string& prefix);
190
191
  /*!
192
     @brief Return the (preferred) prefix for schema namespace \em ns.
193
     @param ns Schema namespace
194
     @return The prefix or an empty string if namespace \em ns is not
195
            registered.
196
   */
197
  static std::string prefix(const std::string& ns);
198
  //! Print a list of properties of a schema namespace to output stream \em os.
199
  static void printProperties(std::ostream& os, const std::string& prefix);
200
201
  //! Interpret and print the value of an XMP property
202
  static std::ostream& printProperty(std::ostream& os, const std::string& key, const Value& value);
203
  /*!
204
    @brief Register namespace \em ns with preferred prefix \em prefix.
205
206
    If the prefix is a known or previously registered prefix, the
207
    corresponding namespace URI is overwritten.
208
209
    @note This invalidates XMP keys generated with the previous prefix.
210
   */
211
  static void registerNs(const std::string& ns, const std::string& prefix);
212
  /*!
213
    @brief Unregister a custom namespace \em ns.
214
215
    The function only has an effect if there is a namespace \em ns
216
    registered earlier, it does not unregister built-in namespaces.
217
218
    @note This invalidates XMP keys generated in this namespace.
219
   */
220
  static void unregisterNs(const std::string& ns);
221
222
  /*!
223
    @brief Get reference to the global XMP lock.
224
           Replaces direct mutex access for better Windows DLL support.
225
   */
226
  static std::mutex& getMutex();
227
228
  /*!
229
    @brief Unregister all custom namespaces.
230
231
    The function only unregisters namespaces registered earlier, it does not
232
    unregister built-in namespaces.
233
234
    @note This invalidates XMP keys generated in any custom namespace.
235
   */
236
  static void unregisterNs();
237
  //! Type for the namespace registry
238
  using NsRegistry = std::map<std::string, XmpNsInfo>;
239
  /*!
240
    @brief Get the registered namespace for a specific \em prefix from the registry.
241
   */
242
  static const XmpNsInfo* lookupNsRegistry(const XmpNsInfo::Prefix& prefix);
243
244
  // DATA
245
  static NsRegistry nsRegistry_;  //!< Namespace registry
246
247
  /*!
248
    @brief Get all registered namespaces (for both Exiv2 and XMPsdk)
249
   */
250
  static void registeredNamespaces(Exiv2::Dictionary& nsDict);
251
252
};  // class XmpProperties
253
254
/*!
255
  @brief Concrete keys for XMP metadata.
256
 */
257
class EXIV2API XmpKey : public Key {
258
 public:
259
  //! Shortcut for an %XmpKey auto pointer.
260
  using UniquePtr = std::unique_ptr<XmpKey>;
261
262
  //! @name Creators
263
  //@{
264
  /*!
265
    @brief Constructor to create an XMP key from a key string.
266
267
    @param key The key string.
268
    @throw Error if the first part of the key is not '<b>Xmp</b>' or
269
           the second part of the key cannot be parsed and converted
270
           to a known (i.e., built-in or registered) schema prefix.
271
  */
272
  explicit XmpKey(const std::string& key);
273
  /*!
274
    @brief Constructor to create an XMP key from a schema prefix
275
           and a property name.
276
277
    @param prefix   Schema prefix name
278
    @param property Property name
279
280
    @throw Error if the schema prefix is not known.
281
  */
282
  XmpKey(const std::string& prefix, const std::string& property);
283
  //! Copy constructor.
284
  XmpKey(const XmpKey& rhs);
285
  //! Virtual destructor.
286
  ~XmpKey() override;
287
  //@}
288
289
  //! @name Manipulators
290
  //@{
291
  //! Assignment operator.
292
  XmpKey& operator=(const XmpKey& rhs);
293
  //@}
294
295
  //! @name Accessors
296
  //@{
297
  [[nodiscard]] std::string key() const override;
298
  [[nodiscard]] const char* familyName() const override;
299
  /*!
300
    @brief Return the name of the group (the second part of the key).
301
           For XMP keys, the group name is the schema prefix name.
302
  */
303
  [[nodiscard]] std::string groupName() const override;
304
  [[nodiscard]] std::string tagName() const override;
305
  [[nodiscard]] std::string tagLabel() const override;
306
  [[nodiscard]] std::string tagDesc() const override;
307
  //! Properties don't have a tag number. Return 0.
308
  [[nodiscard]] uint16_t tag() const override;
309
310
  [[nodiscard]] UniquePtr clone() const;
311
312
  // Todo: Should this be removed? What about tagLabel then?
313
  //! Return the schema namespace for the prefix of the key
314
  [[nodiscard]] std::string ns() const;
315
  //@}
316
317
 private:
318
  //! Internal virtual copy constructor.
319
  [[nodiscard]] XmpKey* clone_() const override;
320
321
  // Pimpl idiom
322
  struct Impl;
323
  std::unique_ptr<Impl> p_;
324
325
  // Internal "unlocked" constructor (Caller MUST hold the lock obtained via XmpProperties::XmpLock)
326
  XmpKey(const std::string& prefix, const std::string& property, const XmpProperties::XmpLock&);
327
  XmpKey(const std::string& key, const XmpProperties::XmpLock&);
328
  friend class XmpParser;
329
  friend class XmpData;
330
  friend class Xmpdatum;
331
332
};  // class XmpKey
333
334
// *****************************************************************************
335
// free functions
336
337
//! Output operator for property info
338
EXIV2API std::ostream& operator<<(std::ostream& os, const XmpPropertyInfo& propertyInfo);
339
340
}  // namespace Exiv2
341
342
#endif  // EXIV2_PROPERTIES_HPP