SAX.c revision 3473f88a7abdf4e585e267288fb77e898c580d2b
1/*
2 * SAX.c : Default SAX handler to build a tree.
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <Daniel.Veillard@w3.org>
7 */
8
9
10#ifdef WIN32
11#include "win32config.h"
12#else
13#include "config.h"
14#endif
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <libxml/xmlmemory.h>
19#include <libxml/tree.h>
20#include <libxml/parser.h>
21#include <libxml/parserInternals.h>
22#include <libxml/valid.h>
23#include <libxml/entities.h>
24#include <libxml/xmlerror.h>
25#include <libxml/debugXML.h>
26#include <libxml/xmlIO.h>
27#include <libxml/SAX.h>
28#include <libxml/uri.h>
29#include <libxml/HTMLtree.h>
30
31/* #define DEBUG_SAX */
32/* #define DEBUG_SAX_TREE */
33
34/**
35 * getPublicId:
36 * @ctx: the user data (XML parser context)
37 *
38 * Return the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
39 *
40 * Returns a xmlChar *
41 */
42const xmlChar *
43getPublicId(void *ctx)
44{
45    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
46    return(NULL);
47}
48
49/**
50 * getSystemId:
51 * @ctx: the user data (XML parser context)
52 *
53 * Return the system ID, basically URL or filename e.g.
54 * http://www.sgmlsource.com/dtds/memo.dtd
55 *
56 * Returns a xmlChar *
57 */
58const xmlChar *
59getSystemId(void *ctx)
60{
61    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
62    return(BAD_CAST ctxt->input->filename);
63}
64
65/**
66 * getLineNumber:
67 * @ctx: the user data (XML parser context)
68 *
69 * Return the line number of the current parsing point.
70 *
71 * Returns an int
72 */
73int
74getLineNumber(void *ctx)
75{
76    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
77    return(ctxt->input->line);
78}
79
80/**
81 * getColumnNumber:
82 * @ctx: the user data (XML parser context)
83 *
84 * Return the column number of the current parsing point.
85 *
86 * Returns an int
87 */
88int
89getColumnNumber(void *ctx)
90{
91    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
92    return(ctxt->input->col);
93}
94
95/*
96 * The default SAX Locator.
97 */
98
99xmlSAXLocator xmlDefaultSAXLocator = {
100    getPublicId, getSystemId, getLineNumber, getColumnNumber
101};
102
103/**
104 * isStandalone:
105 * @ctx: the user data (XML parser context)
106 *
107 * Is this document tagged standalone ?
108 *
109 * Returns 1 if true
110 */
111int
112isStandalone(void *ctx)
113{
114    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
115    return(ctxt->myDoc->standalone == 1);
116}
117
118/**
119 * hasInternalSubset:
120 * @ctx: the user data (XML parser context)
121 *
122 * Does this document has an internal subset
123 *
124 * Returns 1 if true
125 */
126int
127hasInternalSubset(void *ctx)
128{
129    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
130    return(ctxt->myDoc->intSubset != NULL);
131}
132
133/**
134 * hasExternalSubset:
135 * @ctx: the user data (XML parser context)
136 *
137 * Does this document has an external subset
138 *
139 * Returns 1 if true
140 */
141int
142hasExternalSubset(void *ctx)
143{
144    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
145    return(ctxt->myDoc->extSubset != NULL);
146}
147
148/**
149 * internalSubset:
150 * @ctx:  the user data (XML parser context)
151 * @name:  the root element name
152 * @ExternalID:  the external ID
153 * @SystemID:  the SYSTEM ID (e.g. filename or URL)
154 *
155 * Callback on internal subset declaration.
156 */
157void
158internalSubset(void *ctx, const xmlChar *name,
159	       const xmlChar *ExternalID, const xmlChar *SystemID)
160{
161    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
162    xmlDtdPtr dtd;
163#ifdef DEBUG_SAX
164    xmlGenericError(xmlGenericErrorContext,
165	    "SAX.internalSubset(%s, %s, %s)\n",
166            name, ExternalID, SystemID);
167#endif
168
169    if (ctxt->myDoc == NULL)
170	return;
171    dtd = xmlGetIntSubset(ctxt->myDoc);
172    if (dtd != NULL) {
173	if (ctxt->html)
174	    return;
175	xmlUnlinkNode((xmlNodePtr) dtd);
176	xmlFreeDtd(dtd);
177	ctxt->myDoc->intSubset = NULL;
178    }
179    ctxt->myDoc->intSubset =
180	xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
181}
182
183/**
184 * externalSubset:
185 * @ctx: the user data (XML parser context)
186 * @name:  the root element name
187 * @ExternalID:  the external ID
188 * @SystemID:  the SYSTEM ID (e.g. filename or URL)
189 *
190 * Callback on external subset declaration.
191 */
192void
193externalSubset(void *ctx, const xmlChar *name,
194	       const xmlChar *ExternalID, const xmlChar *SystemID)
195{
196    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
197#ifdef DEBUG_SAX
198    xmlGenericError(xmlGenericErrorContext,
199	    "SAX.externalSubset(%s, %s, %s)\n",
200            name, ExternalID, SystemID);
201#endif
202    if (((ExternalID != NULL) || (SystemID != NULL)) &&
203        (((ctxt->validate) || (ctxt->loadsubset)) &&
204	 (ctxt->wellFormed && ctxt->myDoc))) {
205	/*
206	 * Try to fetch and parse the external subset.
207	 */
208	xmlParserInputPtr oldinput;
209	int oldinputNr;
210	int oldinputMax;
211	xmlParserInputPtr *oldinputTab;
212	int oldwellFormed;
213	xmlParserInputPtr input = NULL;
214	xmlCharEncoding enc;
215	int oldcharset;
216
217	/*
218	 * Ask the Entity resolver to load the damn thing
219	 */
220	if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
221	    input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
222	                                        SystemID);
223	if (input == NULL) {
224	    return;
225	}
226
227	xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
228
229	/*
230	 * make sure we won't destroy the main document context
231	 */
232	oldinput = ctxt->input;
233	oldinputNr = ctxt->inputNr;
234	oldinputMax = ctxt->inputMax;
235	oldinputTab = ctxt->inputTab;
236	oldwellFormed = ctxt->wellFormed;
237	oldcharset = ctxt->charset;
238
239	ctxt->inputTab = (xmlParserInputPtr *)
240	                 xmlMalloc(5 * sizeof(xmlParserInputPtr));
241	if (ctxt->inputTab == NULL) {
242	    ctxt->errNo = XML_ERR_NO_MEMORY;
243	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
244		ctxt->sax->error(ctxt->userData,
245		     "externalSubset: out of memory\n");
246	    ctxt->errNo = XML_ERR_NO_MEMORY;
247	    ctxt->input = oldinput;
248	    ctxt->inputNr = oldinputNr;
249	    ctxt->inputMax = oldinputMax;
250	    ctxt->inputTab = oldinputTab;
251	    ctxt->charset = oldcharset;
252	    return;
253	}
254	ctxt->inputNr = 0;
255	ctxt->inputMax = 5;
256	ctxt->input = NULL;
257	xmlPushInput(ctxt, input);
258
259	/*
260	 * On the fly encoding conversion if needed
261	 */
262	enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
263	xmlSwitchEncoding(ctxt, enc);
264
265	if (input->filename == NULL)
266	    input->filename = (char *) xmlStrdup(SystemID);
267	input->line = 1;
268	input->col = 1;
269	input->base = ctxt->input->cur;
270	input->cur = ctxt->input->cur;
271	input->free = NULL;
272
273	/*
274	 * let's parse that entity knowing it's an external subset.
275	 */
276	xmlParseExternalSubset(ctxt, ExternalID, SystemID);
277
278        /*
279	 * Free up the external entities
280	 */
281
282	while (ctxt->inputNr > 1)
283	    xmlPopInput(ctxt);
284	xmlFreeInputStream(ctxt->input);
285        xmlFree(ctxt->inputTab);
286
287	/*
288	 * Restore the parsing context of the main entity
289	 */
290	ctxt->input = oldinput;
291	ctxt->inputNr = oldinputNr;
292	ctxt->inputMax = oldinputMax;
293	ctxt->inputTab = oldinputTab;
294	ctxt->charset = oldcharset;
295	/* ctxt->wellFormed = oldwellFormed; */
296    }
297}
298
299/**
300 * resolveEntity:
301 * @ctx: the user data (XML parser context)
302 * @publicId: The public ID of the entity
303 * @systemId: The system ID of the entity
304 *
305 * The entity loader, to control the loading of external entities,
306 * the application can either:
307 *    - override this resolveEntity() callback in the SAX block
308 *    - or better use the xmlSetExternalEntityLoader() function to
309 *      set up it's own entity resolution routine
310 *
311 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
312 */
313xmlParserInputPtr
314resolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
315{
316    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
317    xmlParserInputPtr ret;
318    xmlChar *URI;
319    const char *base = NULL;
320
321    if (ctxt->input != NULL)
322	base = ctxt->input->filename;
323    if (base == NULL)
324	base = ctxt->directory;
325
326    URI = xmlBuildURI(systemId, (const xmlChar *) base);
327
328#ifdef DEBUG_SAX
329    xmlGenericError(xmlGenericErrorContext,
330	    "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
331#endif
332
333    ret = xmlLoadExternalEntity((const char *) URI,
334				(const char *) publicId, ctxt);
335    if (URI != NULL)
336	xmlFree(URI);
337    return(ret);
338}
339
340/**
341 * getEntity:
342 * @ctx: the user data (XML parser context)
343 * @name: The entity name
344 *
345 * Get an entity by name
346 *
347 * Returns the xmlEntityPtr if found.
348 */
349xmlEntityPtr
350getEntity(void *ctx, const xmlChar *name)
351{
352    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
353    xmlEntityPtr ret;
354
355#ifdef DEBUG_SAX
356    xmlGenericError(xmlGenericErrorContext,
357	    "SAX.getEntity(%s)\n", name);
358#endif
359
360    ret = xmlGetDocEntity(ctxt->myDoc, name);
361    if ((ret != NULL) && (ctxt->validate) && (ret->children == NULL) &&
362	(ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
363	/*
364	 * for validation purposes we really need to fetch and
365	 * parse the external entity
366	 */
367	int parse;
368	xmlNodePtr children;
369
370        parse = xmlParseCtxtExternalEntity(ctxt,
371		  ret->SystemID, ret->ExternalID, &children);
372	xmlAddChildList((xmlNodePtr) ret, children);
373    }
374    return(ret);
375}
376
377/**
378 * getParameterEntity:
379 * @ctx: the user data (XML parser context)
380 * @name: The entity name
381 *
382 * Get a parameter entity by name
383 *
384 * Returns the xmlEntityPtr if found.
385 */
386xmlEntityPtr
387getParameterEntity(void *ctx, const xmlChar *name)
388{
389    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
390    xmlEntityPtr ret;
391
392#ifdef DEBUG_SAX
393    xmlGenericError(xmlGenericErrorContext,
394	    "SAX.getParameterEntity(%s)\n", name);
395#endif
396
397    ret = xmlGetParameterEntity(ctxt->myDoc, name);
398    return(ret);
399}
400
401
402/**
403 * entityDecl:
404 * @ctx: the user data (XML parser context)
405 * @name:  the entity name
406 * @type:  the entity type
407 * @publicId: The public ID of the entity
408 * @systemId: The system ID of the entity
409 * @content: the entity value (without processing).
410 *
411 * An entity definition has been parsed
412 */
413void
414entityDecl(void *ctx, const xmlChar *name, int type,
415          const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
416{
417    xmlEntityPtr ent;
418    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
419
420#ifdef DEBUG_SAX
421    xmlGenericError(xmlGenericErrorContext,
422	    "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
423            name, type, publicId, systemId, content);
424#endif
425    if (ctxt->inSubset == 1) {
426	ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
427		              systemId, content);
428	if ((ent == NULL) && (ctxt->pedantic) &&
429	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
430	    ctxt->sax->warning(ctxt,
431	     "Entity(%s) already defined in the internal subset\n", name);
432	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
433	    xmlChar *URI;
434	    const char *base = NULL;
435
436	    if (ctxt->input != NULL)
437		base = ctxt->input->filename;
438	    if (base == NULL)
439		base = ctxt->directory;
440
441	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
442	    ent->URI = URI;
443	}
444    } else if (ctxt->inSubset == 2) {
445	ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
446		              systemId, content);
447	if ((ent == NULL) && (ctxt->pedantic) &&
448	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
449	    ctxt->sax->warning(ctxt,
450	     "Entity(%s) already defined in the external subset\n", name);
451	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
452	    xmlChar *URI;
453	    const char *base = NULL;
454
455	    if (ctxt->input != NULL)
456		base = ctxt->input->filename;
457	    if (base == NULL)
458		base = ctxt->directory;
459
460	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
461	    ent->URI = URI;
462	}
463    } else {
464	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
465	    ctxt->sax->error(ctxt,
466	     "SAX.entityDecl(%s) called while not in subset\n", name);
467    }
468}
469
470/**
471 * attributeDecl:
472 * @ctx: the user data (XML parser context)
473 * @elem:  the name of the element
474 * @fullname:  the attribute name
475 * @type:  the attribute type
476 * @def:  the type of default value
477 * @defaultValue: the attribute default value
478 * @tree:  the tree of enumerated value set
479 *
480 * An attribute definition has been parsed
481 */
482void
483attributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
484              int type, int def, const xmlChar *defaultValue,
485	      xmlEnumerationPtr tree)
486{
487    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
488    xmlAttributePtr attr;
489    xmlChar *name = NULL, *prefix = NULL;
490
491#ifdef DEBUG_SAX
492    xmlGenericError(xmlGenericErrorContext,
493	    "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
494            elem, fullname, type, def, defaultValue);
495#endif
496    name = xmlSplitQName(ctxt, fullname, &prefix);
497    if (ctxt->inSubset == 1)
498	attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
499	       name, prefix, (xmlAttributeType) type,
500	       (xmlAttributeDefault) def, defaultValue, tree);
501    else if (ctxt->inSubset == 2)
502	attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
503	   name, prefix, (xmlAttributeType) type,
504	   (xmlAttributeDefault) def, defaultValue, tree);
505    else {
506	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
507	    ctxt->sax->error(ctxt,
508	     "SAX.attributeDecl(%s) called while not in subset\n", name);
509	return;
510    }
511    if (attr == 0) ctxt->valid = 0;
512    if (ctxt->validate && ctxt->wellFormed &&
513        ctxt->myDoc && ctxt->myDoc->intSubset)
514	ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
515	                                        attr);
516    if (prefix != NULL)
517	xmlFree(prefix);
518    if (name != NULL)
519	xmlFree(name);
520}
521
522/**
523 * elementDecl:
524 * @ctx: the user data (XML parser context)
525 * @name:  the element name
526 * @type:  the element type
527 * @content: the element value tree
528 *
529 * An element definition has been parsed
530 */
531void
532elementDecl(void *ctx, const xmlChar *name, int type,
533	    xmlElementContentPtr content)
534{
535    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
536    xmlElementPtr elem = NULL;
537
538#ifdef DEBUG_SAX
539    xmlGenericError(xmlGenericErrorContext,
540	    "SAX.elementDecl(%s, %d, ...)\n",
541            fullname, type);
542#endif
543
544    if (ctxt->inSubset == 1)
545	elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
546                             name, (xmlElementTypeVal) type, content);
547    else if (ctxt->inSubset == 2)
548	elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
549                             name, (xmlElementTypeVal) type, content);
550    else {
551	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
552	    ctxt->sax->error(ctxt,
553	     "SAX.elementDecl(%s) called while not in subset\n", name);
554	return;
555    }
556    if (elem == NULL) ctxt->valid = 0;
557    if (ctxt->validate && ctxt->wellFormed &&
558        ctxt->myDoc && ctxt->myDoc->intSubset)
559	ctxt->valid &= xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
560}
561
562/**
563 * notationDecl:
564 * @ctx: the user data (XML parser context)
565 * @name: The name of the notation
566 * @publicId: The public ID of the entity
567 * @systemId: The system ID of the entity
568 *
569 * What to do when a notation declaration has been parsed.
570 */
571void
572notationDecl(void *ctx, const xmlChar *name,
573	     const xmlChar *publicId, const xmlChar *systemId)
574{
575    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
576    xmlNotationPtr nota = NULL;
577
578#ifdef DEBUG_SAX
579    xmlGenericError(xmlGenericErrorContext,
580	    "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
581#endif
582
583    if (ctxt->inSubset == 1)
584	nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
585                              publicId, systemId);
586    else if (ctxt->inSubset == 2)
587	nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
588                              publicId, systemId);
589    else {
590	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
591	    ctxt->sax->error(ctxt,
592	     "SAX.notationDecl(%s) called while not in subset\n", name);
593	return;
594    }
595    if (nota == NULL) ctxt->valid = 0;
596    if (ctxt->validate && ctxt->wellFormed &&
597        ctxt->myDoc && ctxt->myDoc->intSubset)
598	ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
599	                                       nota);
600}
601
602/**
603 * unparsedEntityDecl:
604 * @ctx: the user data (XML parser context)
605 * @name: The name of the entity
606 * @publicId: The public ID of the entity
607 * @systemId: The system ID of the entity
608 * @notationName: the name of the notation
609 *
610 * What to do when an unparsed entity declaration is parsed
611 */
612void
613unparsedEntityDecl(void *ctx, const xmlChar *name,
614		   const xmlChar *publicId, const xmlChar *systemId,
615		   const xmlChar *notationName)
616{
617    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
618#ifdef DEBUG_SAX
619    xmlGenericError(xmlGenericErrorContext,
620	    "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
621            name, publicId, systemId, notationName);
622#endif
623    if (ctxt->validate && ctxt->wellFormed &&
624        ctxt->myDoc && ctxt->myDoc->intSubset)
625	ctxt->valid &= xmlValidateNotationUse(&ctxt->vctxt, ctxt->myDoc,
626	                                      notationName);
627    xmlAddDocEntity(ctxt->myDoc, name,
628                    XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
629		    publicId, systemId, notationName);
630}
631
632/**
633 * setDocumentLocator:
634 * @ctx: the user data (XML parser context)
635 * @loc: A SAX Locator
636 *
637 * Receive the document locator at startup, actually xmlDefaultSAXLocator
638 * Everything is available on the context, so this is useless in our case.
639 */
640void
641setDocumentLocator(void *ctx, xmlSAXLocatorPtr loc)
642{
643    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
644#ifdef DEBUG_SAX
645    xmlGenericError(xmlGenericErrorContext,
646	    "SAX.setDocumentLocator()\n");
647#endif
648}
649
650/**
651 * startDocument:
652 * @ctx: the user data (XML parser context)
653 *
654 * called when the document start being processed.
655 */
656void
657startDocument(void *ctx)
658{
659    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
660    xmlDocPtr doc;
661
662#ifdef DEBUG_SAX
663    xmlGenericError(xmlGenericErrorContext,
664	    "SAX.startDocument()\n");
665#endif
666    if (ctxt->html) {
667	if (ctxt->myDoc == NULL)
668#ifdef LIBXML_HTML_ENABLED
669	    ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
670#else
671        xmlGenericError(xmlGenericErrorContext,
672		"libxml2 built without HTML support\n");
673#endif
674    } else {
675	doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
676	if (doc != NULL) {
677	    if (ctxt->encoding != NULL)
678		doc->encoding = xmlStrdup(ctxt->encoding);
679	    else
680		doc->encoding = NULL;
681	    doc->standalone = ctxt->standalone;
682	}
683    }
684    if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
685	(ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
686        ctxt->myDoc->URL = xmlStrdup((xmlChar *) ctxt->input->filename);
687    }
688}
689
690/**
691 * endDocument:
692 * @ctx: the user data (XML parser context)
693 *
694 * called when the document end has been detected.
695 */
696void
697endDocument(void *ctx)
698{
699    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
700#ifdef DEBUG_SAX
701    xmlGenericError(xmlGenericErrorContext,
702	    "SAX.endDocument()\n");
703#endif
704    if (ctxt->validate && ctxt->wellFormed &&
705        ctxt->myDoc && ctxt->myDoc->intSubset)
706	ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc);
707
708    /*
709     * Grab the encoding if it was added on-the-fly
710     */
711    if ((ctxt->encoding != NULL) && (ctxt->myDoc != NULL) &&
712	(ctxt->myDoc->encoding == NULL)) {
713	ctxt->myDoc->encoding = ctxt->encoding;
714	ctxt->encoding = NULL;
715    }
716    if ((ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
717	(ctxt->myDoc->encoding == NULL)) {
718	ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding);
719    }
720    if ((ctxt->charset != XML_CHAR_ENCODING_NONE) && (ctxt->myDoc != NULL) &&
721	(ctxt->myDoc->charset == XML_CHAR_ENCODING_NONE)) {
722	ctxt->myDoc->charset = ctxt->charset;
723    }
724}
725
726/**
727 * attribute:
728 * @ctx: the user data (XML parser context)
729 * @fullname:  The attribute name, including namespace prefix
730 * @value:  The attribute value
731 *
732 * Handle an attribute that has been read by the parser.
733 * The default handling is to convert the attribute into an
734 * DOM subtree and past it in a new xmlAttr element added to
735 * the element.
736 */
737void
738attribute(void *ctx, const xmlChar *fullname, const xmlChar *value)
739{
740    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
741    xmlAttrPtr ret;
742    xmlChar *name;
743    xmlChar *ns;
744    xmlChar *nval;
745    xmlNsPtr namespace;
746
747/****************
748#ifdef DEBUG_SAX
749    xmlGenericError(xmlGenericErrorContext,
750    "SAX.attribute(%s, %s)\n", fullname, value);
751#endif
752 ****************/
753    /*
754     * Split the full name into a namespace prefix and the tag name
755     */
756    name = xmlSplitQName(ctxt, fullname, &ns);
757
758    /*
759     * Do the last stage of the attribute normalization
760     * Needed for HTML too:
761     *   http://www.w3.org/TR/html4/types.html#h-6.2
762     */
763    nval = xmlValidNormalizeAttributeValue(ctxt->myDoc, ctxt->node,
764					   fullname, value);
765    if (nval != NULL)
766	value = nval;
767
768    /*
769     * Check whether it's a namespace definition
770     */
771    if ((!ctxt->html) && (ns == NULL) &&
772        (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
773        (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
774	if (value[0] != 0) {
775	    xmlURIPtr uri;
776
777	    uri = xmlParseURI((const char *)value);
778	    if (uri == NULL) {
779		if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
780		    ctxt->sax->warning(ctxt->userData,
781			 "nmlns: %s not a valid URI\n", value);
782	    } else {
783		if (uri->scheme == NULL) {
784		    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
785			ctxt->sax->warning(ctxt->userData,
786			     "nmlns: URI %s is not absolute\n", value);
787		}
788		xmlFreeURI(uri);
789	    }
790	}
791
792	/* a default namespace definition */
793	xmlNewNs(ctxt->node, value, NULL);
794	if (name != NULL)
795	    xmlFree(name);
796	if (nval != NULL)
797	    xmlFree(nval);
798	return;
799    }
800    if ((!ctxt->html) &&
801	(ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
802        (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
803	/*
804	 * Validate also for namespace decls, they are attributes from
805	 * an XML-1.0 perspective
806	 TODO ... doesn't map well with current API
807        if (ctxt->validate && ctxt->wellFormed &&
808	    ctxt->myDoc && ctxt->myDoc->intSubset)
809	    ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
810					       ctxt->node, ret, value);
811	 */
812	/* a standard namespace definition */
813	xmlNewNs(ctxt->node, value, name);
814	xmlFree(ns);
815	if (name != NULL)
816	    xmlFree(name);
817	if (nval != NULL)
818	    xmlFree(nval);
819	return;
820    }
821
822    if (ns != NULL)
823	namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns);
824    else {
825	namespace = NULL;
826    }
827
828    /* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */
829    ret = xmlNewNsProp(ctxt->node, namespace, name, NULL);
830
831    if (ret != NULL) {
832        if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
833	    xmlNodePtr tmp;
834
835	    ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
836	    tmp = ret->children;
837	    while (tmp != NULL) {
838		tmp->parent = (xmlNodePtr) ret;
839		if (tmp->next == NULL)
840		    ret->last = tmp;
841		tmp = tmp->next;
842	    }
843	} else if (value != NULL) {
844	    ret->children = xmlNewDocText(ctxt->myDoc, value);
845	    ret->last = ret->children;
846	    if (ret->children != NULL)
847		ret->children->parent = (xmlNodePtr) ret;
848	}
849    }
850
851    if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
852        ctxt->myDoc && ctxt->myDoc->intSubset) {
853
854	/*
855	 * If we don't substitute entities, the validation should be
856	 * done on a value with replaced entities anyway.
857	 */
858        if (!ctxt->replaceEntities) {
859	    xmlChar *val;
860
861	    ctxt->depth++;
862	    val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
863		                          0,0,0);
864	    ctxt->depth--;
865	    if (val == NULL)
866		ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
867				ctxt->myDoc, ctxt->node, ret, value);
868	    else {
869		ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
870			        ctxt->myDoc, ctxt->node, ret, val);
871                xmlFree(val);
872	    }
873	} else {
874	    ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
875					       ctxt->node, ret, value);
876	}
877    } else {
878        /*
879	 * when validating, the ID registration is done at the attribute
880	 * validation level. Otherwise we have to do specific handling here.
881	 */
882	if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
883	    xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret);
884	else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
885	    xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret);
886    }
887
888    if (nval != NULL)
889	xmlFree(nval);
890    if (name != NULL)
891	xmlFree(name);
892    if (ns != NULL)
893	xmlFree(ns);
894}
895
896/**
897 * startElement:
898 * @ctx: the user data (XML parser context)
899 * @fullname:  The element name, including namespace prefix
900 * @atts:  An array of name/value attributes pairs, NULL terminated
901 *
902 * called when an opening tag has been processed.
903 */
904void
905startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts)
906{
907    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
908    xmlNodePtr ret;
909    xmlNodePtr parent = ctxt->node;
910    xmlNsPtr ns;
911    xmlChar *name;
912    xmlChar *prefix;
913    const xmlChar *att;
914    const xmlChar *value;
915    int i;
916
917#ifdef DEBUG_SAX
918    xmlGenericError(xmlGenericErrorContext,
919	    "SAX.startElement(%s)\n", fullname);
920#endif
921
922    /*
923     * First check on validity:
924     */
925    if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) &&
926        ((ctxt->myDoc->intSubset == NULL) ||
927	 ((ctxt->myDoc->intSubset->notations == NULL) &&
928	  (ctxt->myDoc->intSubset->elements == NULL) &&
929	  (ctxt->myDoc->intSubset->attributes == NULL) &&
930	  (ctxt->myDoc->intSubset->entities == NULL)))) {
931	if (ctxt->vctxt.error != NULL) {
932            ctxt->vctxt.error(ctxt->vctxt.userData,
933	      "Validation failed: no DTD found !\n");
934	}
935	ctxt->validate = 0;
936    }
937
938
939    /*
940     * Split the full name into a namespace prefix and the tag name
941     */
942    name = xmlSplitQName(ctxt, fullname, &prefix);
943
944
945    /*
946     * Note : the namespace resolution is deferred until the end of the
947     *        attributes parsing, since local namespace can be defined as
948     *        an attribute at this level.
949     */
950    ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
951    if (ret == NULL) return;
952    if (ctxt->myDoc->children == NULL) {
953#ifdef DEBUG_SAX_TREE
954	xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name);
955#endif
956        xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
957    } else if (parent == NULL) {
958        parent = ctxt->myDoc->children;
959    }
960    ctxt->nodemem = -1;
961
962    /*
963     * We are parsing a new node.
964     */
965#ifdef DEBUG_SAX_TREE
966    xmlGenericError(xmlGenericErrorContext, "pushing(%s)\n", name);
967#endif
968    nodePush(ctxt, ret);
969
970    /*
971     * Link the child element
972     */
973    if (parent != NULL) {
974        if (parent->type == XML_ELEMENT_NODE) {
975#ifdef DEBUG_SAX_TREE
976	    xmlGenericError(xmlGenericErrorContext,
977		    "adding child %s to %s\n", name, parent->name);
978#endif
979	    xmlAddChild(parent, ret);
980	} else {
981#ifdef DEBUG_SAX_TREE
982	    xmlGenericError(xmlGenericErrorContext,
983		    "adding sibling %s to ", name);
984	    xmlDebugDumpOneNode(stderr, parent, 0);
985#endif
986	    xmlAddSibling(parent, ret);
987	}
988    }
989
990    /*
991     * process all the attributes whose name start with "xml"
992     */
993    if (atts != NULL) {
994        i = 0;
995	att = atts[i++];
996	value = atts[i++];
997	if (!ctxt->html) {
998	    while ((att != NULL) && (value != NULL)) {
999		if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l'))
1000		    attribute(ctxt, att, value);
1001
1002		att = atts[i++];
1003		value = atts[i++];
1004	    }
1005	}
1006    }
1007
1008    /*
1009     * Search the namespace, note that since the attributes have been
1010     * processed, the local namespaces are available.
1011     */
1012    ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
1013    if ((ns == NULL) && (parent != NULL))
1014	ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
1015    if ((prefix != NULL) && (ns == NULL)) {
1016	ns = xmlNewNs(ret, NULL, prefix);
1017	if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1018	    ctxt->sax->warning(ctxt->userData,
1019		 "Namespace prefix %s is not defined\n", prefix);
1020    }
1021    xmlSetNs(ret, ns);
1022
1023    /*
1024     * process all the other attributes
1025     */
1026    if (atts != NULL) {
1027        i = 0;
1028	att = atts[i++];
1029	value = atts[i++];
1030	if (ctxt->html) {
1031	    while (att != NULL) {
1032		attribute(ctxt, att, value);
1033		att = atts[i++];
1034		value = atts[i++];
1035	    }
1036	} else {
1037	    while ((att != NULL) && (value != NULL)) {
1038		if ((att[0] != 'x') || (att[1] != 'm') || (att[2] != 'l'))
1039		    attribute(ctxt, att, value);
1040
1041		/*
1042		 * Next ones
1043		 */
1044		att = atts[i++];
1045		value = atts[i++];
1046	    }
1047	}
1048    }
1049
1050    /*
1051     * If it's the Document root, finish the Dtd validation and
1052     * check the document root element for validity
1053     */
1054    if ((ctxt->validate) && (ctxt->vctxt.finishDtd == 0)) {
1055	ctxt->valid &= xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
1056	ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
1057	ctxt->vctxt.finishDtd = 1;
1058    }
1059
1060    if (prefix != NULL)
1061	xmlFree(prefix);
1062    if (name != NULL)
1063	xmlFree(name);
1064
1065}
1066
1067/**
1068 * endElement:
1069 * @ctx: the user data (XML parser context)
1070 * @name:  The element name
1071 *
1072 * called when the end of an element has been detected.
1073 */
1074void
1075endElement(void *ctx, const xmlChar *name)
1076{
1077    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1078    xmlParserNodeInfo node_info;
1079    xmlNodePtr cur = ctxt->node;
1080
1081#ifdef DEBUG_SAX
1082    if (name == NULL)
1083        xmlGenericError(xmlGenericErrorContext, "SAX.endElement(NULL)\n");
1084    else
1085	xmlGenericError(xmlGenericErrorContext, "SAX.endElement(%s)\n", name);
1086#endif
1087
1088    /* Capture end position and add node */
1089    if (cur != NULL && ctxt->record_info) {
1090      node_info.end_pos = ctxt->input->cur - ctxt->input->base;
1091      node_info.end_line = ctxt->input->line;
1092      node_info.node = cur;
1093      xmlParserAddNodeInfo(ctxt, &node_info);
1094    }
1095    ctxt->nodemem = -1;
1096
1097    if (ctxt->validate && ctxt->wellFormed &&
1098        ctxt->myDoc && ctxt->myDoc->intSubset)
1099        ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc,
1100					     cur);
1101
1102
1103    /*
1104     * end of parsing of this node.
1105     */
1106#ifdef DEBUG_SAX_TREE
1107    xmlGenericError(xmlGenericErrorContext, "popping(%s)\n", cur->name);
1108#endif
1109    nodePop(ctxt);
1110}
1111
1112/**
1113 * reference:
1114 * @ctx: the user data (XML parser context)
1115 * @name:  The entity name
1116 *
1117 * called when an entity reference is detected.
1118 */
1119void
1120reference(void *ctx, const xmlChar *name)
1121{
1122    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1123    xmlNodePtr ret;
1124
1125#ifdef DEBUG_SAX
1126    xmlGenericError(xmlGenericErrorContext,
1127	    "SAX.reference(%s)\n", name);
1128#endif
1129    if (name[0] == '#')
1130	ret = xmlNewCharRef(ctxt->myDoc, name);
1131    else
1132	ret = xmlNewReference(ctxt->myDoc, name);
1133#ifdef DEBUG_SAX_TREE
1134    xmlGenericError(xmlGenericErrorContext,
1135	    "add reference %s to %s \n", name, ctxt->node->name);
1136#endif
1137    xmlAddChild(ctxt->node, ret);
1138}
1139
1140/**
1141 * characters:
1142 * @ctx: the user data (XML parser context)
1143 * @ch:  a xmlChar string
1144 * @len: the number of xmlChar
1145 *
1146 * receiving some chars from the parser.
1147 * Question: how much at a time ???
1148 */
1149void
1150characters(void *ctx, const xmlChar *ch, int len)
1151{
1152    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1153    xmlNodePtr lastChild;
1154
1155#ifdef DEBUG_SAX
1156    xmlGenericError(xmlGenericErrorContext,
1157	    "SAX.characters(%.30s, %d)\n", ch, len);
1158#endif
1159    /*
1160     * Handle the data if any. If there is no child
1161     * add it as content, otherwise if the last child is text,
1162     * concatenate it, else create a new node of type text.
1163     */
1164
1165    if (ctxt->node == NULL) {
1166#ifdef DEBUG_SAX_TREE
1167	xmlGenericError(xmlGenericErrorContext,
1168		"add chars: ctxt->node == NULL !\n");
1169#endif
1170        return;
1171    }
1172    lastChild = xmlGetLastChild(ctxt->node);
1173#ifdef DEBUG_SAX_TREE
1174    xmlGenericError(xmlGenericErrorContext,
1175	    "add chars to %s \n", ctxt->node->name);
1176#endif
1177
1178    /*
1179     * Here we needed an accelerator mechanism in case of very large
1180     * elements. Use an attribute in the structure !!!
1181     */
1182    if (lastChild == NULL) {
1183	/* first node, first time */
1184	xmlNodeAddContentLen(ctxt->node, ch, len);
1185#ifndef XML_USE_BUFFER_CONTENT
1186	if (ctxt->node->children != NULL) {
1187	    ctxt->nodelen = len;
1188	    ctxt->nodemem = len + 1;
1189	}
1190#endif
1191    } else {
1192	if ((xmlNodeIsText(lastChild)) && (ctxt->nodemem != 0)) {
1193#ifndef XML_USE_BUFFER_CONTENT
1194	    /*
1195	     * The whole point of maintaining nodelen and nodemem,
1196	     * xmlTextConcat is too costly, i.e. compute lenght,
1197	     * reallocate a new buffer, move data, append ch. Here
1198	     * We try to minimaze realloc() uses and avoid copying
1199	     * and recomputing lenght over and over.
1200	     */
1201	    if (ctxt->nodelen + len >= ctxt->nodemem) {
1202		xmlChar *newbuf;
1203		int size;
1204
1205		size = ctxt->nodemem + len;
1206		size *= 2;
1207                newbuf = (xmlChar *) xmlRealloc(lastChild->content,size);
1208		if (newbuf == NULL) {
1209		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1210			ctxt->sax->error(ctxt->userData,
1211			     "SAX.characters(): out of memory\n");
1212		    return;
1213		}
1214		ctxt->nodemem = size;
1215		lastChild->content = newbuf;
1216	    }
1217	    memcpy(&lastChild->content[ctxt->nodelen], ch, len);
1218	    ctxt->nodelen += len;
1219	    lastChild->content[ctxt->nodelen] = 0;
1220#else
1221	    xmlTextConcat(lastChild, ch, len);
1222#endif
1223	} else {
1224	    /* Mixed content, first time */
1225	    lastChild = xmlNewTextLen(ch, len);
1226	    xmlAddChild(ctxt->node, lastChild);
1227#ifndef XML_USE_BUFFER_CONTENT
1228	    if (ctxt->node->children != NULL) {
1229		ctxt->nodelen = len;
1230		ctxt->nodemem = len + 1;
1231	    }
1232#endif
1233	}
1234    }
1235}
1236
1237/**
1238 * ignorableWhitespace:
1239 * @ctx: the user data (XML parser context)
1240 * @ch:  a xmlChar string
1241 * @len: the number of xmlChar
1242 *
1243 * receiving some ignorable whitespaces from the parser.
1244 * Question: how much at a time ???
1245 */
1246void
1247ignorableWhitespace(void *ctx, const xmlChar *ch, int len)
1248{
1249    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1250#ifdef DEBUG_SAX
1251    xmlGenericError(xmlGenericErrorContext,
1252	    "SAX.ignorableWhitespace(%.30s, %d)\n", ch, len);
1253#endif
1254}
1255
1256/**
1257 * processingInstruction:
1258 * @ctx: the user data (XML parser context)
1259 * @target:  the target name
1260 * @data: the PI data's
1261 *
1262 * A processing instruction has been parsed.
1263 */
1264void
1265processingInstruction(void *ctx, const xmlChar *target,
1266                      const xmlChar *data)
1267{
1268    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1269    xmlNodePtr ret;
1270    xmlNodePtr parent = ctxt->node;
1271
1272#ifdef DEBUG_SAX
1273    xmlGenericError(xmlGenericErrorContext,
1274	    "SAX.processingInstruction(%s, %s)\n", target, data);
1275#endif
1276
1277    ret = xmlNewPI(target, data);
1278    if (ret == NULL) return;
1279    parent = ctxt->node;
1280
1281    if (ctxt->inSubset == 1) {
1282	xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
1283	return;
1284    } else if (ctxt->inSubset == 2) {
1285	xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
1286	return;
1287    }
1288    if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
1289#ifdef DEBUG_SAX_TREE
1290	    xmlGenericError(xmlGenericErrorContext,
1291		    "Setting PI %s as root\n", target);
1292#endif
1293        xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
1294	return;
1295    }
1296    if (parent->type == XML_ELEMENT_NODE) {
1297#ifdef DEBUG_SAX_TREE
1298	xmlGenericError(xmlGenericErrorContext,
1299		"adding PI %s child to %s\n", target, parent->name);
1300#endif
1301	xmlAddChild(parent, ret);
1302    } else {
1303#ifdef DEBUG_SAX_TREE
1304	xmlGenericError(xmlGenericErrorContext,
1305		"adding PI %s sibling to ", target);
1306	xmlDebugDumpOneNode(stderr, parent, 0);
1307#endif
1308	xmlAddSibling(parent, ret);
1309    }
1310}
1311
1312/**
1313 * globalNamespace:
1314 * @ctx: the user data (XML parser context)
1315 * @href:  the namespace associated URN
1316 * @prefix: the namespace prefix
1317 *
1318 * An old global namespace has been parsed.
1319 */
1320void
1321globalNamespace(void *ctx, const xmlChar *href, const xmlChar *prefix)
1322{
1323    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1324#ifdef DEBUG_SAX
1325    xmlGenericError(xmlGenericErrorContext,
1326	    "SAX.globalNamespace(%s, %s)\n", href, prefix);
1327#endif
1328    xmlNewGlobalNs(ctxt->myDoc, href, prefix);
1329}
1330
1331/**
1332 * setNamespace:
1333 * @ctx: the user data (XML parser context)
1334 * @name:  the namespace prefix
1335 *
1336 * Set the current element namespace.
1337 */
1338
1339void
1340setNamespace(void *ctx, const xmlChar *name)
1341{
1342    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1343    xmlNsPtr ns;
1344    xmlNodePtr parent;
1345
1346#ifdef DEBUG_SAX
1347    xmlGenericError(xmlGenericErrorContext, "SAX.setNamespace(%s)\n", name);
1348#endif
1349    ns = xmlSearchNs(ctxt->myDoc, ctxt->node, name);
1350    if (ns == NULL) { /* ctxt->node may not have a parent yet ! */
1351        if (ctxt->nodeNr >= 2) {
1352	    parent = ctxt->nodeTab[ctxt->nodeNr - 2];
1353	    if (parent != NULL)
1354		ns = xmlSearchNs(ctxt->myDoc, parent, name);
1355	}
1356    }
1357    xmlSetNs(ctxt->node, ns);
1358}
1359
1360/**
1361 * getNamespace:
1362 * @ctx: the user data (XML parser context)
1363 *
1364 * Get the current element namespace.
1365 *
1366 * Returns the xmlNsPtr or NULL if none
1367 */
1368
1369xmlNsPtr
1370getNamespace(void *ctx)
1371{
1372    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1373    xmlNsPtr ret;
1374
1375#ifdef DEBUG_SAX
1376    xmlGenericError(xmlGenericErrorContext, "SAX.getNamespace()\n");
1377#endif
1378    ret = ctxt->node->ns;
1379    return(ret);
1380}
1381
1382/**
1383 * checkNamespace:
1384 * @ctx: the user data (XML parser context)
1385 * @namespace: the namespace to check against
1386 *
1387 * Check that the current element namespace is the same as the
1388 * one read upon parsing.
1389 *
1390 * Returns 1 if true 0 otherwise
1391 */
1392
1393int
1394checkNamespace(void *ctx, xmlChar *namespace)
1395{
1396    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1397    xmlNodePtr cur = ctxt->node;
1398
1399#ifdef DEBUG_SAX
1400    xmlGenericError(xmlGenericErrorContext,
1401	    "SAX.checkNamespace(%s)\n", namespace);
1402#endif
1403
1404    /*
1405     * Check that the Name in the ETag is the same as in the STag.
1406     */
1407    if (namespace == NULL) {
1408        if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1409	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1410		ctxt->sax->error(ctxt,
1411		 "End tags for %s don't hold the namespace %s\n",
1412		                 cur->name, cur->ns->prefix);
1413	    ctxt->wellFormed = 0;
1414	}
1415    } else {
1416        if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) {
1417	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1418		ctxt->sax->error(ctxt,
1419		 "End tags %s holds a prefix %s not used by the open tag\n",
1420		                 cur->name, namespace);
1421	    ctxt->wellFormed = 0;
1422	} else if (!xmlStrEqual(namespace, cur->ns->prefix)) {
1423	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1424		ctxt->sax->error(ctxt,
1425    "Start and End tags for %s don't use the same namespaces: %s and %s\n",
1426	                         cur->name, cur->ns->prefix, namespace);
1427	    ctxt->wellFormed = 0;
1428	} else
1429	    return(1);
1430    }
1431    return(0);
1432}
1433
1434/**
1435 * namespaceDecl:
1436 * @ctx: the user data (XML parser context)
1437 * @href:  the namespace associated URN
1438 * @prefix: the namespace prefix
1439 *
1440 * A namespace has been parsed.
1441 */
1442void
1443namespaceDecl(void *ctx, const xmlChar *href, const xmlChar *prefix)
1444{
1445    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1446#ifdef DEBUG_SAX
1447    if (prefix == NULL)
1448	xmlGenericError(xmlGenericErrorContext,
1449		"SAX.namespaceDecl(%s, NULL)\n", href);
1450    else
1451	xmlGenericError(xmlGenericErrorContext,
1452		"SAX.namespaceDecl(%s, %s)\n", href, prefix);
1453#endif
1454    xmlNewNs(ctxt->node, href, prefix);
1455}
1456
1457/**
1458 * comment:
1459 * @ctx: the user data (XML parser context)
1460 * @value:  the comment content
1461 *
1462 * A comment has been parsed.
1463 */
1464void
1465comment(void *ctx, const xmlChar *value)
1466{
1467    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1468    xmlNodePtr ret;
1469    xmlNodePtr parent = ctxt->node;
1470
1471#ifdef DEBUG_SAX
1472    xmlGenericError(xmlGenericErrorContext, "SAX.comment(%s)\n", value);
1473#endif
1474    ret = xmlNewDocComment(ctxt->myDoc, value);
1475    if (ret == NULL) return;
1476
1477    if (ctxt->inSubset == 1) {
1478	xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
1479	return;
1480    } else if (ctxt->inSubset == 2) {
1481	xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
1482	return;
1483    }
1484    if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
1485#ifdef DEBUG_SAX_TREE
1486	    xmlGenericError(xmlGenericErrorContext,
1487		    "Setting comment as root\n");
1488#endif
1489        xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
1490	return;
1491    }
1492    if (parent->type == XML_ELEMENT_NODE) {
1493#ifdef DEBUG_SAX_TREE
1494	xmlGenericError(xmlGenericErrorContext,
1495		"adding comment child to %s\n", parent->name);
1496#endif
1497	xmlAddChild(parent, ret);
1498    } else {
1499#ifdef DEBUG_SAX_TREE
1500	xmlGenericError(xmlGenericErrorContext,
1501		"adding comment sibling to ");
1502	xmlDebugDumpOneNode(stderr, parent, 0);
1503#endif
1504	xmlAddSibling(parent, ret);
1505    }
1506}
1507
1508/**
1509 * cdataBlock:
1510 * @ctx: the user data (XML parser context)
1511 * @value:  The pcdata content
1512 * @len:  the block length
1513 *
1514 * called when a pcdata block has been parsed
1515 */
1516void
1517cdataBlock(void *ctx, const xmlChar *value, int len)
1518{
1519    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1520    xmlNodePtr ret, lastChild;
1521
1522#ifdef DEBUG_SAX
1523    xmlGenericError(xmlGenericErrorContext,
1524	    "SAX.pcdata(%.10s, %d)\n", value, len);
1525#endif
1526    lastChild = xmlGetLastChild(ctxt->node);
1527#ifdef DEBUG_SAX_TREE
1528    xmlGenericError(xmlGenericErrorContext,
1529	    "add chars to %s \n", ctxt->node->name);
1530#endif
1531    if ((lastChild != NULL) &&
1532        (lastChild->type == XML_CDATA_SECTION_NODE)) {
1533	xmlTextConcat(lastChild, value, len);
1534    } else {
1535	ret = xmlNewCDataBlock(ctxt->myDoc, value, len);
1536	xmlAddChild(ctxt->node, ret);
1537    }
1538}
1539
1540/*
1541 * Default handler for XML, builds the DOM tree
1542 */
1543xmlSAXHandler xmlDefaultSAXHandler = {
1544    internalSubset,
1545    isStandalone,
1546    hasInternalSubset,
1547    hasExternalSubset,
1548    resolveEntity,
1549    getEntity,
1550    entityDecl,
1551    notationDecl,
1552    attributeDecl,
1553    elementDecl,
1554    unparsedEntityDecl,
1555    setDocumentLocator,
1556    startDocument,
1557    endDocument,
1558    startElement,
1559    endElement,
1560    reference,
1561    characters,
1562    ignorableWhitespace,
1563    processingInstruction,
1564    comment,
1565    xmlParserWarning,
1566    xmlParserError,
1567    xmlParserError,
1568    getParameterEntity,
1569    cdataBlock,
1570    externalSubset,
1571};
1572
1573/**
1574 * xmlDefaultSAXHandlerInit:
1575 *
1576 * Initialize the default SAX handler
1577 */
1578void
1579xmlDefaultSAXHandlerInit(void)
1580{
1581    xmlDefaultSAXHandler.internalSubset = internalSubset;
1582    xmlDefaultSAXHandler.externalSubset = externalSubset;
1583    xmlDefaultSAXHandler.isStandalone = isStandalone;
1584    xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
1585    xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
1586    xmlDefaultSAXHandler.resolveEntity = resolveEntity;
1587    xmlDefaultSAXHandler.getEntity = getEntity;
1588    xmlDefaultSAXHandler.getParameterEntity = getParameterEntity;
1589    xmlDefaultSAXHandler.entityDecl = entityDecl;
1590    xmlDefaultSAXHandler.attributeDecl = attributeDecl;
1591    xmlDefaultSAXHandler.elementDecl = elementDecl;
1592    xmlDefaultSAXHandler.notationDecl = notationDecl;
1593    xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
1594    xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1595    xmlDefaultSAXHandler.startDocument = startDocument;
1596    xmlDefaultSAXHandler.endDocument = endDocument;
1597    xmlDefaultSAXHandler.startElement = startElement;
1598    xmlDefaultSAXHandler.endElement = endElement;
1599    xmlDefaultSAXHandler.reference = reference;
1600    xmlDefaultSAXHandler.characters = characters;
1601    xmlDefaultSAXHandler.cdataBlock = cdataBlock;
1602    xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1603    xmlDefaultSAXHandler.processingInstruction = processingInstruction;
1604    xmlDefaultSAXHandler.comment = comment;
1605    if (xmlGetWarningsDefaultValue == 0)
1606	xmlDefaultSAXHandler.warning = NULL;
1607    else
1608	xmlDefaultSAXHandler.warning = xmlParserWarning;
1609    xmlDefaultSAXHandler.error = xmlParserError;
1610    xmlDefaultSAXHandler.fatalError = xmlParserError;
1611}
1612
1613/*
1614 * Default handler for HTML, builds the DOM tree
1615 */
1616xmlSAXHandler htmlDefaultSAXHandler = {
1617    internalSubset,
1618    NULL,
1619    NULL,
1620    NULL,
1621    NULL,
1622    getEntity,
1623    NULL,
1624    NULL,
1625    NULL,
1626    NULL,
1627    NULL,
1628    setDocumentLocator,
1629    startDocument,
1630    endDocument,
1631    startElement,
1632    endElement,
1633    NULL,
1634    characters,
1635    ignorableWhitespace,
1636    NULL,
1637    comment,
1638    xmlParserWarning,
1639    xmlParserError,
1640    xmlParserError,
1641    getParameterEntity,
1642    cdataBlock,
1643    NULL,
1644};
1645
1646/**
1647 * htmlDefaultSAXHandlerInit:
1648 *
1649 * Initialize the default SAX handler
1650 */
1651void
1652htmlDefaultSAXHandlerInit(void)
1653{
1654    htmlDefaultSAXHandler.internalSubset = internalSubset;
1655    htmlDefaultSAXHandler.externalSubset = NULL;
1656    htmlDefaultSAXHandler.isStandalone = NULL;
1657    htmlDefaultSAXHandler.hasInternalSubset = NULL;
1658    htmlDefaultSAXHandler.hasExternalSubset = NULL;
1659    htmlDefaultSAXHandler.resolveEntity = NULL;
1660    htmlDefaultSAXHandler.getEntity = getEntity;
1661    htmlDefaultSAXHandler.getParameterEntity = NULL;
1662    htmlDefaultSAXHandler.entityDecl = NULL;
1663    htmlDefaultSAXHandler.attributeDecl = NULL;
1664    htmlDefaultSAXHandler.elementDecl = NULL;
1665    htmlDefaultSAXHandler.notationDecl = NULL;
1666    htmlDefaultSAXHandler.unparsedEntityDecl = NULL;
1667    htmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1668    htmlDefaultSAXHandler.startDocument = startDocument;
1669    htmlDefaultSAXHandler.endDocument = endDocument;
1670    htmlDefaultSAXHandler.startElement = startElement;
1671    htmlDefaultSAXHandler.endElement = endElement;
1672    htmlDefaultSAXHandler.reference = NULL;
1673    htmlDefaultSAXHandler.characters = characters;
1674    htmlDefaultSAXHandler.cdataBlock = cdataBlock;
1675    htmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1676    htmlDefaultSAXHandler.processingInstruction = NULL;
1677    htmlDefaultSAXHandler.comment = comment;
1678    htmlDefaultSAXHandler.warning = xmlParserWarning;
1679    htmlDefaultSAXHandler.error = xmlParserError;
1680    htmlDefaultSAXHandler.fatalError = xmlParserError;
1681}
1682
1683/*
1684 * Default handler for HTML, builds the DOM tree
1685 */
1686xmlSAXHandler sgmlDefaultSAXHandler = {
1687    internalSubset,
1688    NULL,
1689    NULL,
1690    NULL,
1691    NULL,
1692    getEntity,
1693    NULL,
1694    NULL,
1695    NULL,
1696    NULL,
1697    NULL,
1698    setDocumentLocator,
1699    startDocument,
1700    endDocument,
1701    startElement,
1702    endElement,
1703    NULL,
1704    characters,
1705    ignorableWhitespace,
1706    NULL,
1707    comment,
1708    xmlParserWarning,
1709    xmlParserError,
1710    xmlParserError,
1711    getParameterEntity,
1712    NULL,
1713    NULL,
1714};
1715
1716/**
1717 * sgmlDefaultSAXHandlerInit:
1718 *
1719 * Initialize the default SAX handler
1720 */
1721void
1722sgmlDefaultSAXHandlerInit(void)
1723{
1724    sgmlDefaultSAXHandler.internalSubset = internalSubset;
1725    sgmlDefaultSAXHandler.externalSubset = NULL;
1726    sgmlDefaultSAXHandler.isStandalone = NULL;
1727    sgmlDefaultSAXHandler.hasInternalSubset = NULL;
1728    sgmlDefaultSAXHandler.hasExternalSubset = NULL;
1729    sgmlDefaultSAXHandler.resolveEntity = NULL;
1730    sgmlDefaultSAXHandler.getEntity = getEntity;
1731    sgmlDefaultSAXHandler.getParameterEntity = NULL;
1732    sgmlDefaultSAXHandler.entityDecl = NULL;
1733    sgmlDefaultSAXHandler.attributeDecl = NULL;
1734    sgmlDefaultSAXHandler.elementDecl = NULL;
1735    sgmlDefaultSAXHandler.notationDecl = NULL;
1736    sgmlDefaultSAXHandler.unparsedEntityDecl = NULL;
1737    sgmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1738    sgmlDefaultSAXHandler.startDocument = startDocument;
1739    sgmlDefaultSAXHandler.endDocument = endDocument;
1740    sgmlDefaultSAXHandler.startElement = startElement;
1741    sgmlDefaultSAXHandler.endElement = endElement;
1742    sgmlDefaultSAXHandler.reference = NULL;
1743    sgmlDefaultSAXHandler.characters = characters;
1744    sgmlDefaultSAXHandler.cdataBlock = NULL;
1745    sgmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1746    sgmlDefaultSAXHandler.processingInstruction = NULL;
1747    sgmlDefaultSAXHandler.comment = comment;
1748    sgmlDefaultSAXHandler.warning = xmlParserWarning;
1749    sgmlDefaultSAXHandler.error = xmlParserError;
1750    sgmlDefaultSAXHandler.fatalError = xmlParserError;
1751}
1752