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