1 #ifndef __TXMPFiles_hpp__
2 #define __TXMPFiles_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 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 TXMPFiles.hpp
19 /// \brief API for access to the main (document-level) metadata in a file_.
20 ///
21 /// The Adobe XMP Toolkit's file handling component, XMPFiles, is a front end to a set of
22 /// format-specific file handlers that support file I/O for XMP. The file handlers implement smart,
23 /// efficient support for those file formats for which the means to embed XMP is defined in the XMP
24 /// Specification. Where possible, this support allows:
25 ///   \li Injection    of XMP where none currently exists
26 ///   \li Expansion of XMP without regard to existing padding
27 ///   \li Reconciliation of the XMP and other legacy forms of metadata.
28 ///
29 /// \c TXMPFiles is designed for use by clients interested in the metadata and not in the primary
30 /// file content; the Adobe Bridge application is a typical example. \c TXMPFiles is not intended to
31 /// be appropriate for files authored by an application; that is, those files for which the
32 /// application has explicit knowledge of the file format.
33 // =================================================================================================
34 
35 
36 // =================================================================================================
37 /// \class TXMPFiles TXMPFiles.hpp
38 /// \brief API for access to the main (document-level) metadata in a file.
39 ///
40 /// \c TXMPFiles is a template class that provides the API for the Adobe XMP Toolkit's XMPFiles
41 /// component. This provides convenient access to the main, or document level, XMP for a file. Use
42 /// it to obtain metadata from a file, which you can then manipulate with the XMP Core component
43 /// (the classes \c TXMPMeta, \c TXMPUtils, and \c TXMPIterator); and to write new or changed
44 /// metadata back out to a file.
45 ///
46 /// The functions allow you to open a file, read and write the metadata, then close the file.
47 /// While open, portions of the file might be maintained in RAM data structures. Memory
48 /// usage can vary considerably depending onfile format and access options.
49 ///
50 /// A file can be opened for read-only or read-write access, with typical exclusion for both
51 /// modes. Errors result in the throw of an \c XMPError exception.
52 ///
53 /// \c TXMPFiles is the template class. It must be instantiated with a string class such as
54 /// \c std::string. Read the Toolkit Overview for information about the overall architecture of the XMP
55 /// API, and the documentation for \c XMP.hpp for specific instantiation instructions.
56 ///
57 /// Access these functions through the concrete class, \c SXMPFiles.
58 // =================================================================================================
59 
60 
61 #if XMP_StaticBuild    // ! Client XMP_IO objects can only be used in static builds.
62     #include "XMP_IO.hpp"
63 #endif
64 
65 
66 template <class tStringObj>
67 class TXMPFiles {
68 
69 public:
70 
71     // =============================================================================================
72     /// \name Initialization and termination
73     /// @{
74     ///
75     /// A \c TXMPFiles object must be initialized before use and can be terminated when done.
76 
77     // ---------------------------------------------------------------------------------------------
78     /// @brief \c GetVersionInfo() retrieves version information for the XMPFiles component.
79     ///
80     /// Can be called before \c #Initialize(). This function is static; make the call directly from
81     /// the concrete class (\c SXMPFiles).
82     ///
83     /// @param versionInfo [out] A buffer in which to return the version information.
84 
85     static void GetVersionInfo ( XMP_VersionInfo * versionInfo );
86 
87     // ---------------------------------------------------------------------------------------------
88     /// @brief Initializes the XMPFiles library; must be called before creating an \c SXMPFiles object.
89     ///
90     /// The main action is to activate the available smart file handlers. Must be called before
91     /// using any methods except \c GetVersionInfo().
92     ///
93     /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
94     ///
95     /// @return True on success.
96 
97     static bool Initialize();
98 
99     // ---------------------------------------------------------------------------------------------
100     /// @brief Initializes the XMPFiles library; must be called before creating an \c SXMPFiles object.
101     ///
102     /// This overload of TXMPFiles::Initialize() accepts option bits to customize the initialization
103     /// actions. At this time no option is defined.
104     ///
105     /// The main action is to activate the available smart file handlers. Must be called before
106     /// using any methods except \c GetVersionInfo().
107     ///
108     /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
109     ///
110     /// @param options Option flags to control the initialization actions.
111     ///
112     /// @return True on success.
113 
114     static bool Initialize ( XMP_OptionBits options );
115 
116     // ---------------------------------------------------------------------------------------------
117     /// @brief Initializes the XMPFiles library; must be called before creating an \c SXMPFiles object.
118     ///
119     /// This overload of TXMPFiles::Initialize() accepts plugin directory and name of the plug-ins
120     /// as a comma separated list to load the file handler plug-ins. If plugins == NULL, then all
121     /// plug-ins present in the plug-in directory will be loaded.
122     ///
123     /// The main action is to activate the available smart file handlers. Must be called before
124     /// using any methods except \c GetVersionInfo().
125     ///
126     /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
127     ///
128     /// @param pluginFolder Pugin directorty to load the file handler plug-ins.
129     /// @param plugins Comma sepearted list of plug-ins which should be loaded from the plug-in directory.
130     /// If plugin == NULL, then all plug-ins availbale in the plug-in directory will be loaded.
131     ///
132     /// @return True on success.
133 
134     static bool Initialize ( const char* pluginFolder, const char* plugins = NULL );
135 
136     // ---------------------------------------------------------------------------------------------
137     /// @brief Initializes the XMPFiles library; must be called before creating an \c SXMPFiles object.
138     ///
139     /// This overload of TXMPFiles::Initialize( XMP_OptionBits options ) accepts plugin directory and
140     /// name of the plug-ins as a comma separated list to load the file handler plug-ins.
141     /// If plugins == NULL, then all plug-ins present in the plug-in directory will be loaded.
142     ///
143     /// The main action is to activate the available smart file handlers. Must be called before
144     /// using any methods except \c GetVersionInfo().
145     ///
146     /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
147     ///
148     /// @param options Option flags to control the initialization actions.
149     /// @param pluginFolder Pugin directorty to load the file handler plug-ins.
150     /// @param plugins Comma sepearted list of plug-ins which should be loaded from the plug-in directory.
151     /// If plugin == NULL, then all plug-ins availbale in the plug-in directory will be loaded.
152     ///
153     /// @return True on success.
154 
155     static bool Initialize ( XMP_OptionBits options, const char* pluginFolder, const char* plugins = NULL );
156 
157     // ---------------------------------------------------------------------------------------------
158     /// @brief Terminates use of the XMPFiles library.
159     ///
160     /// Optional. Deallocates global data structures created by intialization. Its main action is to
161     /// deallocate heap-allocated global storage, for the benefit of client leak checkers.
162     ///
163     /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
164 
165     static void Terminate();
166 
167     /// @}
168 
169     // =============================================================================================
170     /// \name Constructors and destructor
171     /// @{
172     ///
173     /// The default constructor initializes an object that is associated with no file. The alternate
174     /// constructors call \c OpenFile().
175 
176     // ---------------------------------------------------------------------------------------------
177     /// @brief Default constructor initializes an object that is associated with no file.
178 
179     TXMPFiles();
180 
181     // ---------------------------------------------------------------------------------------------
182     /// @brief Destructor; typical virtual destructor.
183     ///
184     /// The destructor does not call \c CloseFile(); pending updates are lost when the destructor is run.
185     ///
186     /// @see \c OpenFile(), \c CloseFile()
187 
188     virtual ~TXMPFiles() throw();
189 
190     // ---------------------------------------------------------------------------------------------
191     /// @brief Alternate constructor associates the new \c XMPFiles object with a specific file.
192     ///
193     /// Calls \c OpenFile() to open the specified file after performing a default construct.
194     ///
195     /// @param filePath    The path for the file, specified as a nul-terminated UTF-8 string.
196     ///
197     /// @param format A format hint for the file, if known.
198     ///
199     /// @param openFlags Options for how the file is to be opened (for read or read/write, for
200     /// example). Use a logical OR of these bit-flag constants:
201     ///
202     ///   \li \c #kXMPFiles_OpenForRead
203     ///   \li \c #kXMPFiles_OpenForUpdate
204     ///   \li \c #kXMPFiles_OpenOnlyXMP
205     ///   \li \c #kXMPFiles_OpenStrictly
206     ///   \li \c #kXMPFiles_OpenUseSmartHandler
207     ///   \li \c #kXMPFiles_OpenUsePacketScanning
208     ///   \li \c #kXMPFiles_OpenLimitedScanning
209     ///
210     /// @return The new \c TXMPFiles object.
211 
212     TXMPFiles ( XMP_StringPtr  filePath,
213                 XMP_FileFormat format = kXMP_UnknownFile,
214                 XMP_OptionBits openFlags = 0 );
215 
216     // ---------------------------------------------------------------------------------------------
217     /// @brief Alternate constructor associates the new \c XMPFiles object with a specific file,
218     /// using a string object.
219     ///
220     /// Overloads the basic form of the function, allowing you to pass a string object
221     /// for the file path. It is otherwise identical; see details in the canonical form.
222 
223     TXMPFiles ( const tStringObj & filePath,
224                 XMP_FileFormat     format = kXMP_UnknownFile,
225                 XMP_OptionBits     openFlags = 0 );
226 
227     // ---------------------------------------------------------------------------------------------
228     /// @brief Copy constructor
229     ///
230     /// Increments an internal reference count but does not perform a deep copy.
231     ///
232     /// @param original The existing \c TXMPFiles object to copy.
233     ///
234     /// @return The new \c TXMPFiles object.
235 
236     TXMPFiles ( const TXMPFiles<tStringObj> & original );
237 
238     // ---------------------------------------------------------------------------------------------
239     /// @brief Assignment operator
240     ///
241     /// Increments an internal reference count but does not perform a deep copy.
242     ///
243     /// @param rhs The existing \c TXMPFiles object.
244 
245     void operator= ( const TXMPFiles<tStringObj> & rhs );
246 
247     // ---------------------------------------------------------------------------------------------
248     /// @brief Reconstructs a \c TXMPFiles object from an internal reference.
249     ///
250     /// This constructor creates a new \c TXMPFiles object that refers to the underlying reference
251     /// object of an existing \c TXMPFiles object. Use to safely pass \c SXMPFiles references across
252     /// DLL boundaries.
253     ///
254     /// @param xmpFilesObj The underlying reference object, obtained from some other XMP object
255     /// with \c TXMPFiles::GetInternalRef().
256     ///
257     /// @return The new object.
258 
259     TXMPFiles ( XMPFilesRef xmpFilesObj );
260 
261     // ---------------------------------------------------------------------------------------------
262     /// @brief GetInternalRef() retrieves an internal reference that can be safely passed across DLL
263     /// boundaries and reconstructed.
264     ///
265     /// Use with the reconstruction constructor to safely pass \c SXMPFiles references across DLL
266     /// boundaries where the clients might have used different string types when instantiating
267     /// \c TXMPFiles.
268     ///
269     /// @return The internal reference.
270     ///
271     /// @see \c TXMPMeta::GetInternalRef() for usage.
272 
273     XMPFilesRef GetInternalRef();
274 
275     /// @}
276 
277     // =============================================================================================
278     /// \name File handler information
279     /// @{
280     ///
281     /// Call this static function from the concrete class, \c SXMPFiles, to obtain information about
282     /// the file handlers for the XMPFiles component.
283 
284     // ---------------------------------------------------------------------------------------------
285     /// @brief  GetFormatInfo() reports what features are supported for a specific file format.
286     ///
287     /// The file handlers for different file formats vary considerably in what features they
288     /// support. Support depends on both the general capabilities of the format and the
289     /// implementation of the handler for that format.
290     ///
291     ///This function is static; make the call directly from the concrete class (\c SXMPFiles).
292     ///
293     /// @param format The file format whose support flags are desired.
294     ///
295     /// @param handlerFlags [out] A buffer in which to return a logical OR of option bit flags.
296     /// The following constants are defined:
297     ///
298     ///   \li \c #kXMPFiles_CanInjectXMP - Can inject first-time XMP into an existing file.
299     ///   \li \c #kXMPFiles_CanExpand - Can expand XMP or other metadata in an existing file.
300     ///   \li \c #kXMPFiles_CanRewrite - Can copy one file to another, writing new metadata (as in SaveAs)
301     ///   \li \c #kXMPFiles_CanReconcile - Supports reconciliation between XMP and other forms.
302     ///   \li \c #kXMPFiles_AllowsOnlyXMP - Allows access to just the XMP, ignoring other forms.
303     ///   This is only meaningful if \c #kXMPFiles_CanReconcile is set.
304     ///   \li \c #kXMPFiles_ReturnsRawPacket - File handler returns raw XMP packet information and string.
305     ///
306     /// Even if \c #kXMPFiles_ReturnsRawPacket is set, the returned packet information might have an
307     /// offset of -1 to indicate an unknown offset. While all file handlers should be able to return
308     /// the raw packet, some might not know the offset of the packet within the file. This is
309     /// typical in cases where external libraries are used. These cases might not even allow return
310     /// of the raw packet.
311     ///
312     /// @return True if the format has explicit "smart" support, false if the format is handled by
313     /// the default packet scanning plus heuristics. */
314 
315 
316     static bool GetFormatInfo ( XMP_FileFormat   format,
317                                 XMP_OptionBits * handlerFlags = 0 );
318 
319     /// @}
320 
321     // =============================================================================================
322     /// \name File operations
323     /// @{
324     ///
325     /// These functions allow you to open, close, and query files.
326 
327     // ---------------------------------------------------------------------------------------------
328     /// @brief \c CheckFileFormat() tries to determine the format of a file.
329     ///
330     /// Tries to determine the format of a file, returning an \c #XMP_FileFormat value. Uses the
331     /// same logic as \c OpenFile() to select a smart handler.
332     ///
333     /// @param filePath The path for the file, appropriate for the local operating system. Passed as
334     /// a nul-terminated UTF-8 string. The path is the same as would be passed to \c OpenFile.
335     ///
336     /// @return The file's format if a smart handler would be selected by \c OpenFile(), otherwise
337     /// \c #kXMP_UnknownFile.
338 
339     static XMP_FileFormat CheckFileFormat ( XMP_StringPtr filePath );
340 
341     // ---------------------------------------------------------------------------------------------
342     /// @brief \c CheckPackageFormat() tries to determine the format of a "package" folder.
343     ///
344     /// Tries to determine the format of a package, given the name of the top-level folder. Returns
345     /// an \c #XMP_FileFormat value. Examples of recognized packages include the video formats P2,
346     /// XDCAM, or Sony HDV. These packages contain collections of "clips", stored as multiple files
347     /// in specific subfolders.
348     ///
349     /// @param folderPath The path for the top-level folder, appropriate for the local operating
350     /// system. Passed as a nul-terminated UTF-8 string. This is not the same path you would pass to
351     /// \c OpenFile(). For example, the top-level path for a package might be ".../MyMovie", while
352     /// the path to a file you wish to open would be ".../MyMovie/SomeClip".
353     ///
354     /// @return The package's format if it can be determined, otherwise \c #kXMP_UnknownFile.
355 
356     static XMP_FileFormat CheckPackageFormat ( XMP_StringPtr folderPath );
357 
358     // ---------------------------------------------------------------------------------------------
359     /// @brief \c GetFileModDate() returns the last modification date of all files that are returned
360     /// by \c GetAssociatedResources()
361     ///
362     /// Returns the most recent O/S file modification date of all associated files. In the typical case
363     /// of a single file containing embedded XMP, returned date value is the modification date of the
364     /// same file. For sidecar and folder based video packages, returned date value is the modification
365     /// date of that associated file which was updated last.
366     ///
367     /// @param filePath A path exactly as would be passed to \c OpenFile.
368     ///
369     /// @param modDate A required pointer to return the last modification date.
370     ///
371     /// @param format A format hint as would be passed to \c OpenFile.
372     ///
373     /// @param options An optional set of option flags. The only defined one is \c kXMPFiles_ForceGivenHandler,
374     /// used to shortcut the handler selection logic if the caller is certain of the format.
375     ///
376     /// @return Returns true if the file path is valid to select a smart handler, false for an
377     /// invalid path or if fallback packet scanning would be selected.
378 
379     static bool GetFileModDate ( XMP_StringPtr    filePath,
380                                  XMP_DateTime *   modDate,
381                                  XMP_FileFormat * format = 0,
382                                  XMP_OptionBits   options = 0 );
383 
384 
385     // ---------------------------------------------------------------------------------------------
386     /// @brief \c GetAssociatedResources() returns a list of files and folders associated to filePath.
387     ///
388     /// \c GetAssociatedResources is provided to locate all files that are associated to the given
389     /// filePath such as sidecar-based XMP or folder-based video packages.If a smart
390     /// handler can be selected (not fallback packet scanning) then a list of file/folder paths is
391     /// returned for the related files that can be safely copied/imported to a different location,
392     /// keeping intact metadata(XMP and non-XMP),content and the necessary folder structure of the
393     /// format. The necessary folder structure here is the structure that is needed to uniquely
394     /// identify a folder-based format.The filePath and format parameters are exactly as would be
395     /// used for OpenFile. In the simple embedded XMP case just one path is returned. In the simple
396     /// sidecar case one or two paths will be returned, one if there is no sidecar XMP and two if
397     /// sidecar XMP exists. For folder-based handlers paths to all associated files is returned,
398     /// including the files and folders necessary to identify the format.In general, all the returned
399     /// paths are existent.In case of folder based video formats the first associated resource in the
400 	/// resourceList is the root folder.
401     ///
402     /// @param filePath A path exactly as would be passed to \c OpenFile.
403     ///
404     /// @param resourceList Address of a vector of strings to receive all associated resource paths.
405     ///
406     /// @param format A format hint as would be passed to \c OpenFile.
407     ///
408     /// @param options An optional set of option flags. The only defined one is \c kXMPFiles_ForceGivenHandler,
409     /// used to shortcut the handler selection logic if the caller is certain of the format.
410     ///
411     /// @return Returns true if the file path is valid to select a smart handler, false for an
412     /// invalid path or if fallback packet scanning would be selected. Can also return false for
413     /// unexpected errors that prevent knowledge of the file usage.
414 
415     static bool GetAssociatedResources ( XMP_StringPtr            filePath,
416                                          std::vector<tStringObj>* resourceList,
417                                          XMP_FileFormat           format = kXMP_UnknownFile,
418                                          XMP_OptionBits           options = 0);
419 
420     // ---------------------------------------------------------------------------------------------
421     /// @brief \c IsMetadataWritable() returns true if metadata can be updated for the given media path.
422     ///
423     /// \c IsMetadataWritable is provided to check if metadata can be updated or written to the format.In
424     /// the case of folder-based video formats only if all the metadata files can be written to, true is
425     /// returned.In other words, false is returned for a partial-write state of metadata files in
426     /// folder-based media formats.
427     ///
428     /// @param filePath A path exactly as would be passed to \c OpenFile.
429     ///
430     /// @param writable A pointer to the result flag. Is true if the metadata can be updated in the format,
431     /// otherwise false.
432     ///
433     /// @param format A format hint as would be passed to \c OpenFile.
434     ///
435     /// @param options An optional set of option flags. The only defined one is \c kXMPFiles_ForceGivenHandler,
436     /// used to shortcut the handler selection logic if the caller is certain of the format.
437     ///
438     /// @return Returns true if the file path is valid to select a smart handler, false for an
439     /// invalid path or if fallback packet scanning would be selected.
440 
441     static bool IsMetadataWritable (XMP_StringPtr  filePath,
442                                    bool *         writable,
443                                    XMP_FileFormat format = kXMP_UnknownFile,
444                                    XMP_OptionBits options = 0 );
445 
446     // ---------------------------------------------------------------------------------------------
447     /// @brief \c OpenFile() opens a file for metadata access.
448     ///
449     /// Opens a file for the requested forms of metadata access. Opening the file at a minimum
450     /// causes the raw XMP packet to be read from the file. If the file handler supports legacy
451     /// metadata reconciliation then legacy metadata is also read, unless \c #kXMPFiles_OpenOnlyXMP
452     /// is passed.
453     ///
454     /// If the file is opened for read-only access (passing \c #kXMPFiles_OpenForRead), the disk
455     /// file is closed immediately after reading the data from it; the \c XMPFiles object, however,
456     /// remains in the open state. You must call \c CloseFile() when finished using it. Other
457     /// methods, such as \c GetXMP(), can only be used between the \c OpenFile() and \c CloseFile()
458     /// calls. The \c XMPFiles destructor does not call \c CloseFile(); if you call it without
459     /// closing, any pending updates are lost.
460     ///
461     /// If the file is opened for update (passing \c #kXMPFiles_OpenForUpdate), the disk file
462     /// remains open until \c CloseFile() is called. The disk file is only updated once, when
463     /// \c CloseFile() is called, regardless of how many calls are made to \c PutXMP().
464     ///
465     /// Typically, the XMP is not parsed and legacy reconciliation is not performed until \c GetXMP()
466     /// is called, but this is not guaranteed. Specific file handlers might do earlier parsing of
467     /// the XMP. Delayed parsing and early disk file close for read-only access are optimizations
468     /// to help clients implementing file browsers, so that they can access the file briefly
469     /// and possibly display a thumbnail, then postpone more expensive XMP processing until later.
470     ///
471     /// @param filePath The path for the file, appropriate for the local operating system. Passed as
472     /// a nul-terminated UTF-8 string.
473     ///
474     /// @param format The format of the file. If the format is unknown (\c #kXMP_UnknownFile) the
475     /// format is determined from the file content. The first handler to check is guessed from the
476     /// file's extension. Passing a specific format value is generally just a hint about what file
477     /// handler to try first (instead of the one based on the extension). If
478     /// \c #kXMPFiles_OpenStrictly is set, then any format other than \c #kXMP_UnknownFile requires
479     /// that the file actually be that format; otherwise an exception is thrown.
480     ///
481     /// @param openFlags A set of option flags that describe the desired access. By default (zero)
482     /// the file is opened for read-only access and the format handler decides on the level of
483     /// reconciliation that will be performed. A logical OR of these bit-flag constants:
484     ///
485     ///   \li \c #kXMPFiles_OpenForRead - Open for read-only access.
486     ///   \li \c #kXMPFiles_OpenForUpdate - Open for reading and writing.
487     ///   \li \c #kXMPFiles_OpenOnlyXMP - Only the XMP is wanted, no reconciliation.
488     ///   \li \c #kXMPFiles_OpenStrictly - Be strict about locating XMP and reconciling with other
489     ///   forms. By default, a best effort is made to locate the    correct XMP and to reconcile XMP
490     ///   with other forms (if reconciliation is done). This option forces stricter rules, resulting
491     ///   in exceptions for errors. The definition of strictness is specific to each handler, there
492     ///   might be no difference.
493     ///   \li \c #kXMPFiles_OpenUseSmartHandler - Require the use of a smart handler.
494     ///   \li \c #kXMPFiles_OpenUsePacketScanning - Force packet scanning, do not use a smart handler.
495 	///   \li \c #kXMPFiles_OptimizeFileLayout - When updating a file, spend the effort necessary
496 	///    to optimize file layout.
497     ///
498     /// @return True if the file is succesfully opened and attached to a file handler. False for
499     /// anticipated problems, such as passing \c #kXMPFiles_OpenUseSmartHandler but not having an
500     /// appropriate smart handler. Throws an exception for serious problems.
501 
502     bool OpenFile ( XMP_StringPtr  filePath,
503                     XMP_FileFormat format = kXMP_UnknownFile,
504                     XMP_OptionBits openFlags = 0 );
505 
506     // ---------------------------------------------------------------------------------------------
507     /// @brief \c OpenFile() opens a file for metadata access, using a string object
508     ///
509     /// Overloads the basic form of the function, allowing you to pass a string object for the file
510     /// path. It is otherwise identical; see details in the canonical form.
511 
512     bool OpenFile ( const tStringObj & filePath,
513                     XMP_FileFormat     format = kXMP_UnknownFile,
514                     XMP_OptionBits     openFlags = 0 );
515 
516     #if XMP_StaticBuild    // ! Client XMP_IO objects can only be used in static builds.
517     // ---------------------------------------------------------------------------------------------
518     /// @brief \c OpenFile() opens a client-provided XMP_IO object for metadata access.
519     ///
520     /// Alternative to the basic form of the function, allowing you to pass an XMP_IO object for
521     /// client-managed I/O.
522     ///
523 
524     bool OpenFile ( XMP_IO *       clientIO,
525                     XMP_FileFormat format = kXMP_UnknownFile,
526                     XMP_OptionBits openFlags = 0 );
527     #endif
528 
529     // ---------------------------------------------------------------------------------------------
530     /// @brief CloseFile() explicitly closes an opened file.
531     ///
532     /// Performs any necessary output to the file and closes it. Files that are opened for update
533     /// are written to only when closing.
534     ///
535     /// If the file is opened for read-only access (passing \c #kXMPFiles_OpenForRead), the disk
536     /// file is closed immediately after reading the data from it; the \c XMPFiles object, however,
537     /// remains in the open state. You must call \c CloseFile() when finished using it. Other
538     /// methods, such as \c GetXMP(), can only be used between the \c OpenFile() and \c CloseFile()
539     /// calls. The \c XMPFiles destructor does not call \c CloseFile(); if you call it without closing,
540     /// any pending updates are lost.
541     ///
542     /// If the file is opened for update (passing \c #kXMPFiles_OpenForUpdate), the disk file remains
543     /// open until \c CloseFile() is called. The disk file is only updated once, when \c CloseFile()
544     /// is called, regardless of how many calls are made to \c PutXMP().
545     ///
546     /// @param closeFlags Option flags for optional closing actions. This bit-flag constant is
547     /// defined:
548     ///
549     ///   \li \c #kXMPFiles_UpdateSafely - Write into a temporary file then swap for crash safety.
550 
551     void CloseFile ( XMP_OptionBits closeFlags = 0 );
552 
553     // ---------------------------------------------------------------------------------------------
554     /// @brief \c GetFileInfo() retrieves basic information about an opened file.
555     ///
556     /// @param filePath [out] A buffer in which to return the path passed to \c OpenFile(). Can be
557     /// null if value is not wanted.
558     ///
559     /// @param openFlags  [out] A buffer in which to return the option flags passed to
560     /// \c OpenFile(). Can be null if value is not wanted.
561     ///
562     /// @param format [out] A buffer in which to return the file format. Can be null if value is not
563     /// wanted.
564     /// @param handlerFlags  [out] A buffer in which to return the handler's capability flags. Can
565     /// be null if value is not wanted.
566     ///
567     /// @return True if the file object is in the open state; that is, \c OpenFile() has been called
568     /// but \c CloseFile() has not. False otherwise. Even if the file object is open, the actual
569     /// disk file might be closed in the host file-system sense; see \c OpenFile().
570 
571     bool GetFileInfo ( tStringObj *     filePath = 0,
572                        XMP_OptionBits * openFlags = 0,
573                        XMP_FileFormat * format = 0,
574                        XMP_OptionBits * handlerFlags = 0 );
575 
576     // ---------------------------------------------------------------------------------------------
577     /// @brief \c SetAbortProc() registers a callback function used to check for a user-signaled abort.
578     ///
579     /// The specified procedure is called periodically to allow a user to cancel time-consuming
580     /// operations. The callback function should return true to signal an abort, which results in an
581     /// exception being thrown.
582     ///
583     /// @param abortProc The callback function.
584     ///
585     /// @param abortArg A pointer to caller-defined data to pass to the callback function.
586 
587     void SetAbortProc ( XMP_AbortProc abortProc,
588                         void *        abortArg );
589 
590     /// @}
591 
592     // =============================================================================================
593     /// \name Accessing metadata
594     /// @{
595     ///
596     /// These functions allow you to retrieve XMP metadata from open files, so that you can use the
597     /// \c TXMPMeta API to manipulate it. The \c PutXMP() functions update the XMP packet in memory.
598     /// Changed XMP is not actually written out to the file until the file is closed.
599 
600     // ---------------------------------------------------------------------------------------------
601     /// @brief \c GetXMP() retrieves the XMP metadata from an open file.
602     ///
603     /// The function reports whether XMP is present in the file; you can choose to retrieve any or
604     /// all of the parsed XMP, the raw XMP packet,or information about the raw XMP packet. The
605     /// options provided when the file was opened determine if reconciliation is done with other
606     /// forms of metadata.
607     ///
608     /// @param xmpObj [out] An XMP object in which to return the parsed XMP metadata. Can be null.
609     ///
610     /// @param xmpPacket [out] An string object in which to return the raw XMP packet as stored in
611     /// the file. Can be null. The encoding of the packet is given in the \c packetInfo. Returns an
612     /// empty string if the low level file handler does not provide the raw packet.
613     ///
614     /// @param packetInfo [out] An string object in which to return the location and form of the raw
615     /// XMP in the file. \c #XMP_PacketInfo::charForm and \c #XMP_PacketInfo::writeable reflect the
616     /// raw XMP in the file. The parsed XMP property values are always UTF-8. The writeable flag is
617     /// taken from the packet trailer; it applies only to "format ignorant" writing. The
618     /// \c #XMP_PacketInfo structure always reflects the state of the XMP in the file. The offset,
619     /// length, and character form do not change as a result of calling \c PutXMP() unless the file
620     /// is also written. Some file handlers might not return location or contents of the raw packet
621     /// string. To determine whether one does, check the \c #kXMPFiles_ReturnsRawPacket bit returned
622     /// by \c GetFormatInfo(). If the low-level file handler does not provide the raw packet
623     /// location, \c #XMP_PacketInfo::offset and \c #XMP_PacketInfo::length are both 0,
624     /// \c #XMP_PacketInfo::charForm is UTF-8, and \c #XMP_PacketInfo::writeable is false.
625     ///
626     /// @return True if the file has XMP, false otherwise.
627 
628     bool GetXMP ( SXMPMeta *       xmpObj = 0,
629                   tStringObj *     xmpPacket = 0,
630                   XMP_PacketInfo * packetInfo = 0 );
631 
632     // ---------------------------------------------------------------------------------------------
633     /// @brief \c PutXMP() updates the XMP metadata in this object without writing out the file.
634     ///
635     /// This function supplies new XMP for the file. However, the disk file is not written until the
636     /// object is closed with \c CloseFile(). The options provided when the file was opened
637     /// determine if reconciliation is done with other forms of metadata.
638     ///
639     /// @param xmpObj The new metadata as an XMP object.
640 
641     void PutXMP ( const SXMPMeta & xmpObj );
642 
643     // ---------------------------------------------------------------------------------------------
644     /// @brief \c PutXMP() updates the XMP metadata in this object without writing out the file,
645     /// using a string object for input.
646     ///
647     /// Overloads the basic form of the function, allowing you to pass the metadata as a string object
648     /// instead of an XMP object. It is otherwise identical; see details in the canonical form.
649     ///
650     /// @param xmpPacket The new metadata as a string object containing a complete XMP packet.
651 
652     void PutXMP ( const tStringObj & xmpPacket );
653 
654     // ---------------------------------------------------------------------------------------------
655     /// @brief \c PutXMP() updates the XMP metadata in this object without writing out the file,
656        /// using a string object and optional length.
657     ///
658     /// Overloads the basic form of the function, allowing you to pass the metadata as a string object
659     /// instead of an XMP object. It is otherwise identical; see details in the canonical form.
660     ///
661     /// @param xmpPacket The new metadata as a <tt>const char *</tt> string containing an XMP packet.
662     ///
663     /// @param xmpLength Optional. The number of bytes in the string. If not supplied, the string is
664     /// assumed to be nul-terminated.
665 
666     void PutXMP ( XMP_StringPtr xmpPacket,
667                   XMP_StringLen xmpLength = kXMP_UseNullTermination );
668 
669     // ---------------------------------------------------------------------------------------------
670     /// @brief \c CanPutXMP() reports whether this file can be updated with a specific XMP packet.
671     ///
672     /// Use to determine if the file can probably be updated with a given set of XMP metadata. This
673     /// depends on the size of the packet, the options with which the file was opened, and the
674     /// capabilities of the handler for the file format. The function obtains the length of the
675     /// serialized packet for the provided XMP, but does not keep it or modify it, and does not
676     /// cause the file to be written when closed. This is implemented roughly as follows:
677     ///
678     /// <pre>
679     /// bool CanPutXMP ( XMP_StringPtr xmpPacket )
680     /// {
681     ///    XMP_FileFormat format;
682     ///    this->GetFileInfo ( 0, &format, 0 );
683     ///
684     ///    XMP_OptionBits formatFlags;
685     ///    GetFormatInfo ( format, &formatFlags );
686     ///
687     ///    if ( (formatFlags & kXMPFiles_CanInjectXMP) && (formatFlags & kXMPFiles_CanExpand) ) return true;
688     ///
689     ///    XMP_PacketInfo packetInfo;
690     ///    bool hasXMP = this->GetXMP ( 0, 0, &packetInfo );
691     ///
692     ///    if ( ! hasXMP ) {
693     ///       if ( formatFlags & kXMPFiles_CanInjectXMP ) return true;
694     ///    } else {
695     ///       if ( (formatFlags & kXMPFiles_CanExpand) ||
696     ///            (packetInfo.length >= strlen(xmpPacket)) ) return true;
697     ///    }
698     ///    return false;
699     /// }
700     /// </pre>
701     ///
702     /// @param xmpObj The proposed new metadata as an XMP object.
703 
704     bool CanPutXMP ( const SXMPMeta & xmpObj );
705 
706     // ---------------------------------------------------------------------------------------------
707     /// @brief \c CanPutXMP() reports whether this file can be updated with a specific XMP packet,
708     /// passed in a string object.
709     ///
710     /// Overloads the basic form of the function, allowing you to pass the metadata as a string object
711     /// instead of an XMP object. It is otherwise identical; see details in the canonical form.
712     ///
713     /// @param xmpPacket The proposed new metadata as a string object containing an XMP packet.
714 
715     bool CanPutXMP ( const tStringObj & xmpPacket );
716 
717     // ---------------------------------------------------------------------------------------------
718     /// @brief \c CanPutXMP() reports whether this file can be updated with a specific XMP packet,
719     /// passed in a string object.
720     ///
721     /// Overloads the basic form of the function, allowing you to pass the metadata as a string object
722     /// instead of an XMP object. It is otherwise identical; see details in the canonical form.
723     ///
724     /// @param xmpPacket The proposed new metadata as a <tt>const char *</tt> string containing an XMP packet.
725     ///
726     /// @param xmpLength Optional. The number of bytes in the string. If not supplied, the string
727     /// is assumed to be nul-terminated.
728 
729     bool CanPutXMP ( XMP_StringPtr xmpPacket,
730                      XMP_StringLen xmpLength = kXMP_UseNullTermination );
731 
732     /// @}
733 
734     // =============================================================================================
735     /// \name Progress notifications
736     /// @{
737     ///
738     /// These functions allow track the progress of file operations. Initially only file updates are
739     /// tracked, these all occur within calls to SXMPFiles::CloseFile. There are no plans to track
740     /// other operations at this time. Tracking support must be added to specific file handlers,
741     /// there are no guarantees about which handlers will have support. To simplify the logic only
742     /// file writes will be estimated and measured.
743 
744     // ---------------------------------------------------------------------------------------------
745     /// @brief \c SetDefaultProgressCallback() sets a global default for progress tracking. This is
746     /// used as a default for XMPFiles (library) objects created after the default is set. This does
747     /// not affect the callback for new SXMPFiles (client) objects with an existing XMPFiles object.
748     ///
749     /// @param proc The client's callback function. Can be zero to disable notifications.
750     ///
751     /// @param context A pointer used to carry client-private context.
752     ///
753     /// @param interval The desired number of seconds between notifications. Ideally the first
754     /// notification is sent after this interval, then at each following multiple of this interval.
755     ///
756     /// @param sendStartStop A Boolean value indicating if initial and final notifications are
757     /// wanted in addition to those at the reporting intervals.
758 
759     static void SetDefaultProgressCallback ( XMP_ProgressReportProc proc, void * context = 0,
760                                              float interval = 1.0, bool sendStartStop = false );
761 
762     // ---------------------------------------------------------------------------------------------
763     /// @brief \c SetProgressCallback() sets the progress notification callback for the associated
764     /// XMPFiles (library) object.
765     ///
766     /// @param proc The client's callback function. Can be zero to disable notifications.
767     ///
768     /// @param context A pointer used to carry client-private context.
769     ///
770     /// @param interval The desired number of seconds between notifications. Ideally the first
771     /// notification is sent after this interval, then at each following multiple of this interval.
772     ///
773     /// @param sendStartStop A Boolean value indicating if initial and final notifications are
774     /// wanted in addition to those at the reporting intervals.
775 
776     void SetProgressCallback ( XMP_ProgressReportProc proc, void * context = 0,
777                                float interval = 1.0, bool sendStartStop = false );
778 
779     /// @}
780 
781     // =============================================================================================
782     // Error notifications
783     // ===================
784 
785     // ---------------------------------------------------------------------------------------------
786     /// \name Error notifications
787     /// @{
788     ///
789     /// From the beginning through version 5.5, XMP Toolkit errors result in throwing an \c XMP_Error
790     /// exception. For the most part exceptions were thrown early and thus API calls aborted as soon
791     /// as an error was detected. Starting in version 5.5, support has been added for notifications
792     /// of errors arising in calls to \c TXMPFiles functions.
793     ///
794     /// A client can register an error notification callback function for a \c TXMPFile object. This
795     /// can be done as a global default or individually to each object. The global default applies
796     /// to all objects created after it is registered. Within the object there is no difference
797     /// between the global default or explicitly registered callback. The callback function returns
798     /// a \c bool value indicating if recovery should be attempted (true) or an exception thrown
799     /// (false). If no callback is registered, a best effort at recovery and continuation will be
800     /// made with an exception thrown if recovery is not possible.
801     ///
802     /// The number of notifications delivered for a given TXMPFiles object can be limited. This is
803     /// intended to reduce chatter from multiple or cascading errors. The limit is set when the
804     /// callback function is registered. This limits the number of notifications of the highest
805     /// severity delivered or less. If a higher severity error occurs, the counting starts again.
806     /// The limit and counting can be reset at any time, see \c ResetErrorCallbackLimit.
807 
808     //  --------------------------------------------------------------------------------------------
809     /// @brief SetDefaultErrorCallback() registers a global default error notification callback.
810     ///
811     /// @param proc The client's callback function.
812     ///
813     /// @param context Client-provided context for the callback.
814     ///
815     /// @param limit A limit on the number of notifications to be delivered.
816 
817     static void SetDefaultErrorCallback ( XMPFiles_ErrorCallbackProc proc, void* context = 0, XMP_Uns32 limit = 1 );
818 
819     //  --------------------------------------------------------------------------------------------
820     /// @brief SetErrorCallback() registers an error notification callback.
821     ///
822     /// @param proc The client's callback function.
823     ///
824     /// @param context Client-provided context for the callback.
825     ///
826     /// @param limit A limit on the number of notifications to be delivered.
827 
828     void SetErrorCallback ( XMPFiles_ErrorCallbackProc proc, void* context = 0, XMP_Uns32 limit = 1 );
829 
830     //  --------------------------------------------------------------------------------------------
831     /// @brief ResetErrorCallbackLimit() resets the error notification limit and counting. It has no
832     /// effect if an error notification callback function is not registered.
833     ///
834     /// @param limit A limit on the number of notifications to be delivered.
835 
836     void ResetErrorCallbackLimit ( XMP_Uns32 limit = 1 );
837 
838     /// @}
839 
840     // =============================================================================================
841 
842 private:
843 
844     XMPFilesRef xmpFilesRef;
845 
846     // These are used as callbacks from the library code to the client when returning values that
847     // involve heap allocations. This ensures the allocations occur within the client.
848     static void SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
849     static void SetClientStringVector ( void * clientPtr, XMP_StringPtr* arrayPtr, XMP_Uns32 stringCount );
850 };    // class TXMPFiles
851 
852 // =================================================================================================
853 
854 #endif // __TXMPFiles_hpp__
855