/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 |