1 #ifndef __TXMPUtils_hpp__
2 #define __TXMPUtils_hpp__ 1
3 
4 #if ( ! __XMP_hpp__ )
5     #error "Do not directly include, use XMP.hpp"
6 #endif
7 
8 // =================================================================================================
9 // ADOBE SYSTEMS INCORPORATED
10 // Copyright 2002-2008 Adobe Systems Incorporated
11 // All Rights Reserved
12 //
13 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
14 // of the Adobe license agreement accompanying it.
15 // =================================================================================================
16 
17 // =================================================================================================
18 /// \file TXMPUtils.hpp
19 /// \brief API for access to the XMP Toolkit utility services.
20 ///
21 /// \c TXMPUtils is the template class providing utility services for the XMP Toolkit. It must be
22 /// instantiated with a string class such as \c std::string. See the instructions in XMP.hpp, and
23 /// the Overview for a discussion of the overall architecture of the XMP API.
24 // =================================================================================================
25 
26 // =================================================================================================
27 /// \class TXMPUtils TXMPUtils.hpp
28 /// @brief API for access to the XMP Toolkit utility services.
29 ///
30 /// \c TXMPUtils is a template class which must be instantiated with a string class such as
31 /// \c std::string. See the instructions in XMP.hpp, and the Overview for a discussion of the overall
32 /// architecture of the XMP API.
33 ///
34 /// This class defines helper functions that support the basic metadata manipulation provided by
35 /// \c TXMPMeta. All of the functions are static; that is, you call them directly from the concrete
36 /// class (\c SXMPUtils), which is never itself instantiated.
37 ///
38 /// General categories of utilities include:
39 ///
40 ///   \li Composing complex path expressions, which you can then pass to the property access
41 ///   functions in \c TXMPMeta
42 ///   \li Converting between binary and string forms of property values
43 ///   \li Manipulating date/time values
44 ///   \li Encoding and decoding base-64 strings
45 ///   \li JPEG file handling
46 ///   \li Editing aids for creating a user interface for the XMP Toolkit
47 // =================================================================================================
48 
49 template <class tStringObj> class TXMPUtils {
50 
51 public:
52 
53     // =============================================================================================
54     // No constructors or destructor declared or needed
55     // ================================================
56 
57     //  ============================================================================================
58     /// \name Path composition
59     /// @{
60     ///
61     /// These functions provide support for composing path expressions to deeply nested properties.
62     /// The functions in \c TXMPMeta such as \c TXMPMeta::GetProperty(),
63     /// \c TXMPMeta::GetArrayItem(), and \c TXMPMeta::GetStructField() provide easy access to top level
64     /// simple properties, items in top level arrays, and fields of top level structs.	They are
65     /// not as convenient for more complex things, such as fields several levels deep in a complex
66     /// struct, or fields within an array of structs, or items of an array that is a field of a
67     /// struct. You can use these utility functions to compose these paths, which you can then pass
68     /// to the property access functions. You can also compose	paths to top-level array items or
69 	/// struct fields so that you can use the binary accessors such as
70 	/// \c TXMPMeta::GetProperty_Int().
71     ///
72     /// You can use these functions is to compose a complete path expression, or all but the last
73     /// component. For example, suppose you have a property that is an array of integers within a
74     /// struct. You can access one of the array items like this:
75     ///
76     /// <pre>
77     ///   SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &path );
78     ///   SXMPUtils::ComposeArrayItemPath ( schemaNS, path, index, &path );
79     ///   exists = xmpObj.GetProperty_Int ( schemaNS, path, &value, &options );
80     /// </pre>
81     ///
82     /// You could also use this code if you want the string form of the integer:
83     ///
84     /// <pre>
85     ///   SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &path );
86     ///   xmpObj.GetArrayItem ( schemaNS, path, index, &value, &options );
87     /// </pre>
88     ///
89     /// \note It might look confusing that the \c schemaNS is passed in all of the calls above. This
90     /// is because the XMP Toolkit keeps the top-level "schema" namespace separate from the rest of
91     /// the path expression.
92 
93     // ---------------------------------------------------------------------------------------------
94     /// @brief \c ComposeArrayItemPath() composes the path expression for an item in an array.
95     ///
96     /// The returned string is in the form <tt>ns:arrayName[i]</tt>, where "ns" is the prefix for
97     /// the specified namespace, and "i" is the decimal representation of specified item index.
98     /// If the last item was specified, the path is <tt>ns:arrayName[last()]</tt>.
99     ///
100     /// @param schemaNS The namespace URI for the array; see \c GetProperty().
101     ///
102     /// @param arrayName The name of the array. Can be a general path expression, must not be null
103     /// or the empty string; see \c GetProperty() for namespace prefix usage.
104     ///
105     /// @param itemIndex The 1-based index of the desired item. Use the macro
106     /// \c #kXMP_ArrayLastItem to specify the last existing array item.
107     ///
108     /// @param fullPath [out] A string in which to return the composed path.
109 
110     static void ComposeArrayItemPath ( XMP_StringPtr schemaNS,
111 									   XMP_StringPtr arrayName,
112 									   XMP_Index     itemIndex,
113 									   tStringObj *  fullPath );
114 
115     // ---------------------------------------------------------------------------------------------
116     /// @brief \c ComposeStructFieldPath() composes the path expression for a field in a struct.
117     ///
118     /// The returned string is in the form <tt>ns:structName/fNS:fieldName</tt>, where "ns" is the
119     /// prefix for the schema namespace, and "fNS" is the prefix for field namespace.
120     ///
121     /// @param schemaNS The namespace URI for the struct; see \c GetProperty().
122     ///
123     /// @param structName The name of the struct. Can be a general path expression, must not be null
124     /// or the empty string; see \c GetProperty() for namespace prefix usage.
125     ///
126     /// @param fieldNS The namespace URI for the field. Same URI and prefix usage as the
127     /// \c schemaNS and \c structName parameters.
128     ///
129     /// @param fieldName The name of the field. Must be a single XML name, must not be null or the
130     /// empty string. Same URI and prefix usage as the \c schemaNS and \c structName parameters.
131     ///
132     /// @param fullPath [out] A string in which to return the composed path.
133 
134     static void ComposeStructFieldPath ( XMP_StringPtr schemaNS,
135 										 XMP_StringPtr structName,
136 										 XMP_StringPtr fieldNS,
137 										 XMP_StringPtr fieldName,
138 										 tStringObj *  fullPath );
139 
140     // ---------------------------------------------------------------------------------------------
141     /// @brief \c ComposeQualifierPath() composes the path expression for a qualifier.
142     ///
143     /// The returned string is in the form <tt>ns:propName/?qNS:qualName</tt>, where "ns" is the
144     /// prefix for the schema namespace, and "qNS" is the prefix for the qualifier namespace.
145     ///
146     /// @param schemaNS The namespace URI; see \c GetProperty().
147     ///
148     /// @param propName The name of the property to which the qualifier is attached. Can be a
149     /// general path expression, must not be null or the empty string; see \c GetProperty() for
150     /// namespace prefix usage.
151     ///
152     /// @param qualNS The namespace URI for the qualifier. Same URI and prefix usage as the
153     /// \c schemaNS and \c propName parameters.
154     ///
155     /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or the
156     /// empty string. Same URI and prefix usage as the \c schemaNS and \c propName parameters.
157     ///
158     /// @param fullPath [out] A string in which to return the composed path.
159 
160     static void ComposeQualifierPath ( XMP_StringPtr schemaNS,
161 									   XMP_StringPtr propName,
162 									   XMP_StringPtr qualNS,
163 									   XMP_StringPtr qualName,
164 									   tStringObj *  fullPath );
165 
166     // ---------------------------------------------------------------------------------------------
167     /// @brief \c ComposeLangSelector() composes the path expression to select an alternate item by language.
168     ///
169     /// Path syntax allows two forms of "content addressing" to select an item in an array of
170     /// alternatives. The form used in this function lets you select an item in an alt-text array
171     /// based on the value of its \c xml:lang qualifier. The other form of content addressing is
172     /// shown in \c ComposeFieldSelector().
173     ///
174     /// The returned string is in the form <tt>ns:arrayName[\@xml:lang='langName']</tt>, where
175     /// "ns" is the prefix for the schema namespace
176     ///
177     /// This function provides a path expression that is explicitly and only for a specific
178     /// language. In most cases, \c TXMPMeta::SetLocalizedText() and \c TXMPMeta::GetLocalizedText()
179     /// are preferred, because they provide extra logic to choose the appropriate language and
180     /// maintain consistency with the 'x-default' value.
181     ///
182     /// @param schemaNS The namespace URI for the array; see \c GetProperty().
183     ///
184     /// @param arrayName The name of the array. Can be a general path expression, must not be null
185     /// or the empty string; see \c GetProperty() for namespace prefix usage.
186     ///
187     /// @param langName The RFC 3066 code for the desired language, as a null-terminated UTF-8 string.
188     ///
189     /// @param fullPath [out] A string in which to return the composed path.
190 
191     static void ComposeLangSelector ( XMP_StringPtr schemaNS,
192 									  XMP_StringPtr arrayName,
193 									  XMP_StringPtr langName,
194 									  tStringObj *  fullPath );
195 
196     // ---------------------------------------------------------------------------------------------
197     /// @brief \c ComposeLangSelector() composes a path expression to select an alternate item by language.
198     ///
199     /// Path syntax allows two forms of "content addressing" to select an item in an array of
200     /// alternatives. The form used in this function lets you select an item in an alt-text array
201     /// based on the value of its \c xml:lang qualifier. The other form of content addressing is
202     /// shown in \c ComposeFieldSelector().
203     ///
204     /// The returned string is in the form <tt>ns:arrayName[\@xml:lang='langName']</tt>, where
205     /// "ns" is the prefix for the schema namespace
206     ///
207     /// This function provides a path expression that is explicitly and only for a specific
208     /// language. In most cases, \c TXMPMeta::SetLocalizedText() and \c TXMPMeta::GetLocalizedText()
209     /// are preferred, because they provide extra logic to choose the appropriate language and
210     /// maintain consistency with the 'x-default' value.
211     ///
212     /// @param schemaNS The namespace URI for the array; see \c GetProperty().
213     ///
214     /// @param arrayName The name of the array. Can be a general path expression, must not be null
215     /// or the empty string; see \c GetProperty() for namespace prefix usage.
216     ///
217     /// @param langName The RFC 3066 code for the desired language, as a string object.
218     ///
219     /// @param fullPath [out] A string in which to return the composed path.
220 
221     static void ComposeLangSelector ( XMP_StringPtr      schemaNS,
222 									  XMP_StringPtr      arrayName,
223 									  const tStringObj & langName,
224 									  tStringObj *       fullPath );
225 
226     // ---------------------------------------------------------------------------------------------
227     /// @brief \c ComposeFieldSelector() composes a path expression to select an alternate item by a field's value.
228     ///
229     /// Path syntax allows two forms of "content addressing" to select an item in an array of
230     /// alternatives. The form used in this function lets you select an item in an array of structs
231     /// based on the value of one of the fields in the structs. The other form of content addressing
232     /// is shown in \c ComposeLangSelector().
233     ///
234     /// For example, consider a simple struct that has two fields, the name of a city and the URI of
235     /// an FTP site in that city. Use this to create an array of download alternatives. You can show
236     /// the user a popup built from the values of the city fields, then get the corresponding URI as
237     /// follows:
238     /// <pre>
239     ///   ComposeFieldSelector ( schemaNS, "Downloads", fieldNS, "City", chosenCity, &path );
240     ///   exists = GetStructField ( schemaNS, path, fieldNS, "URI", &uri );
241     /// </pre>
242     ///
243     /// The returned string is in the form <tt>ns:arrayName[fNS:fieldName='fieldValue']</tt>, where
244     /// "ns" is the prefix for the schema namespace and "fNS" is the prefix for the field namespace.
245     ///
246     /// @param schemaNS The namespace URI for the array; see \c GetProperty().
247     ///
248     /// @param arrayName The name of the array. Can be a general path expression, must not be null
249     /// or the empty string; see \c GetProperty() for namespace prefix usage.
250     ///
251     /// @param fieldNS The namespace URI for the field used as the selector. Same URI and prefix
252     /// usage as the \c schemaNS and \c arrayName parameters.
253     ///
254     /// @param fieldName The name of the field used as the selector. Must be a single XML name, must
255     /// not be null or the empty string. It must be the name of a field that is itself simple.
256     ///
257     /// @param fieldValue The desired value of the field, specified as a null-terminated UTF-8 string.
258     ///
259     /// @param fullPath [out] A string in which to return the composed path.
260 
261     static void ComposeFieldSelector ( XMP_StringPtr schemaNS,
262 									   XMP_StringPtr arrayName,
263 									   XMP_StringPtr fieldNS,
264 									   XMP_StringPtr fieldName,
265 									   XMP_StringPtr fieldValue,
266 									   tStringObj *  fullPath );
267 
268     // ---------------------------------------------------------------------------------------------
269     /// @brief \c ComposeFieldSelector() composes a path expression to select an alternate item by a field's value.
270     ///
271     /// Path syntax allows two forms of "content addressing" to select an item in an array of
272     /// alternatives. The form used in this function lets you select an item in an array of structs
273     /// based on the value of one of the fields in the structs. The other form of content addressing
274     /// is shown in \c ComposeLangSelector().
275     ///
276     /// For example, consider a simple struct that has two fields, the name of a city and the URI of
277     /// an FTP site in that city. Use this to create an array of download alternatives. You can show
278     /// the user a popup built from the values of the city fields, then get the corresponding URI as
279     /// follows:
280     /// <pre>
281     ///   ComposeFieldSelector ( schemaNS, "Downloads", fieldNS, "City", chosenCity, &path );
282     ///   exists = GetStructField ( schemaNS, path, fieldNS, "URI", &uri );
283     /// </pre>
284     ///
285     /// The returned string is in the form <tt>ns:arrayName[fNS:fieldName='fieldValue']</tt>, where
286     /// "ns" is the prefix for the schema namespace and "fNS" is the prefix for the field namespace.
287     ///
288     /// @param schemaNS The namespace URI for the array; see \c GetProperty().
289     ///
290     /// @param arrayName The name of the array. Can be a general path expression, must not be null
291     /// or the empty string; see \c GetProperty() for namespace prefix usage.
292     ///
293     /// @param fieldNS The namespace URI for the field used as the selector. Same URI and prefix
294     /// usage as the \c schemaNS and \c arrayName parameters.
295     ///
296     /// @param fieldName The name of the field used as the selector. Must be a single XML name, must
297     /// not be null or the empty string. It must be the name of a field that is itself simple.
298     ///
299     /// @param fieldValue The desired value of the field, specified as a string object.
300     ///
301     /// @param fullPath [out] A string in which to return the composed path.
302 
303     static void ComposeFieldSelector ( XMP_StringPtr      schemaNS,
304 									   XMP_StringPtr      arrayName,
305 									   XMP_StringPtr      fieldNS,
306 									   XMP_StringPtr      fieldName,
307 									   const tStringObj & fieldValue,
308 									   tStringObj *       fullPath );
309 
310     /// @}
311 
312     // =============================================================================================
313     /// \name Conversion between binary types and strings
314     /// @{
315     ///
316 	///	The main accessors in \c TXMPMeta set and retrieve property values as strings. additional
317 	///	functions, such as \c TXMPMeta::SetPropertyInt(), set and retrieve property values as
318 	///	explicit binary data types. Use these functions to convert between binary and string
319 	///	values.
320 	///
321 	///	Strings can be specified as null-terminated UTF-8 (\c #XMP_StringPtr), or as string
322 	///	objects (\c tStringObj) of the type declared when instantiating the XMP classes; see
323 	///	\c XMP.hpp. Alternate forms of each conversion function allow either type of string.
324 
325     // ---------------------------------------------------------------------------------------------
326     /// @brief \c ConvertFromBool() converts a Boolean value to a string.
327     ///
328     /// The string values of Booleans are returned by the macros \c #kXMP_TrueStr and
329     /// \c #kXMP_FalseStr in \c XMP_Const.h.
330     ///
331     /// @param binValue The Boolean value to be converted.
332     ///
333     /// @param strValue [out] A buffer in which to return the string representation of the value.
334 
335     static void ConvertFromBool ( bool	       binValue,
336 								  tStringObj * strValue );
337 
338     // ---------------------------------------------------------------------------------------------
339     /// @brief \c ConvertFromInt() converts a 32-bit integer value to a string.
340     ///
341     /// @param binValue The integer value to be converted.
342     ///
343     /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d".
344     ///
345     /// @param strValue [out] A buffer in which to return the string representation of the value.
346 
347     static void ConvertFromInt ( long	       binValue,
348 								 XMP_StringPtr format,
349 								 tStringObj *  strValue );
350     // ---------------------------------------------------------------------------------------------
351     /// @brief \c ConvertFromInt64() converts a 64-bit integer value to a string.
352     ///
353     /// @param binValue The integer value to be converted.
354     ///
355     /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d".
356     ///
357     /// @param strValue [out] A buffer in which to return the string representation of the value.
358 
359     static void ConvertFromInt64 ( long long	 binValue,
360 								   XMP_StringPtr format,
361 								   tStringObj *  strValue );
362 
363     // ---------------------------------------------------------------------------------------------
364     /// @brief \c ConvertFromFloat() converts a floating-point value to a string.
365     ///
366     /// @param binValue The floating-point value to be converted.
367     ///
368     /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d".
369     ///
370     /// @param strValue [out] A buffer in which to return the string representation of the value.
371 
372     static void ConvertFromFloat ( double	     binValue,
373 								   XMP_StringPtr format,
374 								   tStringObj *	 strValue );
375 
376     // ---------------------------------------------------------------------------------------------
377     /// @brief \c ConvertFromDate() converts a date/time value to a string.
378     ///
379     /// Formats a date according to the ISO 8601 profile in http://www.w3.org/TR/NOTE-datetime:
380     /// <pre>
381     ///   YYYY
382     ///   YYYY-MM
383     ///   YYYY-MM-DD
384     ///   YYYY-MM-DDThh:mmTZD
385     ///   YYYY-MM-DDThh:mm:ssTZD
386     ///   YYYY-MM-DDThh:mm:ss.sTZD
387     /// </pre>
388     ///
389     ///  \c YYYY = four-digit year, formatted as "%.4d" <br>
390     ///  \c MM	 = two-digit month (01=January)	<br>
391     ///  \c DD	 = two-digit day of month (01 through 31) <br>
392     ///  \c hh	 = two digits of hour (00 through 23) <br>
393     ///  \c mm	 = two digits of minute (00 through 59)	<br>
394     ///  \c ss	 = two digits of second (00 through 59)	<br>
395     ///  \c s	 = one or more digits representing a decimal fraction of a second <br>
396     ///  \c TZD	 = time zone designator (Z or +hh:mm or -hh:mm)
397     ///
398     /// Time-only input is allowed where the year, month, and day are all zero. This is output as
399     /// "0000-00-00...".
400     ///
401     /// @note ISO 8601 does not allow years less than 1000 or greater than 9999. This API allows
402     /// any year, even negative ones.
403     ///
404     /// @param binValue The date/time value to be converted.
405     ///
406     /// @param strValue [out] A buffer in which to return the ISO 8601 string representation of the date/time.
407 
408     static void ConvertFromDate ( const XMP_DateTime & binValue,
409 								  tStringObj *	       strValue );
410 
411     // ---------------------------------------------------------------------------------------------
412     /// @brief \c ConvertToBool() converts a string to a Boolean value.
413     ///
414     /// The preferred strings are those returned by the macros \c #kXMP_TrueStr and \c #kXMP_FalseStr.
415     /// If these do not match, the function does a case insensitive comparison, then simply 't' or 'f',
416     /// and finally non-zero and zero integer representations.
417     ///
418     /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string.
419     ///
420     /// @return The appropriate C++ bool value for the string.
421 
422     static bool ConvertToBool ( XMP_StringPtr strValue );
423 
424     // ---------------------------------------------------------------------------------------------
425     /// @brief \c ConvertToBool() converts a string to a Boolean value.
426     ///
427     /// Overloads the basic form of the function, allowing you to pass a string object,
428 	/// rather than a <tt>const * char</tt>. It is otherwise identical; see details in the canonical form.
429     ///
430     /// @param strValue The string representation of the value, specified as a string object.
431     ///
432     /// @return The appropriate C++ bool value for the string.
433 
434     static bool ConvertToBool ( const tStringObj & strValue );
435 
436     // ---------------------------------------------------------------------------------------------
437     /// @brief \c ConvertToInt() converts a string to a 32-bit integer value.
438     ///
439     /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string.
440     ///
441     /// @return The 32-bit integer value.
442 
443     static long ConvertToInt ( XMP_StringPtr strValue );
444 
445     // ---------------------------------------------------------------------------------------------
446     /// @brief \c ConvertToInt() converts a string to a 32-bit integer value.
447     ///
448     /// Overloads the basic form of the function, allowing you to pass a string object,
449 	/// rather than a <tt>const * char</tt>. It is otherwise identical.
450 	///
451     /// @param strValue The string representation of the value, specified as a string object.
452     ///
453     /// @return The 32-bit integer value.
454 
455     static long ConvertToInt ( const tStringObj & strValue );
456 
457     // ---------------------------------------------------------------------------------------------
458     /// @brief \c ConvertToInt64() converts a string to a 64-bit integer value.
459     ///
460     /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string.
461     ///
462     /// @return The 64-bit integer value.
463 
464     static long long ConvertToInt64 ( XMP_StringPtr strValue );
465 
466     // ---------------------------------------------------------------------------------------------
467     /// @brief \c ConvertToInt64() converts a string to a 64-bit integer value.
468     ///
469     /// Overloads the basic form of the function, allowing you to pass a string object,
470 	/// rather than a <tt>const * char</tt>. It is otherwise identical.
471 	///
472     /// @param strValue The string representation of the value, specified as a string object.
473     ///
474     /// @return The 64-bit integer value.
475 
476     static long long ConvertToInt64 ( const tStringObj & strValue );
477 
478     // ---------------------------------------------------------------------------------------------
479     /// @brief \c ConvertToFloat() converts a string to a floating-point value.
480     ///
481     /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string.
482     ///
483     /// @return The floating-point value.
484 
485     static double ConvertToFloat ( XMP_StringPtr strValue );
486 
487     // ---------------------------------------------------------------------------------------------
488     /// @brief \c ConvertToFloat() converts a string to a floating-point value.
489     ///
490     /// Overloads the basic form of the function, allowing you to pass a string object,
491 	/// rather than a <tt>const * char</tt>. It is otherwise identical.
492 	///
493     /// @param strValue The string representation of the value, specified as a string object.
494     ///
495     /// @return The floating-point value.
496 
497     static double ConvertToFloat ( const tStringObj & strValue );
498 
499     // ---------------------------------------------------------------------------------------------
500     /// @brief \c ConvertToDate() converts a string to a date/time value.
501     ///
502     /// Parses a date according to the ISO 8601 profile in http://www.w3.org/TR/NOTE-datetime:
503     /// <pre>
504     ///   YYYY
505     ///   YYYY-MM
506     ///   YYYY-MM-DD
507     ///   YYYY-MM-DDThh:mmTZD
508     ///   YYYY-MM-DDThh:mm:ssTZD
509     ///   YYYY-MM-DDThh:mm:ss.sTZD
510     /// </pre>
511     ///
512     ///  \c YYYY = four-digit year, formatted as "%.4d" <br>
513     ///  \c MM	 = two-digit month (01=January)	<br>
514     ///  \c DD	 = two-digit day of month (01 through 31) <br>
515     ///  \c hh	 = two digits of hour (00 through 23) <br>
516     ///  \c mm	 = two digits of minute (00 through 59)	<br>
517     ///  \c ss	 = two digits of second (00 through 59)	<br>
518     ///  \c s	 = one or more digits representing a decimal fraction of a second <br>
519     ///  \c TZD	 = time zone designator (Z or +hh:mm or -hh:mm)
520     ///
521     /// A missing date portion or missing TZD are tolerated. A missing date value can begin with
522     /// "Thh:" or "hh:"; the year, month, and day are all set to zero in the \c #XMP_DateTime value.
523     /// A missing TZD is assumed to be UTC.
524     ///
525     /// @note ISO 8601 does not allow years less than 1000 or greater than 9999. This API allows
526     /// any year, even negative ones.
527     ///
528     /// @param strValue The ISO 8601 string representation of the date/time, specified as a
529     /// null-terminated UTF-8 string.
530     ///
531     /// @param binValue [out] A buffer in which to return the binary date/time value.
532 
533     static void ConvertToDate ( XMP_StringPtr  strValue,
534 								XMP_DateTime * binValue );
535 
536     // ---------------------------------------------------------------------------------------------
537     /// @brief \c ConvertToDate() converts a string to a date/time value.
538     ///
539     /// Overloads the basic form of the function, allowing you to pass a string object,
540 	/// rather than a <tt>const * char</tt>. It is otherwise identical.
541 	/// See details for the canonical form.
542 	///
543     ///
544     /// @param strValue The ISO 8601 string representation of the date/time, specified as a string
545     /// object.
546     ///
547     /// @param binValue [out] A buffer in which to return the binary date/time value.
548 
549     static void ConvertToDate ( const tStringObj & strValue,
550 								XMP_DateTime *     binValue );
551 
552     /// @}
553 
554     // =============================================================================================
555     /// \name Date-time manipulation
556     /// @{
557     ///
558 	///	In addition to the type-conversion functions that convert between strings and binary
559 	///	date-time values, these functions create, manipulate, and compare date-time values.
560 
561     // ---------------------------------------------------------------------------------------------
562     /// @brief \c CurrentDateTime() obtains the current date and time.
563     ///
564     /// Creates and returns a binary \c #XMP_DateTime value. The returned time is UTC, properly
565     /// adjusted for the local time zone. The resolution of the time is not guaranteed to be finer
566     /// than seconds.
567     ///
568     /// @param time	[out] A buffer in which to return the date/time value.
569 
570     static void CurrentDateTime ( XMP_DateTime * time );
571 
572     // ---------------------------------------------------------------------------------------------
573     /// @brief \c SetTimeZone() sets the time zone in a date/time value to the local time zone.
574     ///
575     /// Any existing time zone value is replaced. The other date/time fields are not adjusted in any way.
576     ///
577     /// @param time	A pointer to the date-time value, which is modified in place.
578 
579     static void SetTimeZone ( XMP_DateTime * time );
580 
581     // ---------------------------------------------------------------------------------------------
582     /// @brief \c ConvertToUTCTime() ensures that a time is UTC.
583     ///
584     /// If the time zone is not UTC, the time is adjusted and the time zone set to be UTC. If the
585     /// time zone is already UTC, the value is not modified.
586     ///
587     /// @param time	A pointer to the date-time value, which is modified in place.
588 
589     static void ConvertToUTCTime ( XMP_DateTime * time );
590 
591     // ---------------------------------------------------------------------------------------------
592     /// @brief \c ConvertToLocalTime() ensures that a time is local.
593     ///
594     /// If the time zone is not the local zone, the time is adjusted and the time zone set to be local.
595     /// If the time zone is already the local zone, the value is not modified.
596     ///
597     /// @param time	A pointer to the date-time value, which is modified in place.
598 
599     static void ConvertToLocalTime ( XMP_DateTime * time );
600 
601     // ---------------------------------------------------------------------------------------------
602     /// @brief \c CompareDateTime() compares the order of two date/time values.
603     ///
604     /// @param left The left-side date/time value.
605     ///
606     /// @param right The right-side date/time value.
607     ///
608     /// @return An integer indicating the order:
609     ///   \li -1 if left is earlier than right
610     ///   \li 0 if left matches right
611     ///   \li +1 if left is later than right
612 
613     static int CompareDateTime ( const XMP_DateTime & left,
614 								 const XMP_DateTime & right );
615 
616     /// @}
617 
618     // =============================================================================================
619     /// \name Base64 encoding and decoding
620     /// @{
621     ///
622 	/// These functions convert between raw data values and Base64-encoded strings.
623 
624     // ---------------------------------------------------------------------------------------------
625     /// @brief \c EncodeToBase64() converts a raw data value to a Base64-encoded string.
626     ///
627     /// @param rawStr An \c #XMP_StringPtr (char *) string containing the raw data to be converted.
628     ///
629     /// @param rawLen The number of characters of raw data to be converted.
630     ///
631     /// @param encodedStr [out] A string object in which to return the encoded string.
632 
633     static void EncodeToBase64 ( XMP_StringPtr rawStr,
634 								 XMP_StringLen rawLen,
635 								 tStringObj *  encodedStr );
636 
637     // ---------------------------------------------------------------------------------------------
638     /// @brief \c EncodeToBase64() converts a raw data value passed in a string object to a Base64-encoded string.
639     ///
640     /// Overloads the basic form of the function, allowing you to pass a string object as input.
641 	/// It is otherwise identical.
642  	///
643     /// @param rawStr A string object containing the raw data to be converted.
644     ///
645     /// @param encodedStr [out] A string object in which to return the encoded string.
646 
647     static void  EncodeToBase64 ( const tStringObj & rawStr,
648 								  tStringObj *       encodedStr );
649 
650     // ---------------------------------------------------------------------------------------------
651     /// @brief \c  DecodeFromBase64() Decodes a Base64-encoded string to raw data.
652     ///
653     /// @param encodedStr An \c #XMP_StringPtr (char *) string containing the encoded data to be converted.
654     ///
655     /// @param encodedLen The number of characters of raw data to be converted.
656     ///
657     /// @param rawStr [out] A string object in which to return the decoded data.
658 
659     static void DecodeFromBase64 ( XMP_StringPtr encodedStr,
660 								   XMP_StringLen encodedLen,
661 								   tStringObj *  rawStr );
662 
663     // ---------------------------------------------------------------------------------------------
664     /// @brief \c  DecodeFromBase64() Decodes a Base64-encoded string, passed as a string object, to raw data.
665     ///
666     /// Overloads the basic form of the function, allowing you to pass a string object as input.
667 	/// It is otherwise identical.
668  	///
669     /// @param encodedStr An string object containing the encoded data to be converted.
670     ///
671     /// @param rawStr [out] A string object in which to return the decoded data.
672 
673     static void DecodeFromBase64 ( const tStringObj & encodedStr,
674 								   tStringObj *       rawStr );
675 
676     /// @}
677 
678     // =============================================================================================
679     // =============================================================================================
680     /// \name JPEG file handling
681     /// @{
682     ///
683     /// These functions support the partitioning of XMP in JPEG files into standard and extended
684     /// portions in order to work around the 64KB size limit of JPEG marker segments.
685     ///
686 	/// @note (Doc note) Add detail about how to write out and read back extended data
687 
688     // ---------------------------------------------------------------------------------------------
689     /// @brief \c PackageForJPEG() creates XMP serializations appropriate for a JPEG file.
690     ///
691     /// The standard XMP in a JPEG file is limited to 64K bytes. This function serializes the XMP
692     /// metadata in an XMP object into a string of RDF (see \c TXMPMeta::SerializeToBuffer()). If
693     /// the data does not fit into the 64K byte limit, it creates a second packet string with the
694     /// extended data.
695     ///
696     /// @param xmpObj The XMP object containing the metadata.
697     ///
698     /// @param standardXMP [out] A string object in which to return the full standard XMP packet.
699     ///
700     /// @param extendedXMP [out] A string object in which to return the serialized extended XMP,
701     /// empty if not needed.
702     ///
703     /// @param extendedDigest [out] A string object in which to return an MD5 digest of the serialized
704     /// extended XMP, empty if not needed.
705     ///
706     /// @see \c MergeFromJPEG()
707 
708     static void PackageForJPEG ( const TXMPMeta<tStringObj> & xmpObj,
709 								 tStringObj *                 standardXMP,
710 								 tStringObj *                 extendedXMP,
711 								 tStringObj *                 extendedDigest );
712 
713     // ---------------------------------------------------------------------------------------------
714     /// @brief \c MergeFromJPEG() merges standard and extended XMP retrieved from a JPEG file.
715     ///
716     /// When an extended partition stores properties that do not fit into the JPEG file limitation
717     /// of 64K bytes, this function integrates those properties back into the same XMP object with
718     /// those from the standard XMP packet.
719     ///
720     /// @param fullXMP [in, out] An XMP object which the caller has initialized from the standard
721     /// XMP packet in a JPEG file. The extended XMP is added to this object.
722     ///
723     /// @param extendedXMP An XMP object which the caller has initialized from the extended XMP
724     /// packet in a JPEG file.
725     ///
726     /// @see \c PackageForJPEG()
727 
728     static void MergeFromJPEG ( TXMPMeta<tStringObj> *       fullXMP,
729 								const TXMPMeta<tStringObj> & extendedXMP );
730 
731     /// @}
732 
733     // =============================================================================================
734     /// \name Editing utilities
735     /// @{
736     ///
737     /// These functions are useful in implementing a user interface for editing XMP. They
738 	/// convert sets of property values to and from displayable and manipulable strings, and perform
739 	/// operations on sets of metadata, such as those available from the File Info dialog box.
740 
741     // ---------------------------------------------------------------------------------------------
742     /// @brief \c CatenateArrayItems() creates a single edit string from a set of array item values.
743     ///
744     /// Collects the values of all items in an array into a single string, using a specified
745     /// separation string. Each item in the specified array must be a simple string value.
746     ///
747     /// @param xmpObj The XMP object containing the array to be catenated.
748     ///
749     /// @param schemaNS The schema namespace URI for the array. Must not be null or the empty string.
750     ///
751     /// @param arrayName The name of the array. May be a general path expression, must not be null
752     /// or the empty string.
753     ///
754     /// @param separator The string with which to separate the items in the catenated string.
755     /// Defaults to "; ", ASCII semicolon and space (U+003B, U+0020).
756     ///
757     /// @param quotes The character or characters to use as quotes around array items that contain a
758     /// separator. Defaults to the double-quote character ("), ASCII quote (U+0022).
759     ///
760     /// @param options Option flags to control the catenation. <<what options?>>
761     ///
762     /// @param catedStr [out] A string object in which to return the catenated array items.
763     ///
764     /// @see \c SeparateArrayItems()
765 
766     static void CatenateArrayItems ( const TXMPMeta<tStringObj> & xmpObj,
767 									 XMP_StringPtr                schemaNS,
768 									 XMP_StringPtr                arrayName,
769 									 XMP_StringPtr                separator,
770 									 XMP_StringPtr                quotes,
771 									 XMP_OptionBits               options,
772 									 tStringObj *                 catedStr );
773 
774     // ---------------------------------------------------------------------------------------------
775     /// @brief \c SeparateArrayItems() updates an array from a concatenated edit string of values.
776     ///
777     /// This reverses the action of \c CatenateArrayItems(), separating out individual array items
778     /// from the edit string and updating the array with the new values. Each item in the array must
779     /// be a simple string value.
780     ///
781     /// @param xmpObj The XMP object containing the array to be updated.
782     ///
783     /// @param schemaNS The schema namespace URI for the array. Must not be null or the empty string.
784     ///
785     /// @param arrayName The name of the array. May be a general path expression, must not be null
786     /// or the empty string.
787     ///
788     /// @param options Option flags to control the separation. <<what options?>>
789     ///
790     /// @param catedStr The concatenated array items, as created by \c CatenateArrayItems(),
791     /// specified as a null-terminated UTF-8 string.
792 
793     static void SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
794 									 XMP_StringPtr          schemaNS,
795 									 XMP_StringPtr          arrayName,
796 									 XMP_OptionBits         options,
797 									 XMP_StringPtr          catedStr );
798 
799     // ---------------------------------------------------------------------------------------------
800     /// @brief \c SeparateArrayItems() updates an array from a concatenated edit string of values.
801     ///
802     /// Overloads the basic form of the function, allowing you to pass a string object in which
803     ///	to return the concatenated string. It is otherwise identical; see details for the canonical form.
804  	///
805 
806     static void SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
807 									 XMP_StringPtr          schemaNS,
808 									 XMP_StringPtr          arrayName,
809 									 XMP_OptionBits         options,
810 									 const tStringObj &     catedStr );
811 
812     // ---------------------------------------------------------------------------------------------
813     /// @brief \c  RemoveProperties() removes multiple properties from an XMP object.
814     ///
815     /// The operation depends on how the namespace and property are specified:
816     ///
817     ///   \li Non-empty \c schemaNS and \c propName - The named property is removed if it is an
818     ///   external property, or if the \c #kXMPUtil_DoAllProperties option flag is set. It does not
819     ///   matter whether the named property is an actual property or an alias.
820     ///
821     ///   \li Non-empty \c schemaNS and empty \c propName - All external properties in the named
822     ///   schema are removed. Internal properties are also removed if the
823     ///   \c #kXMPUtil_DoAllProperties option flag is set. In addition, aliases from the named schema
824     ///   are removed if the \c #kXMPUtil_IncludeAliases option flag is set.
825     ///
826     ///   \li Empty \c schemaNS and empty \c propName - All external properties in all schemas are
827     ///   removed. Internal properties are also removed if the \c #kXMPUtil_DoAllProperties option
828     ///   flag is set. Aliases are handled implicitly, because the associated actuals are removed or
829     ///   not.
830     ///
831     ///   \li It is an error to pass an empty \c schemaNS and non-empty \c propName.
832     ///
833     /// @param xmpObj The XMP object containing the properties to be removed.
834     ///
835     /// @param schemaNS Optional schema namespace URI for the properties to be removed.
836     ///
837     /// @param propName Optional path expression for the property to be removed.
838     ///
839     /// @param options Option flags to control the deletion operation. A logical OR of these
840     /// bit-flag constants:
841     ///   \li \c #kXMPUtil_DoAllProperties - Delete internal properties in addition to external properties.
842     ///   \li \c #kXMPUtil_IncludeAliases - Include aliases if the schema is explicitly specified.
843 
844     static void RemoveProperties ( TXMPMeta<tStringObj> * xmpObj,
845 								   XMP_StringPtr          schemaNS = 0,
846 								   XMP_StringPtr          propName = 0,
847 								   XMP_OptionBits         options = 0 );
848 
849     // ---------------------------------------------------------------------------------------------
850     /// @brief \c AppendProperties() adds or moves properties from one XMP object to another.
851     ///
852     /// The default operation is to append only external properties that do not already exist in the
853     /// destination. Option flags allow you to	add internal properties, and to merge values of
854     /// properties that exist in both the source and destination.
855     ///
856     ///   \li \c #kXMPUtil_DoAllProperties: Operate on all top-level properties, external and
857     ///   internal. You can use this flag together with \c #kXMPUtil_ReplaceOldValues to replace the
858     ///   values of existing top-level properties.
859     ///
860     ///   \li \c #kXMPUtil_ReplaceOldValues: Propogate all top-level properties from the source to
861     ///   the destination, replacing any existing values. The values of properties in the
862     ///   destination that are not in the source are not modified.<br>
863     ///   The keep-or-replace-old notion also applies within structs and arrays. Top-level
864     ///   properties are added to the destination if they do not already exist. If they do exist but
865     ///   differ in form (simple/struct/array) then the destination is not modified. If the forms
866     ///   match, simple properties are left unchanged, while structs and arrays are merged.<br>
867     ///   Do not use this option when the processing is more complicated. <<than what??>>
868     ///
869     ///   \li \c #kXMPUtil_DeleteEmptyValues: An empty value in the source XMP causes the
870     ///   corresponding destination property to be deleted. By default, empty values are treated in
871     ///   the same way as non-empty values. An empty value is a simple empty string, an array with
872     ///   no items,or a struct with no fields. Qualifiers are ignored.
873     ///
874     /// The detailed behavior is defined by the following pseudo-code:
875     ///
876     /// <pre>
877     /// AppendProperties ( sourceXMP, destXMP, options ):
878     ///    doAll = options & kXMPUtil_DoAllProperties
879     ///    replaceOld = options & kXMPUtil_ReplaceOldValues
880     ///    deleteEmpty = options & kXMPUtil_DeleteEmptyValues
881     ///    for all source schema (top level namespaces):
882     ///    for all top level properties in sourceSchema:
883     ///    if doAll or prop is external:
884     ///       AppendSubtree ( sourceNode, destSchema, replaceOld, deleteEmpty )
885     ///
886     /// AppendSubtree ( sourceNode, destParent, replaceOld, deleteEmpty ):
887     ///    if deleteEmpty and source value is empty:
888     ///       delete the corresponding child from destParent
889     ///    else if sourceNode not in destParent (by name):
890     ///       copy sourceNode's subtree to destParent
891     ///    else if replaceOld:
892     ///       delete subtree from destParent
893     ///       copy sourceNode's subtree to destParent
894     ///    else: // (Already exists in dest and not replacing, merge structs and arrays)
895     ///       if sourceNode and destNode forms differ:
896     ///          return, leave the destNode alone
897     ///       else if form is a struct:
898     ///          for each field in sourceNode:
899     ///             AppendSubtree ( sourceNode.field, destNode, replaceOld )
900     ///       else if form is an alt-text array:
901     ///          copy new items by xml:lang value into the destination
902     ///       else if form is an array:
903     ///          copy new items by value into the destination, ignoring order and duplicates
904     /// </pre>
905     ///
906     /// Array item checking is n-squared; this can be time-intensive if the replace-old options is
907     /// not specified. Each source item is checked to see if it already exists in the destination,
908     /// without regard to order or duplicates. Simple items are compared by value and \c xml:lang
909     /// qualifier; other qualifiers are ignored. Structs are recursively compared by field names,
910     /// without regard to field order. Arrays are compared by recursively comparing all items.
911     ///
912     /// @param source The source XMP object.
913     ///
914     /// @param dest The destination XMP object.
915     ///
916     /// @param options Option flags to control the copying.	A logical OR of these bit-flag constants:
917     ///   \li \c kXMPUtil_DoAllProperties - Operate on internal properties in addition to external properties.
918     ///   \li \c kXMPUtil_ReplaceOldValues - Replace the values of existing properties.
919     ///   \li \c kXMPUtil_DeleteEmptyValues - Delete properties if the new value is empty.
920 
921     static void AppendProperties ( const TXMPMeta<tStringObj> & source,
922 								   TXMPMeta<tStringObj> *       dest,
923 								   XMP_OptionBits               options = 0 );
924 
925     // ---------------------------------------------------------------------------------------------
926     /// @brief \c DuplicateSubtree() replicates a subtree from one XMP object into another.
927     ///
928     /// The destination can be a different namespace and root location in the same object, or the
929     /// same or a different location in another XMP object.
930     ///
931     /// @param source The source XMP object.
932     ///
933     /// @param dest The destination XMP object.
934     ///
935     /// @param sourceNS The schema namespace URI for the source subtree.
936     ///
937     /// @param sourceRoot The root location for the source subtree. Can be a general path expression,
938     /// must not be null or the empty string.
939     ///
940     /// @param destNS The schema namespace URI for the destination. Defaults to the source namespace.
941     ///
942     /// @param destRoot The root location for the destination. Can be a general path expression.
943     /// Defaults to the source location.
944     ///
945     /// @param options Option flags to control the operation. <<options?>>
946 
947     static void DuplicateSubtree ( const TXMPMeta<tStringObj> & source,
948 								   TXMPMeta<tStringObj> *       dest,
949 								   XMP_StringPtr                sourceNS,
950 								   XMP_StringPtr                sourceRoot,
951 								   XMP_StringPtr                destNS = 0,
952 								   XMP_StringPtr                destRoot = 0,
953 								   XMP_OptionBits               options = 0 );
954 
955     /// @}
956 
957     // =============================================================================================
958 
959     // =============================================================================================
960 
961 };  // class TXMPUtils
962 
963 // =================================================================================================
964 
965 #endif // __TXMPUtils_hpp__
966