File Coverage

perl-libxml-sax.c
Criterion Covered Total %
statement 553 757 73.0
branch 387 1598 24.2
condition n/a
subroutine n/a
pod n/a
total 940 2355 39.9


line stmt bran cond sub pod time code
1             /**
2             * perl-libxml-sax.c
3             * $Id$
4             *
5             * This is free software, you may use it and distribute it under the same terms as
6             * Perl itself.
7             *
8             * Copyright 2001-2003 AxKit.com Ltd., 2002-2006 Christian Glahn, 2006-2009 Petr Pajas
9             */
10              
11             #ifdef __cplusplus
12             extern "C" {
13             #endif
14             /* Disable this and use a threaded perl to test MSVC compilation errors */
15             #define PERL_NO_GET_CONTEXT /* we want efficiency */
16              
17             #include "EXTERN.h"
18             #include "perl.h"
19             #include "XSUB.h"
20             #include "ppport.h"
21              
22             #include
23             #include
24             #include
25             #include
26             #include
27             #include
28             #include
29              
30             #include "perl-libxml-sax.h"
31              
32             #ifdef __cplusplus
33             }
34             #endif
35              
36              
37             /*
38             we must call CLEAR_SERROR_HANDLER upon each excurse from
39             perl
40             */
41             #define WITH_SERRORS
42              
43             #ifdef WITH_SERRORS
44             #define CLEAR_SERROR_HANDLER /*xmlSetStructuredErrorFunc(NULL,NULL);*/
45             #else
46             #define CLEAR_SERROR_HANDLER
47             #endif
48              
49             #define NSDELIM ':'
50             /* #define NSDEFAULTURI "http://www.w3.org/XML/1998/namespace" */
51             #define NSDEFAULTURI "http://www.w3.org/2000/xmlns/"
52             typedef struct {
53             SV * parser;
54             xmlNodePtr ns_stack;
55             HV * locator;
56             xmlDocPtr ns_stack_root;
57             SV * handler;
58             SV * saved_error;
59             struct CBuffer *charbuf;
60             int joinchars;
61             } PmmSAXVector;
62              
63             typedef PmmSAXVector* PmmSAXVectorPtr;
64              
65             struct CBufferChunk {
66             struct CBufferChunk *next;
67             xmlChar *data;
68             int len;
69             };
70              
71             struct CBuffer {
72             struct CBufferChunk *head;
73             struct CBufferChunk *tail;
74             };
75              
76             static U32 PrefixHash; /* pre-computed */
77             static U32 NsURIHash;
78             static U32 NameHash;
79             static U32 LocalNameHash;
80             static U32 AttributesHash;
81             static U32 ValueHash;
82             static U32 DataHash;
83             static U32 TargetHash;
84             static U32 VersionHash;
85             static U32 EncodingHash;
86             static U32 PublicIdHash;
87             static U32 SystemIdHash;
88              
89             /* helper function C2Sv is ment to work faster than the perl-libxml-mm
90             version. this shortcut is useful, because SAX handles only UTF8
91             strings, so there is no conversion logic required.
92             */
93             SV*
94 1761           _C2Sv( const xmlChar *string, const xmlChar *dummy )
95             {
96              
97             dTHX;
98 1761           SV *retval = &PL_sv_undef;
99             STRLEN len;
100              
101 1761 50         if ( string != NULL ) {
102 1761           len = xmlStrlen( string );
103 1761           retval = NEWSV(0, len+1);
104 1761           sv_setpvn(retval, (const char *)string, len );
105             #ifdef HAVE_UTF8
106 1761           SvUTF8_on( retval );
107             #endif
108             }
109              
110 1761           return retval;
111             }
112              
113             SV*
114 113           _C2Sv_len( const xmlChar *string, int len )
115             {
116              
117             dTHX;
118 113           SV *retval = &PL_sv_undef;
119              
120 113 50         if ( string != NULL ) {
121 113           retval = NEWSV(0, len+1);
122 113           sv_setpvn(retval, (const char *)string, (STRLEN) len );
123             #ifdef HAVE_UTF8
124 113           SvUTF8_on( retval );
125             #endif
126             }
127              
128 113           return retval;
129             }
130              
131             void
132 66           PmmSAXInitialize(pTHX)
133             {
134 66           PERL_HASH(PrefixHash, "Prefix", 6);
135 66           PERL_HASH(NsURIHash, "NamespaceURI", 12);
136 66           PERL_HASH(NameHash, "Name", 4);
137 66           PERL_HASH(LocalNameHash, "LocalName", 9);
138 66           PERL_HASH(AttributesHash, "Attributes", 10);
139 66           PERL_HASH(ValueHash, "Value", 5);
140 66           PERL_HASH(DataHash, "Data", 4);
141 66           PERL_HASH(TargetHash, "Target", 6);
142 66           PERL_HASH(VersionHash, "Version", 7);
143 66           PERL_HASH(EncodingHash, "Encoding", 8);
144 66           PERL_HASH(PublicIdHash, "PublicId", 8);
145 66           PERL_HASH(SystemIdHash, "SystemId", 8);
146 66           }
147              
148             xmlSAXHandlerPtr PSaxGetHandler();
149             int PSaxCharactersFlush(void *, struct CBuffer *);
150              
151              
152             /* Character buffering functions */
153              
154 0           struct CBufferChunk * CBufferChunkNew(void) {
155 0           struct CBufferChunk *newchunk = xmlMalloc(sizeof(struct CBufferChunk));
156 0           memset(newchunk, 0, sizeof(struct CBufferChunk));
157 0           return newchunk;
158             }
159              
160 0           struct CBuffer * CBufferNew(void) {
161 0           struct CBuffer *new = xmlMalloc(sizeof(struct CBuffer));
162 0           struct CBufferChunk *newchunk = CBufferChunkNew();
163              
164 0           memset(new, 0, sizeof(struct CBuffer));
165              
166 0           new->head = newchunk;
167 0           new->tail = newchunk;
168              
169 0           return new;
170             }
171              
172 0           void CBufferPurge(struct CBuffer *buffer) {
173             struct CBufferChunk *p1;
174             struct CBufferChunk *p2;
175              
176 0 0         if (buffer == NULL || buffer->head->data == NULL) {
    0          
177 0           return;
178             }
179              
180 0 0         if ((p1 = buffer->head)) {
181              
182 0 0         while(p1) {
183 0           p2 = p1->next;
184              
185 0 0         if (p1->data) {
186 0           xmlFree(p1->data);
187             }
188              
189 0           xmlFree(p1);
190              
191 0           p1 = p2;
192             }
193             }
194              
195 0           buffer->head = CBufferChunkNew();
196 0           buffer->tail = buffer->head;
197             }
198              
199 102           void CBufferFree(struct CBuffer *buffer) {
200             struct CBufferChunk *p1;
201             struct CBufferChunk *p2;
202              
203 102 50         if (buffer == NULL) {
204 102           return;
205             }
206              
207 0 0         if ((p1 = buffer->head)) {
208              
209 0 0         while(p1) {
210 0           p2 = p1->next;
211              
212 0 0         if (p1->data) {
213 0           xmlFree(p1->data);
214             }
215              
216 0           xmlFree(p1);
217              
218 0           p1 = p2;
219             }
220             }
221              
222 0           xmlFree(buffer);
223              
224 0           return;
225             }
226              
227 0           int CBufferLength(struct CBuffer *buffer) {
228 0           int length = 0;
229             struct CBufferChunk *cur;
230              
231 0 0         for(cur = buffer->head; cur; cur = cur->next) {
232 0           length += cur->len;
233             }
234              
235 0           return length;
236             }
237              
238 0           void CBufferAppend(struct CBuffer *buffer, const xmlChar *newstring, int len) {
239 0           xmlChar *copy = xmlMalloc(len);
240              
241 0           memcpy(copy, newstring, len);
242              
243 0           buffer->tail->data = copy;
244 0           buffer->tail->len = len;
245 0           buffer->tail->next = CBufferChunkNew();
246 0           buffer->tail = buffer->tail->next;
247 0           }
248              
249 0           xmlChar * CBufferCharacters(struct CBuffer *buffer) {
250 0           int length = CBufferLength(buffer);
251 0           xmlChar *new = xmlMalloc(length + 1);
252 0           xmlChar *p = new;
253 0           int copied = 0;
254             struct CBufferChunk *cur;
255              
256             /* We need this because stderr on some perls requires
257             * my_perl. See:
258             *
259             * https://rt.cpan.org/Public/Bug/Display.html?id=69082
260             *
261             * */
262             dTHX;
263              
264 0 0         if (buffer->head->data == NULL) {
265 0           return NULL;
266             }
267              
268 0 0         for(cur = buffer->head;cur;cur = cur->next) {
269 0 0         if (! cur->data) {
270 0           continue;
271             }
272              
273 0 0         if ((copied = copied + cur->len) > length) {
274 0           fprintf(stderr, "string overflow\n");
275 0           abort();
276             }
277              
278 0           memcpy(p, cur->data, cur->len);
279 0           p += cur->len;
280             }
281              
282 0           new[length] = '\0';
283              
284 0           return new;
285             }
286              
287             /* end character buffering functions */
288              
289              
290             void
291 103           PmmSAXInitContext( xmlParserCtxtPtr ctxt, SV * parser, SV * saved_error )
292             {
293 103           PmmSAXVectorPtr vec = NULL;
294             SV ** th;
295             SV ** joinchars;
296              
297             dTHX;
298              
299             CLEAR_SERROR_HANDLER
300 103           vec = (PmmSAXVector*) xmlMalloc( sizeof(PmmSAXVector) );
301              
302 103           vec->ns_stack_root = xmlNewDoc(NULL);
303 103           vec->ns_stack = xmlNewDocNode(vec->ns_stack_root,
304             NULL,
305             (const xmlChar*)"stack",
306             NULL );
307              
308 103           xmlAddChild((xmlNodePtr)vec->ns_stack_root, vec->ns_stack);
309              
310 103           vec->locator = NULL;
311              
312 103           vec->saved_error = saved_error;
313              
314 103           vec->parser = SvREFCNT_inc( parser );
315 103           th = hv_fetch( (HV*)SvRV(parser), "HANDLER", 7, 0 );
316 103 50         if ( th != NULL && SvTRUE(*th) ) {
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
317 103           vec->handler = SvREFCNT_inc(*th) ;
318             }
319             else {
320 0           vec->handler = NULL;
321             }
322              
323 103           joinchars = hv_fetch((HV*)SvRV(parser), "JOIN_CHARACTERS", 15, 0);
324              
325 103 100         if (joinchars != NULL) {
326 40 50         vec->joinchars = (SvIV(*joinchars));
327             } else {
328 63           vec->joinchars = 0;
329             }
330              
331 103 50         if (vec->joinchars) {
332 0           vec->charbuf = CBufferNew();
333             } else {
334 103           vec->charbuf = NULL;
335             }
336              
337 103 50         if ( ctxt->sax ) {
338 103           xmlFree( ctxt->sax );
339             }
340 103           ctxt->sax = PSaxGetHandler();
341              
342 103           ctxt->_private = (void*)vec;
343 103           }
344              
345             void
346 102           PmmSAXCloseContext( xmlParserCtxtPtr ctxt )
347             {
348 102           PmmSAXVector * vec = (PmmSAXVectorPtr) ctxt->_private;
349             dTHX;
350              
351 102 50         if ( vec->handler != NULL ) {
352 102           SvREFCNT_dec( vec->handler );
353 102           vec->handler = NULL;
354             }
355              
356 102           CBufferFree(vec->charbuf);
357 102           vec->charbuf = NULL;
358              
359 102           xmlFree( ctxt->sax );
360 102           ctxt->sax = NULL;
361              
362 102           SvREFCNT_dec( vec->parser );
363 102           vec->parser = NULL;
364              
365 102           xmlFreeDoc( vec->ns_stack_root );
366 102           vec->ns_stack_root = NULL;
367              
368 102 100         if ( vec->locator != NULL ) {
369 73           SvREFCNT_dec( vec->locator );
370 73           vec->locator = NULL;
371             }
372              
373 102           xmlFree( vec );
374 102           ctxt->_private = NULL;
375 102           }
376              
377              
378             xmlNsPtr
379 310           PmmGetNsMapping( xmlNodePtr ns_stack, const xmlChar * prefix )
380             {
381 310 50         if ( ns_stack != NULL ) {
382 310           return xmlSearchNs( ns_stack->doc, ns_stack, prefix );
383             }
384              
385 0           return NULL;
386             }
387              
388              
389             void
390 35           PSaxStartPrefix( PmmSAXVectorPtr sax, const xmlChar * prefix,
391             const xmlChar * uri, SV * handler )
392             {
393             dTHX;
394             HV * param;
395             SV * rv;
396              
397 35           dSP;
398              
399 35           ENTER;
400 35           SAVETMPS;
401              
402 35           param = newHV();
403              
404 35           (void) hv_store(param, "NamespaceURI", 12,
405             _C2Sv(uri, NULL), NsURIHash);
406              
407 35 100         if ( prefix != NULL ) {
408 31           (void) hv_store(param, "Prefix", 6,
409             _C2Sv(prefix, NULL), PrefixHash);
410             }
411             else {
412 4           (void) hv_store(param, "Prefix", 6,
413             _C2Sv((const xmlChar*)"", NULL), PrefixHash);
414             }
415              
416 35 50         PUSHMARK(SP) ;
417 35 50         XPUSHs(handler);
418              
419 35           rv = newRV_noinc((SV*)param);
420              
421 35 50         XPUSHs(rv);
422 35           PUTBACK;
423              
424 35           call_method( "start_prefix_mapping", G_SCALAR | G_EVAL | G_DISCARD );
425 35           sv_2mortal(rv);
426 35 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
427 0           croak_obj;
428             }
429 35 50         FREETMPS ;
430 35           LEAVE ;
431             CLEAR_SERROR_HANDLER
432 35           }
433              
434             void
435 35           PSaxEndPrefix( PmmSAXVectorPtr sax, const xmlChar * prefix,
436             const xmlChar * uri, SV * handler )
437             {
438             dTHX;
439             HV * param;
440             SV * rv;
441              
442 35           dSP;
443              
444 35           ENTER;
445 35           SAVETMPS;
446 35           param = newHV();
447 35           (void) hv_store(param, "NamespaceURI", 12,
448             _C2Sv(uri, NULL), NsURIHash);
449              
450 35 100         if ( prefix != NULL ) {
451 31           (void) hv_store(param, "Prefix", 6,
452             _C2Sv(prefix, NULL), PrefixHash);
453             }
454             else {
455 4           (void) hv_store(param, "Prefix", 6,
456             _C2Sv((const xmlChar *)"", NULL), PrefixHash);
457             }
458              
459 35 50         PUSHMARK(SP) ;
460 35 50         XPUSHs(handler);
461              
462              
463 35           rv = newRV_noinc((SV*)param);
464              
465 35 50         XPUSHs(rv);
466 35           PUTBACK;
467              
468 35           call_method( "end_prefix_mapping", G_SCALAR | G_EVAL | G_DISCARD );
469 35           sv_2mortal(rv);
470 35 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
471 0           croak_obj;
472             }
473              
474 35 50         FREETMPS ;
475 35           LEAVE ;
476             CLEAR_SERROR_HANDLER
477 35           }
478              
479             void
480 151           PmmExtendNsStack( PmmSAXVectorPtr sax , const xmlChar * name) {
481 151           xmlNodePtr newNS = NULL;
482 151           xmlChar * localname = NULL;
483 151           xmlChar * prefix = NULL;
484              
485 151           localname = xmlSplitQName( NULL, name, &prefix );
486 151 100         if ( prefix != NULL ) {
487             /* check if we can find a namespace with that prefix... */
488 26           xmlNsPtr ns = xmlSearchNs( sax->ns_stack->doc, sax->ns_stack, prefix );
489              
490 26 100         if ( ns != NULL ) {
491 16           newNS = xmlNewDocNode( sax->ns_stack_root, ns, localname, NULL );
492             }
493             else {
494 26           newNS = xmlNewDocNode( sax->ns_stack_root, NULL, name, NULL );
495             }
496             }
497             else {
498 125           newNS = xmlNewDocNode( sax->ns_stack_root, NULL, name, NULL );
499             }
500              
501 151 50         if ( newNS != NULL ) {
502 151           xmlAddChild(sax->ns_stack, newNS);
503 151           sax->ns_stack = newNS;
504             }
505              
506 151 50         if ( localname != NULL ) {
507 151           xmlFree( localname ) ;
508             }
509 151 100         if ( prefix != NULL ) {
510 26           xmlFree( prefix );
511             }
512 151           }
513              
514             void
515 146           PmmNarrowNsStack( PmmSAXVectorPtr sax, SV *handler )
516             {
517 146           xmlNodePtr parent = sax->ns_stack->parent;
518 146           xmlNsPtr list = sax->ns_stack->nsDef;
519              
520 181 100         while ( list ) {
521 35 50         if ( !xmlStrEqual(list->prefix, (const xmlChar*)"xml") ) {
522 35           PSaxEndPrefix( sax, list->prefix, list->href, handler );
523             }
524 35           list = list->next;
525             }
526 146           xmlUnlinkNode(sax->ns_stack);
527 146           xmlFreeNode(sax->ns_stack);
528 146           sax->ns_stack = parent;
529 146           }
530              
531             void
532 35           PmmAddNamespace( PmmSAXVectorPtr sax, const xmlChar * name,
533             const xmlChar * href, SV *handler)
534             {
535 35           xmlNsPtr ns = NULL;
536 35           xmlChar * prefix = NULL;
537 35           xmlChar * localname = NULL;
538              
539              
540 35 50         if ( sax->ns_stack == NULL ) {
541 0           return;
542             }
543              
544 35           ns = xmlNewNs( sax->ns_stack, href, name );
545              
546 35 100         if ( sax->ns_stack->ns == NULL ) {
547 33           localname = xmlSplitQName( NULL, sax->ns_stack->name, &prefix );
548              
549 33 100         if ( name != NULL ) {
550 29 100         if ( xmlStrEqual( prefix , name ) ) {
551 10           xmlChar * oname = (xmlChar*)(sax->ns_stack->name);
552 10           sax->ns_stack->ns = ns;
553 10           xmlFree( oname );
554 29           sax->ns_stack->name = (const xmlChar*) xmlStrdup( localname );
555             }
556             }
557 4 50         else if ( prefix == NULL ) {
558 4           sax->ns_stack->ns = ns;
559             }
560             }
561              
562 35 100         if ( prefix ) {
563 22           xmlFree( prefix );
564             }
565 35 100         if ( localname ) {
566 33           xmlFree( localname );
567             }
568              
569 35           PSaxStartPrefix( sax, name, href, handler );
570             }
571              
572             #define XML_STR_NOT_EMPTY(s) ((s)[0] != 0)
573              
574             HV *
575 297           PmmGenElementSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar * name )
576             {
577 297           HV * retval = newHV();
578 297           xmlChar * localname = NULL;
579 297           xmlChar * prefix = NULL;
580              
581 297           xmlNsPtr ns = NULL;
582              
583 297 50         if ( name != NULL && XML_STR_NOT_EMPTY( name ) ) {
    50          
584 297           (void) hv_store(retval, "Name", 4,
585             _C2Sv(name, NULL), NameHash);
586              
587 297           localname = xmlSplitQName(NULL, name, &prefix);
588 297 50         if (localname != NULL) xmlFree(localname);
589 297           ns = PmmGetNsMapping( sax->ns_stack, prefix );
590 297 100         if (prefix != NULL) xmlFree(prefix);
591              
592 297 100         if ( ns != NULL ) {
593 82           (void) hv_store(retval, "NamespaceURI", 12,
594             _C2Sv(ns->href, NULL), NsURIHash);
595 82 100         if ( ns->prefix ) {
596 52           (void) hv_store(retval, "Prefix", 6,
597             _C2Sv(ns->prefix, NULL), PrefixHash);
598             }
599             else {
600 30           (void) hv_store(retval, "Prefix", 6,
601             _C2Sv((const xmlChar *)"",NULL), PrefixHash);
602             }
603              
604 82           (void) hv_store(retval, "LocalName", 9,
605             _C2Sv(sax->ns_stack->name, NULL), LocalNameHash);
606             }
607             else {
608 215           (void) hv_store(retval, "NamespaceURI", 12,
609             _C2Sv((const xmlChar *)"",NULL), NsURIHash);
610 215           (void) hv_store(retval, "Prefix", 6,
611             _C2Sv((const xmlChar *)"",NULL), PrefixHash);
612 215           (void) hv_store(retval, "LocalName", 9,
613             _C2Sv(name, NULL), LocalNameHash);
614             }
615             }
616              
617 297           return retval;
618             }
619              
620             xmlChar *
621 69           PmmGenNsName( const xmlChar * name, const xmlChar * nsURI )
622             {
623 69           int namelen = 0;
624 69           int urilen = 0;
625 69           xmlChar * retval = NULL;
626              
627 69 50         if ( name == NULL ) {
628 0           return NULL;
629             }
630 69           namelen = xmlStrlen( name );
631              
632 69           retval = xmlStrncat( retval, (const xmlChar *)"{", 1 );
633 69 100         if ( nsURI != NULL ) {
634 43           urilen = xmlStrlen( nsURI );
635 43           retval = xmlStrncat( retval, nsURI, urilen );
636             }
637 69           retval = xmlStrncat( retval, (const xmlChar *)"}", 1 );
638 69           retval = xmlStrncat( retval, name, namelen );
639 69           return retval;
640             }
641              
642             HV *
643 151           PmmGenAttributeHashSV( pTHX_ PmmSAXVectorPtr sax,
644             const xmlChar **attr, SV * handler )
645             {
646 151           HV * retval = NULL;
647 151           HV * atV = NULL;
648 151           xmlNsPtr ns = NULL;
649              
650 151           U32 atnameHash = 0;
651 151           int len = 0;
652              
653 151           const xmlChar * nsURI = NULL;
654 151           const xmlChar **ta = attr;
655 151           const xmlChar * name = NULL;
656 151           const xmlChar * value = NULL;
657              
658 151           xmlChar * keyname = NULL;
659 151           xmlChar * localname = NULL;
660 151           xmlChar * prefix = NULL;
661              
662 151           retval = newHV();
663              
664 151 100         if ( ta != NULL ) {
665 112 100         while ( *ta != NULL ) {
666 69           atV = newHV();
667 69           name = *ta; ta++;
668 69           value = *ta; ta++;
669              
670 69 50         if ( name != NULL && XML_STR_NOT_EMPTY( name ) ) {
    50          
671 69           localname = xmlSplitQName(NULL, name, &prefix);
672              
673 69           (void) hv_store(atV, "Name", 4,
674             _C2Sv(name, NULL), NameHash);
675 69 50         if ( value != NULL ) {
676 69           (void) hv_store(atV, "Value", 5,
677             _C2Sv(value, NULL), ValueHash);
678             }
679              
680 69 100         if ( xmlStrEqual( (const xmlChar *)"xmlns", name ) ) {
681             /* a default namespace */
682 4           PmmAddNamespace( sax, NULL, value, handler);
683             /* nsURI = (const xmlChar*)NSDEFAULTURI; */
684 4           nsURI = NULL;
685 4           (void) hv_store(atV, "Name", 4,
686             _C2Sv(name, NULL), NameHash);
687              
688 4           (void) hv_store(atV, "Prefix", 6,
689             _C2Sv((const xmlChar *)"", NULL), PrefixHash);
690 4           (void) hv_store(atV, "LocalName", 9,
691             _C2Sv(name,NULL), LocalNameHash);
692 4           (void) hv_store(atV, "NamespaceURI", 12,
693             _C2Sv((const xmlChar *)"", NULL), NsURIHash);
694              
695             }
696 65 100         else if (xmlStrncmp((const xmlChar *)"xmlns:", name, 6 ) == 0 ) {
697 31           PmmAddNamespace( sax,
698             localname,
699             value,
700             handler);
701              
702 31           nsURI = (const xmlChar*)NSDEFAULTURI;
703              
704 31           (void) hv_store(atV, "Prefix", 6,
705             _C2Sv(prefix, NULL), PrefixHash);
706 31           (void) hv_store(atV, "LocalName", 9,
707             _C2Sv(localname, NULL), LocalNameHash);
708 31           (void) hv_store(atV, "NamespaceURI", 12,
709             _C2Sv((const xmlChar *)NSDEFAULTURI,NULL),
710             NsURIHash);
711             }
712 34 100         else if ( prefix != NULL
713 13 100         && (ns = PmmGetNsMapping( sax->ns_stack, prefix ) ) ) {
714 12           nsURI = ns->href;
715              
716 12           (void) hv_store(atV, "NamespaceURI", 12,
717             _C2Sv(ns->href, NULL), NsURIHash);
718 12           (void) hv_store(atV, "Prefix", 6,
719             _C2Sv(ns->prefix, NULL), PrefixHash);
720 12           (void) hv_store(atV, "LocalName", 9,
721             _C2Sv(localname, NULL), LocalNameHash);
722             }
723             else {
724 22           nsURI = NULL;
725 22           (void) hv_store(atV, "NamespaceURI", 12,
726             _C2Sv((const xmlChar *)"", NULL), NsURIHash);
727 22           (void) hv_store(atV, "Prefix", 6,
728             _C2Sv((const xmlChar *)"", NULL), PrefixHash);
729 22           (void) hv_store(atV, "LocalName", 9,
730             _C2Sv(name, NULL), LocalNameHash);
731             }
732              
733 69 50         keyname = PmmGenNsName( localname != NULL ? localname : name,
734             nsURI );
735              
736 69           len = xmlStrlen( keyname );
737 69           PERL_HASH( atnameHash, (const char *)keyname, len );
738 69           (void) hv_store(retval,
739             (const char *)keyname,
740             len,
741             newRV_noinc((SV*)atV),
742             atnameHash );
743              
744 69 50         if ( keyname != NULL ) {
745 69           xmlFree( keyname );
746             }
747 69 50         if ( localname != NULL ) {
748 69           xmlFree(localname);
749             }
750 69           localname = NULL;
751 69 100         if ( prefix != NULL ) {
752 44           xmlFree( prefix );
753             }
754 69           prefix = NULL;
755              
756             }
757             }
758             }
759              
760 151           return retval;
761             }
762              
763             HV *
764 116           PmmGenCharDataSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar * data, int len )
765             {
766 116           HV * retval = newHV();
767              
768 116 50         if ( data != NULL && XML_STR_NOT_EMPTY( data ) ) {
    100          
769 113           (void) hv_store(retval, "Data", 4,
770             _C2Sv_len(data, len), DataHash);
771             }
772              
773 116           return retval;
774             }
775              
776             HV *
777 0           PmmGenPISV( pTHX_ PmmSAXVectorPtr sax,
778             const xmlChar * target,
779             const xmlChar * data )
780             {
781 0           HV * retval = newHV();
782              
783 0 0         if ( target != NULL && XML_STR_NOT_EMPTY( target ) ) {
    0          
784 0           (void) hv_store(retval, "Target", 6,
785             _C2Sv(target, NULL), TargetHash);
786              
787 0 0         if ( data != NULL && XML_STR_NOT_EMPTY( data ) ) {
    0          
788 0           (void) hv_store(retval, "Data", 4,
789             _C2Sv(data, NULL), DataHash);
790             }
791             else {
792 0           (void) hv_store(retval, "Data", 4,
793             _C2Sv((const xmlChar *)"", NULL), DataHash);
794             }
795             }
796              
797 0           return retval;
798             }
799              
800             HV *
801 9           PmmGenDTDSV( pTHX_ PmmSAXVectorPtr sax,
802             const xmlChar * name,
803             const xmlChar * publicId,
804             const xmlChar * systemId )
805             {
806 9           HV * retval = newHV();
807 9 50         if ( name != NULL && XML_STR_NOT_EMPTY( name ) ) {
    50          
808 9           (void) hv_store(retval, "Name", 4,
809             _C2Sv(name, NULL), NameHash);
810             }
811 9 50         if ( publicId != NULL && XML_STR_NOT_EMPTY( publicId ) ) {
    0          
812 0           (void) hv_store(retval, "PublicId", 8,
813             _C2Sv(publicId, NULL), PublicIdHash);
814             }
815 9 50         if ( systemId != NULL && XML_STR_NOT_EMPTY( systemId ) ) {
    0          
816 0           (void) hv_store(retval, "SystemId", 8,
817             _C2Sv(systemId, NULL), SystemIdHash);
818             }
819 9           return retval;
820             }
821              
822             HV *
823 74           PmmGenLocator( xmlSAXLocatorPtr loc)
824             {
825             dTHX;
826 74           HV * locator = newHV();
827              
828 74           const xmlChar * PublicId = loc->getPublicId(NULL);
829 74           const xmlChar * SystemId = loc->getSystemId(NULL);
830              
831 74 50         if ( PublicId != NULL && XML_STR_NOT_EMPTY( PublicId ) ) {
    0          
832 0           (void) hv_store(locator, "PublicId", 8,
833             newSVpv((char *)PublicId, 0), 0);
834             }
835              
836 74 50         if ( SystemId != NULL && XML_STR_NOT_EMPTY( SystemId ) ) {
    0          
837 0           (void) hv_store(locator, "SystemId", 8,
838             newSVpv((char *)SystemId, 0), 0);
839             }
840              
841 74           return locator;
842             }
843              
844              
845             void
846 496           PmmUpdateLocator( xmlParserCtxtPtr ctxt )
847             {
848             dTHX;
849             const xmlChar * encoding;
850             const xmlChar * version;
851 496           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
852              
853 496 100         if (sax->locator == NULL) {
854 105           return;
855             }
856              
857 391           (void) hv_store(sax->locator, "LineNumber", 10,
858             newSViv(ctxt->input->line), 0);
859              
860 391           (void) hv_store(sax->locator, "ColumnNumber", 12,
861             newSViv(ctxt->input->col), 0);
862              
863 391           encoding = ctxt->input->encoding;
864 391           version = ctxt->input->version;
865              
866 391 100         if ( encoding != NULL && XML_STR_NOT_EMPTY( encoding ) ) {
    50          
867 3           (void) hv_store(sax->locator, "Encoding", 8,
868             newSVpv((char *)encoding, 0), 0);
869             }
870              
871 391 50         if ( version != NULL && XML_STR_NOT_EMPTY( version ) ) {
    0          
872 0           (void) hv_store(sax->locator, "XMLVersion", 10,
873             newSVpv((char *)version, 0), 0);
874             }
875             }
876              
877             int
878 74           PSaxSetDocumentLocator(void *ctx, xmlSAXLocatorPtr loc)
879             {
880 74           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
881 74           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
882             dTHX;
883             HV* empty;
884 74           SV * handler = sax->handler;
885             SV * rv;
886              
887 74           dSP;
888              
889 74 50         if (sax->joinchars)
890             {
891 0           PSaxCharactersFlush(ctxt, sax->charbuf);
892             }
893              
894 74           ENTER;
895 74           SAVETMPS;
896              
897 74 50         PUSHMARK(SP) ;
898              
899 74 50         XPUSHs(handler);
900              
901 74           sax->locator = PmmGenLocator(loc);
902              
903 74           rv = newRV_inc((SV*)sax->locator);
904 74 50         XPUSHs( rv);
905              
906 74           PUTBACK;
907              
908 74           call_method( "set_document_locator", G_SCALAR | G_EVAL | G_DISCARD );
909 74           sv_2mortal(rv) ;
910              
911 74 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
912 0           croak_obj;
913             }
914              
915 74 50         FREETMPS ;
916 74           LEAVE ;
917             CLEAR_SERROR_HANDLER
918 74           return 1;
919             }
920              
921             int
922 74           PSaxStartDocument(void * ctx)
923             {
924 74           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
925 74           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
926             dTHX;
927             HV* empty;
928 74           SV * handler = sax->handler;
929              
930             SV * rv;
931 74 50         if ( handler != NULL ) {
932              
933 74           dSP;
934 74           PmmUpdateLocator(ctx);
935              
936 74           ENTER;
937 74           SAVETMPS;
938              
939 74           empty = newHV();
940 74 50         PUSHMARK(SP) ;
941 74 50         XPUSHs(handler);
942 74 50         XPUSHs(sv_2mortal(newRV_noinc((SV*)empty)));
943 74           PUTBACK;
944              
945 74           call_method( "start_document", G_SCALAR | G_EVAL | G_DISCARD );
946 74 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
947 0           croak_obj;
948             }
949              
950 74           SPAGAIN;
951              
952 74 50         PUSHMARK(SP) ;
953              
954              
955 74 50         XPUSHs(handler);
956              
957 74           empty = newHV();
958 74 50         if ( ctxt->version != NULL ) {
959 74           (void) hv_store(empty, "Version", 7,
960             _C2Sv(ctxt->version, NULL), VersionHash);
961             }
962             else {
963 0           (void) hv_store(empty, "Version", 7,
964             _C2Sv((const xmlChar *)"1.0", NULL), VersionHash);
965             }
966              
967 74 100         if ( ctxt->input->encoding != NULL ) {
968 1           (void) hv_store(empty, "Encoding", 8,
969             _C2Sv(ctxt->input->encoding, NULL), EncodingHash);
970             }
971              
972 74           rv = newRV_noinc((SV*)empty);
973 74 50         XPUSHs( rv);
974              
975 74           PUTBACK;
976              
977 74           call_method( "xml_decl", G_SCALAR | G_EVAL | G_DISCARD );
978             CLEAR_SERROR_HANDLER
979 74           sv_2mortal(rv);
980 74 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
981 0           croak_obj;
982             }
983              
984 74 50         FREETMPS ;
985 74           LEAVE ;
986             }
987             CLEAR_SERROR_HANDLER
988 74           return 1;
989             }
990              
991             int
992 0           PSaxEndDocument(void * ctx)
993             {
994 0           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
995 0           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
996              
997             dTHX;
998 0           dSP;
999              
1000 0           PmmUpdateLocator(ctx);
1001              
1002 0 0         if (sax->joinchars)
1003             {
1004 0           PSaxCharactersFlush(ctxt, sax->charbuf);
1005             }
1006              
1007              
1008 0           ENTER;
1009 0           SAVETMPS;
1010              
1011 0 0         PUSHMARK(SP) ;
1012 0 0         XPUSHs(sax->parser);
1013 0           PUTBACK;
1014              
1015 0           call_pv( "XML::LibXML::_SAXParser::end_document", G_SCALAR | G_EVAL | G_DISCARD );
1016 0 0         if (SvTRUE(ERRSV)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1017 0           croak_obj;
1018             }
1019              
1020 0 0         FREETMPS ;
1021 0           LEAVE ;
1022             CLEAR_SERROR_HANDLER
1023 0           return 1;
1024             }
1025              
1026             int
1027 151           PSaxStartElement(void *ctx, const xmlChar * name, const xmlChar** attr)
1028             {
1029 151           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1030 151           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1031             dTHX;
1032 151           HV * attrhash = NULL;
1033 151           HV * element = NULL;
1034 151           SV * handler = sax->handler;
1035             SV * rv;
1036             SV * arv;
1037              
1038 151           dSP;
1039              
1040 151           PmmUpdateLocator(ctx);
1041              
1042 151 50         if (sax->joinchars)
1043             {
1044 0           PSaxCharactersFlush(ctxt, sax->charbuf);
1045             }
1046              
1047 151           ENTER;
1048 151           SAVETMPS;
1049              
1050 151           PmmExtendNsStack(sax, name);
1051              
1052 151           attrhash = PmmGenAttributeHashSV(aTHX_ sax, attr, handler );
1053 151           element = PmmGenElementSV(aTHX_ sax, name);
1054              
1055 151           arv = newRV_noinc((SV*)attrhash);
1056 151           (void) hv_store( element,
1057             "Attributes",
1058             10,
1059             arv,
1060             AttributesHash );
1061              
1062 151 50         PUSHMARK(SP) ;
1063              
1064 151 50         XPUSHs(handler);
1065 151           rv = newRV_noinc((SV*)element);
1066 151 50         XPUSHs(rv);
1067 151           PUTBACK;
1068              
1069 151           call_method( "start_element", G_SCALAR | G_EVAL | G_DISCARD );
1070 151           sv_2mortal(rv) ;
1071              
1072 151 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
1073 1           croak_obj;
1074             }
1075              
1076 150 50         FREETMPS ;
1077 150           LEAVE ;
1078             CLEAR_SERROR_HANDLER
1079 150           return 1;
1080             }
1081              
1082             int
1083 146           PSaxEndElement(void *ctx, const xmlChar * name) {
1084 146           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1085 146           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1086             dTHX;
1087 146           SV * handler = sax->handler;
1088             SV * rv;
1089             HV * element;
1090              
1091 146           dSP;
1092              
1093 146           PmmUpdateLocator(ctx);
1094              
1095 146 50         if (sax->joinchars)
1096             {
1097 0           PSaxCharactersFlush(ctxt, sax->charbuf);
1098             }
1099              
1100 146           ENTER;
1101 146           SAVETMPS;
1102              
1103 146 50         PUSHMARK(SP) ;
1104 146 50         XPUSHs(handler);
1105              
1106 146           element = PmmGenElementSV(aTHX_ sax, name);
1107 146           rv = newRV_noinc((SV*)element);
1108              
1109 146 50         XPUSHs(rv);
1110 146           PUTBACK;
1111              
1112 146           call_method( "end_element", G_SCALAR | G_EVAL | G_DISCARD );
1113 146           sv_2mortal(rv);
1114              
1115 146 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
1116 0           croak_obj;
1117             }
1118              
1119 146 50         FREETMPS ;
1120 146           LEAVE ;
1121              
1122 146           PmmNarrowNsStack(sax, handler);
1123             CLEAR_SERROR_HANDLER
1124 146           return 1;
1125             }
1126              
1127             int
1128 89           PSaxCharactersDispatch(void *ctx, const xmlChar * ch, int len) {
1129 89           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1130 89           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1131             dTHX;
1132             HV* element;
1133             SV * handler;
1134 89           SV * rv = NULL;
1135              
1136 89 50         if ( sax == NULL ) {
1137             /* warn( "lost my sax context!? ( %s, %d )\n", ch, len ); */
1138 0           return 0;
1139             }
1140              
1141 89           handler = sax->handler;
1142              
1143 89 50         if ( ch != NULL && handler != NULL ) {
    50          
1144              
1145 89           dSP;
1146              
1147 89           ENTER;
1148 89           SAVETMPS;
1149              
1150 89 50         PUSHMARK(SP) ;
1151              
1152 89 50         XPUSHs(handler);
1153 89           element = PmmGenCharDataSV(aTHX_ sax, ch, len );
1154              
1155 89           rv = newRV_noinc((SV*)element);
1156 89 50         XPUSHs(rv);
1157 89           sv_2mortal(rv);
1158              
1159 89           PUTBACK;
1160              
1161 89           call_method( "characters", G_SCALAR | G_EVAL | G_DISCARD );
1162              
1163 89 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
1164 0           croak_obj;
1165             }
1166 89 50         FREETMPS ;
1167 89           LEAVE ;
1168              
1169             }
1170             CLEAR_SERROR_HANDLER;
1171 89           return 1;
1172             }
1173              
1174 0           int PSaxCharactersFlush (void *ctx, struct CBuffer *buffer) {
1175 0           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1176 0           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1177             xmlChar *ch;
1178             int len;
1179              
1180 0 0         if (buffer->head->data == NULL) {
1181 0           return 1;
1182             }
1183              
1184 0           ch = CBufferCharacters(sax->charbuf);
1185 0           len = CBufferLength(sax->charbuf);
1186              
1187 0           CBufferPurge(buffer);
1188              
1189 0           return PSaxCharactersDispatch(ctx, ch, len);
1190             }
1191              
1192 89           int PSaxCharacters (void *ctx, const xmlChar * ch, int len) {
1193 89           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1194 89           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1195              
1196 89           PmmUpdateLocator(ctx);
1197              
1198 89 50         if (sax->joinchars) {
1199 0           struct CBuffer *buffer = sax->charbuf;
1200 0           CBufferAppend(buffer, ch, len);
1201 0           return 1;
1202             }
1203              
1204 89           return PSaxCharactersDispatch(ctx, ch, len);
1205             }
1206              
1207             int
1208 15           PSaxComment(void *ctx, const xmlChar * ch) {
1209 15           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1210 15           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1211             dTHX;
1212             HV* element;
1213 15           SV * handler = sax->handler;
1214 15           SV * rv = NULL;
1215              
1216 15           PmmUpdateLocator(ctx);
1217              
1218 15 50         if ( ch != NULL && handler != NULL ) {
    50          
1219 15           dSP;
1220              
1221 15           int len = xmlStrlen( ch );
1222              
1223 15 50         if (sax->joinchars)
1224             {
1225 0           PSaxCharactersFlush(ctxt, sax->charbuf);
1226             }
1227              
1228 15           ENTER;
1229 15           SAVETMPS;
1230              
1231 15 50         PUSHMARK(SP) ;
1232 15 50         XPUSHs(handler);
1233 15           element = PmmGenCharDataSV(aTHX_ sax, ch, len);
1234              
1235 15           rv = newRV_noinc((SV*)element);
1236 15 50         XPUSHs(rv);
1237 15           PUTBACK;
1238              
1239 15           call_method( "comment", G_SCALAR | G_EVAL | G_DISCARD );
1240 15           sv_2mortal(rv);
1241              
1242 15 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
1243 0           croak_obj;
1244             }
1245              
1246 15 50         FREETMPS ;
1247 15           LEAVE ;
1248             }
1249             CLEAR_SERROR_HANDLER
1250 15           return 1;
1251             }
1252              
1253             int
1254 12           PSaxCDATABlock(void *ctx, const xmlChar * ch, int len) {
1255 12           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1256 12           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1257             dTHX;
1258             HV* element;
1259 12           SV * handler = sax->handler;
1260 12           SV * rv = NULL;
1261              
1262 12           PmmUpdateLocator(ctx);
1263              
1264 12 50         if ( ch != NULL && handler != NULL ) {
    50          
1265 12           dSP;
1266              
1267 12 50         if (sax->joinchars)
1268             {
1269 0           PSaxCharactersFlush(ctxt, sax->charbuf);
1270             }
1271              
1272              
1273 12           ENTER;
1274 12           SAVETMPS;
1275              
1276 12 50         PUSHMARK(SP) ;
1277 12 50         XPUSHs(handler);
1278 12           PUTBACK;
1279 12           call_method( "start_cdata", G_SCALAR | G_EVAL | G_DISCARD );
1280 12 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
1281 0           croak_obj;
1282             }
1283              
1284 12           SPAGAIN;
1285 12 50         PUSHMARK(SP) ;
1286              
1287 12 50         XPUSHs(handler);
1288 12           element = PmmGenCharDataSV(aTHX_ sax, ch, len);
1289              
1290 12           rv = newRV_noinc((SV*)element);
1291 12 50         XPUSHs(rv);
1292 12           PUTBACK;
1293              
1294 12           call_method( "characters", G_SCALAR | G_EVAL | G_DISCARD);
1295 12 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
1296 0           croak_obj;
1297             }
1298              
1299 12           SPAGAIN;
1300 12 50         PUSHMARK(SP) ;
1301              
1302 12 50         XPUSHs(handler);
1303 12           PUTBACK;
1304              
1305 12           call_method( "end_cdata", G_SCALAR | G_EVAL | G_DISCARD );
1306 12           sv_2mortal(rv);
1307              
1308 12 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
1309 0           croak_obj;
1310             }
1311              
1312 12 50         FREETMPS ;
1313 12           LEAVE ;
1314              
1315             }
1316             CLEAR_SERROR_HANDLER
1317 12           return 1;
1318              
1319             }
1320              
1321             int
1322 0           PSaxProcessingInstruction( void * ctx, const xmlChar * target, const xmlChar * data )
1323             {
1324 0           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1325 0           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1326             dTHX;
1327 0           SV * handler = sax->handler;
1328             SV * element;
1329 0           SV * rv = NULL;
1330              
1331 0           PmmUpdateLocator(ctx);
1332              
1333 0 0         if ( handler != NULL ) {
1334 0           dSP;
1335              
1336 0 0         if (sax->joinchars)
1337             {
1338 0           PSaxCharactersFlush(ctxt, sax->charbuf);
1339             }
1340              
1341 0           ENTER;
1342 0           SAVETMPS;
1343              
1344 0 0         PUSHMARK(SP) ;
1345 0 0         XPUSHs(handler);
1346 0           element = (SV*)PmmGenPISV(aTHX_ sax, (const xmlChar *)target, data);
1347 0           rv = newRV_noinc((SV*)element);
1348 0 0         XPUSHs(rv);
1349              
1350 0           PUTBACK;
1351              
1352 0           call_method( "processing_instruction", G_SCALAR | G_EVAL | G_DISCARD );
1353              
1354 0           sv_2mortal(rv);
1355              
1356 0 0         if (SvTRUE(ERRSV)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1357 0           croak_obj;
1358             }
1359              
1360 0 0         FREETMPS ;
1361 0           LEAVE ;
1362             }
1363             CLEAR_SERROR_HANDLER
1364 0           return 1;
1365             }
1366              
1367 9           void PSaxExternalSubset (void * ctx,
1368             const xmlChar * name,
1369             const xmlChar * ExternalID,
1370             const xmlChar * SystemID)
1371             {
1372 9           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1373 9           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1374              
1375             dTHX;
1376 9           SV * handler = sax->handler;
1377             SV * element;
1378 9           SV * rv = NULL;
1379              
1380 9           PmmUpdateLocator(ctx);
1381              
1382 9 50         if ( handler != NULL ) {
1383 9           dSP;
1384              
1385 9           ENTER;
1386 9           SAVETMPS;
1387              
1388 9 50         PUSHMARK(SP) ;
1389 9 50         XPUSHs(handler);
1390 9           element = (SV*)PmmGenDTDSV(aTHX_ sax,
1391             name,
1392             ExternalID,
1393             SystemID);
1394 9           rv = newRV_noinc((SV*)element);
1395 9 50         XPUSHs(rv);
1396              
1397 9           PUTBACK;
1398              
1399 9           call_method( "start_dtd", G_SCALAR | G_EVAL | G_DISCARD );
1400 9           sv_2mortal(rv);
1401              
1402 9 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
1403 0           croak_obj;
1404             }
1405              
1406 9 50         PUSHMARK(SP) ;
1407 9 50         XPUSHs(handler);
1408 9           rv = newRV_noinc((SV*)newHV()); /* empty */
1409 9 50         XPUSHs(rv);
1410              
1411 9           PUTBACK;
1412              
1413 9           call_method( "end_dtd", G_SCALAR | G_EVAL | G_DISCARD );
1414              
1415 9 50         FREETMPS ;
1416 9           LEAVE ;
1417             }
1418             CLEAR_SERROR_HANDLER
1419 9           return;
1420             }
1421              
1422              
1423             /*
1424              
1425             void PSaxInternalSubset (void * ctx,
1426             const xmlChar * name,
1427             const xmlChar * ExternalID,
1428             const xmlChar * SystemID)
1429             {
1430             // called before ExternalSubset
1431             // if used, how do we generate the correct start_dtd ?
1432             }
1433              
1434             void PSaxElementDecl (void *ctx, const xmlChar *name,
1435             int type,
1436             xmlElementContentPtr content) {
1437             // this one is not easy to implement
1438             // since libxml2 has no (reliable) public method
1439             // for dumping xmlElementContent :-(
1440             }
1441              
1442             void
1443             PSaxAttributeDecl (void * ctx,
1444             const xmlChar * elem,
1445             const xmlChar * fullname,
1446             int type,
1447             int def,
1448             const xmlChar * defaultValue,
1449             xmlEnumerationPtr tree)
1450             {
1451             }
1452              
1453             void
1454             PSaxEntityDecl (void * ctx,
1455             const xmlChar * name,
1456             int type,
1457             const xmlChar * publicId,
1458             const xmlChar * systemId,
1459             xmlChar * content)
1460             {
1461             }
1462              
1463             void
1464             PSaxNotationDecl (void * ctx,
1465             const xmlChar * name,
1466             const xmlChar * publicId,
1467             const xmlChar * systemId)
1468             {
1469             }
1470              
1471             void
1472             PSaxUnparsedEntityDecl (void * ctx,
1473             const xmlChar * name,
1474             const xmlChar * publicId,
1475             const xmlChar * systemId,
1476             const xmlChar * notationName)
1477             {
1478             }
1479             */
1480              
1481             int
1482 0           PmmSaxWarning(void * ctx, const char * msg, ...)
1483             {
1484 0           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1485 0           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1486              
1487             va_list args;
1488             SV * svMessage;
1489              
1490             dTHX;
1491 0           dSP;
1492 0           svMessage = NEWSV(0,512);
1493              
1494 0           va_start(args, msg);
1495 0           sv_vsetpvfn(svMessage,
1496             msg,
1497             xmlStrlen((const xmlChar *)msg),
1498             &args,
1499             NULL,
1500             0,
1501             NULL);
1502 0           va_end(args);
1503              
1504 0           ENTER;
1505 0           SAVETMPS;
1506              
1507 0 0         PUSHMARK(SP) ;
1508 0 0         XPUSHs(sax->parser);
1509              
1510 0 0         XPUSHs(sv_2mortal(svMessage));
1511 0 0         XPUSHs(sv_2mortal(newSViv(ctxt->input->line)));
1512 0 0         XPUSHs(sv_2mortal(newSViv(ctxt->input->col)));
1513              
1514 0           PUTBACK;
1515              
1516 0           call_pv( "XML::LibXML::_SAXParser::warning", G_SCALAR | G_EVAL | G_DISCARD );
1517              
1518 0 0         if (SvTRUE(ERRSV)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1519 0           croak_obj;
1520             }
1521              
1522 0 0         FREETMPS ;
1523 0           LEAVE ;
1524             CLEAR_SERROR_HANDLER
1525 0           return 1;
1526             }
1527              
1528              
1529             int
1530 1           PmmSaxError(void * ctx, const char * msg, ...)
1531             {
1532 1           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1533 1           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1534              
1535             va_list args;
1536             SV * svMessage;
1537              
1538             #if LIBXML_VERSION > 20600
1539 1           xmlErrorPtr last_err = xmlCtxtGetLastError( ctxt );
1540             #endif
1541             dTHX;
1542 1           dSP;
1543              
1544 1           ENTER;
1545 1           SAVETMPS;
1546              
1547 1 50         PUSHMARK(SP) ;
1548              
1549 1 50         XPUSHs(sax->parser);
1550              
1551 1           svMessage = NEWSV(0,512);
1552              
1553 1           va_start(args, msg);
1554 1           sv_vsetpvfn(svMessage, msg, xmlStrlen((const xmlChar *)msg), &args, NULL, 0, NULL);
1555 1           va_end(args);
1556 1 50         if (SvOK(sax->saved_error)) {
    50          
    50          
1557 0           sv_catsv( sax->saved_error, svMessage );
1558             } else {
1559 1           sv_setsv( sax->saved_error, svMessage );
1560             }
1561 1 50         XPUSHs(sv_2mortal(svMessage));
1562 1 50         XPUSHs(sv_2mortal(newSViv(ctxt->input->line)));
1563 1 50         XPUSHs(sv_2mortal(newSViv(ctxt->input->col)));
1564              
1565 1           PUTBACK;
1566             #if LIBXML_VERSION > 20600
1567             /*
1568             this is a workaround: at least some versions of libxml2 didn't not call
1569             the fatalError callback at all
1570             */
1571 1 50         if (last_err && last_err->level == XML_ERR_FATAL) {
    50          
1572 1           call_pv( "XML::LibXML::_SAXParser::fatal_error", G_SCALAR | G_EVAL | G_DISCARD );
1573             } else {
1574 0           call_pv( "XML::LibXML::_SAXParser::error", G_SCALAR | G_EVAL | G_DISCARD );
1575             }
1576             #else
1577             /* actually, we do not know if it is a fatal error or not */
1578             call_pv( "XML::LibXML::_SAXParser::fatal_error", G_SCALAR | G_EVAL | G_DISCARD );
1579             #endif
1580 1 50         if (SvTRUE(ERRSV)) {
    50          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
1581 0           croak_obj;
1582             }
1583              
1584 1 50         FREETMPS ;
1585 1           LEAVE ;
1586             CLEAR_SERROR_HANDLER
1587 1           return 1;
1588             }
1589              
1590              
1591             int
1592 0           PmmSaxFatalError(void * ctx, const char * msg, ...)
1593             {
1594 0           xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
1595 0           PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
1596              
1597             va_list args;
1598             SV * svMessage;
1599              
1600             dTHX;
1601 0           dSP;
1602              
1603 0           svMessage = NEWSV(0,512);
1604              
1605 0           va_start(args, msg);
1606 0           sv_vsetpvfn(svMessage, msg, xmlStrlen((const xmlChar *)msg), &args, NULL, 0, NULL);
1607 0           va_end(args);
1608              
1609 0           ENTER;
1610 0           SAVETMPS;
1611              
1612 0 0         PUSHMARK(SP) ;
1613 0 0         XPUSHs(sax->parser);
1614              
1615 0 0         if (SvOK(sax->saved_error)) {
    0          
    0          
1616 0           sv_catsv( sax->saved_error, svMessage );
1617             } else {
1618 0           sv_setsv( sax->saved_error, svMessage );
1619             }
1620              
1621 0 0         XPUSHs(sv_2mortal(svMessage));
1622 0 0         XPUSHs(sv_2mortal(newSViv(ctxt->input->line)));
1623 0 0         XPUSHs(sv_2mortal(newSViv(ctxt->input->col)));
1624              
1625 0           PUTBACK;
1626 0           call_pv( "XML::LibXML::_SAXParser::fatal_error", G_SCALAR | G_EVAL | G_DISCARD );
1627 0 0         if (SvTRUE(ERRSV)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1628 0           croak_obj;
1629             }
1630              
1631 0 0         FREETMPS ;
1632 0           LEAVE ;
1633             CLEAR_SERROR_HANDLER
1634 0           return 1;
1635             }
1636              
1637             /* NOTE:
1638             * end document is not handled by the parser itself! use
1639             * XML::LibXML::SAX instead!
1640             */
1641             xmlSAXHandlerPtr
1642 133           PSaxGetHandler()
1643             {
1644 133           xmlSAXHandlerPtr retval = (xmlSAXHandlerPtr)xmlMalloc(sizeof(xmlSAXHandler));
1645 133           memset(retval, 0, sizeof(xmlSAXHandler));
1646              
1647 133           retval->setDocumentLocator = (setDocumentLocatorSAXFunc)&PSaxSetDocumentLocator;
1648              
1649 133           retval->startDocument = (startDocumentSAXFunc)&PSaxStartDocument;
1650              
1651             /* libxml2 will not handle perls returnvalue correctly, so we have
1652             * to end the document ourselfes
1653             */
1654 133           retval->endDocument = NULL; /* (endDocumentSAXFunc)&PSaxEndDocument; */
1655              
1656 133           retval->startElement = (startElementSAXFunc)&PSaxStartElement;
1657 133           retval->endElement = (endElementSAXFunc)&PSaxEndElement;
1658              
1659 133           retval->characters = (charactersSAXFunc)&PSaxCharacters;
1660 133           retval->ignorableWhitespace = (ignorableWhitespaceSAXFunc)&PSaxCharacters;
1661              
1662 133           retval->comment = (commentSAXFunc)&PSaxComment;
1663 133           retval->cdataBlock = (cdataBlockSAXFunc)&PSaxCDATABlock;
1664              
1665 133           retval->processingInstruction = (processingInstructionSAXFunc)&PSaxProcessingInstruction;
1666              
1667             /* warning functions should be internal */
1668 133           retval->warning = (warningSAXFunc)&PmmSaxWarning;
1669 133           retval->error = (errorSAXFunc)&PmmSaxError;
1670 133           retval->fatalError = (fatalErrorSAXFunc)&PmmSaxFatalError;
1671              
1672 133           retval->externalSubset = (externalSubsetSAXFunc)&PSaxExternalSubset;
1673              
1674             /*
1675             retval->internalSubset = (internalSubsetSAXFunc)&PSaxInternalSubset;
1676             retval->elementDecl = (elementDeclSAXFunc)&PSaxElementDecl;
1677             retval->entityDecl = (entityDeclSAXFunc)&PSaxEntityDecl;
1678             retval->notationDecl = (notationDeclSAXFunc)&PSaxNotationDecl;
1679             retval->attributeDecl = (attributeDeclSAXFunc)&PSaxAttributeDecl;
1680             retval->unparsedEntityDecl = (unparsedEntityDeclSAXFunc)&PSaxUnparsedEntityDecl;
1681             */
1682              
1683 133           return retval;
1684             }
1685