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