summaryrefslogtreecommitdiff
path: root/XMPCore/source/XMPCore_Impl.hpp
blob: 860cfc493803aa1b39df554c1481ff09a19c2044 (plain)
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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
#ifndef __XMPCore_Impl_hpp__
#define __XMPCore_Impl_hpp__ 1

// =================================================================================================
// 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"	// ! Must be the first #include!
#include "public/include/XMP_Const.h"
#include "build/XMP_BuildInfo.h"
#include "source/XMP_LibUtils.hpp"

// #include "XMPCore/source/XMPMeta.hpp"

#include "public/include/client-glue/WXMP_Common.hpp"

#include <vector>
#include <string>
#include <map>
#include <cassert>
#include <cstring>
#include <cstdlib>

#if XMP_WinBuild
	#pragma warning ( disable : 4244 )	// possible loss of data (temporary for 64 bit builds)
	#pragma warning ( disable : 4267 )	// possible loss of data (temporary for 64 bit builds)
#endif

// =================================================================================================
// Primary internal types

class XMP_Node;
class XML_Node;
class XPathStepInfo;

typedef XMP_Node *	XMP_NodePtr;

typedef std::vector<XMP_Node*>		XMP_NodeOffspring;
typedef XMP_NodeOffspring::iterator	XMP_NodePtrPos;

typedef XMP_VarString::iterator			XMP_VarStringPos;
typedef XMP_VarString::const_iterator	XMP_cVarStringPos;

typedef std::vector < XPathStepInfo >		XMP_ExpandedXPath;
typedef XMP_ExpandedXPath::iterator			XMP_ExpandedXPathPos;
typedef XMP_ExpandedXPath::const_iterator	XMP_cExpandedXPathPos;

typedef std::map < XMP_VarString, XMP_ExpandedXPath > XMP_AliasMap;	// Alias name to actual path.
typedef XMP_AliasMap::iterator			XMP_AliasMapPos;
typedef XMP_AliasMap::const_iterator	XMP_cAliasMapPos;

// =================================================================================================
// General global variables and macros

extern XMP_Int32 sXMP_InitCount;

typedef void * (*XMP_AllocateProc) (size_t size);

typedef void(*XMP_DeleteProc)   (void * ptr);

#if ! XMP_StaticBuild

	extern XMP_AllocateProc sXMP_MemAlloc;
	extern XMP_DeleteProc   sXMP_MemFree;

	#define malloc(size) (*sXMP_MemAlloc) ( size )
	#define free(addr)   (*sXMP_MemFree) ( addr )

#endif


extern XMP_Bool sUseNewCoreAPIs;
extern XMP_NamespaceTable * sRegisteredNamespaces;

extern XMP_AliasMap * sRegisteredAliasMap;

extern XMP_ReadWriteLock * sDefaultNamespacePrefixMapLock;

#define WtoXMPMeta_Ref(xmpRef)	(const XMPMeta &) (*((XMPMeta*)(xmpRef)))
#define WtoXMPMeta_Ptr(xmpRef)	((XMPMeta*)(xmpRef))

#define WtoXMPDocOps_Ptr(docRef)	((XMPDocOps*)(docRef))

// **** see CTECHXMP-4169947 ***//

//extern void *			voidVoidPtr;	// Used to backfill null output parameters.
//extern XMP_StringPtr	voidStringPtr;
//extern XMP_StringLen	voidStringLen;
//extern XMP_OptionBits	voidOptionBits;
//extern XMP_Bool			voidByte;
//extern bool				voidBool;
//extern XMP_Int32		voidInt32;
//extern XMP_Int64		voidInt64;
//extern double			voidDouble;
//extern XMP_DateTime		voidDateTime;
//extern WXMP_Result		void_wResult;


#define kHexDigits "0123456789ABCDEF"

#define XMP_LitMatch(s,l)		(strcmp((s),(l)) == 0)
#define XMP_LitNMatch(s,l,n)	(strncmp((s),(l),(n)) == 0)
	// *** Use the above macros!

#if XMP_WinBuild
	#define snprintf _snprintf
#endif

// =================================================================================================
// Version info

#if XMP_DebugBuild
	#define kXMPCore_DebugFlag 1
#else
	#define kXMPCore_DebugFlag 0
#endif

#define kXMPCore_VersionNumber	( (kXMPCore_DebugFlag << 31)    |	\
                                  (XMP_API_VERSION_MAJOR << 24) |	\
						          (XMP_API_VERSION_MINOR << 16) |	\
						          (XMP_API_VERSION_MICRO << 8) )

	#define kXMPCoreName "XMP Core"
	#define kXMPCore_VersionMessage	kXMPCoreName " " XMPCORE_API_VERSION_STRING
// =================================================================================================
// Support for call tracing

#ifndef XMP_TraceCoreCalls
	#define XMP_TraceCoreCalls			0
	#define XMP_TraceCoreCallsToFile	0
#endif

#if XMP_TraceCoreCalls

	#undef AnnounceThrow
	#undef AnnounceCatch

	#undef AnnounceEntry
	#undef AnnounceNoLock
	#undef AnnounceExit

	extern FILE * xmpCoreLog;

	#define AnnounceThrow(msg)	\
		fprintf ( xmpCoreLog, "XMP_Throw: %s\n", msg ); fflush ( xmpCoreLog )
	#define AnnounceCatch(msg)	\
		fprintf ( xmpCoreLog, "Catch in %s: %s\n", procName, msg ); fflush ( xmpCoreLog )

	#define AnnounceEntry(proc)			\
		const char * procName = proc;	\
		fprintf ( xmpCoreLog, "Entering %s\n", procName ); fflush ( xmpCoreLog )
	#define AnnounceNoLock(proc)		\
		const char * procName = proc;	\
		fprintf ( xmpCoreLog, "Entering %s (no lock)\n", procName ); fflush ( xmpCoreLog )
	#define AnnounceExit()	\
		fprintf ( xmpCoreLog, "Exiting %s\n", procName ); fflush ( xmpCoreLog )

#endif

// =================================================================================================
// ExpandXPath, FindNode, and related support

// *** Normalize the use of "const xx &" for input params

#define kXMP_ArrayItemName	"[]"

#define kXMP_CreateNodes	true
#define kXMP_ExistingOnly	false

#define FindConstSchema(t,u)	FindSchemaNode ( const_cast<XMP_Node*>(t), u, kXMP_ExistingOnly, 0 )
#define FindConstChild(p,c)		::FindChildNode ( const_cast<XMP_Node*>(p), c, kXMP_ExistingOnly, 0 )
#define FindConstQualifier(p,c)	FindQualifierNode ( const_cast<XMP_Node*>(p), c, kXMP_ExistingOnly, 0 )
#define FindConstNode(t,p)		::FindNode ( const_cast<XMP_Node*>(t), p, kXMP_ExistingOnly, 0 )

void
SplitNameAndValue(const XMP_VarString & selStep, 
				  XMP_VarString *       nameStr, 
				  XMP_VarString *       valueStr);

extern XMP_OptionBits
VerifySetOptions ( XMP_OptionBits options, XMP_StringPtr propValue );

extern void
ComposeXPath ( const XMP_ExpandedXPath & expandedXPath,
			   XMP_VarString * stringXPath );

extern void
ExpandXPath	( XMP_StringPtr			schemaNS,
			  XMP_StringPtr			propPath,
			  XMP_ExpandedXPath *	expandedXPath );

typedef bool (*PrefixSearchFnPtr) ( void * privateData, XMP_StringPtr nsURI, XMP_StringPtr * namespacePrefix, XMP_StringLen * prefixSize );

extern XMP_Node *
FindSchemaNode ( XMP_Node *		  xmpTree,
				 XMP_StringPtr	  nsURI,
				 bool			  createNodes,
				 XMP_NodePtrPos * ptrPos = 0,
				 PrefixSearchFnPtr prefixSearchFnPtr = NULL,
				 void * privateData = NULL );

extern XMP_Node *
FindChildNode ( XMP_Node *		 parent,
				XMP_StringPtr	 childName,
				bool			 createNodes,
				XMP_NodePtrPos * ptrPos = 0 );

extern XMP_Node *
FindQualifierNode ( XMP_Node *		 parent,
					XMP_StringPtr	 qualName,
					bool			 createNodes,
					XMP_NodePtrPos * ptrPos = 0 );

extern XMP_Node *
FindNode ( XMP_Node *		xmpTree,
		   const XMP_ExpandedXPath & expandedXPath,
		   bool				createNodes,
		   XMP_OptionBits	leafOptions = 0,
		   XMP_NodePtrPos * ptrPos = 0 );

extern XMP_Index
LookupLangItem ( const XMP_Node * arrayNode, XMP_VarString & lang );	// ! Lang must be normalized!

extern XMP_Index
LookupFieldSelector ( const XMP_Node * arrayNode, XMP_StringPtr fieldName, XMP_StringPtr fieldValue );

extern void
CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent, bool skipEmpty = false );

extern XMP_Node *
CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent, bool skipEmpty = false );

extern bool
CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode );

extern void
DeleteSubtree ( XMP_NodePtrPos rootNodePos );

extern void
DeleteEmptySchema ( XMP_Node * schemaNode );

extern void
NormalizeLangValue ( XMP_VarString * value );

extern void
NormalizeLangArray ( XMP_Node * array );

extern void
DetectAltText ( XMP_Node * xmpParent );

extern void
SortNamedNodes ( XMP_NodeOffspring & nodeVector );

static inline bool
IsPathPrefix ( XMP_StringPtr fullPath, XMP_StringPtr prefix )
{
	bool isPrefix = false;
	XMP_StringLen prefixLen = static_cast< XMP_StringLen >( strlen(prefix) );
	if ( XMP_LitNMatch ( prefix, fullPath, prefixLen ) ) {
		char separator = fullPath[prefixLen];
		if ( (separator == 0) || (separator == '/') ||
			 (separator == '[') || (separator == '*') ) isPrefix = true;
	}
	return isPrefix;
}

// -------------------------------------------------------------------------------------------------

class XPathStepInfo {
public:
	XMP_VarString	step;
	XMP_OptionBits	options;
	XPathStepInfo ( XMP_StringPtr _step, XMP_OptionBits _options ) : step(_step), options(_options) {};
	XPathStepInfo ( XMP_VarString _step, XMP_OptionBits _options ) : step(_step), options(_options) {};
private:
	XPathStepInfo() : options(0) {};	// ! Hide the default constructor.
};

enum { kSchemaStep = 0, kRootPropStep = 1, kAliasIndexStep = 2 };

enum {	// Bits for XPathStepInfo options.	// *** Add mask check to init code.
	kXMP_StepKindMask		= 0x0F,	// ! The step kinds are mutually exclusive numbers.
	kXMP_StructFieldStep	= 0x01,	// Also for top level nodes (schema "fields").
	kXMP_QualifierStep		= 0x02,	// ! Order is significant to separate struct/qual from array kinds!
	kXMP_ArrayIndexStep		= 0x03,	// ! The kinds must not overlay array form bits!
	kXMP_ArrayLastStep		= 0x04,
	kXMP_QualSelectorStep	= 0x05,
	kXMP_FieldSelectorStep	= 0x06,
	kXMP_StepIsAlias        = 0x10
};

#define GetStepKind(f)	((f) & kXMP_StepKindMask)

#define kXMP_NewImplicitNode	kXMP_InsertAfterItem

// =================================================================================================
// XMP_Node details

#if 0	// Pattern for iterating over the children or qualifiers:
	for ( size_t xxNum = 0, xxLim = _node_->_offspring_.size(); xxNum < xxLim; ++xxNum ) {
		const XMP_Node * _curr_ = _node_->_offspring_[xxNum];
	}
#endif

class XMP_Node {
public:

	XMP_OptionBits		options;
	XMP_VarString		name, value;
	XMP_Node *			parent;
	XMP_NodeOffspring	children;
	XMP_NodeOffspring	qualifiers;
	#if XMP_DebugBuild
		// *** XMP_StringPtr	_namePtr, _valuePtr;	// *** Not working, need operator=?
	#endif

	XMP_Node ( XMP_Node * _parent, XMP_StringPtr _name, XMP_OptionBits _options )
		: options(_options), name(_name), parent(_parent)
	{
		#if XMP_DebugBuild
			XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
			             (options & kXMP_SchemaNode) || (parent == 0) );
			// *** _namePtr  = name.c_str();
			// *** _valuePtr = value.c_str();
		#endif
	};

	XMP_Node ( XMP_Node * _parent, const XMP_VarString & _name, XMP_OptionBits _options )
		: options(_options), name(_name), parent(_parent)
	{
		#if XMP_DebugBuild
			XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
			             (options & kXMP_SchemaNode) || (parent == 0) );
			// *** _namePtr  = name.c_str();
			// *** _valuePtr = value.c_str();
		#endif
	};

	XMP_Node ( XMP_Node * _parent, XMP_StringPtr _name, XMP_StringPtr _value, XMP_OptionBits _options )
		: options(_options), name(_name), value(_value), parent(_parent)
	{
		#if XMP_DebugBuild
			XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
			             (options & kXMP_SchemaNode) || (parent == 0) );
			// *** _namePtr  = name.c_str();
			// *** _valuePtr = value.c_str();
		#endif
	};

	XMP_Node ( XMP_Node * _parent, const XMP_VarString & _name, const XMP_VarString & _value, XMP_OptionBits _options )
		: options(_options), name(_name), value(_value), parent(_parent)
	{
		#if XMP_DebugBuild
			XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
			             (options & kXMP_SchemaNode) || (parent == 0) );
			// *** _namePtr  = name.c_str();
			// *** _valuePtr = value.c_str();
		#endif
	};

	void GetLocalURI ( XMP_StringPtr * uriStr, XMP_StringLen * uriSize ) const;

	void GetFullQualifiedName( XMP_StringPtr * uriStr, XMP_StringLen * uriSize, XMP_StringPtr * nameStr, XMP_StringLen * nameSize ) const;

	void RemoveChildren()
	{
		for ( size_t i = 0, vLim = children.size(); i < vLim; ++i ) {
			if ( children[i] != 0 ) delete children[i];
		}
		children.clear();
	}

	void RemoveQualifiers()
	{
		for ( size_t i = 0, vLim = qualifiers.size(); i < vLim; ++i ) {
			if ( qualifiers[i] != 0 ) delete qualifiers[i];
		}
		qualifiers.clear();
	}

	void ClearNode()
	{
		options = 0;
		name.erase();
		value.erase();
		this->RemoveChildren();
		this->RemoveQualifiers();
	}

	void SetValue( XMP_StringPtr value );

	virtual ~XMP_Node() { RemoveChildren(); RemoveQualifiers(); };

private:
	XMP_Node() : options(0), parent(0)	// ! Make sure parent pointer is always set.
	{
		#if XMP_DebugBuild
			// *** _namePtr  = name.c_str();
			// *** _valuePtr = value.c_str();
		#endif
	};

};

class XMP_AutoNode {	// Used to hold a child during subtree construction.
public:
	XMP_Node * nodePtr;
	XMP_AutoNode() : nodePtr(0) {};
	~XMP_AutoNode() { if ( nodePtr != 0 ) delete ( nodePtr ); nodePtr = 0; };
	XMP_AutoNode ( XMP_Node * _parent, XMP_StringPtr _name, XMP_OptionBits _options )
		: nodePtr ( new XMP_Node ( _parent, _name, _options ) ) {};
	XMP_AutoNode ( XMP_Node * _parent, const XMP_VarString & _name, XMP_OptionBits _options )
		: nodePtr ( new XMP_Node ( _parent, _name, _options ) ) {};
	XMP_AutoNode ( XMP_Node * _parent, XMP_StringPtr _name, XMP_StringPtr _value, XMP_OptionBits _options )
		: nodePtr ( new XMP_Node ( _parent, _name, _value, _options ) ) {};
	XMP_AutoNode ( XMP_Node * _parent, const XMP_VarString & _name, const XMP_VarString & _value, XMP_OptionBits _options )
		: nodePtr ( new XMP_Node ( _parent, _name, _value, _options ) ) {};
};

// =================================================================================================

#endif	// __XMPCore_Impl_hpp__