1
1
// =================================================================================================
2
// Copyright 2005-2007 Adobe Systems Incorporated
2
// Copyright 2005-2008 Adobe Systems Incorporated
3
3
// All Rights Reserved.
5
5
// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
12
12
#include "ExpatAdapter.hpp"
13
13
#include "XMPMeta.hpp"
15
17
#include <string.h>
17
19
using namespace std;
20
#pragma warning ( disable : 4996 ) // '...' was declared deprecated
23
#pragma warning ( disable : 4996 ) // '...' was declared deprecated
23
27
// *** Set memory handlers.
25
29
#ifndef DumpXMLParseEvents
26
#define DumpXMLParseEvents 0
30
#define DumpXMLParseEvents 0
29
33
#define FullNameSeparator '@'
43
47
static void ProcessingInstructionHandler ( void * userData, XMP_StringPtr target, XMP_StringPtr data );
44
48
static void CommentHandler ( void * userData, XMP_StringPtr comment );
46
// =================================================================================================
47
// =================================================================================================
49
ExpatAdapter::ExpatAdapter() : parser(0), nesting(0)
52
#if XMP_DebugBuild & DumpXMLParseEvents
53
if ( this->parseLog == 0 ) this->parseLog = stdout;
52
// For now we do this by banning DOCTYPE entirely. This is easy and consistent with what is
53
// available in recent Java XML parsers. Another, somewhat less drastic, approach would be to
54
// ban all entity declarations. We can't allow declarations and ban references, Expat does not
55
// call the SkippedEntityHandler for references in attribute values.
57
// ! Standard entities (&, <, >, ", ', and numeric character references) are
58
// ! not banned. Expat handles them transparently no matter what.
60
static void StartDoctypeDeclHandler ( void * userData, XMP_StringPtr doctypeName,
61
XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset );
65
// =================================================================================================
67
extern "C" ExpatAdapter * XMP_NewExpatAdapter()
69
return new ExpatAdapter;
70
} // XMP_NewExpatAdapter
72
// =================================================================================================
74
ExpatAdapter::ExpatAdapter() : parser(0)
78
this->elemNesting = 0;
79
#if DumpXMLParseEvents
80
if ( this->parseLog == 0 ) this->parseLog = stdout;
56
84
this->parser = XML_ParserCreateNS ( 0, FullNameSeparator );
67
95
XML_SetProcessingInstructionHandler ( this->parser, ProcessingInstructionHandler );
68
96
XML_SetCommentHandler ( this->parser, CommentHandler );
70
// ??? XML_SetDefaultHandlerExpand ( this->parser, DefaultHandler );
99
XML_SetStartDoctypeDeclHandler ( this->parser, StartDoctypeDeclHandler );
72
103
this->parseStack.push_back ( &this->tree ); // Push the XML root node.
74
105
} // ExpatAdapter::ExpatAdapter
92
123
static const char * kOneSpace = " ";
94
void ExpatAdapter::ParseBuffer ( const void * buffer, size_t length, bool last )
125
void ExpatAdapter::ParseBuffer ( const void * buffer, size_t length, bool last /* = true */ )
96
127
enum XML_Status status;
104
135
status = XML_Parse ( this->parser, (const char *)buffer, length, last );
137
#if BanAllEntityUsage
138
if ( this->isAborted ) XMP_Throw ( "DOCTYPE is not allowed", kXMPErr_BadXML );
106
141
if ( status != XML_STATUS_OK ) {
140
175
#if XMP_DebugBuild & DumpXMLParseEvents
142
static inline void PrintIndent ( FILE * file, size_t nesting )
177
static inline void PrintIndent ( FILE * file, size_t count )
144
for ( ; nesting > 0; --nesting ) fprintf ( file, " " );
179
for ( ; count > 0; --count ) fprintf ( file, " " );
168
203
if ( fullName[sepPos] == FullNameSeparator ) {
170
205
XMP_StringPtr prefix;
206
XMP_StringLen prefixLen;
171
207
XMP_StringPtr localPart = fullName + sepPos + 1;
173
209
node->ns.assign ( fullName, sepPos );
174
210
if ( node->ns == "http://purl.org/dc/1.1/" ) node->ns = "http://purl.org/dc/elements/1.1/";
175
bool found = XMPMeta::GetNamespacePrefix ( node->ns.c_str(), &prefix, &voidStringLen );
212
bool found = XMPMeta::GetNamespacePrefix ( node->ns.c_str(), &prefix, &prefixLen );
176
213
if ( ! found ) XMP_Throw ( "Unknown URI in Expat full name", kXMPErr_ExternalFailure );
214
node->nsPrefixLen = prefixLen; // ! Includes the ':'.
178
216
node->name = prefix;
179
217
node->name += localPart;
186
224
if ( node->name == "about" ) {
187
225
node->ns = kXMP_NS_RDF;
188
226
node->name = "rdf:about";
227
node->nsPrefixLen = 4; // ! Include the ':'.
189
228
} else if ( node->name == "ID" ) {
190
229
node->ns = kXMP_NS_RDF;
191
230
node->name = "rdf:ID";
231
node->nsPrefixLen = 4; // ! Include the ':'.
215
255
#if XMP_DebugBuild & DumpXMLParseEvents
216
256
if ( thiz->parseLog != 0 ) {
217
PrintIndent ( thiz->parseLog, thiz->nesting );
257
PrintIndent ( thiz->parseLog, thiz->elemNesting );
218
258
fprintf ( thiz->parseLog, "StartNamespace: %s - \"%s\"\n", prefix, uri );
239
279
#if XMP_DebugBuild & DumpXMLParseEvents
240
280
if ( thiz->parseLog != 0 ) {
241
PrintIndent ( thiz->parseLog, thiz->nesting );
281
PrintIndent ( thiz->parseLog, thiz->elemNesting );
242
282
fprintf ( thiz->parseLog, "EndNamespace: %s\n", prefix );
262
302
#if XMP_DebugBuild & DumpXMLParseEvents
263
303
if ( thiz->parseLog != 0 ) {
264
PrintIndent ( thiz->parseLog, thiz->nesting );
304
PrintIndent ( thiz->parseLog, thiz->elemNesting );
265
305
fprintf ( thiz->parseLog, "StartElement: %s, %d attrs", name, attrCount );
266
306
for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) {
267
307
XMP_StringPtr attrName = *attr;
293
333
parentNode->content.push_back ( elemNode );
294
334
thiz->parseStack.push_back ( elemNode );
296
if ( (elemNode->name == "rdf:RDF") || (elemNode->name == "pxmp:XMP_Packet") ) {
336
if ( elemNode->name == "rdf:RDF" ) {
297
337
thiz->rootNode = elemNode;
298
338
++thiz->rootCount;
303
344
} // StartElementHandler
311
352
ExpatAdapter * thiz = (ExpatAdapter*)userData;
314
357
(void) thiz->parseStack.pop_back();
316
359
#if XMP_DebugBuild & DumpXMLParseEvents
317
360
if ( thiz->parseLog != 0 ) {
318
PrintIndent ( thiz->parseLog, thiz->nesting );
361
PrintIndent ( thiz->parseLog, thiz->elemNesting );
319
362
fprintf ( thiz->parseLog, "EndElement: %s\n", name );
333
376
#if XMP_DebugBuild & DumpXMLParseEvents
334
377
if ( thiz->parseLog != 0 ) {
335
PrintIndent ( thiz->parseLog, thiz->nesting );
378
PrintIndent ( thiz->parseLog, thiz->elemNesting );
336
379
fprintf ( thiz->parseLog, "CharContent: \"" );
337
for ( ; len > 0; --len, ++cData ) fprintf ( thiz->parseLog, "%c", *cData );
380
for ( int i = 0; i < len; ++i ) fprintf ( thiz->parseLog, "%c", cData[i] );
338
381
fprintf ( thiz->parseLog, "\"\n" );
360
403
#if XMP_DebugBuild & DumpXMLParseEvents
361
404
if ( thiz->parseLog != 0 ) {
362
PrintIndent ( thiz->parseLog, thiz->nesting );
405
PrintIndent ( thiz->parseLog, thiz->elemNesting );
363
406
fprintf ( thiz->parseLog, "StartCDATA\n" );
381
424
#if XMP_DebugBuild & DumpXMLParseEvents
382
425
if ( thiz->parseLog != 0 ) {
383
PrintIndent ( thiz->parseLog, thiz->nesting );
426
PrintIndent ( thiz->parseLog, thiz->elemNesting );
384
427
fprintf ( thiz->parseLog, "EndCDATA\n" );
400
443
#if XMP_DebugBuild & DumpXMLParseEvents
401
444
if ( thiz->parseLog != 0 ) {
402
PrintIndent ( thiz->parseLog, thiz->nesting );
445
PrintIndent ( thiz->parseLog, thiz->elemNesting );
403
446
fprintf ( thiz->parseLog, "PI: %s - \"%s\"\n", target, data );
427
470
#if XMP_DebugBuild & DumpXMLParseEvents
428
471
if ( thiz->parseLog != 0 ) {
429
PrintIndent ( thiz->parseLog, thiz->nesting );
472
PrintIndent ( thiz->parseLog, thiz->elemNesting );
430
473
fprintf ( thiz->parseLog, "Comment: \"%s\"\n", comment );
436
479
} // CommentHandler
438
481
// =================================================================================================
483
#if BanAllEntityUsage
484
static void StartDoctypeDeclHandler ( void * userData, XMP_StringPtr doctypeName,
485
XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset )
487
IgnoreParam(userData);
489
ExpatAdapter * thiz = (ExpatAdapter*)userData;
491
#if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
492
if ( thiz->parseLog != 0 ) {
493
PrintIndent ( thiz->parseLog, thiz->elemNesting );
494
fprintf ( thiz->parseLog, "DocType: \"%s\"\n", doctypeName );
498
thiz->isAborted = true; // ! Can't throw an exception across the plain C Expat frames.
499
(void) XML_StopParser ( thiz->parser, XML_FALSE /* not resumable */ );
501
} // StartDoctypeDeclHandler
504
// =================================================================================================