~ubuntu-branches/ubuntu/precise/exiv2/precise

« back to all changes in this revision

Viewing changes to xmpsdk/src/ExpatAdapter.cpp

Tags: upstream-0.20
ImportĀ upstreamĀ versionĀ 0.20

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// =================================================================================================
2
 
// Copyright 2005-2007 Adobe Systems Incorporated
 
2
// Copyright 2005-2008 Adobe Systems Incorporated
3
3
// All Rights Reserved.
4
4
//
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"
14
14
 
 
15
#include "expat.h"
 
16
 
15
17
#include <string.h>
16
18
 
17
19
using namespace std;
18
20
 
19
21
#if XMP_WinBuild
20
 
        #pragma warning ( disable : 4996 )      // '...' was declared deprecated
 
22
#   ifdef _MSC_VER
 
23
        #pragma warning ( disable : 4996 )      // '...' was declared deprecated
 
24
#   endif
21
25
#endif
22
26
 
23
27
// *** Set memory handlers.
24
28
 
25
29
#ifndef DumpXMLParseEvents
26
 
        #define DumpXMLParseEvents 0
 
30
        #define DumpXMLParseEvents      0
27
31
#endif
28
32
 
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 );
45
49
 
46
 
// =================================================================================================
47
 
// =================================================================================================
48
 
 
49
 
ExpatAdapter::ExpatAdapter() : parser(0), nesting(0)
50
 
{
51
 
 
52
 
        #if XMP_DebugBuild & DumpXMLParseEvents
53
 
                if ( this->parseLog == 0 ) this->parseLog = stdout;
 
50
#if BanAllEntityUsage
 
51
 
 
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.
 
56
        
 
57
        // ! Standard entities (&amp;, &lt;, &gt;, &quot;, &apos;, and numeric character references) are
 
58
        // ! not banned. Expat handles them transparently no matter what.
 
59
 
 
60
        static void StartDoctypeDeclHandler ( void * userData, XMP_StringPtr doctypeName,
 
61
                                                                                  XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset );
 
62
 
 
63
#endif
 
64
 
 
65
// =================================================================================================
 
66
 
 
67
extern "C" ExpatAdapter * XMP_NewExpatAdapter()
 
68
{
 
69
        return new ExpatAdapter;
 
70
}       // XMP_NewExpatAdapter
 
71
 
 
72
// =================================================================================================
 
73
 
 
74
ExpatAdapter::ExpatAdapter() : parser(0)
 
75
{
 
76
 
 
77
        #if XMP_DebugBuild
 
78
                this->elemNesting = 0;
 
79
                #if DumpXMLParseEvents
 
80
                        if ( this->parseLog == 0 ) this->parseLog = stdout;
 
81
                #endif
54
82
        #endif
55
83
 
56
84
        this->parser = XML_ParserCreateNS ( 0, FullNameSeparator );
67
95
        XML_SetProcessingInstructionHandler ( this->parser, ProcessingInstructionHandler );
68
96
        XML_SetCommentHandler ( this->parser, CommentHandler );
69
97
 
70
 
        // ??? XML_SetDefaultHandlerExpand ( this->parser, DefaultHandler );
71
 
        
 
98
        #if BanAllEntityUsage
 
99
                XML_SetStartDoctypeDeclHandler ( this->parser, StartDoctypeDeclHandler );
 
100
                isAborted = false;
 
101
        #endif
 
102
 
72
103
        this->parseStack.push_back ( &this->tree );     // Push the XML root node.
73
104
 
74
105
}       // ExpatAdapter::ExpatAdapter
91
122
 
92
123
static const char * kOneSpace = " ";
93
124
 
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 */ )
95
126
{
96
127
        enum XML_Status status;
97
128
        
102
133
        }
103
134
        
104
135
        status = XML_Parse ( this->parser, (const char *)buffer, length, last );
 
136
        
 
137
        #if BanAllEntityUsage
 
138
                if ( this->isAborted ) XMP_Throw ( "DOCTYPE is not allowed", kXMPErr_BadXML );
 
139
        #endif
105
140
 
106
141
        if ( status != XML_STATUS_OK ) {
107
142
        
139
174
 
140
175
#if XMP_DebugBuild & DumpXMLParseEvents
141
176
 
142
 
        static inline void PrintIndent ( FILE * file, size_t nesting )
 
177
        static inline void PrintIndent ( FILE * file, size_t count )
143
178
        {
144
 
                for ( ; nesting > 0; --nesting ) fprintf ( file, "  " );
 
179
                for ( ; count > 0; --count ) fprintf ( file, "  " );
145
180
        }
146
181
 
147
182
#endif
168
203
        if ( fullName[sepPos] == FullNameSeparator ) {
169
204
 
170
205
                XMP_StringPtr prefix;
 
206
                XMP_StringLen prefixLen;
171
207
                XMP_StringPtr localPart = fullName + sepPos + 1;
172
208
 
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 );
 
211
 
 
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 ':'.
177
215
                
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 ':'.
192
232
                        }
193
233
                }
194
234
                
214
254
        
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 );
219
259
                }
220
260
        #endif
238
278
        
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 );
243
283
                }
244
284
        #endif
261
301
        
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 );
295
335
        
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;
299
339
        }
300
 
 
301
 
        ++thiz->nesting;
 
340
        #if XMP_DebugBuild
 
341
                ++thiz->elemNesting;
 
342
        #endif
302
343
 
303
344
}       // StartElementHandler
304
345
 
310
351
        
311
352
        ExpatAdapter * thiz = (ExpatAdapter*)userData;
312
353
 
313
 
        --thiz->nesting;
 
354
        #if XMP_DebugBuild
 
355
                --thiz->elemNesting;
 
356
        #endif
314
357
        (void) thiz->parseStack.pop_back();
315
358
        
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 );
320
363
                }
321
364
        #endif
332
375
        
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" );
339
382
                }
340
383
        #endif
359
402
        
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" );
364
407
                }
365
408
        #endif
380
423
        
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" );
385
428
                }
386
429
        #endif  
399
442
        
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 );
404
447
                }
405
448
        #endif
426
469
        
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 );
431
474
                }
432
475
        #endif
436
479
}       // CommentHandler
437
480
 
438
481
// =================================================================================================
 
482
 
 
483
#if BanAllEntityUsage
 
484
static void StartDoctypeDeclHandler ( void * userData, XMP_StringPtr doctypeName,
 
485
                                                                          XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset )
 
486
{
 
487
        IgnoreParam(userData);
 
488
 
 
489
        ExpatAdapter * thiz = (ExpatAdapter*)userData;
 
490
 
 
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 );
 
495
                }
 
496
        #endif
 
497
        
 
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 */ );
 
500
 
 
501
}       // StartDoctypeDeclHandler
 
502
#endif
 
503
 
 
504
// =================================================================================================