1 #ifndef __XMPFiles_hpp__
2 #define __XMPFiles_hpp__	1
3 
4 // =================================================================================================
5 // ADOBE SYSTEMS INCORPORATED
6 // Copyright 2004 Adobe Systems Incorporated
7 // All Rights Reserved
8 //
9 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
10 // of the Adobe license agreement accompanying it.
11 // =================================================================================================
12 
13 #include "public/include/XMP_Environment.h"	// ! This must be the first include.
14 
15 #include <string>
16 #define TXMP_STRING_TYPE std::string
17 #include "public/include/XMP.hpp"
18 
19 #include "public/include/XMP_IO.hpp"
20 #include "source/SafeStringAPIs.h"
21 #include "source/XMP_ProgressTracker.hpp"
22 
23 class XMPFileHandler;
24 namespace Common{ struct XMPFileHandlerInfo; }
25 
26 // =================================================================================================
27 /// \file XMPFiles.hpp
28 /// \brief High level support to access metadata in files of interest to Adobe applications.
29 ///
30 /// This header ...
31 ///
32 // =================================================================================================
33 
34 // =================================================================================================
35 // *** Usage Notes (eventually to become Doxygen comments) ***
36 // ===========================================================
37 //
38 // This is the main part of the internal (DLL side) implementation of XMPFiles. Other parts are
39 // the entry point wrappers and the file format handlers. The XMPFiles class distills the client
40 // API from TXMPFiles.hpp, removing convenience overloads and substituting a pointer/length pair
41 // for output strings.
42 //
43 // The wrapper functions provide a stable binary interface and perform minor impedance correction
44 // between the client template API from TDocMeta.hpp and the DLL's XMPFiles class. The details of
45 // the wrappers should be considered private.
46 //
47 // File handlers are registered during DLL initialization with hard coded calls in Init_XMPFiles.
48 // Each file handler provides 2 standalone functions, CheckFormatProc and DocMetaHandlerCTor, plus a
49 // class derived from DocMetaHandler. The format and capability flags are passed when registering.
50 // This allows the same physical handler to be registered for multiple formats.
51 //
52 // -------------------------------------------------------------------------------------------------
53 //
54 // Basic outlines of the processing by the XMPFiles methods:
55 //
56 //	Constructor:
57 //		- Minimal work to create an empty XMPFiles object, set the ref count to 1.
58 //
59 //	Destructor:
60 //		- Decrement the ref count, return if greater than zero.
61 //		- Call LFA_Close if necessary.
62 ////
63 //	GetFormatInfo:
64 //		- Return the flags for the registered handler.
65 //
66 //	OpenFile:
67 //		- The physical file is opened via LFA_OpenFile.
68 //		- A handler is selected by calling the registered format checkers.
69 //		- The handler object is created by calling the registered constructor proc.
70 //
71 //	CloseFile:
72 //		- Return if there is no open file (not an error).
73 //		- If not a crash-safe update (includes read-only or no update), or the handler owns the file:
74 //			- Throw an exception if the handler owns the file but does not support safe update.
75 //			- If the file needs updating, call the handler's UpdateFile method.
76 //		- else:
77 //			- If the handler supports file rewrite:
78 //				- *** This might not preserve ownership and permissions.
79 //				- Create an empty temp file.
80 //				- Call the handler's WriteFile method, writing to the temp file.
81 //			- else
82 //				- *** This preserves ownership, permissions, and Mac resources.
83 //				- Copy the original file to a temp name (Mac data fork only).
84 //				- Rename the original file to a different temp name.
85 //				- Rename the copy file back to the original name.
86 //				- Call the handler's UpdateFile method for the "original as temp" file.
87 //			- Close both the original and temp files.
88 //			- Delete the file with the original name.
89 //			- Rename the temp file to the original name.
90 //		- Delete the handler object.
91 //		- Call LFA_Close if necessary.
92 //
93 //	GetFileInfo:
94 //		- Return the file info from the XMPFiles member variables.
95 //
96 //	GetXMP:
97 //		- Throw an exception if there is no open file.
98 //		- Call the handler's GetXMP method.
99 //
100 //	PutXMP:
101 //		- Throw an exception if there is no open file.
102 //		- Call the handler's PutXMP method.
103 //
104 //	CanPutXMP:
105 //		- Implement roughly as shown in TXMPFiles.hpp, there is no handler CanPutXMP method.
106 //
107 // -------------------------------------------------------------------------------------------------
108 //
109 // The format checker should do nothing but the minimal work to identify the overall file format.
110 // In particular it should not look for XMP or other metadata. Note that the format checker has no
111 // means to carry state forward, it just returns a yes/no answer about a particular file format.
112 //
113 // The format checker and file handler should use the LFA_* functions for all I/O. They should not
114 // open or close the file themselves unless the handler sets the "handler-owns-file" flag.
115 //
116 // The format checker is passed the format being checked, allowing one checker to handle multiple
117 // formats. It is passed the LFA file ref so that it can do additional reads if necessary. The
118 // buffer is from the start of the file, the file will be positioned to the byte following the
119 // buffer. The buffer length will be at least 4K, unless the file is smaller in which case it will
120 // be the length of the file. This buffer may be reused for additional reads.
121 //
122 // Identifying some file formats can require checking variable length strings. Doing seeks and reads
123 // for each is suboptimal. There are utilities to maintain a rolling buffer and ensure that a given
124 // amount of data is available. See the template file handler code for details.
125 //
126 // -------------------------------------------------------------------------------------------------
127 //
128 // The file handler has no explicit open and close methods. These are implicit in the handler's
129 // constructor and destructor. The file handler should use the XMPFiles member variables for the
130 // active file ref (and path if necessary), unless it owns the file. Note that these might change
131 // between the open and close in the case of crash-safe updates. Don't copy the XMPFiles member
132 // variables in the handler's constructor, save the pointer to the XMPFiles object and access
133 // directly as needed.
134 //
135 // The handler should have an UpdateFile method. This is called from XMPFiles::CloseFile if the
136 // file needs to be updated. The handler's destructor must only close the file, not update it.
137 // The handler can optionally have a WriteFile method, if it can rewrite the entire file.
138 //
139 // The handler is free to use its best judgment about caching parts of the file in memory. Overall
140 // speed of a single open/get/put/close cycle is probably the best goal, assuming a modern processor
141 // with a reasonable (significant but not enormous) amount of RAM.
142 //
143 // The handler methods will be called in a per-object thread safe manner. Concurrent access might
144 // occur for different objects, but not for the same object. The handler's constructor and destructor
145 // will always be globally serialized, so they can safely modify global data structures.
146 //
147 // (Testing issue: What about separate XMPFiles objects accessing the same file?)
148 //
149 // Handler's must not have any global objects that are heap allocated. Use pointers to objects that
150 // are allocated and deleted during the XMPFiles initialization and termination process. Some
151 // client apps are very picky about what they detect as memory leaks.
152 //
153 //    static char gSomeBuffer [10*1000];          // OK, not from the heap.
154 //    static std::string gSomeString;             // Not OK, content from the heap.
155 //    static std::vector<int> gSomeVector;        // Not OK, content from the heap.
156 //    static std::string * gSomeString = 0;       // OK, alloc at init, delete at term.
157 //    static std::vector<int> * gSomeVector = 0;  // OK, alloc at init, delete at term.
158 //
159 // =================================================================================================
160 
161 class XMPFiles {
162 public:
163 	static bool Initialize(XMP_OptionBits options, const char* pluginFolder, const char* plugins = NULL);
164 	static void Terminate();
165 
166 	static void GetVersionInfo(XMP_VersionInfo * info);
167 
168 	static bool GetFormatInfo(XMP_FileFormat format, XMP_OptionBits * flags = 0);
169 
170 	static bool GetFileModDate(
171 		XMP_StringPtr filePath,
172 		XMP_DateTime * modDate,
173 		XMP_FileFormat * format = 0,
174 		XMP_OptionBits options = 0);
175 
176 	static bool GetFileModDate(
177 		const Common::XMPFileHandlerInfo& hdlInfo,
178 		XMP_StringPtr    clientPath,
179 		XMP_DateTime *   modDate,
180 		XMP_OptionBits   options = 0 );
181 
182 	static XMP_FileFormat CheckFileFormat(XMP_StringPtr filePath);
183 	static XMP_FileFormat CheckPackageFormat(XMP_StringPtr folderPath);
184 
185 	static bool GetAssociatedResources (
186 		XMP_StringPtr              filePath,
187         std::vector<std::string> * resourceList,
188         XMP_FileFormat             format  = kXMP_UnknownFile ,
189         XMP_OptionBits             options  = 0 );
190 
191 	static bool GetAssociatedResources (
192 		const Common::XMPFileHandlerInfo& hdlInfo,
193 		XMP_StringPtr              filePath,
194         std::vector<std::string> * resourceList,
195         XMP_OptionBits             options  = 0 );
196 
197 	static bool IsMetadataWritable (
198 		XMP_StringPtr  filePath,
199         XMP_Bool *     writable,
200         XMP_FileFormat format  = kXMP_UnknownFile ,
201         XMP_OptionBits options  = 0 );
202 
203 	static bool IsMetadataWritable (
204 		const Common::XMPFileHandlerInfo& hdlInfo,
205 		XMP_StringPtr  filePath,
206         XMP_Bool *     writable,
207         XMP_OptionBits options  = 0 );
208 
209 	static void SetDefaultProgressCallback(const XMP_ProgressTracker::CallbackInfo & cbInfo);
210 	static void SetDefaultErrorCallback(XMPFiles_ErrorCallbackWrapper wrapperProc,
211 		XMPFiles_ErrorCallbackProc clientProc,
212 		void * context,
213 		XMP_Uns32 limit);
214 
215 	XMPFiles();
216 	virtual ~XMPFiles();
217 
218 	bool OpenFile(XMP_StringPtr filePath, XMP_FileFormat format = kXMP_UnknownFile, XMP_OptionBits openFlags = 0);
219 	bool OpenFile(const Common::XMPFileHandlerInfo & hdlInfo, XMP_StringPtr filePath, XMP_OptionBits openFlags = 0);
220 
221 #if XMP_StaticBuild	// ! Client XMP_IO objects can only be used in static builds.
222 	bool OpenFile(XMP_IO * clientIO, XMP_FileFormat format = kXMP_UnknownFile, XMP_OptionBits openFlags = 0);
223 	bool OpenFile(const Common::XMPFileHandlerInfo & hdlInfo, XMP_IO * clientIO, XMP_OptionBits openFlags = 0);
224 #endif
225 
226 	void CloseFile(XMP_OptionBits closeFlags = 0);
227 
228 	bool GetFileInfo(
229 		XMP_StringPtr * filePath = 0,
230 		XMP_StringLen * filePathLen = 0,
231 		XMP_OptionBits * openFlags = 0,
232 		XMP_FileFormat * format = 0,
233 		XMP_OptionBits * handlerFlags = 0 ) const;
234 
235 	bool GetXMP(
236 		SXMPMeta * xmpObj = 0,
237 		XMP_StringPtr * xmpPacket = 0,
238 		XMP_StringLen * xmpPacketLen = 0,
239 		XMP_PacketInfo * packetInfo = 0);
240 
241 	void PutXMP(const SXMPMeta & xmpObj);
242 	void PutXMP(XMP_StringPtr xmpPacket, XMP_StringLen xmpPacketLen = kXMP_UseNullTermination);
243 
244 	bool CanPutXMP(const SXMPMeta & xmpObj);
245 	bool CanPutXMP(XMP_StringPtr xmpPacket, XMP_StringLen xmpPacketLen = kXMP_UseNullTermination);
246 	void SetAbortProc(XMP_AbortProc abortProc, void * abortArg);
247 
248 	void SetProgressCallback(const XMP_ProgressTracker::CallbackInfo & cbInfo);
249 
250 	void SetErrorCallback(
251 		XMPFiles_ErrorCallbackWrapper wrapperProc,
252 		XMPFiles_ErrorCallbackProc clientProc,
253 		void * context,
254 		XMP_Uns32 limit);
255 	void ResetErrorCallbackLimit(XMP_Uns32 limit);
256 
257 	class ErrorCallbackInfo : public GenericErrorCallback {
258 	public:
259 		XMPFiles_ErrorCallbackWrapper	wrapperProc;
260 		XMPFiles_ErrorCallbackProc		clientProc;
261 		void *							context;
262 		std::string						filePath;
263 
ErrorCallbackInfo()264 		ErrorCallbackInfo()
265 			: wrapperProc(0)
266 			, clientProc(0)
267 			, context(0) {};
268 
Clear()269 		void Clear() {
270 			this->wrapperProc = 0; this->clientProc = 0; this->context = 0;
271 			GenericErrorCallback::Clear();
272 		};
273 
274 		bool CanNotify() const;
275 
276 		bool ClientCallbackWrapper(
277 			XMP_StringPtr filePath,
278 			XMP_ErrorSeverity severity,
279 			XMP_Int32 cause,
280 			XMP_StringPtr messsage) const;
281 	};
282 
UsesClientIO()283 	inline bool UsesClientIO() { return this->filePath.empty(); };
UsesLocalIO()284 	inline bool UsesLocalIO() { return ( ! this->UsesClientIO() ); };
SetFilePath(XMP_StringPtr _filePath)285 	inline void SetFilePath(XMP_StringPtr _filePath) { filePath = _filePath; errorCallback.filePath = _filePath; }
ClearFilePath()286 	inline void ClearFilePath() { filePath.clear(); errorCallback.filePath.clear(); }
GetFilePath()287 	inline const std::string& GetFilePath() { return filePath; }
288 
289 	// Leave this data public so file handlers can see it.
290 	XMP_Int32				clientRefs;	// ! Must be signed to allow decrement from zero.
291 	XMP_ReadWriteLock		lock;
292 	XMP_FileFormat			format;
293 	XMP_IO *				ioRef;		// Non-zero if a file is open.
294 	XMP_OptionBits			openFlags;
295 	XMPFileHandler *		handler;	// Non-null if a file is open.
296 	void *					tempPtr;	// For use between the CheckProc and handler creation.
297 	XMP_Uns32				tempUI32;
298 	XMP_AbortProc			abortProc;
299 	void *					abortArg;
300 	XMP_ProgressTracker *	progressTracker;
301 	ErrorCallbackInfo		errorCallback;
302 
303 private:
304 	std::string				filePath;	// Empty for client-managed I/O.
305 };
306 
307 bool ErrorCallbackForXMPMeta(void * context, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr message);
308 
309 #endif /* __XMPFiles_hpp__ */
310